0

I got a problem with keccak hashing.

The Goal:

  1. A Server should create a parameter list and a sign. (I try it here with just one uint256 parameter)
  2. 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.

1 Answer 1

0

Just found out by myself... Here the answer if someone stuck at the same problem:

ethers.utils.hashMessage() 

Can take a string or binary datas... from Doc(https://docs.ethers.io/v5/api/utils/hashing/):

NOTE: It is important to understand how strings and binary data is handled differently. A string is ALWAYS processed as the bytes of the string, so a hexstring MUST be converted to an ArrayLike object first.

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:

const messageHashBinary = ethers.utils.arrayify(message0);
const hash0 = ethers.utils.hashMessage(messageHashBinary);

In that way I get the same hash in solidity an js.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.