web3, secp256k1簽名與Solidity驗籤

買賣虛擬貨幣
現在個好像越來約多Dapp用到鏈下簽名,可以設計多步驟、需要不同私鑰簽署同意之後一起上鍊給智慧合約驗證執行。其中有名的例子包含了許多去中心化交易所使用的0xProtocal,個人覺得是個非常聰明的設計,這裡就記錄一下自己試著用web3玩玩鏈下簽名的心得。web3簽名其實雖說簽名的過程就是把一段訊息加上私鑰進行 ECDSA簽名,但其實在Ethereum世界裡的簽名還加了一個小規則,就是要在要簽名的message在Hash之前,還要在前面加上一小段prefix:message= "\x19Ethereum Signed Message:\n" + message.length + message

在web3提供好給我們的 sign 函式( web3.eth.accounts.sign )當中,就已經包含了上述步驟。直接看web3.eth.accounts.sign程式程式碼比較好懂:

簡單的使用方法如下:把要進行簽章的string ( orderHash)直接連同 privateKey 丟進函示就好。

其實是丟進去簽名的 orderHash 要不要先轉換成為 bytes 都可以,出來的結果會是相同的。 sign 函式回傳的結果會包含 message 、 messageHash 以及 r s v 三個橢圓簽名結果。其中message是原來我想要簽名的內容( orderHash), messageHash 則是程式中自動幫我們加上prefix,並且進行Sha3 Hash的結果,也就是真正被拿去用私鑰簽名的一段Hash值。

簡而言之web3什麼都幫你做好了,不要像我一樣傻傻的自己想辦法加prefix最後才發現做了兩次。

secp256k1 簽名

那麼如果我們想要單純用私鑰簽名一段資料,不要有Ethereum定義的那些prefix的話,就必須要直接呼叫 secp256k1 這一包library了。不過在用之前要知道,所有要丟給secp256k1簽名的message,長度都必須是256 bits,也就是32 bytes。剛剛我們說web3的簽名函式丟什麼都可以,是因為它會幫我加上prefix之後再做sha3 Hash (keccak),最後一定會變成一個32bytes的東西。如果我們自己純靠私要簽名訊息的話,也勢必要先透過這個函式來整理input長度。我在這裡舉個例子,手動作上面web3的 sign 幫我們包好的流程,也就是自己以符合Ethereum協議的方法做一遍,比較方便我們驗證結果。

所以一開始我們可以透過 soliditySha3 來把prefix跟 orderHash 混在一起然後進行hash,這一段的結果會跟上面產出的 messageHash 相同,也等同於在Solidity裡面使用keccak:

keccak256("\x19Ethereum Signed Message:\n32", hash)

得到這串「要簽名的hash」之後,在丟進secp256k1之前,要先轉成bytes (長度會為32),存入buffer,然後才能進行簽名。若是直接用string的話,會發生 message length is invalid 的錯誤。同理,用來簽名的 privateKey 也要轉換成Buffer才行。

使用 secp256k1 回傳的物件裡還需要自己解析出r , s ,v 三個元素,不過我是直接複製貼上web3裡面包的做法。

所以說,如果自己使用 secp256k1 來簽名的話,可以略過加上prefix那一段,未來在智慧合約上驗章也可以少一段,不過還是需要使用到 keccak 來進行雜湊就是了。

Solidity驗籤

好不容易簽好名當然就是要來線上驗簽了。Solidity上面驗籤很簡單,只要使用 ercrecover 這個function就可以了。我們讓 hash 是一個 bytes32 的數,套用我們前面的例子,就是最原始的 orderHash 值。而 v ,r ,s 則是驗簽結果:

bytes32 hash
uint8 v
bytes32 r
bytes32 s

那麼下面這個函式就應該回傳我們所用來簽名的public Key。注意到這裡會使用 keccak256 來把 hash加上ETH規定的prefix ,我們很常可以在合約中看到這段文字,因為web3預設的簽名就要這樣來還原。當然,如果想要設計沒有用prefix的,那麼這一步就省了。

ecrecover(
   keccak256("\x19Ethereum Signed Message:\n32", hash),
   v, r, s
);

可以試試看到我deploy的合約上直接call這兩個函示玩玩看結果:
Ropsten 地址:0x209ce2886420b27e497ce343e59574166400f1ab

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;