web3, secp256k1 簽章與Solidity驗章

Anton Cheng
Sep 5, 2018 · 5 min read

現在個好像越來約多Dapp用到鏈下簽章,可以設計多步驟、需要不同私鑰簽署同意之後一起上鏈給智能合約驗證執行。其中有名的例子包含了許多去中心化交易所使用的0x Protocal,個人覺得是個非常聰明的設計,這裡就記錄一下自己試著用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程式碼比較好懂:

GitHub連結

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

其實是丟進去簽章的 orderHash 要不要先轉換成為 bytes 都可以,出來的結果會是相同的。 sign 函數回傳的結果會包含 messagemessageHash 以及 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),最後一定會變成一個32 bytes的東西。如果我們自己純靠私要簽章訊息的話,也勢必要先通過這個函式來整理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

小結

雖然整理下來很簡單,但是我可是花了好多時間才豁然開朗原來web3這麼雞婆。總之感覺是很多人可能遇到的問題,就整理一波吧~

Anton Cheng

Written by

Develop a passion for learning. If you do, you will never cease to grow. — Anthony J. D’Angelo

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade