Solidity
在solidity中驗證使用web3生成的簽名
我正在嘗試驗證我在松露測試中生成的可靠簽名。我按照本教程 實施智能合約,但做了一些小的調整:
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");
希望能幫助到你。