1

我需要能够从合同中检索文档,让用户钱包对其进行签名,然后将其发送回合同并验证签名。

这是我让 address0 在客户端签名的方法:

   let message : string = "check this message signed by account0";
   let messageHash = keccak256(utils.toUtf8Bytes(message));
   let signature = await address0.signMessage(messageHash);
   await hm.connect(address0).verifyMessage(message, signature);

这是我合同中的验证器:

   function verifyMessage(string memory message, 
      bytes memory signature) 
      public view  returns(bool) {
      
        //hash the plain text message
        bytes32 messagehash =  keccak256(bytes(message));
        //hash the prefix and messagehash together   
        bytes32 messagehash2 = keccak256(abi.encodePacked("\x19Ethereum Signed Messsage:\n32", messagehash));
        //extract the signing contract address
        address signeraddress = ECDSA.recover( messagehash2, signature);
        if (msg.sender==signeraddress) {
            //The message is authentic
            return true;
        } else {
            //msg.sender didnt sign this message.
            return false;
        }
    }

遗憾的是,ECDSA.recover 为 signeraddress 返回的值不是 account0 的地址,尽管经过大量实验,我仍无法从签名中得出消息发送者的正确地址。

将不胜感激任何指针。

4

1 回答 1

1

我能够从 Openzeppelin 上的人们那里得到答案。

万一任何其他机构遇到这种情况,一个问题是计算哈希和在客户端计算签名的方式

代替

   let messageHash = keccak256(utils.toUtf8Bytes(message));

利用

    let messageHash = ethers.utils.solidityKeccak256(['string'], [message]);

而不是

    let signature = await address0.signMessage(messageHash);

利用

     let signature = await address0.signMessage(ethers.utils.arrayify(messageHash));

在服务器端,可以使用 `ECDSA.toEthSignedMessageHash() 更简单地添加前缀,如下面的解决方案所示:

using ECDSA for bytes32; 

function verifyMessage(string memory message, bytes memory signature) public view  returns(address, bool) {
        //hash the plain text message
        bytes32 messagehash =  keccak256(bytes(message));
       
        address signeraddress = messagehash.toEthSignedMessageHash().recover(signature);
              
        if (msg.sender==signeraddress) {
            //The message is authentic
            return (signeraddress, true);
        } else {
            //msg.sender didnt sign this message.
            return (signeraddress, false);
        }
    }
  

    
于 2021-10-15T20:02:26.897 回答