I'm trying to get a little example working with ECDSA.sol here: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol
This contract:
- Generate a random(ish) bytes32 (stub for a future message digest).
- Morph it into an EthSignedHash with
keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
- Use ecrecover to work out who signed a message.
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);
}
}
On the client side:
- Conjure up a random(ish) message.
- Make an ethHash of the message.
- Sign it.
- Send ethHash and the signature to ecRecover and get the signer address.
I'm not sure what I'm missing. I think the original message hash should be signed and EIP-712 does the "Ethereum Signing", so I should send the "Ethereum Hash" to ecrecover (as implemented in ECDSA.sol). In any case, no combination brings any joy.
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.");
});
});
I'd be very grateful if someone can sort me out.
Truffle v5.0.41 (core: 5.0.41)
Solidity - 0.5.8 (solc-js)
Node v8.10.0
Web3.js v1.2.1
Thanks!
Update
For anyone else who happens across this, this is the revised, passing test.
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.");
});
});
openzeppelin-solidity
is now@openzeppelin/contracts
. Also in environments like truffle, you can write your import as:import "@openzeppelin/contracts/cryptography/ECDSA.sol";
You don't need to specifynode_modules