Estoy tratando de obtener un pequeño ejemplo trabajando con ECDSA.sol aquí: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol
Este contrato:
keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
pragma solidity 0.5.8;
import "../../node_modules/openzeppelin-solidity/contracts/cryptography/ECDSA.sol";
contract Sigs {
using ECDSA for bytes32;
function rndHash() public view returns(bytes32) {
return keccak256(abi.encodePacked(block.number));
}
function ethSignedHash(bytes32 messageHash) public pure returns(bytes32) {
return messageHash.toEthSignedMessageHash();
}
function recover(bytes32 hash, bytes memory signature) public pure returns(address) {
return hash.recover(signature);
}
}
Del lado del cliente:
No estoy seguro de lo que me estoy perdiendo. Creo que el hash del mensaje original debe estar firmado y EIP-712 realiza la "Firma de Ethereum", por lo que debo enviar el "Ethereum Hash" a ecrecover (como se implementa en ECDSA.sol). En cualquier caso, ninguna combinación trae alegría.
var Sigs = artifacts.require("./Junk/Sigs");
contract("Sigs", accounts => {
var signer;
beforeEach(async () => {
signer = accounts[0];
sigs = await Sigs.new({from: signer});
});
it("should recover signer address.", async () => {
console.log("SIGNER: ", signer);
var random = await sigs.rndHash({from: signer});
var ethHash = await sigs.ethSignedHash(random);
// four possible combinations tried for the next step :/
var signature = await web3.eth.sign(random, signer); // sign the random hash or the ethHash
var recovered = await sigs.recover(ethHash, signature); // recover from the random hash or the ethHash
console.log("random1: ", random);
console.log("signature: ", signature);
console.log("recovered: ", recovered);
assert.strictEqual(recovered, signer, "The recovered signature does not match the signer.");
});
});
Agradecería mucho si alguien me puede solucionar.
Truffle v5.0.41 (core: 5.0.41)
Solidity - 0.5.8 (solc-js)
Node v8.10.0
Web3.js v1.2.1
¡Gracias!
Actualizar
Para cualquier otra persona que se encuentre con esto, esta es la prueba aprobada revisada.
const Sigs = artifacts.require("./Junk/Sigs");
const EthCrypto = require("eth-crypto");
contract("Sigs", accounts => {
var signer;
beforeEach(async () => {
signer = accounts[0];
sigs = await Sigs.new({from: signer});
});
it("should recover signer address.", async () => {
console.log("SIGNER: ", signer);
var message = "0x1234";
console.log("message: ", message);
var msgHash = await sigs.messageHash(message);
var ethHash = await sigs.ethSignedHash(msgHash);
var signature = await web3.eth.sign(msgHash, signer); // sign the mesage hash
signature = signature.substr(0, 130) + (signature.substr(130) == "00" ? "1b" : "1c"); // v: 0,1 => 27,28
var recovered = await sigs.recover(ethHash, signature); // recover from the ethHash
console.log("msgHash: ", msgHash);
console.log("ethHash: ", ethHash);
console.log("signature: ", signature);
console.log("recovered: ", recovered);
assert.strictEqual(recovered, signer, "The recovered signature does not match the signer.");
});
});
El problema es que eth.sign
devuelve una firma donde v
es 0 o 1 y ecrecover
espera que sea 27 o 28.
Una nota en la documentación de web3 v0.20 es clara:
Tenga en cuenta que si está utilizando
ecrecover
,v
será"00"
o"01"
. Como resultado, para usar este valor, tendrá que analizarlo en un número entero y luego agregar27
. Esto dará como resultado un27
o un28
.
tienes que hacer algo como esto
var signature = await web3.eth.sign(random, signer); // sign the random hash or the ethHash
signature = signature.substr(0, 130) + (signature.substr(130) == "00" ? "1b" : "1c");
var recovered = await sigs.recover(ethHash, signature); // recover from the random hash or the ethHash
Rob, veo que ya lo resolviste (lo cual es genial).
Para futuros lectores:
Para Contratos OpenZeppelin puede consultar la documentación para más información, en este caso la sección Criptografía: https://docs.openzeppelin.com/contracts/2.x/utilities#cryptography
Las pruebas para los contratos pueden ser útiles, en este caso ECDSA.test.js: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/cryptography/ECDSA.test.js
Hay un tutorial sobre cómo iniciar sesión en el foro: https://forum.openzeppelin.com/t/sign-it-like-you-mean-it-creating-and-verifying-ethereum-signatures/697
Si tiene preguntas sobre el uso de OpenZeppelin, también puede preguntar en el Foro de la comunidad: https://forum.openzeppelin.com/
Divulgación: soy el administrador de la comunidad en OpenZeppelin
buena vibración
abcoathup
openzeppelin-solidity
es ahora@openzeppelin/contracts
. También en entornos como la trufa, puede escribir su importación como:import "@openzeppelin/contracts/cryptography/ECDSA.sol";
No necesita especificarnode_modules
abcoathup