Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Amxx committed Jun 17, 2024
1 parent a44bb71 commit 3a6e1f5
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 41 deletions.
4 changes: 2 additions & 2 deletions contracts/utils/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ library Errors {
error FailedDeployment();

/**
* @dev A necessary EIP/RIP is missing on the current network.
* @dev A necessary precompile is missing.
*/
error MissingEIP(uint256);
error MissingPrecompile(address);
}
41 changes: 14 additions & 27 deletions contracts/utils/cryptography/P256.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ library P256 {
uint256 private constant P1DIV4 = 0x3fffffffc0000000400000000000000000000000400000000000000000000000;

/**
* @dev Verifies a secp256r1 signature using the EIP-7212 or RIP-7212 precompiles and falls back to the Solidity
* implementation if the precompile is not available. This version should work on all chains, but requires the
* deployment of more bytecode.
* @dev Verifies a secp256r1 signature using the RIP-7212 precompile and falls back to the Solidity implementation
* if the precompile is not available. This version should work on all chains, but requires the deployment of more
* bytecode.
*
* @param h - hashed message
* @param r - signature half R
Expand All @@ -50,61 +50,48 @@ library P256 {
* @param qy - public key coordinate Y
*/
function verify(uint256 h, uint256 r, uint256 s, uint256 qx, uint256 qy) internal view returns (bool) {
(bool valid, bool supported) = tryVerifyPrecompile(h, r, s, qx, qy);
(bool valid, bool supported) = tryVerify7212(h, r, s, qx, qy);
return supported ? valid : verifySolidity(h, r, s, qx, qy);
}

/**
* @dev signature verification - using EIP-7212 and RIP-7212 precompiles. This version will only work on chains
* that have one of these precompile available. On chains that do not have these precompile, this function reverts.
* @dev signature verification - using the RIP-7212 precompile. This version will only work on chains that have
* the precompile available. This function will revert on networks that do not have this precompile.
*
* @param h - hashed message
* @param r - signature half R
* @param s - signature half S
* @param qx - public key coordinate X
* @param qy - public key coordinate Y
*/
function verifyPrecompile(uint256 h, uint256 r, uint256 s, uint256 qx, uint256 qy) internal view returns (bool) {
(bool valid, bool supported) = tryVerifyPrecompile(h, r, s, qx, qy);
function verify7212(uint256 h, uint256 r, uint256 s, uint256 qx, uint256 qy) internal view returns (bool) {
(bool valid, bool supported) = tryVerify7212(h, r, s, qx, qy);
if (supported) {
return valid;
} else {
revert Errors.MissingEIP(7212);
revert Errors.MissingPrecompile(address(0x100));
}
}

/**
* @dev try signature verification - using EIP-7212 and RIP-7212 precompiles. This function does not revert is the
* required precompiles are missing. Instead it will return with `supported = false`.
* @dev try signature verification - using the RIP-7212 precompiles. This function does not revert is the required
* precompile is missing. Instead it will return with `supported = false`.
*
* @param h - hashed message
* @param r - signature half R
* @param s - signature half S
* @param qx - public key coordinate X
* @param qy - public key coordinate Y
*/
function tryVerifyPrecompile(
function tryVerify7212(
uint256 h,
uint256 r,
uint256 s,
uint256 qx,
uint256 qy
) internal view returns (bool valid, bool supported) {
bytes memory params = abi.encode(h, r, s, qx, qy);

// try using EIP-7212 precompile at 0x0B
(bool success, bytes memory returndata) = address(0x0B).staticcall(params);
if (success && returndata.length == 0x20) {
return (abi.decode(returndata, (bool)), true);
}

// try using RIP-7212 precompile at 0x100
(success, returndata) = address(0x100).staticcall(params);
if (success && returndata.length == 0x20) {
return (abi.decode(returndata, (bool)), true);
}

return (false, false);
(bool success, bytes memory returndata) = address(0x100).staticcall(abi.encode(h, r, s, qx, qy));
return (success && returndata.length == 0x20) ? (abi.decode(returndata, (bool)), true) : (false, false);
}

/**
Expand Down
24 changes: 12 additions & 12 deletions test/utils/cryptography/P256.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ describe('P256', function () {
it('verify valid signature', async function () {
expect(await this.mock.$verify(this.messageHash, ...this.signature, ...this.publicKey)).to.be.true;
expect(await this.mock.$verifySolidity(this.messageHash, ...this.signature, ...this.publicKey)).to.be.true;
await expect(this.mock.$verifyPrecompile(this.messageHash, ...this.signature, ...this.publicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingEIP')
.withArgs(7212);
await expect(this.mock.$verify7212(this.messageHash, ...this.signature, ...this.publicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingPrecompile')
.withArgs('0x0000000000000000000000000000000000000100');
});

it('recover public key', async function () {
Expand All @@ -50,18 +50,18 @@ describe('P256', function () {
const reversedPublicKey = Array.from(this.publicKey).reverse();
expect(await this.mock.$verify(this.messageHash, ...this.signature, ...reversedPublicKey)).to.be.false;
expect(await this.mock.$verifySolidity(this.messageHash, ...this.signature, ...reversedPublicKey)).to.be.false;
await expect(this.mock.$verifyPrecompile(this.messageHash, ...this.signature, ...reversedPublicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingEIP')
.withArgs(7212);
await expect(this.mock.$verify7212(this.messageHash, ...this.signature, ...reversedPublicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingPrecompile')
.withArgs('0x0000000000000000000000000000000000000100');
});

it('reject signature with flipped signature values ([r,s] >> [s,r])', async function () {
const reversedSignature = Array.from(this.signature).reverse();
expect(await this.mock.$verify(this.messageHash, ...reversedSignature, ...this.publicKey)).to.be.false;
expect(await this.mock.$verifySolidity(this.messageHash, ...reversedSignature, ...this.publicKey)).to.be.false;
await expect(this.mock.$verifyPrecompile(this.messageHash, ...reversedSignature, ...this.publicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingEIP')
.withArgs(7212);
await expect(this.mock.$verify7212(this.messageHash, ...reversedSignature, ...this.publicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingPrecompile')
.withArgs('0x0000000000000000000000000000000000000100');
expect(await this.mock.$recovery(this.messageHash, this.recovery, ...reversedSignature)).to.not.deep.equal(
this.publicKey,
);
Expand All @@ -74,9 +74,9 @@ describe('P256', function () {
const invalidMessageHash = ethers.hexlify(ethers.randomBytes(32));
expect(await this.mock.$verify(invalidMessageHash, ...this.signature, ...this.publicKey)).to.be.false;
expect(await this.mock.$verifySolidity(invalidMessageHash, ...this.signature, ...this.publicKey)).to.be.false;
await expect(this.mock.$verifyPrecompile(invalidMessageHash, ...this.signature, ...this.publicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingEIP')
.withArgs(7212);
await expect(this.mock.$verify7212(invalidMessageHash, ...this.signature, ...this.publicKey))
.to.be.revertedWithCustomError(this.mock, 'MissingPrecompile')
.withArgs('0x0000000000000000000000000000000000000100');
expect(await this.mock.$recovery(invalidMessageHash, this.recovery, ...this.signature)).to.not.deep.equal(
this.publicKey,
);
Expand Down

0 comments on commit 3a6e1f5

Please sign in to comment.