From 1f42f7d797f803029bcc95f344cbd9e794c3cf34 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 14:04:01 +0100 Subject: [PATCH 01/11] snapshot --- .gitignore | 3 +-- src/solidity/run-tests.sh | 4 ++-- src/solidity/snapshots/VerifierTest.json | 3 +++ src/solidity/snapshots/ZKPassportVerifierTest.json | 13 +++++++++++++ 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 src/solidity/snapshots/VerifierTest.json create mode 100644 src/solidity/snapshots/ZKPassportVerifierTest.json diff --git a/.gitignore b/.gitignore index ea1de09f4..43bc61d50 100644 --- a/.gitignore +++ b/.gitignore @@ -16,10 +16,9 @@ src/solidity/out src/solidity/broadcast # Ignore the anvil deployment file src/solidity/deployments/deployment-31337.json -src/solidity/snapshots src/ts/tests/fixtures/zkr/keypairs output-fixtures settings.json src/noir/lib/facematch/src/android/tests.nr -src/noir/bin/facematch/android/**/src/tests.nr \ No newline at end of file +src/noir/bin/facematch/android/**/src/tests.nr diff --git a/src/solidity/run-tests.sh b/src/solidity/run-tests.sh index c63048e80..88e0bbe07 100755 --- a/src/solidity/run-tests.sh +++ b/src/solidity/run-tests.sh @@ -57,7 +57,7 @@ script/bash/update-roots.sh cd $SCRIPT_DIR # Run the tests -forge test --rpc-url http://localhost:${PORT} -vv +forge test --rpc-url http://localhost:${PORT} -vv --isolate # Kill the anvil process lsof -ti:${PORT} | xargs kill -9 @@ -67,4 +67,4 @@ echo "Tests completed successfully" # If the tests were run based off a fresh clone of the zkpassport-packages repo, remove it if [ "$LOCAL_DIR" = "null" ]; then rm -rf zkpassport-packages -fi \ No newline at end of file +fi diff --git a/src/solidity/snapshots/VerifierTest.json b/src/solidity/snapshots/VerifierTest.json new file mode 100644 index 000000000..0cd5be0cd --- /dev/null +++ b/src/solidity/snapshots/VerifierTest.json @@ -0,0 +1,3 @@ +{ + "UltraHonkVerifier verify": "1828340" +} \ No newline at end of file diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json new file mode 100644 index 000000000..9c150b99a --- /dev/null +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -0,0 +1,13 @@ +{ + "ZKPassportVerifier enforceSanctionsRoot": "47921", + "ZKPassportVerifier getBoundData": "75198", + "ZKPassportVerifier getDisclosedData": "41193", + "ZKPassportVerifier isAgeAboveOrEqual": "35853", + "ZKPassportVerifier isBirthdateBeforeOrEqual": "21939", + "ZKPassportVerifier isExpiryDateAfterOrEqual": "33808", + "ZKPassportVerifier isFaceMatchVerified": "32933", + "ZKPassportVerifier isIssuingCountryIn": "210077", + "ZKPassportVerifier isIssuingCountryOut": "207907", + "ZKPassportVerifier isNationalityIn": "207221", + "ZKPassportVerifier verifyProof": "1883422" +} \ No newline at end of file From 5d86b149e8e21d9a0d3a9e4a93373a412326bbf3 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 14:06:06 +0100 Subject: [PATCH 02/11] ignore packages --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 43bc61d50..1362dfe37 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ res src/solidity/cache src/solidity/out src/solidity/broadcast +src/solidity/zkpassport-packages/ # Ignore the anvil deployment file src/solidity/deployments/deployment-31337.json src/ts/tests/fixtures/zkr/keypairs From 97cad60fde4f25127719298b57511c2b21f002f7 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 14:21:16 +0100 Subject: [PATCH 03/11] mod test --- src/solidity/run-tests.sh | 2 +- .../snapshots/ZKPassportVerifierTest.json | 3 +- src/solidity/test/ZKPassportVerifier.t.sol | 74 +++++++++++-------- 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/solidity/run-tests.sh b/src/solidity/run-tests.sh index 88e0bbe07..160bdde85 100755 --- a/src/solidity/run-tests.sh +++ b/src/solidity/run-tests.sh @@ -57,7 +57,7 @@ script/bash/update-roots.sh cd $SCRIPT_DIR # Run the tests -forge test --rpc-url http://localhost:${PORT} -vv --isolate +forge test --rpc-url http://localhost:${PORT} -vv "${@:2}" # Kill the anvil process lsof -ti:${PORT} | xargs kill -9 diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index 9c150b99a..7a2dafbd8 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -9,5 +9,6 @@ "ZKPassportVerifier isIssuingCountryIn": "210077", "ZKPassportVerifier isIssuingCountryOut": "207907", "ZKPassportVerifier isNationalityIn": "207221", - "ZKPassportVerifier verifyProof": "1883422" + "ZKPassportVerifier test_VerifyAllSubproofsProof": "2022043", + "ZKPassportVerifier test_VerifyValidProof": "1883411" } \ No newline at end of file diff --git a/src/solidity/test/ZKPassportVerifier.t.sol b/src/solidity/test/ZKPassportVerifier.t.sol index cd5c0c581..064b8bcae 100644 --- a/src/solidity/test/ZKPassportVerifier.t.sol +++ b/src/solidity/test/ZKPassportVerifier.t.sol @@ -61,7 +61,7 @@ contract ZKPassportVerifierTest is TestUtils { committedInputCounts[1] = CommittedInputLen.BIND; // Verify the proof - vm.startSnapshotGas("ZKPassportVerifier verifyProof"); + vm.startSnapshotGas("ZKPassportVerifier test_VerifyValidProof"); vm.warp(CURRENT_DATE); ProofVerificationParams memory params = ProofVerificationParams({ proofVerificationData: ProofVerificationData({ @@ -91,7 +91,10 @@ contract ZKPassportVerifierTest is TestUtils { ); vm.startSnapshotGas("ZKPassportVerifier getDisclosedData"); - DisclosedData memory disclosedData = zkPassportVerifier.getDisclosedData(params.commitments, false); + DisclosedData memory disclosedData = zkPassportVerifier.getDisclosedData( + params.commitments, + false + ); uint256 gasUsedGetDisclosedData = vm.stopSnapshotGas(); console.log("Gas used in ZKPassportVerifier getDisclosedData"); console.log(gasUsedGetDisclosedData); @@ -117,7 +120,7 @@ contract ZKPassportVerifierTest is TestUtils { vm.warp(CURRENT_DATE); ProofVerificationParams memory params = ProofVerificationParams({ proofVerificationData: ProofVerificationData({ - vkeyHash: VKEY_HASH, + vkeyHash: VKEY_HASH, proof: proof, publicInputs: publicInputs }), @@ -140,8 +143,7 @@ contract ZKPassportVerifierTest is TestUtils { ); vm.startSnapshotGas("ZKPassportVerifier getBoundData"); - BoundData memory boundData = zkPassportVerifier - .getBoundData(params.commitments); + BoundData memory boundData = zkPassportVerifier.getBoundData(params.commitments); uint256 gasUsedGetBoundData = vm.stopSnapshotGas(); console.log("Gas used in ZKPassportVerifier getBoundData"); console.log(gasUsedGetBoundData); @@ -171,7 +173,7 @@ contract ZKPassportVerifierTest is TestUtils { committedInputCounts[9] = CommittedInputLen.FACEMATCH; // Verify the proof - vm.startSnapshotGas("ZKPassportVerifier verifyProof"); + vm.startSnapshotGas("ZKPassportVerifier test_VerifyAllSubproofsProof"); vm.warp(CURRENT_DATE); ProofVerificationParams memory params = ProofVerificationParams({ proofVerificationData: ProofVerificationData({ @@ -201,11 +203,10 @@ contract ZKPassportVerifierTest is TestUtils { ); vm.startSnapshotGas("ZKPassportVerifier isAgeAboveOrEqual"); - assertEq(zkPassportVerifier.isAgeAboveOrEqual( - 18, - params.commitments, - params.serviceConfig - ), true); + assertEq( + zkPassportVerifier.isAgeAboveOrEqual(18, params.commitments, params.serviceConfig), + true + ); uint256 gasUsedGetAgeProofInputs = vm.stopSnapshotGas(); console.log("Gas used in ZKPassportVerifier isAgeAboveOrEqual"); console.log(gasUsedGetAgeProofInputs); @@ -216,16 +217,12 @@ contract ZKPassportVerifierTest is TestUtils { countryList[1] = "FRA"; countryList[2] = "USA"; countryList[3] = "GBR"; - bool isNationalityIn = zkPassportVerifier.isNationalityIn( - countryList, - params.commitments - ); + bool isNationalityIn = zkPassportVerifier.isNationalityIn(countryList, params.commitments); uint256 gasUsedGetCountryProofInputs = vm.stopSnapshotGas(); console.log("Gas used in ZKPassportVerifier isNationalityIn"); console.log(gasUsedGetCountryProofInputs); assertEq(isNationalityIn, true); - vm.startSnapshotGas("ZKPassportVerifier isIssuingCountryOut"); string[] memory exclusionCountryList = new string[](3); exclusionCountryList[0] = "ESP"; @@ -282,10 +279,10 @@ contract ZKPassportVerifierTest is TestUtils { vm.startSnapshotGas("ZKPassportVerifier isBirthdateBeforeOrEqual"); bool isBirthdateBeforeOrEqual = zkPassportVerifier.isBirthdateBeforeOrEqual( - PROOF_GENERATION_DATE, - params.commitments, - params.serviceConfig - ); + PROOF_GENERATION_DATE, + params.commitments, + params.serviceConfig + ); uint256 gasUsedIsBirthdateBeforeOrEqual = vm.stopSnapshotGas(); console.log("Gas used in ZKPassportVerifier isBirthdateBeforeOrEqual"); console.log(gasUsedIsBirthdateBeforeOrEqual); @@ -294,10 +291,10 @@ contract ZKPassportVerifierTest is TestUtils { { vm.startSnapshotGas("ZKPassportVerifier isExpiryDateAfterOrEqual"); bool isExpiryDateAfterOrEqual = zkPassportVerifier.isExpiryDateAfterOrEqual( - PROOF_GENERATION_DATE, - params.commitments, - params.serviceConfig - ); + PROOF_GENERATION_DATE, + params.commitments, + params.serviceConfig + ); uint256 gasUsedIsExpiryDateAfterOrEqual = vm.stopSnapshotGas(); console.log("Gas used in ZKPassportVerifier isExpiryDateAfterOrEqual"); console.log(gasUsedIsExpiryDateAfterOrEqual); @@ -315,9 +312,7 @@ contract ZKPassportVerifierTest is TestUtils { params.commitments ); uint256 gasUsedIsIssuingCountryIn = vm.stopSnapshotGas(); - console.log( - "Gas used in ZKPassportVerifier isIssuingCountryIn" - ); + console.log("Gas used in ZKPassportVerifier isIssuingCountryIn"); console.log(gasUsedIsIssuingCountryIn); assertEq(isIssuingCountryIn, true); } @@ -332,17 +327,34 @@ contract ZKPassportVerifierTest is TestUtils { { vm.startSnapshotGas("ZKPassportVerifier isFaceMatchVerified"); - bool isFacematchVerified = zkPassportVerifier.isFaceMatchVerified(FaceMatchMode.REGULAR, OS.IOS, params.commitments); + bool isFacematchVerified = zkPassportVerifier.isFaceMatchVerified( + FaceMatchMode.REGULAR, + OS.IOS, + params.commitments + ); uint256 gasUsedIsFaceMatchVerified = vm.stopSnapshotGas(); console.log("Gas used in ZKPassportVerifier isFaceMatchVerified"); console.log(gasUsedIsFaceMatchVerified); assertEq(isFacematchVerified, true); // Should be false because the facematch mode is not strict but regular - assertEq(zkPassportVerifier.isFaceMatchVerified(FaceMatchMode.STRICT, OS.IOS, params.commitments), false); + assertEq( + zkPassportVerifier.isFaceMatchVerified(FaceMatchMode.STRICT, OS.IOS, params.commitments), + false + ); // Should be false because the OS is not iOS - assertEq(zkPassportVerifier.isFaceMatchVerified(FaceMatchMode.REGULAR, OS.ANDROID, params.commitments), false); + assertEq( + zkPassportVerifier.isFaceMatchVerified( + FaceMatchMode.REGULAR, + OS.ANDROID, + params.commitments + ), + false + ); // Should be true because the OS is any - assertEq(zkPassportVerifier.isFaceMatchVerified(FaceMatchMode.REGULAR, OS.ANY, params.commitments), true); + assertEq( + zkPassportVerifier.isFaceMatchVerified(FaceMatchMode.REGULAR, OS.ANY, params.commitments), + true + ); } } } From 342c57b782ffb88693044e8dde6a0ac15d44df08 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 14:28:42 +0100 Subject: [PATCH 04/11] rename test --- src/solidity/snapshots/ZKPassportVerifierTest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index 7a2dafbd8..274e20a3b 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -9,6 +9,6 @@ "ZKPassportVerifier isIssuingCountryIn": "210077", "ZKPassportVerifier isIssuingCountryOut": "207907", "ZKPassportVerifier isNationalityIn": "207221", - "ZKPassportVerifier test_VerifyAllSubproofsProof": "2022043", "ZKPassportVerifier test_VerifyValidProof": "1883411" + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2022043" } \ No newline at end of file From ae6907bc6c31290bc622d62a6c8414d6340f1e82 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 14:38:24 +0100 Subject: [PATCH 05/11] optimize encode packed --- src/solidity/snapshots/ZKPassportVerifierTest.json | 4 ++-- src/solidity/src/ZKPassportVerifier.sol | 6 +++--- src/solidity/test/ZKPassportVerifier.t.sol | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index 274e20a3b..652c71613 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -9,6 +9,6 @@ "ZKPassportVerifier isIssuingCountryIn": "210077", "ZKPassportVerifier isIssuingCountryOut": "207907", "ZKPassportVerifier isNationalityIn": "207221", - "ZKPassportVerifier test_VerifyValidProof": "1883411" - "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2022043" + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2019724", + "ZKPassportVerifier test_VerifyValidProof": "1882699" } \ No newline at end of file diff --git a/src/solidity/src/ZKPassportVerifier.sol b/src/solidity/src/ZKPassportVerifier.sol index 5f01cfe9c..c10177cbe 100644 --- a/src/solidity/src/ZKPassportVerifier.sol +++ b/src/solidity/src/ZKPassportVerifier.sol @@ -593,12 +593,12 @@ contract ZKPassportVerifier { // What we call scope internally is derived from the domain bytes32 scopeHash = StringUtils.isEmpty(domain) ? bytes32(0) - : sha256(abi.encodePacked(domain)) >> 8; + : sha256(bytes(domain)) >> 8; // What we call the subscope internally is the scope specified // manually in the SDK bytes32 subscopeHash = StringUtils.isEmpty(scope) ? bytes32(0) - : sha256(abi.encodePacked(scope)) >> 8; + : sha256(bytes(scope)) >> 8; return publicInputs[PublicInput.SCOPE_INDEX] == scopeHash && publicInputs[PublicInput.SUBSCOPE_INDEX] == subscopeHash; } @@ -610,7 +610,7 @@ contract ZKPassportVerifier { for (uint256 i = 0; i < commitments.committedInputCounts.length; i++) { // One byte is dropped inside the circuit as BN254 is limited to 254 bits bytes32 calculatedCommitment = sha256( - abi.encodePacked(commitments.committedInputs[offset:offset + commitments.committedInputCounts[i]]) + bytes(commitments.committedInputs[offset:offset + commitments.committedInputCounts[i]]) ) >> 8; require(calculatedCommitment == paramCommitments[i], "Invalid commitment"); offset += commitments.committedInputCounts[i]; diff --git a/src/solidity/test/ZKPassportVerifier.t.sol b/src/solidity/test/ZKPassportVerifier.t.sol index 064b8bcae..8e054339b 100644 --- a/src/solidity/test/ZKPassportVerifier.t.sol +++ b/src/solidity/test/ZKPassportVerifier.t.sol @@ -152,7 +152,7 @@ contract ZKPassportVerifierTest is TestUtils { assertEq(boundData.customData, "email:test@test.com,customer_id:1234567890"); } - function test_VerifyAllSubproofsProof() public { + function test_VerifyAllSubproofsProof1() public { // Load proof and public inputs from files bytes memory proof = loadBytesFromFile(ALL_SUBPROOFS_PROOF_PATH); bytes32[] memory publicInputs = loadBytes32FromFile(ALL_SUBPROOFS_PUBLIC_INPUTS_PATH); @@ -173,7 +173,7 @@ contract ZKPassportVerifierTest is TestUtils { committedInputCounts[9] = CommittedInputLen.FACEMATCH; // Verify the proof - vm.startSnapshotGas("ZKPassportVerifier test_VerifyAllSubproofsProof"); + vm.startSnapshotGas("ZKPassportVerifier test_VerifyAllSubproofsProof1"); vm.warp(CURRENT_DATE); ProofVerificationParams memory params = ProofVerificationParams({ proofVerificationData: ProofVerificationData({ From 64f7b0f11a588a54a857ce8925d9921ace132892 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 14:41:18 +0100 Subject: [PATCH 06/11] memory -> calldata --- .../snapshots/ZKPassportVerifierTest.json | 22 +++++++++---------- src/solidity/src/ZKPassportVerifier.sol | 14 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index 652c71613..5f59653cf 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -1,14 +1,14 @@ { - "ZKPassportVerifier enforceSanctionsRoot": "47921", - "ZKPassportVerifier getBoundData": "75198", - "ZKPassportVerifier getDisclosedData": "41193", + "ZKPassportVerifier enforceSanctionsRoot": "47917", + "ZKPassportVerifier getBoundData": "75146", + "ZKPassportVerifier getDisclosedData": "40969", "ZKPassportVerifier isAgeAboveOrEqual": "35853", - "ZKPassportVerifier isBirthdateBeforeOrEqual": "21939", - "ZKPassportVerifier isExpiryDateAfterOrEqual": "33808", - "ZKPassportVerifier isFaceMatchVerified": "32933", - "ZKPassportVerifier isIssuingCountryIn": "210077", - "ZKPassportVerifier isIssuingCountryOut": "207907", - "ZKPassportVerifier isNationalityIn": "207221", - "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2019724", - "ZKPassportVerifier test_VerifyValidProof": "1882699" + "ZKPassportVerifier isBirthdateBeforeOrEqual": "21943", + "ZKPassportVerifier isExpiryDateAfterOrEqual": "33812", + "ZKPassportVerifier isFaceMatchVerified": "32925", + "ZKPassportVerifier isIssuingCountryIn": "206685", + "ZKPassportVerifier isIssuingCountryOut": "204662", + "ZKPassportVerifier isNationalityIn": "203829", + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2019244", + "ZKPassportVerifier test_VerifyValidProof": "1882351" } \ No newline at end of file diff --git a/src/solidity/src/ZKPassportVerifier.sol b/src/solidity/src/ZKPassportVerifier.sol index c10177cbe..0cf06d578 100644 --- a/src/solidity/src/ZKPassportVerifier.sol +++ b/src/solidity/src/ZKPassportVerifier.sol @@ -89,7 +89,7 @@ contract ZKPassportVerifier { } function checkDate( - bytes32[] memory publicInputs, + bytes32[] calldata publicInputs, uint256 validityPeriodInSeconds ) internal view returns (bool) { uint256 currentDateTimeStamp = uint256(publicInputs[PublicInput.CURRENT_DATE_INDEX]); @@ -464,7 +464,7 @@ contract ZKPassportVerifier { } function isCountryInOrOut( - string[] memory countryList, + string[] calldata countryList, ProofType proofType, Commitments calldata commitments ) private pure returns (bool) { @@ -487,7 +487,7 @@ contract ZKPassportVerifier { * @return True if the nationality is in the list of countries, false otherwise */ function isNationalityIn( - string[] memory countryList, + string[] calldata countryList, Commitments calldata commitments ) public pure returns (bool) { return isCountryInOrOut(countryList, ProofType.NATIONALITY_INCLUSION, commitments); @@ -500,7 +500,7 @@ contract ZKPassportVerifier { * @return True if the issuing country is in the list of countries, false otherwise */ function isIssuingCountryIn( - string[] memory countryList, + string[] calldata countryList, Commitments calldata commitments ) public pure returns (bool) { return isCountryInOrOut(countryList, ProofType.ISSUING_COUNTRY_INCLUSION, commitments); @@ -514,7 +514,7 @@ contract ZKPassportVerifier { * @return True if the nationality is not in the list of countries, false otherwise */ function isNationalityOut( - string[] memory countryList, + string[] calldata countryList, Commitments calldata commitments ) public pure returns (bool) { return isCountryInOrOut(countryList, ProofType.NATIONALITY_EXCLUSION, commitments); @@ -528,7 +528,7 @@ contract ZKPassportVerifier { * @return True if the issuing country is not in the list of countries, false otherwise */ function isIssuingCountryOut( - string[] memory countryList, + string[] calldata countryList, Commitments calldata commitments ) public pure returns (bool) { return isCountryInOrOut(countryList, ProofType.ISSUING_COUNTRY_EXCLUSION, commitments); @@ -603,7 +603,7 @@ contract ZKPassportVerifier { } function verifyCommittedInputs( - bytes32[] memory paramCommitments, + bytes32[] calldata paramCommitments, Commitments calldata commitments ) internal pure { uint256 offset = 0; From 35fa7e189b4a926261a1d5bd55ed01320c390f42 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 15:33:01 +0100 Subject: [PATCH 07/11] temp breakpoint --- .../snapshots/ZKPassportVerifierTest.json | 20 +++++++++---------- src/solidity/src/ZKPassportVerifier.sol | 5 ++++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index 5f59653cf..b629ff0e4 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -1,14 +1,14 @@ { "ZKPassportVerifier enforceSanctionsRoot": "47917", - "ZKPassportVerifier getBoundData": "75146", - "ZKPassportVerifier getDisclosedData": "40969", - "ZKPassportVerifier isAgeAboveOrEqual": "35853", - "ZKPassportVerifier isBirthdateBeforeOrEqual": "21943", - "ZKPassportVerifier isExpiryDateAfterOrEqual": "33812", + "ZKPassportVerifier getBoundData": "75168", + "ZKPassportVerifier getDisclosedData": "38447", + "ZKPassportVerifier isAgeAboveOrEqual": "33398", + "ZKPassportVerifier isBirthdateBeforeOrEqual": "21965", + "ZKPassportVerifier isExpiryDateAfterOrEqual": "33834", "ZKPassportVerifier isFaceMatchVerified": "32925", - "ZKPassportVerifier isIssuingCountryIn": "206685", - "ZKPassportVerifier isIssuingCountryOut": "204662", - "ZKPassportVerifier isNationalityIn": "203829", - "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2019244", - "ZKPassportVerifier test_VerifyValidProof": "1882351" + "ZKPassportVerifier isIssuingCountryIn": "206730", + "ZKPassportVerifier isIssuingCountryOut": "204684", + "ZKPassportVerifier isNationalityIn": "203851", + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2022166", + "ZKPassportVerifier test_VerifyValidProof": "1885273" } \ No newline at end of file diff --git a/src/solidity/src/ZKPassportVerifier.sol b/src/solidity/src/ZKPassportVerifier.sol index 0cf06d578..e06b63490 100644 --- a/src/solidity/src/ZKPassportVerifier.sol +++ b/src/solidity/src/ZKPassportVerifier.sol @@ -9,8 +9,10 @@ import {IRootRegistry} from "../src/IRootRegistry.sol"; import {InputsExtractor} from "../src/InputsExtractor.sol"; import {CommittedInputLen, MRZIndex, MRZLength, SECONDS_BETWEEN_1900_AND_1970, PublicInput, AppAttest} from "../src/Constants.sol"; import {ProofType, ProofVerificationParams, BoundDataIdentifier, DisclosedData, BoundData, FaceMatchMode, Environment, NullifierType, Commitments, ServiceConfig, OS} from "../src/Types.sol"; +import {Test} from "forge-std/Test.sol"; +import {console} from "forge-std/console.sol"; -contract ZKPassportVerifier { +contract ZKPassportVerifier is Test { bytes32 public constant CERTIFICATE_REGISTRY_ID = bytes32(uint256(1)); bytes32 public constant CIRCUIT_REGISTRY_ID = bytes32(uint256(2)); bytes32 public constant SANCTIONS_REGISTRY_ID = bytes32(uint256(3)); @@ -707,6 +709,7 @@ contract ZKPassportVerifier { // to ensure all the param commitments are covered require(params.commitments.committedInputCounts.length == params.proofVerificationData.publicInputs.length - PublicInput.PUBLIC_INPUTS_EXCLUDING_PARAM_COMMITMENTS_LENGTH, "Invalid committed input counts length"); + vm.breakpoint("v"); // Call the UltraHonk verifier for the given Outer Circuit to verify if the actual proof is valid isValid = IVerifier(verifier).verify(params.proofVerificationData.proof, params.proofVerificationData.publicInputs); From 22fc9811baddc82c6b7e21907a3de4f50dc8916c Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 15:50:01 +0100 Subject: [PATCH 08/11] hypothetical verifier optimization --- .../snapshots/ZKPassportVerifierTest.json | 2 +- .../src/ultra-honk-verifiers/OuterCount13.sol | 45 ++++++++++++------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index b629ff0e4..a05d420d1 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -9,6 +9,6 @@ "ZKPassportVerifier isIssuingCountryIn": "206730", "ZKPassportVerifier isIssuingCountryOut": "204684", "ZKPassportVerifier isNationalityIn": "203851", - "ZKPassportVerifier test_VerifyAllSubproofsProof1": "2022166", + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "1898666", "ZKPassportVerifier test_VerifyValidProof": "1885273" } \ No newline at end of file diff --git a/src/solidity/src/ultra-honk-verifiers/OuterCount13.sol b/src/solidity/src/ultra-honk-verifiers/OuterCount13.sol index fa30695d4..d6a64ed89 100644 --- a/src/solidity/src/ultra-honk-verifiers/OuterCount13.sol +++ b/src/solidity/src/ultra-honk-verifiers/OuterCount13.sol @@ -711,60 +711,62 @@ library TranscriptLib { // Pairing point object for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { - p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.pairingPointObject[i] = bytesToFr(proof, boundary); boundary += FIELD_ELEMENT_SIZE; } // Commitments - p.w1 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.w1 = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; - p.w2 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.w2 = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; - p.w3 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.w3 = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; // Lookup / Permutation Helper Commitments - p.lookupReadCounts = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadCounts = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; - p.lookupReadTags = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupReadTags = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; - p.w4 = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.w4 = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; - p.lookupInverses = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.lookupInverses = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; - p.zPerm = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.zPerm = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; // Sumcheck univariates for (uint256 i = 0; i < logN; i++) { for (uint256 j = 0; j < BATCHED_RELATION_PARTIAL_LENGTH; j++) { - p.sumcheckUnivariates[i][j] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckUnivariates[i][j] = bytesToFr(proof, boundary); boundary += FIELD_ELEMENT_SIZE; } } // Sumcheck evaluations for (uint256 i = 0; i < NUMBER_OF_ENTITIES; i++) { - p.sumcheckEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.sumcheckEvaluations[i] = bytesToFr(proof, boundary); boundary += FIELD_ELEMENT_SIZE; } // Gemini // Read gemini fold univariates for (uint256 i = 0; i < logN - 1; i++) { - p.geminiFoldComms[i] = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.geminiFoldComms[i] = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; } // Read gemini a evaluations for (uint256 i = 0; i < logN; i++) { - p.geminiAEvaluations[i] = bytesToFr(proof[boundary:boundary + FIELD_ELEMENT_SIZE]); + p.geminiAEvaluations[i] = bytesToFr(proof, boundary); boundary += FIELD_ELEMENT_SIZE; } // Shplonk - p.shplonkQ = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.shplonkQ = bytesToG1Point(proof, boundary); boundary += GROUP_ELEMENT_SIZE; // KZG - p.kzgQuotient = bytesToG1Point(proof[boundary:boundary + GROUP_ELEMENT_SIZE]); + p.kzgQuotient = bytesToG1Point(proof, boundary); + + require(boundary + GROUP_ELEMENT_SIZE <= proof.length); } } @@ -1568,6 +1570,12 @@ function bytesToFr(bytes calldata proofSection) pure returns (Fr scalar) { scalar = FrLib.fromBytes32(bytes32(proofSection)); } +function bytesToFr(bytes calldata proof, uint offset) pure returns (Fr scalar) { + assembly { + scalar := mod(calldataload(add(proof.offset, offset)), MODULUS) + } +} + // EC Point utilities function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point memory point) { point = Honk.G1Point({ @@ -1576,6 +1584,13 @@ function bytesToG1Point(bytes calldata proofSection) pure returns (Honk.G1Point }); } +function bytesToG1Point(bytes calldata proofSection, uint offset) pure returns (Honk.G1Point memory point) { + assembly ("memory-safe") { + mstore(point, mod(calldataload(add(proofSection.offset, offset)), Q)) + mstore(add(point, 0x20), mod(calldataload(add(proofSection.offset, add(offset, 0x20))), Q)) + } +} + function negateInplace(Honk.G1Point memory point) pure returns (Honk.G1Point memory) { point.y = (Q - point.y) % Q; return point; From 6eb2b66ad86f9d1ccad08bfba21cf296270da2da Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 15:59:50 +0100 Subject: [PATCH 09/11] le update --- src/solidity/snapshots/ZKPassportVerifierTest.json | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index a05d420d1..4c87df092 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -1,14 +1,6 @@ { - "ZKPassportVerifier enforceSanctionsRoot": "47917", - "ZKPassportVerifier getBoundData": "75168", - "ZKPassportVerifier getDisclosedData": "38447", - "ZKPassportVerifier isAgeAboveOrEqual": "33398", - "ZKPassportVerifier isBirthdateBeforeOrEqual": "21965", - "ZKPassportVerifier isExpiryDateAfterOrEqual": "33834", - "ZKPassportVerifier isFaceMatchVerified": "32925", - "ZKPassportVerifier isIssuingCountryIn": "206730", + "ZKPassportVerifier isAgeAboveOrEqual": "30898", "ZKPassportVerifier isIssuingCountryOut": "204684", "ZKPassportVerifier isNationalityIn": "203851", - "ZKPassportVerifier test_VerifyAllSubproofsProof1": "1898666", - "ZKPassportVerifier test_VerifyValidProof": "1885273" + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "1902011" } \ No newline at end of file From 7422cf0f7bd769c9384f3a57db4ce8cb44ccc1f4 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 16:07:09 +0100 Subject: [PATCH 10/11] optimize `verifyCommittedInputs` with assembly shenanigans --- .../snapshots/ZKPassportVerifierTest.json | 12 +++++++-- src/solidity/src/ZKPassportVerifier.sol | 25 +++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index 4c87df092..9e32c23ed 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -1,6 +1,14 @@ { - "ZKPassportVerifier isAgeAboveOrEqual": "30898", + "ZKPassportVerifier enforceSanctionsRoot": "47917", + "ZKPassportVerifier getBoundData": "75168", + "ZKPassportVerifier getDisclosedData": "38447", + "ZKPassportVerifier isAgeAboveOrEqual": "33398", + "ZKPassportVerifier isBirthdateBeforeOrEqual": "21965", + "ZKPassportVerifier isExpiryDateAfterOrEqual": "33834", + "ZKPassportVerifier isFaceMatchVerified": "32925", + "ZKPassportVerifier isIssuingCountryIn": "206730", "ZKPassportVerifier isIssuingCountryOut": "204684", "ZKPassportVerifier isNationalityIn": "203851", - "ZKPassportVerifier test_VerifyAllSubproofsProof1": "1902011" + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "1885829", + "ZKPassportVerifier test_VerifyValidProof": "1882736" } \ No newline at end of file diff --git a/src/solidity/src/ZKPassportVerifier.sol b/src/solidity/src/ZKPassportVerifier.sol index e06b63490..1c787284b 100644 --- a/src/solidity/src/ZKPassportVerifier.sol +++ b/src/solidity/src/ZKPassportVerifier.sol @@ -607,18 +607,27 @@ contract ZKPassportVerifier is Test { function verifyCommittedInputs( bytes32[] calldata paramCommitments, Commitments calldata commitments - ) internal pure { + ) internal view { uint256 offset = 0; - for (uint256 i = 0; i < commitments.committedInputCounts.length; i++) { - // One byte is dropped inside the circuit as BN254 is limited to 254 bits - bytes32 calculatedCommitment = sha256( - bytes(commitments.committedInputs[offset:offset + commitments.committedInputCounts[i]]) - ) >> 8; + uint[] calldata counts = commitments.committedInputCounts; + bytes calldata inputs = commitments.committedInputs; + for (uint256 i = 0; i < counts.length; i++) { + uint count; + bytes32 calculatedCommitment; + assembly ("memory-safe") { + count := calldataload(add(counts.offset, shl(5, i))) + calldatacopy(mload(0x40), add(inputs.offset, offset), count) + if iszero(staticcall(gas(), 0x02, mload(0x40), count, 0x00, 0x20)) { + revert(0, 0) + } + // One byte is dropped inside the circuit as BN254 is limited to 254 bits + calculatedCommitment := shr(8, mload(0x00)) + } require(calculatedCommitment == paramCommitments[i], "Invalid commitment"); - offset += commitments.committedInputCounts[i]; + offset += count; } // Check that all the committed inputs have been covered, otherwise something is wrong - require(offset == commitments.committedInputs.length, "Invalid committed inputs length"); + require(offset == inputs.length, "Invalid committed inputs length"); } function _getVerifier(bytes32 vkeyHash) internal view returns (address) { From a6f1a39480cfb77a570832608af4a236fe3dada3 Mon Sep 17 00:00:00 2001 From: philogy Date: Tue, 14 Oct 2025 16:08:34 +0100 Subject: [PATCH 11/11] remove breakpoint --- .../snapshots/ZKPassportVerifierTest.json | 20 +++++++++---------- src/solidity/src/ZKPassportVerifier.sol | 5 +---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/solidity/snapshots/ZKPassportVerifierTest.json b/src/solidity/snapshots/ZKPassportVerifierTest.json index 9e32c23ed..c9c74a8a3 100644 --- a/src/solidity/snapshots/ZKPassportVerifierTest.json +++ b/src/solidity/snapshots/ZKPassportVerifierTest.json @@ -1,14 +1,14 @@ { "ZKPassportVerifier enforceSanctionsRoot": "47917", - "ZKPassportVerifier getBoundData": "75168", - "ZKPassportVerifier getDisclosedData": "38447", - "ZKPassportVerifier isAgeAboveOrEqual": "33398", - "ZKPassportVerifier isBirthdateBeforeOrEqual": "21965", - "ZKPassportVerifier isExpiryDateAfterOrEqual": "33834", + "ZKPassportVerifier getBoundData": "75146", + "ZKPassportVerifier getDisclosedData": "40969", + "ZKPassportVerifier isAgeAboveOrEqual": "35853", + "ZKPassportVerifier isBirthdateBeforeOrEqual": "21943", + "ZKPassportVerifier isExpiryDateAfterOrEqual": "33812", "ZKPassportVerifier isFaceMatchVerified": "32925", - "ZKPassportVerifier isIssuingCountryIn": "206730", - "ZKPassportVerifier isIssuingCountryOut": "204684", - "ZKPassportVerifier isNationalityIn": "203851", - "ZKPassportVerifier test_VerifyAllSubproofsProof1": "1885829", - "ZKPassportVerifier test_VerifyValidProof": "1882736" + "ZKPassportVerifier isIssuingCountryIn": "206685", + "ZKPassportVerifier isIssuingCountryOut": "204662", + "ZKPassportVerifier isNationalityIn": "203829", + "ZKPassportVerifier test_VerifyAllSubproofsProof1": "1882907", + "ZKPassportVerifier test_VerifyValidProof": "1879814" } \ No newline at end of file diff --git a/src/solidity/src/ZKPassportVerifier.sol b/src/solidity/src/ZKPassportVerifier.sol index 1c787284b..81c1428b1 100644 --- a/src/solidity/src/ZKPassportVerifier.sol +++ b/src/solidity/src/ZKPassportVerifier.sol @@ -9,10 +9,8 @@ import {IRootRegistry} from "../src/IRootRegistry.sol"; import {InputsExtractor} from "../src/InputsExtractor.sol"; import {CommittedInputLen, MRZIndex, MRZLength, SECONDS_BETWEEN_1900_AND_1970, PublicInput, AppAttest} from "../src/Constants.sol"; import {ProofType, ProofVerificationParams, BoundDataIdentifier, DisclosedData, BoundData, FaceMatchMode, Environment, NullifierType, Commitments, ServiceConfig, OS} from "../src/Types.sol"; -import {Test} from "forge-std/Test.sol"; -import {console} from "forge-std/console.sol"; -contract ZKPassportVerifier is Test { +contract ZKPassportVerifier { bytes32 public constant CERTIFICATE_REGISTRY_ID = bytes32(uint256(1)); bytes32 public constant CIRCUIT_REGISTRY_ID = bytes32(uint256(2)); bytes32 public constant SANCTIONS_REGISTRY_ID = bytes32(uint256(3)); @@ -718,7 +716,6 @@ contract ZKPassportVerifier is Test { // to ensure all the param commitments are covered require(params.commitments.committedInputCounts.length == params.proofVerificationData.publicInputs.length - PublicInput.PUBLIC_INPUTS_EXCLUDING_PARAM_COMMITMENTS_LENGTH, "Invalid committed input counts length"); - vm.breakpoint("v"); // Call the UltraHonk verifier for the given Outer Circuit to verify if the actual proof is valid isValid = IVerifier(verifier).verify(params.proofVerificationData.proof, params.proofVerificationData.publicInputs);