比特幣中P2PKH(pay-to-public-key-hash)的鎖定腳本和解鎖腳本

腳本格式

P2PKH的鎖定腳本爲:java

OP_DUP OP_HASH160 PUSHDATA(<Cafe Public Key Hash>) OP_EQUALVERIFY OP_CHECKSIG

P2PKH的解鎖腳本爲:git

PUSHDATA(<Cafe Signature>) <Cafe Public Key>

腳本參數解釋

腳本中的常量值

OP_DUP=0x76
OP_HASH160=0xA9
OP_EQUALVERIFY=0x88
OP_CHECKSIG=0xAC

PUSHDATA

PUSHDATA封裝格式爲:github

若是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) + SIGHASHjson

DER的封裝格式

DER是ASN1數據格式中的一種,DER的封裝規則尚未搞太明白,可是數據結構可解,開頭是固定值0x30,後面0x45爲後續數據長度,0x0220或者0x022100後面就是簽名值r和s。
DER的java代碼實現:api

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標誌類型,只有在你考慮到由許多參與者在比特幣網絡以外共同協做去更新僅部分簽署了的交易,才具備意義。ide

有三個SIGHASH標誌:ALL,NONE和SINGLE,以下表所示。測試

signhash-flag

另外還有一個修飾符標誌SIGHASH_ANYONECANPAY,它能夠與前面的每一個標誌組合。 當設置ANYONECANPAY時,只有一個輸入被簽名,其他的(及其序列號)打開以進行修改。 ANYONECANPAY的值爲0x80,並經過按位OR運算,獲得以下所示的組合標誌:3d

signhash-flag2 png

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

tx912d

經過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

相關文章
相關標籤/搜索