From 0745425e103e1e5d4f29859074e532dd666435fd Mon Sep 17 00:00:00 2001 From: Cedoor Date: Fri, 7 Nov 2025 14:46:33 +0100 Subject: [PATCH 01/13] test: add test for on-chain zk verification --- .../contracts/CRISPVerifier.sol | 115 ++++++----- .../tests/crisp.contracts.test.ts | 194 +++++++++++++----- examples/CRISP/packages/crisp-sdk/src/vote.ts | 4 +- 3 files changed, 199 insertions(+), 114 deletions(-) diff --git a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol index 93216d4fd5..514a915eed 100644 --- a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol +++ b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol @@ -3,124 +3,125 @@ // This file is provided WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. + pragma solidity >=0.8.21; uint256 constant N = 1048576; uint256 constant LOG_N = 20; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 0; +uint256 constant NUMBER_OF_PUBLIC_INPUTS = 12304; library HonkVerificationKey { function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { Honk.VerificationKey memory vk = Honk.VerificationKey({ circuitSize: uint256(1048576), logCircuitSize: uint256(20), - publicInputsSize: uint256(0), + publicInputsSize: uint256(12304), ql: Honk.G1Point({ - x: uint256(0x10d36906c36e560297d7bc49c7661fbf50a476bea06e780c40d53a45c459599e), - y: uint256(0x1ed002ce45e75474d75d25ef1764280c6f1974b704ae77315baf31726978c175) + x: uint256(0x20f46ed8fd04696a67a05eaf00eab8364d0c6613911378ad075a2cabe0c6e959), + y: uint256(0x28aaca3062981f3803a6e9f1b7ed001ec9485fe6daaff563030d2f217cabc0e7) }), qr: Honk.G1Point({ - x: uint256(0x248d6c5782f08a14f794dae5832e8d4a5b42afebf0b248532d725e5d633e7215), - y: uint256(0x266b795b6cf4aa5fff2eb8c3e5a9b9780d6fd5d7170fc2b87f0e6aec8eaa9551) + x: uint256(0x1f0b6ec3b0212ad162651a9594e5d6e6d7b4f81d161fb04c00be5871f66a60cc), + y: uint256(0x013505ccd9a968d3309662d622d32b1ac351316d32e7996deb3b76323fe1ad9c) }), qo: Honk.G1Point({ - x: uint256(0x2137d78eee77dfd53fc4bf2adeacef7b15a94cc050a06fb8f52e5a28e938a78e), - y: uint256(0x1b0888693ee93d8804044d8d5e8d950ed53fbb451da45863f6f768145c7d24b1) + x: uint256(0x0999a011947240c3e51d4d58c1425f521a1c5ffdd161e837fa23e86f485f406d), + y: uint256(0x2b58265a5590fd70bc00a147e42658baf6c6d842002527fbc6c5f09a9bade415) }), q4: Honk.G1Point({ - x: uint256(0x00dceb0527695295e8bc90df562acf14d9bdb55e6250ca81034c7f56b9345985), - y: uint256(0x07963d90a20b5fbd22fcb35424b408b2ed41ab59fb2014027d9ec235a5f5905f) + x: uint256(0x171a4b6e911f59297cb6553275bec242426df2afaa4be9f55521eb8076be3ae0), + y: uint256(0x0d1f055cc8398a20fb276d49763c8dcdea63dacf600ea150a80f6847c1017266) }), qm: Honk.G1Point({ - x: uint256(0x11a037d3a9259c512f1039f1049fc7541cbbf315ddb90fe2869e6281c12023ef), - y: uint256(0x2d9966faba8461ee70d9db68e1d817fb21b15fb1e09e7476839dc6d07135cc23) + x: uint256(0x000d32dea00d92dea00000005806041ad00024c8900000002d00000000000000), + y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000) }), qc: Honk.G1Point({ - x: uint256(0x1219c094d86699487f09191b809a6be165c9b4808bbcadef831592295a1d7da6), - y: uint256(0x20b99b2dcadc856a88cc731f349aa47893a0569c4e747b4af0d7aae0dc9bdcda) + x: uint256(0x0003084bf4c510d1d0771cd5feb9ad975787d5a92d23e339162d8628d5e241ed), + y: uint256(0x21f9871c19e8a5b4e8764ee4d1f78e370af5330d8855b7e373ccf8f2f0ee5592) }), qArith: Honk.G1Point({ - x: uint256(0x147b6a393db982d0f0c7764012b6835c95bc0fa7926fda3f8bf684105282d388), - y: uint256(0x25b693e3f55d510c41dde8bd6b0d61b5c39db3888b55aeada5d7622f34254edf) + x: uint256(0x2f1ae34772a874e1cdc5134aedd885d4f0cc33fafd1681bfd96c83e46042d3e0), + y: uint256(0x120b10d7333ff20c8622693cce80fba874e96c912ce398be39ef45a84f0300c7) }), qDeltaRange: Honk.G1Point({ - x: uint256(0x2c9e01c750140eb161d24b9ee0fc8984acb60bf4e395b8e6ebbaa91c1be174e9), - y: uint256(0x1bc18c861d47b1f9a988e2e3d3d7a0a6252dc986d614fcca0e4f8ac7457c0892) + x: uint256(0x25f405da15293ea9c0550182f657ffd63d45b021f76fd7cdfb1daddf6762a87b), + y: uint256(0x1e90be4377dd7be59a06a0627493ea25170ee02a709a6e1a32339a0a39b4b796) }), qElliptic: Honk.G1Point({ - x: uint256(0x088a610ed8e4090aefcac9ab7277b21fdfb04ce437eb458bdb3696bff53c1cd0), - y: uint256(0x2c5353cedecc1e5f4d84b3ae7f3711e36deebc3071201975bf0fecc655545f5e) + x: uint256(0x2c5c9669f83715395e65e3286a7fdbae974c08b9eb7dec8ee07acfb15ab535af), + y: uint256(0x2cb8945e346b1074bcd3c7e72911ddc586870d54377b5d3fe7657572089a3a0b) }), qAux: Honk.G1Point({ - x: uint256(0x1baad7c6c4a0f76d721636e31a5b5c28c1062d21f2148339266343c8c1d38996), - y: uint256(0x1eb16da6aed4aa1a55302d002d233fd4dbb885c96431a494683dc97a9275f43b) + x: uint256(0x0a221e23189d5a934d666a1af63354aae7d8133a80e7d3081656be36771b1db7), + y: uint256(0x1b402958c962fa02055120ccfa4777e0562a1500596d31fc8f029ffa3ac69add) }), qLookup: Honk.G1Point({ - x: uint256(0x1d64341216e323f076ac53aa06192392677f44b67b6947dd6a0a1490fb32a083), - y: uint256(0x28d02cea9cc379ace2ae8779011e247ddc4213ef69895a8e634f425844107141) + x: uint256(0x1c1b5e0da292950dc8d2bd55deaf24fa2ffb22ae838f941e077887c17f2afcac), + y: uint256(0x22f6583ad9c3f8da311d590cb651fc409c9577a68c4018fd35e38566a3a18588) }), qPoseidon2External: Honk.G1Point({ - x: uint256(0x1e0266510d883b6379b58686bd63642eae499ea68a706cc9e70c14c9c0e8536a), - y: uint256(0x11491f77ce7999d3618f0bac66ef7c4f1ed122f862d1c1465e71ce1262c4d7bd) + x: uint256(0x2f856943c5ee3e14cf3b6f4c4866373dd6b1567c62a8819b05f0af37dbb6825d), + y: uint256(0x0eb63c2076230d34772a10dc2d6d9c6f2d7cbba0a5c8c30a290638e31cfb94fe) }), qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x22b036a9ca9be4e71743a125c08648843a55f2cf070dafbbda117ca79e071ad5), - y: uint256(0x12fd44e4853d17621023115fbb658d1150aa85fae5a020f07eddd2215812b2f8) + x: uint256(0x09f47eee49daf785f6537341d240f25fdfcb606b181ecdd9e2dc0ee487eea8c4), + y: uint256(0x12dccc545f4c8a5b6dd7dee88880d40dc9c1d92fbec228e75fe620c436946f57) }), s1: Honk.G1Point({ - x: uint256(0x1a18a989b31c09eea3da5ae3faa7680ef410474de274210f9c39ebfe6a798c7d), - y: uint256(0x2108883b1e5364123ffd7c32161f9228987ee6aa31ba3c579765f6096579b8e0) + x: uint256(0x023996c97fdb72f6ba018dbf25565ea30a9615d7f91d871949b4fe962d703487), + y: uint256(0x30404a2f028799b1f2a90566c5f1296973da69b568f86620a48316ed43489c07) }), s2: Honk.G1Point({ - x: uint256(0x26ddc6264203943a7c31aed2afb7d53fe32a7a38249897fc2a8771c65c414096), - y: uint256(0x0249864a3e742b55386cf6ab4051915fa677a11885e4b0eb04d20d38e9632afe) + x: uint256(0x0923badba8fad04ceb37862d8519ce750f313948606442eb1e8b252029d45681), + y: uint256(0x16e2a0ea4a9b901d2c33fb4afbf0e2e16fd90b36c11f273da473946ec2570659) }), s3: Honk.G1Point({ - x: uint256(0x250a1f5dd0a1e0ec7ab855db5863a25a567877ef1bd1c19e5bc1ccdb733b2956), - y: uint256(0x2cc285a8d6a6e91d142e2a941e23c0a7aee361316975b582e0370e46c4939d9f) + x: uint256(0x0b0cf425fe493bfc57a991a5cbfaefdb2e4941b202b279f9e2b0c6db890dcf1f), + y: uint256(0x1215e9b2a75efae2d1274e008d43f3640585a4f8016262d3e32b491d8041233e) }), s4: Honk.G1Point({ - x: uint256(0x0fc8be2a322d1c45d22b210211992629be0450555321e4a55c2cf2d8f5498c6c), - y: uint256(0x1091f3056debdf6a98ab5e4c6df48dc4fded590c78788baf2b394ff6005df6f6) + x: uint256(0x0d8e8adb9d7f93e2cfcde90b61cd87b1b3301b64f766921cd5ed043cddc409fc), + y: uint256(0x0927a2830958ba6886b9be4faca3536e7a9a6ade899f664245600f630c5530a8) }), t1: Honk.G1Point({ - x: uint256(0x1bf7da4add7c858eb94b75f2e78fbd89c84f5fa43824a0d5534173872ee099c2), - y: uint256(0x1b35fa2a35673699ee1cb260d9e6c4be79b26d488c26dc2531194e43c8f747ea) + x: uint256(0x2100dc5f3c96e05b79d2e5deaede9799613b5fa5fda16879a4e01496dad318b0), + y: uint256(0x0dd9861bed3ece688ec53d4648af6b39fa1105e67221d27250830c4b38378652) }), t2: Honk.G1Point({ - x: uint256(0x16bf79791869cec464180d5322eeaaef18fed6dc10c3e64e314c04d85c3faece), - y: uint256(0x2e2ec6341669b5b975e25e465af5d9e40533d5ac173554df19daed27f66c36ff) + x: uint256(0x189efef6ad68f3a4f97adc8c9541cfdb0d0cf4a02c51bf23a387feefe4302c26), + y: uint256(0x03d8dc2662b5f3fd4de5d8186d7b1181dfa0af5d68f48c64b9d7600d95556dcb) }), t3: Honk.G1Point({ - x: uint256(0x150253026f1b985165783c2f4ee1df612c826dda543d06d34711b965730ab69e), - y: uint256(0x0c4062ebcca21d81273b9c58d64447e4ee4d55effa8cbc8fdbd6a76bc3092264) + x: uint256(0x29a11faf9e2fd4c41e061e247120bbe2b49ab9ae0453c3831ae6e4e520144961), + y: uint256(0x089426aa63b98ecf2a2af850dfaaf6d4f67f095ba05e257d487da168f2f606c0) }), t4: Honk.G1Point({ - x: uint256(0x159f2541ce446c6d59ea3f06be91ec9f47c9c82f3e4fd10696511efaff4121fa), - y: uint256(0x15f873b33ec9467e1f0c4fb3a0b59a6fcd6f3480515f1ff5506c48f0c521f00f) + x: uint256(0x1801dbf4674e237a96e3e661f522d7e1000ba32cb10b6b1042e8a492243b8663), + y: uint256(0x0c2dfc2cc3c5e10e39cbd92ff0fced3015a0836c15e33d751eb32409dd16f6ab) }), id1: Honk.G1Point({ - x: uint256(0x0c02225e1d329e09a738ff6a3d1f2eefee2d9c2446f748430a4c9e3db3af493e), - y: uint256(0x22970a47d992efe75e1a9ae8c48617327596f0b9d1536898b516e9dc0d92e351) + x: uint256(0x08a717b501a32fd4eddb7a6fae4d0474b1612fc6723084259999ce2d9c54e7fd), + y: uint256(0x21e2b873ad3613b648340385f92bd1f44057fb02639d39390c164f79aa7ebee2) }), id2: Honk.G1Point({ - x: uint256(0x025b15baf18a3565112553243b581ab7c1ef2bb7b6cecb6fd3dbcb494f131c1b), - y: uint256(0x0784d79e6aa29c9c710670f3e62df4c3bf99a73a85bb255a009d5566da762426) + x: uint256(0x1d7fc3d0d2d83bba0de7de905956c586d127f0ebc2be06601fec423603471283), + y: uint256(0x172aa6319bc4d3ae5ab98b126c49051b6a043caec79d94cf819e3f223f72ecd2) }), id3: Honk.G1Point({ - x: uint256(0x2f0d8870dfa4fe4f0bcf1e8a8b69f750b15e8315a76dea5965fe82d369e00ffd), - y: uint256(0x0b8a634aa17cb7e29434a052392f7c40e013e37f2dfdcce584ecaa23a3508c89) + x: uint256(0x0582d66e6532135ff2d5ab1e5f44f6878e742ed13c8a19663aba5b05f85f25ae), + y: uint256(0x2296a32478ec04e19d9862f96a91145e076f4732a11b1b3a9ce47f202c146564) }), id4: Honk.G1Point({ - x: uint256(0x126143c034d5218ac854d254492806967ae0d23ec5684d341d730cd4dda79f08), - y: uint256(0x1c00c21435080bb1e5b99a42eba611eda1328b0e38e92fcd955d81e96b9b2917) + x: uint256(0x10675f0d3f3a90f33dad5a77c7968a687d9566c8fcdfbc3ad58f396741039968), + y: uint256(0x295783bc1876dabec577af369a5fbf07947a57bb47759014f01991beec0934cb) }), lagrangeFirst: Honk.G1Point({ - x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) + x: uint256(0x021b4d94b9512ffd6ce87e4aeedbcfa8f52acd0b40a29ccb45c6b4dfc1f9fb71), + y: uint256(0x03df675f4dc930162f78bd4254480022ce3faddddcd6e66fbae368991d1ab966) }), lagrangeLast: Honk.G1Point({ - x: uint256(0x1120d97a81a9c90c251f46b1ec3998bc67e7978323aebf46551a536bf4d0f167), - y: uint256(0x26d1e132ba53edea7d5e8aa5b21067176a3cf0ba74257f595e17bf0db56a98de) + x: uint256(0x2d00000000000000000000000000000000000000000000000000000000000000), + y: uint256(0x0100000000000000000000000000000000000000000000000000000000000000) }) }); return vk; @@ -1883,4 +1884,4 @@ contract HonkVerifier is BaseHonkVerifier(N, LOG_N, NUMBER_OF_PUBLIC_INPUTS) { function loadVerificationKey() internal pure override returns (Honk.VerificationKey memory) { return HonkVerificationKey.loadVerificationKey(); } -} \ No newline at end of file +} diff --git a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts index 2f318ebf51..ba7d4de284 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts @@ -6,69 +6,153 @@ import { network } from "hardhat"; import { zeroAddress, zeroHash } from "viem"; +import { ZKInputsGenerator } from "@crisp-e3/zk-inputs"; +import { + encryptVoteAndGenerateCRISPInputs, + generateProof, + VotingMode, + encodeVote, + MESSAGE, + generateMerkleProof, + hashLeaf, +} from "@crisp-e3/sdk"; import { expect } from "chai"; -import { MockEnclave } from "../types"; +import type { HonkVerifier, MockEnclave } from "../types"; + +let zkInputsGenerator = ZKInputsGenerator.withDefaults(); +let publicKey = zkInputsGenerator.generatePublicKey(); +const previousCiphertext = zkInputsGenerator.encryptVote( + publicKey, + new BigInt64Array([0n]) +); describe("CRISP Contracts", function () { - const nonZeroAddress = "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d"; + const nonZeroAddress = "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d"; - describe("deployment", () => { - it("should deploy the contracts", async () => { - const { ethers } = await network.connect(); - /* + describe("deployment", () => { + it("should deploy the contracts", async () => { + const { ethers } = await network.connect(); + /* IEnclave _enclave, IRiscZeroVerifier _verifier, CRISPInputValidatorFactory _inputValidatorFactory, HonkVerifier _honkVerifier, bytes32 _imageId */ - const program = await ethers.deployContract("CRISPProgram", [ - nonZeroAddress, - nonZeroAddress, - nonZeroAddress, - nonZeroAddress, - zeroHash - ]) - - expect(await program.getAddress()).to.not.equal(zeroAddress) - }) - }) - - describe("decode tally", () => { - it("should decode different tallies correctly", async () => { - const { ethers } = await network.connect(); - const mockEnclave = await ethers.deployContract("MockEnclave") as MockEnclave; - - const program = await ethers.deployContract("CRISPProgram", [ - await mockEnclave.getAddress(), - nonZeroAddress, - nonZeroAddress, - nonZeroAddress, - zeroHash - ]) - - // 2 * 2 + 1 * 1 = 5 Y - // 2 * 1 + 0 * 1 = 2 N - const tally1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 1, 0]; - - await mockEnclave.setPlaintextOutput(tally1); - - const decodedTally1 = await program.decodeTally(0); - - expect(decodedTally1[0]).to.equal(5n) - expect(decodedTally1[1]).to.equal(2n) - - // 1 * 1 + 2 * 2 + 5 * 16 + 8 * 1024 = 8277 - // 2 * 1 + 3 * 64 + 1024 = - const tally2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0 , 0, 0, 0, 5, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 , 0, 3, 0, 0, 0, 0, 1, 0]; - await mockEnclave.setPlaintextOutput(tally2); - - const decodedTally2 = await program.decodeTally(0); - - expect(decodedTally2[0]).to.equal(8277n) - expect(decodedTally2[1]).to.equal(1218n) - - }) - }) -}) + const program = await ethers.deployContract("CRISPProgram", [ + nonZeroAddress, + nonZeroAddress, + nonZeroAddress, + nonZeroAddress, + zeroHash, + ]); + + expect(await program.getAddress()).to.not.equal(zeroAddress); + }); + }); + + describe("decode tally", () => { + it("should decode different tallies correctly", async () => { + const { ethers } = await network.connect(); + const mockEnclave = (await ethers.deployContract( + "MockEnclave" + )) as MockEnclave; + + const program = await ethers.deployContract("CRISPProgram", [ + await mockEnclave.getAddress(), + nonZeroAddress, + nonZeroAddress, + nonZeroAddress, + zeroHash, + ]); + + // 2 * 2 + 1 * 1 = 5 Y + // 2 * 1 + 0 * 1 = 2 N + const tally1 = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + ]; + + await mockEnclave.setPlaintextOutput(tally1); + + const decodedTally1 = await program.decodeTally(0); + + expect(decodedTally1[0]).to.equal(5n); + expect(decodedTally1[1]).to.equal(2n); + + // 1 * 1 + 2 * 2 + 5 * 16 + 8 * 1024 = 8277 + // 2 * 1 + 3 * 64 + 1024 = + const tally2 = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 5, + 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 3, 0, 0, 0, 0, 1, 0, + ]; + await mockEnclave.setPlaintextOutput(tally2); + + const decodedTally2 = await program.decodeTally(0); + + expect(decodedTally2[0]).to.equal(8277n); + expect(decodedTally2[1]).to.equal(1218n); + }); + }); + + describe("validate input", () => { + it("should verify the proof correctly wi", async function () { + // It needs some time to generate the proof. + this.timeout(60000); + + const { ethers } = await network.connect(); + + const signers = await ethers.getSigners(); + const signer = signers[0]; + const address = ( + await signer.getAddress() + ).toLowerCase() as `0x${string}`; + + const honkVerifier = (await ethers.deployContract( + "HonkVerifier" + )) as HonkVerifier; + + const vote = { yes: 10n, no: 0n }; + const votingPower = vote.yes; + + const encodedVote = encodeVote(vote, VotingMode.GOVERNANCE, votingPower); + + const signature = (await signer.signMessage(MESSAGE)) as `0x${string}`; + const leaf = hashLeaf(address, vote.yes.toString()); + const leaves = [...[10n, 20n], leaf]; + + const threshold = 0n; + const merkleProof = generateMerkleProof( + threshold, + vote.yes, + address, + leaves, + 20 + ); + + const inputs = await encryptVoteAndGenerateCRISPInputs({ + encodedVote, + publicKey, + previousCiphertext, + signature, + message: MESSAGE, + merkleData: merkleProof, + balance: vote.yes, + slotAddress: address, + isFirstVote: true, + }); + + const proof = await generateProof(inputs); + + const isValid = await honkVerifier.verify( + proof.proof, + proof.publicInputs + ); + + expect(isValid).to.be.true; + }); + }); +}); diff --git a/examples/CRISP/packages/crisp-sdk/src/vote.ts b/examples/CRISP/packages/crisp-sdk/src/vote.ts index 86bc8ce47b..1780494702 100644 --- a/examples/CRISP/packages/crisp-sdk/src/vote.ts +++ b/examples/CRISP/packages/crisp-sdk/src/vote.ts @@ -266,7 +266,7 @@ export const generateProof = async (crispInputs: CRISPCircuitInputs): Promise Date: Mon, 10 Nov 2025 10:24:02 +0100 Subject: [PATCH 02/13] chore: update noir/aztec dependencies --- examples/CRISP/circuits/.gitignore | 3 +- examples/CRISP/package.json | 6 +- .../contracts/CRISPVerifier.sol | 178 ++++++++++-------- .../tests/crisp.contracts.test.ts | 2 +- .../CRISP/packages/crisp-sdk/package.json | 4 +- examples/CRISP/packages/crisp-sdk/src/vote.ts | 15 +- pnpm-lock.yaml | 131 ++++++++++++- 7 files changed, 251 insertions(+), 88 deletions(-) diff --git a/examples/CRISP/circuits/.gitignore b/examples/CRISP/circuits/.gitignore index 767eaf4c68..5ea1c2abe2 100644 --- a/examples/CRISP/circuits/.gitignore +++ b/examples/CRISP/circuits/.gitignore @@ -1,2 +1,3 @@ target/ -Prover.toml \ No newline at end of file +Prover.toml +crs \ No newline at end of file diff --git a/examples/CRISP/package.json b/examples/CRISP/package.json index c289a49acf..2e33479df0 100644 --- a/examples/CRISP/package.json +++ b/examples/CRISP/package.json @@ -31,12 +31,12 @@ "@synthetixio/synpress": "^4.1.0", "@synthetixio/synpress-cache": "^0.0.12", "@types/node": "^22.18.0", - "dotenv": "^16.4.5", "concurrently": "^9.1.2", + "dotenv": "^16.4.5", + "ethers": "^6.15.0", "playwright": "1.52.0", "typescript": "5.8.3", - "wait-on": "^8.0.3", - "ethers": "^6.15.0" + "wait-on": "^8.0.3" }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808" } diff --git a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol index 514a915eed..d38e751e98 100644 --- a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol +++ b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol @@ -3,125 +3,124 @@ // This file is provided WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. - pragma solidity >=0.8.21; uint256 constant N = 1048576; uint256 constant LOG_N = 20; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 12304; +uint256 constant NUMBER_OF_PUBLIC_INPUTS = 12321; library HonkVerificationKey { function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { Honk.VerificationKey memory vk = Honk.VerificationKey({ circuitSize: uint256(1048576), logCircuitSize: uint256(20), - publicInputsSize: uint256(12304), + publicInputsSize: uint256(12321), ql: Honk.G1Point({ - x: uint256(0x20f46ed8fd04696a67a05eaf00eab8364d0c6613911378ad075a2cabe0c6e959), - y: uint256(0x28aaca3062981f3803a6e9f1b7ed001ec9485fe6daaff563030d2f217cabc0e7) + x: uint256(0x11ab7480853c0994c0ee6f875c793a98bab22e5c7f90f770b0427a2641ba49bd), + y: uint256(0x09a4a4bb7300c3215173bc2b80b90be96d12705260bb653c19245bc9a6952488) }), qr: Honk.G1Point({ - x: uint256(0x1f0b6ec3b0212ad162651a9594e5d6e6d7b4f81d161fb04c00be5871f66a60cc), - y: uint256(0x013505ccd9a968d3309662d622d32b1ac351316d32e7996deb3b76323fe1ad9c) + x: uint256(0x197295d419d7d48c56e0ecb700db3e676ae397c90cb385453c2e9e919a8367c3), + y: uint256(0x23188dc025634fb3a1e81fa9998065320d9533e616d5b08afe0833a41b0d117f) }), qo: Honk.G1Point({ - x: uint256(0x0999a011947240c3e51d4d58c1425f521a1c5ffdd161e837fa23e86f485f406d), - y: uint256(0x2b58265a5590fd70bc00a147e42658baf6c6d842002527fbc6c5f09a9bade415) + x: uint256(0x03374d5d8e633f27e9377e108089232000a3d8aec29b6f0d4c31793b8191a5e7), + y: uint256(0x2dc1d873b6dfb4d4608a75c872801dab3ad9eeff27b2650b25771b0a2d7f8289) }), q4: Honk.G1Point({ - x: uint256(0x171a4b6e911f59297cb6553275bec242426df2afaa4be9f55521eb8076be3ae0), - y: uint256(0x0d1f055cc8398a20fb276d49763c8dcdea63dacf600ea150a80f6847c1017266) + x: uint256(0x16cdb42cfe1fd558dae41be23f9980b72dc7a2c2a9de8aba0c406af8b35fd92d), + y: uint256(0x034ebdb1c2aefe025fede6dcce808cbaa6821d7eb2ff48cbdd4935a74b76e072) }), qm: Honk.G1Point({ - x: uint256(0x000d32dea00d92dea00000005806041ad00024c8900000002d00000000000000), - y: uint256(0x0000000000000000000000000000000000000000000000000000000000000000) + x: uint256(0x20d73990f6d612ab63409f72e6ce05a9706beca47246be39370dad53cebf3e33), + y: uint256(0x07a3afaf6fbf9b5dbc5a4968b173f5ddb07921d7314d15ebd075fef2ca5984db) }), qc: Honk.G1Point({ - x: uint256(0x0003084bf4c510d1d0771cd5feb9ad975787d5a92d23e339162d8628d5e241ed), - y: uint256(0x21f9871c19e8a5b4e8764ee4d1f78e370af5330d8855b7e373ccf8f2f0ee5592) + x: uint256(0x15559b08bc16f95c17edc29ed99a8b2247fc09b858aa0abd04708965d074a2d4), + y: uint256(0x1702febc6b0dd8b6a7d2736804f2ade40132d1ab012c7bb385d7cadd0504d86d) }), qArith: Honk.G1Point({ - x: uint256(0x2f1ae34772a874e1cdc5134aedd885d4f0cc33fafd1681bfd96c83e46042d3e0), - y: uint256(0x120b10d7333ff20c8622693cce80fba874e96c912ce398be39ef45a84f0300c7) + x: uint256(0x279b1e6a922fc5789f086c9fa429a2457e72a37705fad297039809b6e0b892e2), + y: uint256(0x28aab2f65345f12169bed84736d33c6f8ea4c5391b9fd27e51d553de53edcee2) }), qDeltaRange: Honk.G1Point({ - x: uint256(0x25f405da15293ea9c0550182f657ffd63d45b021f76fd7cdfb1daddf6762a87b), - y: uint256(0x1e90be4377dd7be59a06a0627493ea25170ee02a709a6e1a32339a0a39b4b796) + x: uint256(0x010283af75922802e4351c05ccbcec65c51db947749ab8e1b4488a0ba66e8467), + y: uint256(0x2e7da5f4d5f99540bd26141ae760988d51e7281f62e72db693628145a9b84072) }), qElliptic: Honk.G1Point({ - x: uint256(0x2c5c9669f83715395e65e3286a7fdbae974c08b9eb7dec8ee07acfb15ab535af), - y: uint256(0x2cb8945e346b1074bcd3c7e72911ddc586870d54377b5d3fe7657572089a3a0b) + x: uint256(0x292b94199d88fb5daf62b70b737926076c14346fbf59f4588cfd8a18c69f0f06), + y: uint256(0x2aaa3fbb2511272aab0e4b06e63abf0d0d54eb51a4cbcc6511572403a96daa0c) }), qAux: Honk.G1Point({ - x: uint256(0x0a221e23189d5a934d666a1af63354aae7d8133a80e7d3081656be36771b1db7), - y: uint256(0x1b402958c962fa02055120ccfa4777e0562a1500596d31fc8f029ffa3ac69add) + x: uint256(0x067ed4882213477ccd49a2017534e6fe7017691962085cadd0b5cd5567815a4a), + y: uint256(0x2753ebb00d4f25941251c2bd31684970d0922965563688f00c77b81776f1a2d8) }), qLookup: Honk.G1Point({ - x: uint256(0x1c1b5e0da292950dc8d2bd55deaf24fa2ffb22ae838f941e077887c17f2afcac), - y: uint256(0x22f6583ad9c3f8da311d590cb651fc409c9577a68c4018fd35e38566a3a18588) + x: uint256(0x045d382b516ec5bf15829c61492d624c981d11ecc86e4ddf6f05a5326a0f1f17), + y: uint256(0x03c40d1e7586e5a18de27dac5a049f851ccd7db0d6daf165cc6d7a474d8d5786) }), qPoseidon2External: Honk.G1Point({ - x: uint256(0x2f856943c5ee3e14cf3b6f4c4866373dd6b1567c62a8819b05f0af37dbb6825d), - y: uint256(0x0eb63c2076230d34772a10dc2d6d9c6f2d7cbba0a5c8c30a290638e31cfb94fe) + x: uint256(0x0ddafd8f31b9ac7e7623199996375b060b3af3d5e0801daeab90c5cbe1b5ed16), + y: uint256(0x2081c961a09710e7a90f8ad76c84de1510c3f6c3ec45517cd1ff1ba4ed619913) }), qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x09f47eee49daf785f6537341d240f25fdfcb606b181ecdd9e2dc0ee487eea8c4), - y: uint256(0x12dccc545f4c8a5b6dd7dee88880d40dc9c1d92fbec228e75fe620c436946f57) + x: uint256(0x24d33e04a465bba0ba5a573af010b1f51310c3f0929d526f90f1c250e26eb147), + y: uint256(0x04ed04e9b3dd68235ae44476665dd8d9c0426df63d3f8a456ae2ae97162e76e0) }), s1: Honk.G1Point({ - x: uint256(0x023996c97fdb72f6ba018dbf25565ea30a9615d7f91d871949b4fe962d703487), - y: uint256(0x30404a2f028799b1f2a90566c5f1296973da69b568f86620a48316ed43489c07) + x: uint256(0x01717cb1b7ea32c92fbdd4e9ca97e34058b62016b7e8ed9ca85eee38727ad680), + y: uint256(0x1f303204bb194c0ddf8fb18859ad37720ecd6efd390d224b7b2cafcff6938dfc) }), s2: Honk.G1Point({ - x: uint256(0x0923badba8fad04ceb37862d8519ce750f313948606442eb1e8b252029d45681), - y: uint256(0x16e2a0ea4a9b901d2c33fb4afbf0e2e16fd90b36c11f273da473946ec2570659) + x: uint256(0x025216492c6d8f1424a0af1919eef0092726ec86f205f4a41a8ee7673b564f1c), + y: uint256(0x24e3ad32113cb91f9d43fd78e02aa55e807ad85e5c3210eef575090269669ef1) }), s3: Honk.G1Point({ - x: uint256(0x0b0cf425fe493bfc57a991a5cbfaefdb2e4941b202b279f9e2b0c6db890dcf1f), - y: uint256(0x1215e9b2a75efae2d1274e008d43f3640585a4f8016262d3e32b491d8041233e) + x: uint256(0x1d6d125f8375c1cf467de7ba1818b9e50b10cae1ffb740bd6173478c2e253734), + y: uint256(0x0638b55bd81bec9ed6e5b8db7ee25401ef3628c850f7b6d76738a7c911530b87) }), s4: Honk.G1Point({ - x: uint256(0x0d8e8adb9d7f93e2cfcde90b61cd87b1b3301b64f766921cd5ed043cddc409fc), - y: uint256(0x0927a2830958ba6886b9be4faca3536e7a9a6ade899f664245600f630c5530a8) + x: uint256(0x1180ecea5358ef0f3ae9e0f6131bb20146056933b106aaa2a672c03daf1e9a30), + y: uint256(0x058c742592719bdf1b489e804990a42ee3cbb9def577467961d117e06ae442b3) }), t1: Honk.G1Point({ - x: uint256(0x2100dc5f3c96e05b79d2e5deaede9799613b5fa5fda16879a4e01496dad318b0), - y: uint256(0x0dd9861bed3ece688ec53d4648af6b39fa1105e67221d27250830c4b38378652) + x: uint256(0x1cd34417941390ad1d78afcaabf7076e0a14cb155debdc3f26a9a1262d4533cb), + y: uint256(0x27bead0375689fc07d70af56f50dc436f1ef04de5c830404874a57ef7b7e4a56) }), t2: Honk.G1Point({ - x: uint256(0x189efef6ad68f3a4f97adc8c9541cfdb0d0cf4a02c51bf23a387feefe4302c26), - y: uint256(0x03d8dc2662b5f3fd4de5d8186d7b1181dfa0af5d68f48c64b9d7600d95556dcb) + x: uint256(0x2c7c23940bfef093f10d770d15d99062cac798dd3710f1e8f33ce9cc4f600da7), + y: uint256(0x15640aaa42131fdb97d7352af2defa8649242b65d4b8bb124d49c85a21352bbb) }), t3: Honk.G1Point({ - x: uint256(0x29a11faf9e2fd4c41e061e247120bbe2b49ab9ae0453c3831ae6e4e520144961), - y: uint256(0x089426aa63b98ecf2a2af850dfaaf6d4f67f095ba05e257d487da168f2f606c0) + x: uint256(0x0575f603bcec91b98a5b59db5f96ab53ecfb365c84eca91899a06054f1eefc7f), + y: uint256(0x1b62fdb53646ebd136e5c5bdfce5560351785d5b577fc3c3db22cf93e3ebbddc) }), t4: Honk.G1Point({ - x: uint256(0x1801dbf4674e237a96e3e661f522d7e1000ba32cb10b6b1042e8a492243b8663), - y: uint256(0x0c2dfc2cc3c5e10e39cbd92ff0fced3015a0836c15e33d751eb32409dd16f6ab) + x: uint256(0x162d18f57637d1935879cb690fcc33c3c047252fecf1d970e0acfb58f2a156e2), + y: uint256(0x065ffdba45cb7f494e9cbdf803d0b6dd428f7d9567a6eee3b624f01232d71812) }), id1: Honk.G1Point({ - x: uint256(0x08a717b501a32fd4eddb7a6fae4d0474b1612fc6723084259999ce2d9c54e7fd), - y: uint256(0x21e2b873ad3613b648340385f92bd1f44057fb02639d39390c164f79aa7ebee2) + x: uint256(0x1ddd559c79bf177b7c5cafe1fa3a8a4c80ebdf63b967f2b3d3c6b46dbd39809a), + y: uint256(0x13ad9fe1ed53b97ccbb8c233d6b7aed6d61c7a038d2d4ae6cb320498323bad89) }), id2: Honk.G1Point({ - x: uint256(0x1d7fc3d0d2d83bba0de7de905956c586d127f0ebc2be06601fec423603471283), - y: uint256(0x172aa6319bc4d3ae5ab98b126c49051b6a043caec79d94cf819e3f223f72ecd2) + x: uint256(0x121eddfa278380b7e440c94836a30d6d8f15d52a6242a5075d503544ecef5509), + y: uint256(0x1ed6fcdcd0c3f871a886f321b998be23f2f96d0a7550af3db266aa4e73d51ab7) }), id3: Honk.G1Point({ - x: uint256(0x0582d66e6532135ff2d5ab1e5f44f6878e742ed13c8a19663aba5b05f85f25ae), - y: uint256(0x2296a32478ec04e19d9862f96a91145e076f4732a11b1b3a9ce47f202c146564) + x: uint256(0x1ae077c555042138f18e96214a7dee716fec159e885e285260fac7c6362990bf), + y: uint256(0x2f92bb28595ce751e5dcbddb93c7122f0bd105eb1e600bd73e40f5bc26115461) }), id4: Honk.G1Point({ - x: uint256(0x10675f0d3f3a90f33dad5a77c7968a687d9566c8fcdfbc3ad58f396741039968), - y: uint256(0x295783bc1876dabec577af369a5fbf07947a57bb47759014f01991beec0934cb) + x: uint256(0x031a27b1fb99b50ba6281ae65b14fff94731de5efd9116c60b9e99b5f72414cf), + y: uint256(0x09218fcb88888ffd5223063db6568c90c85e0a6b8924747d3b9c8e9659475575) }), lagrangeFirst: Honk.G1Point({ - x: uint256(0x021b4d94b9512ffd6ce87e4aeedbcfa8f52acd0b40a29ccb45c6b4dfc1f9fb71), - y: uint256(0x03df675f4dc930162f78bd4254480022ce3faddddcd6e66fbae368991d1ab966) + x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), + y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) }), lagrangeLast: Honk.G1Point({ - x: uint256(0x2d00000000000000000000000000000000000000000000000000000000000000), - y: uint256(0x0100000000000000000000000000000000000000000000000000000000000000) + x: uint256(0x1bf7a989829b904caab4a07e61c9312e50b43aabf923d52133126b9fc6de38ee), + y: uint256(0x0f265aa0270e42290c3814c6b4faa80004ec7bd8cfadf0518b6221349869d2eb) }) }); return vk; @@ -273,6 +272,7 @@ uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; uint256 constant NUMBER_OF_ENTITIES = 40; uint256 constant NUMBER_UNSHIFTED = 35; uint256 constant NUMBER_TO_BE_SHIFTED = 5; +uint256 constant PAIRING_POINTS_SIZE = 16; // Alphas are used as relation separators so there should be NUMBER_OF_SUBRELATIONS - 1 uint256 constant NUMBER_OF_ALPHAS = 25; @@ -390,6 +390,8 @@ library Honk { struct Proof { + // Pairing point object + Fr[PAIRING_POINTS_SIZE] pairingPointObject; // Free wires Honk.G1ProofPoint w1; Honk.G1ProofPoint w2; @@ -487,9 +489,13 @@ library TranscriptLib { round0[0] = bytes32(circuitSize); round0[1] = bytes32(publicInputsSize); round0[2] = bytes32(pubInputsOffset); - for (uint256 i = 0; i < publicInputsSize; i++) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1331): Consider making publicInputsSize not include pairing point object. + for (uint256 i = 0; i < publicInputsSize - PAIRING_POINTS_SIZE; i++) { round0[3 + i] = bytes32(publicInputs[i]); } + for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { + round0[3 + publicInputsSize - PAIRING_POINTS_SIZE + i] = FrLib.toBytes32(proof.pairingPointObject[i]); + } // Create the first challenge // Note: w4 is added to the challenge later on @@ -674,19 +680,33 @@ library TranscriptLib { } function loadProof(bytes calldata proof) internal pure returns (Honk.Proof memory p) { - // Commitments - p.w1 = bytesToG1ProofPoint(proof[0x0:0x80]); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1332): Optimize this away when we finalize. + uint256 boundary = 0x0; - p.w2 = bytesToG1ProofPoint(proof[0x80:0x100]); - p.w3 = bytesToG1ProofPoint(proof[0x100:0x180]); + // Pairing point object + for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { + p.pairingPointObject[i] = bytesToFr(proof[boundary:boundary + 0x20]); + boundary += 0x20; + } + // Commitments + p.w1 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; + p.w2 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; + p.w3 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; // Lookup / Permutation Helper Commitments - p.lookupReadCounts = bytesToG1ProofPoint(proof[0x180:0x200]); - p.lookupReadTags = bytesToG1ProofPoint(proof[0x200:0x280]); - p.w4 = bytesToG1ProofPoint(proof[0x280:0x300]); - p.lookupInverses = bytesToG1ProofPoint(proof[0x300:0x380]); - p.zPerm = bytesToG1ProofPoint(proof[0x380:0x400]); - uint256 boundary = 0x400; + p.lookupReadCounts = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; + p.lookupReadTags = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; + p.w4 = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; + p.lookupInverses = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; + p.zPerm = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); + boundary += 0x80; // Sumcheck univariates for (uint256 i = 0; i < CONST_PROOF_SIZE_LOG_N; i++) { @@ -716,7 +736,7 @@ library TranscriptLib { // Shplonk p.shplonkQ = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); - boundary = boundary + 0x80; + boundary += 0x80; // KZG p.kzgQuotient = bytesToG1ProofPoint(proof[boundary:boundary + 0x80]); } @@ -1543,7 +1563,7 @@ abstract contract BaseHonkVerifier is IVerifier { error ShpleminiFailed(); // Number of field elements in a ultra honk zero knowledge proof - uint256 constant PROOF_SIZE = 440; + uint256 constant PROOF_SIZE = 456; function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); @@ -1556,7 +1576,7 @@ abstract contract BaseHonkVerifier is IVerifier { Honk.VerificationKey memory vk = loadVerificationKey(); Honk.Proof memory p = TranscriptLib.loadProof(proof); - if (publicInputs.length != vk.publicInputsSize) { + if (publicInputs.length != vk.publicInputsSize - PAIRING_POINTS_SIZE) { revert PublicInputsLengthWrong(); } @@ -1567,7 +1587,7 @@ abstract contract BaseHonkVerifier is IVerifier { // Derive public input delta // TODO(https://github.com/AztecProtocol/barretenberg/issues/1281): Add pubInputsOffset to VK or remove entirely. t.relationParameters.publicInputsDelta = computePublicInputDelta( - publicInputs, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1 + publicInputs, p.pairingPointObject, t.relationParameters.beta, t.relationParameters.gamma, /*pubInputsOffset=*/1 ); // Sumcheck @@ -1580,7 +1600,7 @@ abstract contract BaseHonkVerifier is IVerifier { return sumcheckVerified && shpleminiVerified; // Boolean condition not required - nice for vanity :) } - function computePublicInputDelta(bytes32[] memory publicInputs, Fr beta, Fr gamma, uint256 offset) + function computePublicInputDelta(bytes32[] memory publicInputs, Fr[PAIRING_POINTS_SIZE] memory pairingPointObject, Fr beta, Fr gamma, uint256 offset) internal view returns (Fr publicInputDelta) @@ -1592,7 +1612,7 @@ abstract contract BaseHonkVerifier is IVerifier { Fr denominatorAcc = gamma - (beta * FrLib.from(offset + 1)); { - for (uint256 i = 0; i < numPublicInputs; i++) { + for (uint256 i = 0; i < numPublicInputs - PAIRING_POINTS_SIZE; i++) { Fr pubInput = FrLib.fromBytes32(publicInputs[i]); numerator = numerator * (numeratorAcc + pubInput); @@ -1601,6 +1621,16 @@ abstract contract BaseHonkVerifier is IVerifier { numeratorAcc = numeratorAcc + beta; denominatorAcc = denominatorAcc - beta; } + + for (uint256 i = 0; i < PAIRING_POINTS_SIZE; i++) { + Fr pubInput = pairingPointObject[i]; + + numerator = numerator * (numeratorAcc + pubInput); + denominator = denominator * (denominatorAcc + pubInput); + + numeratorAcc = numeratorAcc + beta; + denominatorAcc = denominatorAcc - beta; + } } // Fr delta = numerator / denominator; // TOOO: batch invert later? diff --git a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts index ba7d4de284..6f305a9fc4 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts @@ -99,7 +99,7 @@ describe("CRISP Contracts", function () { }); describe("validate input", () => { - it("should verify the proof correctly wi", async function () { + it("should verify the proof correctly with the crisp verifier", async function () { // It needs some time to generate the proof. this.timeout(60000); diff --git a/examples/CRISP/packages/crisp-sdk/package.json b/examples/CRISP/packages/crisp-sdk/package.json index 48f2c2e5c5..431297efd0 100644 --- a/examples/CRISP/packages/crisp-sdk/package.json +++ b/examples/CRISP/packages/crisp-sdk/package.json @@ -46,8 +46,8 @@ "@zk-kit/lean-imt": "^2.2.4", "poseidon-lite": "^0.3.0", "viem": "2.30.6", - "@aztec/bb.js": "^0.82.2", - "@noir-lang/noir_js": "1.0.0-beta.3" + "@aztec/bb.js": "0.87.0", + "@noir-lang/noir_js": "1.0.0-beta.9" }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808" } diff --git a/examples/CRISP/packages/crisp-sdk/src/vote.ts b/examples/CRISP/packages/crisp-sdk/src/vote.ts index 1780494702..c08fddf5b9 100644 --- a/examples/CRISP/packages/crisp-sdk/src/vote.ts +++ b/examples/CRISP/packages/crisp-sdk/src/vote.ts @@ -263,11 +263,14 @@ export const generateMaskVote = async ( export const generateProof = async (crispInputs: CRISPCircuitInputs): Promise => { const noir = new Noir(circuit as CompiledCircuit) - const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode) + const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode, { threads: 4 }) const { witness } = await noir.execute(crispInputs as any) + const proof = await backend.generateProof(witness, { keccak: true }) + await backend.destroy() + return proof } @@ -275,11 +278,13 @@ export const generateProofWithReturnValue = async ( crispInputs: CRISPCircuitInputs, ): Promise<{ returnValue: unknown; proof: ProofData }> => { const noir = new Noir(circuit as CompiledCircuit) - const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode) + const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode, { threads: 4 }) const { witness, returnValue } = await noir.execute(crispInputs as any) const proof = await backend.generateProof(witness, { keccak: true }) + await backend.destroy() + return { returnValue, proof } } @@ -294,5 +299,9 @@ export const getCircuitOutputValue = async (crispInputs: CRISPCircuitInputs): Pr export const verifyProof = async (proof: ProofData): Promise => { const backend = new UltraHonkBackend((circuit as CompiledCircuit).bytecode) - return await backend.verifyProof(proof) + const isValid = await backend.verifyProof(proof, { keccak: true }) + + await backend.destroy() + + return isValid } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0bd915214b..093ab7b112 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -349,14 +349,14 @@ importers: examples/CRISP/packages/crisp-sdk: dependencies: '@aztec/bb.js': - specifier: ^0.82.2 - version: 0.82.3 + specifier: 0.87.0 + version: 0.87.0 '@crisp-e3/zk-inputs': specifier: workspace:* version: link:../crisp-zk-inputs '@noir-lang/noir_js': - specifier: 1.0.0-beta.3 - version: 1.0.0-beta.3 + specifier: 1.0.0-beta.9 + version: 1.0.0-beta.9 '@zk-kit/lean-imt': specifier: ^2.2.4 version: 2.2.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -844,6 +844,10 @@ packages: resolution: {integrity: sha512-jtnCqf+/QLw5yJGOmy818RMQqzHzHqcROtTdQZJybSxp0z3h76xpLSwoDQUBmZZVbP9e46FJjOLqB6gM9gY5cw==} hasBin: true + '@aztec/bb.js@0.87.0': + resolution: {integrity: sha512-1tGxrJc/or9p4zwP7yvSLHU0z0N/DQGLfIeTYRdlQQPBMcnKX51rMI0PJ07/zZj0XxwHVFlqtV+PqvFBszIPwA==} + hasBin: true + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -2472,6 +2476,36 @@ packages: '@motionone/utils@10.18.0': resolution: {integrity: sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} + cpu: [arm64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==} + cpu: [x64] + os: [darwin] + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==} + cpu: [arm64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==} + cpu: [arm] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==} + cpu: [x64] + os: [linux] + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==} + cpu: [x64] + os: [win32] + '@napi-rs/simple-git-android-arm-eabi@0.1.22': resolution: {integrity: sha512-JQZdnDNm8o43A5GOzwN/0Tz3CDBQtBUNqzVwEopm32uayjdjxev1Csp1JeaqF3v9djLDIvsSE39ecsN2LhCKKQ==} engines: {node: '>= 10'} @@ -2702,15 +2736,27 @@ packages: '@noir-lang/acvm_js@1.0.0-beta.3': resolution: {integrity: sha512-Dc6g5rJr/x7tKsWvnTbZvjwqI1uiAtvq+NAz5tcLRzUHJw6NAvDXEH5h117h+BfIAhhsHXuPTkDfDB1Gnqp/Bg==} + '@noir-lang/acvm_js@1.0.0-beta.9': + resolution: {integrity: sha512-cWDKgOkDCj6USfSITB0IM/o3ThndLOsrH6pDptaB6D6wHpSxTOpl/pKP8m1KHXGLVsU0BjIImZ2RrWB4F3a2Pw==} + '@noir-lang/noir_js@1.0.0-beta.3': resolution: {integrity: sha512-Nt/rP7zRMOfNq9urD8+GtRpYqEc0K10FoKXs/v+ZTbGaP6Jkm7+F+UPj2bkWy66k1HNzsN6ortli7c7mnLDHwA==} + '@noir-lang/noir_js@1.0.0-beta.9': + resolution: {integrity: sha512-UDHvQBvWiAbo70+taFQyUgBysVxgxuMkEXxtQUPD8v9sbHp4J5ecGRrtp/1eq15D0zpVc34Vfo8zy2CWndfbaA==} + '@noir-lang/noirc_abi@1.0.0-beta.3': resolution: {integrity: sha512-L6BI64ennatwTUciHqQ14ahUFsgzL41tzghqUELzO7XojasStcWDaSMjlTxca/2pvpWtEJHDtseKe1VZWIIVXQ==} + '@noir-lang/noirc_abi@1.0.0-beta.9': + resolution: {integrity: sha512-JOBLJBZqE6skGztI5xy4GW5WB40YGADt0mU/vf1QAuVY9yArRU3oAJIjuXi4Mo1fvE1TSx/4XPZr7Rocl6Effg==} + '@noir-lang/types@1.0.0-beta.3': resolution: {integrity: sha512-BPOmf0qDiTn4wH1Lo7mHa67GTQFueIVaDUcUb+N9+ALiXC5nVU8HrzWmx1yvZB64ZiCEy7yPdNEaNrszSrE2fg==} + '@noir-lang/types@1.0.0-beta.9': + resolution: {integrity: sha512-2KB4uSUUHjDZzrUY8CIRyaIS4Q9d0s1T9bwabw1rysSBICDkgKOdVKkG0szaCFbmeDNQ3kqanPjqBj7IEEHD7A==} + '@nomicfoundation/edr-darwin-arm64@0.12.0-next.10': resolution: {integrity: sha512-LYXaU0Pk7zA4iAHMdvZ9Gs5QaScs9n5IpclWBNVevSHnL1/uJiFLDF4FYE/NonvaCST6Rd0E4MS3pJltsrBQmA==} engines: {node: '>= 20'} @@ -7441,6 +7487,13 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msgpackr-extract@3.0.3: + resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} + hasBin: true + + msgpackr@1.11.5: + resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==} + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} @@ -7549,6 +7602,10 @@ packages: encoding: optional: true + node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -9997,6 +10054,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@aztec/bb.js@0.87.0': + dependencies: + comlink: 4.4.2 + commander: 12.1.0 + debug: 4.4.3(supports-color@8.1.1) + fflate: 0.8.2 + msgpackr: 1.11.5 + pako: 2.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -12108,6 +12177,24 @@ snapshots: hey-listen: 1.0.8 tslib: 2.8.1 + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + optional: true + '@napi-rs/simple-git-android-arm-eabi@0.1.22': optional: true @@ -12262,18 +12349,33 @@ snapshots: '@noir-lang/acvm_js@1.0.0-beta.3': {} + '@noir-lang/acvm_js@1.0.0-beta.9': {} + '@noir-lang/noir_js@1.0.0-beta.3': dependencies: '@noir-lang/acvm_js': 1.0.0-beta.3 '@noir-lang/noirc_abi': 1.0.0-beta.3 '@noir-lang/types': 1.0.0-beta.3 + '@noir-lang/noir_js@1.0.0-beta.9': + dependencies: + '@noir-lang/acvm_js': 1.0.0-beta.9 + '@noir-lang/noirc_abi': 1.0.0-beta.9 + '@noir-lang/types': 1.0.0-beta.9 + pako: 2.1.0 + '@noir-lang/noirc_abi@1.0.0-beta.3': dependencies: '@noir-lang/types': 1.0.0-beta.3 + '@noir-lang/noirc_abi@1.0.0-beta.9': + dependencies: + '@noir-lang/types': 1.0.0-beta.9 + '@noir-lang/types@1.0.0-beta.3': {} + '@noir-lang/types@1.0.0-beta.9': {} + '@nomicfoundation/edr-darwin-arm64@0.12.0-next.10': {} '@nomicfoundation/edr-darwin-x64@0.12.0-next.10': {} @@ -19255,6 +19357,22 @@ snapshots: ms@2.1.3: {} + msgpackr-extract@3.0.3: + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 + optional: true + + msgpackr@1.11.5: + optionalDependencies: + msgpackr-extract: 3.0.3 + muggle-string@0.4.1: {} multiformats@9.9.0: {} @@ -19407,6 +19525,11 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + node-gyp-build@4.8.4: {} node-mock-http@1.0.3: {} From c95581334c57222d6dd43e569a4df1e9031367d1 Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 16:16:46 +0100 Subject: [PATCH 03/13] refactor: update client to use new proof --- examples/CRISP/circuits/src/main.nr | 24 +-- .../client/libs/wasm/pkg/crisp_worker.js | 63 ++++-- examples/CRISP/client/package.json | 6 +- .../voteManagement/VoteManagement.types.ts | 8 +- .../client/src/hooks/voting/useVoteCasting.ts | 200 ++++++++---------- .../client/src/hooks/wasm/useWebAssembly.tsx | 14 +- examples/CRISP/client/src/model/vote.model.ts | 18 +- examples/CRISP/client/vite.config.ts | 10 +- .../contracts/CRISPVerifier.sol | 116 +++++----- .../CRISP/packages/crisp-sdk/package.json | 10 +- .../CRISP/packages/crisp-sdk/src/constants.ts | 2 + .../CRISP/packages/crisp-sdk/src/utils.ts | 14 +- examples/CRISP/packages/crisp-sdk/src/vote.ts | 13 +- .../packages/crisp-sdk/tests/constants.ts | 2 +- .../packages/crisp-sdk/tests/utils.test.ts | 9 +- .../packages/crisp-sdk/tests/vote.test.ts | 25 +-- examples/CRISP/scripts/setup.sh | 2 + pnpm-lock.yaml | 73 +------ 18 files changed, 285 insertions(+), 324 deletions(-) diff --git a/examples/CRISP/circuits/src/main.nr b/examples/CRISP/circuits/src/main.nr index afb60af7a3..0d1e02a8f3 100644 --- a/examples/CRISP/circuits/src/main.nr +++ b/examples/CRISP/circuits/src/main.nr @@ -18,16 +18,16 @@ use utils::{check_coefficient_values_with_balance, check_coefficient_zero}; fn main( // Ciphertext Addition Section. - prev_ct0is: pub [Polynomial<2048>; 1], - prev_ct1is: pub [Polynomial<2048>; 1], + prev_ct0is: [Polynomial<2048>; 1], + prev_ct1is: [Polynomial<2048>; 1], sum_ct0is: [Polynomial<2048>; 1], sum_ct1is: [Polynomial<2048>; 1], sum_r0is: [Polynomial<2048>; 1], sum_r1is: [Polynomial<2048>; 1], // Greco Section. - params: pub Params<2048, 1>, - pk0is: pub [Polynomial<2048>; 1], - pk1is: pub [Polynomial<2048>; 1], + params: Params<2048, 1>, + pk0is: [Polynomial<2048>; 1], + pk1is: [Polynomial<2048>; 1], ct0is: [Polynomial<2048>; 1], ct1is: [Polynomial<2048>; 1], u: Polynomial<2048>, @@ -45,17 +45,17 @@ fn main( signature: [u8; 64], hashed_message: [u8; 32], // Merkle Tree Section. - merkle_root: pub Field, + merkle_root: Field, merkle_proof_length: u32, merkle_proof_indices: [u1; 20], merkle_proof_siblings: [Field; 20], // Slot Address Section. - slot_address: pub Field, + slot_address: Field, // Balance Section. balance: Field, // Whether this is the first vote for this slot. - is_first_vote: pub bool, -) -> pub ([Polynomial<2048>; 1], [Polynomial<2048>; 1]) { + is_first_vote: bool, +) { // Verify the ECDSA signature. let is_signature_valid = verify_signature(hashed_message, public_key_x, public_key_y, signature); @@ -118,7 +118,7 @@ fn main( // Verify the correct coefficient values and that the vote is <= balance check_coefficient_values_with_balance(k1, params.crypto_params().q_mod_t, balance); - (ct0is, ct1is) + // (ct0is, ct1is) } else { // check if vote == 0. let is_vote_zero = check_coefficient_zero(k1); @@ -128,11 +128,11 @@ fn main( // If so, (ct0is, ct1is) should be returned. if is_first_vote { - (ct0is, ct1is) + // (ct0is, ct1is) } else { // check if the sum is valid assert(is_ct_add_valid); - (sum_ct0is, sum_ct1is) + // (sum_ct0is, sum_ct1is) } } } diff --git a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js index 35a7aa5656..7cb51e28e6 100755 --- a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js +++ b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js @@ -4,38 +4,63 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { EnclaveSDK, FheProtocol } from '@enclave-e3/sdk' -import circuit from '../../noir/crisp_circuit.json' +import { + encryptVoteAndGenerateCRISPInputs, + generateProofWithReturnValue, + VotingMode, + encodeVote, + encryptVote, + generateMerkleProof, + verifyProof, + hashLeaf, +} from '@crisp-e3/sdk' self.onmessage = async function (event) { const { type, data } = event.data switch (type) { case 'encrypt_vote': try { - const { voteId, publicKey } = data - // use default params for now as they do not matter for what we are doing here, - // which is just encrypting the vote and generating a proof - const sdk = EnclaveSDK.create({ - chainId: 31337, - contracts: { - enclave: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', - ciphernodeRegistry: '0xc6e7DF5E7b4f2A278906862b61205850344D4e7d', - }, - // local node - rpcUrl: 'http://localhost:8545', - // default Anvil private key - privateKey: '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', - protocol: FheProtocol.BFV, + const { voteId, publicKey, address, signature, message } = data + + // voteId is either 0 or 1, so we need to encode the vote accordingly. + // We are adapting to the current CRISP application. + const vote = voteId === 0 ? { yes: 0n, no: 1n } : { yes: 1n, no: 0n } + const balance = 1n + + const leaf = hashLeaf(address.toLowerCase(), balance.toString()) + // TODO: get the leaves from the server (pass them from the client). + const merkleProof = generateMerkleProof(0n, balance, address, [ + leaf, + 4720511075913887710172192848636076523165432993226978491435561065722130431597n, + 14131255645332550266535358189863475289290770471998199141522479556687499890181n, + ]) + + const encodedVote = encodeVote(vote, VotingMode.GOVERNANCE, balance) + const encryptedVote = await encryptVote(encodedVote, publicKey) + + const inputs = await encryptVoteAndGenerateCRISPInputs({ + encodedVote, + publicKey, + previousCiphertext: encryptedVote, + signature, + message, + merkleData: merkleProof, + balance, + slotAddress: address.toLowerCase(), + isFirstVote: true, }) - const result = await sdk.encryptNumberAndGenProof(voteId, publicKey, circuit) + const { proof, returnValue } = await generateProofWithReturnValue(inputs) + + // TODO: returnValue is the encrypted vote. We need to convert it from Noir format to BFV format + // instead of using the encryptVote function (which should be removed from the SDK). self.postMessage({ type: 'encrypt_vote', success: true, encryptedVote: { - vote: result.encryptedVote, - proofData: result.proof, + vote: encryptedVote, + proofData: proof, }, }) } catch (error) { diff --git a/examples/CRISP/client/package.json b/examples/CRISP/client/package.json index ee0b5c94dc..ae3dea892e 100644 --- a/examples/CRISP/client/package.json +++ b/examples/CRISP/client/package.json @@ -19,13 +19,9 @@ "deploy": "gh-pages -d dist" }, "dependencies": { - "@aztec/bb.js": "^0.82.2", + "@crisp-e3/sdk": "workspace:*", "@emotion/babel-plugin": "^11.11.0", "@emotion/react": "^11.11.4", - "@enclave-e3/sdk": "^0.1.5", - "@noir-lang/acvm_js": "1.0.0-beta.3", - "@noir-lang/noir_js": "1.0.0-beta.3", - "@noir-lang/noirc_abi": "1.0.0-beta.3", "@phosphor-icons/react": "^2.1.4", "@svgr/rollup": "^8.1.0", "@tanstack/react-query": "^5.74.3", diff --git a/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts b/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts index 042a367242..fe8acff6f5 100644 --- a/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts +++ b/examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts @@ -27,7 +27,13 @@ export type VoteManagementContextType = { getPastPolls: () => Promise setVotingRound: React.Dispatch> setUser: React.Dispatch> - encryptVote: (voteId: bigint, publicKey: Uint8Array) => Promise + encryptVote: ( + voteId: bigint, + publicKey: Uint8Array, + address: string, + signature: string, + message: string, + ) => Promise broadcastVote: (vote: BroadcastVoteRequest) => Promise getRoundStateLite: (roundCount: number) => Promise setPastPolls: React.Dispatch> diff --git a/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts b/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts index c9e0a31b76..2141e38483 100644 --- a/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts +++ b/examples/CRISP/client/src/hooks/voting/useVoteCasting.ts @@ -4,125 +4,111 @@ // without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. -import { useState, useCallback } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useSignMessage } from 'wagmi'; +import { useState, useCallback } from 'react' +import { useNavigate } from 'react-router-dom' +import { useSignMessage } from 'wagmi' -import { useVoteManagementContext } from '@/context/voteManagement'; -import { useNotificationAlertContext } from '@/context/NotificationAlert/NotificationAlert.context.tsx'; -import { Poll } from '@/model/poll.model'; -import { BroadcastVoteRequest } from '@/model/vote.model'; +import { useVoteManagementContext } from '@/context/voteManagement' +import { useNotificationAlertContext } from '@/context/NotificationAlert/NotificationAlert.context.tsx' +import { Poll } from '@/model/poll.model' +import { BroadcastVoteRequest } from '@/model/vote.model' export const useVoteCasting = () => { - const { - user, - roundState, - votingRound, - encryptVote, - broadcastVote, - setTxUrl, - } = useVoteManagementContext(); + const { user, roundState, votingRound, encryptVote, broadcastVote, setTxUrl } = useVoteManagementContext() - const { signMessageAsync } = useSignMessage(); - const { showToast } = useNotificationAlertContext(); - const navigate = useNavigate(); - const [isLoading, setIsLoading] = useState(false); + const { signMessageAsync } = useSignMessage() + const { showToast } = useNotificationAlertContext() + const navigate = useNavigate() + const [isLoading, setIsLoading] = useState(false) - const handleVoteEncryption = useCallback( - async (vote: Poll) => { - if (!votingRound) throw new Error('No voting round available for encryption'); - return encryptVote(BigInt(vote.value), new Uint8Array(votingRound.pk_bytes)); - }, - [encryptVote, votingRound], - ); + const handleVoteEncryption = useCallback( + async (vote: Poll, address: string, signature: string, message: string) => { + if (!votingRound) throw new Error('No voting round available for encryption') + return encryptVote(BigInt(vote.value), new Uint8Array(votingRound.pk_bytes), address, signature, message) + }, + [encryptVote, votingRound], + ) - const castVoteWithProof = useCallback(async (pollSelected: Poll | null) => { - if (!pollSelected) { - console.log("Cannot cast vote: Poll option not selected."); - showToast({ type: 'danger', message: 'Please select a poll option first.' }); - return; - } - if (!user || !roundState) { - console.error("Cannot cast vote: Missing user or round state."); - showToast({ type: 'danger', message: 'Cannot cast vote. Ensure you are connected, and the round is active.' }); - return; - } + const castVoteWithProof = useCallback( + async (pollSelected: Poll | null) => { + if (!pollSelected) { + console.log('Cannot cast vote: Poll option not selected.') + showToast({ type: 'danger', message: 'Please select a poll option first.' }) + return + } + if (!user || !roundState) { + console.error('Cannot cast vote: Missing user or round state.') + showToast({ type: 'danger', message: 'Cannot cast vote. Ensure you are connected, and the round is active.' }) + return + } - setIsLoading(true); - console.log("Processing vote..."); + setIsLoading(true) + console.log('Processing vote...') - // For now just sign and do not do nothing with the signature - // await signMessageAsync({ message: `Vote for round ${roundState.id}` }); + // For now just sign and do not do nothing with the signature + const message = `Vote for round ${roundState.id}` + const signature = await signMessageAsync({ message }) - try { - const voteEncrypted = await handleVoteEncryption(pollSelected); - if (!voteEncrypted) { - throw new Error("Failed to encrypt vote."); - } + try { + const voteEncrypted = await handleVoteEncryption(pollSelected, user.address, signature, message) + if (!voteEncrypted) { + throw new Error('Failed to encrypt vote.') + } - const voteRequest: BroadcastVoteRequest = { - round_id: roundState.id, - enc_vote_bytes: Array.from(voteEncrypted.vote), - proof: Array.from(voteEncrypted.proof), - public_inputs: voteEncrypted.public_inputs, - address: user.address, - }; + const voteRequest: BroadcastVoteRequest = { + round_id: roundState.id, + enc_vote_bytes: Array.from(voteEncrypted.vote), + proof: Array.from(voteEncrypted.proof), + public_inputs: voteEncrypted.public_inputs, + address: user.address, + } - const broadcastVoteResponse = await broadcastVote(voteRequest); + const broadcastVoteResponse = await broadcastVote(voteRequest) - if (broadcastVoteResponse) { - switch (broadcastVoteResponse.status) { - case 'success': { - const url = `https://sepolia.etherscan.io/tx/${broadcastVoteResponse.tx_hash}`; - setTxUrl(url); - showToast({ - type: 'success', - message: broadcastVoteResponse.message || 'Successfully voted', - linkUrl: url, - }); - navigate(`/result/${roundState.id}/confirmation`); - break; - } - case 'user_already_voted': - showToast({ - type: 'danger', - message: broadcastVoteResponse.message || 'User has already voted', - }); - break; - case 'failed_broadcast': - showToast({ - type: 'danger', - message: 'Failed to broadcast the vote' - }) - break; - default: - showToast({ - type: 'danger', - message: broadcastVoteResponse.message || 'Error broadcasting the vote', - }); - break; - } - } else { - throw new Error('Received no response after broadcasting vote.'); + if (broadcastVoteResponse) { + switch (broadcastVoteResponse.status) { + case 'success': { + const url = `https://sepolia.etherscan.io/tx/${broadcastVoteResponse.tx_hash}` + setTxUrl(url) + showToast({ + type: 'success', + message: broadcastVoteResponse.message || 'Successfully voted', + linkUrl: url, + }) + navigate(`/result/${roundState.id}/confirmation`) + break } - } catch (error) { - console.error("Vote processing failed:", error); - showToast({ type: 'danger', message: `Vote failed: ${error instanceof Error ? error.message : String(error)}` }); - } finally { - setIsLoading(false); + case 'user_already_voted': + showToast({ + type: 'danger', + message: broadcastVoteResponse.message || 'User has already voted', + }) + break + case 'failed_broadcast': + showToast({ + type: 'danger', + message: 'Failed to broadcast the vote', + }) + break + default: + showToast({ + type: 'danger', + message: broadcastVoteResponse.message || 'Error broadcasting the vote', + }) + break + } + } else { + throw new Error('Received no response after broadcasting vote.') } - }, [ - user, - roundState, - votingRound, - encryptVote, - broadcastVote, - setTxUrl, - showToast, - navigate, - handleVoteEncryption, - signMessageAsync, - ]); + } catch (error) { + console.error('Vote processing failed:', error) + showToast({ type: 'danger', message: `Vote failed: ${error instanceof Error ? error.message : String(error)}` }) + } finally { + setIsLoading(false) + } + }, + [user, roundState, votingRound, encryptVote, broadcastVote, setTxUrl, showToast, navigate, handleVoteEncryption, signMessageAsync], + ) - return { castVoteWithProof, isLoading }; -}; \ No newline at end of file + return { castVoteWithProof, isLoading } +} diff --git a/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx b/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx index 784c1274d9..007ad07a0c 100644 --- a/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx +++ b/examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx @@ -24,7 +24,13 @@ export const useWebAssemblyHook = () => { } }, []) - const encryptVote = async (voteId: bigint, publicKey: Uint8Array): Promise => { + const encryptVote = async ( + voteId: bigint, + publicKey: Uint8Array, + address: string, + signature: string, + message: string, + ): Promise => { if (!worker) { console.error('WebAssembly worker not initialized') return @@ -32,14 +38,14 @@ export const useWebAssemblyHook = () => { return new Promise((resolve, reject) => { setIsLoading(true) - worker.postMessage({ type: 'encrypt_vote', data: { voteId, publicKey } }) + worker.postMessage({ type: 'encrypt_vote', data: { voteId, publicKey, address, signature, message } }) worker.onmessage = async (event) => { const { type, success, encryptedVote, error } = event.data if (type === 'encrypt_vote') { if (success) { - const { vote, proofData } = encryptedVote; + const { vote, proofData } = encryptedVote const { proof, publicInputs } = proofData - + resolve({ vote: vote, proof: proof, diff --git a/examples/CRISP/client/src/model/vote.model.ts b/examples/CRISP/client/src/model/vote.model.ts index 9c017a61e3..d922cf7a78 100644 --- a/examples/CRISP/client/src/model/vote.model.ts +++ b/examples/CRISP/client/src/model/vote.model.ts @@ -22,18 +22,18 @@ export interface CurrentRound { } export interface BroadcastVoteRequest { - round_id: number; - enc_vote_bytes: number[]; - proof: number[]; - public_inputs: string[]; - address: string; + round_id: number + enc_vote_bytes: number[] + proof: number[] + public_inputs: string[] + address: string } -export type VoteResponseStatus = 'success' | 'user_already_voted' | 'failed_broadcast'; +export type VoteResponseStatus = 'success' | 'user_already_voted' | 'failed_broadcast' export interface BroadcastVoteResponse { - status: VoteResponseStatus; - tx_hash?: string; - message?: string; + status: VoteResponseStatus + tx_hash?: string + message?: string } export interface VoteStateLite { diff --git a/examples/CRISP/client/vite.config.ts b/examples/CRISP/client/vite.config.ts index b50269281c..3d499fd15c 100644 --- a/examples/CRISP/client/vite.config.ts +++ b/examples/CRISP/client/vite.config.ts @@ -23,7 +23,15 @@ export default defineConfig({ }, optimizeDeps: { esbuildOptions: { target: 'esnext' }, - exclude: ['@rollup/browser', '@noir-lang/noirc_abi', '@noir-lang/acvm_js', '@enclave-e3/wasm', '@enclave-e3/wasm/init'], + exclude: [ + '@rollup/browser', + '@crisp-e3/zk-inputs', + '@crisp-e3/sdk', + '@noir-lang/noirc_abi', + '@noir-lang/acvm_js', + '@noir-lang/noir_js', + '@aztec/bb.js', + ], }, resolve: { alias: { diff --git a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol index d38e751e98..520b7ebe06 100644 --- a/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol +++ b/examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol @@ -5,122 +5,122 @@ // or FITNESS FOR A PARTICULAR PURPOSE. pragma solidity >=0.8.21; -uint256 constant N = 1048576; -uint256 constant LOG_N = 20; -uint256 constant NUMBER_OF_PUBLIC_INPUTS = 12321; +uint256 constant N = 524288; +uint256 constant LOG_N = 19; +uint256 constant NUMBER_OF_PUBLIC_INPUTS = 16; library HonkVerificationKey { function loadVerificationKey() internal pure returns (Honk.VerificationKey memory) { Honk.VerificationKey memory vk = Honk.VerificationKey({ - circuitSize: uint256(1048576), - logCircuitSize: uint256(20), - publicInputsSize: uint256(12321), + circuitSize: uint256(524288), + logCircuitSize: uint256(19), + publicInputsSize: uint256(16), ql: Honk.G1Point({ - x: uint256(0x11ab7480853c0994c0ee6f875c793a98bab22e5c7f90f770b0427a2641ba49bd), - y: uint256(0x09a4a4bb7300c3215173bc2b80b90be96d12705260bb653c19245bc9a6952488) + x: uint256(0x13ab223ff59cd43e0728277b3e37bce97e3d2faac23f2b3311d8a30a44e25963), + y: uint256(0x16f019597ce96b3e75f6ba1c88a2ca4d229090e158eb668690748f9dbe53d557) }), qr: Honk.G1Point({ - x: uint256(0x197295d419d7d48c56e0ecb700db3e676ae397c90cb385453c2e9e919a8367c3), - y: uint256(0x23188dc025634fb3a1e81fa9998065320d9533e616d5b08afe0833a41b0d117f) + x: uint256(0x0efc1c7316fb670707e58edc7b3b27311d1885a1c991a07b33867c684a9a863c), + y: uint256(0x174f93332ed828e0bef2437d6db802d5126ebab2c3702e8974c6a4ae0646c0c2) }), qo: Honk.G1Point({ - x: uint256(0x03374d5d8e633f27e9377e108089232000a3d8aec29b6f0d4c31793b8191a5e7), - y: uint256(0x2dc1d873b6dfb4d4608a75c872801dab3ad9eeff27b2650b25771b0a2d7f8289) + x: uint256(0x208152ab37453ed055b7108a1424e41ac9e878722aa8ef880c6c012d21eef3d5), + y: uint256(0x1f7dcf9351580536e0fff33cb7b13fb3b0609f0f38c309935a6324959ef64338) }), q4: Honk.G1Point({ - x: uint256(0x16cdb42cfe1fd558dae41be23f9980b72dc7a2c2a9de8aba0c406af8b35fd92d), - y: uint256(0x034ebdb1c2aefe025fede6dcce808cbaa6821d7eb2ff48cbdd4935a74b76e072) + x: uint256(0x0963ddfd632aedb1ebae9f7f3ae7ef217ff9bdf5d5dee30d1f0425d7e5d598b1), + y: uint256(0x220a29354f7f15a3a56faea2719c51fd96b0bc9bb5be5278cc18e4a70b73daec) }), qm: Honk.G1Point({ - x: uint256(0x20d73990f6d612ab63409f72e6ce05a9706beca47246be39370dad53cebf3e33), - y: uint256(0x07a3afaf6fbf9b5dbc5a4968b173f5ddb07921d7314d15ebd075fef2ca5984db) + x: uint256(0x13c6f463efbfdbb1f61e4d88750781b6739363c7892f9833226d65c0ccd9033e), + y: uint256(0x1a46391907c3fb9562fa563bab195d093cc843ede63f936b25344901919d90db) }), qc: Honk.G1Point({ - x: uint256(0x15559b08bc16f95c17edc29ed99a8b2247fc09b858aa0abd04708965d074a2d4), - y: uint256(0x1702febc6b0dd8b6a7d2736804f2ade40132d1ab012c7bb385d7cadd0504d86d) + x: uint256(0x1bb538b0a6019118e246dce49852f4bdbcd60fb4150833dafc064b1a8a73e8e5), + y: uint256(0x2969a444b671dd94a764dbd631698886cc3b2e64750c2c4143c6736fa7c56845) }), qArith: Honk.G1Point({ - x: uint256(0x279b1e6a922fc5789f086c9fa429a2457e72a37705fad297039809b6e0b892e2), - y: uint256(0x28aab2f65345f12169bed84736d33c6f8ea4c5391b9fd27e51d553de53edcee2) + x: uint256(0x1928e8e9fee021507d02bcd30412ce506a543e67a85bee951d8af25432cf1e2d), + y: uint256(0x258bf8ef04faf434cc77fe4edaffcc94e6013df01f85ca64260d5d7099280381) }), qDeltaRange: Honk.G1Point({ - x: uint256(0x010283af75922802e4351c05ccbcec65c51db947749ab8e1b4488a0ba66e8467), - y: uint256(0x2e7da5f4d5f99540bd26141ae760988d51e7281f62e72db693628145a9b84072) + x: uint256(0x01dbbbd0cd1b7aa0b578c58d34b271245b64061ef676ef15e092b3089a54cb24), + y: uint256(0x1f1bfae9f9c59de7326795e9f089c7bbbdb1925f439b29206c58b90f624ff057) }), qElliptic: Honk.G1Point({ - x: uint256(0x292b94199d88fb5daf62b70b737926076c14346fbf59f4588cfd8a18c69f0f06), - y: uint256(0x2aaa3fbb2511272aab0e4b06e63abf0d0d54eb51a4cbcc6511572403a96daa0c) + x: uint256(0x0daade853bee6788e93755b59e0da87732527349b02c44a04c71c0facc512df0), + y: uint256(0x08d2431b4246dde4c512fef36fd2057f756fa86df9437b82499788521accab1e) }), qAux: Honk.G1Point({ - x: uint256(0x067ed4882213477ccd49a2017534e6fe7017691962085cadd0b5cd5567815a4a), - y: uint256(0x2753ebb00d4f25941251c2bd31684970d0922965563688f00c77b81776f1a2d8) + x: uint256(0x091d75c333a546baa162025fc5413bd6a15b73b744bff710a75299a9b1cbb11e), + y: uint256(0x160cd0464b1e360218bb120bf522b2f4c51564750d5acce626d87dadd594ca5e) }), qLookup: Honk.G1Point({ - x: uint256(0x045d382b516ec5bf15829c61492d624c981d11ecc86e4ddf6f05a5326a0f1f17), - y: uint256(0x03c40d1e7586e5a18de27dac5a049f851ccd7db0d6daf165cc6d7a474d8d5786) + x: uint256(0x0d8127977a1a35c9a0d79cb984e7c146cf55d0dcfffed4fe47ba792d80630a57), + y: uint256(0x29a459a12da1ff349a61bc22f74ccf21003c6023d6c2eacfff820f034ca4c4d0) }), qPoseidon2External: Honk.G1Point({ - x: uint256(0x0ddafd8f31b9ac7e7623199996375b060b3af3d5e0801daeab90c5cbe1b5ed16), - y: uint256(0x2081c961a09710e7a90f8ad76c84de1510c3f6c3ec45517cd1ff1ba4ed619913) + x: uint256(0x2e7849b38119f1afb8aefdac89a181e566c5be05150575534bb783802819ae88), + y: uint256(0x039cda5b4478a254bcd6b192d1c67b3ac2143bac86b241b08dc50e0a8d23ceca) }), qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x24d33e04a465bba0ba5a573af010b1f51310c3f0929d526f90f1c250e26eb147), - y: uint256(0x04ed04e9b3dd68235ae44476665dd8d9c0426df63d3f8a456ae2ae97162e76e0) + x: uint256(0x11bca67681de3ea476550a63f2b35b177d7c0fc83eeaf5534832e05e67d1477f), + y: uint256(0x258998c74d0c585178ed727548943a4497be15d53bb82603a365a8fa859cbb2c) }), s1: Honk.G1Point({ - x: uint256(0x01717cb1b7ea32c92fbdd4e9ca97e34058b62016b7e8ed9ca85eee38727ad680), - y: uint256(0x1f303204bb194c0ddf8fb18859ad37720ecd6efd390d224b7b2cafcff6938dfc) + x: uint256(0x183047a917ca53516ae710d178cdb35c17b58d4cf6bebe73ab84edc260969dac), + y: uint256(0x16fa136788614a8d2a8bbb8a40742a2ec88200a7557899dc22eebb9917f39e79) }), s2: Honk.G1Point({ - x: uint256(0x025216492c6d8f1424a0af1919eef0092726ec86f205f4a41a8ee7673b564f1c), - y: uint256(0x24e3ad32113cb91f9d43fd78e02aa55e807ad85e5c3210eef575090269669ef1) + x: uint256(0x2337ae7661f0d0a9cc43523f73e3ccca7f2e98e6de8eff0caef5a2e38bac8050), + y: uint256(0x2dbdd39e65dccf475c00f58e0eb06a9be49797a86404bc850eb56fc27a4ca8eb) }), s3: Honk.G1Point({ - x: uint256(0x1d6d125f8375c1cf467de7ba1818b9e50b10cae1ffb740bd6173478c2e253734), - y: uint256(0x0638b55bd81bec9ed6e5b8db7ee25401ef3628c850f7b6d76738a7c911530b87) + x: uint256(0x15569d9f85dc5d0f5d1e8f18ae7eea3b909c7e68626c609b33e7959bb9918648), + y: uint256(0x2d6729e1c9a15ba58ba3cbe46e8c97880014e3f126b17a1b300715cd449be8b1) }), s4: Honk.G1Point({ - x: uint256(0x1180ecea5358ef0f3ae9e0f6131bb20146056933b106aaa2a672c03daf1e9a30), - y: uint256(0x058c742592719bdf1b489e804990a42ee3cbb9def577467961d117e06ae442b3) + x: uint256(0x062d199e2a3abdc6bd9c51c9e304859f1c52c29a07449cb515a36ad7ec377240), + y: uint256(0x28000e3b5fe7da7621520bab4c69e5141c6d6d4dc542a8333748d76a07df71b2) }), t1: Honk.G1Point({ - x: uint256(0x1cd34417941390ad1d78afcaabf7076e0a14cb155debdc3f26a9a1262d4533cb), - y: uint256(0x27bead0375689fc07d70af56f50dc436f1ef04de5c830404874a57ef7b7e4a56) + x: uint256(0x0d64abbea744f03212f1bf39e9d9c693424fa71ab2235b3f501ac3bc615e8577), + y: uint256(0x03abf1a9c83fe43033856e016b6940b2cde1a7438d4150d5f6343e54e692544d) }), t2: Honk.G1Point({ - x: uint256(0x2c7c23940bfef093f10d770d15d99062cac798dd3710f1e8f33ce9cc4f600da7), - y: uint256(0x15640aaa42131fdb97d7352af2defa8649242b65d4b8bb124d49c85a21352bbb) + x: uint256(0x112dfebe6cfb2e00aeee241e82c6091f7706a596da1ed976801260f85fced62b), + y: uint256(0x0cf123627a5260072ece8c03020a378094ef14d4ecd6fa7787cb92b0ff41e16f) }), t3: Honk.G1Point({ - x: uint256(0x0575f603bcec91b98a5b59db5f96ab53ecfb365c84eca91899a06054f1eefc7f), - y: uint256(0x1b62fdb53646ebd136e5c5bdfce5560351785d5b577fc3c3db22cf93e3ebbddc) + x: uint256(0x0a7a39e50057960052581f511cb596259f1e1588666bc96a9795c0194676c2a3), + y: uint256(0x18d60133c86a16d9192eaffc8a6ac18ccaf3a7ef9f7a2c2a8c0e04df810193a2) }), t4: Honk.G1Point({ - x: uint256(0x162d18f57637d1935879cb690fcc33c3c047252fecf1d970e0acfb58f2a156e2), - y: uint256(0x065ffdba45cb7f494e9cbdf803d0b6dd428f7d9567a6eee3b624f01232d71812) + x: uint256(0x2ced4be26f6936520870ea5f91a46f746098f71fbd39136e72e816fd1ccf3fcb), + y: uint256(0x05e4f50caa7b245e81355a0f8966474c9669792cf09f6b4d807a6604ef93cfba) }), id1: Honk.G1Point({ - x: uint256(0x1ddd559c79bf177b7c5cafe1fa3a8a4c80ebdf63b967f2b3d3c6b46dbd39809a), - y: uint256(0x13ad9fe1ed53b97ccbb8c233d6b7aed6d61c7a038d2d4ae6cb320498323bad89) + x: uint256(0x1b4b9477e130161cd3a4dab7b5a107cf6eff7794a4dadef3bc0cdf65ec6aa7e5), + y: uint256(0x1abd71747ef723da70730a348cc041dc13da45be7318091d98b6b9d74c79f399) }), id2: Honk.G1Point({ - x: uint256(0x121eddfa278380b7e440c94836a30d6d8f15d52a6242a5075d503544ecef5509), - y: uint256(0x1ed6fcdcd0c3f871a886f321b998be23f2f96d0a7550af3db266aa4e73d51ab7) + x: uint256(0x12fab07a701a5614890650c7bb37dade42de520bc6933812670c802fcd5c1a69), + y: uint256(0x29a07f1b4b391180ec8bf71f361f2b1ce53959dbbfdada7bd2578ed270e20b82) }), id3: Honk.G1Point({ - x: uint256(0x1ae077c555042138f18e96214a7dee716fec159e885e285260fac7c6362990bf), - y: uint256(0x2f92bb28595ce751e5dcbddb93c7122f0bd105eb1e600bd73e40f5bc26115461) + x: uint256(0x125c6b504f1acc65b0fb6e30eced8baff778514e407bf588dd108153fbeda5af), + y: uint256(0x15f46d027b762ec2aa4a7d59511d5e17e1e13d4df10eb2a5e9748599045d131b) }), id4: Honk.G1Point({ - x: uint256(0x031a27b1fb99b50ba6281ae65b14fff94731de5efd9116c60b9e99b5f72414cf), - y: uint256(0x09218fcb88888ffd5223063db6568c90c85e0a6b8924747d3b9c8e9659475575) + x: uint256(0x0bbc2d69742f95edbeffe3f80527c6e11e9644918540121093c5244ac6d67737), + y: uint256(0x05780b6e9938c0ff75721918d5a4039840c7b9e2827a02e74845a0b51049794f) }), lagrangeFirst: Honk.G1Point({ x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) }), lagrangeLast: Honk.G1Point({ - x: uint256(0x1bf7a989829b904caab4a07e61c9312e50b43aabf923d52133126b9fc6de38ee), - y: uint256(0x0f265aa0270e42290c3814c6b4faa80004ec7bd8cfadf0518b6221349869d2eb) + x: uint256(0x2616fcd041a9cf147f53b259e2110fc80de4cf4382c39a7f6b75109300489dbd), + y: uint256(0x1329a5245299bcd004a3ba9f7b72bcd050d16cbb6c437cb690343e131697fed8) }) }); return vk; diff --git a/examples/CRISP/packages/crisp-sdk/package.json b/examples/CRISP/packages/crisp-sdk/package.json index 431297efd0..ff8e5dafb8 100644 --- a/examples/CRISP/packages/crisp-sdk/package.json +++ b/examples/CRISP/packages/crisp-sdk/package.json @@ -33,21 +33,21 @@ "devDependencies": { "@types/chai": "^5.2.2", "@types/node": "22.7.5", - "tsup": "^8.5.0", - "typescript": "5.8.3", "chai": "^6.2.0", "prettier": "^3.2.5", + "tsup": "^8.5.0", + "typescript": "5.8.3", "vite": "^5.4.19", "vite-plugin-wasm": "^3.2.2", "vitest": "^1.6.1" }, "dependencies": { + "@aztec/bb.js": "0.87.0", "@crisp-e3/zk-inputs": "workspace:*", + "@noir-lang/noir_js": "1.0.0-beta.9", "@zk-kit/lean-imt": "^2.2.4", "poseidon-lite": "^0.3.0", - "viem": "2.30.6", - "@aztec/bb.js": "0.87.0", - "@noir-lang/noir_js": "1.0.0-beta.9" + "viem": "2.30.6" }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808" } diff --git a/examples/CRISP/packages/crisp-sdk/src/constants.ts b/examples/CRISP/packages/crisp-sdk/src/constants.ts index 3cf49dfb41..96af5126ec 100644 --- a/examples/CRISP/packages/crisp-sdk/src/constants.ts +++ b/examples/CRISP/packages/crisp-sdk/src/constants.ts @@ -10,6 +10,8 @@ import { BFVParams } from './types' export const CRISP_SERVER_TOKEN_TREE_ENDPOINT = 'state/token-holders' export const CRISP_SERVER_STATE_LITE_ENDPOINT = 'state/lite' +export const MERKLE_TREE_MAX_DEPTH = 20 // static, hardcoded in the circuit. + /** * Half the minimum degree needed to support the maxium vote value * If you change MAXIMUM_VOTE_VALUE, make sure to update this value too. diff --git a/examples/CRISP/packages/crisp-sdk/src/utils.ts b/examples/CRISP/packages/crisp-sdk/src/utils.ts index 804013b60f..db6a388b6f 100644 --- a/examples/CRISP/packages/crisp-sdk/src/utils.ts +++ b/examples/CRISP/packages/crisp-sdk/src/utils.ts @@ -8,6 +8,7 @@ import { poseidon2 } from 'poseidon-lite' import { LeanIMT } from '@zk-kit/lean-imt' import type { IMerkleProof } from './types' +import { MERKLE_TREE_MAX_DEPTH } from './constants' /** * Hash a leaf node for the Merkle tree @@ -34,15 +35,8 @@ export const generateMerkleTree = (leaves: bigint[]): LeanIMT => { * @param balance The voter's balance * @param address The voter's address * @param leaves The leaves of the Merkle tree - * @param maxDepth The maximum depth of the Merkle tree */ -export const generateMerkleProof = ( - threshold: bigint, - balance: bigint, - address: string, - leaves: bigint[], - maxDepth: number, -): IMerkleProof => { +export const generateMerkleProof = (threshold: bigint, balance: bigint, address: string, leaves: bigint[]): IMerkleProof => { if (balance < threshold) { throw new Error('Balance is below the threshold') } @@ -60,10 +54,10 @@ export const generateMerkleProof = ( const proof = tree.generateProof(index) // Pad siblings with zeros - const paddedSiblings = [...proof.siblings, ...Array(maxDepth - proof.siblings.length).fill(0n)] + const paddedSiblings = [...proof.siblings, ...Array(MERKLE_TREE_MAX_DEPTH - proof.siblings.length).fill(0n)] // Pad indices with zeros const indices = proof.siblings.map((_, i) => Number((BigInt(proof.index) >> BigInt(i)) & 1n)) - const paddedIndices = [...indices, ...Array(maxDepth - indices.length).fill(0)] + const paddedIndices = [...indices, ...Array(MERKLE_TREE_MAX_DEPTH - indices.length).fill(0)] return { leaf, diff --git a/examples/CRISP/packages/crisp-sdk/src/vote.ts b/examples/CRISP/packages/crisp-sdk/src/vote.ts index c08fddf5b9..6c2e2895c8 100644 --- a/examples/CRISP/packages/crisp-sdk/src/vote.ts +++ b/examples/CRISP/packages/crisp-sdk/src/vote.ts @@ -152,6 +152,18 @@ export const validateVote = (votingMode: VotingMode, vote: IVote, votingPower: b } } +export const encryptVote = async (encodedVote: string[], publicKey: Uint8Array): Promise => { + const zkInputsGenerator: ZKInputsGenerator = new ZKInputsGenerator( + DEFAULT_BFV_PARAMS.degree, + DEFAULT_BFV_PARAMS.plaintextModulus, + DEFAULT_BFV_PARAMS.moduli, + ) + + const vote = BigInt64Array.from(encodedVote.map(BigInt)) + + return zkInputsGenerator.encryptVote(publicKey, vote) +} + /** * This is a wrapper around enclave-e3/sdk encryption functions as CRISP circuit will require some more * input values which generic Greco do not need. @@ -266,7 +278,6 @@ export const generateProof = async (crispInputs: CRISPCircuitInputs): Promise { describe('hashLeaf', () => { @@ -29,11 +29,10 @@ describe('Utils', () => { it('should generate a valid merkle proof for a leaf', () => { const tree = generateMerkleTree(LEAVES) - const proof = generateMerkleProof(0n, balance, address, LEAVES, MAX_DEPTH) + const proof = generateMerkleProof(0n, balance, address, LEAVES) expect(proof.leaf).toBe(hashLeaf(address, balance.toString())) expect(proof.length).toBe(4) - expect(proof.indices.length).toBe(MAX_DEPTH) // Unpad the proof for verification const unpaddedProof = { ...proof.proof, @@ -43,8 +42,8 @@ describe('Utils', () => { expect(tree.verifyProof(unpaddedProof)).toBe(true) }) it('should throw if the leaf does not exist in the tree', () => { - expect(() => generateMerkleProof(0n, balance, address, [], MAX_DEPTH)).toThrow('Leaf not found in the tree') - expect(() => generateMerkleProof(0n, 999n, address, LEAVES, MAX_DEPTH)).toThrow('Leaf not found in the tree') + expect(() => generateMerkleProof(0n, balance, address, [])).toThrow('Leaf not found in the tree') + expect(() => generateMerkleProof(0n, 999n, address, LEAVES)).toThrow('Leaf not found in the tree') }) }) }) diff --git a/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts b/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts index de399e0c0a..33ef26d9dc 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/vote.test.ts @@ -124,8 +124,6 @@ describe('Vote', () => { const validVote = { yes: 10n, no: 0n } const invalidVote = { yes: 5n, no: 5n } - const votingPower = 10n - it('should throw an error for invalid GOVERNANCE votes', () => { expect(() => { validateVote(VotingMode.GOVERNANCE, invalidVote, votingPower) @@ -136,11 +134,6 @@ describe('Vote', () => { validateVote(VotingMode.GOVERNANCE, validVote, votingPower) }).not.toThrow() }) - it('should throw when vote are greater than the voting power available', () => { - expect(() => { - validateVote(VotingMode.GOVERNANCE, { yes: 11n, no: 0n }, votingPower) - }).toThrow('Invalid vote for GOVERNANCE mode: vote exceeds voting power') - }) it('should not throw when vote does not exceed the maximum value supported', () => { expect(() => { validateVote(VotingMode.GOVERNANCE, { yes: 10n, no: 0n }, votingPower) @@ -275,7 +268,7 @@ describe('Vote', () => { const signature = await account.signMessage({ message: MESSAGE }) const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves, 20) + const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) const inputs = await encryptVoteAndGenerateCRISPInputs({ encodedVote, @@ -350,7 +343,7 @@ describe('Vote', () => { }) it('should throw when the signature is invalid and it is a vote (no masking)', { timeout: 100000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPowerLeaf) + const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) // hardhat default private key const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' @@ -358,7 +351,7 @@ describe('Vote', () => { const signature = await account.signMessage({ message: MESSAGE }) const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves, 20) + const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) const inputs = await encryptVoteAndGenerateCRISPInputs({ encodedVote, @@ -379,7 +372,7 @@ describe('Vote', () => { }) it('should throw when the merkle tree inclusion proof is invalid and it is a vote (no masking)', { timeout: 100000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPowerLeaf) + const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) // hardhat default private key const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' @@ -387,7 +380,7 @@ describe('Vote', () => { const signature = await account.signMessage({ message: MESSAGE }) const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves, 20) + const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) const inputs = await encryptVoteAndGenerateCRISPInputs({ encodedVote, @@ -417,7 +410,7 @@ describe('Vote', () => { no: 0n, } - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPowerLeaf) + const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) // hardhat default private key const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' @@ -425,7 +418,7 @@ describe('Vote', () => { const signature = await account.signMessage({ message: MESSAGE }) const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves, 20) + const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) const inputs = await encryptVoteAndGenerateCRISPInputs({ encodedVote, @@ -446,7 +439,7 @@ describe('Vote', () => { }) it('should throw when the vote is > balance', { timeout: 100000 }, async () => { - const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPowerLeaf) + const encodedVote = encodeVote(VOTE, VotingMode.GOVERNANCE, votingPower) // hardhat default private key const privateKey = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' @@ -454,7 +447,7 @@ describe('Vote', () => { const signature = await account.signMessage({ message: MESSAGE }) const leaf = hashLeaf(account.address.toLowerCase(), votingPowerLeaf.toString()) const leaves = [...LEAVES, leaf] - const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves, 20) + const merkleProof = generateMerkleProof(0n, votingPowerLeaf, account.address.toLowerCase(), leaves) const inputs = await encryptVoteAndGenerateCRISPInputs({ encodedVote, diff --git a/examples/CRISP/scripts/setup.sh b/examples/CRISP/scripts/setup.sh index 2428dd002f..c9c1aef1bd 100755 --- a/examples/CRISP/scripts/setup.sh +++ b/examples/CRISP/scripts/setup.sh @@ -7,6 +7,8 @@ export CARGO_INCREMENTAL=1 echo "SETUP..." echo "pnpm install" (cd ../../ && pnpm install --frozen-lockfile) +echo "sdk" +(cd packages/crisp-sdk && pnpm install && pnpm build) echo "evm" (cd ../../packages/enclave-contracts && pnpm compile) echo "server" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 093ab7b112..c30a3dce9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -118,27 +118,15 @@ importers: examples/CRISP/client: dependencies: - '@aztec/bb.js': - specifier: ^0.82.2 - version: 0.82.3 + '@crisp-e3/sdk': + specifier: workspace:* + version: link:../packages/crisp-sdk '@emotion/babel-plugin': specifier: ^11.11.0 version: 11.13.5 '@emotion/react': specifier: ^11.11.4 version: 11.14.0(@types/react@18.3.26)(react@18.3.1) - '@enclave-e3/sdk': - specifier: ^0.1.5 - version: 0.1.5(@openzeppelin/contracts@5.3.0)(@swc/helpers@0.5.17)(@types/node@22.7.5)(bufferutil@4.0.9)(rollup@4.52.5)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@5.4.21(@types/node@22.7.5))(zod@4.1.12) - '@noir-lang/acvm_js': - specifier: 1.0.0-beta.3 - version: 1.0.0-beta.3 - '@noir-lang/noir_js': - specifier: 1.0.0-beta.3 - version: 1.0.0-beta.3 - '@noir-lang/noirc_abi': - specifier: 1.0.0-beta.3 - version: 1.0.0-beta.3 '@phosphor-icons/react': specifier: ^2.1.4 version: 2.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1566,15 +1554,6 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@enclave-e3/contracts@0.1.5': - resolution: {integrity: sha512-C1Mo9z2JG6netDhpOsk0kZV8DBjVd4ftE5oqhpXDDbK+HHD4XHozjKMqmlUYTooSzzT3INGYNS/IEDUHxYOqTA==} - - '@enclave-e3/sdk@0.1.5': - resolution: {integrity: sha512-AZGIYrlJZ6FeK6DIQWqNKZDwvDpw+l1zCd7hc97giFX2LrNbSAzf/UJmNewAXFfaGtlnOePSVsuixk/ZQd1TVw==} - - '@enclave-e3/wasm@0.1.5': - resolution: {integrity: sha512-PZ/TpABK/PAAzO0d2+q17i3plzCs/E3chihc4yOi9DqCxdGFhm76hTueY/lDXusDnM+LUrEuaD11YR/2kBRvTg==} - '@esbuild/aix-ppc64@0.20.0': resolution: {integrity: sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==} engines: {node: '>=12'} @@ -11135,52 +11114,6 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} - '@enclave-e3/contracts@0.1.5(@openzeppelin/contracts@5.3.0)': - dependencies: - '@openzeppelin/contracts-upgradeable': 5.4.0(@openzeppelin/contracts@5.3.0) - '@zk-kit/lean-imt.sol': 2.0.1 - poseidon-solidity: 0.0.5 - transitivePeerDependencies: - - '@openzeppelin/contracts' - - '@enclave-e3/sdk@0.1.5(@openzeppelin/contracts@5.3.0)(@swc/helpers@0.5.17)(@types/node@22.7.5)(bufferutil@4.0.9)(rollup@4.52.5)(typescript@5.8.3)(utf-8-validate@5.0.10)(vite@5.4.21(@types/node@22.7.5))(zod@4.1.12)': - dependencies: - '@aztec/bb.js': 0.82.3 - '@enclave-e3/contracts': 0.1.5(@openzeppelin/contracts@5.3.0) - '@enclave-e3/wasm': 0.1.5 - '@noir-lang/noir_js': 1.0.0-beta.3 - comlink: 4.4.2 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) - vite-plugin-top-level-await: 1.6.0(@swc/helpers@0.5.17)(rollup@4.52.5)(vite@5.4.21(@types/node@22.7.5)) - vite-plugin-wasm: 3.5.0(vite@5.4.21(@types/node@22.7.5)) - vitest: 1.6.1(@types/node@22.7.5) - web-worker: 1.5.0 - transitivePeerDependencies: - - '@edge-runtime/vm' - - '@openzeppelin/contracts' - - '@swc/helpers' - - '@types/node' - - '@vitest/browser' - - '@vitest/ui' - - bufferutil - - happy-dom - - jsdom - - less - - lightningcss - - rollup - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - typescript - - utf-8-validate - - vite - - zod - - '@enclave-e3/wasm@0.1.5': {} - '@esbuild/aix-ppc64@0.20.0': optional: true From dbd86490d5fab24b45d114a152220f766898f10e Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 17:21:06 +0100 Subject: [PATCH 04/13] test: add signature confirmation --- examples/CRISP/test/crisp.spec.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/CRISP/test/crisp.spec.ts b/examples/CRISP/test/crisp.spec.ts index 7848adb66a..70f3eb3bdd 100644 --- a/examples/CRISP/test/crisp.spec.ts +++ b/examples/CRISP/test/crisp.spec.ts @@ -15,7 +15,7 @@ async function runCliInit(): Promise { // Execute the command and wait for it to complete const output = execSync( "pnpm cli init --token-address 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 --balance-threshold 1000", - { encoding: "utf-8" }, + { encoding: "utf-8" } ); console.log("Command output:", output); const lines = output.trim().split("\n"); @@ -47,7 +47,7 @@ async function checkE3Activated(e3id: number): Promise { async function waitForE3Activation( e3id: number, - maxWaitMs: number = 300000, + maxWaitMs: number = 300000 ): Promise { const startTime = Date.now(); while (Date.now() - startTime < maxWaitMs) { @@ -66,7 +66,7 @@ const { expect } = test; async function ensureHomePageLoaded(page: Page) { return await expect(page.locator("h4")).toHaveText( - "Coercion-Resistant Impartial Selection Protocol", + "Coercion-Resistant Impartial Selection Protocol" ); } @@ -93,7 +93,7 @@ test("CRISP smoke test", async ({ context, metamaskPage, basicSetup.walletPassword, - extensionId, + extensionId ); log("runCliInit()..."); @@ -125,6 +125,8 @@ test("CRISP smoke test", async ({ .click(); log(`clicking Cast Vote...`); await page.locator('button:has-text("Cast Vote")').click(); + log(`confirming MetaMask signature request...`); + await metamask.confirmSignature(); const WAIT = 300_000; log(`waiting for ${WAIT}ms...`); await page.waitForTimeout(WAIT); @@ -134,11 +136,11 @@ test("CRISP smoke test", async ({ await expect(page.locator("h1")).toHaveText("Historic polls"); log(`asserting that result has 100% on the vote we clicked on...`); await expect( - page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-0'] h3"), + page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-0'] h3") ).toHaveText("100%"); log(`asserting that result has 0% on the vote we did not click on...`); await expect( - page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-1'] h3"), + page.locator("[data-test-id='poll-0-0'] [data-test-id='poll-result-1'] h3") ).toHaveText("0%"); log("============================================"); From 5e74efdf790551fc784f9c91c1a578875eb02472 Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 17:48:08 +0100 Subject: [PATCH 05/13] chore: add plugins to vite worker --- examples/CRISP/client/vite.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/CRISP/client/vite.config.ts b/examples/CRISP/client/vite.config.ts index 3d499fd15c..9d1f5d68fe 100644 --- a/examples/CRISP/client/vite.config.ts +++ b/examples/CRISP/client/vite.config.ts @@ -41,6 +41,7 @@ export default defineConfig({ }, worker: { format: 'es', + plugins: () => [wasm(), topLevelAwait()], }, plugins: [ // here is the main update From 87d6249523e1c2e1caeecd3ff6a191dbd79386bf Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 17:51:15 +0100 Subject: [PATCH 06/13] fix: update merkle proof to use lowercase address --- examples/CRISP/client/libs/wasm/pkg/crisp_worker.js | 2 +- .../packages/crisp-contracts/tests/crisp.contracts.test.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js index 7cb51e28e6..2928eba2a2 100755 --- a/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js +++ b/examples/CRISP/client/libs/wasm/pkg/crisp_worker.js @@ -29,7 +29,7 @@ self.onmessage = async function (event) { const leaf = hashLeaf(address.toLowerCase(), balance.toString()) // TODO: get the leaves from the server (pass them from the client). - const merkleProof = generateMerkleProof(0n, balance, address, [ + const merkleProof = generateMerkleProof(0n, balance, address.toLowerCase(), [ leaf, 4720511075913887710172192848636076523165432993226978491435561065722130431597n, 14131255645332550266535358189863475289290770471998199141522479556687499890181n, diff --git a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts index 6f305a9fc4..e3e5e75b1d 100644 --- a/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts +++ b/examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts @@ -129,8 +129,7 @@ describe("CRISP Contracts", function () { threshold, vote.yes, address, - leaves, - 20 + leaves ); const inputs = await encryptVoteAndGenerateCRISPInputs({ From fb4b0757f3d99a943744e5850b7d2174cf6df4f1 Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 22:52:57 +0100 Subject: [PATCH 07/13] chore: add export to package.json for crisp-sdk --- examples/CRISP/packages/crisp-sdk/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/CRISP/packages/crisp-sdk/package.json b/examples/CRISP/packages/crisp-sdk/package.json index ff8e5dafb8..7dfbf94ab6 100644 --- a/examples/CRISP/packages/crisp-sdk/package.json +++ b/examples/CRISP/packages/crisp-sdk/package.json @@ -14,7 +14,8 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.js" + "import": "./dist/index.js", + "default": "./dist/index.js" } }, "homepage": "https://github.com/gnosisguild/enclave", From f0153101e5cd1d04f3e4dcd20a9a17c4617e3576 Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 22:56:09 +0100 Subject: [PATCH 08/13] chore(crisp): publish version 0.1.0-test - Updated @crisp-e3/sdk to 0.1.0-test - Updated @crisp-e3/contracts to 0.1.0-test - Updated @crisp-e3/zk-inputs to 0.1.0-test - Published to npm --- examples/CRISP/packages/crisp-contracts/package.json | 2 +- examples/CRISP/packages/crisp-sdk/package.json | 2 +- examples/CRISP/packages/crisp-zk-inputs/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/CRISP/packages/crisp-contracts/package.json b/examples/CRISP/packages/crisp-contracts/package.json index ded5daca9d..ad23dbd1d1 100644 --- a/examples/CRISP/packages/crisp-contracts/package.json +++ b/examples/CRISP/packages/crisp-contracts/package.json @@ -1,6 +1,6 @@ { "name": "@crisp-e3/contracts", - "version": "0.0.2-test", + "version": "0.1.0-test", "type": "module", "files": [ "contracts", diff --git a/examples/CRISP/packages/crisp-sdk/package.json b/examples/CRISP/packages/crisp-sdk/package.json index 7dfbf94ab6..6deae0f7e8 100644 --- a/examples/CRISP/packages/crisp-sdk/package.json +++ b/examples/CRISP/packages/crisp-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@crisp-e3/sdk", - "version": "0.0.2-test", + "version": "0.1.0-test", "type": "module", "author": { "name": "gnosisguild", diff --git a/examples/CRISP/packages/crisp-zk-inputs/package.json b/examples/CRISP/packages/crisp-zk-inputs/package.json index 485e40629d..cb28278661 100644 --- a/examples/CRISP/packages/crisp-zk-inputs/package.json +++ b/examples/CRISP/packages/crisp-zk-inputs/package.json @@ -2,7 +2,7 @@ "name": "@crisp-e3/zk-inputs", "type": "module", "description": "Core logic to pre-compute CRISP ZK inputs (WASM/JavaScript bindings).", - "version": "0.0.2-test", + "version": "0.1.0-test", "license": "LGPL-3.0-only", "repository": { "type": "git", From 3780fcf85a5d6e19802c90e93fd7692678a3a31f Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 22:57:22 +0100 Subject: [PATCH 09/13] chore(crisp): publish version 0.2.0-test - Updated @crisp-e3/sdk to 0.2.0-test - Updated @crisp-e3/contracts to 0.2.0-test - Updated @crisp-e3/zk-inputs to 0.2.0-test - Published to npm --- examples/CRISP/packages/crisp-contracts/package.json | 2 +- examples/CRISP/packages/crisp-sdk/package.json | 2 +- examples/CRISP/packages/crisp-zk-inputs/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/CRISP/packages/crisp-contracts/package.json b/examples/CRISP/packages/crisp-contracts/package.json index ad23dbd1d1..93d4c0b3b7 100644 --- a/examples/CRISP/packages/crisp-contracts/package.json +++ b/examples/CRISP/packages/crisp-contracts/package.json @@ -1,6 +1,6 @@ { "name": "@crisp-e3/contracts", - "version": "0.1.0-test", + "version": "0.2.0-test", "type": "module", "files": [ "contracts", diff --git a/examples/CRISP/packages/crisp-sdk/package.json b/examples/CRISP/packages/crisp-sdk/package.json index 6deae0f7e8..8cc9bbeab6 100644 --- a/examples/CRISP/packages/crisp-sdk/package.json +++ b/examples/CRISP/packages/crisp-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@crisp-e3/sdk", - "version": "0.1.0-test", + "version": "0.2.0-test", "type": "module", "author": { "name": "gnosisguild", diff --git a/examples/CRISP/packages/crisp-zk-inputs/package.json b/examples/CRISP/packages/crisp-zk-inputs/package.json index cb28278661..93d82ccc4c 100644 --- a/examples/CRISP/packages/crisp-zk-inputs/package.json +++ b/examples/CRISP/packages/crisp-zk-inputs/package.json @@ -2,7 +2,7 @@ "name": "@crisp-e3/zk-inputs", "type": "module", "description": "Core logic to pre-compute CRISP ZK inputs (WASM/JavaScript bindings).", - "version": "0.1.0-test", + "version": "0.2.0-test", "license": "LGPL-3.0-only", "repository": { "type": "git", From 340bcc82293fc3365b40420b985ce78386dd5be8 Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 23:09:54 +0100 Subject: [PATCH 10/13] chore: update crisp-sdk version to 0.2.0-test --- examples/CRISP/client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CRISP/client/package.json b/examples/CRISP/client/package.json index ae3dea892e..462cb4674d 100644 --- a/examples/CRISP/client/package.json +++ b/examples/CRISP/client/package.json @@ -19,7 +19,7 @@ "deploy": "gh-pages -d dist" }, "dependencies": { - "@crisp-e3/sdk": "workspace:*", + "@crisp-e3/sdk": "^0.2.0-test", "@emotion/babel-plugin": "^11.11.0", "@emotion/react": "^11.11.4", "@phosphor-icons/react": "^2.1.4", From 992dc4c1d0e356f9b0918fffb3cbfcf48a7fe54f Mon Sep 17 00:00:00 2001 From: Cedoor Date: Mon, 10 Nov 2025 23:12:49 +0100 Subject: [PATCH 11/13] chore: update pnpm lock --- pnpm-lock.yaml | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c30a3dce9f..8ca4c98a8e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -119,8 +119,8 @@ importers: examples/CRISP/client: dependencies: '@crisp-e3/sdk': - specifier: workspace:* - version: link:../packages/crisp-sdk + specifier: ^0.2.0-test + version: 0.2.0-test(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@emotion/babel-plugin': specifier: ^11.11.0 version: 11.13.5 @@ -1462,6 +1462,12 @@ packages: conventional-commits-parser: optional: true + '@crisp-e3/sdk@0.2.0-test': + resolution: {integrity: sha512-SgpwtV7G2onsf5yyDBrK+uV+PnyRvInR00YlG1rAxL8A6xjNNntTJzzx/92zgg6uWIsKY6c6iHF8EAVGgwqJpw==} + + '@crisp-e3/zk-inputs@0.2.0-test': + resolution: {integrity: sha512-MHJR9roV09I3Oq/MWd7+wQ6Z3sdC9opv/qzXy+kpQ8GSBrXGY0QoujbUG7INmjy5yLBgjebPWkeXhU8WGffXcA==} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -10992,6 +10998,23 @@ snapshots: conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.2.1 + '@crisp-e3/sdk@0.2.0-test(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@aztec/bb.js': 0.87.0 + '@crisp-e3/zk-inputs': 0.2.0-test + '@noir-lang/noir_js': 1.0.0-beta.9 + '@zk-kit/lean-imt': 2.2.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) + poseidon-lite: 0.3.0 + viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + - zod + + '@crisp-e3/zk-inputs@0.2.0-test': {} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 From 7365a7c184a7a86707552164d672821e5bea16a0 Mon Sep 17 00:00:00 2001 From: Cedoor Date: Tue, 11 Nov 2025 10:34:20 +0100 Subject: [PATCH 12/13] chore: use workspace:* for crisp-sdk in client --- examples/CRISP/client/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/CRISP/client/package.json b/examples/CRISP/client/package.json index 462cb4674d..4e624c5673 100644 --- a/examples/CRISP/client/package.json +++ b/examples/CRISP/client/package.json @@ -12,14 +12,15 @@ "cli": "pnpm sh ./scripts/cli.sh", "dev": "vite --no-open --host", "dev-static": "NO_HOT=1 vite --no-open --host", - "build": "tsc && vite build", + "build:sdk": "pnpm -C ../packages/crisp-sdk build", + "build": "pnpm build:sdk && tsc && vite build", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "predeploy": "pnpm run build", "deploy": "gh-pages -d dist" }, "dependencies": { - "@crisp-e3/sdk": "^0.2.0-test", + "@crisp-e3/sdk": "workspace:*", "@emotion/babel-plugin": "^11.11.0", "@emotion/react": "^11.11.4", "@phosphor-icons/react": "^2.1.4", From 36e53d51782be4b57a6cba8ab88c0c9954314a11 Mon Sep 17 00:00:00 2001 From: Cedoor Date: Tue, 11 Nov 2025 10:36:21 +0100 Subject: [PATCH 13/13] chore: update pnpm-lock.yaml --- pnpm-lock.yaml | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ca4c98a8e..c30a3dce9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -119,8 +119,8 @@ importers: examples/CRISP/client: dependencies: '@crisp-e3/sdk': - specifier: ^0.2.0-test - version: 0.2.0-test(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + specifier: workspace:* + version: link:../packages/crisp-sdk '@emotion/babel-plugin': specifier: ^11.11.0 version: 11.13.5 @@ -1462,12 +1462,6 @@ packages: conventional-commits-parser: optional: true - '@crisp-e3/sdk@0.2.0-test': - resolution: {integrity: sha512-SgpwtV7G2onsf5yyDBrK+uV+PnyRvInR00YlG1rAxL8A6xjNNntTJzzx/92zgg6uWIsKY6c6iHF8EAVGgwqJpw==} - - '@crisp-e3/zk-inputs@0.2.0-test': - resolution: {integrity: sha512-MHJR9roV09I3Oq/MWd7+wQ6Z3sdC9opv/qzXy+kpQ8GSBrXGY0QoujbUG7INmjy5yLBgjebPWkeXhU8WGffXcA==} - '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -10998,23 +10992,6 @@ snapshots: conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.2.1 - '@crisp-e3/sdk@0.2.0-test(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': - dependencies: - '@aztec/bb.js': 0.87.0 - '@crisp-e3/zk-inputs': 0.2.0-test - '@noir-lang/noir_js': 1.0.0-beta.9 - '@zk-kit/lean-imt': 2.2.4(bufferutil@4.0.9)(utf-8-validate@5.0.10) - poseidon-lite: 0.3.0 - viem: 2.38.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) - transitivePeerDependencies: - - bufferutil - - supports-color - - typescript - - utf-8-validate - - zod - - '@crisp-e3/zk-inputs@0.2.0-test': {} - '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9