驗證簽名數據
我正忙於嘗試使用 ecrecover() 恢復地址。在向契約提供簽名數據時,我無法恢復正確的地址。
我正在測試的契約如下所示:
pragma solidity ^0.4.24; contract VerifyTest { // https://ethereum.stackexchange.com/a/15911 function verifyMessage(bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) private view returns (bool) { bytes memory hashPrefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = keccak256(abi.encodePacked(hashPrefix, messageHash)); return ecrecover(prefixedHash, v, r, s) == msg.sender; } function testBuyOrder(uint256 orderTotal, address tokenContract, uint8 v, bytes32 r, bytes32 s) public view returns (bool) { bytes32 messageHash = keccak256(abi.encodePacked(orderTotal, tokenContract)); return verifyMessage(messageHash, v, r, s); } }
編譯後,將生成以下 ABI 對象:
[ { "constant": true, "inputs": [ { "name": "orderTotal", "type": "uint256" }, { "name": "tokenContract", "type": "address" }, { "name": "v", "type": "uint8" }, { "name": "r", "type": "bytes32" }, { "name": "s", "type": "bytes32" } ], "name": "testBuyOrder", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ]
我可以
testBuyOrder()
使用下面的一小段 Javascript 成功呼叫該函式:// Trying to keep it concise; assume we have a functioning web3 instance... const signTestAddr = "[ADDRESS_OF_DEPLOYED_CONTRACT]"; const signTestABI = [...]; // ABI quoted above... testSignMessage = () => { console.log(web3.version.api); let tokenAddr = "0x128Df2a07Dc41E034bD9a3CEaddDc0341250a6C8"; let verifyTest = web3.eth.contract(signTestABI).at(signTestAddr); let orderTotal = web3.fromDecimal(100000000); console.log(orderTotal); let testHash = web3.sha3(orderTotal + tokenAddr); signHashedMessage(testHash, (error, signature) => { if(error === null) { signature = signature.substring(2); let r = '0x' + signature.substring(0, 64); let s = '0x' + signature.substring(64, 128); let v = '0x' + signature.slice(128, 130); let vDec = parseInt(v, 16); // Call the function on our contract here... verifyTest.testBuyOrder(100000000, tokenAddr, vDec, r, s, (testErr, result) => { if(testErr === null) { console.log("Success: " + result); } else { console.log("Error: " + testErr); } }); } else { console.log("error: " + error); } }) };
上面 javascript 的輸出是:
0.20.3 0x5f5e100 Success: false
上面的程式碼成功呼叫了合約,但是我不明白為什麼呼叫
testBuyOrder()
總是返回false。**Edit0:**此外,我為看似重複的問題道歉,但我試圖應用其他人的答案的智慧無濟於事。
編輯1:
Ismael 的第一個建議是在合約本身中包含散列函式,這將確保數據在散列之前被正確連接和格式化。Ismael 的函式必須稍作修改才能獲得要簽名的正確雜湊值。
該功能的工作解決方案如下:
function getMessageHash(uint256 orderTotal, address tokenContract) public pure returns (bytes32) { bytes memory hashPrefix = "\x19Ethereum Signed Message:\n32"; bytes32 messageHash = keccak256(abi.encodePacked(orderTotal, tokenContract)); return keccak256(abi.encodePacked(hashPrefix, messageHash)); }
編輯2:
在探索了 Web3 v1.0 的使用之後,我仍然在努力恢復合約中的發件人地址。
我更新的客戶端程式碼如下所示:
signHashedMessage = (messageHash, callback) => { web3.eth.getCoinbase().then((coinbase) => { web3.eth.sign(prefixHashedData(messageHash), coinbase, callback); }); }; prefixHashedData = (messageHash) => { let msgPrefix = "\x19Ethereum Signed Message:\n32"; return web3.utils.soliditySha3(msgPrefix, messageHash); }; testSignMessage = () => { let verifyTest = new web3.eth.Contract(signTestABI, signTestAddr); let tokenAddr = "0x128Df2a07Dc41E034bD9a3CEaddDc0341250a6C8"; let orderTotal = 100000000; let testHash = web3.utils.soliditySha3(orderTotal, tokenAddr); signHashedMessage(testHash, (error, signature) => { if(error === null) { signature = signature.substring(2); let r = '0x' + signature.substring(0, 64); let s = '0x' + signature.substring(64, 128); let v = '0x' + signature.slice(128, 130); let vDec = parseInt(v, 16); // Call the function on our contract here... let testBuyOrderRes = verifyTest.methods.testBuyOrder(orderTotal, tokenAddr, vDec, r, s); testBuyOrderRes.call((callError, callResult) => { if (callError === null) { console.log("Verified: " + callResult); } else { console.log("Error: " + callError); } }); } else { console.log("error: " + error); } }); };
為了完整展示我的工作,我添加了
signHashedMessage()
和。prefixHashedMessage()
為了驗證
prefixHashedData()
,我getMessageHash()
在我的契約中添加瞭如上所述的 。呼叫getMessageHash()
返回的雜湊值與使用web.utils.soliditySha3()
Ismael 所描述的返回值相同。我在上面的 Web3 v1.0 程式碼中遇到的新問題;在驗證合約上的簽名時,通過呼叫
testBuyOrder()
,函式返回false
.誰能看到我犯的錯誤?
您發送給合約的消息與您在 javascript 中編碼的消息
orderTotal + tokenAddr
不同,與abi.encodePacked(orderTotal, tokenContract)
.要麼使用您在契約中使用的相同功能。
function getMessageHash(uint256 orderTotal, address tokenContract) public pure returns (bytes32) { bytes32 messageHash = keccak256(abi.encodePacked(orderTotal, tokenContract)); returnmessageHash; }
並從 javascript 呼叫它
verifyTest.getMessageHash(orderTotal, tokenAddr)
。另一種選擇是從 web3 v1.0 呼叫soliditysha3,它將正確格式化數據。