Solidity

Solidity ecrecover 和 web3j Sign.signMessage() 不兼容,是嗎?

  • October 4, 2018

使用 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

引用自:https://ethereum.stackexchange.com/questions/17708