Solidity
Solidity ecrecover 和 web3j Sign.signMessage() 不兼容,是嗎?
使用 Web3j 簽名和驗證消息很好,但是當我使用 Web3j 生成的簽名來驗證使用ecrecover時,它似乎無法正常工作。執行solidity程式碼時簽名者地址不同。
在尋找解決方案時,我發現較新的 geth 版本會在簽名時添加字元串“\x19Ethereum Signed Message:\n32”。
此處參考:完全被 ecrecover 困惑
我嘗試使用參考問題中的解決方案,但它似乎不起作用。我的問題是 Web3j 有什麼不同?任何熟悉 Web3j 的人都可以為我提供消息簽名和驗證的工作範例嗎?
這是我正在處理的契約的簡化版本:
pragma solidity ^0.4.0; contract Auth { string public name; function Auth(){ name = "Auth 1.0"; } function verify(bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) constant returns (address) { address signer = ecrecover(_message, _v, _r, _s); return signer; } function verifyWithPrefix(bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) constant returns (address) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = sha3(prefix, _message); address signer = ecrecover(prefixedHash, _v, _r, _s); return signer; } }
這是使用 Web3j 的 java 程式碼。
// Message to sign String plainMessage = "hello world"; byte[] hexMessage = Hash.sha3(plainMessage.getBytes()); // Use java to sign and verify the signature Sign.SignatureData signMessage = Sign.signMessage(hexMessage, ALICE.getEcKeyPair()); String pubKey = Sign.signedMessageToKey(hexMessage, signMessage).toString(16); String signerAddress = Keys.getAddress(pubKey); System.out.println("Signer address : 0x"+ signerAddress); // Now use java signature to verify from the blockchain Bytes32 message = new Bytes32(hexMessage); Uint8 v = new Uint8(signMessage.getV()); Bytes32 r = new Bytes32(signMessage.getR()); Bytes32 s = new Bytes32(signMessage.getS()); String address = contract.verify(message, v, r, s).get().getValue().toString(16); String address2 = contract.verifyWithPrefix(message, v, r, s).get().getValue().toString(16); System.out.println("Recovered address1 : 0x"+address); System.out.println("Recovered address2 : 0x"+address2);
問題實際上是雙重雜湊。
看 Web3j 的 signMessage() 方法
Sign.SignatureData sig =Sign.signMessage(messageBytes, ecKeyPair);
和 signedMessageToKey() 方法
String pubKey = Sign.signedMessageToKey(messageBytes, sig).toString(16);
這些方法在簽名和驗證之前在內部散列(sha3)輸入消息字節。當使用 Web3j 本身生成和驗證兩個簽名時,這可以正常工作。但這使得 Web3j 的簽名不同於從 geth 的 sign() 方法獲得的簽名。
這是一個修改了 Web3j 的 Sign.java 文件的公共要點,可用於避免雙重雜湊問題: https ://gist.github.com/xoriole/4c2a9630dba5a20ee28fb58edf193375