解析BTC区块交易SRC20铭文算法

解析BTC区块交易SRC20铭文算法

写在最开始,SRC-20的相关技术文档确实少的可怜,很多东西都没有现成可用(拿来主义是不行了),我在做这方面的时候也是搜索一番实在没找到,只能硬“肝”了。

一、介绍
SRC-20,即STAMPS/SRC-20,是比特币生态中的一种协议。它由Mike In Space于2023年3月发布,是基于STAMPS协议发展而来的,灵感部分来源于比特币的ORDINALS协议及BRC-20协议等。SRC-20协议规定了一组资产通证化的规则,这些规则必须包含在证券型资产之中,可帮助程序员开发可使用证券通证的应用程序。

二、SRC-20代币
自区块高度 796,000 起,SRC-20 规范已更改协议规范。SRC-20 交易现在直接在 BTC 上创建,不再支持作为合约交易。SRC-20 的铸造、部署和转账均免收服务费,但使用受支持的钱包进行交易时需支付 BTC 矿工费。

SRC-20 是基于 BRC-20 建模的前沿规范。SRC-20 的早期规范基于合约交易构建,并对发行交易有特定要求。截至区块 796,000 的当前规范将 SRC-20 交易直接编码到 BTC 上,并且不使用合约交易。区块 796,000 之后在合约交易上创建的任何 SRC-20 交易都将无效。我们设计了一种直接到 BTC 的方法,该方法可以优化交易规模并降低 SRC-20 交易的成本,因此我们将其用作概念验证。

三、在了解到这些背景后,我再来做交易数据的解码功能,从上面介绍来讲解码算法跟高度有一定的个关心,由于截止目前btc区块高度,我们不对之前的高度做解析,这一点还请知悉,下面直接上代码:

1.对应btc交易src-20有两种数据,我先把两种交易HASH数据贴出来:

#第一种多签的方式
{
	"jsonrpc": "2.0",
	"result": {
		"txid": "9676d6a46bb6733442928ed27990ee17bffe62666a1ce2bfeb170390a8c9ad53",
		"hash": "da0e8138cfd07143c4ee097d0394ade05ed4bc63cb59d65d0b9c6be0939ece08",
		"version": 2,
		"size": 450,
		"vsize": 369,
		"weight": 1473,
		"locktime": 0,
		"vin": [
			{
				"txid": "b646592769c53bad806d53931502b171bb7b94c36b3e42138bf36bf3cd9d99ef",
				"vout": 3,
				"scriptSig": {
					"asm": "",
					"hex": ""
				},
				"txinwitness": [
					"304402207392fedfe647426e105c38d518b8eb68badd50032a9d05084014d2b2c200202f02206adc3f569b74e3436c16a39b1d52c1bcd131ac9ad4f1bba0ae455529eebc570601",
					"02d6b8e961a9cbbe6f1f5be08f0017a4f84bb773e3298ea236ae4f90456a6fb632"
				],
				"sequence": 4294967293
			}
		],
		"vout": [
			{
				"value": 0.0000079,
				"n": 0,
				"scriptPubKey": {
					"asm": "0 41fab71bc5e225bb8b31af473f08f59f7c386a88",
					"desc": "addr(bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8)#93sr8xlc",
					"hex": "001441fab71bc5e225bb8b31af473f08f59f7c386a88",
					"address": "bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8",
					"type": "witness_v0_keyhash"
				}
			},
			{
				"value": 0.0000079,
				"n": 1,
				"scriptPubKey": {
					"asm": "1 03fb9cb4286f2a862d14ea8a9468ddc67bb1942f484e69e0b65b3e9ec337e77d00 021acd30a69266572b280aab63a1bf26582ef90b7047c620ef4f8f3e2a3d7ded00 020202020202020202020202020202020202020202020202020202020202020202 3 OP_CHECKMULTISIG",
					"desc": "multi(1,03fb9cb4286f2a862d14ea8a9468ddc67bb1942f484e69e0b65b3e9ec337e77d00,021acd30a69266572b280aab63a1bf26582ef90b7047c620ef4f8f3e2a3d7ded00,020202020202020202020202020202020202020202020202020202020202020202)#r3aa3efh",
					"hex": "512103fb9cb4286f2a862d14ea8a9468ddc67bb1942f484e69e0b65b3e9ec337e77d0021021acd30a69266572b280aab63a1bf26582ef90b7047c620ef4f8f3e2a3d7ded002102020202020202020202020202020202020202020202020202020202020202020253ae",
					"type": "multisig"
				}
			},
			{
				"value": 0.0000079,
				"n": 2,
				"scriptPubKey": {
					"asm": "1 037ea1f327b994a0d915fee911f9124e3ed47ac6a49096bd4c80249a3601470900 0275f544716081676b0ad6f27371f20f60070c650c66ca8141671e48c6984db900 020202020202020202020202020202020202020202020202020202020202020202 3 OP_CHECKMULTISIG",
					"desc": "multi(1,037ea1f327b994a0d915fee911f9124e3ed47ac6a49096bd4c80249a3601470900,0275f544716081676b0ad6f27371f20f60070c650c66ca8141671e48c6984db900,020202020202020202020202020202020202020202020202020202020202020202)#0vlpjvkg",
					"hex": "5121037ea1f327b994a0d915fee911f9124e3ed47ac6a49096bd4c80249a3601470900210275f544716081676b0ad6f27371f20f60070c650c66ca8141671e48c6984db9002102020202020202020202020202020202020202020202020202020202020202020253ae",
					"type": "multisig"
				}
			},
			{
				"value": 0.0001946,
				"n": 3,
				"scriptPubKey": {
					"asm": "0 8776da9ce66061d2497fe025c7798102ba6ee191",
					"desc": "addr(bc1qsamd488xvpsayjtluqjuw7vpq2axacv3jx2cxa)#38qcp2er",
					"hex": "00148776da9ce66061d2497fe025c7798102ba6ee191",
					"address": "bc1qsamd488xvpsayjtluqjuw7vpq2axacv3jx2cxa",
					"type": "witness_v0_keyhash"
				}
			}
		]
	},
	"id": 1
}
#第二种,普通方式
{
	"jsonrpc": "2.0",
	"result": {
		"txid": "7d6b51f0bf20dd121388343536e2ae0b74a15503a52a53d631609827f84fc8ce",
		"hash": "551728c0f7d29ad699edec1c6e311db01d9279b188b9221482c46a96aa896bdc",
		"version": 2,
		"size": 352,
		"vsize": 270,
		"weight": 1078,
		"locktime": 0,
		"vin": [
			{
				"txid": "24de58a077b51363961f717969dfeb8a5a3823a6ac2f8b71ff084854901ba6a1",
				"vout": 0,
				"scriptSig": {
					"asm": "",
					"hex": ""
				},
				"txinwitness": [
					"304502210080fe936bcb5fab584035d6834bd7ad9308af672d0146e30fa680b000b165b31f022074e36296caa5f8ca5ae54627d9ffed75174b5534dea934cd5bfc1941746e48f081",
					"0266111294c27223e9dd58e6d2de99ce3c62d2dacf4754f9c9e0febd541a9af897"
				],
				"sequence": 4294967293
			}
		],
		"vout": [
			{
				"value": 0.00000547,
				"n": 0,
				"scriptPubKey": {
					"asm": "1 3dcc869b59505a250348b668d0892659fb4f4001f4e00d44fece587efcd1c9e5",
					"desc": "rawtr(3dcc869b59505a250348b668d0892659fb4f4001f4e00d44fece587efcd1c9e5)#n3qywyzr",
					"hex": "51203dcc869b59505a250348b668d0892659fb4f4001f4e00d44fece587efcd1c9e5",
					"address": "bc1p8hxgdx6e2pdz2q6gke5dpzfxt8a57sqp7nsq6387eev8alx3e8js37kw5z",
					"type": "witness_v1_taproot"
				}
			},
			{
				"value": 0.0000033,
				"n": 1,
				"scriptPubKey": {
					"asm": "0 003d7374616d703a7b2270223a227372632d3230222c226f70223a227472616e",
					"desc": "addr(bc1qqq7hxarpd4cr57ezwq3r5gnnwf3j6v3sygkzymmsygazyarjv9hqylmqeg)#pgz9204k",
					"hex": "0020003d7374616d703a7b2270223a227372632d3230222c226f70223a227472616e",
					"address": "bc1qqq7hxarpd4cr57ezwq3r5gnnwf3j6v3sygkzymmsygazyarjv9hqylmqeg",
					"type": "witness_v0_scripthash"
				}
			},
			{
				"value": 0.0000033,
				"n": 2,
				"scriptPubKey": {
					"asm": "0 73666572222c227469636b223a224d534b45222c22616d74223a323230367d00",
					"desc": "addr(bc1qwdnx2u3z9s38g6trdv3r5gjd2d952g3vyfsk6apz8geryvpk05qqze0nuw)#7ghqd9cn",
					"hex": "002073666572222c227469636b223a224d534b45222c22616d74223a323230367d00",
					"address": "bc1qwdnx2u3z9s38g6trdv3r5gjd2d952g3vyfsk6apz8geryvpk05qqze0nuw",
					"type": "witness_v0_scripthash"
				}
			},
			{
				"value": 0.0008335,
				"n": 3,
				"scriptPubKey": {
					"asm": "0 41fab71bc5e225bb8b31af473f08f59f7c386a88",
					"desc": "addr(bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8)#93sr8xlc",
					"hex": "001441fab71bc5e225bb8b31af473f08f59f7c386a88",
					"address": "bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8",
					"type": "witness_v0_keyhash"
				}
			},
			{
				"value": 0.00003486,
				"n": 4,
				"scriptPubKey": {
					"asm": "0 b393ece604d23b32dcbfdf161a222aa125287fe2",
					"desc": "addr(bc1qkwf7eesy6gan9h9lmutp5g325yjjsllzr22u59)#gzgzpwka",
					"hex": "0014b393ece604d23b32dcbfdf161a222aa125287fe2",
					"address": "bc1qkwf7eesy6gan9h9lmutp5g325yjjsllzr22u59",
					"type": "witness_v0_keyhash"
				}
			}
		],
		"hex": "02000000000101a1a61b90544808ff718b2faca623385a8aebdf6979711f966313b577a058de240000000000fdffffff0523020000000000002251203dcc869b59505a250348b668d0892659fb4f4001f4e00d44fece587efcd1c9e54a01000000000000220020003d7374616d703a7b2270223a227372632d3230222c226f70223a227472616e4a0100000000000022002073666572222c227469636b223a224d534b45222c22616d74223a323230367d00964501000000000016001441fab71bc5e225bb8b31af473f08f59f7c386a889e0d000000000000160014b393ece604d23b32dcbfdf161a222aa125287fe20248304502210080fe936bcb5fab584035d6834bd7ad9308af672d0146e30fa680b000b165b31f022074e36296caa5f8ca5ae54627d9ffed75174b5534dea934cd5bfc1941746e48f081210266111294c27223e9dd58e6d2de99ce3c62d2dacf4754f9c9e0febd541a9af89700000000",
		"blockhash": "00000000000000000001debd1260bd8c6ee130f8f3500bdd3220e345699049c2",
		"confirmations": 3354,
		"time": 1752220031,
		"blocktime": 1752220031
	},
	"id": 1
}

所以这里我们需要针对这里两种交易数据方式分别做解码

第一种交易数据解码方式,多签的解码方式相对比较复杂需要。提取并反转ARC4密钥,然后从多签输出提取公钥数据来做解码算法,具体看下面代码

#第一种数据解码方式

import json
from Crypto.Cipher import ARC4
import binascii
import re

def parse_src20_transaction(tx_data):
    try:
        # 1. 提取并反转ARC4密钥 (vin[0].txid反转)
        #vin_txid = tx_data["vin"][0]["txid"]
        #raw_bytes = binascii.unhexlify(vin_txid)[::-1]  #  # 关键步骤:字节反转
        #print("Reversed Key:", raw_bytes.hex())
        #arc4_key = raw_bytes[::-1] 
        #研究协议需要反转,但实际这里不需要,这里比较坑人。
		arc4_key = binascii.unhexlify(vin_txid)
        # 2. 从多签输出提取公钥数据
        pubkey_fragments = []
        for vout in tx_data["vout"]:
            if vout["scriptPubKey"]["type"] == "multisig":
                hex_script = vout["scriptPubKey"]["hex"]
                # 提取前两个公钥 (各66字符)
                pubkey1 = hex_script[4:70]  # 跳过OP_CODE(51=0x33)
                pubkey2 = hex_script[72:138]  # 跳过间隔符
                # 移除首尾字节 (首字节类型标识,尾字节00填充)
                pubkey_fragments.append(pubkey1[2:-2])
                pubkey_fragments.append(pubkey2[2:-2])

        encrypted_hex = "".join(pubkey_fragments)
        print("Encrypted Data:", encrypted_hex)
        # 3. ARC4解密
        cipher = ARC4.new(arc4_key)
        decrypted = cipher.decrypt(binascii.unhexlify(encrypted_hex))
        # 4. 协议结构解析(关键修复)
        if len(decrypted) < 8:
            return "错误:解密数据过短"

        # 读取长度标识(2字节大端序)
        data_length = int.from_bytes(decrypted[0:2], byteorder="big")

        print("解密原始字节:", decrypted[:20].hex())

        print("拼接后的加密数据 (hex):", encrypted_hex)  # 应为576字符
        print("解密密钥 (hex):", arc4_key.hex())  # 应为64字符

        # 验证协议前缀
        if decrypted[2:8] != b"stamp:":
            return "错误:无效数据前缀"

        decoded_str = decrypted.decode('utf-8', errors='ignore')

        stamp_match = re.search(r'stamp:\s*(\{.*\})', decoded_str, re.DOTALL)
        if not stamp_match:
            return "错误:未找到有效JSON数据"

        # 3. 提取并清洗JSON字符串
        json_str = stamp_match.group(1)
        # 移除控制字符和尾随空字符
        cleaned_json = re.sub(r'[\x00-\x1F]', '', json_str).strip()

        return json.loads(cleaned_json)

    except Exception as e:
        return f"解析失败: {str(e)}"


# ===== 使用示例 =====
if __name__ == "__main__":
    # 替换为你的交易数据
    tx_data = {
        "vin": [{"txid": "ca3b28031b279de22b398e1d1c61b0f6b692afc59a674643c96551b9ea52396a"}],
        "vout": [
            {
                "value": 0.0000079,
                "n": 0,
                "scriptPubKey": {
                    "asm": "0 41fab71bc5e225bb8b31af473f08f59f7c386a88",
                    "desc": "addr(bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8)#93sr8xlc",
                    "hex": "001441fab71bc5e225bb8b31af473f08f59f7c386a88",
                    "address": "bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8",
                    "type": "witness_v0_keyhash"
                }
            },
            {
                "value": 0.0000079,
                "n": 1,
                "scriptPubKey": {
                    "asm": "1 035297b61ef0596ffa119c7bfe572ce32ecf602607c7e6e88486b99999b2b56400 02480ed2a3933d656184950bb99431b5af6f3db3af95212e9927bfa16313e45000 020202020202020202020202020202020202020202020202020202020202020202 3 OP_CHECKMULTISIG",
                    "desc": "multi(1,035297b61ef0596ffa119c7bfe572ce32ecf602607c7e6e88486b99999b2b56400,02480ed2a3933d656184950bb99431b5af6f3db3af95212e9927bfa16313e45000,020202020202020202020202020202020202020202020202020202020202020202)#eap59csk",
                    "hex": "5121035297b61ef0596ffa119c7bfe572ce32ecf602607c7e6e88486b99999b2b564002102480ed2a3933d656184950bb99431b5af6f3db3af95212e9927bfa16313e450002102020202020202020202020202020202020202020202020202020202020202020253ae",
                    "type": "multisig"
                }
            },
            {
                "value": 0.0000079,
                "n": 2,
                "scriptPubKey": {
                    "asm": "1 03677879b8c530f8456b31d8a06623b511283764ee20eb1c59ba25df295e4edf00 0212c125c13de7ca7f50b02fbc3a391adb7ceab1a90b0d28cbd1ec506140f5f600 020202020202020202020202020202020202020202020202020202020202020202 3 OP_CHECKMULTISIG",
                    "desc": "multi(1,03677879b8c530f8456b31d8a06623b511283764ee20eb1c59ba25df295e4edf00,0212c125c13de7ca7f50b02fbc3a391adb7ceab1a90b0d28cbd1ec506140f5f600,020202020202020202020202020202020202020202020202020202020202020202)#78g9qxzq",
                    "hex": "512103677879b8c530f8456b31d8a06623b511283764ee20eb1c59ba25df295e4edf00210212c125c13de7ca7f50b02fbc3a391adb7ceab1a90b0d28cbd1ec506140f5f6002102020202020202020202020202020202020202020202020202020202020202020253ae",
                    "type": "multisig"
                }
            },
            {
                "value": 0.00015425,
                "n": 3,
                "scriptPubKey": {
                    "asm": "0 d4b0878659667c9b43cca4bc1eeb61a92c33ffdb",
                    "desc": "addr(bc1q6jcg0pjeve7fks7v5j7pa6mp4ykr8l7mjurcst)#mh3fex56",
                    "hex": "0014d4b0878659667c9b43cca4bc1eeb61a92c33ffdb",
                    "address": "bc1q6jcg0pjeve7fks7v5j7pa6mp4ykr8l7mjurcst",
                    "type": "witness_v0_keyhash"
                }
            }
        ]
    }


    result = parse_src20_transaction(tx_data)
    print("解析结果:")

    decoded_str = json.dumps(result, indent=2)
    print(decoded_str)



第二种交易数据解码方式就比较简单,直接拼接具体数据解码即可,具体看下面代码

import binascii
import json
import re

def parse_src20_from_vouts(vouts):
    data_hex = ""
    # 按索引顺序提取数据(确保顺序正确)
    for vout in sorted(vouts, key=lambda x: x["n"]):
        if vout["scriptPubKey"]["type"] == "witness_v0_scripthash":
            hex_data = vout["scriptPubKey"]["hex"]
            # 跳过脚本头(OP_0 + PUSH32: 0020)
            if hex_data.startswith("0020"):
                data_hex += hex_data[4:]  # 移除0020前缀

    # 十六进制转文本
    json_data = binascii.unhexlify(data_hex).decode("utf-8")
    # 剥离"stamp:"前缀
    if json_data.startswith("stamp:"):
        json_data = json_data[6:]

    cleaned_data = re.sub(r'[\x00-\x1F]', '', json_data)
    # 使用正则匹配第一个{到最后一个}之间的内容
    json_match = re.search(r'\{.*\}', cleaned_data)
    if not json_match:
        return {"error": "No valid JSON found in: " + cleaned_data}

    json_str = json_match.group(0)

    try:
        return json.loads(json_str)
    except json.JSONDecodeError as e:
        # 处理常见错误格式
        fixed_str = re.sub(r',\s*}', '}', json_str)  # 修复多余逗号
        fixed_str = re.sub(r',\s*\]', ']', fixed_str)
        try:
            return json.loads(fixed_str)
        except:
            return {"error": f"JSON decode failed: {str(e)}", "raw_data": cleaned_data}


# 示例调用

if __name__ == "__main__":
    tx_data = {
        "vin": [{"txid": "ca3b28031b279de22b398e1d1c61b0f6b692afc59a674643c96551b9ea52396a"}],
        "vout": [
            {
                "value": 0.00000547,
                "n": 0,
                "scriptPubKey": {
                    "asm": "1 3dcc869b59505a250348b668d0892659fb4f4001f4e00d44fece587efcd1c9e5",
                    "desc": "rawtr(3dcc869b59505a250348b668d0892659fb4f4001f4e00d44fece587efcd1c9e5)#n3qywyzr",
                    "hex": "51203dcc869b59505a250348b668d0892659fb4f4001f4e00d44fece587efcd1c9e5",
                    "address": "bc1p8hxgdx6e2pdz2q6gke5dpzfxt8a57sqp7nsq6387eev8alx3e8js37kw5z",
                    "type": "witness_v1_taproot"
                }
            },
            {
                "value": 0.0000033,
                "n": 1,
                "scriptPubKey": {
                    "asm": "0 003d7374616d703a7b2270223a227372632d3230222c226f70223a227472616e",
                    "desc": "addr(bc1qqq7hxarpd4cr57ezwq3r5gnnwf3j6v3sygkzymmsygazyarjv9hqylmqeg)#pgz9204k",
                    "hex": "0020003d7374616d703a7b2270223a227372632d3230222c226f70223a227472616e",
                    "address": "bc1qqq7hxarpd4cr57ezwq3r5gnnwf3j6v3sygkzymmsygazyarjv9hqylmqeg",
                    "type": "witness_v0_scripthash"
                }
            },
            {
                "value": 0.0000033,
                "n": 2,
                "scriptPubKey": {
                    "asm": "0 73666572222c227469636b223a224d534b45222c22616d74223a323230367d00",
                    "desc": "addr(bc1qwdnx2u3z9s38g6trdv3r5gjd2d952g3vyfsk6apz8geryvpk05qqze0nuw)#7ghqd9cn",
                    "hex": "002073666572222c227469636b223a224d534b45222c22616d74223a323230367d00",
                    "address": "bc1qwdnx2u3z9s38g6trdv3r5gjd2d952g3vyfsk6apz8geryvpk05qqze0nuw",
                    "type": "witness_v0_scripthash"
                }
            },
            {
                "value": 0.0008335,
                "n": 3,
                "scriptPubKey": {
                    "asm": "0 41fab71bc5e225bb8b31af473f08f59f7c386a88",
                    "desc": "addr(bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8)#93sr8xlc",
                    "hex": "001441fab71bc5e225bb8b31af473f08f59f7c386a88",
                    "address": "bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8",
                    "type": "witness_v0_keyhash"
                }
            },
            {
                "value": 0.00003486,
                "n": 4,
                "scriptPubKey": {
                    "asm": "0 b393ece604d23b32dcbfdf161a222aa125287fe2",
                    "desc": "addr(bc1qkwf7eesy6gan9h9lmutp5g325yjjsllzr22u59)#gzgzpwka",
                    "hex": "0014b393ece604d23b32dcbfdf161a222aa125287fe2",
                    "address": "bc1qkwf7eesy6gan9h9lmutp5g325yjjsllzr22u59",
                    "type": "witness_v0_keyhash"
                }
            }
        ]
    }
    vouts = tx_data["vout"]  # 你的vout数组
    result = parse_src20_from_vouts(vouts)
    print(result)

四、以上就是解码具体过程,下面是获取区块数据

curl https://fragrant-fittest-violet.btc.quiknode.pro/1xxxxx/ \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{"id": 1, "jsonrpc": "2.0", "method": "getblockhash", "params": [892809]}'

  curl https://fragrant-fittest-violet.btc.quiknode.pro/1xxxxx/ \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{"id": 1, "jsonrpc": "2.0", "method": "getblock", "params": ["00000000000000000000a2a31e36944c434c0f3b6ad04c03ccab80eeababbcb1"]}'

curl https://fragrant-fittest-violet.btc.quiknode.pro/1xxxxx/ \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{"id": 1, "jsonrpc": "2.0", "method": "getrawtransaction", "params": ["9676d6a46bb6733442928ed27990ee17bffe62666a1ce2bfeb170390a8c9ad53", true]}'

最后我第一种的 Java 实现方式也贴出来,第二种比较简单就省略了。

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>2.0.39</version>
</dependency>
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Src20TransactionParser {

    // 实现ARC4解密算法
    private static byte[] decryptARC4(byte[] key, byte[] ciphertext) {
        // 初始化S盒
        int[] s = new int[256];
        for (int i = 0; i < 256; i++) {
            s[i] = i;
        }
        
        // 密钥调度算法
        int j = 0;
        for (int i = 0; i < 256; i++) {
            j = (j + s[i] + (key[i % key.length] & 0xFF)) % 256;
            int temp = s[i];
            s[i] = s[j];
            s[j] = temp;
        }
        
        // 伪随机生成算法
        int i = 0;
        j = 0;
        byte[] plaintext = new byte[ciphertext.length];
        for (int k = 0; k < ciphertext.length; k++) {
            i = (i + 1) % 256;
            j = (j + s[i]) % 256;
            int temp = s[i];
            s[i] = s[j];
            s[j] = temp;
            int keyStream = s[(s[i] + s[j]) % 256];
            plaintext[k] = (byte) (ciphertext[k] ^ keyStream);
        }
        return plaintext;
    }

    // 十六进制字符串转字节数组
    private static byte[] hexStringToByteArray(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                                 + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }

    // 解析SRC20交易
    public static Object parseSrc20Transaction(JSONObject txData) {
        try {
            // 1. 提取并处理ARC4密钥
            JSONObject firstVin = txData.getJSONArray("vin").getJSONObject(0);
            String vinTxid = firstVin.getString("txid");
            byte[] arc4Key = hexStringToByteArray(vinTxid); // 直接使用原始txid字节

            // 2. 从多签输出提取公钥数据
            List<String> pubkeyFragments = new ArrayList<>();
            JSONArray vouts = txData.getJSONArray("vout");
            
            for (int i = 0; i < vouts.size(); i++) {
                JSONObject vout = vouts.getJSONObject(i);
                JSONObject scriptPubKey = vout.getJSONObject("scriptPubKey");
                
                if ("multisig".equals(scriptPubKey.getString("type"))) {
                    String hexScript = scriptPubKey.getString("hex");
                    // 提取两个公钥片段 (各66字符)
                    if (hexScript.length() >= 138) {
                        String pubkey1 = hexScript.substring(4, 70); // 51 OP_CODE后的第一个公钥
                        String pubkey2 = hexScript.substring(72, 138); // 第二个公钥
                        pubkeyFragments.add(pubkey1.substring(2, pubkey1.length() - 2));
                        pubkeyFragments.add(pubkey2.substring(2, pubkey2.length() - 2));
                    }
                }
            }

            // 3. 拼接加密数据并解密
            StringBuilder encryptedHex = new StringBuilder();
            for (String fragment : pubkeyFragments) {
                encryptedHex.append(fragment);
            }
            
            byte[] encryptedData = hexStringToByteArray(encryptedHex.toString());
            byte[] decrypted = decryptARC4(arc4Key, encryptedData);

            // 4. 验证协议前缀并提取JSON
            if (decrypted.length < 8) {
                return "错误:解密数据过短";
            }
            
            // 检查"stamp:"前缀
            byte[] stampPrefix = "stamp:".getBytes(StandardCharsets.UTF_8);
            for (int i = 0; i < stampPrefix.length; i++) {
                if (decrypted[i + 2] != stampPrefix[i]) {
                    return "错误:无效数据前缀";
                }
            }
            
            // 5. 提取并清洗JSON字符串
            String decryptedStr = new String(decrypted, StandardCharsets.UTF_8);
            Pattern pattern = Pattern.compile("stamp:\\s*(\\{.*\\})", Pattern.DOTALL);
            Matcher matcher = pattern.matcher(decryptedStr);
            
            if (!matcher.find()) {
                return "错误:未找到有效JSON数据";
            }
            
            String jsonStr = matcher.group(1);
            String cleanedJson = jsonStr.replaceAll("[\\x00-\\x1F]", "").trim();
            
            return JSON.parseObject(cleanedJson);

        } catch (Exception e) {
            return "解析失败: " + e.getMessage();
        }
    }

    // 测试用例
    public static void main(String[] args) {
        String jsonData = "{\"txid\":\"9676d6a46bb6733442928ed27990ee17bffe62666a1ce2bfeb170390a8c9ad53\",\"hash\":\"da0e8138cfd07143c4ee097d0394ade05ed4bc63cb59d65d0b9c6be0939ece08\",\"version\":2,\"size\":450,\"vsize\":369,\"weight\":1473,\"locktime\":0,\"vin\":[{\"txid\":\"b646592769c53bad806d53931502b171bb7b94c36b3e42138bf36bf3cd9d99ef\",\"vout\":3,\"scriptSig\":{\"asm\":\"\",\"hex\":\"\"},\"txinwitness\":[\"304402207392fedfe647426e105c38d518b8eb68badd50032a9d05084014d2b2c200202f02206adc3f569b74e3436c16a39b1d52c1bcd131ac9ad4f1bba0ae455529eebc570601\",\"02d6b8e961a9cbbe6f1f5be08f0017a4f84bb773e3298ea236ae4f90456a6fb632\"],\"sequence\":4294967293}],\"vout\":[{\"value\":0.00000790,\"n\":0,\"scriptPubKey\":{\"asm\":\"0 41fab71bc5e225bb8b31af473f08f59f7c386a88\",\"desc\":\"addr(bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8)#93sr8xlc\",\"hex\":\"001441fab71bc5e225bb8b31af473f08f59f7c386a88\",\"address\":\"bc1qg8atwx79ugjmhze34arn7z84na7rs65gw6k6l8\",\"type\":\"witness_v0_keyhash\"}},{\"value\":0.00000790,\"n\":1,\"scriptPubKey\":{\"asm\":\"1 03fb9cb4286f2a862d14ea8a9468ddc67bb1942f484e69e0b65b3e9ec337e77d00 021acd30a69266572b280aab63a1bf26582ef90b7047c620ef4f8f3e2a3d7ded00 020202020202020202020202020202020202020202020202020202020202020202 3 OP_CHECKMULTISIG\",\"desc\":\"multi(1,03fb9cb4286f2a862d14ea8a9468ddc67bb1942f484e69e0b65b3e9ec337e77d00,021acd30a69266572b280aab63a1bf26582ef90b7047c620ef4f8f3e2a3d7ded00,020202020202020202020202020202020202020202020202020202020202020202)#r3aa3efh\",\"hex\":\"512103fb9cb4286f2a862d14ea8a9468ddc67bb1942f484e69e0b65b3e9ec337e77d0021021acd30a69266572b280aab63a1bf26582ef90b7047c620ef4f8f3e2a3d7ded002102020202020202020202020202020202020202020202020202020202020202020253ae\",\"type\":\"multisig\"}},{\"value\":0.00000790,\"n\":2,\"scriptPubKey\":{\"asm\":\"1 037ea1f327b994a0d915fee911f9124e3ed47ac6a49096bd4c80249a3601470900 0275f544716081676b0ad6f27371f20f60070c650c66ca8141671e48c6984db900 020202020202020202020202020202020202020202020202020202020202020202 3 OP_CHECKMULTISIG\",\"desc\":\"multi(1,037ea1f327b994a0d915fee911f9124e3ed47ac6a49096bd4c80249a3601470900,0275f544716081676b0ad6f27371f20f60070c650c66ca8141671e48c6984db900,020202020202020202020202020202020202020202020202020202020202020202)#0vlpjvkg\",\"hex\":\"5121037ea1f327b994a0d915fee911f9124e3ed47ac6a49096bd4c80249a3601470900210275f544716081676b0ad6f27371f20f60070c650c66ca8141671e48c6984db9002102020202020202020202020202020202020202020202020202020202020202020253ae\",\"type\":\"multisig\"}},{\"value\":0.00019460,\"n\":3,\"scriptPubKey\":{\"asm\":\"0 8776da9ce66061d2497fe025c7798102ba6ee191\",\"desc\":\"addr(bc1qsamd488xvpsayjtluqjuw7vpq2axacv3jx2cxa)#38qcp2er\",\"hex\":\"00148776da9ce66061d2497fe025c7798102ba6ee191\",\"address\":\"bc1qsamd488xvpsayjtluqjuw7vpq2axacv3jx2cxa\",\"type\":\"witness_v0_keyhash\"}}],\"hex\":\"02000000000101ef999dcdf36bf38b13423e6bc3947bbb71b1021593536d80ad3bc569275946b60300000000fdffffff04160300000000000016001441fab71bc5e225bb8b31af473f08f59f7c386a88160300000000000069512103fb9cb4286f2a862d14ea8a9468ddc67bb1942f484e69e0b65b3e9ec337e77d0021021acd30a69266572b280aab63a1bf26582ef90b7047c620ef4f8f3e2a3d7ded002102020202020202020202020202020202020202020202020202020202020202020253ae1603000000000000695121037ea1f327b994a0d915fee911f9124e3ed47ac6a49096bd4c80249a3601470900210275f544716081676b0ad6f27371f20f60070c650c66ca8141671e48c6984db9002102020202020202020202020202020202020202020202020202020202020202020253ae044c0000000000001600148776da9ce66061d2497fe025c7798102ba6ee1910247304402207392fedfe647426e105c38d518b8eb68badd50032a9d05084014d2b2c200202f02206adc3f569b74e3436c16a39b1d52c1bcd131ac9ad4f1bba0ae455529eebc5706012102d6b8e961a9cbbe6f1f5be08f0017a4f84bb773e3298ea236ae4f90456a6fb63200000000\",\"blockhash\":\"00000000000000000000a2a31e36944c434c0f3b6ad04c03ccab80eeababbcb1\",\"confirmations\":15432,\"time\":1744879151,\"blocktime\":1744879151}";


        JSONObject txData = JSON.parseObject(jsonData);


        Object result = parseSrc20Transaction(txData);
        
        if (result instanceof JSONObject) {
            System.out.println("解析结果:");
            System.out.println(JSON.toJSONString((JSONObject) result, true));
        } else {
            System.out.println(result);
        }
    }
}

打完收工。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值