Solidity

來自 Geth 和 web3.eth.sign 的 ecrecover

  • July 31, 2019

我試圖用它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合約中進行前綴可能會更好,因為它會更便宜。

有關的

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