I got a problem with keccak hashing.
The Goal:
- A Server should create a parameter list and a sign. (I try it here with just one uint256 parameter)
- The Contract should check if the sign fits with the parameter list (Thats why I need to create the message in the contract again – it is not enough to check if the signer is correct for the given signiture)
… I do not get the correct hash from: "keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", inputHash)"
Test:
it("Test Sign", async function () {
accounts = await hre.ethers.getSigners();
deployer = accounts[1]
const SignTest = await ethers.getContractFactory("SignTest");
const iSignTest = await SignTest.connect(deployer).deploy();
await iSignTest.deployed();
const strInput = "Test"//
console.log("test_String: ", strInput)
const amount = ethers.BigNumber.from("1")
console.log("test_amount: ", amount)
const message0 = utils.keccak256(
utils.defaultAbiCoder.encode(["uint256"], [amount])
)
// const message1 = utils.keccak256(
// utils.defaultAbiCoder.encode(["uint256","string"], [amount,strInput])//
// )
const hash0 = ethers.utils.hashMessage(message0)
// const hash1 = ethers.utils.hashMessage(message1)
var sig0 = await deployer.signMessage(message0);
// var sig1 = await deployer.signMessage(message1);
console.log("test_message0: ", message0)
console.log("test_hash0: ", hash0)
// console.log("test_message0-type: ", typeof message0)
// console.log("test_message0-type: ", typeof message0)
// console.log("test_message0: ", message0)
// console.log("test_message1: ", message1)
// console.log("test_premessage0: ", hash0)
// console.log("test_premessage1: ", hash1)
// console.log("test_sig0: ", sig0)
// console.log("test_sig1: ", sig1)
var toProve = await iSignTest.test(amount, strInput, message0, sig0, hash0)
console.log("Signer: ", deployer.address)
const breakdown = utils.splitSignature(sig0)
// console.log("Sig breakdown: ", utils.splitSignature(sig))
});
Contract:
contract SignTest {
// using ECDSA for bytes32;
address owner = msg.sender;
mapping(uint256 => bool) usedNonces;
function test(uint256 amount, string memory inpStr, bytes32 checkMsg, bytes memory sig0, bytes32 inpHash) public returns(address) {
bytes32 msg0 = keccak256(abi.encodePacked(amount));
console.log("msg");
console.logBytes32(msg0);
require(msg0 == checkMsg, "Wrong msg0");
bytes32 prefixed = perfixTest(msg0);
require(inpHash == prefixed, "Wrong prefix");
address signer = recoverSigner(msg0,sig0);
console.log("Signer: ", signer);
return address(0);
}
function perfixTest(bytes32 inputHash) internal view returns(bytes32) {
bytes32 shouldBe = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", inputHash));
bytes32 t0 = keccak256(abi.encodePacked("\x19Ethereum Signed Message:", inputHash));
bytes32 t1 = keccak256(abi.encodePacked("\x19Ethereum Signed Message:32", inputHash));
bytes32 t2 = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", inputHash));
bytes32 t3 = keccak256(abi.encodePacked("\x19Ethereum Signed Message:32\n", inputHash));
bytes32 t4 = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", inputHash));
bytes32 t5 = keccak256(abi.encodePacked("\x19Ethereum Signed Message", inputHash));
bytes32 t6 = keccak256(abi.encodePacked("\x19Ethereum Signed Message32", inputHash));
bytes32 t7 = keccak256(abi.encodePacked("\x19Ethereum Signed Message\n32", inputHash));
bytes32 t8 = keccak256(abi.encodePacked("\x19Ethereum Signed Message32\n", inputHash));
bytes32 t9 = keccak256(abi.encodePacked("\x19Ethereum Signed Message\n", inputHash));
bytes32 t10 = keccak256(abi.encodePacked("\x19", inputHash));
console.log("shouldBe");
console.logBytes32(shouldBe);
console.log("t0");
console.logBytes32(t0);
console.log("t1");
console.logBytes32(t1);
console.log("t2");
console.logBytes32(t2);
console.log("t3");
console.logBytes32(t3);
console.log("t4");
console.logBytes32(t4);
console.log("t5");
console.logBytes32(t5);
console.log("t6");
console.logBytes32(t6);
console.log("t7");
console.logBytes32(t7);
console.log("t8");
console.logBytes32(t8);
console.log("t9");
console.logBytes32(t9);
console.log("t10");
console.logBytes32(t10);
return shouldBe;
}
...
}
The Output:
SignTest
test_String: Test
test_amount: BigNumber { value: "1" }
test_message0: 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
test_hash0: 0x83e1e609f6e437e4b1b0b8f55f889d630f6e370c7822706b6f01b2021b80023e
msg
0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
shouldBe
0x3774a77bfb45a273febe88cfa6a2e064f33bda3d273ffd1789c83de39d861cda
t0
0x824943dde35e6711106f370b125e24dd0575b7515156591fe2826580dadfb545
t1
0x6010d0d77e4ef38b121f73450f88d9ead35733c6466906167d9db82fd47a5a1c
t2
0x3774a77bfb45a273febe88cfa6a2e064f33bda3d273ffd1789c83de39d861cda
t3
0x8636027d0098a1d8bffb9850456a6843561d8f999eb32b6504a06e43de270826
t4
0xe4a070576f45c577b0bc5bfba5cc0f7a5e58eefb087b5ff0ca8573443f95d4ef
t5
0x96d81a91ffdf8855859535927e389489daea3b0d1a4ad194aa8bc5f48ed05570
t6
0x6f032e9e6e063263446d4850fc00d5181dadbd2ed827d7a0555b8828e52f2766
t7
0x3c1c58823ced9e929caecc6af5926d61f1cf399c55b92d4a144dfad849a67a12
t8
0x040ebab1408207f4ab4c4a17f93314e4173f2e7ceac8ec3e5817f4ec1fbc8b9a
t9
0xb6d16314cd28df003f74eb15434c464faaf56a631011e69de3b0d228f9575784
t10
0x92260e8161838b56f23e51ce7147f3b76f4865d18708f7c0dc0dd6e6f000f96b
1) Test Sign
0 passing (4s)
1 failing
1) SignTest
Test Sign:
Error: VM Exception while processing transaction: reverted with reason string 'Wrong prefix'...
In my world… the way to set the "shouldBe" variable should be the same hash as the output of "test_hash0" … But it is not …
Hope someone can help.
Best Answer
Just found out by myself... Here the answer if someone stuck at the same problem:
Can take a string or binary datas... from Doc(https://docs.ethers.io/v5/api/utils/hashing/):
So ethers can use a string and solidtiy (as far as I unserstand) use a bytes32 array.
utils.keccak() returns a string. So I had to cast that string to an bytes (bytes 32 in my case) with:
In that way I get the same hash in solidity an js.