Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for EIP2098 "short signatures" in the ECDSA library #2539

Closed
Amxx opened this issue Feb 24, 2021 · 2 comments · Fixed by #2582
Closed

Add support for EIP2098 "short signatures" in the ECDSA library #2539

Amxx opened this issue Feb 24, 2021 · 2 comments · Fixed by #2582
Labels
contracts Smart contract code. idea

Comments

@Amxx
Copy link
Collaborator

Amxx commented Feb 24, 2021

🧐 Motivation
Secp256k1 signatures produced by EOA to sign transaction and messages are usually encode on 65 bytes:

  • R: 32 bytes
  • S: 32 bytes
  • V: 1 bytes.

However, the V parameter can be reduced to only one single bit, and the S parameter only requiers 255 bits to be encoded (due to parity constraints). This result in the signature space fitting inside 64 bytes! EIP2098 describes how to pack the R,S,V values into a shorter R,VS format tat would take less space and thus me less expensive to transmit/store

Ethers.js already include tooling to produce such signatures.

📝 Details
EIP details are available here.
Implementation in the ECDSA only requires to accept 65 & 64 bytes long signatures, split them into R,S,V values, and call the recover method. Since the changes that only in the "bytes unpacking" part of the function, and the actual cryptography check done in ECDSA.recover are not modified or bypassed, there should be no security concern.

function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
    // Divide the signature in r, s and v variables
    bytes32 r;
    bytes32 s;
    uint8 v;

    // Check the signature length
    // - case 65: r,s,v signature (standard)
    // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098)
    if (signature.length == 65) {
        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }
    } else if (signature.length == 64) {
        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := and(mload(add(signature, 0x40)), 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            v := add(shr(7, byte(0, mload(add(signature, 0x40)))), 27)
        }
    } else {
        revert("ECDSA: invalid signature length");
    }

    return recover(hash, v, r, s);
}
@Amxx Amxx added contracts Smart contract code. idea labels Feb 24, 2021
@frangio
Copy link
Contributor

frangio commented Feb 24, 2021

Are there any downsides to this signature encoding?

@Amxx
Copy link
Collaborator Author

Amxx commented Feb 25, 2021

Apart from it not being the default anywhere ... I can't see any.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contracts Smart contract code. idea
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants