Solidity
來自 Geth 和 web3.eth.sign 的 ecrecover
我試圖用它
ecrecover()
來驗證消息的簽名。我在這里和其他地方查看了很多參考資料,例如:
和別的。
但我仍然無法
ecrecover()
返回簽名地址。所以我希望有人能指出我犯的一些愚蠢的錯誤。這是我的程式碼:
pragma solidity ^0.4.0; contract test { function test() { } function verify(bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) constant returns (address) { address signer = ecrecover(_message, _v, _r, _s); return signer; } }
然後在geth,我這樣做:
> var msg = web3.sha3("hello") "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8" > eth.accounts[0] --> "0x7156526fbd7a3c72969b54f64e42c10fbb768c8a" > var sig = eth.sign(eth.accounts[0], msg) "0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac80388256084f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada1c" > var r = sig.substr(0,66) "0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608" > var s = "0x" + sig.substr(66,64) "0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada" > var v = 28 28 > test.verify(msg,v,r,s) "0x33692ee5cbf7ecdb8ca43ec9e815c47f3db8cd11"
…當然,不是
eth.accounts[0]
我完全被難住了。有沒有人可以看到我做錯了什麼?
我也被這個問題困擾了很長時間。
所以解決方案是:將此前綴字元串添加到您的 Solidity 智能合約中。
function verify(bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(bool) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = keccak256(prefix, hash); return ecrecover(prefixedHash, v, r, s) == (Your Address); }
根據問題 #3731:
Geth
\x19Ethereum Signed Message:\n<length of message>
在簽名之前將字元串添加到所有數據中(https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign)。如果您想從 Solidity 驗證這樣的簽名,則必須在進行 ecrecovery 之前在solidity 中添加相同的字元串。這是我使用truffle測試的一個工作範例:
例子.sol
pragma solidity ^0.4.0; contract Example { function testRecovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) returns (address) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = sha3(prefix, h); address addr = ecrecover(prefixedHash, v, r, s); return addr; } }
example.js(測試)
var Example = artifacts.require('./Example.sol') var Web3 = require('web3') var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')) contract('Example', (accounts) => { var address = accounts[0] it('ecrecover result matches address', async function() { var instance = await Example.deployed() var msg = '0x8CbaC5e4d803bE2A3A5cd3DbE7174504c6DD0c1C' var h = web3.sha3(msg) var sig = web3.eth.sign(address, h).slice(2) var r = `0x${sig.slice(0, 64)}` var s = `0x${sig.slice(64, 128)}` var v = web3.toDecimal(sig.slice(128, 130)) + 27 var result = await instance.testRecovery.call(h, v, r, s) assert.equal(result, address) }) })
執行測試:
$ truffle test Using network 'development'. Compiling ./contracts/Example.sol... Contract: Example ✓ ecrecover result matches address (132ms) 1 passing (147ms)
在應用程序級別而不是在solidity合約中進行前綴可能會更好,因為它會更便宜。
有關的