He intentado utilizar ecrecover()
para verificar la firma de un mensaje.
He mirado muchas referencias aquí y en otros lugares, como:
y otros.
Pero todavía no puedo ecrecover()
devolver la dirección de firma. Así que espero que alguien pueda señalar algún error estúpido que estoy cometiendo.
Aquí está mi código:
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;
}
}
Luego en geth, hago:
> 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"
...que por supuesto, NO eseth.accounts[0]
Estoy totalmente perplejo. ¿Hay alguien que pueda ver lo que estoy haciendo mal?
También estuve atascado en este tema durante mucho tiempo.
Entonces, la solución es: agregue esta cadena de prefijo a su contrato inteligente de 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);
}
32
al final del prefix
corresponde a la longitud del mensaje! github.com/ethereum/wiki/wiki/JSON-RPC#eth_signAdd this prefix string to your Solidity smart contract
y en caso de que no controle el contrato inteligente ?Según el número 3731 :
Geth antepone la cadena
\x19Ethereum Signed Message:\n<length of message>
a todos los datos antes de firmarlos ( https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign ). Si desea verificar dicha firma de Solidity, deberá anteponer la misma cadena en solidity antes de realizar la ecrecovery.
Aquí hay un ejemplo de trabajo que probé usando truffle :
Ejemplo.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;
}
}
ejemplo.js (prueba)
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)
})
})
Prueba de carrera:
$ truffle test
Using network 'development'.
Compiling ./contracts/Example.sol...
Contract: Example
✓ ecrecover result matches address (132ms)
1 passing (147ms)
Probablemente sea mejor hacer el prefijo en el nivel de la aplicación en lugar de en el contrato de solidez, ya que será más económico.
Relacionado
Entonces, gracias a Adil (ver arriba), aquí está el código terminado que utilicé que definitivamente funciona con el proceso como lo describí anteriormente:
solidez de pragma ^0.4.0; prueba de contrato { prueba de funcionamiento() { } función verificar(bytes32 _mensaje, uint8 _v, bytes32 _r, bytes32 _s) devoluciones constantes (dirección) { prefijo de memoria de bytes = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = sha3(prefijo, _mensaje); firmante de la dirección = ecrecover(prefixedHash, _v, _r, _s); firmante de retorno; } }
v+27
en su lugar. github.com/ethereum/go-ethereum/issues/2053v+27
falla donde lo he visto, pero alguien lo usa por alguna razón¿Está seguro de que está utilizando los tipos de datos correctos? Creé una aplicación de validación simple usando ecrecover hace unas semanas.
Puede ver el código aquí: https://github.com/Shultzi/validator/blob/master/client/main.js
Como puede ver, pasé el h
, r
y s
no como buffers
sino un hex
. Además, asegúrese de que en su contrato inteligente el v
valor seauint8
El siguiente artículo puede explicar la parte "\x19EthereumSignedMessage"
https://blog.ricmoo.com/verificando-mensajes-en-solidez-50a94f82b2ca
ECDSA de OpenZeppelin tiene una herramienta para generar estos mensajes envueltos, así como eliminar casos de esquina adicionales en ECDSA.
Escribí un artículo describiendo lo que creo que es la forma correcta de usar hashMessage() y sign() de web3, ecrecover() de Solidity y ECDSA lib de Open Zeppelin.
https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/cryptography/ECDSA.sol
https://medium.com/@yaoshiang/ethereums-ecrecover-openzeppelin-s-ecdsa-and-web3-s-sign-8ff8d16595e1
Verde en línea
usuario53765
shane fontaine
Nicolás Massart