Solidity

在solidity中驗證使用web3生成的簽名

  • May 2, 2021

我正在嘗試驗證我在松露測試中生成的可靠簽名。我按照本教程 實施智能合約,但做了一些小的調整:

library Lib {

   /**
       Signature verification functions
    */
   function getMessageHash(address _to) public pure returns (bytes32) {
       return keccak256(abi.encodePacked(_to));
   }

   function getEthSignedMessageHash(bytes32 _messageHash) public pure returns (bytes32) {
       /*
       Signature is produced by signing a keccak256 hash with the following format:
       "\x19Ethereum Signed Message\n" + len(msg) + msg
       */
       return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
   }

       function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature)
       public pure returns (address)
   {
       (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);

       return ecrecover(_ethSignedMessageHash, v, r, s);
   }

   function splitSignature(bytes memory sig) public pure returns (bytes32 r, bytes32 s, uint8 v) {
       require(sig.length == 65, "invalid signature length");

       assembly {
           /*
           First 32 bytes stores the length of the signature

           add(sig, 32) = pointer of sig + 32
           effectively, skips first 32 bytes of signature

           mload(p) loads next 32 bytes starting at the memory address p into memory
           */

           // first 32 bytes, after the length prefix
           r := mload(add(sig, 32))
           // second 32 bytes
           s := mload(add(sig, 64))
           // final byte (first byte of the next 32 bytes)
           v := byte(0, mload(add(sig, 96)))
       }

       // implicitly return (r, s, v)
   }

   function verify(address _signer, address _to, bytes memory signature) public pure returns (bool) {
       bytes32 messageHash = getMessageHash(_to);
       bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);

       return recoverSigner(ethSignedMessageHash, signature) == _signer;
   }

}

contract MyContract{

   address public myaddr;
   ...

   function submitSignature(bytes memory signature) signerCheck public {
       if(Lib.verify(myaddr, address(this), signature)){ // returns false
           mysignature = signature;
           ...
       }else{
           revert("Signature does not match sender.");
       }
   }

}

在我的松露測試中,我創建的簽名如下:

var hash = MyContract.web3.extend.utils
           .soliditySha3({v: mycontract.address,  t: 'address' });

var prefixedHash = MyContract.web3.extend.utils.soliditySha3("\x19Ethereum Signed Message:\n32", hash);
var signature = await MyContract.web3.eth.sign(prefixedHash, accounts[1], (error, result) => {
  if (error) {
     console.log(error)
  }
});
var tx = await mycontract.submitSignature(signature, { from: accounts[1] });

verify函式返回假。我不完全確定solidity如何散列地址以及是否web3.eth.sign為簽名添加前綴\x19Ethereum Signed Message:\n。我嘗試了不同的變化,沒有任何效果。

更新: web3.eth.sign已經前置\x19Ethereum Signed Message:\n,所以正確的簽名是

var hash = MyContract.web3.extend.utils
           .soliditySha3({v: mycontract.address,  t: 'address' });

var signature = await MyContract.web3.eth.sign(prefixedHash, accounts[1]);});
signature = signature.substr(0, 130) + (signature.substr(130) == "00" ? "1b" : "1c");

看看這個:Sign message with web3 and verify with openzeppelin-solidity ECDSA.sol

注意這個小切換器:

signature = signature.substr(0, 130) + (signature.substr(130) == "00" ? "1b" : "1c");

希望能幫助到你。

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