Skip to content

Commit

Permalink
improve usage code (#21)
Browse files Browse the repository at this point in the history
* improve usage code

* review comment rename
  • Loading branch information
nalinbhardwaj authored Oct 8, 2023
1 parent 402e7b4 commit 024caa5
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 7 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
id: build
- run: |
forge test -vv
forge coverage --ir-minimum --report lcov
forge test -vv --fork-url "https://base-goerli.publicnode.com"
forge coverage --ir-minimum --report lcov --fork-url "https://base-goerli.publicnode.com"
git diff --exit-code
id: test
Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,24 @@ The secp256r1 elliptic curve, aka P256, is used by high-quality consumer enclave

Available on any chain. If missing, see `deploy.sh`.

Install with:
- `forge install daimo-eth/p256-verifier`
- add `p256-verifier/=lib/p256-verifier/src/` to remappings.txt

```solidity
import "p256-verifier/P256.sol";
bytes32 hash; // message hash
uint256 r, s; // signature
uint256 x, y; // public key
address verifier = 0xc2b78104907F722DABAc4C69f826a522B2754De4;
bytes memory args = abi.encode(hash, r, s, x, y);
(bool success, bytes memory ret) = verifier.staticcall(args);
assert(success); // never reverts, always returns 0 or 1
bool valid = abi.decode(ret, (uint256)) == 1;
bool valid = P256.verifySignature(hash, r, s, x, y);
```

Alternately, calling `P256.verifySignatureAllowMalleability` ignores
malleability of signatures, matching the behavior specified by the NIST standard
exactly.

## Development

Run `foundryup` to ensure you have the latest foundry. Then,
Expand Down
24 changes: 24 additions & 0 deletions lcov.info
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
TN:
SF:src/P256.sol
FN:10,P256.verifySignatureAllowMalleability
FNDA:3,P256.verifySignatureAllowMalleability
DA:17,3
DA:18,3
DA:19,3
BRDA:19,0,0,-
BRDA:19,0,1,-
DA:21,3
FN:28,P256.verifySignature
FNDA:2,P256.verifySignature
DA:36,2
BRDA:36,1,0,1
BRDA:36,1,1,1
DA:37,1
DA:40,1
FNF:2
FNH:2
LF:7
LH:7
BRF:4
BRH:2
end_of_record
TN:
SF:src/P256Verifier.sol
FN:26,P256Verifier.
FNDA:2567,P256Verifier.
Expand Down
42 changes: 42 additions & 0 deletions src/P256.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

/**
* Helper library for external contracts to verify P256 signatures.
**/
library P256 {
address constant VERIFIER = 0xc2b78104907F722DABAc4C69f826a522B2754De4;

function verifySignatureAllowMalleability(
bytes32 message_hash,
uint256 r,
uint256 s,
uint256 x,
uint256 y
) public view returns (bool) {
bytes memory args = abi.encode(message_hash, r, s, x, y);
(bool success, bytes memory ret) = VERIFIER.staticcall(args);
assert(success); // never reverts, always returns 0 or 1

return abi.decode(ret, (uint256)) == 1;
}

/// P256 curve order n/2 for malleability check
uint256 constant P256_N_DIV_2 =
57896044605178124381348723474703786764998477612067880171211129530534256022184;

function verifySignature(
bytes32 message_hash,
uint256 r,
uint256 s,
uint256 x,
uint256 y
) public view returns (bool) {
// check for signature malleability
if (s > P256_N_DIV_2) {
return false;
}

return verifySignatureAllowMalleability(message_hash, r, s, x, y);
}
}
58 changes: 58 additions & 0 deletions test/P256.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {Test, console2} from "forge-std/Test.sol";
import {stdJson} from "forge-std/StdJson.sol";
import {P256} from "../src/P256.sol";
import {P256Verifier} from "../src/P256Verifier.sol";

contract P256Test is Test {
uint256[2] public pubKey;

function setUp() public {
pubKey = [
0x65a2fa44daad46eab0278703edb6c4dcf5e30b8a9aec09fdc71a56f52aa392e4,
0x4a7a9e4604aa36898209997288e902ac544a555e4b5e0a9efef2b59233f3f437
];
}

function testMalleable() public {
// Malleable signature. s is > n/2
uint256 r = 0x01655c1753db6b61a9717e4ccc5d6c4bf7681623dd54c2d6babc55125756661c;
uint256 s = 0xf073023b6de130f18510af41f64f067c39adccd59f8789a55dbbe822b0ea2317;

bytes32 hash = 0x267f9ea080b54bbea2443dff8aa543604564329783b6a515c6663a691c555490;

bool res = P256.verifySignatureAllowMalleability(
hash,
r,
s,
pubKey[0],
pubKey[1]
);
assertEq(res, true);

res = P256.verifySignature(hash, r, s, pubKey[0], pubKey[1]);
assertEq(res, false);
}

function testNonMalleable() public {
// Non-malleable signature. s is <= n/2
uint256 r = 0x01655c1753db6b61a9717e4ccc5d6c4bf7681623dd54c2d6babc55125756661c;
uint256 s = 7033802732221576339889804108463427183539365869906989872244893535944704590394;

bytes32 hash = 0x267f9ea080b54bbea2443dff8aa543604564329783b6a515c6663a691c555490;

bool res = P256.verifySignatureAllowMalleability(
hash,
r,
s,
pubKey[0],
pubKey[1]
);
assertEq(res, true);

res = P256.verifySignature(hash, r, s, pubKey[0], pubKey[1]);
assertEq(res, true);
}
}

0 comments on commit 024caa5

Please sign in to comment.