Search code examples
solidityecdsa

how to use the ECDSA.sol module correctly?


I have this contract using the ECDSA library.

import "./ECDSA.sol";
struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }
function make(Signature memory sign) public returns(bool)

I try to understand the parameters I have to use in this case. What I can see it's a tuple type value, but I can't figure out what it looks like for v, r, s. Where can I get these values from my address?


Solution

  • The v, r, and s parameters are a result of signing a message with a private key. The signature has 65 bytes, which are split into 3 parts:

    65 byte array (of type bytes in Solidity) arranged the following way: [[v (1)], [r (32)], [s (32)]].

    Source: OpenZeppelin


    Sign off-chain (because you're using a private key).

    Note the address in the comment, we'll verify it on-chain later.

    const signature = await web3.eth.accounts.sign(
        'Hello world',
        // below is private key to the address `0x0647EcF0D64F65AdA7991A44cF5E7361fd131643`
        '02ed07b6d5f2e29907962d2bfde8f46f03c46e79d5f2ded0b1e0c27fa82f1384'
    );
    
    console.log(signature);
    

    Output

    {
        message: 'Hello world',
        messageHash: '0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede',
        v: '0x1c',
        r: '0x285e6fbb504b57dca3ceacc851a7bfa37743c79b5c53fb184f4cc0b10ebff6ad',
        s: '0x245f558fa13540029f0ee2dc0bd73264cf04f28ba9c2520ad63ddb1f2e7e9b24',
        signature: '0x285e6fbb504b57dca3ceacc851a7bfa37743c79b5c53fb184f4cc0b10ebff6ad245f558fa13540029f0ee2dc0bd73264cf04f28ba9c2520ad63ddb1f2e7e9b241c'
    }
    

    Note that v is the last byte of signature, r is the first half, and s is the second half (excluding the last byte).


    Verify on-chain

    pragma solidity ^0.8;
    
    import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol";
    
    contract MyContract {
        function foo() external pure returns (bool) {
            address recovered = ECDSA.recover(
                0x8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede, // messageHash
                0x1c, // v
                0x285e6fbb504b57dca3ceacc851a7bfa37743c79b5c53fb184f4cc0b10ebff6ad, // r
                0x245f558fa13540029f0ee2dc0bd73264cf04f28ba9c2520ad63ddb1f2e7e9b24 // s
            );
            
            return recovered == address(0x0647EcF0D64F65AdA7991A44cF5E7361fd131643);
        }
    }