0

In Ethers.js i am signing a message which I want to recover in Solidity using the ECDSA library from openzeppeling, I have one version which works but when I try the same method in which the parameters are arrays I do not get the correct address recovered.

1) The Working Version (Signing a message without uint256 arrays)

In ethers.js

    // Test single sign
    let message1 = ethers.utils.solidityPack(
        ["uint256","uint256","uint256"],
        [ 1,2,123456789]
    );

    message1 = ethers.utils.solidityKeccak256(["bytes"], [message1]);
    const signature1 = await mintData.signer.signMessage(ethers.utils.arrayify(message1));
    const testSignature1 = await collection.testSignature1(1,2,signature1);
    console.log('Verify hash: ', message1, testSignature1);

Recover in Solidity:

    function testSignature1(
        uint256 param1,
        uint256 param2,
        bytes memory _signature
    )
        public
        view
        returns ( bytes32 msgHash )
    {
        uint256 nonce = 123456789;
        
        bytes32 msgHash = keccak256(
            abi.encode(
                param1,
                param2,
                nonce
            )
        );
        address signer = msgHash.toEthSignedMessageHash().recover(_signature);
        console.log("signer: ", signer);
        return msgHash;
    }

The above code recovers the correct signer.

2) The non working Version (Signing a message with uint256 arrays)

In ethers.js

    let message2 = ethers.utils.solidityPack(
        [
            "uint256[]",
            "uint256[]",
            "uint256"
        ],
        [
            [1,1],
            [2,2],
            123456789
        ]
    );

    message2 = ethers.utils.solidityKeccak256(["bytes"], [message2]);
    console.log("signer: ", signer);
    const signature2 = await mintData.signer.signMessage(ethers.utils.arrayify(message2));
    const testSignature2 = await collection.testSignature2(1,2,signature2);
    console.log('Verify hash: ', message2, testSignature2);

Solidity:

      function testSignature2(
           bytes memory _signature,
           uint256[] memory param1,
           uint256[] memory param2
    )
        public
        view
        returns ( bytes32 msgHash )
    {   
        uint256 nonce = 123456789;
        
        bytes32 msgHash = keccak256(
            abi.encode(
                param1,
                param2,
                nonce
            )
        );
        address signer = msgHash.toEthSignedMessageHash().recover(_signature);
        console.log("signer: ", signer);
        return msgHash;
    }

The second method does not recover the correct signer address in solidity and I cannot figure out why. With Ethers.js I can recover the correct address with:

 ethers.utils.verifyMessage(message2,signature2));

Also the hash that is generated from ethers.js and the solidityPack with keccak256 in solidity are the same, as per below console output:

Verify hash:  0x086e3fc9b14f58aca90fb67e71e7f5c3bf1fc5a971488c7681eda8620848f651 0x086e3fc9b14f58aca90fb67e71e7f5c3bf1fc5a971488c7681eda8620848f651
Verify hash:  0x80b1d198523e1dd6e131e71dc5c53d3af997775699592708dde607e4c69d5720 0x086e3fc9b14f58aca90fb67e71e7f5c3bf1fc5a971488c7681eda8620848f651
2
  • You're calling collection.testSignature1 and not collection.testSignature2 in the second example. Is that a typo?
    – 0xSanson
    Commented Nov 15, 2022 at 23:41
  • Thank you for pointing that out @0xSanson, it still was not working but I figured out that the has is not the same with my second method, I found the resolution though and will post the answer.
    – 0xFlem
    Commented Nov 16, 2022 at 8:31

1 Answer 1

1

Found the problem, the hashes were not the same (Corrected the mistake pointed out by @OxSanson) and I found out that in order to get the same hash and verify I had to change the way I am encoding the variables in Solidity.

Instead of using abi.encode I used abi.encodePacked instead:

bytes32 msgHash = keccak256(
            abi.encodePacked(
                param1,
                param2,
                nonce
            )
        );
1
  • The only drawback from what I have read is that encodePacked can cause a hash collision for dynamic types, would the dynamic uint256[] arrays I use be considered a dynamic type and could using encodePacked in my example open a security vulnerability ?
    – 0xFlem
    Commented Nov 16, 2022 at 13:26

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.