diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 534c185..2ed5c1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,8 @@ env: jobs: test: runs-on: ubuntu-latest + env: + FOUNDRY_GAS_LIMIT: 10000000000 steps: - uses: actions/checkout@v3 with: @@ -23,11 +25,11 @@ jobs: - run: | forge --version - forge build --sizes + forge build --via-ir --sizes id: build - run: | - forge test -vv + forge test --via-ir -vv forge coverage --ir-minimum --report lcov git diff --exit-code id: test diff --git a/README.md b/README.md index e808fbb..01e5110 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Our implementation was inspired by [Renaud Dubois/Ledger's FCL library](https:// 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 @@ -33,7 +34,7 @@ uint256 x, y; // public key bool valid = P256.verifySignature(hash, r, s, x, y); ``` -Alternately, calling `P256.verifySignatureAllowMalleability` ignores +Alternately, calling `P256.verifySignatureAllowMalleability` ignores malleability of signatures, matching the behavior specified by the NIST standard exactly. @@ -51,7 +52,7 @@ Run `foundryup` to ensure you have the latest foundry. Then, ``` git clone --recurse-submodules git@github.com:daimo-eth/p256-verifier cd p256-verifier -forge test -vv +forge test --via-ir -vv ``` This runs test input and output handling as well as all applicable Wycheproof @@ -87,7 +88,7 @@ npm test # Validate that all vectors also work with EIP-7212 # Test the fallback contract... cd .. -forge test -vv +forge test --via-ir -vv # In future, execution spec and clients can test against the same clean vectors ``` diff --git a/lcov.info b/lcov.info index 0796ed4..670b5f9 100644 --- a/lcov.info +++ b/lcov.info @@ -1,628 +1,316 @@ TN: SF:src/P256.sol -FN:13,P256.verifySignatureAllowMalleability +FN:14,P256.verifySignatureAllowMalleability FNDA:9,P256.verifySignatureAllowMalleability -DA:20,9 -DA:20,9 -DA:20,9 -DA:22,9 -DA:22,9 -DA:22,9 +DA:21,9 DA:23,9 -DA:23,9 -DA:23,9 -BRDA:23,0,0,8 -BRDA:23,0,1,1 -DA:27,1 -DA:27,1 -DA:27,1 -DA:27,1 -DA:30,8 -DA:30,8 -DA:30,8 -DA:33,8 -DA:33,8 -BRDA:33,1,0,- -BRDA:33,1,1,- -DA:35,8 -DA:35,8 -DA:35,8 -DA:35,8 -FN:42,P256.verifySignature +DA:24,9 +BRDA:24,0,0,1 +DA:28,1 +DA:31,8 +DA:34,8 +BRDA:34,1,0,- +BRDA:34,1,1,- +DA:36,8 +FN:43,P256.verifySignature FNDA:5,P256.verifySignature -DA:50,5 -DA:50,5 -BRDA:50,2,0,4 -BRDA:50,2,1,1 -DA:51,1 -DA:51,1 -DA:54,4 -DA:54,4 -DA:54,4 +DA:51,5 +BRDA:51,2,0,1 +DA:52,1 +DA:55,4 FNF:2 FNH:2 LF:10 LH:10 -BRF:6 -BRH:4 +BRF:4 +BRH:2 end_of_record TN: SF:src/P256Verifier.sol -FN:26,P256Verifier. +FN:27,P256Verifier. FNDA:2577,P256Verifier. -DA:27,2577 -DA:27,2577 -BRDA:27,0,0,2576 -BRDA:27,0,1,1 -DA:28,1 -DA:28,1 -DA:28,1 -DA:31,2576 -DA:31,2576 -DA:31,2576 -DA:32,2576 +DA:28,2577 +BRDA:28,0,0,1 +DA:29,1 DA:32,2576 -DA:32,2576 -DA:33,2576 DA:33,2576 -DA:33,2576 -DA:34,2576 -DA:34,2576 DA:34,2576 DA:35,2576 -DA:35,2576 -DA:35,2576 -DA:37,2576 -DA:37,2576 -DA:37,2576 -DA:39,2576 -DA:39,2576 -DA:39,2576 -FN:70,P256Verifier.ecdsa_verify +DA:36,2576 +DA:38,2576 +DA:40,2576 +FN:71,P256Verifier.ecdsa_verify FNDA:2576,P256Verifier.ecdsa_verify -DA:77,2576 -DA:77,2576 -DA:77,2576 -DA:77,2576 -DA:77,2576 -DA:77,2547 -DA:77,2343 -DA:77,2331 -BRDA:77,1,0,2279 -BRDA:77,1,1,297 -DA:78,297 -DA:78,297 -DA:81,2279 -DA:81,2279 -BRDA:81,2,0,2272 -BRDA:81,2,1,7 -DA:82,7 -DA:82,7 -DA:85,2272 -DA:85,2272 -DA:85,2272 -DA:87,2272 -DA:87,2272 -DA:87,2272 -DA:88,2272 -DA:88,2272 +DA:78,2576 +BRDA:78,1,0,297 +DA:79,297 +DA:82,2279 +BRDA:82,2,0,7 +DA:83,7 +DA:86,2272 DA:88,2272 -DA:90,2272 -DA:90,2272 -DA:90,2272 -DA:96,2272 -DA:96,2272 -DA:96,2272 -DA:96,2272 -FN:103,P256Verifier.ecAff_isValidPubkey +DA:89,2272 +DA:91,2272 +DA:97,2272 +FN:104,P256Verifier.ecAff_isValidPubkey FNDA:2279,P256Verifier.ecAff_isValidPubkey -DA:107,2279 -DA:107,2279 -DA:107,2279 -DA:107,2279 -DA:107,2278 -BRDA:107,3,0,2277 -BRDA:107,3,1,1 -DA:108,2 -DA:108,2 -DA:111,2277 -DA:111,2277 -DA:111,2277 -FN:114,P256Verifier.ecAff_satisfiesCurveEqn +DA:108,2279 +BRDA:108,3,0,2 +DA:109,2 +DA:112,2277 +FN:115,P256Verifier.ecAff_satisfiesCurveEqn FNDA:2277,P256Verifier.ecAff_satisfiesCurveEqn -DA:118,2277 -DA:118,2277 -DA:118,2277 DA:119,2277 -DA:119,2277 -DA:119,2277 -DA:120,2277 DA:120,2277 -DA:122,2277 -DA:122,2277 -DA:122,2277 -FN:130,P256Verifier.ecZZ_mulmuladd +DA:121,2277 +DA:123,2277 +FN:131,P256Verifier.ecZZ_mulmuladd FNDA:2272,P256Verifier.ecZZ_mulmuladd -DA:136,2272 -DA:136,2272 DA:137,2272 -DA:137,2272 -DA:138,2272 DA:138,2272 DA:139,2272 -DA:139,2272 -DA:140,2272 DA:140,2272 -DA:142,2272 -DA:142,2272 -DA:142,2272 -DA:142,0 -BRDA:142,4,0,2272 -BRDA:142,4,1,- -DA:142,0 -DA:145,2272 -DA:145,2272 -DA:147,2272 -DA:147,2272 +DA:141,2272 +DA:143,2272 +DA:146,2272 DA:148,2272 -DA:148,2272 -DA:151,3088 -DA:151,3088 -DA:152,3088 +DA:149,2272 DA:152,3088 DA:153,3088 -DA:153,3088 DA:154,3088 -DA:154,3088 -BRDA:154,5,0,816 -BRDA:154,5,1,2272 -DA:154,0 -DA:160,2272 -DA:160,2272 -BRDA:160,6,0,836 -BRDA:160,6,1,1436 -DA:161,836 -DA:161,836 -DA:162,1436 -DA:162,1436 -BRDA:162,7,0,711 -BRDA:162,7,1,725 -DA:163,711 -DA:163,711 -DA:164,725 -DA:164,725 -BRDA:164,8,0,725 -BRDA:164,8,1,725 -DA:165,725 +DA:155,3088 +DA:161,2272 +BRDA:161,6,0,836 +BRDA:161,6,1,725 +DA:162,836 +DA:163,1436 +BRDA:163,7,0,711 +BRDA:163,7,1,725 +DA:164,711 DA:165,725 -DA:168,2272 -DA:168,2272 +BRDA:165,8,0,725 +DA:166,725 DA:169,2272 -DA:169,2272 -DA:170,580816 -DA:170,580816 -DA:171,578544 -DA:171,578544 -DA:173,578544 -DA:173,578544 -DA:174,578544 +DA:170,2272 +DA:171,580816 +DA:172,578544 DA:174,578544 -DA:176,578544 -DA:176,578544 -BRDA:176,9,0,148056 -BRDA:176,9,1,430488 -DA:177,148056 -DA:177,148056 -DA:178,430488 -DA:178,430488 -BRDA:178,10,0,147107 -BRDA:178,10,1,283381 -DA:179,147107 -DA:179,147107 -DA:180,283381 -DA:180,283381 -BRDA:180,11,0,140187 -BRDA:180,11,1,143194 -DA:181,140187 -DA:181,140187 -DA:183,143194 -DA:183,143194 -DA:186,430488 -DA:186,430488 -DA:189,2272 -DA:189,2272 -DA:189,2272 +DA:175,578544 +DA:177,578544 +BRDA:177,9,0,148056 +BRDA:177,9,1,143194 +DA:178,148056 +DA:179,430488 +BRDA:179,10,0,147107 +BRDA:179,10,1,143194 +DA:180,147107 +DA:181,283381 +BRDA:181,11,0,140187 +BRDA:181,11,1,143194 +DA:182,140187 +DA:184,143194 +DA:187,430488 DA:190,2272 -DA:190,2272 -FN:203,P256Verifier.compute_bitpair +DA:191,2272 +FN:204,P256Verifier.compute_bitpair FNDA:581632,P256Verifier.compute_bitpair -DA:204,581632 -DA:204,581632 -FN:211,P256Verifier.ecAff_add +DA:205,581632 +FN:212,P256Verifier.ecAff_add FNDA:2272,P256Verifier.ecAff_add -DA:220,2272 -DA:220,2272 -DA:221,2272 DA:221,2272 -DA:223,2272 -DA:223,2272 -BRDA:223,12,0,2272 -BRDA:223,12,1,- -DA:223,0 +DA:222,2272 DA:224,2272 -DA:224,2272 -BRDA:224,13,0,2272 -BRDA:224,13,1,- -DA:224,0 -DA:226,2272 -DA:226,2272 -DA:228,2272 -DA:228,2272 -DA:228,2272 -FN:235,P256Verifier.ecAff_IsInf +DA:225,2272 +DA:227,2272 +DA:229,2272 +FN:236,P256Verifier.ecAff_IsInf FNDA:437324,P256Verifier.ecAff_IsInf -DA:241,437324 -DA:241,437324 -FN:248,P256Verifier.ecZZ_IsInf +DA:242,437324 +FN:249,P256Verifier.ecZZ_IsInf FNDA:1013576,P256Verifier.ecZZ_IsInf -DA:255,1013576 -DA:255,1013576 -FN:265,P256Verifier.ecZZ_dadd_affine +DA:256,1013576 +FN:266,P256Verifier.ecZZ_dadd_affine FNDA:432760,P256Verifier.ecZZ_dadd_affine -DA:273,432760 -DA:273,432760 -BRDA:273,14,0,272 -BRDA:273,14,1,1020 -DA:274,1292 -DA:274,1292 -BRDA:274,15,0,272 -BRDA:274,15,1,1020 -DA:274,1020 -DA:274,1020 -DA:275,272 -DA:275,272 -DA:276,431468 -DA:276,431468 -BRDA:276,16,0,431460 -BRDA:276,16,1,8 -DA:277,8 -DA:277,8 -DA:280,431460 -DA:280,431460 -DA:280,431460 -DA:281,431460 +DA:274,432760 +BRDA:274,14,0,272 +BRDA:274,14,1,8 +DA:275,1292 +DA:276,272 +DA:277,431468 +BRDA:277,16,0,8 +DA:278,8 DA:281,431460 -DA:281,431460 -DA:283,431460 -DA:283,431460 -BRDA:283,17,0,431384 -BRDA:283,17,1,- -DA:285,431384 -DA:285,431384 -DA:285,431384 -DA:286,431384 +DA:282,431460 +DA:284,431460 +BRDA:284,17,0,431384 +BRDA:284,17,1,56 DA:286,431384 -DA:286,431384 -DA:287,431384 DA:287,431384 DA:288,431384 -DA:288,431384 -DA:289,431384 -DA:289,431384 DA:289,431384 DA:290,431384 -DA:290,431384 -DA:295,431384 -DA:295,431384 -DA:300,76 -DA:300,76 -BRDA:300,18,0,20 -BRDA:300,18,1,56 -DA:304,20 -DA:304,20 -DA:307,56 -DA:307,56 -DA:310,431460 -DA:310,431460 -FN:318,P256Verifier.ecZZ_double_zz +DA:291,431384 +DA:296,431384 +DA:301,76 +BRDA:301,18,0,20 +BRDA:301,18,1,56 +DA:305,20 +DA:308,56 +DA:311,431460 +FN:319,P256Verifier.ecZZ_double_zz FNDA:578544,P256Verifier.ecZZ_double_zz -DA:320,578544 -DA:320,578544 -BRDA:320,19,0,576456 -BRDA:320,19,1,2088 -DA:320,2088 -DA:320,2088 -DA:322,576456 -DA:322,576456 -DA:322,576456 -DA:323,576456 +DA:321,578544 DA:323,576456 -DA:323,576456 -DA:324,576456 DA:324,576456 -DA:324,576456 -DA:325,576456 -DA:325,576456 DA:325,576456 DA:326,576456 -DA:326,576456 -DA:326,576456 -DA:328,576456 -DA:328,576456 +DA:327,576456 DA:329,576456 -DA:329,576456 -DA:330,576456 DA:330,576456 DA:331,576456 -DA:331,576456 -FN:339,P256Verifier.ecZZ_double_affine +DA:332,576456 +FN:340,P256Verifier.ecZZ_double_affine FNDA:20,P256Verifier.ecZZ_double_affine -DA:341,20 -DA:341,20 -BRDA:341,20,0,20 -BRDA:341,20,1,- -DA:341,0 -DA:341,0 -DA:343,20 -DA:343,20 -DA:343,20 -DA:344,20 +DA:342,20 DA:344,20 DA:345,20 -DA:345,20 DA:346,20 -DA:346,20 -DA:346,20 -DA:347,20 -DA:347,20 DA:347,20 -DA:349,20 -DA:349,20 +DA:348,20 DA:350,20 -DA:350,20 -FN:358,P256Verifier.ecZZ_SetAff +DA:351,20 +FN:359,P256Verifier.ecZZ_SetAff FNDA:2272,P256Verifier.ecZZ_SetAff -DA:364,2272 -DA:364,2272 -BRDA:364,21,0,2256 -BRDA:364,21,1,16 -DA:365,16 -DA:365,16 -DA:366,16 +DA:365,2272 +BRDA:365,21,0,16 DA:366,16 -DA:369,2256 -DA:369,2256 -DA:369,2256 -DA:370,2256 -DA:370,2256 +DA:367,16 DA:370,2256 DA:371,2256 -DA:371,2256 -DA:371,2256 -DA:376,2256 -DA:376,2256 +DA:372,2256 DA:377,2256 -DA:377,2256 -FN:383,P256Verifier.ecZZ_PointAtInf +DA:378,2256 +FN:384,P256Verifier.ecZZ_PointAtInf FNDA:3164,P256Verifier.ecZZ_PointAtInf -DA:384,3164 -DA:384,3164 -FN:390,P256Verifier.ecAffine_PointAtInf +DA:385,3164 +FN:391,P256Verifier.ecAffine_PointAtInf FNDA:16,P256Verifier.ecAffine_PointAtInf -DA:391,16 -DA:391,16 -FN:397,P256Verifier.nModInv +DA:392,16 +FN:398,P256Verifier.nModInv FNDA:2272,P256Verifier.nModInv -DA:398,2272 -DA:398,2272 -DA:398,2272 -FN:404,P256Verifier.pModInv +DA:399,2272 +FN:405,P256Verifier.pModInv FNDA:4528,P256Verifier.pModInv -DA:405,4528 -DA:405,4528 -DA:405,4528 -FN:414,P256Verifier.modInv +DA:406,4528 +FN:415,P256Verifier.modInv FNDA:6800,P256Verifier.modInv -DA:421,6800 -DA:421,6800 -DA:422,6800 DA:422,6800 -BRDA:422,22,0,- -BRDA:422,22,1,- -DA:423,6800 DA:423,6800 +BRDA:423,22,0,- +BRDA:423,22,1,- +DA:424,6800 FNF:18 FNH:18 LF:121 LH:121 -BRF:46 -BRH:39 +BRF:25 +BRH:23 end_of_record TN: SF:src/WebAuthn.sol -FN:12,WebAuthn.startsWith +FN:13,WebAuthn.startsWith FNDA:6,WebAuthn.startsWith -DA:16,6 -DA:16,6 -DA:16,6 -DA:17,6 -DA:17,6 DA:17,6 -DA:19,6 -DA:19,6 +DA:18,6 DA:20,6 -DA:20,6 -DA:22,6 -DA:22,6 -DA:22,212 -DA:22,212 -DA:23,209 -DA:23,209 -BRDA:23,0,0,208 -BRDA:23,0,1,1 -DA:24,1 -DA:24,1 -DA:27,208 -DA:27,208 -BRDA:27,1,0,206 -BRDA:27,1,1,2 -DA:28,2 -DA:28,2 -DA:32,3 -DA:32,3 -FN:43,WebAuthn.checkAuthFlags +DA:21,6 +DA:23,6 +DA:24,209 +BRDA:24,0,0,1 +DA:25,1 +DA:28,208 +BRDA:28,1,0,2 +DA:29,2 +DA:33,3 +FN:44,WebAuthn.checkAuthFlags FNDA:9,WebAuthn.checkAuthFlags -DA:48,9 -DA:48,9 -DA:48,9 -BRDA:48,2,0,8 -BRDA:48,2,1,1 -DA:49,1 -DA:49,1 -DA:56,8 -DA:56,8 -DA:57,5 -DA:57,5 -BRDA:55,3,0,7 -BRDA:55,3,1,1 -DA:59,1 +DA:49,9 +BRDA:49,2,0,1 +DA:50,1 +DA:57,8 +DA:58,5 DA:59,1 -DA:64,7 -DA:64,7 -DA:64,7 -BRDA:64,4,0,1 -BRDA:64,4,1,1 -DA:65,2 -DA:65,2 -DA:65,2 -BRDA:65,5,0,1 -BRDA:65,5,1,1 -DA:66,1 -DA:66,1 -DA:70,6 -DA:70,6 -FN:123,WebAuthn.verifySignature +BRDA:59,3,0,1 +DA:60,1 +DA:65,7 +BRDA:65,4,0,2 +DA:66,2 +BRDA:66,5,0,1 +DA:67,1 +DA:71,6 +FN:124,WebAuthn.verifySignature FNDA:10,WebAuthn.verifySignature -DA:135,10 -DA:135,10 -DA:135,10 -DA:136,9 -DA:136,9 -BRDA:134,6,0,6 -BRDA:134,6,1,4 +DA:136,10 +DA:137,9 DA:138,4 -DA:138,4 -DA:144,6 -DA:144,6 -DA:144,6 -DA:145,6 +BRDA:138,6,0,4 +DA:139,4 DA:145,6 -DA:145,6 -DA:150,6 -DA:150,6 -BRDA:150,7,0,3 -BRDA:150,7,1,3 -DA:151,3 -DA:151,3 -DA:155,3 -DA:155,3 -DA:155,3 -DA:156,3 -DA:156,3 +DA:146,6 +DA:151,6 +BRDA:151,7,0,3 +DA:152,3 DA:156,3 -DA:160,3 -DA:160,3 -DA:160,3 +DA:157,3 +DA:161,3 FNF:3 FNH:3 -LF:29 -LH:29 -BRF:16 -BRH:16 +LF:31 +LH:31 +BRF:8 +BRH:8 end_of_record TN: SF:src/utils/Base64URL.sol FN:7,Base64URL.encode FNDA:1800,Base64URL.encode DA:8,1800 -DA:8,1800 -DA:8,1800 DA:9,1800 -DA:9,1800 -DA:9,1800 -DA:12,1800 DA:12,1800 DA:13,1800 -DA:13,1800 -DA:13,1800 -DA:13,1796 -BRDA:13,0,0,519 -BRDA:13,0,1,1281 -DA:13,519 -DA:14,1281 -DA:14,1281 -DA:14,1281 -DA:14,1277 -BRDA:14,1,0,1281 -BRDA:14,1,1,511 -DA:14,511 -DA:16,1800 -DA:16,1800 DA:16,1800 DA:17,1800 -DA:17,1800 -DA:17,1800 -DA:19,1800 DA:19,1800 -DA:19,526651 -DA:19,526651 DA:20,524851 -DA:20,524851 -BRDA:20,2,0,1248 -BRDA:20,2,1,523603 -DA:21,1248 +BRDA:20,1,0,1248 +BRDA:20,1,1,347412 DA:21,1248 DA:22,523603 -DA:22,523603 -BRDA:22,3,0,176191 -BRDA:22,3,1,347412 -DA:23,176191 +BRDA:22,2,0,176191 +BRDA:22,2,1,347412 DA:23,176191 DA:25,347412 -DA:25,347412 -DA:29,1800 -DA:29,1800 DA:29,1800 FNF:1 FNH:1 -LF:14 -LH:14 -BRF:8 -BRH:8 +LF:13 +LH:13 +BRF:4 +BRH:4 end_of_record TN: SF:test/P256.t.sol FN:10,FakePrecompile. FNDA:2,FakePrecompile. DA:11,2 -DA:11,2 -DA:11,2 -DA:12,2 DA:12,2 BRDA:12,0,0,- BRDA:12,0,1,- DA:14,2 -DA:14,2 -DA:14,2 -DA:15,2 DA:15,2 BRDA:15,1,0,1 BRDA:15,1,1,1 DA:16,1 -DA:16,1 -DA:16,1 -DA:18,1 -DA:18,1 DA:18,1 FNF:1 FNH:1 diff --git a/src/P256.sol b/src/P256.sol index c7792ea..d7d1617 100644 --- a/src/P256.sol +++ b/src/P256.sol @@ -2,9 +2,10 @@ pragma solidity 0.8.21; /** - * Helper library for external contracts to verify P256 signatures. - * Tries to use RIP-7212 precompile if available on the chain, and if not falls - * back to more expensive Solidity implementation. + * @dev Helper library to verify P256 signatures. Uses the RIP-7212 precompile + * if available. If unavailable (or if the signature is invalid), falls back to + * a more expensive Solidity implementation. + * @custom:security-contact security@daimo.com **/ library P256 { address constant PRECOMPILE = address(0x100); diff --git a/src/P256Verifier.sol b/src/P256Verifier.sol index 50731d1..302851e 100644 --- a/src/P256Verifier.sol +++ b/src/P256Verifier.sol @@ -3,15 +3,16 @@ pragma solidity 0.8.21; /** - * This contract verifies P256 (secp256r1) signatures. It matches the exact + * @dev This contract verifies P256 (secp256r1) signatures. It matches the exact * interface specified in the EIP-7212 precompile, allowing it to be used as a * fallback. It's based on Ledger's optimized implementation: * https://github.com/rdubois-crypto/FreshCryptoLib/tree/master/solidity - **/ + * @custom:security-contact security@daimo.com + */ contract P256Verifier { /** - * Precompiles don't use a function signature. The first byte of callldata - * is the first byte of an input argument. In this case: + * @dev Precompiles don't use a function signature. The first byte of + * calldata is the first byte of an input argument. In this case: * * input[ 0: 32] = signed data hash * input[ 32: 64] = signature r diff --git a/src/WebAuthn.sol b/src/WebAuthn.sol index b7fefbd..bbe1c96 100644 --- a/src/WebAuthn.sol +++ b/src/WebAuthn.sol @@ -5,8 +5,9 @@ import "./utils/Base64URL.sol"; import "./P256.sol"; /** - * Helper library for external contracts to verify WebAuthn signatures. - **/ + * @dev Helper library to verify WebAuthn (aka passkey) signatures. + * @custom:security-contact security@daimo.com + */ library WebAuthn { /// Checks whether prefix occurs in the beginning of str. function startsWith(