Transaction 簽章的流程

徐粲邦
12 min readNov 5, 2016

--

在 Bitcoin 裡 transaction 分成 5 類,但跟上一篇提過 Gcoin 所謂的 7 種 transaction type 是不一樣的,Gcoin 的 7 種 transaction 是因為 Gcoin 為聯盟制架構,且擁有多貨幣功能的區塊鏈,導致在 transaction 的型態上可以有 7 種分類。而 Bitcoin 裡 transaction 的五個分類指的是 5 種 Standard transaction,這 5 個分類的依據則是因為 transaction script 的不同,所以 Gcoin 也享有這五個分類,而他們分別是 Pay-to-Public_Key_Hash (P2PKH) Pay-to-Public-Key (P2PK) Multi-Signature Pay-to-Script-Hash (P2SH) 和 Data Output (OP_RETURN),如果你想要了解這五種的差異,可以參考強者我同學做的筆記

而這篇我比較想要專注在 transaction 簽章的流程,會用最常見的 P2PKH 來當範例。

前言

還記得上一篇在拆解 transaction 的過程中有提過,在 transaction output 有一個 script 叫做 locking script,它的意義在於定義這個 output 可以被花掉的條件,而在 transaction input 有另一個 script 叫做 unlocking script,他的任務就是去滿足他要花掉的那個 output 的 locking script,一旦 input 的 unlocking script 經過驗證是符合上一筆 transaction output 的 locking script,這筆 transaction 才會被解鎖且認為是合法的。而最常見的 P2PKH transaction script 就長得像下圖這樣

在 Bitcoin script 裡,他們採用一種語言叫做 script language,他是一個 stack-based 的語言,從左向右執行,所以當你看到 Bitcoin script 時,不管是 locking script 還是 unlocking script,都建議搭配這個一起看才會知道這個 script 的動作到底是什麼,例如當我在 script 裡面出現 63,我就要對表知道他代表 OP_IF 這個動作。

現在我們回想一下上一篇的 raw transaction,locking script 的值長的像這樣

76a9149dd353a079ad3b149e00dcc9f6a62f399d3d1c8f88ac

透過 Bitcoin script 對照表我們就可以把它翻譯成

OP_DUP OP_HASH160 9dd353a079ad3b149e00dcc9f6a62f399d3d1c8f OP_EQUALVERIFY OP_CKECHSIG

會發現他跟上圖結構上長一樣了!但如果有看仔細你會發現 76a9 後面的 14 被我偷渡掉了,他在對照表上沒有實質的動作,他表明了接下來這麼多 bytes 會被放上去 stack,而 0x14 就是 20 bytes,所以接下來的 20 bytes 9dd353a079ad3b149e00dcc9f6a62f399d3d1c8f 才會是我的重點,在執行時會被放上去 stack,而這串就是上圖的 PubKHash,他其實就是 public key 去做 hash160 的結果,也可以從 address 推過去,另外因為這個 locking script 裡面含 public key,所以又稱為 scriptPubKey。而他的用處到底是什麼?以及為什麼 unlocking script 還長的跟上圖不一樣,等等會介紹。

簽名

transaction 的簽名意思就是我去把 input 的 unlocking script 換掉,換成可以滿足我要花掉的那個 output 的 locking script,所以可以預期做完之後,我們的 unlocking script 結構也要長的跟上圖一樣。還記得我們上一篇的 raw transaction 嗎?

01000000018eff490c3dac592caf4954ad1e142e6e8d8fbb427909bb18d7271e7d66dcf9d4000000001976a9149dd353a079ad3b149e00dcc9f6a62f399d3d1c8f88acffffffff0200e40b54020000001976a9144400e18b93766b106220343dbd37d4135501d6da88ac01000000003bbf15f08623001976a9149dd353a079ad3b149e00dcc9f6a62f399d3d1c8f88ac010000000000000000000000
  1. 首先我們先暫時的在 raw transaction 後面掛上 4 bytes 的 hash type code,一般的 transaction 來說都用 SIGHASH_ALL (0x00000001),要記得因為也是用 little endian 表示所以是 01000000
  2. 然後我們把整串 raw transaction 複製一份之後拿去做兩次 SHA256
  3. 接著把兩次 SHA256 的結果連同我自己的 private key 一起送去 ECDSA 簽名,會得到一個 signature
  4. 再來把 signature 後面再掛上 1 byte 的 hash code type,在這邊一樣是 01 的 SIGHASH_ALL
  5. 最後把上一步的 signature 連同我自己的 public key 去取代這個 raw transaction 原本的 input unlocking script,記得也要符合 script language,所以 signature 和 public key 前面都需要加他們的長度

步驟上看起來很少,但是第 3 步的 ECDSA 到底是怎麼簽名的?在這之前我們需要先回憶一下 public key 是怎麼產生的,Bitcoin 用的橢圓曲線是 secp256k1 如下圖

圖中的 G 為 generator point,在 Bitcoin 裡面是一個滿足此方程式的點

G * k = K

其中 k 為你的 private key,而產生的 K 就是你的 public key,而橢圓曲線的乘法如左邊顯示,所以可以知道其實 public key 也是曲線上的一個點,只是一般我們看到都是把他的兩個座標接在一起而已。

回到我們的 signature,他其實也是由 G 去乘上一個 k 所產生的一個座標,只是這個 k 並不只是 private key 了,他是由 private key 和傳進來的 message (兩次 SHA256 的 raw transaction) 和一個 random number 所組成的,因此要簽名一個 transaction 還是一定要有 private key 才能產生。

但如果要驗證 transaction 的 signature 是不是合法除了要有本來的 message 之外,則只需要用到 public key 就可以了,而 message 很容易可以再次創建一個,因為畢竟他只是一個空有 input output 的 raw transaction 在做兩次 sha256 而已,所以這就是為什麼我們的 unlocking script 是由 signature 和 public key 兩個所組成的就好,因為等等驗證 transaction 時並不需要其他的東西了。

ECDSA 詳細的內容我也沒有很懂,可能要問問數學系的了,或是看看這篇

總而言之,以下就是我們新的 unlocking script,他會用來取代舊的

上面拆解有幾個比較特別的地方,signature 和 public key 明明都是一個座標,但他們表示的方式竟然不一樣,signature 是用一個叫做 DER encoding 的方式來編碼,而 public key 就比較正常,但前面有一個 byte 的 type 要寫在前面。另外要注意 signature 後面也有掛一個 byte 的 hash type code,他並不是真正 signature 的一部分。

驗證

先來看一眼我們簽名過的 transaction 長什麼樣子

01000000018eff490c3dac592caf4954ad1e142e6e8d8fbb427909bb18d7271e7d66dcf9d4000000008b4830450221009227b2e4f8c36518049bafc88839c19c5597a7a5cfd1e133b84bd6ff8046c6c50220077fdcbb210f4361f20cbe4c056982a798b1d009c391a1447ccef11ea7a1675c0141046036a0a8f54895704ac5cba5b642153331bc2d13dda142665c6a501a606e2099a61d22d22a5cbe8c966672e2a353631f05014157ae37659238381b59bbbcce80ffffffff0200e40b54020000001976a9144400e18b93766b106220343dbd37d4135501d6da88ac01000000003bbf15f08623001976a9149dd353a079ad3b149e00dcc9f6a62f399d3d1c8f88ac010000000000000000000000

雖然感覺變長了,但仔細解析其實會發現只有 input 的 unlocking script 改過了,而真正的 unlocking script 是由一個 signature 和一個 public key 所組成,又稱為 scriptSig。現在我們的 transaction 已經準備好了,當我們一把它 broadcast 到網路上,就會進行 transaction 的驗證流程,一但驗證成功了,他就會被收到 block 裡面去,現在我們來看看驗證是怎麼進行的。

因為這筆 transaction 的 input 會記載著我是要花哪一個 transaction 的哪一個 output,所以就會去拿出那個 output 的 locking script,長得像這樣

OP_DUP OP_HASH160 9dd353a079ad3b149e00dcc9f6a62f399d3d1c8f OP_EQUALVERIFY OP_CHECKSIG

接著我們就要拿我們這筆 transaction 的 input unlocking script 去解鎖他,而我們的 unlocking script 長這樣

30450221009227b2e4f8c36518049bafc88839c19c5597a7a5cfd1e133b84bd6ff8046c6c50220077fdcbb210f4361f20cbe4c056982a798b1d009c391a1447ccef11ea7a1675c01 046036a0a8f54895704ac5cba5b642153331bc2d13dda142665c6a501a606e2099a61d22d22a5cbe8c966672e2a353631f05014157ae37659238381b59bbbcce80

其實就是兩個字串,分別是 signature 和 public key。接著記得上面提過 Bitcoin 的 script language 是一個 stack-based 的語言嗎?下面就是 stack 的操作,如果最後出來是對的,那就驗證成功代表我們可以花這筆錢,如果是錯的當然就會交易失敗。

  1. 將前一個 output 的 locking script 和我們 input 的 unlocking script 接在一起
  2. 把 signature 和 public key 都 push 到 stack 上
  3. 把 stack 頂部的東西複製一份,所以現在 stack 上又多了一個 public key
  4. 把剛剛複製的 public key 做 OP_HASH160,這邊要注意的是,如果你是自己在電腦上做驗證,要記得把 public key 從 hex 轉成 bytes 才能丟進去 HASH160,出來才會跟你看到的 pubKeyHash 長一樣
  5. 把原本 locking script 的 pubKeyHash 也 push 到 stack 上,並比較他和本來在 stack 上的 pubKeyHash 是否一樣,如果一樣就把他們兩個都 pop 出來繼續操作,但如果不一樣,就代表這個 locking script 根本不是你可以掌控的,也就是說你想要花的那個 output 根本不是你的錢,所以 transaction 驗證就會失敗
  6. 最後把 signature 和我們的 public key 拿去 ECDSA 驗證看看是不是符合,而前面提過,驗證 transaction 只需要 public key 就可以了

當以上的步驟都成功之後,transaction 的驗證也就完成了,雖然這長長的一個範例只有 P2PKH,但其實其他的概念上也差不多,有空也會再介紹其他的,或可以看看最上面我貼的強者我朋友的文章。

--

--