腳本格式
P2PKH的鎖定腳本為:
OP_DUP OP_HASH160 PUSHDATA(<Cafe Public Key Hash>) OP_EQUALVERIFY OP_CHECKSIG
P2PKH的解鎖腳本為:
PUSHDATA(<Cafe Signature>) <Cafe Public Key>
腳本參數解釋
腳本中的常量值
OP_DUP=0x76
OP_HASH160=0xA9
OP_EQUALVERIFY=0x88
OP_CHECKSIG=0xAC
PUSHDATA
PUSHDATA封裝格式為:
如果0 < data.length < 76(0x4C),則結果為:1個字節data.length + data數據
如果76(0x4C) <= data.length < 2^8,則結果為:0x4C + 1個字節data.length + data數據
如果2^8 <= data.length < 2^16,則結果為:0x4D + 2個字節data.length + data數據
如果2^16 <= data.length < 2^32,則結果為:0x4E + 4個字節data.length + data數據
Signature的格式
Signature的格式為DER(r,s) + SIGHASH
DER的封裝格式
DER是ASN1數據格式中的一種,DER的封裝規則還沒有搞太明白,但是數據結構可解,開頭是固定值0x30,后面0x45為后續數據長度,0x0220或者0x022100后面就是簽名值r和s。
DER的java代碼實現:
private static byte[] toDER(BigInteger r, BigInteger s) {
ByteArrayOutputStream bos = new ByteArrayOutputStream(72);
DERSequenceGenerator seq = null;
byte[] res = new byte[0];
try {
seq = new DERSequenceGenerator(bos);
seq.addObject(new ASN1Integer(r));
seq.addObject(new ASN1Integer(s));
seq.close();
res = bos.toByteArray();
return res;
} catch (IOException e) {
}
return null;
}
SIGHASH
SIGHASH是簽名哈希類型。
比特幣簽名具有指示交易數據的哪一部分包含在使用 SIGHASH 標志的私鑰簽名的哈希中的方式。SIGHASH 標志是附加到簽名的單個字節。 每個簽名都有一個SIGHASH標志,該標志在不同輸入之間也可以不同。 具有三個簽名輸入的交易可以具有不同SIGHASH標志的三個簽名,每個簽名簽署(承諾)交易的不同部分。
記住,每個輸入可能在其解鎖腳本中包含一個簽名。 因此,包含多個輸入的交易可以擁有具有不同SIGHASH標志的簽名,這些標志在每個輸入中承諾交易的不同部分。 還要注意,比特幣交易可能包含來自不同“所有者”的輸入,他們在部分構建(和無效)的交易中可能僅簽署一個輸入,繼而與他人協作收集所有必要的簽名后再使交易生效。 許多SIGHSASH標志類型,只有在你考慮到由許多參與者在比特幣網絡之外共同協作去更新僅部分簽署了的交易,才具有意義。
有三個SIGHASH標志:ALL,NONE和SINGLE,如下表所示。
另外還有一個修飾符標志SIGHASH_ANYONECANPAY,它可以與前面的每個標志組合。 當設置ANYONECANPAY時,只有一個輸入被簽名,其余的(及其序列號)打開以進行修改。 ANYONECANPAY的值為0x80,並通過按位OR運算,得到如下所示的組合標志:
SIGHASH標志在簽名和驗證期間應用的方式是建立交易的副本和刪節其中的某些字段(設置長度為零並清空),繼而生成的交易被序列化,SIGHASH標志被添加到序列化交易的結尾,並將結果哈希化 ,得到的哈希值本身即是被簽名的“消息”。 基於SIGHASH標志的使用,交易的不同部分被刪節。 所得到的哈希值取決於交易中數據的不同子集。 在哈希化前,SIGHASH作為最后一步被包含在內,簽名也會對SIGHASH類型進行簽署,因此不能更改(例如,被礦工)。
Public Key
Public Key有兩種表示方式,分別是非壓縮格式和壓縮格式,這兩種方式算出來的比特幣地址不同,所以不能混用。
壓縮格式就是數據中只有公鑰的X,沒有Y。壓縮公鑰以0x21開頭,0x02或0x03代表Y值在X軸的上方還是下方,后面是X點的數據(32 bytes)。示例:
21 03 0b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478
非壓縮格式的數據,開頭是0x41,0x04,后面緊跟着X點的數據(32 bytes)和Y點的數據(32 bytes)。示例:
41 04
0bf69616981e5970c992a0762f441abcadfed9fc4630fa5e1b82ab00e81d1690 // X
5d3820e073e1bd4a9dcfed336f4bf25edc634c2e174989767d299748359c2daf // Y
示例
比特幣testnet的一筆交易示例:912d470a1178ac09e31c43ee5696138fc51e94c7834864ed5c8eff29e5f54370
通過blockcypher的API接口可以拿到更加詳細的JSON數據
這筆交易的JSON返回數據:
{
"block_hash": "000000003b5f089b739219d8f40ec34ca66b051c627cbb8e5d7a3dd031ff47d2",
"block_height": 1298300,
"block_index": 1,
"hash": "912d470a1178ac09e31c43ee5696138fc51e94c7834864ed5c8eff29e5f54370",
"hex": "010000000184f3684abd720033ff7a7654b48936088cd22c8d9e96d3a12e64559562e0fd93000000006b483045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d20121030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478ffffffff0100a92d01000000001976a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac00000000",
"addresses": [
"mv24N7xJZySdMrLeQHvKTJYWmRyv9DY82Q",
"n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8"
],
"total": 19769600,
"fees": 134400,
"size": 192,
"preference": "high",
"relayed_by": "35.205.92.62:18333",
"confirmed": "2018-05-22T03:22:51Z",
"received": "2018-05-22T03:18:51.259Z",
"ver": 1,
"double_spend": false,
"vin_sz": 1,
"vout_sz": 1,
"confirmations": 1,
"confidence": 1,
"inputs": [
{
"prev_hash": "93fde0629555642ea1d3969e8d2cd28c083689b454767aff330072bd4a68f384",
"output_index": 0,
"script": "483045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d20121030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478",
"output_value": 19904000,
"sequence": 4294967295,
"addresses": [
"mv24N7xJZySdMrLeQHvKTJYWmRyv9DY82Q"
],
"script_type": "pay-to-pubkey-hash",
"age": 1298299
}
],
"outputs": [
{
"value": 19769600,
"script": "76a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac",
"addresses": [
"n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8"
],
"script_type": "pay-to-pubkey-hash"
}
]
}
解析交易中的hex原始數據(如何解析比特幣中的交易原始數據rawData):
01000000 // version,4字節,倒序
01 // 輸入腳本個數
84f3684abd720033ff7a7654b48936088cd22c8d9e96d3a12e64559562e0fd93 // UTXO(Unspent Transaction Output,未花費的交易輸出),倒序
00000000 // UTXO的index,從0開始
6b // 解鎖腳本長度
48 3045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d201 21030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478 // 解鎖腳本
ffffffff // sequence,序列號
01 // 輸出腳本個數
00a92d0100000000 // 轉賬金額,8字節,倒序
19 // 鎖定腳本長度
76a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac // 鎖定腳本
00000000 // lock time,時間戳
這是一筆普通地址轉賬給普通地址的交易,正好用來解釋P2PKH的鎖定腳本和解鎖腳本。
鎖定腳本
例子中,鎖定腳本為:
76a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac // 鎖定腳本
對照鎖定腳本的格式,可以解析這段腳本如下:
// OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG
76 // OP_DUP
a9 // OP_HASH160
14 // 公鑰的HASH值的長度,PUSHDATA
d9c637cc30bb0fe9add3a185c1f5d884d12b7b78 // 公鑰的HASH值
88 // OP_EQUALVERIFY
ac // OP_CHECKSIG
公鑰HASH值的計算方法
按常理來說,公鑰HASH值計算方法是拿到公鑰的byte數據做SHA256,再做RIPEMD160計算,結果為20字節HASH值。
但是這里做的是轉賬,輸入項肯定只有轉賬地址n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8
。因為地址就是公鑰的HASH值再加入一個頭的network type和最后的四個字節checkSum后做base58生成的,所以可以反向操作:
將比特幣地址n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8
進行base58解碼,得到:6fd9c637cc30bb0fe9add3a185c1f5d884d12b7b783bcba0fb
,其中0x6f
代表是測試網絡地址。將上面的結果去掉一字節頭和尾部4字節校驗和,得到:d9c637cc30bb0fe9add3a185c1f5d884d12b7b78
,即為公鑰HASH值
解鎖腳本
例子中,解鎖腳本為:
48 3045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d201 21030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478 // 解鎖腳本
將解鎖腳本按照PUSHDATA的規則解析成兩個字段:
Signature=483045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d201
Public Key=21030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478
解析一下Signature:
48 // PUSHDATA
3045022100
ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d // signature r
0220
70a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d2 // signature s
01 // SIGHASH
解析一下Public Key:
// 壓縮格式的公鑰
21 03 0b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478