签署比特币 Segwit 交易

Signing a Bitcoin Segwit Transaction

为了了解有关比特币交易的更多信息,我正在研究二进制文件,并没有真正使用任何工具,如 BitcoinTx 或 Bitcoin-cli。无论如何,我在尝试签署隔离见证交易时遇到了一些障碍。现在这是一个简单的交易,一个 UTXO 和一个接收者,这是一个 P2WPKH 交易。

问题是,对于 segwit,我不知道在签署交易之前要在 SigScript 字段中输入什么。文档说它应该是空的,但这似乎不起作用。

02000000010a02214430acee2ed509798187210171bb387075ce2c82ef5a73774d6159387500000000 00 ffffffff
018ca1b404000000001976a914906ec1c4804632c0b067e5a2732c41cdf620c4e688ac0000000001000000

以上是原始交易,1个输入,1个输出。在 segwit 字段中,我有一个 0x00 字节,如图所示。所以,我 sha256(sha256) 上面的二进制文件,然后创建我的签名隔离见证交易如下:

020000000001010a02214430acee2ed509798187210171bb387075ce2c82ef5a73774d615938750000000017160014d99f1ea19e98d9ed10e5d442be37a44b76ffffc44b76b63 018ca1b404000000001976a914906ec1c4804632c0b067e5a2732c41cdf620c4e688ac 02 4830460221009f5743a2fc62bb9cee292ef79eb3ec3a20a3ed1ec84bdf9e8520592ca1d84f35022100922f887be7283eb0fd73da53efa554e62a589f6e268c0d300c2f727791 41047d011958b661181242addd300b6d5c51f80d62674555831dd855b34358b57e05fb46477ba167a57b23bf8a492305c0085d8c34aa04d483b7f15a2d5610=1e00[0ff60]

所以在上面,我得到了我的输入交易,在 SigScript 中我输入了 0,然后是 public 键的 20 字节 Hash160。

接下来,输出交易,它只有一个 public 键散列 OP_DUP, OP_HASH_160 OP_EQUALVERIFY, OP_CHECKSIG.

最后是签名,02 分为两部分,1 是签名本身(反编码),最后是 public 密钥。

出于某种原因,它说签名不正确,我不知道为什么。在我签名之前,交易中的 SigScript 实际上应该为 NULL 吗?在我签名之前,它是否应该是钱包的 public 密钥的 HASH160 有资金(就像它用于 P2PKH 交易)?

任何指点都将不胜感激,因为我认为我已经接近了,我只需要知道交易必须是什么样子,然后再签名。

您需要将 ScriptPubKey 放在 SigScript 字段上以进行签名。对椭圆曲线签名的字节顺序和低-高 R 和 S 规则要非常小心。

解释来自:https://bitcoin.stackexchange.com/posts/32695/edit

分步说明:

我们开始创建一个我们散列并签名的新交易。

  1. 添加四字节版本字段:01000000
  2. 指定输入数量的单字节 varint:01
  3. 我们要从中兑换输出的交易的 32 字节哈希值(倒序):be66e10da854e7aea9338c1f91cd489768d1d6d7189f586d7a3613f2a24d5396
  4. 四字节字段,表示我们要从具有上述哈希(从零开始计算)的交易中兑换的输出索引:00000000
  5. 现在是scriptSig。为了签署交易,这里临时填充了我们要兑换的输出的 scriptPubKey。首先,我们写一个单字节的 varint,表示 scriptSig 的长度(0x19 = 25 字节):19
  6. 然后我们编写实际的 scriptSig(这是我们要兑换的输出的 scriptPubKey):76 a9 14 dd6cce9f255a8cc17bda8ba0373df8e861cb866e 88 ac(查看 https://blockchain.info/tx/96534da2f213367a6d589f18d7d6d1689748cd911f8c33a9aee754a80de166be?show_adv=true 上的底线)
  7. 然后我们写一个四字节的字段来表示序列。当前始终设置为 0xffffffff:ffffffff
  8. 接下来是一个单字节的 varint,其中包含我们新交易中的输出数量。在本例中我们将其设置为 1:01
  9. 然后我们写入一个 8 字节字段(64 位整数,小端),其中包含我们要从指定输出中兑换的金额。我会将其设置为输出中可用的总金额减去 0.0001 BTC (128307 - 10000) 的费用:23ce010000000000
  10. 然后我们开始写交易的输出。我们从一个单字节的 varint 开始,表示输出脚本的长度(0x19 或 25 字节):19
  11. 然后实际输出脚本:76 a9 14 a2fd2e039a86dbcf0e1a664729e09e8007f89510 88 ac(这是将资金转回地址1FromKBPAS8MWsk1Yv1Yiu8rJbjfVioBHc)
  12. 然后我们写入四字节的"lock time"字段:00000000
  13. 最后,我们写了一个四字节的 "hash code type"(在我们的例子中是 1):01000000

好的,结果是

01000000
01
be66e10da854e7aea9338c1f91cd489768d1d6d7189f586d7a3613f2a24d5396
00000000
19 76 a9 14 dd6cce9f255a8cc17bda8ba0373df8e861cb866e 88 ac
ffffffff
01
23ce010000000000
19 76 a9 14 a2fd2e039a86dbcf0e1a664729e09e8007f89510 88 ac
00000000
01000000
  1. 现在我们对整个结构进行双重 SHA256 哈希,得到哈希 1cde0239b55717cca8003104abc2ec2673d4f6fabea0b74351940e382e88486f

  2. 现在我们应该创建 ECDSA 签名... 1MBngSqZbMydscpzSoehjP8kznMaHAzh9y"mrbubbymrbubbymrbubby!" 的脑钱包,它恰好编码了一个从 'MB' 开始的地址(使链接 2 变得非常容易;请参阅下面的@WizardOfAussie 评论以了解短语来源)。 WIF 中的私钥:5HvofFG7K1e2aeWESm5pbCzRHtCSiZNbfLYXBvxyA57DhKHV4U3

在十六进制中,私钥是0ecd20654c2e2be708495853e8da35c664247040c00bd10b9b13e5e86e6a808d。每个加密库中都有一个 sign (key, digest) 方法。它将 return 一个字节数组。这个数组不超过 72 个字节,以十六进制代码 30 开头。假设签名是 3046022100cf4d7571dd47a4d47f5cb767d54d6702530a3555726b27b6ac56117f5e7808fe0221008cbb42233bb04d7f28a715cf7c938e238afde90207e9d103dd9018e12cb7180e 对于这个签名,我们附加了一个字节的哈希码类型:01。 1MBngSqZbMydscpzSoehjP8kznMaHAzh9y 的 public 密钥是:042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9

  1. 我们通过连接构造最终的 scriptSig:<包含 DER 编码签名的长度加上一字节哈希代码类型的单字节脚本 OPCODE>|< 实际的 DER 编码签名加上一字节哈希码类型>|< 包含 public 密钥长度的单字节脚本 OPCODE>|<实际 public 密钥>

scriptSig 将是

49 3046022100cf4d7571dd47a4d47f5cb767d54d6702530a3555726b27b6ac56117f5e7808fe0221008cbb42233bb04d7f28a715cf7c938e238afde90207e9d103dd9018e12cb7180e 01
41 042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9

第一行是'push signature concatenated with 01',第二行是'push pubkey'。 scriptSig 的长度为 140 字节(十六进制为 0x8c)

  1. 然后我们用第 16 步的数据长度替换第 5 步的单字节 varint 长度字段。长度为 140 字节,或 0x8C 字节:8c

  2. 并且我们将实际的scriptSig替换为第16步中构建的数据结构。

  3. 我们通过 删除 我们在步骤 13 中添加的四字节哈希码类型来完成,我们最终得到以下字节流,是最终交易:

    01000000 01 be66e10da854e7aea9338c1f91cd489768d1d6d7189f586d7a3613f2a24d5396 00000000 8c 49 3046022100cf4d7571dd47a4d47f5cb767d54d6702530a3555726b27b6ac56117f5e7808fe0221008cbb42233bb04d7f28a715cf7c938e238afde90207de9cd18103 41 042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09db988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9 ffffffff 01 23ce010000000000 19 76 a9 14 a2fd2e039a86dbcf0e1a664729e09e8007f89510 88 交流电 00000000