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/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..2928eba2a2 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.toLowerCase(), [ + 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..4e624c5673 100644 --- a/examples/CRISP/client/package.json +++ b/examples/CRISP/client/package.json @@ -12,20 +12,17 @@ "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": { - "@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..9d1f5d68fe 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: { @@ -33,6 +41,7 @@ export default defineConfig({ }, worker: { format: 'es', + plugins: () => [wasm(), topLevelAwait()], }, plugins: [ // here is the main update 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 93216d4fd5..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 = 0; +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(0), + circuitSize: uint256(524288), + logCircuitSize: uint256(19), + publicInputsSize: uint256(16), ql: Honk.G1Point({ - x: uint256(0x10d36906c36e560297d7bc49c7661fbf50a476bea06e780c40d53a45c459599e), - y: uint256(0x1ed002ce45e75474d75d25ef1764280c6f1974b704ae77315baf31726978c175) + x: uint256(0x13ab223ff59cd43e0728277b3e37bce97e3d2faac23f2b3311d8a30a44e25963), + y: uint256(0x16f019597ce96b3e75f6ba1c88a2ca4d229090e158eb668690748f9dbe53d557) }), qr: Honk.G1Point({ - x: uint256(0x248d6c5782f08a14f794dae5832e8d4a5b42afebf0b248532d725e5d633e7215), - y: uint256(0x266b795b6cf4aa5fff2eb8c3e5a9b9780d6fd5d7170fc2b87f0e6aec8eaa9551) + x: uint256(0x0efc1c7316fb670707e58edc7b3b27311d1885a1c991a07b33867c684a9a863c), + y: uint256(0x174f93332ed828e0bef2437d6db802d5126ebab2c3702e8974c6a4ae0646c0c2) }), qo: Honk.G1Point({ - x: uint256(0x2137d78eee77dfd53fc4bf2adeacef7b15a94cc050a06fb8f52e5a28e938a78e), - y: uint256(0x1b0888693ee93d8804044d8d5e8d950ed53fbb451da45863f6f768145c7d24b1) + x: uint256(0x208152ab37453ed055b7108a1424e41ac9e878722aa8ef880c6c012d21eef3d5), + y: uint256(0x1f7dcf9351580536e0fff33cb7b13fb3b0609f0f38c309935a6324959ef64338) }), q4: Honk.G1Point({ - x: uint256(0x00dceb0527695295e8bc90df562acf14d9bdb55e6250ca81034c7f56b9345985), - y: uint256(0x07963d90a20b5fbd22fcb35424b408b2ed41ab59fb2014027d9ec235a5f5905f) + x: uint256(0x0963ddfd632aedb1ebae9f7f3ae7ef217ff9bdf5d5dee30d1f0425d7e5d598b1), + y: uint256(0x220a29354f7f15a3a56faea2719c51fd96b0bc9bb5be5278cc18e4a70b73daec) }), qm: Honk.G1Point({ - x: uint256(0x11a037d3a9259c512f1039f1049fc7541cbbf315ddb90fe2869e6281c12023ef), - y: uint256(0x2d9966faba8461ee70d9db68e1d817fb21b15fb1e09e7476839dc6d07135cc23) + x: uint256(0x13c6f463efbfdbb1f61e4d88750781b6739363c7892f9833226d65c0ccd9033e), + y: uint256(0x1a46391907c3fb9562fa563bab195d093cc843ede63f936b25344901919d90db) }), qc: Honk.G1Point({ - x: uint256(0x1219c094d86699487f09191b809a6be165c9b4808bbcadef831592295a1d7da6), - y: uint256(0x20b99b2dcadc856a88cc731f349aa47893a0569c4e747b4af0d7aae0dc9bdcda) + x: uint256(0x1bb538b0a6019118e246dce49852f4bdbcd60fb4150833dafc064b1a8a73e8e5), + y: uint256(0x2969a444b671dd94a764dbd631698886cc3b2e64750c2c4143c6736fa7c56845) }), qArith: Honk.G1Point({ - x: uint256(0x147b6a393db982d0f0c7764012b6835c95bc0fa7926fda3f8bf684105282d388), - y: uint256(0x25b693e3f55d510c41dde8bd6b0d61b5c39db3888b55aeada5d7622f34254edf) + x: uint256(0x1928e8e9fee021507d02bcd30412ce506a543e67a85bee951d8af25432cf1e2d), + y: uint256(0x258bf8ef04faf434cc77fe4edaffcc94e6013df01f85ca64260d5d7099280381) }), qDeltaRange: Honk.G1Point({ - x: uint256(0x2c9e01c750140eb161d24b9ee0fc8984acb60bf4e395b8e6ebbaa91c1be174e9), - y: uint256(0x1bc18c861d47b1f9a988e2e3d3d7a0a6252dc986d614fcca0e4f8ac7457c0892) + x: uint256(0x01dbbbd0cd1b7aa0b578c58d34b271245b64061ef676ef15e092b3089a54cb24), + y: uint256(0x1f1bfae9f9c59de7326795e9f089c7bbbdb1925f439b29206c58b90f624ff057) }), qElliptic: Honk.G1Point({ - x: uint256(0x088a610ed8e4090aefcac9ab7277b21fdfb04ce437eb458bdb3696bff53c1cd0), - y: uint256(0x2c5353cedecc1e5f4d84b3ae7f3711e36deebc3071201975bf0fecc655545f5e) + x: uint256(0x0daade853bee6788e93755b59e0da87732527349b02c44a04c71c0facc512df0), + y: uint256(0x08d2431b4246dde4c512fef36fd2057f756fa86df9437b82499788521accab1e) }), qAux: Honk.G1Point({ - x: uint256(0x1baad7c6c4a0f76d721636e31a5b5c28c1062d21f2148339266343c8c1d38996), - y: uint256(0x1eb16da6aed4aa1a55302d002d233fd4dbb885c96431a494683dc97a9275f43b) + x: uint256(0x091d75c333a546baa162025fc5413bd6a15b73b744bff710a75299a9b1cbb11e), + y: uint256(0x160cd0464b1e360218bb120bf522b2f4c51564750d5acce626d87dadd594ca5e) }), qLookup: Honk.G1Point({ - x: uint256(0x1d64341216e323f076ac53aa06192392677f44b67b6947dd6a0a1490fb32a083), - y: uint256(0x28d02cea9cc379ace2ae8779011e247ddc4213ef69895a8e634f425844107141) + x: uint256(0x0d8127977a1a35c9a0d79cb984e7c146cf55d0dcfffed4fe47ba792d80630a57), + y: uint256(0x29a459a12da1ff349a61bc22f74ccf21003c6023d6c2eacfff820f034ca4c4d0) }), qPoseidon2External: Honk.G1Point({ - x: uint256(0x1e0266510d883b6379b58686bd63642eae499ea68a706cc9e70c14c9c0e8536a), - y: uint256(0x11491f77ce7999d3618f0bac66ef7c4f1ed122f862d1c1465e71ce1262c4d7bd) + x: uint256(0x2e7849b38119f1afb8aefdac89a181e566c5be05150575534bb783802819ae88), + y: uint256(0x039cda5b4478a254bcd6b192d1c67b3ac2143bac86b241b08dc50e0a8d23ceca) }), qPoseidon2Internal: Honk.G1Point({ - x: uint256(0x22b036a9ca9be4e71743a125c08648843a55f2cf070dafbbda117ca79e071ad5), - y: uint256(0x12fd44e4853d17621023115fbb658d1150aa85fae5a020f07eddd2215812b2f8) + x: uint256(0x11bca67681de3ea476550a63f2b35b177d7c0fc83eeaf5534832e05e67d1477f), + y: uint256(0x258998c74d0c585178ed727548943a4497be15d53bb82603a365a8fa859cbb2c) }), s1: Honk.G1Point({ - x: uint256(0x1a18a989b31c09eea3da5ae3faa7680ef410474de274210f9c39ebfe6a798c7d), - y: uint256(0x2108883b1e5364123ffd7c32161f9228987ee6aa31ba3c579765f6096579b8e0) + x: uint256(0x183047a917ca53516ae710d178cdb35c17b58d4cf6bebe73ab84edc260969dac), + y: uint256(0x16fa136788614a8d2a8bbb8a40742a2ec88200a7557899dc22eebb9917f39e79) }), s2: Honk.G1Point({ - x: uint256(0x26ddc6264203943a7c31aed2afb7d53fe32a7a38249897fc2a8771c65c414096), - y: uint256(0x0249864a3e742b55386cf6ab4051915fa677a11885e4b0eb04d20d38e9632afe) + x: uint256(0x2337ae7661f0d0a9cc43523f73e3ccca7f2e98e6de8eff0caef5a2e38bac8050), + y: uint256(0x2dbdd39e65dccf475c00f58e0eb06a9be49797a86404bc850eb56fc27a4ca8eb) }), s3: Honk.G1Point({ - x: uint256(0x250a1f5dd0a1e0ec7ab855db5863a25a567877ef1bd1c19e5bc1ccdb733b2956), - y: uint256(0x2cc285a8d6a6e91d142e2a941e23c0a7aee361316975b582e0370e46c4939d9f) + x: uint256(0x15569d9f85dc5d0f5d1e8f18ae7eea3b909c7e68626c609b33e7959bb9918648), + y: uint256(0x2d6729e1c9a15ba58ba3cbe46e8c97880014e3f126b17a1b300715cd449be8b1) }), s4: Honk.G1Point({ - x: uint256(0x0fc8be2a322d1c45d22b210211992629be0450555321e4a55c2cf2d8f5498c6c), - y: uint256(0x1091f3056debdf6a98ab5e4c6df48dc4fded590c78788baf2b394ff6005df6f6) + x: uint256(0x062d199e2a3abdc6bd9c51c9e304859f1c52c29a07449cb515a36ad7ec377240), + y: uint256(0x28000e3b5fe7da7621520bab4c69e5141c6d6d4dc542a8333748d76a07df71b2) }), t1: Honk.G1Point({ - x: uint256(0x1bf7da4add7c858eb94b75f2e78fbd89c84f5fa43824a0d5534173872ee099c2), - y: uint256(0x1b35fa2a35673699ee1cb260d9e6c4be79b26d488c26dc2531194e43c8f747ea) + x: uint256(0x0d64abbea744f03212f1bf39e9d9c693424fa71ab2235b3f501ac3bc615e8577), + y: uint256(0x03abf1a9c83fe43033856e016b6940b2cde1a7438d4150d5f6343e54e692544d) }), t2: Honk.G1Point({ - x: uint256(0x16bf79791869cec464180d5322eeaaef18fed6dc10c3e64e314c04d85c3faece), - y: uint256(0x2e2ec6341669b5b975e25e465af5d9e40533d5ac173554df19daed27f66c36ff) + x: uint256(0x112dfebe6cfb2e00aeee241e82c6091f7706a596da1ed976801260f85fced62b), + y: uint256(0x0cf123627a5260072ece8c03020a378094ef14d4ecd6fa7787cb92b0ff41e16f) }), t3: Honk.G1Point({ - x: uint256(0x150253026f1b985165783c2f4ee1df612c826dda543d06d34711b965730ab69e), - y: uint256(0x0c4062ebcca21d81273b9c58d64447e4ee4d55effa8cbc8fdbd6a76bc3092264) + x: uint256(0x0a7a39e50057960052581f511cb596259f1e1588666bc96a9795c0194676c2a3), + y: uint256(0x18d60133c86a16d9192eaffc8a6ac18ccaf3a7ef9f7a2c2a8c0e04df810193a2) }), t4: Honk.G1Point({ - x: uint256(0x159f2541ce446c6d59ea3f06be91ec9f47c9c82f3e4fd10696511efaff4121fa), - y: uint256(0x15f873b33ec9467e1f0c4fb3a0b59a6fcd6f3480515f1ff5506c48f0c521f00f) + x: uint256(0x2ced4be26f6936520870ea5f91a46f746098f71fbd39136e72e816fd1ccf3fcb), + y: uint256(0x05e4f50caa7b245e81355a0f8966474c9669792cf09f6b4d807a6604ef93cfba) }), id1: Honk.G1Point({ - x: uint256(0x0c02225e1d329e09a738ff6a3d1f2eefee2d9c2446f748430a4c9e3db3af493e), - y: uint256(0x22970a47d992efe75e1a9ae8c48617327596f0b9d1536898b516e9dc0d92e351) + x: uint256(0x1b4b9477e130161cd3a4dab7b5a107cf6eff7794a4dadef3bc0cdf65ec6aa7e5), + y: uint256(0x1abd71747ef723da70730a348cc041dc13da45be7318091d98b6b9d74c79f399) }), id2: Honk.G1Point({ - x: uint256(0x025b15baf18a3565112553243b581ab7c1ef2bb7b6cecb6fd3dbcb494f131c1b), - y: uint256(0x0784d79e6aa29c9c710670f3e62df4c3bf99a73a85bb255a009d5566da762426) + x: uint256(0x12fab07a701a5614890650c7bb37dade42de520bc6933812670c802fcd5c1a69), + y: uint256(0x29a07f1b4b391180ec8bf71f361f2b1ce53959dbbfdada7bd2578ed270e20b82) }), id3: Honk.G1Point({ - x: uint256(0x2f0d8870dfa4fe4f0bcf1e8a8b69f750b15e8315a76dea5965fe82d369e00ffd), - y: uint256(0x0b8a634aa17cb7e29434a052392f7c40e013e37f2dfdcce584ecaa23a3508c89) + x: uint256(0x125c6b504f1acc65b0fb6e30eced8baff778514e407bf588dd108153fbeda5af), + y: uint256(0x15f46d027b762ec2aa4a7d59511d5e17e1e13d4df10eb2a5e9748599045d131b) }), id4: Honk.G1Point({ - x: uint256(0x126143c034d5218ac854d254492806967ae0d23ec5684d341d730cd4dda79f08), - y: uint256(0x1c00c21435080bb1e5b99a42eba611eda1328b0e38e92fcd955d81e96b9b2917) + x: uint256(0x0bbc2d69742f95edbeffe3f80527c6e11e9644918540121093c5244ac6d67737), + y: uint256(0x05780b6e9938c0ff75721918d5a4039840c7b9e2827a02e74845a0b51049794f) }), lagrangeFirst: Honk.G1Point({ x: uint256(0x0000000000000000000000000000000000000000000000000000000000000001), y: uint256(0x0000000000000000000000000000000000000000000000000000000000000002) }), lagrangeLast: Honk.G1Point({ - x: uint256(0x1120d97a81a9c90c251f46b1ec3998bc67e7978323aebf46551a536bf4d0f167), - y: uint256(0x26d1e132ba53edea7d5e8aa5b21067176a3cf0ba74257f595e17bf0db56a98de) + x: uint256(0x2616fcd041a9cf147f53b259e2110fc80de4cf4382c39a7f6b75109300489dbd), + y: uint256(0x1329a5245299bcd004a3ba9f7b72bcd050d16cbb6c437cb690343e131697fed8) }) }); return vk; @@ -272,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; @@ -389,6 +390,8 @@ library Honk { struct Proof { + // Pairing point object + Fr[PAIRING_POINTS_SIZE] pairingPointObject; // Free wires Honk.G1ProofPoint w1; Honk.G1ProofPoint w2; @@ -486,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 @@ -673,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++) { @@ -715,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]); } @@ -1542,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); @@ -1555,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(); } @@ -1566,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 @@ -1579,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) @@ -1591,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); @@ -1600,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? @@ -1883,4 +1914,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/package.json b/examples/CRISP/packages/crisp-contracts/package.json index ded5daca9d..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.0.2-test", + "version": "0.2.0-test", "type": "module", "files": [ "contracts", 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..e3e5e75b1d 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,152 @@ 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 with the crisp verifier", 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 + ); + + 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/package.json b/examples/CRISP/packages/crisp-sdk/package.json index 48f2c2e5c5..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.0.2-test", + "version": "0.2.0-test", "type": "module", "author": { "name": "gnosisguild", @@ -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", @@ -33,21 +34,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.82.2", - "@noir-lang/noir_js": "1.0.0-beta.3" + "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 86bc8ce47b..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. @@ -263,10 +275,12 @@ 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) + const proof = await backend.generateProof(witness, { keccak: true }) + + await backend.destroy() return proof } @@ -275,10 +289,12 @@ 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) + const proof = await backend.generateProof(witness, { keccak: true }) + + await backend.destroy() return { returnValue, proof } } @@ -294,5 +310,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/examples/CRISP/packages/crisp-sdk/tests/constants.ts b/examples/CRISP/packages/crisp-sdk/tests/constants.ts index 26d797d734..c1328cba4e 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/constants.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/constants.ts @@ -30,4 +30,4 @@ export const MAX_DEPTH = 20 export const votingPowerLeaf = 1000n export const testAddress = '0x1234567890123456789012345678901234567890' -export const merkleProof = generateMerkleProof(0n, votingPowerLeaf, testAddress, LEAVES, MAX_DEPTH) +export const merkleProof = generateMerkleProof(0n, votingPowerLeaf, testAddress, LEAVES) diff --git a/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts b/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts index 7e76573ca5..20890c53f2 100644 --- a/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts +++ b/examples/CRISP/packages/crisp-sdk/tests/utils.test.ts @@ -6,7 +6,7 @@ import { expect, describe, it } from 'vitest' import { generateMerkleProof, generateMerkleTree, hashLeaf } from '../src/utils' -import { LEAVES, MAX_DEPTH } from './constants' +import { LEAVES } from './constants' describe('Utils', () => { 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/packages/crisp-zk-inputs/package.json b/examples/CRISP/packages/crisp-zk-inputs/package.json index 485e40629d..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.0.2-test", + "version": "0.2.0-test", "license": "LGPL-3.0-only", "repository": { "type": "git", 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/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("============================================"); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0bd915214b..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) @@ -349,14 +337,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 +832,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'} @@ -1562,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'} @@ -2472,6 +2455,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 +2715,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 +7466,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 +7581,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 +10033,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 @@ -11066,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 @@ -12108,6 +12110,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 +12282,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 +19290,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 +19458,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: {}