@crisp-e3/sdk 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/circuits.ts","../src/constants.ts","../src/token.ts","../src/chain.ts","../src/state.ts","../src/api.ts","../src/utils.ts","../src/encoding.ts","../src/circuitInputs.ts","../src/vote.ts","../../../circuits/bin/fold/target/crisp_fold.json","../../../circuits/bin/fold_onchain/target/crisp_onchain_fold.json","../../../../../circuits/bin/threshold/target/user_data_encryption.json","../src/sdk.ts","../src/types.ts"],"sourcesContent":["// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport type { CompiledCircuit } from '@noir-lang/noir_js'\n\n/** BFV parameter sets the circuits can be compiled against. */\nexport type CircuitPreset = 'insecure-512' | 'secure-8192'\n\n/**\n * The circuits whose ABI is shaped by the BFV degree, and which therefore exist once per preset.\n *\n * The aggregation circuits — `crisp_fold`, `crisp_onchain_fold` and `user_data_encryption` — are\n * deliberately absent. Their parameters are proof and verification-key shaped (410/115 fields), not\n * polynomial shaped, so one compiled artifact serves both presets; the fold circuits assert\n * `chain_key_hash` against the insecure *or* the secure constant for exactly that reason. They ship\n * in the main entry point, which is why `verifyProof` works without a preset loaded.\n */\nexport type CircuitBundle = {\n readonly preset: CircuitPreset\n readonly crisp: CompiledCircuit\n readonly crispOnchain: CompiledCircuit\n readonly userDataEncryptionCt0: CompiledCircuit\n readonly userDataEncryptionCt1: CompiledCircuit\n}\n\nlet registered: CircuitBundle | null = null\n\n/**\n * Install the preset-bound circuits used by `generateProof`.\n *\n * The bundle is not bundled into the main entry point, because the secure-8192 artifacts are more\n * than an order of magnitude larger than the insecure-512 ones and no consumer needs both. Load the\n * one you want from its subpath and register it once at start-up:\n *\n * ```ts\n * import { setCircuits } from '@crisp-e3/sdk'\n * import { loadCircuits } from '@crisp-e3/sdk/insecure-512'\n *\n * setCircuits(await loadCircuits())\n * ```\n */\nexport const setCircuits = (bundle: CircuitBundle): void => {\n registered = bundle\n}\n\n/** The registered bundle, or `null` when none has been installed yet. */\nexport const getRegisteredCircuits = (): CircuitBundle | null => registered\n\n/** The preset currently installed, or `null` when none has been installed yet. */\nexport const registeredPreset = (): CircuitPreset | null => registered?.preset ?? null\n\n/**\n * The registered bundle, throwing a directed error when nothing has been installed.\n *\n * Proving cannot fall back to a default preset: a ballot proved against the wrong parameters fails\n * on chain rather than locally, so guessing here would move the failure somewhere much harder to\n * read.\n */\nexport const requireCircuits = (): CircuitBundle => {\n if (!registered) {\n throw new Error(\n 'No circuit preset registered. Import `loadCircuits` from \"@crisp-e3/sdk/insecure-512\" or ' +\n '\"@crisp-e3/sdk/secure-8192\" and pass the result to `setCircuits()` before proving.',\n )\n }\n\n return registered\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { hashMessage } from 'viem'\n\nexport const CRISP_SERVER_TOKEN_TREE_ENDPOINT = 'state/token-holders'\nexport const CRISP_SERVER_STATE_LITE_ENDPOINT = 'state/lite'\nexport const CRISP_SERVER_PREVIOUS_CIPHERTEXT_ENDPOINT = 'state/previous-ciphertext'\nexport const CRISP_SERVER_STATE_RESULT_ENDPOINT = 'state/result'\nexport const CRISP_SERVER_STATE_ALL_ENDPOINT = 'state/all'\nexport const CRISP_SERVER_ELIGIBLE_ADDRESSES_ENDPOINT = 'state/eligible-addresses'\nexport const CRISP_SERVER_VOTING_BROADCAST_ENDPOINT = 'voting/broadcast'\nexport const CRISP_SERVER_VOTING_STATUS_ENDPOINT = 'voting/status'\nexport const CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT = 'rounds/current'\nexport const CRISP_SERVER_ROUNDS_PUBLIC_KEY_ENDPOINT = 'rounds/public-key'\nexport const CRISP_SERVER_ROUNDS_CIPHERTEXT_ENDPOINT = 'rounds/ciphertext'\nexport const CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT = 'rounds/request'\n\n// Chain access. These let a client read the contracts CRISP already watches without holding a\n// hosted-provider key of its own — see the `/chain/*` routes on the server.\nexport const CRISP_SERVER_CHAIN_RPC_ENDPOINT = 'chain/rpc'\nexport const CRISP_SERVER_CHAIN_HEAD_ENDPOINT = 'chain/head'\nexport const CRISP_SERVER_CHAIN_READ_ENDPOINT = 'chain/read'\nexport const CRISP_SERVER_CHAIN_LOGS_ENDPOINT = 'chain/logs'\nexport const CRISP_SERVER_CHAIN_BLOCK_AT_TIMESTAMP_ENDPOINT = 'chain/block-at-timestamp'\n\nexport const MERKLE_TREE_MAX_DEPTH = 20 // static, hardcoded in the circuit.\n\n// @note Must stay aligned with CRISP circuits / threshold message layout (Rust & Noir MAX_MSG_NON_ZERO_COEFFS).\n// Vote payload uses only the first MAX_MSG_NON_ZERO_COEFFS polynomial coeffs, split evenly across options\n// (e.g. 2 options → 50 binary coeffs each within those 100).\nexport const MAX_MSG_NON_ZERO_COEFFS = 100\n// Hard limit on the maximum number of vote options supported.\nexport const MAX_VOTE_OPTIONS = 10\n\n/**\n * Message used by users to prove ownership of their Ethereum account\n * This message is signed by the user's private key to authenticate their identity\n * @notice Apps ideally want to use a different message to avoid signature reuse across different applications\n */\nexport const SIGNATURE_MESSAGE = 'CRISP: Sign this message to prove ownership of your Ethereum account'\nexport const SIGNATURE_MESSAGE_HASH = hashMessage(SIGNATURE_MESSAGE)\n\n// Placeholder signature for masking votes.\nexport const MASK_SIGNATURE =\n '0x8e7d77112641d59e9409ec3052041703bb9d9e6ed39bfcf75aefbcafe829ac6b21dd7648116ad5db0466fcb4bd468dcb28f6c069def8bc47cd9d859c85a016e31b'\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { CRISP_SERVER_TOKEN_TREE_ENDPOINT } from './constants'\n\nimport { parseAbi } from 'viem'\n\nimport { getPublicClient } from './chain'\n\n/**\n * Get the merkle tree data from the CRISP server\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n */\nexport const getTreeData = async (serverUrl: string, e3Id: bigint): Promise<bigint[]> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_TOKEN_TREE_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ round_id: e3Id.toString() }),\n })\n\n const hashes = (await response.json()) as string[]\n\n // Convert hex strings to BigInts\n return hashes.map((hash) => {\n // Ensure the hash is treated as a hex string\n if (!hash.startsWith('0x')) {\n return BigInt('0x' + hash)\n }\n return BigInt(hash)\n })\n}\n\n/**\n * Get the token balance at a specific block for a given address\n * @param voterAddress - The address of the voter\n * @param tokenAddress - The address of the token contract\n * @param snapshotBlock - The block number at which to get the balance\n * @param chainId - The chain ID of the network\n * @returns The token balance as a bigint\n */\nexport const getBalanceAt = async (voterAddress: string, tokenAddress: string, snapshotBlock: number, chainId: number): Promise<bigint> => {\n const publicClient = getPublicClient(chainId)\n\n const balance = (await publicClient.readContract({\n address: tokenAddress as `0x${string}`,\n abi: parseAbi(['function getPastVotes(address, uint256) view returns (uint256)']),\n functionName: 'getPastVotes',\n args: [voterAddress as `0x${string}`, BigInt(snapshotBlock)],\n })) as bigint\n\n return balance\n}\n\n/**\n * Get the total supply of a ERC20Votes Token at a specific block\n * @param tokenAddress The token address to query\n * @param snapshotBlock The block number at which to get the total supply\n * @param chainId The chain ID of the network\n * @returns The total supply as a bigint\n */\nexport const getTotalSupplyAt = async (tokenAddress: string, snapshotBlock: number, chainId: number): Promise<bigint> => {\n const publicClient = getPublicClient(chainId)\n\n const totalSupply = (await publicClient.readContract({\n address: tokenAddress as `0x${string}`,\n abi: parseAbi(['function getPastTotalSupply(uint256) view returns (uint256)']),\n functionName: 'getPastTotalSupply',\n args: [BigInt(snapshotBlock)],\n })) as bigint\n\n return totalSupply\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { createPublicClient, http } from 'viem'\nimport { localhost, mainnet, sepolia } from 'viem/chains'\n\nimport type { Chain, PublicClient } from 'viem'\n\n/**\n * The chain definition for a supported id, or `undefined` when it is not one we know.\n *\n * Unknown is not automatically fatal: with an explicit RPC URL the transport is fully determined,\n * and viem only needs the chain for conveniences like a default endpoint. Refusing outright would\n * mean this SDK could not talk to a network it had every means to reach.\n */\nconst resolveChain = (chainId: number): Chain | undefined => {\n switch (chainId) {\n case 1:\n return mainnet\n case 11155111:\n return sepolia\n case 31337:\n return localhost\n default:\n return undefined\n }\n}\n\n/**\n * Create a public client for reading contracts.\n *\n * Prefer passing `rpcUrl` — typically the CRISP server's own read-only endpoint, via\n * `chainRpcUrl(serverUrl)`. Without one, viem falls back to its default public endpoint for the\n * chain, which is a third-party service this SDK neither controls nor can observe: it is\n * rate-limited per IP, and a caller who has deliberately routed everything else through their own\n * infrastructure would still be depending on it here without knowing.\n *\n * @param chainId - The chain ID of the network\n * @param rpcUrl - Endpoint to read through. Omit only when the default public RPC is acceptable.\n * @returns The public client\n */\nexport const getPublicClient = (chainId: number, rpcUrl?: string): PublicClient => {\n const chain = resolveChain(chainId)\n\n if (!chain && !rpcUrl) {\n throw new Error(`Unsupported chainId ${chainId}: pass an rpcUrl to read through`)\n }\n\n return createPublicClient({\n transport: http(rpcUrl),\n chain,\n })\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { parseAbi } from 'viem'\n\nimport { CRISP_SERVER_PREVIOUS_CIPHERTEXT_ENDPOINT } from './constants'\nimport { getRoundStateLite } from './api'\nimport { getPublicClient } from './chain'\n\nimport type { CreditMode, OnChainRoundData, RoundDetails, SlotHead, TokenDetails } from './types'\n\n/**\n * Get the details of a specific round in a camelCase convenience format\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The round details\n */\nexport const getRoundDetails = async (serverUrl: string, e3Id: bigint): Promise<RoundDetails> => {\n const data = await getRoundStateLite(serverUrl, e3Id)\n\n return {\n e3Id: BigInt(data.id),\n tokenAddress: data.token_address,\n balanceThreshold: BigInt(data.balance_threshold),\n chainId: BigInt(data.chain_id),\n interfoldAddress: data.interfold_address,\n status: data.status,\n voteCount: BigInt(data.vote_count),\n startTime: BigInt(data.start_time),\n endTime: BigInt(data.end_time),\n startBlock: BigInt(data.start_block),\n snapshotBlock: BigInt(data.snapshot_block),\n committeePublicKey: new Uint8Array(data.committee_public_key),\n emojis: data.emojis,\n numOptions: BigInt(data.num_options),\n requester: data.requester,\n creditMode: data.credit_mode,\n credits: data.credits !== null ? BigInt(data.credits) : undefined,\n }\n}\n\n/**\n * Get the token address, balance threshold and snapshot block for a specific round\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The token address, balance threshold and snapshot block\n */\nexport const getRoundTokenDetails = async (serverUrl: string, e3Id: bigint): Promise<TokenDetails> => {\n const roundDetails = await getRoundDetails(serverUrl, e3Id)\n return {\n tokenAddress: roundDetails.tokenAddress,\n threshold: roundDetails.balanceThreshold,\n snapshotBlock: roundDetails.snapshotBlock,\n }\n}\n\n/**\n * Get the round data stored in the CRISPProgram contract, such as the merkle root\n * of the census and the merkle root of the encrypted votes published so far.\n *\n * Unlike {@link getRoundDetails}, this reads directly from the chain and so does not\n * depend on the CRISP server.\n *\n * @param programAddress - The address of the CRISPProgram contract\n * @param e3Id - The e3Id of the round\n * @param chainId - The chain ID of the network the program is deployed on\n * @param rpcUrl - Endpoint to read through. Omitted, viem's default public RPC for the chain is\n * used — a third-party service this SDK cannot observe or rate-limit.\n * @returns The on chain round data\n */\nexport const getOnChainRoundData = async (\n programAddress: string,\n e3Id: bigint,\n chainId: number,\n rpcUrl?: string,\n): Promise<OnChainRoundData> => {\n const publicClient = getPublicClient(chainId, rpcUrl)\n\n const [merkleRoot, paramsHash, numOptions, creditMode, inputRoot, numberOfVotes] = await publicClient.readContract({\n address: programAddress as `0x${string}`,\n abi: parseAbi([\n 'function getRoundData(uint256 e3Id) view returns (uint256 merkleRoot, bytes32 paramsHash, uint256 numOptions, uint8 creditMode, uint256 inputRoot, uint40 numberOfVotes)',\n ]),\n functionName: 'getRoundData',\n args: [e3Id],\n })\n\n return {\n merkleRoot,\n paramsHash,\n numOptions,\n creditMode: creditMode as CreditMode,\n inputRoot,\n numberOfVotes: BigInt(numberOfVotes),\n }\n}\n\n/**\n * Get the voting power a slot may spend in a `CensusMode.ONCHAIN` round, in ballot units.\n *\n * Read from the CRISP program rather than derived here. The contract scales raw token power by a\n * per-round divisor before handing it to the circuit as public input 4, and it is the same\n * contract that verifies the proof — so recomputing the value client-side would mean re-deriving\n * the round's snapshot, its divisor and the rounding, and any drift surfaces only as an opaque\n * verifier failure.\n *\n * @param programAddress - The CRISP program address\n * @param e3Id - The e3Id of the round\n * @param slot - The slot address the ballot is written to\n * @param chainId - The chain the program is deployed on\n * @param rpcUrl - Endpoint to read through; see {@link getOnChainRoundData}.\n * @returns The spendable voting power in ballot units, or 0 for a round that is not ONCHAIN\n */\nexport const getOnchainVotingPower = async (\n programAddress: string,\n e3Id: bigint,\n slot: string,\n chainId: number,\n rpcUrl?: string,\n): Promise<bigint> => {\n const publicClient = getPublicClient(chainId, rpcUrl)\n\n return publicClient.readContract({\n address: programAddress as `0x${string}`,\n abi: parseAbi(['function votingPowerOf(uint256 e3Id, address slot) view returns (uint256)']),\n functionName: 'votingPowerOf',\n args: [e3Id, slot as `0x${string}`],\n })\n}\n\n/**\n * Get the previous ciphertext for a slot from the CRISP server.\n * Returns undefined when the slot is empty (404).\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @param address - The address of the slot\n * @returns The end of the slot's chain of usable entries and its tree index, or undefined when the\n * slot holds nothing usable. The index is what a new input names as its parent.\n */\nexport const getPreviousCiphertext = async (serverUrl: string, e3Id: bigint, address: string): Promise<SlotHead | undefined> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_PREVIOUS_CIPHERTEXT_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ round_id: e3Id.toString(), address }),\n })\n\n if (response.status === 404) {\n return undefined\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch previous ciphertext: ${response.statusText}`)\n }\n\n const data = await response.json()\n\n return { ciphertext: new Uint8Array(data.ciphertext), index: Number(data.index) }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n CRISP_SERVER_ELIGIBLE_ADDRESSES_ENDPOINT,\n CRISP_SERVER_ROUNDS_CIPHERTEXT_ENDPOINT,\n CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT,\n CRISP_SERVER_ROUNDS_PUBLIC_KEY_ENDPOINT,\n CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT,\n CRISP_SERVER_STATE_ALL_ENDPOINT,\n CRISP_SERVER_STATE_LITE_ENDPOINT,\n CRISP_SERVER_STATE_RESULT_ENDPOINT,\n CRISP_SERVER_TOKEN_TREE_ENDPOINT,\n CRISP_SERVER_VOTING_BROADCAST_ENDPOINT,\n CRISP_SERVER_VOTING_STATUS_ENDPOINT,\n CRISP_SERVER_CHAIN_HEAD_ENDPOINT,\n CRISP_SERVER_CHAIN_READ_ENDPOINT,\n CRISP_SERVER_CHAIN_LOGS_ENDPOINT,\n CRISP_SERVER_CHAIN_BLOCK_AT_TIMESTAMP_ENDPOINT,\n CRISP_SERVER_CHAIN_RPC_ENDPOINT,\n} from './constants'\n\nimport type {\n ChainHead,\n ContractRead,\n ContractReadResult,\n IndexedLog,\n LogQuery,\n BroadcastVoteRequest,\n BroadcastVoteResponse,\n CurrentRoundResponse,\n E3StateLiteResponse,\n JsonResponse,\n NewRoundRequest,\n TokenHolder,\n VoteStatusResponse,\n WebResultResponse,\n} from './types'\n\n/**\n * POST a JSON body to a CRISP server endpoint and parse the JSON response.\n * @param serverUrl - The base URL of the CRISP server\n * @param endpoint - The endpoint path (without leading slash)\n * @param body - The request body to serialize as JSON\n * @returns The parsed JSON response\n * @throws If the server responds with a non-OK status\n */\nconst postJson = async <TResponse>(serverUrl: string, endpoint: string, body: unknown): Promise<TResponse> => {\n const response = await fetch(`${serverUrl}/${endpoint}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) {\n throw new Error(`CRISP server request to /${endpoint} failed (${response.status}): ${await response.text()}`)\n }\n\n return (await response.json()) as TResponse\n}\n\n/**\n * Get the current (most recent) round, optionally filtered by requester addresses.\n * Returns undefined when no current round exists (404).\n * @param serverUrl - The base URL of the CRISP server\n * @param requesters - Optional list of requester addresses to filter by (only the first is used by the server)\n * @returns The current round id, or undefined if none exists\n */\nexport const getCurrentRound = async (serverUrl: string, requesters: string[] = []): Promise<CurrentRoundResponse | undefined> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ requesters }),\n })\n\n if (response.status === 404) {\n return undefined\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch current round (${response.status}): ${await response.text()}`)\n }\n\n return (await response.json()) as CurrentRoundResponse\n}\n\n/**\n * Get the committee public key for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The committee public key bytes\n */\nexport const getRoundPublicKey = async (serverUrl: string, e3Id: bigint): Promise<Uint8Array> => {\n const data = await postJson<{ round_id: string; pk_bytes: number[] }>(serverUrl, CRISP_SERVER_ROUNDS_PUBLIC_KEY_ENDPOINT, {\n round_id: e3Id.toString(),\n pk_bytes: [],\n })\n\n return new Uint8Array(data.pk_bytes)\n}\n\n/**\n * Get the ciphertext output for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The ciphertext output bytes\n */\nexport const getRoundCiphertext = async (serverUrl: string, e3Id: bigint): Promise<Uint8Array> => {\n const data = await postJson<{ round_id: string; ct_bytes: number[] }>(serverUrl, CRISP_SERVER_ROUNDS_CIPHERTEXT_ENDPOINT, {\n round_id: e3Id.toString(),\n ct_bytes: [],\n })\n\n return new Uint8Array(data.ct_bytes)\n}\n\n/**\n * Request a new E3 round. Requires the server's cron API key.\n * @param serverUrl - The base URL of the CRISP server\n * @param request - The new round request (cron API key, token address and balance threshold)\n * @returns The server confirmation message\n */\nexport const requestNewRound = async (serverUrl: string, request: NewRoundRequest): Promise<JsonResponse> =>\n postJson<JsonResponse>(serverUrl, CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT, {\n cron_api_key: request.cronApiKey,\n token_address: request.tokenAddress,\n balance_threshold: request.balanceThreshold,\n census_mode: request.censusMode,\n })\n\n/**\n * Broadcast an encrypted vote through the CRISP server, which relays it on-chain.\n * @param serverUrl - The base URL of the CRISP server\n * @param request - The vote request (round id and hex encoded proof)\n * @returns The broadcast result, including the transaction hash on success\n */\nexport const broadcastVote = async (serverUrl: string, request: BroadcastVoteRequest): Promise<BroadcastVoteResponse> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_VOTING_BROADCAST_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n round_id: request.e3Id.toString(),\n encoded_proof: request.encodedProof,\n }),\n })\n\n // The server returns a structured VoteResponse body for broadcast failures (500) as well\n const data = (await response.json()) as BroadcastVoteResponse | string\n\n if (typeof data === 'string') {\n throw new Error(`Failed to broadcast vote (${response.status}): ${data}`)\n }\n\n return data\n}\n\n/**\n * Get the vote status for an address in a specific round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @param address - The voter address\n * @returns The vote status for the address\n */\nexport const getVoteStatus = async (serverUrl: string, e3Id: bigint, address: string): Promise<VoteStatusResponse> =>\n postJson<VoteStatusResponse>(serverUrl, CRISP_SERVER_VOTING_STATUS_ENDPOINT, { round_id: e3Id.toString(), address })\n\n/**\n * Get the result for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The round result (tally, emojis, total votes, end time and requester)\n */\nexport const getRoundResult = async (serverUrl: string, e3Id: bigint): Promise<WebResultResponse> =>\n postJson<WebResultResponse>(serverUrl, CRISP_SERVER_STATE_RESULT_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * Get the results for all rounds, optionally filtered by requester addresses.\n * @param serverUrl - The base URL of the CRISP server\n * @param requesters - Optional list of requester addresses to filter by\n * @returns The results for all matching rounds\n */\nexport const getAllRoundResults = async (serverUrl: string, requesters: string[] = []): Promise<WebResultResponse[]> =>\n postJson<WebResultResponse[]>(serverUrl, CRISP_SERVER_STATE_ALL_ENDPOINT, { requesters })\n\n/**\n * Get the lite state for a given round, as returned by the server (snake_case fields).\n * See `getRoundDetails` in `state.ts` for a camelCase convenience wrapper over this endpoint.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The lite round state\n */\nexport const getRoundStateLite = async (serverUrl: string, e3Id: bigint): Promise<E3StateLiteResponse> =>\n postJson<E3StateLiteResponse>(serverUrl, CRISP_SERVER_STATE_LITE_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * Get the token holder hashes (hash(address, balance)) for a given round.\n * These are the Merkle tree leaves used for eligibility proofs.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The list of token holder hashes\n */\nexport const getTokenHolderHashes = async (serverUrl: string, e3Id: bigint): Promise<string[]> =>\n postJson<string[]>(serverUrl, CRISP_SERVER_TOKEN_TREE_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * Get the eligible addresses and their balances for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The list of eligible token holders\n */\nexport const getEligibleAddresses = async (serverUrl: string, e3Id: bigint): Promise<TokenHolder[]> =>\n postJson<TokenHolder[]>(serverUrl, CRISP_SERVER_ELIGIBLE_ADDRESSES_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * The chain head (block number, timestamp, chain id) as seen by the CRISP server.\n *\n * One call in place of polling `eth_blockNumber` from every hook that wants to know whether\n * something has advanced, and it carries the timestamp so a caller deciding whether a voting\n * window has closed does not need a second round trip for the block.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @returns The current head\n */\nexport const getChainHead = async (serverUrl: string): Promise<ChainHead> => {\n const data = await postJson<{ block_number: number | string; timestamp: number | string; chain_id: number }>(\n serverUrl,\n CRISP_SERVER_CHAIN_HEAD_ENDPOINT,\n {},\n )\n\n return {\n blockNumber: BigInt(data.block_number),\n timestamp: BigInt(data.timestamp),\n chainId: Number(data.chain_id),\n }\n}\n\n/**\n * Read allowlisted contracts through the CRISP server, batched.\n *\n * Point reads are answered from the chain rather than from the server's index on purpose: they\n * are per-account and change constantly, and a stale answer here is not a slow UI but a wrong\n * balance or a voter wrongly told they cannot vote.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param calls - The calls to perform, in order\n * @returns One result per call, in the same order\n */\nexport const readContracts = async (serverUrl: string, calls: ContractRead[]): Promise<ContractReadResult[]> => {\n if (calls.length === 0) return []\n\n const data = await postJson<{ result: string | null; error: string | null }[]>(serverUrl, CRISP_SERVER_CHAIN_READ_ENDPOINT, {\n calls: calls.map((call) => ({\n address: call.address,\n data: call.data,\n block_number: call.blockNumber !== undefined ? Number(call.blockNumber) : undefined,\n })),\n })\n\n return data.map((entry) => ({\n result: entry.result ? (entry.result as `0x${string}`) : undefined,\n error: entry.error ?? undefined,\n }))\n}\n\n/**\n * Query logs for an allowlisted contract over an arbitrary block range.\n *\n * The range needs no chunking by the caller: the server splits it into windows the upstream\n * provider accepts, which is the whole reason clients otherwise carry range-splitting code.\n *\n * It is still BOUNDED — the server refuses a span wider than a million blocks, and `fromBlock`\n * defaults to 0, so a query naming only an address is rejected on a long-lived chain. Pass the\n * contract's deployment block as `fromBlock`; that is the intended usage and always in range.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param query - The log query\n * @returns The matching logs, ordered by block and log index\n */\nexport const getIndexedLogs = async (serverUrl: string, query: LogQuery): Promise<IndexedLog[]> => {\n const data = await postJson<\n {\n address: string\n topics: string[]\n data: string\n block_number: number | null\n transaction_hash: string | null\n log_index: number | null\n }[]\n >(serverUrl, CRISP_SERVER_CHAIN_LOGS_ENDPOINT, {\n address: query.address,\n topics: (query.topics ?? []).map((topic) => topic ?? null),\n from_block: query.fromBlock !== undefined ? Number(query.fromBlock) : undefined,\n to_block: query.toBlock !== undefined ? Number(query.toBlock) : undefined,\n })\n\n return data.map((log) => ({\n address: log.address,\n topics: log.topics as `0x${string}`[],\n data: log.data as `0x${string}`,\n blockNumber: log.block_number !== null ? BigInt(log.block_number) : undefined,\n transactionHash: log.transaction_hash ?? undefined,\n logIndex: log.log_index ?? undefined,\n }))\n}\n\n/**\n * The last block at or before a timestamp.\n *\n * Clients need this to turn a proposal's snapshot timepoint into a block. Done client-side it is\n * a binary search costing `O(log n)` block fetches per lookup; the server spends those on its own\n * connection instead.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param timestamp - The unix timestamp to resolve\n * @returns The block at or before the timestamp, and that block's timestamp\n */\nexport const getBlockAtTimestamp = async (serverUrl: string, timestamp: bigint): Promise<{ blockNumber: bigint; timestamp: bigint }> => {\n const data = await postJson<{ block_number: number | string; timestamp: number | string }>(\n serverUrl,\n CRISP_SERVER_CHAIN_BLOCK_AT_TIMESTAMP_ENDPOINT,\n { timestamp: Number(timestamp) },\n )\n\n return { blockNumber: BigInt(data.block_number), timestamp: BigInt(data.timestamp) }\n}\n\n/**\n * The URL of the server's read-only JSON-RPC endpoint.\n *\n * Point a standard Ethereum client at this to read the allowlisted contracts without a\n * hosted-provider key. It serves reads only — transactions are signed and broadcast by the\n * user's wallet, which brings its own transport.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @returns The JSON-RPC URL\n */\nexport const chainRpcUrl = (serverUrl: string): string =>\n `${serverUrl.replace(/\\/+$/, '')}/${CRISP_SERVER_CHAIN_RPC_ENDPOINT}`\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { poseidon2 } from 'poseidon-lite'\nimport { LeanIMT } from '@zk-kit/lean-imt'\nimport type { MerkleProof } from './types'\nimport { MAX_MSG_NON_ZERO_COEFFS, MERKLE_TREE_MAX_DEPTH, SIGNATURE_MESSAGE_HASH } from './constants'\nimport { publicKeyToAddress } from 'viem/utils'\nimport { hexToBytes, recoverPublicKey } from 'viem'\n\n/**\n * Hash a leaf node for the Merkle tree\n * @param address The voter's address\n * @param balance The voter's balance\n * @returns The hashed leaf as a bigint\n */\nexport const hashLeaf = (address: string, balance: bigint): bigint => {\n return poseidon2([address.toLowerCase(), balance])\n}\n\n/**\n * Generate a new LeanIMT with the leaves provided\n * @param leaves The leaves of the Merkle tree\n * @returns the generated Merkle tree\n */\nexport const generateMerkleTree = (leaves: bigint[]): LeanIMT => {\n return new LeanIMT((a, b) => poseidon2([a, b]), leaves)\n}\n\n/**\n * Generate a Merkle proof for a given address to prove inclusion in the voters' list\n * @param balance The voter's balance\n * @param address The voter's address\n * @param leaves The leaves of the Merkle tree\n */\nexport const generateMerkleProof = (balance: bigint, address: string, leaves: bigint[] | string[]): MerkleProof => {\n const leaf = hashLeaf(address.toLowerCase(), balance)\n\n const index = leaves.findIndex((l) => BigInt(l) === leaf)\n\n if (index === -1) {\n throw new Error('Leaf not found in the tree')\n }\n\n const tree = generateMerkleTree(leaves.map((l) => BigInt(l)))\n\n const proof = tree.generateProof(index)\n\n // Pad siblings with zeros\n const paddedSiblings = [...proof.siblings, ...Array(MERKLE_TREE_MAX_DEPTH - proof.siblings.length).fill(0n)]\n // Pad indices with zeros\n const indices = proof.siblings.map((_, i) => Number((BigInt(proof.index) >> BigInt(i)) & 1n))\n const paddedIndices = [...indices, ...Array(MERKLE_TREE_MAX_DEPTH - indices.length).fill(0)]\n\n return {\n leaf,\n index,\n proof: {\n ...proof,\n siblings: paddedSiblings,\n },\n // Original length before padding\n length: proof.siblings.length,\n indices: paddedIndices,\n }\n}\n\n/**\n * Convert a number to its binary representation\n * @param number The number to convert to binary\n * @returns The binary representation of the number as a string\n */\nexport const toBinary = (number: number): string => {\n if (number < 0) {\n throw new Error('Value cannot be negative')\n }\n\n return number.toString(2)\n}\n\n/**\n * Given a signature, extract the signature components for the Noir signature verification circuit.\n * @param signature The signature to extract the components from.\n * @returns The extracted signature components.\n */\nexport const extractSignatureComponents = async (\n signature: `0x${string}`,\n messageHash: `0x${string}` = SIGNATURE_MESSAGE_HASH,\n): Promise<{\n messageHash: Uint8Array\n publicKeyX: Uint8Array\n publicKeyY: Uint8Array\n signature: Uint8Array\n}> => {\n const publicKey = await recoverPublicKey({ hash: messageHash, signature })\n const publicKeyBytes = hexToBytes(publicKey)\n const publicKeyX = publicKeyBytes.slice(1, 33)\n const publicKeyY = publicKeyBytes.slice(33, 65)\n\n // Extract r and s from signature (remove v)\n const sigBytes = hexToBytes(signature)\n const r = sigBytes.slice(0, 32) // First 32 bytes\n const s = sigBytes.slice(32, 64) // Next 32 bytes\n\n const signatureBytes = new Uint8Array(64)\n signatureBytes.set(r, 0)\n signatureBytes.set(s, 32)\n\n return {\n messageHash: hexToBytes(messageHash),\n publicKeyX: publicKeyX,\n publicKeyY: publicKeyY,\n signature: signatureBytes,\n }\n}\n\nexport const getAddressFromSignature = async (signature: `0x${string}`, messageHash?: `0x${string}`): Promise<string> => {\n const publicKey = await recoverPublicKey({ hash: messageHash || SIGNATURE_MESSAGE_HASH, signature })\n\n return publicKeyToAddress(publicKey)\n}\n\n/**\n * Get the maximum vote value for a given number of choices.\n * @param numChoices Number of choices.\n * @returns Maximum value per choice.\n */\nexport const getMaxVoteValue = (numChoices: number): number => {\n const segmentSize = Math.floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)\n return 2 ** segmentSize - 1\n}\n\n/**\n * Get a zero vote with the given number of choices.\n * @param numChoices Number of choices.\n * @returns A zero vote with the given number of choices.\n */\nexport const getZeroVote = (numChoices: number): number[] => {\n return Array(numChoices).fill(0)\n}\n\n/**\n * Decode bytes to a bigint array (little-endian, 8 bytes per value).\n *\n * @remarks\n * Returns `bigint` rather than `number`: a coefficient of an aggregated plaintext\n * is a sum over all ballots and can exceed `Number.MAX_SAFE_INTEGER`.\n *\n * @param data The bytes to decode (must be multiple of 8).\n * @returns Array of coefficients.\n */\nexport const decodeBytesToBigInts = (data: Uint8Array): bigint[] => {\n if (data.length % 8 !== 0) {\n throw new Error('Data length must be multiple of 8')\n }\n\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength)\n const arrayLength = data.length / 8\n const result: bigint[] = []\n\n for (let i = 0; i < arrayLength; i++) {\n result.push(view.getBigUint64(i * 8, true)) // true = little-endian\n }\n\n return result\n}\n\nexport const bigInt64ArrayToNumberArray = (bigInt64Array: BigInt64Array): number[] => {\n return Array.from(bigInt64Array).map(Number)\n}\n\nexport const numberArrayToBigInt64Array = (numberArray: number[]): BigInt64Array => {\n return BigInt64Array.from(numberArray.map(BigInt))\n}\n\n// Helper function to convert proof bytes to field elements\nexport const proofToFields = (proof: Uint8Array): string[] => {\n const fields: string[] = []\n for (let i = 0; i < proof.length; i += 32) {\n const chunk = proof.slice(i, i + 32)\n fields.push('0x' + Buffer.from(chunk).toString('hex'))\n }\n return fields\n}\n\n/**\n * Scale down the raw balance to 1 decimal precision\n * @param balance - The raw balance (with all tokens decimals)\n * @param decimals - The decimals of the token\n * @returns The balance as a .1 precision scaled value\n */\nexport const getScaledBalance = (balance: bigint, decimals: bigint): bigint => {\n const precision = decimals > 1n ? decimals - 1n : 0n\n\n return balance / 10n ** precision\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\n/**\n * Vote encoding and BFV encryption for the CRISP voting protocol.\n *\n * Encodes vote choices (numbers per option) into polynomial coefficient arrays\n * suitable for BFV homomorphic encryption. Each choice is represented as a\n * segment of binary digits within the first MAX_MSG_NON_ZERO_COEFFS coeffs, then\n * zero-padded to the BFV polynomial degree. Supports\n * encoding, encryption, decryption, and tally decoding.\n */\n\nimport { ZKInputsGenerator } from '@crisp-e3/zk-inputs'\nimport { registeredPreset, type CircuitPreset } from './circuits'\nimport { toBinary, numberArrayToBigInt64Array, decodeBytesToBigInts, getMaxVoteValue } from './utils'\nimport { MAX_MSG_NON_ZERO_COEFFS, MAX_VOTE_OPTIONS } from './constants'\nimport { hexToBytes } from 'viem'\nimport type { Hex } from 'viem'\nimport type { TallyResult, Vote } from './types'\n\nlet _zkInputsGenerator: InstanceType<typeof ZKInputsGenerator> | null = null\nlet _zkInputsGeneratorPreset: CircuitPreset | 'default' | null = null\nlet _zkInputsGeneratorPresetOverride: CircuitPreset | null = null\n\n/** Force a BFV preset for contexts that do not share the registered circuit bundle. */\nexport const setZkInputsGeneratorPreset = (preset: CircuitPreset): void => {\n if (_zkInputsGeneratorPresetOverride !== preset) {\n _zkInputsGenerator = null\n _zkInputsGeneratorPreset = null\n _zkInputsGeneratorPresetOverride = preset\n }\n}\n\n/**\n * Returns the singleton ZK inputs generator instance for the registered BFV preset.\n */\nexport const getZkInputsGenerator = () => {\n const preset = _zkInputsGeneratorPresetOverride ?? registeredPreset()\n const targetPreset = preset ?? 'default'\n\n if (!_zkInputsGenerator || _zkInputsGeneratorPreset !== targetPreset) {\n _zkInputsGenerator = preset ? ZKInputsGenerator.fromPreset(preset) : ZKInputsGenerator.withDefaults()\n _zkInputsGeneratorPreset = targetPreset\n }\n\n return _zkInputsGenerator\n}\n\n/**\n * Encodes vote choices into a polynomial coefficient array for BFV encryption.\n * Each choice occupies floor(MAX_MSG_NON_ZERO_COEFFS / n) binary coefficients;\n * remaining slots in the first MAX_MSG_NON_ZERO_COEFFS coeffs are zero; then\n * the vector is padded to the BFV degree.\n *\n * @param vote - Array of numeric values per choice (e.g. [10, 5] for 2 options)\n * @returns Array of 0s and 1s representing coefficients\n * @throws If vote has fewer than 2 choices, any value exceeds max for its segment, or degree is too small\n */\nexport const encodeVote = (vote: Vote): number[] => {\n const numChoices = vote.length\n\n if (numChoices < 2) {\n throw new Error('Vote must have at least two choices')\n }\n\n // The Noir circuit asserts num_options <= MAX_OPTIONS, so a vote beyond this can never\n // produce a valid proof. Reject it here rather than encoding an unprovable vote.\n if (numChoices > MAX_VOTE_OPTIONS) {\n throw new Error(`Number of choices (${numChoices}) exceeds MAX_VOTE_OPTIONS (${MAX_VOTE_OPTIONS})`)\n }\n\n const bfvParams = getZkInputsGenerator().getBFVParams()\n const degree = bfvParams.degree\n if (degree < MAX_MSG_NON_ZERO_COEFFS) {\n throw new Error(`BFV degree (${degree}) must be at least MAX_MSG_NON_ZERO_COEFFS (${MAX_MSG_NON_ZERO_COEFFS})`)\n }\n\n const segmentSize = Math.floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)\n const maxValue = getMaxVoteValue(numChoices)\n const voteArray: number[] = []\n\n for (let choiceIdx = 0; choiceIdx < numChoices; choiceIdx += 1) {\n const value = vote[choiceIdx]\n\n if (value > maxValue) {\n throw new Error(`Vote value for choice ${choiceIdx} exceeds maximum (${maxValue})`)\n }\n\n const binary = toBinary(value).split('')\n\n for (let i = 0; i < segmentSize; i += 1) {\n const offset = segmentSize - binary.length\n voteArray.push(i < offset ? 0 : parseInt(binary[i - offset], 10))\n }\n }\n\n const msgCoeffsUsed = segmentSize * numChoices\n for (let i = msgCoeffsUsed; i < MAX_MSG_NON_ZERO_COEFFS; i += 1) {\n voteArray.push(0)\n }\n\n for (let i = 0; i < degree - MAX_MSG_NON_ZERO_COEFFS; i += 1) {\n voteArray.push(0)\n }\n\n return voteArray\n}\n\n/**\n * Encrypts an encoded vote using BFV homomorphic encryption.\n *\n * @param vote - Vote choices to encrypt\n * @param publicKey - BFV public key\n * @returns Encrypted ciphertext\n */\nexport const encryptVote = (vote: Vote, publicKey: Uint8Array): Uint8Array => {\n const encodedVote = encodeVote(vote)\n\n return getZkInputsGenerator().encryptVote(publicKey, numberArrayToBigInt64Array(encodedVote))\n}\n\n/**\n * Decodes raw tally bytes (or coefficients) into a total per choice.\n * Expects the same segment layout as used in encodeVote.\n *\n * Mirrors `crisp_utils::decode_tally` (Rust) and `CRISPProgram.decodeTally` (Solidity):\n * only the first MAX_MSG_NON_ZERO_COEFFS coefficients carry the payload, split into\n * `floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)` binary coefficients per choice, MSB first.\n *\n * @param tallyBytes - Hex string, or the polynomial coefficients from tally/decryption\n * @param numChoices - Number of vote options: an integer from 2 to MAX_VOTE_OPTIONS\n * @returns One total per choice\n * @throws If numChoices is outside 2..MAX_VOTE_OPTIONS or not an integer, or there are fewer\n * coefficients than the payload region\n */\nexport const decodeTally = (tallyBytes: string | number[] | bigint[], numChoices: number): TallyResult => {\n // `CRISPProgram.validate` rejects a round outside 2..MAX_VOTE_OPTIONS, and `encodeVote` refuses\n // to encode fewer than two choices, so no tally in that range can exist. `Number.isInteger` also\n // screens out NaN, Infinity, and fractions: a fractional count silently returns `ceil(numChoices)`\n // segments, and NaN passes both bound checks to return an empty tally.\n if (!Number.isInteger(numChoices) || numChoices < 2) {\n throw new Error(`Number of choices (${numChoices}) must be an integer of at least 2`)\n }\n\n // Rounds cannot exceed MAX_VOTE_OPTIONS (the circuit's MAX_OPTIONS), so a larger count\n // is a caller error rather than a tally to decode.\n if (numChoices > MAX_VOTE_OPTIONS) {\n throw new Error(`Number of choices (${numChoices}) exceeds MAX_VOTE_OPTIONS (${MAX_VOTE_OPTIONS})`)\n }\n\n let coefficients: bigint[]\n if (typeof tallyBytes === 'string') {\n const hexString = tallyBytes.startsWith('0x') ? tallyBytes : `0x${tallyBytes}`\n coefficients = decodeBytesToBigInts(hexToBytes(hexString as Hex))\n } else {\n coefficients = (tallyBytes as Array<number | bigint>).map(BigInt)\n }\n\n if (coefficients.length < MAX_MSG_NON_ZERO_COEFFS) {\n throw new Error(`decoded coefficient count (${coefficients.length}) is less than MAX_MSG_NON_ZERO_COEFFS (${MAX_MSG_NON_ZERO_COEFFS})`)\n }\n\n const segmentSize = Math.floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)\n const results: TallyResult = []\n\n for (let choiceIdx = 0; choiceIdx < numChoices; choiceIdx++) {\n const segmentStart = choiceIdx * segmentSize\n\n let value = 0n\n for (let i = 0; i < segmentSize; i++) {\n value += coefficients[segmentStart + i] << BigInt(segmentSize - 1 - i)\n }\n\n results.push(value)\n }\n\n return results\n}\n\n/**\n * Decrypts a BFV-encrypted vote and decodes it to vote values.\n *\n * @param ciphertext - Encrypted vote\n * @param secretKey - BFV secret key\n * @param numChoices - Number of vote options\n * @returns One total per choice\n */\nexport const decryptVote = (ciphertext: Uint8Array, secretKey: Uint8Array, numChoices: number): TallyResult => {\n const decryptedVote = getZkInputsGenerator().decryptVote(secretKey, ciphertext)\n\n return decodeTally(\n Array.from(decryptedVote, (value) => BigInt(value)),\n numChoices,\n )\n}\n\n/**\n * Generates a BFV keypair for vote encryption and decryption.\n *\n * @returns Object with secretKey and publicKey as Uint8Arrays\n */\nexport const generateBFVKeys = (): { secretKey: Uint8Array; publicKey: Uint8Array } => {\n return getZkInputsGenerator().generateKeys()\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { getZkInputsGenerator, encodeVote } from './encoding'\nimport { extractSignatureComponents, generateMerkleProof, getZeroVote, numberArrayToBigInt64Array } from './utils'\nimport type { PreparedBallot, PrepareBallotInputs } from './types'\n\n/**\n * Split a 32-byte digest into the two 16-byte halves the circuit takes as public inputs.\n *\n * A Keccak digest is 256 bits and a field element holds fewer than 254, so it cannot cross the\n * circuit boundary in one piece. `crisp_lib::ecdsa::digest_from_halves` rebuilds the 32 bytes and\n * range-checks each half, and `CRISPProgram.publishInput` splits the same way.\n *\n * @param digest The 32-byte ballot digest.\n * @returns The high and low halves as hex field elements.\n */\nexport const splitDigest = (digest: `0x${string}`): { digestHi: `0x${string}`; digestLo: `0x${string}` } => {\n if (digest.length !== 66) {\n throw new Error(`Invalid digest: expected 32 bytes, got ${(digest.length - 2) / 2}`)\n }\n\n return {\n digestHi: `0x${digest.slice(2, 34)}`,\n digestLo: `0x${digest.slice(34, 66)}`,\n }\n}\n\n/**\n * Phase one of building a ballot: encrypt the vote and build every circuit input that does not\n * depend on the signature.\n *\n * Kept separate from the signature because the digest a voter signs binds the ciphertext, so the\n * ciphertext has to exist first. The returned `ctCommitment` is what `CRISPProgram.ballotDigest`\n * takes as its `ciphertextCommitment` argument.\n *\n * One path for all three operations. A first vote, a re-vote, and a mask reach the same generator\n * with the same arguments, differ only in `isMaskVote` — which stays private to the proof — and\n * produce the same shape of submission. Branching here would make the three tellable apart by\n * anything watching the client, which is what masks exist to prevent.\n *\n * Kept in a separate module so it can run in a worker.\n *\n * @param inputs The ballot to prepare.\n * @returns The partial circuit inputs, the ciphertext, and its commitment.\n */\nexport const prepareCircuitInputsImpl = async (inputs: PrepareBallotInputs): Promise<PreparedBallot> => {\n const zkInputsGenerator = getZkInputsGenerator()\n\n const numOptions = inputs.isMaskVote ? inputs.numOptions : inputs.vote.length\n const vote = inputs.isMaskVote ? getZeroVote(numOptions) : inputs.vote\n const encodedVote = encodeVote(vote)\n\n // Only a mask adds to what the slot already holds. A vote replaces it, so a voter cannot have\n // their old ballot counted alongside the new one. The circuit derives the same choice from\n // `is_mask_vote` and rejects any witness built the other way.\n const keepPrevious = inputs.isMaskVote && !!inputs.previousCiphertext\n\n const { inputs: circuitInputs, encryptedVote } = await zkInputsGenerator.generateInputs(\n inputs.previousCiphertext,\n inputs.publicKey,\n numberArrayToBigInt64Array(encodedVote),\n keepPrevious,\n )\n\n circuitInputs.slot_address = inputs.slotAddress.toLowerCase()\n circuitInputs.is_first_vote = !inputs.previousCiphertext\n circuitInputs.is_mask_vote = inputs.isMaskVote\n circuitInputs.num_options = numOptions.toString()\n\n if (inputs.censusMode === 'onchain') {\n circuitInputs.voting_power = inputs.votingPower.toString()\n } else {\n // Derived here rather than by the caller. The old API recovered the slot address from the\n // signature to build this, which is no longer possible: the signature now comes after the\n // ciphertext, and the caller states the slot address instead.\n const merkleProof = generateMerkleProof(inputs.balance, inputs.slotAddress, inputs.merkleLeaves)\n\n circuitInputs.balance = inputs.balance.toString()\n circuitInputs.merkle_root = merkleProof.proof.root.toString()\n circuitInputs.merkle_proof_length = merkleProof.length.toString()\n circuitInputs.merkle_proof_indices = merkleProof.indices.map((i) => i === 1)\n circuitInputs.merkle_proof_siblings = merkleProof.proof.siblings.map((s) => s.toString())\n }\n\n // The commitment to `encryptedVote`, which is the ciphertext this ballot publishes: the ballot\n // itself for a vote or a re-vote, the slot plus the zero ballot for a mask over an occupied slot.\n // The circuit returns the same value as `final_ct_commitment`, `CRISPProgram` stores it, and\n // `CRISPProgram.ballotDigest` is built over it — so it is what a voter has to sign, and it has to\n // be known before proving because the digest is itself a circuit input.\n //\n // Exported by the wasm alongside the witness. Recomputing it here would have to match\n // `compute_ciphertext_commitment` exactly, so it is carried across instead.\n const ctCommitment = `0x${BigInt(circuitInputs.sum_ct_commitment).toString(16).padStart(64, '0')}` as `0x${string}`\n\n // Zero when there is nothing to extend, which is what the contract reads as `is_first_vote`.\n //\n // Checked at runtime as well as in the type, because a caller reaching this through plain\n // JavaScript or a widened object gets no type error. Defaulting a missing index to zero would\n // name the slot's first entry as the parent, and the proof would be built against one commitment\n // while the contract supplied another — visible only as a rejected proof.\n if (inputs.previousCiphertext !== undefined) {\n const index = inputs.previousIndex\n // Non-negative and safe, not merely an integer. `-1` would come back out as zero, which the\n // contract reads as \"extends nothing\" — a re-vote silently published as a first vote against a\n // slot that already holds one. Anything at or above `MAX_SAFE_INTEGER` cannot represent\n // `index + 1` exactly, so the parent it names is not the parent it meant.\n if (!Number.isSafeInteger(index) || (index as number) < 0 || (index as number) + 1 > Number.MAX_SAFE_INTEGER) {\n throw new Error(\n `previousCiphertext needs a non-negative safe integer previousIndex; got ${String(index)}. Pass the slot head as a pair.`,\n )\n }\n }\n\n const parentIndexPlusOne = inputs.previousCiphertext !== undefined ? (inputs.previousIndex as number) + 1 : 0\n\n return { circuitInputs, encryptedVote, ctCommitment, parentIndexPlusOne, censusMode: inputs.censusMode }\n}\n\n/**\n * Phase two: attach the signed digest to a prepared ballot.\n *\n * The digest is a public input in both branches, because `CRISPProgram.publishInput` computes it\n * for every input. A mask carries the same digest as a real vote and only skips the signature\n * check inside the circuit, which is what keeps the two indistinguishable on chain.\n *\n * @param prepared The output of `prepareCircuitInputsImpl`.\n * @param digest The digest from `CRISPProgram.ballotDigest`.\n * @param signature The signature over that digest. A mask passes the placeholder signature.\n * @returns The complete circuit inputs.\n */\nexport const attachSignatureImpl = async (prepared: PreparedBallot, digest: `0x${string}`, signature: `0x${string}`): Promise<any> => {\n const { digestHi, digestLo } = splitDigest(digest)\n const components = await extractSignatureComponents(signature, digest)\n\n const circuitInputs = prepared.circuitInputs\n circuitInputs.digest_hi = digestHi\n circuitInputs.digest_lo = digestLo\n circuitInputs.public_key_x = Array.from(components.publicKeyX).map((b) => b.toString())\n circuitInputs.public_key_y = Array.from(components.publicKeyY).map((b) => b.toString())\n circuitInputs.signature = Array.from(components.signature).map((b) => b.toString())\n\n return circuitInputs\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { type Vote, type CensusVariant, type PrepareBallotInputs, type PreparedBallot, ProofData } from './types'\nimport { getMaxVoteValue, proofToFields } from './utils'\nimport { attachSignatureImpl, prepareCircuitInputsImpl } from './circuitInputs'\nimport { MASK_SIGNATURE } from './constants'\nexport { encodeVote, encryptVote, decodeTally, decryptVote, generateBFVKeys } from './encoding'\nexport { splitDigest } from './circuitInputs'\nimport { Noir, type CompiledCircuit } from '@noir-lang/noir_js'\nimport { Barretenberg, BackendType, UltraHonkBackend } from '@aztec/bb.js'\n// Only the aggregation circuits are imported here. Their ABI is proof and verification-key shaped\n// rather than polynomial shaped, so one artifact serves every preset and inlining them costs ~0.3MB.\n// The BFV-shaped circuits arrive through `setCircuits()` — see ./circuits.\nimport foldCircuit from '../../../circuits/bin/fold/target/crisp_fold.json'\nimport foldOnchainCircuit from '../../../circuits/bin/fold_onchain/target/crisp_onchain_fold.json'\nimport userDataEncryptionCircuit from '../../../../../circuits/bin/threshold/target/user_data_encryption.json'\nimport { requireCircuits } from './circuits'\nimport { bytesToHex, encodeAbiParameters, parseAbiParameters, numberToHex, getAddress } from 'viem/utils'\nimport { Hex } from 'viem'\n\n// Cached Barretenberg API instance — avoids re-initialising WASM + SRS on every proof.\nlet _bbApi: Barretenberg | null = null\nlet _bbApiInitPromise: Promise<Barretenberg> | null = null\n\nconst getBBApi = async (): Promise<Barretenberg> => {\n if (_bbApi) return _bbApi\n if (_bbApiInitPromise) return _bbApiInitPromise\n\n _bbApiInitPromise = (async () => {\n try {\n // Outside the browser, bb.js prefers its native Unix-socket backend, allows the bb\n // process only 5s to create the socket, and drops the timeout into an unhandled\n // rejection — callers then wait forever instead of failing. Pin Node to WASM. The\n // browser is unaffected: it already selects the (multi-threaded) worker backend.\n const backend = typeof window === 'undefined' ? { backend: BackendType.Wasm } : {}\n const api = await Barretenberg.new({ srsSize: 2 ** 21, ...backend })\n _bbApi = api\n return api\n } finally {\n _bbApiInitPromise = null\n }\n })()\n\n return _bbApiInitPromise\n}\n\n// Destroy the cached Barretenberg API and free its resources.\nexport const destroyBBApi = (): void => {\n _bbApiInitPromise = null\n if (_bbApi) {\n _bbApi.destroy()\n _bbApi = null\n }\n}\n\n/**\n * Encrypt a ballot and build every circuit input that does not depend on the signature.\n * Runs in a worker when available to avoid blocking the main thread.\n */\nexport const prepareCircuitInputs = async (inputs: PrepareBallotInputs): Promise<PreparedBallot> => {\n const preset = requireCircuits().preset\n\n if (typeof Worker !== 'undefined') {\n try {\n const worker = new Worker(new URL('./workers/generateCircuitInputs.worker.js', import.meta.url), { type: 'module' })\n return new Promise((resolve, reject) => {\n worker.onmessage = (e: MessageEvent<{ type: 'result'; prepared: PreparedBallot } | { type: 'error'; error: string }>) => {\n worker.terminate()\n if (e.data.type === 'result') {\n resolve(e.data.prepared)\n } else {\n reject(new Error(e.data.error))\n }\n }\n worker.onerror = (err) => {\n worker.terminate()\n reject(err)\n }\n worker.postMessage({ inputs, preset })\n })\n } catch {\n // Worker creation failed (e.g. bundler path resolution); fall back to main thread\n }\n }\n\n return prepareCircuitInputsImpl(inputs)\n}\n\n/**\n * Execute a circuit.\n * @param circuit - The circuit to execute.\n * @param inputs - The inputs to the circuit.\n * @returns The execute circuit result.\n */\nexport const executeCircuit = async (circuit: CompiledCircuit, inputs: any): Promise<{ witness: Uint8Array; returnValue: any }> => {\n const noir = new Noir(circuit as CompiledCircuit)\n\n return noir.execute(inputs)\n}\n\n/**\n * Generate a proof for the CRISP circuit given the circuit inputs.\n * @param circuitInputs - Inputs used in both the CRISP and GRECO circuits.\n * @returns The proof.\n */\nexport const generateProof = async (circuitInputs: any, censusMode: CensusVariant = 'merkle') => {\n const api = await getBBApi()\n\n const circuits = requireCircuits()\n const ballotCircuit = censusMode === 'onchain' ? circuits.crispOnchain : circuits.crisp\n const foldCircuitForMode = censusMode === 'onchain' ? foldOnchainCircuit : foldCircuit\n\n const { witness: userDataEncryptionCt0Witness } = await executeCircuit(circuits.userDataEncryptionCt0 as CompiledCircuit, {\n pk0is: circuitInputs.pk0is,\n ct0is: circuitInputs.ct0is,\n u: circuitInputs.u,\n e0: circuitInputs.e0,\n e0is: circuitInputs.e0is,\n e0_quotients: circuitInputs.e0_quotients,\n k1: circuitInputs.k1,\n r1is: circuitInputs.r1is,\n r2is: circuitInputs.r2is,\n })\n const { witness: userDataEncryptionCt1Witness } = await executeCircuit(circuits.userDataEncryptionCt1 as CompiledCircuit, {\n pk1is: circuitInputs.pk1is,\n ct1is: circuitInputs.ct1is,\n u: circuitInputs.u,\n e1: circuitInputs.e1,\n p1is: circuitInputs.p1is,\n p2is: circuitInputs.p2is,\n })\n // The two stacks share every input except how eligibility reaches the circuit: a census round\n // proves a Merkle path, an on-chain round takes the voting power the contract read.\n const eligibilityInputs =\n censusMode === 'onchain'\n ? { voting_power: circuitInputs.voting_power }\n : {\n merkle_root: circuitInputs.merkle_root,\n balance: circuitInputs.balance,\n merkle_proof_length: circuitInputs.merkle_proof_length,\n merkle_proof_indices: circuitInputs.merkle_proof_indices,\n merkle_proof_siblings: circuitInputs.merkle_proof_siblings,\n }\n\n const { witness: crispWitness, returnValue: crispReturnValue } = await executeCircuit(ballotCircuit as CompiledCircuit, {\n prev_ct0is: circuitInputs.prev_ct0is,\n prev_ct1is: circuitInputs.prev_ct1is,\n prev_ct_commitment: circuitInputs.prev_ct_commitment,\n sum_ct0is: circuitInputs.sum_ct0is,\n sum_ct1is: circuitInputs.sum_ct1is,\n sum_r0is: circuitInputs.sum_r0is,\n sum_r1is: circuitInputs.sum_r1is,\n ct0is: circuitInputs.ct0is,\n ct1is: circuitInputs.ct1is,\n k1: circuitInputs.k1,\n public_key_x: circuitInputs.public_key_x,\n public_key_y: circuitInputs.public_key_y,\n signature: circuitInputs.signature,\n digest_hi: circuitInputs.digest_hi,\n digest_lo: circuitInputs.digest_lo,\n slot_address: circuitInputs.slot_address,\n ...eligibilityInputs,\n is_first_vote: circuitInputs.is_first_vote,\n is_mask_vote: circuitInputs.is_mask_vote,\n num_options: circuitInputs.num_options,\n })\n\n const userDataEncryptionCt0Backend = new UltraHonkBackend((circuits.userDataEncryptionCt0 as CompiledCircuit).bytecode, api)\n const userDataEncryptionCt1Backend = new UltraHonkBackend((circuits.userDataEncryptionCt1 as CompiledCircuit).bytecode, api)\n const userDataEncryptionBackend = new UltraHonkBackend((userDataEncryptionCircuit as CompiledCircuit).bytecode, api)\n const crispBackend = new UltraHonkBackend((ballotCircuit as CompiledCircuit).bytecode, api)\n const foldBackend = new UltraHonkBackend((foldCircuitForMode as CompiledCircuit).bytecode, api)\n\n const { proof: userDataEncryptionCt0Proof, publicInputs: userDataEncryptionCt0PublicInputs } =\n await userDataEncryptionCt0Backend.generateProof(userDataEncryptionCt0Witness, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n const { proof: userDataEncryptionCt1Proof, publicInputs: userDataEncryptionCt1PublicInputs } =\n await userDataEncryptionCt1Backend.generateProof(userDataEncryptionCt1Witness, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n const { proof: crispProof, publicInputs: crispPublicInputs } = await crispBackend.generateProof(crispWitness, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n\n const userDataEncryptionCt0Artifacts = await userDataEncryptionCt0Backend.generateRecursiveProofArtifacts(\n userDataEncryptionCt0Proof,\n userDataEncryptionCt0PublicInputs.length,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n const userDataEncryptionCt1Artifacts = await userDataEncryptionCt1Backend.generateRecursiveProofArtifacts(\n userDataEncryptionCt1Proof,\n userDataEncryptionCt1PublicInputs.length,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n const crispArtifacts = await crispBackend.generateRecursiveProofArtifacts(crispProof, crispPublicInputs.length, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n\n const { witness: userDataEncryptionWitness } = await executeCircuit(userDataEncryptionCircuit as CompiledCircuit, {\n ct0_verification_key: userDataEncryptionCt0Artifacts.vkAsFields,\n ct0_proof: proofToFields(userDataEncryptionCt0Proof),\n ct0_public_inputs: userDataEncryptionCt0PublicInputs,\n ct0_key_hash: userDataEncryptionCt0Artifacts.vkHash,\n ct1_verification_key: userDataEncryptionCt1Artifacts.vkAsFields,\n ct1_proof: proofToFields(userDataEncryptionCt1Proof),\n ct1_public_inputs: userDataEncryptionCt1PublicInputs,\n ct1_key_hash: userDataEncryptionCt1Artifacts.vkHash,\n })\n\n const { proof: userDataEncryptionProof, publicInputs: userDataEncryptionPublicInputs } = await userDataEncryptionBackend.generateProof(\n userDataEncryptionWitness,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n const userDataEncryptionArtifacts = await userDataEncryptionBackend.generateRecursiveProofArtifacts(\n userDataEncryptionProof,\n userDataEncryptionPublicInputs.length,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n\n const { witness: foldWitness } = await executeCircuit(foldCircuitForMode as CompiledCircuit, {\n user_data_encryption_verification_key: userDataEncryptionArtifacts.vkAsFields,\n user_data_encryption_proof: proofToFields(userDataEncryptionProof),\n user_data_encryption_public_inputs: userDataEncryptionPublicInputs,\n user_data_encryption_key_hash: userDataEncryptionArtifacts.vkHash,\n crisp_verification_key: crispArtifacts.vkAsFields,\n crisp_proof: proofToFields(crispProof),\n crisp_key_hash: crispArtifacts.vkHash,\n prev_ct_commitment: circuitInputs.prev_ct_commitment,\n digest_hi: circuitInputs.digest_hi,\n digest_lo: circuitInputs.digest_lo,\n slot_address: circuitInputs.slot_address,\n // Position 4 of the public inputs, and the only slot the two stacks disagree on.\n ...(censusMode === 'onchain' ? { voting_power: circuitInputs.voting_power } : { merkle_root: circuitInputs.merkle_root }),\n is_first_vote: circuitInputs.is_first_vote,\n num_options: circuitInputs.num_options,\n final_ct_commitment: crispReturnValue[0].toString(),\n ct_commitment: crispReturnValue[1].toString(),\n k1_commitment: crispReturnValue[2].toString(),\n })\n\n const proof = await foldBackend.generateProof(foldWitness, { verifierTarget: 'evm' })\n\n return proof\n}\n\n/**\n * Validate a vote.\n * @param vote - The vote to validate.\n * @param balance - The balance of the voter.\n */\nexport const validateVote = (vote: Vote, balance: bigint): void => {\n const numChoices = vote.length\n const maxValue = getMaxVoteValue(numChoices)\n\n for (let i = 0; i < vote.length; i++) {\n if (vote[i] < 0) {\n throw new Error(`Invalid vote: choice ${i} is negative`)\n }\n if (vote[i] > maxValue) {\n throw new Error(`Invalid vote: choice ${i} exceeds maximum encodable value`)\n }\n }\n\n if (numChoices === 2) {\n // Binary: mutually exclusive\n const nonZeroCount = vote.filter((v) => v > 0).length\n if (nonZeroCount > 1) {\n throw new Error('Invalid vote: for 2 options, only one choice can be non-zero')\n }\n const votedAmount = vote.find((v) => v > 0) ?? 0\n if (votedAmount > balance) {\n throw new Error('Invalid vote: vote exceeds balance')\n }\n } else {\n // 3+ options: split allowed, total capped\n const total = vote.reduce((sum, v) => sum + v, 0)\n if (total > balance) {\n throw new Error(`Invalid vote: total votes (${total}) exceed balance (${balance})`)\n }\n }\n}\n\n/**\n * Phase one: encrypt a ballot, before the voter signs anything.\n *\n * A ballot must be encrypted before it can be signed, because the digest binds the ciphertext.\n * Take `ctCommitment` from the result, read the digest from `CRISPProgram.ballotDigest`, have the\n * voter sign it, then call {@link finishBallotProof}.\n *\n * @param inputs - The ballot to encrypt.\n * @returns The prepared ballot.\n */\nexport const prepareBallot = async (inputs: PrepareBallotInputs): Promise<PreparedBallot> => {\n if (!inputs.isMaskVote) {\n validateVote(inputs.vote, inputs.censusMode === 'onchain' ? inputs.votingPower : inputs.balance)\n }\n\n // Through the worker wrapper, not the impl: BFV encryption is the heaviest step in the flow and\n // running it on the main thread freezes the browser for its duration. The wrapper falls back to\n // the main thread by itself where `Worker` is unavailable.\n return prepareCircuitInputs(inputs)\n}\n\n/**\n * Phase two: prove a prepared ballot, given the signature over its digest.\n *\n * Get the digest from `CRISPProgram.ballotDigest(e3Id, slot, prepared.ctCommitment)` and have the\n * voter sign it. Reading it from the contract rather than rebuilding the EIP-712 struct here means\n * there is only one implementation of the domain to keep correct.\n *\n * @param prepared The output of `prepareBallot`.\n * @param digest The ballot digest.\n * @param signature The voter signature over that digest.\n * @returns The proof.\n */\nexport const finishBallotProof = async (prepared: PreparedBallot, digest: `0x${string}`, signature: `0x${string}`): Promise<ProofData> => {\n const circuitInputs = await attachSignatureImpl(prepared, digest, signature)\n\n return {\n ...(await generateProof(circuitInputs, prepared.censusMode)),\n encryptedVote: prepared.encryptedVote,\n parentIndexPlusOne: prepared.parentIndexPlusOne,\n }\n}\n\n/**\n * Phase two for a mask.\n *\n * A mask carries the same digest as a real vote, because `CRISPProgram.publishInput` computes it\n * for every input regardless of branch. Only the signature is a placeholder, and the circuit does\n * not check it on the mask branch. Passing a real digest here is what keeps a mask and a vote\n * indistinguishable in the published public inputs.\n *\n * @param prepared The output of `prepareBallot` with `isMaskVote: true`.\n * @param digest The ballot digest, from the same contract call a real vote would use.\n * @returns The proof.\n */\nexport const finishMaskProof = async (prepared: PreparedBallot, digest: `0x${string}`): Promise<ProofData> => {\n return finishBallotProof(prepared, digest, MASK_SIGNATURE)\n}\n\n/**\n * Locally verify a Noir proof.\n * @param proof - The proof to verify.\n * @returns True if the proof is valid, false otherwise.\n */\nexport const verifyProof = async (proof: ProofData, censusMode: CensusVariant = 'merkle'): Promise<boolean> => {\n const api = await getBBApi()\n const circuit = censusMode === 'onchain' ? foldOnchainCircuit : foldCircuit\n const foldBackend = new UltraHonkBackend(circuit.bytecode, api)\n\n return foldBackend.verifyProof(proof, { verifierTarget: 'evm' })\n}\n\n/**\n * Encode the proof data into a format that can be used by the CRISP program in Solidity\n * to validate the proof.\n * @param proof The proof data.\n * @returns The encoded proof data as a hex string.\n */\nexport const encodeSolidityProof = ({ publicInputs, proof, encryptedVote, parentIndexPlusOne }: ProofData): Hex => {\n // Indices follow the fold circuit public inputs:\n // 0 prev_ct_commitment, 1 digest_hi, 2 digest_lo, 3 slot_address,\n // 4 merkle_root | voting_power, 5 is_first_vote, 6 num_options,\n // 7 final_ct_commitment, 8 committee public key\n const slotAddress = getAddress(numberToHex(BigInt(publicInputs[3]), { size: 20 }))\n const encryptedVoteCommitment = publicInputs[7] as `0x${string}`\n\n return encodeAbiParameters(parseAbiParameters('bytes, address, bytes32, bytes, uint40'), [\n bytesToHex(proof),\n slotAddress,\n encryptedVoteCommitment,\n bytesToHex(encryptedVote),\n parentIndexPlusOne,\n ])\n}\n","{\"noir_version\":\"1.0.0-beta.26+40d6574f851d926f93e0c3a271bac3e6e82ac905\",\"hash\":\"12034458935140291205\",\"abi\":{\"parameters\":[{\"name\":\"user_data_encryption_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":5,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"crisp_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"prev_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_hi\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_lo\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"slot_address\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"merkle_root\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"is_first_vote\",\"type\":{\"kind\":\"boolean\"},\"visibility\":\"public\"},{\"name\":\"num_options\",\"type\":{\"kind\":\"integer\",\"sign\":\"unsigned\",\"width\":32},\"visibility\":\"public\"},{\"name\":\"final_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"k1_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"}],\"return_type\":{\"abi_type\":{\"kind\":\"field\"},\"visibility\":\"public\"},\"error_types\":{}},\"bytecode\":\"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\",\"debug_symbols\":\"tZbdjqMwDIXfJddcxM6P43mV1aqiLR0hIVoxMNKqmnff0CEBKiWaTbVXbgn55HPsmNzFuTlO74e2v1w/xNuvuzgObde174fueqrH9tr7p/evSoS/h3FoGv9IbNb9rls9NP0o3vqp6yrxWXfT46WPW90/4lgPflVWounPPnrgpe2a+ddXte6W6a1gNS27wWkdAQZ3BMgRDAYCsVoJakfANEEpcgtBaQuRgPhTFQgYVCBoSqnI+eBMcBGRbIpgXvbB/lcfNEQftNEFPqBitRJMCcGwDQSrVBGBcCUUqSAVq0mWigirD07JEgLLqILRJU+WzrQUMAUvASWsQhztIZm+JKKghJxWSUSmMUlykEIg16ZwvEdQGmFB8oKw2xPK9GOEcbEkhjdZPCM4jWCwwU8G5hQCM2VVHA+plrBmAfQPXsQsLEpd4sUOAWkvckUFFftiW5GnomKmP8nq2BfWJIWgeb0i9uWKZIU4s54RxlQW2dNuIMxuKW3BvFASVSSQLZo48RvmCUVTj5WOBKeLVHD0AZ6m3m//rz61w+4OJNC/WQnlna+E9pZXwsyTrxJ2/phXgr6Dm2dyJfg7gJyT9RGWiEtUcwo+6iWaJXqYmuv6WQ9tfeya5fp1mfrT5jY2/rmFlXBfuw3XU3OehmbO+rHmdfwF\",\"file_map\":{\"17\":{\"source\":\"// Exposed only for usage in `std::meta`\\npub(crate) mod poseidon2;\\n\\nuse crate::default::Default;\\nuse crate::embedded_curve_ops::{\\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\\n};\\nuse crate::meta::derive_via;\\nuse crate::static_assert;\\n\\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\\n\\n#[foreign(sha256_compression)]\\n// docs:start:sha256_compression\\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\\n// docs:end:sha256_compression\\n\\n#[foreign(keccakf1600)]\\n// docs:start:keccakf1600\\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\\n// docs:end:keccakf1600\\n\\n#[foreign(blake2s)]\\n// docs:start:blake2s\\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake2s\\n{}\\n\\n// docs:start:blake3\\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake3\\n{\\n if crate::runtime::is_unconstrained() {\\n // Temporary measure while Barretenberg is main proving system.\\n // Please open an issue if you're working on another proving system and running into problems due to this.\\n crate::static_assert(\\n N <= 1024,\\n \\\"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\\\",\\n );\\n }\\n __blake3(input)\\n}\\n\\n#[foreign(blake3)]\\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\\n\\n// docs:start:pedersen_commitment\\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\\n // docs:end:pedersen_commitment\\n pedersen_commitment_with_separator(input, 0)\\n}\\n\\n#[inline_always]\\npub fn pedersen_commitment_with_separator<let N: u32>(\\n input: [Field; N],\\n separator: u32,\\n) -> EmbeddedCurvePoint {\\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\\n for i in 0..N {\\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\\n }\\n let generators = derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n multi_scalar_mul(generators, points)\\n}\\n\\n// docs:start:pedersen_hash\\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\\n// docs:end:pedersen_hash\\n{\\n pedersen_hash_with_separator(input, 0)\\n}\\n\\n#[no_predicates]\\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\\n let mut generators: [EmbeddedCurvePoint; N + 1] =\\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\\n crate::assert_constant(separator);\\n let domain_generators: [EmbeddedCurvePoint; N] =\\n derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n\\n for i in 0..N {\\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\\n generators[i] = domain_generators[i];\\n }\\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\\n\\n let length_generator: [EmbeddedCurvePoint; 1] =\\n derive_generators(\\\"pedersen_hash_length\\\".as_bytes(), 0);\\n generators[N] = length_generator[0];\\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\\n}\\n\\n#[field(bn254)]\\n#[inline_always]\\npub fn derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {\\n crate::assert_constant(domain_separator_bytes);\\n crate::assert_constant(starting_index);\\n __derive_generators(domain_separator_bytes, starting_index)\\n}\\n\\n#[builtin(derive_pedersen_generators)]\\n#[field(bn254)]\\nfn __derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {}\\n\\npub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {\\n static_assert(\\n N == POSEIDON2_CONFIG_STATE_SIZE,\\n f\\\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\\\",\\n );\\n poseidon2_permutation_internal(input)\\n}\\n\\n#[foreign(poseidon2_permutation)]\\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\\n\\n#[foreign(poseidon2_config_state_size)]\\ncomptime fn poseidon2_config_state_size() -> u32 {}\\n\\n// Generic hashing support.\\n// Partially ported and impacted by rust.\\n\\n// Hash trait shall be implemented per type.\\n#[derive_via(derive_hash)]\\npub trait Hash {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher;\\n}\\n\\n// docs:start:derive_hash\\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\\n let name = quote { $crate::hash::Hash };\\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\\n let for_each_field = |name| quote { _self.$name.hash(_state); };\\n crate::meta::make_trait_impl(\\n s,\\n name,\\n signature,\\n for_each_field,\\n quote {},\\n |fields| fields,\\n )\\n}\\n// docs:end:derive_hash\\n\\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\\n// TODO: consider making the types generic here ([u8], [Field], etc.)\\npub trait Hasher {\\n fn finish(self) -> Field;\\n\\n /// Returns the hash value without consuming the hasher.\\n /// Override this for more efficient implementations that avoid copying.\\n /// TODO: deprecate finish() and replace it\\n fn finish_ref(&self) -> Field {\\n (*self).finish()\\n }\\n\\n fn write(&mut self, input: Field);\\n}\\n\\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\\npub trait BuildHasher {\\n type H: Hasher;\\n\\n fn build_hasher(self) -> H;\\n}\\n\\npub struct BuildHasherDefault<H>;\\n\\nimpl<H> BuildHasher for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n type H = H;\\n\\n fn build_hasher(_self: Self) -> H {\\n H::default()\\n }\\n}\\n\\nimpl<H> Default for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n fn default() -> Self {\\n BuildHasherDefault {}\\n }\\n}\\n\\nimpl Hash for Field {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self);\\n }\\n}\\n\\nimpl Hash for u8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u128 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for i8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u8 as Field);\\n }\\n}\\n\\nimpl Hash for i16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u16 as Field);\\n }\\n}\\n\\nimpl Hash for i32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u32 as Field);\\n }\\n}\\n\\nimpl Hash for i64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u64 as Field);\\n }\\n}\\n\\nimpl Hash for bool {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for () {\\n fn hash<H>(_self: Self, _state: &mut H)\\n where\\n H: Hasher,\\n {}\\n}\\n\\nimpl<T, let N: u32> Hash for [T; N]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<T> Hash for [T]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.len().hash(state);\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<A> Hash for (A,)\\nwhere\\n A: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n }\\n}\\n\\nimpl<A, B> Hash for (A, B)\\nwhere\\n A: Hash,\\n B: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n }\\n}\\n\\nimpl<A, B, C> Hash for (A, B, C)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D> Hash for (A, B, C, D)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F> Hash for (A, B, C, D, E, F)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G> Hash for (A, B, C, D, E, F, G)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_> Hash for (A, B, C, D, E, F, G, H_)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I> Hash for (A, B, C, D, E, F, G, H_, I)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J> Hash for (A, B, C, D, E, F, G, H_, I, J)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K> Hash for (A, B, C, D, E, F, G, H_, I, J, K)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K, L> Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n L: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n self.11.hash(state);\\n }\\n}\\n\\n// Some test vectors for Pedersen hash and Pedersen Commitment.\\n// They have been generated using the same functions so the tests are for now useless\\n// but they will be useful when we switch to Noir implementation.\\n#[test]\\nfn assert_pedersen() {\\n assert_eq(\\n pedersen_hash_with_separator([1], 1),\\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1], 1),\\n EmbeddedCurvePoint {\\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\\n },\\n );\\n\\n assert_eq(\\n pedersen_hash_with_separator([1, 2], 2),\\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2], 2),\\n EmbeddedCurvePoint {\\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3], 3),\\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3], 3),\\n EmbeddedCurvePoint {\\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\\n EmbeddedCurvePoint {\\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\\n EmbeddedCurvePoint {\\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\\n EmbeddedCurvePoint {\\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n EmbeddedCurvePoint {\\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n EmbeddedCurvePoint {\\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n EmbeddedCurvePoint {\\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n EmbeddedCurvePoint {\\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\\n },\\n );\\n}\\n\",\"path\":\"std/hash/mod.nr\",\"function_locations\":[{\"start\":572,\"name\":\"sha256_compression\"},{\"start\":707,\"name\":\"keccakf1600\"},{\"start\":852,\"name\":\"blake2s\"},{\"start\":950,\"name\":\"blake3\"},{\"start\":1437,\"name\":\"__blake3\"},{\"start\":1555,\"name\":\"pedersen_commitment\"},{\"start\":1784,\"name\":\"pedersen_commitment_with_separator\"},{\"start\":2188,\"name\":\"pedersen_hash\"},{\"start\":2345,\"name\":\"pedersen_hash_with_separator\"},{\"start\":3339,\"name\":\"derive_generators\"},{\"start\":3698,\"name\":\"__derive_generators\"},{\"start\":3776,\"name\":\"poseidon2_permutation\"},{\"start\":4132,\"name\":\"poseidon2_permutation_internal\"},{\"start\":4225,\"name\":\"poseidon2_config_state_size\"},{\"start\":4536,\"name\":\"derive_hash\"},{\"start\":5327,\"name\":\"Hasher::finish_ref\"},{\"start\":5761,\"name\":\"<impl BuildHasher for BuildHasherDefault<H>>::build_hasher\"},{\"start\":5893,\"name\":\"<impl Default for BuildHasherDefault<H>>::default\"},{\"start\":6025,\"name\":\"<impl Hash for Field>::hash\"},{\"start\":6155,\"name\":\"<impl Hash for u8>::hash\"},{\"start\":6295,\"name\":\"<impl Hash for u16>::hash\"},{\"start\":6435,\"name\":\"<impl Hash for u32>::hash\"},{\"start\":6575,\"name\":\"<impl Hash for u64>::hash\"},{\"start\":6716,\"name\":\"<impl Hash for u128>::hash\"},{\"start\":6855,\"name\":\"<impl Hash for i8>::hash\"},{\"start\":7001,\"name\":\"<impl Hash for i16>::hash\"},{\"start\":7148,\"name\":\"<impl Hash for i32>::hash\"},{\"start\":7295,\"name\":\"<impl Hash for i64>::hash\"},{\"start\":7443,\"name\":\"<impl Hash for bool>::hash\"},{\"start\":7590,\"name\":\"<impl Hash for ()>::hash\"},{\"start\":7722,\"name\":\"<impl Hash for [T; N]>::hash\"},{\"start\":7911,\"name\":\"<impl Hash for [T]>::hash\"},{\"start\":8133,\"name\":\"<impl Hash for (A,)>::hash\"},{\"start\":8302,\"name\":\"<impl Hash for (A, B)>::hash\"},{\"start\":8518,\"name\":\"<impl Hash for (A, B, C)>::hash\"},{\"start\":8781,\"name\":\"<impl Hash for (A, B, C, D)>::hash\"},{\"start\":9091,\"name\":\"<impl Hash for (A, B, C, D, E)>::hash\"},{\"start\":9448,\"name\":\"<impl Hash for (A, B, C, D, E, F)>::hash\"},{\"start\":9852,\"name\":\"<impl Hash for (A, B, C, D, E, F, G)>::hash\"},{\"start\":10306,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_)>::hash\"},{\"start\":10807,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I)>::hash\"},{\"start\":11355,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J)>::hash\"},{\"start\":11950,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K)>::hash\"},{\"start\":12593,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)>::hash\"},{\"start\":13187,\"name\":\"assert_pedersen\"}]},\"22\":{\"source\":\"pub mod hash;\\npub mod aes128;\\npub mod array;\\npub mod vector;\\npub mod ecdsa_secp256k1;\\npub mod ecdsa_secp256r1;\\npub mod embedded_curve_ops;\\npub mod field;\\npub mod collections;\\npub mod compat;\\npub mod convert;\\npub mod option;\\npub mod string;\\npub mod test;\\npub mod cmp;\\npub mod ops;\\npub mod default;\\npub mod prelude;\\npub mod runtime;\\npub mod meta;\\npub mod append;\\npub mod mem;\\npub mod panic;\\npub mod hint;\\n\\nmod integer;\\nmod primitive_docs;\\nmod internal;\\n\\n// Oracle calls are required to be wrapped in an unconstrained function\\n// Thus, the only argument to the `println` oracle is expected to always be an ident\\n#[oracle(print)]\\nunconstrained fn print_oracle<T>(with_newline: bool, input: T) {}\\n\\nunconstrained fn print_unconstrained<T>(with_newline: bool, input: T) {\\n print_oracle(with_newline, input);\\n}\\n\\n/// Print the given input to stdout followed by a newline\\npub fn println<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(true, input);\\n }\\n}\\n\\n/// Print the given input to stdout\\npub fn print<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(false, input);\\n }\\n}\\n\\n/// Asserts the validity of the provided proof and public inputs against the provided verification key and hash.\\n///\\n/// The ACVM cannot determine whether the provided proof is valid during execution as this requires knowledge of\\n/// the backend against which the program is being proven. However if an invalid proof if submitted, the program may\\n/// fail to prove or the backend may generate a proof which will subsequently fail to verify.\\n///\\n/// # Important Note\\n///\\n/// If you are not developing your own backend such as [Barretenberg](https://github.com/AztecProtocol/barretenberg)\\n/// you probably shouldn't need to interact with this function directly. It's easier and safer to use a verification\\n/// library which is published by the developers of the backend which will document or enforce any safety requirements.\\n///\\n/// If you use this directly, you're liable to introduce underconstrainedness bugs and *your circuit will be insecure*.\\n///\\n/// # Arguments\\n/// - verification_key: The verification key of the circuit to be verified.\\n/// - proof: The proof to be verified.\\n/// - public_inputs: The public inputs associated with `proof`\\n/// - key_hash: The hash of `verification_key` of the form expected by the backend.\\n/// - proof_type: An identifier for the proving scheme used to generate the proof to be verified. This allows\\n/// for a single backend to support verifying multiple proving schemes.\\n///\\n/// # Constraining `key_hash`\\n///\\n/// The Noir compiler does not by itself constrain that `key_hash` is a valid hash of `verification_key`.\\n/// This is because different backends may differ in how they hash their verification keys.\\n/// It is then the responsibility of either the noir developer (by explicitly hashing the verification key\\n/// in the correct manner) or by the proving system itself internally asserting the correctness of `key_hash`.\\npub fn verify_proof_with_type<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {\\n if !crate::runtime::is_unconstrained() {\\n crate::assert_constant(proof_type);\\n }\\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\\n}\\n\\n#[foreign(recursive_aggregation)]\\nfn verify_proof_internal<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {}\\n\\n/// Asserts that the given value is known at compile-time.\\n/// Useful for debugging for-loop bounds.\\n#[builtin(assert_constant)]\\npub fn assert_constant<T>(x: T) {}\\n\\n/// Asserts that the given value is both true and known at compile-time.\\n/// The message can be a string, a format string, or any value, as long as it is known at compile-time\\n#[builtin(static_assert)]\\npub fn static_assert<T>(predicate: bool, message: T) {}\\n\\n/// Force a field value to be a witness instead of a constant in the compiled output.\\n/// This is often only useful for debugging compiler optimizations.\\n///\\n/// This has no effect in unconstrained or comptime code.\\n#[builtin(as_witness)]\\npub fn as_witness(x: Field) {}\\n\",\"path\":\"std/lib.nr\",\"function_locations\":[{\"start\":689,\"name\":\"print_oracle\"},{\"start\":763,\"name\":\"print_unconstrained\"},{\"start\":893,\"name\":\"println\"},{\"start\":1076,\"name\":\"print\"},{\"start\":3277,\"name\":\"verify_proof_with_type\"},{\"start\":3694,\"name\":\"verify_proof_internal\"},{\"start\":3859,\"name\":\"assert_constant\"},{\"start\":4118,\"name\":\"static_assert\"},{\"start\":4389,\"name\":\"as_witness\"}]},\"52\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse bb_proof_verification::{UltraHonkProof, UltraHonkVerificationKey, verify_honk_proof_non_zk};\\nuse interfold_lib::math::commitments::compute_vk_hash;\\n\\n/// Binds the four inner `vk_hash` witnesses. Regenerate with `pnpm compute:vk-hash` in\\n/// `examples/CRISP` after changing ct0 / ct1 / user_data_encryption / crisp (or the lib preset).\\n/// Insecure: `lib::configs::default` uses `insecure::*`; secure: uses `secure::*`.\\npub global CRISP_FOLD_EXPECTED_KEY_HASH_INSECURE: Field =\\n 0x0cfedc11fbb1437ca55ba6ae31fe3adb29eefba7a62ea8257d427ce1e1e32e6f;\\npub global CRISP_FOLD_EXPECTED_KEY_HASH_SECURE: Field =\\n 0x133970fec6679c0be03d6bf71981d9bdb9135f919b1c8c3fcc24aee68acb12ad;\\n\\nfn main(\\n // User Data Encryption Section.\\n user_data_encryption_verification_key: UltraHonkVerificationKey,\\n user_data_encryption_proof: UltraHonkProof,\\n user_data_encryption_public_inputs: [Field; 5], // ct0_key_hash, ct1_key_hash, pk_commitment, ct_commitment, k1_commitment\\n user_data_encryption_key_hash: Field,\\n // Crisp Section.\\n crisp_verification_key: UltraHonkVerificationKey,\\n crisp_proof: UltraHonkProof,\\n crisp_key_hash: Field,\\n prev_ct_commitment: pub Field,\\n digest_hi: pub Field,\\n digest_lo: pub Field,\\n slot_address: pub Field,\\n merkle_root: pub Field,\\n is_first_vote: pub bool,\\n num_options: pub u32,\\n final_ct_commitment: pub Field,\\n ct_commitment: Field,\\n k1_commitment: Field,\\n) -> pub Field {\\n verify_honk_proof_non_zk(\\n user_data_encryption_verification_key,\\n user_data_encryption_proof,\\n user_data_encryption_public_inputs,\\n user_data_encryption_key_hash,\\n );\\n verify_honk_proof_non_zk(\\n crisp_verification_key,\\n crisp_proof,\\n [\\n prev_ct_commitment,\\n digest_hi,\\n digest_lo,\\n slot_address,\\n merkle_root,\\n if is_first_vote { 1 } else { 0 },\\n num_options as Field,\\n final_ct_commitment,\\n ct_commitment,\\n k1_commitment,\\n ],\\n crisp_key_hash,\\n );\\n\\n // Verify that the ct_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(ct_commitment == user_data_encryption_public_inputs[3]);\\n\\n // Verify that the k1_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(k1_commitment == user_data_encryption_public_inputs[4]);\\n\\n let vk_hashes = [\\n user_data_encryption_key_hash,\\n crisp_key_hash,\\n user_data_encryption_public_inputs[0], // ct0_key_hash\\n user_data_encryption_public_inputs[1], // ct1_key_hash\\n ]\\n .as_vector();\\n\\n let chain_key_hash = compute_vk_hash(vk_hashes);\\n assert(\\n (chain_key_hash == CRISP_FOLD_EXPECTED_KEY_HASH_INSECURE)\\n | (chain_key_hash == CRISP_FOLD_EXPECTED_KEY_HASH_SECURE),\\n );\\n\\n user_data_encryption_public_inputs[2]\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/examples/CRISP/circuits/bin/fold/src/main.nr\",\"function_locations\":[{\"start\":1641,\"name\":\"main\"}]},\"53\":{\"source\":\"// Constants for UltraHonk recursive verifier inputs\\npub global PROOF_TYPE_HONK: u32 = 0; // identifier for UltraHonk verfier\\npub global RECURSIVE_PROOF_LENGTH: u32 = 410;\\npub global ULTRA_VK_LENGTH_IN_FIELDS: u32 = 115;\\n\\npub type UltraHonkProof = [Field; RECURSIVE_PROOF_LENGTH];\\npub type UltraHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\n// Constants for Rollup-UltraHonk recursive verifier inputs (N.B. this is equivalent to UH plus IPA claim and proof)\\npub global PROOF_TYPE_ROLLUP_HONK: u32 = 4; // identifier for rollup-UltraHonk verfier\\npub global PROOF_TYPE_ROOT_ROLLUP_HONK: u32 = 5; // identifier for root-rollup-UltraHonk verfier (closes the IPA accumulator)\\npub global IPA_CLAIM_SIZE: u32 = 6;\\npub global IPA_PROOF_LENGTH: u32 = 64;\\npub global RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 =\\n RECURSIVE_PROOF_LENGTH + IPA_CLAIM_SIZE + IPA_PROOF_LENGTH;\\n\\npub type RollupHonkProof = [Field; RECURSIVE_ROLLUP_HONK_PROOF_LENGTH];\\npub type RollupHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\npub global PROOF_TYPE_HONK_ZK: u32 = 6; // identifier for UltraHonk ZK verfier\\npub global RECURSIVE_ZK_PROOF_LENGTH: u32 = 450 + 8;\\n\\npub type UltraHonkZKProof = [Field; RECURSIVE_ZK_PROOF_LENGTH];\\n\\n// Verifies a non-zero-knowledge UltraHonk proof.\\n//\\n// Represents standard UltraHonk recursive verification for proofs that do not hide the witness.\\n// Use this only in situations where zero-knowledge is not required.\\npub fn verify_honk_proof_non_zk<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof with IPA (Inner Product Argument).\\n//\\n// This variant includes an IPA claim and proof appended to the standard UltraHonk proof,\\n// used to amortize IPA recursive verification costs in rollup circuits.\\npub fn verify_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof and closes the IPA accumulator in-circuit.\\n//\\n// Use this at the root of a rollup aggregation tree. The inner proof has the same RollupHonk shape\\n// as `verify_rolluphonk_proof`, but instead of propagating an accumulated IPA claim out as a public\\n// input, this variant performs a full native IPA verification inside the circuit. The outer circuit\\n// should therefore be proved as a standard (non-rollup) UltraHonk circuit, producing a proof\\n// suitable for verification by `verify_honk_proof` / `verify_honk_proof_non_zk`.\\n//\\n// When two RollupHonk inputs are verified this way in one circuit, their two IPA claims are first\\n// accumulated into one, then the accumulated claim is fully verified.\\npub fn verify_root_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROOT_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a zero-knowledge UltraHonk proof.\\n//\\n// This verifier is for UltraHonk proofs constructed with zero-knowledge, which hide the witness\\n// values from the verifier.\\n// Note: We intentionally choose the generic name \\\"verify_honk_proof\\\" for this function, as we\\n// want ZK to be the default unless the user explicitly opts out.\\npub fn verify_honk_proof<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkZKProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK_ZK,\\n );\\n}\\n\",\"path\":\"/home/ace/nargo/github.com/AztecProtocol/aztec-packages/v5.1.0/barretenberg/noir/bb_proof_verification/src/lib.nr\",\"function_locations\":[{\"start\":1646,\"name\":\"verify_honk_proof_non_zk\"},{\"start\":2262,\"name\":\"verify_rolluphonk_proof\"},{\"start\":3386,\"name\":\"verify_root_rolluphonk_proof\"},{\"start\":4087,\"name\":\"verify_honk_proof\"}]},\"87\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse crate::math::helpers::{compute_safe, flatten};\\nuse crate::math::polynomial::Polynomial;\\n\\n/// DOMAIN SEPARATORS\\n\\n// Domain separator - \\\"PK\\\"\\npub global DS_PK: [u8; 64] = [\\n 0x50, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_GENERATION\\\"\\npub global DS_PK_GENERATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_COMPUTATION\\\"\\npub global DS_SHARE_COMPUTATION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_ENCRYPTION\\\"\\npub global DS_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_AGGREGATION\\\"\\npub global DS_PK_AGGREGATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CIPHERTEXT\\\"\\npub global DS_CIPHERTEXT: [u8; 64] = [\\n 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"AGGREGATED_SHARES\\\"\\npub global DS_AGGREGATED_SHARES: [u8; 64] = [\\n 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45,\\n 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"VK_HASH\\\"\\npub global DS_VK_HASH: [u8; 64] = [\\n 0x56, 0x4b, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"RECURSIVE_AGGREGATION\\\"\\npub global DS_RECURSIVE_AGGREGATION: [u8; 64] = [\\n 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47,\\n 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_PK_GENERATION\\\"\\npub global DS_CLG_PK_GENERATION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_ENCRYPTION\\\"\\npub global DS_CLG_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_USER_DATA_ENCRYPTION\\\"\\npub global DS_CLG_USER_DATA_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e,\\n 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_DECRYPTION\\\"\\npub global DS_CLG_SHARE_DECRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"THRESHOLD_DECRYPTION_SHARE\\\"\\npub global DS_THRESHOLD_DECRYPTION_SHARE: [u8; 64] = [\\n 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"USER_DATA_ENCRYPTION_COMMITMENT\\\"\\npub global DS_USER_DATA_ENCRYPTION_COMMITMENT: [u8; 64] = [\\n 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n/// WRAPPERS\\n\\npub fn compute_commitment(inputs: [Field], domain_separator: [u8; 64]) -> Field {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 1])[0]\\n}\\n\\npub fn compute_single_polynomial_commitment<let N: u32, let BIT: u32>(\\n polynomial: Polynomial<N>,\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT>([].as_vector(), polynomial);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_multiple_polynomial_commitment<let N: u32, let L: u32, let BIT: u32>(\\n polynomials: [Polynomial<N>; L],\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT>([].as_vector(), polynomials);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_challenge<let L: u32>(inputs: [Field], domain_separator: [u8; 64]) -> [Field] {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 2 * L])\\n}\\n\\npub fn single_polynomial_payload<let N: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n input: Polynomial<N>,\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, [input])\\n}\\n\\npub fn multiple_polynomial_payload<let N: u32, let L: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n inputs: [Polynomial<N>; L],\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, inputs)\\n}\\n\\n/// COMMITMENTS\\n\\npub fn compute_dkg_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let mut payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n payload = multiple_polynomial_payload::<N, L, BIT_PK>(payload, pk1);\\n\\n compute_commitment(payload, DS_PK)\\n}\\n\\npub fn compute_threshold_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n compute_commitment(payload, DS_PK_GENERATION)\\n}\\n\\npub fn compute_share_computation_sk_commitment<let N: u32, let BIT_SK: u32>(\\n sk: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_SK>([].as_vector(), sk);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_computation_e_sm_commitment<let N: u32, let L: u32, let BIT_E_SM: u32>(\\n e_sm: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_E_SM>([].as_vector(), e_sm);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_encryption_commitment_from_message<let N: u32, let BIT_MSG: u32>(\\n message: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_MSG>([].as_vector(), message);\\n compute_commitment(payload, DS_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_aggregated_shares_commitment<let N: u32, let L: u32, let BIT_MSG: u32>(\\n agg_shares: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_MSG>([].as_vector(), agg_shares);\\n compute_commitment(payload, DS_AGGREGATED_SHARES)\\n}\\n\\n/// Commitment to a threshold decryption share: all CRT limbs, first `K` coefficients per limb\\n/// (same layout as `Polynomial<K>` in decrypted_shares_aggregation).\\n///\\n/// `NATIVE_BIT_WIDTH` must cover native coefficients in \\\\([0, q_l)\\\\) per limb (not centered `d` bounds).\\npub fn compute_threshold_decryption_share_commitment<let K: u32, let L: u32, let NATIVE_BIT_WIDTH: u32>(\\n d_share_limbs: [Polynomial<K>; L],\\n) -> Field {\\n let payload =\\n multiple_polynomial_payload::<K, L, NATIVE_BIT_WIDTH>([].as_vector(), d_share_limbs);\\n compute_commitment(payload, DS_THRESHOLD_DECRYPTION_SHARE)\\n}\\n\\npub fn compute_pk_aggregation_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_pk0 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk0, DS_PK_AGGREGATION);\\n let commit_pk1 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk1, DS_PK_AGGREGATION);\\n\\n let inputs = [commit_pk0, commit_pk1].as_vector();\\n\\n compute_commitment(inputs, DS_PK_AGGREGATION)\\n}\\n\\npub fn compute_recursive_aggregation_commitment(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_RECURSIVE_AGGREGATION)\\n}\\n\\npub fn compute_vk_hash(vk_hashes: [Field]) -> Field {\\n compute_commitment(vk_hashes, DS_VK_HASH)\\n}\\n\\npub fn compute_ciphertext_commitment<let N: u32, let L: u32, let BIT_CT: u32>(\\n ct0: [Polynomial<N>; L],\\n ct1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_ct0 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct0, DS_CIPHERTEXT);\\n let commit_ct1 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct1, DS_CIPHERTEXT);\\n\\n let inputs = [commit_ct0, commit_ct1].as_vector();\\n\\n compute_commitment(inputs, DS_CIPHERTEXT)\\n}\\n\\n/// COMMITMENTS FOR CHALLENGES\\n\\npub fn compute_threshold_pk_challenge(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_CLG_PK_GENERATION)\\n}\\n\\npub fn compute_share_encryption_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_threshold_share_decryption_challenge<let L: u32>(payload: [Field]) -> Field {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_DECRYPTION)[0]\\n}\\n\\npub fn compute_user_data_encryption_ct0_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\\npub fn compute_user_data_encryption_ct1_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/commitments.nr\",\"function_locations\":[{\"start\":7767,\"name\":\"compute_commitment\"},{\"start\":7995,\"name\":\"compute_single_polynomial_commitment\"},{\"start\":8298,\"name\":\"compute_multiple_polynomial_commitment\"},{\"start\":8535,\"name\":\"compute_challenge\"},{\"start\":8745,\"name\":\"single_polynomial_payload\"},{\"start\":8944,\"name\":\"multiple_polynomial_payload\"},{\"start\":9157,\"name\":\"compute_dkg_pk_commitment\"},{\"start\":9484,\"name\":\"compute_threshold_pk_commitment\"},{\"start\":9734,\"name\":\"compute_share_computation_sk_commitment\"},{\"start\":10005,\"name\":\"compute_share_computation_e_sm_commitment\"},{\"start\":10277,\"name\":\"compute_share_encryption_commitment_from_message\"},{\"start\":10553,\"name\":\"compute_aggregated_shares_commitment\"},{\"start\":11134,\"name\":\"compute_threshold_decryption_share_commitment\"},{\"start\":11466,\"name\":\"compute_pk_aggregation_commitment\"},{\"start\":11855,\"name\":\"compute_recursive_aggregation_commitment\"},{\"start\":11970,\"name\":\"compute_vk_hash\"},{\"start\":12169,\"name\":\"compute_ciphertext_commitment\"},{\"start\":12568,\"name\":\"compute_threshold_pk_challenge\"},{\"start\":12710,\"name\":\"compute_share_encryption_challenge\"},{\"start\":12867,\"name\":\"compute_threshold_share_decryption_challenge\"},{\"start\":13027,\"name\":\"compute_user_data_encryption_ct0_challenge\"},{\"start\":13188,\"name\":\"compute_user_data_encryption_ct1_challenge\"}]},\"89\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\n//! Helper functions for circuit construction and cryptographic operations.\\nuse crate::math::polynomial::Polynomial;\\nuse crate::math::safe::SafeSponge;\\n\\n/// Compute hex-aligned packing parameters for a given `BIT`.\\n///\\n/// # Purpose\\n/// Returns `(nibble_bits, group)` for use by pack/flatten so layout stays consistent.\\n/// - `nibble_bits`: ceil (`BIT`) to the next multiple of 4 (nibble alignment).\\n/// - Examples: `BIT = 7 -> 8`, `BIT = 8 -> 8`, `BIT = 9 -> 12`, `BIT = 10 -> 12`, `BIT = 11 -> 12`,\\n/// `BIT=16 -> 16`, `BIT = 17 -> 20`.\\n/// - `group`: max number of encoded limbs that fit in one BN254 field element,\\n/// when each limb uses an extra 4 bits (see below).\\n///\\n/// # Rationale\\n/// - We align to nibbles so powers of two are hex-friendly and deterministic.\\n/// - We reserve one extra nibble (4 bits) per stored value to lift signed\\n/// coefficients into the non-negative range (e.g., store `v + 2^nibble_bits`),\\n/// which implies a radix of `2^(nibble_bits + 4)`.\\n///\\n/// # Safety\\n/// - Asserts `nibble_bits + 4 <= 254` to avoid mod-p wrap on BN254.\\n/// - Ensures at least one limb fits: `group >= 1`.\\nfn packing_layout<let BIT: u32>() -> (u32, u32) {\\n // Ceil BIT up to the next multiple of 4 (nibble alignment).\\n let nibble_bits = ((BIT + 3) / 4) * 4;\\n\\n // Each stored limb uses an extra nibble because negative coefficients\\n // will be shifted to positive, so radix = 2^(nibble_bits+4).\\n assert(nibble_bits + 4 <= 254);\\n\\n // Maximum limbs that fit in one BN254 element without wrap.\\n let group = 254 / (nibble_bits + 4);\\n assert(group >= 1);\\n (nibble_bits, group)\\n}\\n\\n/// Flatten `L` polynomials into a single linear stream of packed `Field` carriers.\\n///\\n/// ## What this does\\n/// - For each CRT limb `j` in `0..L`, it packs the coefficients of `poly[j]`\\n/// with `pack::<A, BIT>` and appends all resulting carriers to `inputs`.\\n/// - The packing layout (nibble-aligned width and `group` size) is taken from\\n/// `packing_layout::<BIT>()` and must match what `pack` uses.\\n///\\n/// ## Determinism & order\\n/// - Preserves a stable order: iterate `j = 0..L`, then for each `j` append\\n/// carriers in ascending chunk index `i = 0..num_chunks`.\\n/// - This ensures transcripts remain deterministic across runs.\\n///\\n/// ## Generics\\n/// - `A`: polynomial degree (number of coefficients per polynomial).\\n/// - `L`: number of CRT bases (polynomials).\\n/// - `BIT`: per-coefficient bit bound used by the packing layout (compile-time).\\n///\\n/// ## Returns\\n/// - The same `inputs` vector, extended with all carriers in deterministic order.\\npub fn flatten<let A: u32, let L: u32, let BIT: u32>(\\n mut inputs: [Field],\\n poly: [Polynomial<A>; L],\\n) -> [Field] {\\n for j in 0..L {\\n // Pack its A coefficients into `num_chunks` carriers using the same BIT layout.\\n let packed = pack::<A, BIT>(poly[j].coefficients);\\n\\n // Append carriers in-order to `inputs` to keep a stable transcript layout.\\n for i in 0..packed.len() {\\n inputs = inputs.push_back(packed[i]);\\n }\\n }\\n\\n // Return the extended input stream.\\n inputs\\n}\\n\\n/// Pack `A` values into a `[Field]` vector of carriers using the shared hex-aligned layout.\\n///\\n/// ## What this does\\n/// - Computes `(nibble_bits, group)` via `packing_layout::<BIT>()`.\\n/// - Encodes each value as a limb `digit = v + 2^nibble_bits` and concatenates\\n/// limbs in base `radix = 2^(nibble_bits + 4)` (one extra nibble of headroom).\\n/// - Packs up to `group` limbs per carrier (fits within BN254 254-bit capacity).\\n/// - Pads the last, partial carrier with `digit = 2^nibble_bits` to keep a stable layout.\\n///\\n/// ## Determinism & order\\n/// - Processes values in increasing index order and emits carriers in chunk order\\n/// (`chunk = 0..num_chunks`). Padding is deterministic.\\n///\\n/// ## Generics\\n/// - `A`: number of input values.\\n/// - `BIT`: per-value bit bound; rounded up to `nibble_bits` by `packing_layout`.\\n///\\n/// ## Preconditions / Notes\\n/// - Call with the raw coefficients whose magnitudes already satisfy the BIT bound\\n/// (as enforced by the upstream range checks); `pack` performs the signed -> unsigned\\n/// shift internally via `v + base`.\\n/// - `group >= 1` is enforced by `packing_layout::<BIT>()`.\\n/// - Padding with `digit = 2^nibble_bits` encodes `zero limb` consistently.\\n///\\n/// ## Returns\\n/// - A `[Field]` vector where each element is a concatenation of up to `group` limbs,\\n/// suitable for hashing or transcript I/O.\\npub fn pack<let A: u32, let BIT: u32>(values: [Field; A]) -> [Field] {\\n // Layout parameters: nibble-aligned width and limbs-per-carrier group size.\\n let (nibble_bits, group) = packing_layout::<BIT>();\\n\\n let base = 2.pow_32(nibble_bits as Field); // 2^nibble_bits\\n let radix = 2.pow_32((nibble_bits + 4) as Field); // 2^(nibble_bits + 4)\\n\\n // Number of chunks to emit: ceil(A / group).\\n let num_chunks = (A + group - 1) / group;\\n let mut out: [Field] = [].as_vector();\\n\\n // Process in fixed-size chunks of `group` limbs.\\n for chunk in 0..num_chunks {\\n // How many real values go into this chunk.\\n let remain = A - (chunk * group);\\n let take = if remain < group { remain } else { group };\\n\\n // Build field element accumulator (big-endian concatenation in `radix`).\\n let mut acc = 0;\\n for i in 0..take {\\n let v = values[chunk * group + i];\\n acc = acc * radix + (v + base);\\n }\\n\\n // Pad remaining limb slots with the canonical zero-limb `digit = base`.\\n for _ in 0..(group - take) {\\n acc = acc * radix + base;\\n }\\n\\n out = out.push_back(acc);\\n }\\n out\\n}\\n\\n/// Computes a cryptographic hash using the SAFE (Sponge API for Field Elements) protocol.\\n///\\n/// This is a convenience wrapper around the SAFE sponge API that handles the full\\n/// lifecycle: initialization, absorption, squeezing, and finalization. It's designed\\n/// for use in Fiat-Shamir challenge generation and commitment schemes within zero-knowledge circuits.\\n///\\n/// # Arguments\\n/// * `domain_separator` - A 64-byte domain separator used to differentiate between\\n/// different protocol instances and prevent cross-protocol attacks.\\n/// * `inputs` - Vector of field elements to be absorbed into the sponge.\\n/// * `io_pattern` - A 2-element array encoding the I/O pattern:\\n/// - `io_pattern[0]`: Encoded ABSORB operation (MSB=1, lower 31 bits = length)\\n/// - `io_pattern[1]`: Encoded SQUEEZE operation (MSB=0, lower 31 bits = length)\\n///\\n/// # Returns\\n/// A vector of field elements squeezed from the sponge, with length determined by\\n/// the SQUEEZE operation in the IO pattern.\\npub fn compute_safe(domain_separator: [u8; 64], inputs: [Field], io_pattern: [u32; 2]) -> [Field] {\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(inputs);\\n let digests = sponge.squeeze();\\n sponge.finish();\\n\\n digests\\n}\\n\\n#[test]\\nfn test_flatten() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([1, 2, 3]); // degree 2\\n let poly2 = Polynomial::new([4, -16, 6]); // degree 2\\n let poly3 = Polynomial::new([-7, 8, 9]); // degree 2\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 4>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n assert(result[0] == 0x11121310101010101010101010101010101010101010101010101010101010);\\n assert(result[1] == 0x14001610101010101010101010101010101010101010101010101010101010); // -16 became 00 at 0x 14 00 16,\\n assert(result[2] == 0x09181910101010101010101010101010101010101010101010101010101010); // -7 became 09 at 0x 09 18 19(16 - 7 = 9)\\n}\\n\\n#[test]\\nfn test_flatten_big() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([\\n 1791218451968394,\\n 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n 5430119342984413,\\n 704811298945172,\\n 8901715723925099,\\n 21888242871839275222246405745257275088548364400416034343698203098124042812559,\\n 21888242871839275222246405745257275088548364400416034343698200215091693880034,\\n ]);\\n let poly2 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698200314078269634250,\\n 21888242871839275222246405745257275088548364400416034343698200967285641915872,\\n 2909990636858607,\\n 7896103832076587,\\n 2078397209533893,\\n 21888242871839275222246405745257275088548364400416034343698199792421452734531,\\n 614400389245817,\\n 8290314119277588,\\n ]);\\n let poly3 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698201373175279892906,\\n 21888242871839275222246405745257275088548364400416034343698201087241869723721,\\n 6768789983786188,\\n 635797784303388,\\n 7610153424227556,\\n 4633893206538324,\\n 2016269760615332,\\n 21888242871839275222246405745257275088548364400416034343698201007080554428142,\\n ]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 54>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n\\n // For the first index of result operation goes like this,\\n\\n // First four index of poly1\\n // 1791218451968394,\\n // 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n // 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n // 5430119342984413,\\n\\n // base + 1791218451968394 = 0x1065d1a8b8b718a\\n // base - 5921327228407753 = 0xeaf69591f3b037 (negative coefficient shifted)\\n // base - 3644467483862151 = 0xf30d604a3a9b79 (negative coefficient shifted)\\n // base + 5430119342984413 = 0x1134aaa2e86ccdd\\n assert(result[0] == 0x1065d1a8b8b718a0eaf69591f3b0370f30d604a3a9b791134aaa2e86ccdd);\\n assert(result[1] == 0x1028105ab1b789411fa010339db66b0fc220f1326bc8e0f1e3f4cc1e02e1);\\n assert(result[2] == 0x0f23dfbe7cd76c90f4901299312ddf10a569efe35acef11c0d76f005412b);\\n assert(result[3] == 0x107624a8f605dc50f0638a368960421022ecb3cf36b7911d73ff2c27ec14);\\n assert(result[4] == 0x0f6013a24e1b9a90f4fd2c158a08481180c2dba8af4cc10242413515171c);\\n assert(result[5] == 0x11b0964eb898ce411076805680b85410729c962da53a40f4b44412d0f6ed);\\n}\\n\\n#[test]\\nfn test_flatten_small() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([712345, 104857, 999999, 500001, 123, 654321, 77]);\\n let poly2 = Polynomial::new([1, 524287, 888888, 23456, 34567, 765432, 0]);\\n let poly3 = Polynomial::new([444444, 333333, 222222, 111111, 987654, 246810, 13579]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 20>(inputs, polynomials);\\n\\n assert(result[0] == 0x1ade991199991f423f17a12110007b19fbf110004d100000100000100000);\\n assert(result[1] == 0x10000117ffff1d9038105ba01087071badf8100000100000100000100000);\\n assert(result[2] == 0x16c81c15161513640e11b2071f120613c41a10350b100000100000100000);\\n}\\n\\n#[test]\\nfn test_safe_hashing_with_safe_helper() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let digests1 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests1.len() == 1);\\n assert(digests1[0] != 0);\\n\\n // Test determinism\\n let digests2 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests2.len() == 1);\\n assert(digests2[0] != 0);\\n assert(digests2[0] == digests1[0]);\\n}\\n\\n#[test]\\nfn test_pack() {\\n // Test pack function directly with small values\\n let values = [1, 2, 3, 4];\\n let packed = pack::<4, 4>(values);\\n\\n // With BIT=4, nibble_bits=4, group should be floor(254/(4+4)) = 31\\n // So all 4 values should fit in one carrier\\n assert(packed.len() >= 1);\\n\\n // Test with negative values\\n let values_neg = [-1, 2, -3, 4];\\n let packed_neg = pack::<4, 4>(values_neg);\\n assert(packed_neg.len() >= 1);\\n}\\n\\n#[test]\\nfn test_pack_single_value() {\\n // Test packing a single value\\n let values = [42];\\n let packed = pack::<1, 8>(values);\\n assert(packed.len() == 1);\\n assert(packed[0] != 0);\\n}\\n\\n#[test]\\nfn test_pack_determinism() {\\n // Test that packing is deterministic\\n let values = [10, 20, 30];\\n let packed1 = pack::<3, 8>(values);\\n let packed2 = pack::<3, 8>(values);\\n\\n assert(packed1.len() == packed2.len());\\n for i in 0..packed1.len() {\\n assert(packed1[i] == packed2[i]);\\n }\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/helpers.nr\",\"function_locations\":[{\"start\":1374,\"name\":\"packing_layout\"},{\"start\":2905,\"name\":\"flatten\"},{\"start\":4755,\"name\":\"pack\"},{\"start\":7016,\"name\":\"compute_safe\"},{\"start\":7214,\"name\":\"test_flatten\"},{\"start\":8157,\"name\":\"test_flatten_big\"},{\"start\":11058,\"name\":\"test_flatten_small\"},{\"start\":11885,\"name\":\"test_safe_hashing_with_safe_helper\"},{\"start\":12731,\"name\":\"test_pack\"},{\"start\":13201,\"name\":\"test_pack_single_value\"},{\"start\":13397,\"name\":\"test_pack_determinism\"}]},\"97\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse keccak256::keccak256;\\nuse poseidon::poseidon2_permutation;\\n\\n/// SAFE (Sponge API for Field Elements)\\n///\\n/// This module provides a complete implementation of the SAFE API in Noir as defined in:\\n/// \\\"SAFE (Sponge API for Field Elements) - A Toolbox for ZK Hash Applications\\\"\\n/// see https://hackmd.io/bHgsH6mMStCVibM_wYvb2w#22-Sponge-state for more details.\\n///\\n/// SAFE provides a unified interface for cryptographic sponge functions that can be\\n/// instantiated with various permutations to create hash functions, MACs, authenticated\\n/// encryption schemes, and other cryptographic primitives for ZK proof systems.\\n///\\n/// This implementation follows the SAFE specification exactly, providing:\\n/// - Complete API: START, ABSORB, SQUEEZE, FINISH operations.\\n/// - Full security: Domain separation, tag computation, IO pattern validation.\\n/// - Poseidon2 integration: Field-friendly permutation for ZK systems.\\n/// - Specification compliance: All operations follow SAFE spec 2.4 exactly.\\n/// - Natural API design: Variable-length inputs, automatic length detection from IO patterns.\\n///\\n/// # API Design\\n///\\n/// The API is designed for natural usage while maintaining type safety:\\n/// - `absorb(input: [Field])`: Accepts variable-length arrays, no padding required.\\n/// - `squeeze()`: Returns a vector with field element(s).\\n/// - IO patterns automatically determine operation lengths for validation.\\n\\n/// Rate parameter for the sponge construction (number of field elements that can be absorbed per permutation call).\\nglobal RATE: u32 = 3;\\n\\n/// Capacity parameter for the sponge construction (security parameter, typically 1-2 field elements).\\nglobal CAPACITY: u32 = 1;\\n\\n/// Total state size (rate + capacity) in field elements.\\nglobal STATE_SIZE: u32 = RATE + CAPACITY;\\n\\n/// IO Pattern encoding constants (from SAFE spec 2.3).\\n///\\n/// These constants are used for encoding operation types in the 32-bit word format:\\n/// - MSB set to 1 for ABSORB operations\\n/// - MSB set to 0 for SQUEEZE operations\\n\\n/// Flag for ABSORB operations (MSB = 1)\\nglobal ABSORB_FLAG: u32 = 0x80000000;\\n\\n/// Flag for SQUEEZE operations (MSB = 0)\\nglobal SQUEEZE_FLAG: u32 = 0x00000000;\\n\\n/// SAFE Sponge State (following spec 2.2)\\n///\\n/// The sponge state consists of the permutation state, tag, position counters,\\n/// and IO pattern tracking as defined in the SAFE specification.\\n///\\n/// # Generic Parameters\\n/// - `L`: The length of the IO pattern array\\n///\\n/// # Fields\\n/// - `state`: Permutation state V in F^n (rate + capacity elements)\\n/// - `tag`: Parameter tag T used for instance differentiation\\n/// - `absorb_pos`: Current absorb position (<= n-c)\\n/// - `squeeze_pos`: Current squeeze position (<= n-c)\\n/// - `io_pattern`: Expected IO pattern for validation (encoded 32-bit words)\\n/// - `io_count`: Current operation count for pattern tracking\\npub struct SafeSponge<let L: u32> {\\n /// Permutation state V in F^n (rate + capacity elements).\\n state: [Field; STATE_SIZE],\\n /// Parameter tag T used for instance differentiation.\\n tag: Field,\\n /// Current absorb position (<= n-c).\\n absorb_pos: u32,\\n /// Current squeeze position (<= n-c).\\n squeeze_pos: u32,\\n /// Expected IO pattern for validation.\\n io_pattern: [u32; L],\\n /// Current operation count for pattern tracking (spec 2.4: io_count).\\n io_count: u32,\\n}\\n\\nimpl<let L: u32> SafeSponge<L> {\\n /// Initializes a new SAFE sponge instance with the given IO pattern and domain separator (following spec 2.4).\\n ///\\n /// # Arguments\\n /// - `io_pattern`: Array of 32-bit encoded operations defining the expected sequence of ABSORB/SQUEEZE calls.\\n /// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n /// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n ///\\n /// # Returns\\n /// A new `SafeSponge` instance with initialized state\\n pub fn start(io_pattern: [u32; L], domain_separator: [u8; 64]) -> SafeSponge<L> {\\n // Compute tag from IO pattern and domain separator (spec 2.3).\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n let mut state = [0; STATE_SIZE];\\n // Initialize capacity with tag (spec 2.4).\\n // Add T to the first 128 bits of the state.\\n state[0] = tag;\\n\\n SafeSponge { state, tag, absorb_pos: 0, squeeze_pos: 0, io_pattern, io_count: 0 }\\n }\\n\\n /// Absorbs field elements into the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to absorb is automatically validated against the IO pattern.\\n /// This method accepts variable-length arrays, making it natural to use without padding.\\n ///\\n /// # Arguments\\n /// - `input`: Array of field elements to absorb (variable length, must match IO pattern)\\n pub fn absorb(&mut self, input: [Field]) {\\n let length = input.len() as u32;\\n\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_absorb = (expected_encoded_word & ABSORB_FLAG) != 0;\\n let expected_length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type and length\\n assert(is_expected_absorb, \\\"Expected ABSORB operation\\\");\\n assert(expected_length == length, \\\"Length mismatch\\\");\\n\\n // Process each element naturally (no unnecessary iterations).\\n for i in 0..length {\\n // If absorb_pos == (n-c) then permute and reset (spec 2.4).\\n if self.absorb_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.absorb_pos = 0;\\n }\\n\\n // Add X[i] to state at absorb_pos (spec 2.4).\\n // Note: absorb_pos is the rate position, not capacity position.\\n self.state[self.absorb_pos + CAPACITY] =\\n self.state[self.absorb_pos + CAPACITY] + input[i];\\n self.absorb_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = ABSORB_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n\\n // Force permute at start of next SQUEEZE (spec 2.4).\\n self.squeeze_pos = RATE;\\n }\\n\\n /// Extracts field elements from the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to squeeze is automatically determined from the IO pattern.\\n pub fn squeeze(&mut self) -> [Field] {\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_squeeze = (expected_encoded_word & ABSORB_FLAG) == 0;\\n let length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type\\n assert(is_expected_squeeze, \\\"Expected SQUEEZE operation\\\");\\n\\n let mut output: [Field] = [].as_vector();\\n\\n // SQUEEZE implementation following spec 2.4.\\n // If length==0, loop won't execute (spec 2.4).\\n for _ in 0..length {\\n // If squeeze_pos==(n-c) then permute and reset (spec 2.4).\\n if self.squeeze_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.squeeze_pos = 0;\\n self.absorb_pos = 0;\\n }\\n // Set Y[i] to state element at squeeze_pos (spec 2.4).\\n output = output.push_back(self.state[self.squeeze_pos + CAPACITY]);\\n self.squeeze_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = SQUEEZE_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n output\\n }\\n\\n /// Finalizes the sponge instance, verifying that all expected operations have been performed and clearing the internal state for security (following spec 2.4).\\n ///\\n /// This function is used to ensure that the sponge instance has been used correctly and to prevent information leakage.\\n pub fn finish(&mut self) {\\n // Check that io_count equals the length of the IO pattern expected (spec 2.4).\\n assert(self.io_count == L, \\\"IO pattern not completed\\\");\\n\\n // Erase the state and its variables (spec 2.4).\\n self.state = [0; STATE_SIZE];\\n self.absorb_pos = 0;\\n self.squeeze_pos = 0;\\n self.io_count = 0;\\n }\\n\\n /// Permute the state using Poseidon2 (following spec 2.4).\\n ///\\n /// Applies the Poseidon2 permutation to the current state.\\n /// This is the core cryptographic primitive of the sponge construction.\\n ///\\n /// # Returns\\n /// New state after permutation\\n fn permute(self) -> [Field; STATE_SIZE] {\\n poseidon2_permutation(self.state)\\n }\\n}\\n\\n/// Computes a unique tag for a sponge instance based on its IO pattern and domain separator.\\n/// The tag is used to ensure that distinct instances behave like distinct functions.\\n///\\n/// # Arguments\\n/// - `io_pattern`: Array of 32-bit encoded operations defining the sponge's usage pattern.\\n/// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n/// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n///\\n/// # Returns\\n/// A field element representing the 128-bit tag.\\npub fn compute_tag<let L: u32>(io_pattern: [u32; L], domain_separator: [u8; 64]) -> Field {\\n // Step 1: Parse and aggregate consecutive operations of the same type\\n let mut encoded_words = [0; L]; // Support up to L operations.\\n let mut word_count = 0;\\n let mut current_absorb_sum = 0;\\n let mut current_squeeze_sum = 0;\\n let mut last_was_absorb = false;\\n\\n for i in 0..L {\\n if io_pattern[i] > 0 {\\n // Parse operation type from MSB and length from lower 31 bits\\n let is_absorb = (io_pattern[i] & ABSORB_FLAG) != 0;\\n let length = io_pattern[i] & 0x7FFFFFFF; // Clear MSB to get length\\n\\n if is_absorb {\\n if last_was_absorb {\\n // Aggregate consecutive ABSORB operations\\n current_absorb_sum += length;\\n } else {\\n // Start new ABSORB sequence\\n if current_squeeze_sum > 0 {\\n // Flush previous SQUEEZE sequence\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n current_squeeze_sum = 0;\\n }\\n current_absorb_sum = length;\\n }\\n last_was_absorb = true;\\n } else {\\n if !last_was_absorb {\\n // Aggregate consecutive SQUEEZE operations\\n current_squeeze_sum += length;\\n } else {\\n // Start new SQUEEZE sequence\\n if current_absorb_sum > 0 {\\n // Flush previous ABSORB sequence\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n current_absorb_sum = 0;\\n }\\n current_squeeze_sum = length;\\n }\\n last_was_absorb = false;\\n }\\n }\\n }\\n\\n // Flush remaining operations\\n if current_absorb_sum > 0 {\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n }\\n if current_squeeze_sum > 0 {\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n }\\n\\n // Step 2: Serialize to byte string and append domain separator (following SAFE spec 2.3).\\n // Buffer is 256 bytes: max 192 bytes for IO pattern (48 words) + 64 bytes for domain separator.\\n // Note: We must use a fixed-size array because Noir's keccak256 requires [u8; N], not [u8].\\n let max_io_pattern_bytes: u32 = 192; // 256 - 64 (domain separator)\\n let io_pattern_bytes = word_count * 4;\\n assert(\\n io_pattern_bytes <= max_io_pattern_bytes,\\n \\\"IO pattern too large: max 48 aggregated words supported\\\",\\n );\\n\\n let mut input_bytes = [0u8; 256];\\n let mut byte_count: u32 = 0;\\n\\n // Serialize encoded words to bytes (big-endian as per SAFE spec).\\n // Note: Noir requires compile-time loop bounds, so we iterate over L (the array size)\\n // instead of word_count (runtime value). The condition `i < word_count` ensures we only\\n // process valid encoded words. This is safe because word_count <= L always holds\\n // (we can have at most L encoded words from L input operations).\\n for i in 0..L {\\n if i < word_count {\\n let word = encoded_words[i];\\n input_bytes[byte_count] = (word >> 24) as u8;\\n input_bytes[byte_count + 1] = (word >> 16) as u8;\\n input_bytes[byte_count + 2] = (word >> 8) as u8;\\n input_bytes[byte_count + 3] = word as u8;\\n byte_count += 4;\\n }\\n }\\n\\n // Append full 64-byte domain separator.\\n for i in 0..64 {\\n input_bytes[byte_count] = domain_separator[i];\\n byte_count += 1;\\n }\\n\\n // Step 3: Hash with Keccak-256 and truncate to 128 bits.\\n // Note: The SAFE spec uses SHA3-256, but we use Keccak-256 for Noir compatibility.\\n // Keccak-256 differs from SHA3-256 in padding, but both provide equivalent security.\\n let hash_bytes = keccak256(input_bytes, byte_count);\\n\\n // Convert first 128 bits (16 bytes) to field element.\\n let mut tag_value: Field = 0;\\n for i in 0..16 {\\n tag_value = tag_value * 256 + (hash_bytes[i] as Field);\\n }\\n\\n tag_value\\n}\\n\\n#[test]\\nfn test_safe_hashing() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_merkle_node() {\\n // Verifies SAFE can be used for Merkle tree node hashing with pattern ABSORB(1) + ABSORB(1) + SQUEEZE(1).\\n // Tests the ability to absorb multiple inputs before squeezing output.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let left = [123].as_vector();\\n let right = [456].as_vector();\\n\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(left);\\n sponge.absorb(right);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(left);\\n sponge2.absorb(right);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_commitment_scheme() {\\n // Verifies SAFE can be used for commitment schemes with pattern ABSORB(3) + SQUEEZE(1).\\n // Tests the ability to create deterministic commitments from multiple field elements.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let values = [10, 20, 30].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(values);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(values);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_domain_separation() {\\n // Verifies that different domain separators produce different outputs for the same input.\\n // This is crucial for cross-protocol security and preventing collisions between different applications.\\n let elements = [1, 2, 3].as_vector();\\n let domain1 = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let domain2 = [\\n 0x41, 0x42, 0x43, 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n\\n let mut sponge1 = SafeSponge::start(io_pattern, domain1);\\n sponge1.absorb(elements);\\n let output1 = sponge1.squeeze();\\n sponge1.finish();\\n\\n let mut sponge2 = SafeSponge::start(io_pattern, domain2);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output1.len() == 1);\\n assert(output2.len() == 1);\\n assert(output1[0] != output2[0]); // Different domain separators should produce different outputs\\n}\\n\\n#[test]\\nfn test_multiple_squeeze() {\\n // Verifies that multiple field elements can be squeezed in a single operation.\\n // Tests pattern ABSORB(3) + SQUEEZE(2) to ensure proper state management.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(2)\\n let io_pattern = [0x80000003, 0x00000002];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 2);\\n assert(output[0] != 0);\\n assert(output[1] != 0);\\n assert(output[0] != output[1]); // Different squeeze outputs should be different\\n}\\n\\n#[test]\\nfn test_zero_length_operations() {\\n // Verifies that zero-length ABSORB and SQUEEZE operations are handled correctly.\\n // Tests pattern ABSORB(0) + SQUEEZE(1) to ensure proper state transitions.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(0), SQUEEZE(1)\\n let io_pattern = [0x80000000, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb([].as_vector());\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n}\\n\\n#[test]\\nfn test_tag_computation() {\\n // Verifies the tag computation algorithm using the example from the SAFE specification.\\n // Pattern: ABSORB(3), ABSORB(3), SQUEEZE(3)\\n // Should aggregate to: ABSORB(6), SQUEEZE(3)\\n // Encoded as: [0x80000006, 0x00000003]\\n // Tests determinism and pattern differentiation.\\n\\n let io_pattern = [0x80000003, 0x80000003, 0x00000003];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test determinism\\n let tag2 = compute_tag(io_pattern, domain_separator);\\n assert(tag == tag2);\\n\\n // Test that different patterns produce different tags\\n let io_pattern2 = [0x80000003, 0x00000003]; // ABSORB(3), SQUEEZE(3) - different pattern\\n let tag3 = compute_tag(io_pattern2, domain_separator);\\n assert(tag != tag3);\\n}\\n\\n#[test]\\nfn test_tag_computation_debug() {\\n println(\\\"=== SAFE Tag Computation Debug Test ===\\\");\\n\\n // Test your specific pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\n let io_pattern = [0x80000002, 0x00000002, 0x80000002];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n println(f\\\"Testing pattern: {io_pattern}\\\");\\n println(\\n f\\\"Expected to aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(2)\\\",\\n );\\n println(\\n f\\\"Expected encoded words: [0x80000002, 0x00000002, 0x80000002]\\\",\\n );\\n println(\\\"\\\");\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n println(f\\\"=== Expected Rust Output ===\\\");\\n println(\\\"Pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\\");\\n println(\\\"Domain separator: 0x41424344...\\\");\\n println(\\\"Tag: 0xce3bb9ee4b2d41c42e9cdda38afe8b6a\\\");\\n println(\\\"\\\");\\n\\n println(f\\\"=== Noir Output ===\\\");\\n println(f\\\"Tag: {tag}\\\");\\n println(\\\"\\\");\\n\\n println(\\\"Compare the tag values above with Rust script!\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_absorb_aggregation() {\\n // Test that consecutive ABSORB operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1) should aggregate to ABSORB(2), SQUEEZE(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(1) = [0x80000002, 0x00000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(2), SQUEEZE(1)\\n let aggregated_pattern = [0x80000002, 0x00000001];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Consecutive ABSORB operations should aggregate to the same tag\\\");\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive ABSORB operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive ABSORB Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001] (ABSORB(1), ABSORB(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000002, 0x00000001] (ABSORB(2), SQUEEZE(1))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_squeeze_aggregation() {\\n // Test that consecutive SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1) should aggregate to ABSORB(1), SQUEEZE(2)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x00000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(1), SQUEEZE(2) = [0x80000001, 0x00000002]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(1), SQUEEZE(2)\\n let aggregated_pattern = [0x80000001, 0x00000002];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(\\n tag == aggregated_tag,\\n \\\"Consecutive SQUEEZE operations should aggregate to the same tag\\\",\\n );\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive SQUEEZE operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive SQUEEZE Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x00000001, 0x00000001] (ABSORB(1), SQUEEZE(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000001, 0x00000002] (ABSORB(1), SQUEEZE(2))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_mixed_consecutive_aggregation() {\\n // Test that both consecutive ABSORB and SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n // Should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1) = [0x80000002, 0x00000002, 0x80000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag\\n let aggregated_pattern = [0x80000002, 0x00000002, 0x80000001]; // ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Mixed consecutive operations should aggregate to the same tag\\\");\\n\\n println(\\\"=== Mixed Consecutive Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001]\\\",\\n );\\n println(\\n f\\\" (ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1))\\\",\\n );\\n println(f\\\"Aggregated pattern: [0x80000002, 0x00000002, 0x80000001]\\\");\\n println(f\\\" (ABSORB(2), SQUEEZE(2), ABSORB(1))\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n}\\n\\n#[test]\\nfn test_large_io_pattern() {\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Create pattern with 48 alternating ABSORB(1) and SQUEEZE(1) operations\\n // This is the maximum supported (48 words * 4 bytes = 192 bytes, leaving 64 for domain separator)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1; // ABSORB(1)\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1; // SQUEEZE(1)\\n }\\n }\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n assert(tag != 0);\\n}\\n\\n#[test]\\nfn test_domain_separator_not_truncated() {\\n // This test verifies that the domain separator is always included in the tag computation,\\n // even for large IO patterns. If the domain separator were truncated, different domain\\n // separators would produce the same tag for large patterns.\\n\\n let domain_separator_a = [\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41,\\n ]; // All 'A's\\n\\n let domain_separator_b = [\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42,\\n ]; // All 'B's\\n\\n // Create pattern with 48 alternating operations (max supported: 192 bytes of IO pattern)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1;\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1;\\n }\\n }\\n\\n let tag_a = compute_tag(io_pattern, domain_separator_a);\\n let tag_b = compute_tag(io_pattern, domain_separator_b);\\n\\n // Tags MUST be different because domain separators are different.\\n // If they were the same, it would mean the domain separator was truncated/ignored.\\n assert(tag_a != tag_b, \\\"Domain separator must affect tag even for large IO patterns\\\");\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/safe.nr\",\"function_locations\":[{\"start\":4164,\"name\":\"SafeSponge<L>::start\"},{\"start\":5046,\"name\":\"SafeSponge<L>::absorb\"},{\"start\":6826,\"name\":\"SafeSponge<L>::squeeze\"},{\"start\":8494,\"name\":\"SafeSponge<L>::finish\"},{\"start\":9156,\"name\":\"SafeSponge<L>::permute\"},{\"start\":9830,\"name\":\"compute_tag\"},{\"start\":14128,\"name\":\"test_safe_hashing\"},{\"start\":15104,\"name\":\"test_merkle_node\"},{\"start\":16281,\"name\":\"test_commitment_scheme\"},{\"start\":17357,\"name\":\"test_domain_separation\"},{\"start\":18710,\"name\":\"test_multiple_squeeze\"},{\"start\":19639,\"name\":\"test_zero_length_operations\"},{\"start\":20415,\"name\":\"test_tag_computation\"},{\"start\":21477,\"name\":\"test_tag_computation_debug\"},{\"start\":22681,\"name\":\"test_consecutive_absorb_aggregation\"},{\"start\":24750,\"name\":\"test_consecutive_squeeze_aggregation\"},{\"start\":26760,\"name\":\"test_mixed_consecutive_aggregation\"},{\"start\":28520,\"name\":\"test_large_io_pattern\"},{\"start\":29333,\"name\":\"test_domain_separator_not_truncated\"}]}}}","{\"noir_version\":\"1.0.0-beta.26+40d6574f851d926f93e0c3a271bac3e6e82ac905\",\"hash\":\"1039263030772024318\",\"abi\":{\"parameters\":[{\"name\":\"user_data_encryption_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":5,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"crisp_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"prev_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_hi\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_lo\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"slot_address\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"voting_power\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"is_first_vote\",\"type\":{\"kind\":\"boolean\"},\"visibility\":\"public\"},{\"name\":\"num_options\",\"type\":{\"kind\":\"integer\",\"sign\":\"unsigned\",\"width\":32},\"visibility\":\"public\"},{\"name\":\"final_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"k1_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"}],\"return_type\":{\"abi_type\":{\"kind\":\"field\"},\"visibility\":\"public\"},\"error_types\":{}},\"bytecode\":\"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\",\"debug_symbols\":\"tZbdiuMwDIXfxde+sOQfWfMqy1LSNh0CIS2ZZmAp8+7rdGKnGbDpuuyVmjj+0DmSVd/Esd1P77tuOJ0/xNuvm9iPXd9377v+fGiu3XkIb29fUsTH3XVs2/BKPKyHXZdmbIereBumvpfis+mn+0cfl2a4x2szhlUlRTscQwzAU9e3868vue5W+a3gCJfd4B0ngMUNAUoEmwjEeiXoDQHzBK3JLwRtHCQC4rMqEKxeCAikcypKPniykaAV5gj2ZR/cf/XBmOSD8arCBzTAKwFqCA6jD+gs1xAs+0RwVSrIukjY1OJ5gl998NbVEBiTCrYme7JMoaWAKeoAVEAJ4mkLKfQlEcWeIG90FlFoTFIcS0qg7IrgLYLyCAcq+unArEKYnkZYz1GI5YcsfiI4j2Bw0U8G5hwCC2XVnA6pUbBmAfQPXqQsHCpT48UGAXkvSkUFnfrisSI/ioqF/iRnUl84mxWC9vWKuJcrUhTi7XpGGHNZFE87UZzdytTMLK1sIgD4qomTpkUgVE1edioRsGbq6bWrNNDWh9/hqTl04+YOJDB8KYUOzkthguVS2HnySeHmP3Mp6Dv4eZRLwd8B1JxsiLBEXKKejQzRLNEuMcD0XNfPZuyafd8u16/TNBwebmPXP5e4Eu9rl/F8aI/T2M5Z39eCjr8=\",\"file_map\":{\"17\":{\"source\":\"// Exposed only for usage in `std::meta`\\npub(crate) mod poseidon2;\\n\\nuse crate::default::Default;\\nuse crate::embedded_curve_ops::{\\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\\n};\\nuse crate::meta::derive_via;\\nuse crate::static_assert;\\n\\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\\n\\n#[foreign(sha256_compression)]\\n// docs:start:sha256_compression\\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\\n// docs:end:sha256_compression\\n\\n#[foreign(keccakf1600)]\\n// docs:start:keccakf1600\\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\\n// docs:end:keccakf1600\\n\\n#[foreign(blake2s)]\\n// docs:start:blake2s\\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake2s\\n{}\\n\\n// docs:start:blake3\\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake3\\n{\\n if crate::runtime::is_unconstrained() {\\n // Temporary measure while Barretenberg is main proving system.\\n // Please open an issue if you're working on another proving system and running into problems due to this.\\n crate::static_assert(\\n N <= 1024,\\n \\\"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\\\",\\n );\\n }\\n __blake3(input)\\n}\\n\\n#[foreign(blake3)]\\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\\n\\n// docs:start:pedersen_commitment\\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\\n // docs:end:pedersen_commitment\\n pedersen_commitment_with_separator(input, 0)\\n}\\n\\n#[inline_always]\\npub fn pedersen_commitment_with_separator<let N: u32>(\\n input: [Field; N],\\n separator: u32,\\n) -> EmbeddedCurvePoint {\\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\\n for i in 0..N {\\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\\n }\\n let generators = derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n multi_scalar_mul(generators, points)\\n}\\n\\n// docs:start:pedersen_hash\\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\\n// docs:end:pedersen_hash\\n{\\n pedersen_hash_with_separator(input, 0)\\n}\\n\\n#[no_predicates]\\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\\n let mut generators: [EmbeddedCurvePoint; N + 1] =\\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\\n crate::assert_constant(separator);\\n let domain_generators: [EmbeddedCurvePoint; N] =\\n derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n\\n for i in 0..N {\\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\\n generators[i] = domain_generators[i];\\n }\\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\\n\\n let length_generator: [EmbeddedCurvePoint; 1] =\\n derive_generators(\\\"pedersen_hash_length\\\".as_bytes(), 0);\\n generators[N] = length_generator[0];\\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\\n}\\n\\n#[field(bn254)]\\n#[inline_always]\\npub fn derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {\\n crate::assert_constant(domain_separator_bytes);\\n crate::assert_constant(starting_index);\\n __derive_generators(domain_separator_bytes, starting_index)\\n}\\n\\n#[builtin(derive_pedersen_generators)]\\n#[field(bn254)]\\nfn __derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {}\\n\\npub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {\\n static_assert(\\n N == POSEIDON2_CONFIG_STATE_SIZE,\\n f\\\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\\\",\\n );\\n poseidon2_permutation_internal(input)\\n}\\n\\n#[foreign(poseidon2_permutation)]\\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\\n\\n#[foreign(poseidon2_config_state_size)]\\ncomptime fn poseidon2_config_state_size() -> u32 {}\\n\\n// Generic hashing support.\\n// Partially ported and impacted by rust.\\n\\n// Hash trait shall be implemented per type.\\n#[derive_via(derive_hash)]\\npub trait Hash {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher;\\n}\\n\\n// docs:start:derive_hash\\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\\n let name = quote { $crate::hash::Hash };\\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\\n let for_each_field = |name| quote { _self.$name.hash(_state); };\\n crate::meta::make_trait_impl(\\n s,\\n name,\\n signature,\\n for_each_field,\\n quote {},\\n |fields| fields,\\n )\\n}\\n// docs:end:derive_hash\\n\\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\\n// TODO: consider making the types generic here ([u8], [Field], etc.)\\npub trait Hasher {\\n fn finish(self) -> Field;\\n\\n /// Returns the hash value without consuming the hasher.\\n /// Override this for more efficient implementations that avoid copying.\\n /// TODO: deprecate finish() and replace it\\n fn finish_ref(&self) -> Field {\\n (*self).finish()\\n }\\n\\n fn write(&mut self, input: Field);\\n}\\n\\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\\npub trait BuildHasher {\\n type H: Hasher;\\n\\n fn build_hasher(self) -> H;\\n}\\n\\npub struct BuildHasherDefault<H>;\\n\\nimpl<H> BuildHasher for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n type H = H;\\n\\n fn build_hasher(_self: Self) -> H {\\n H::default()\\n }\\n}\\n\\nimpl<H> Default for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n fn default() -> Self {\\n BuildHasherDefault {}\\n }\\n}\\n\\nimpl Hash for Field {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self);\\n }\\n}\\n\\nimpl Hash for u8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u128 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for i8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u8 as Field);\\n }\\n}\\n\\nimpl Hash for i16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u16 as Field);\\n }\\n}\\n\\nimpl Hash for i32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u32 as Field);\\n }\\n}\\n\\nimpl Hash for i64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u64 as Field);\\n }\\n}\\n\\nimpl Hash for bool {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for () {\\n fn hash<H>(_self: Self, _state: &mut H)\\n where\\n H: Hasher,\\n {}\\n}\\n\\nimpl<T, let N: u32> Hash for [T; N]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<T> Hash for [T]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.len().hash(state);\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<A> Hash for (A,)\\nwhere\\n A: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n }\\n}\\n\\nimpl<A, B> Hash for (A, B)\\nwhere\\n A: Hash,\\n B: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n }\\n}\\n\\nimpl<A, B, C> Hash for (A, B, C)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D> Hash for (A, B, C, D)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F> Hash for (A, B, C, D, E, F)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G> Hash for (A, B, C, D, E, F, G)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_> Hash for (A, B, C, D, E, F, G, H_)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I> Hash for (A, B, C, D, E, F, G, H_, I)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J> Hash for (A, B, C, D, E, F, G, H_, I, J)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K> Hash for (A, B, C, D, E, F, G, H_, I, J, K)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K, L> Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n L: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n self.11.hash(state);\\n }\\n}\\n\\n// Some test vectors for Pedersen hash and Pedersen Commitment.\\n// They have been generated using the same functions so the tests are for now useless\\n// but they will be useful when we switch to Noir implementation.\\n#[test]\\nfn assert_pedersen() {\\n assert_eq(\\n pedersen_hash_with_separator([1], 1),\\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1], 1),\\n EmbeddedCurvePoint {\\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\\n },\\n );\\n\\n assert_eq(\\n pedersen_hash_with_separator([1, 2], 2),\\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2], 2),\\n EmbeddedCurvePoint {\\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3], 3),\\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3], 3),\\n EmbeddedCurvePoint {\\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\\n EmbeddedCurvePoint {\\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\\n EmbeddedCurvePoint {\\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\\n EmbeddedCurvePoint {\\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n EmbeddedCurvePoint {\\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n EmbeddedCurvePoint {\\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n EmbeddedCurvePoint {\\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n EmbeddedCurvePoint {\\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\\n },\\n );\\n}\\n\",\"path\":\"std/hash/mod.nr\",\"function_locations\":[{\"start\":572,\"name\":\"sha256_compression\"},{\"start\":707,\"name\":\"keccakf1600\"},{\"start\":852,\"name\":\"blake2s\"},{\"start\":950,\"name\":\"blake3\"},{\"start\":1437,\"name\":\"__blake3\"},{\"start\":1555,\"name\":\"pedersen_commitment\"},{\"start\":1784,\"name\":\"pedersen_commitment_with_separator\"},{\"start\":2188,\"name\":\"pedersen_hash\"},{\"start\":2345,\"name\":\"pedersen_hash_with_separator\"},{\"start\":3339,\"name\":\"derive_generators\"},{\"start\":3698,\"name\":\"__derive_generators\"},{\"start\":3776,\"name\":\"poseidon2_permutation\"},{\"start\":4132,\"name\":\"poseidon2_permutation_internal\"},{\"start\":4225,\"name\":\"poseidon2_config_state_size\"},{\"start\":4536,\"name\":\"derive_hash\"},{\"start\":5327,\"name\":\"Hasher::finish_ref\"},{\"start\":5761,\"name\":\"<impl BuildHasher for BuildHasherDefault<H>>::build_hasher\"},{\"start\":5893,\"name\":\"<impl Default for BuildHasherDefault<H>>::default\"},{\"start\":6025,\"name\":\"<impl Hash for Field>::hash\"},{\"start\":6155,\"name\":\"<impl Hash for u8>::hash\"},{\"start\":6295,\"name\":\"<impl Hash for u16>::hash\"},{\"start\":6435,\"name\":\"<impl Hash for u32>::hash\"},{\"start\":6575,\"name\":\"<impl Hash for u64>::hash\"},{\"start\":6716,\"name\":\"<impl Hash for u128>::hash\"},{\"start\":6855,\"name\":\"<impl Hash for i8>::hash\"},{\"start\":7001,\"name\":\"<impl Hash for i16>::hash\"},{\"start\":7148,\"name\":\"<impl Hash for i32>::hash\"},{\"start\":7295,\"name\":\"<impl Hash for i64>::hash\"},{\"start\":7443,\"name\":\"<impl Hash for bool>::hash\"},{\"start\":7590,\"name\":\"<impl Hash for ()>::hash\"},{\"start\":7722,\"name\":\"<impl Hash for [T; N]>::hash\"},{\"start\":7911,\"name\":\"<impl Hash for [T]>::hash\"},{\"start\":8133,\"name\":\"<impl Hash for (A,)>::hash\"},{\"start\":8302,\"name\":\"<impl Hash for (A, B)>::hash\"},{\"start\":8518,\"name\":\"<impl Hash for (A, B, C)>::hash\"},{\"start\":8781,\"name\":\"<impl Hash for (A, B, C, D)>::hash\"},{\"start\":9091,\"name\":\"<impl Hash for (A, B, C, D, E)>::hash\"},{\"start\":9448,\"name\":\"<impl Hash for (A, B, C, D, E, F)>::hash\"},{\"start\":9852,\"name\":\"<impl Hash for (A, B, C, D, E, F, G)>::hash\"},{\"start\":10306,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_)>::hash\"},{\"start\":10807,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I)>::hash\"},{\"start\":11355,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J)>::hash\"},{\"start\":11950,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K)>::hash\"},{\"start\":12593,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)>::hash\"},{\"start\":13187,\"name\":\"assert_pedersen\"}]},\"22\":{\"source\":\"pub mod hash;\\npub mod aes128;\\npub mod array;\\npub mod vector;\\npub mod ecdsa_secp256k1;\\npub mod ecdsa_secp256r1;\\npub mod embedded_curve_ops;\\npub mod field;\\npub mod collections;\\npub mod compat;\\npub mod convert;\\npub mod option;\\npub mod string;\\npub mod test;\\npub mod cmp;\\npub mod ops;\\npub mod default;\\npub mod prelude;\\npub mod runtime;\\npub mod meta;\\npub mod append;\\npub mod mem;\\npub mod panic;\\npub mod hint;\\n\\nmod integer;\\nmod primitive_docs;\\nmod internal;\\n\\n// Oracle calls are required to be wrapped in an unconstrained function\\n// Thus, the only argument to the `println` oracle is expected to always be an ident\\n#[oracle(print)]\\nunconstrained fn print_oracle<T>(with_newline: bool, input: T) {}\\n\\nunconstrained fn print_unconstrained<T>(with_newline: bool, input: T) {\\n print_oracle(with_newline, input);\\n}\\n\\n/// Print the given input to stdout followed by a newline\\npub fn println<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(true, input);\\n }\\n}\\n\\n/// Print the given input to stdout\\npub fn print<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(false, input);\\n }\\n}\\n\\n/// Asserts the validity of the provided proof and public inputs against the provided verification key and hash.\\n///\\n/// The ACVM cannot determine whether the provided proof is valid during execution as this requires knowledge of\\n/// the backend against which the program is being proven. However if an invalid proof if submitted, the program may\\n/// fail to prove or the backend may generate a proof which will subsequently fail to verify.\\n///\\n/// # Important Note\\n///\\n/// If you are not developing your own backend such as [Barretenberg](https://github.com/AztecProtocol/barretenberg)\\n/// you probably shouldn't need to interact with this function directly. It's easier and safer to use a verification\\n/// library which is published by the developers of the backend which will document or enforce any safety requirements.\\n///\\n/// If you use this directly, you're liable to introduce underconstrainedness bugs and *your circuit will be insecure*.\\n///\\n/// # Arguments\\n/// - verification_key: The verification key of the circuit to be verified.\\n/// - proof: The proof to be verified.\\n/// - public_inputs: The public inputs associated with `proof`\\n/// - key_hash: The hash of `verification_key` of the form expected by the backend.\\n/// - proof_type: An identifier for the proving scheme used to generate the proof to be verified. This allows\\n/// for a single backend to support verifying multiple proving schemes.\\n///\\n/// # Constraining `key_hash`\\n///\\n/// The Noir compiler does not by itself constrain that `key_hash` is a valid hash of `verification_key`.\\n/// This is because different backends may differ in how they hash their verification keys.\\n/// It is then the responsibility of either the noir developer (by explicitly hashing the verification key\\n/// in the correct manner) or by the proving system itself internally asserting the correctness of `key_hash`.\\npub fn verify_proof_with_type<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {\\n if !crate::runtime::is_unconstrained() {\\n crate::assert_constant(proof_type);\\n }\\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\\n}\\n\\n#[foreign(recursive_aggregation)]\\nfn verify_proof_internal<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {}\\n\\n/// Asserts that the given value is known at compile-time.\\n/// Useful for debugging for-loop bounds.\\n#[builtin(assert_constant)]\\npub fn assert_constant<T>(x: T) {}\\n\\n/// Asserts that the given value is both true and known at compile-time.\\n/// The message can be a string, a format string, or any value, as long as it is known at compile-time\\n#[builtin(static_assert)]\\npub fn static_assert<T>(predicate: bool, message: T) {}\\n\\n/// Force a field value to be a witness instead of a constant in the compiled output.\\n/// This is often only useful for debugging compiler optimizations.\\n///\\n/// This has no effect in unconstrained or comptime code.\\n#[builtin(as_witness)]\\npub fn as_witness(x: Field) {}\\n\",\"path\":\"std/lib.nr\",\"function_locations\":[{\"start\":689,\"name\":\"print_oracle\"},{\"start\":763,\"name\":\"print_unconstrained\"},{\"start\":893,\"name\":\"println\"},{\"start\":1076,\"name\":\"print\"},{\"start\":3277,\"name\":\"verify_proof_with_type\"},{\"start\":3694,\"name\":\"verify_proof_internal\"},{\"start\":3859,\"name\":\"assert_constant\"},{\"start\":4118,\"name\":\"static_assert\"},{\"start\":4389,\"name\":\"as_witness\"}]},\"52\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse bb_proof_verification::{UltraHonkProof, UltraHonkVerificationKey, verify_honk_proof_non_zk};\\nuse interfold_lib::math::commitments::compute_vk_hash;\\n\\n/// Binds the four inner `vk_hash` witnesses. Regenerate with `pnpm compute:vk-hash` in\\n/// `examples/CRISP` after changing ct0 / ct1 / user_data_encryption / crisp_onchain (or the lib\\n/// preset). Insecure: `lib::configs::default` uses `insecure::*`; secure: uses `secure::*`.\\npub global CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_INSECURE: Field =\\n 0x06c830801c0712d55b8095ea55a13d5122694f33969a2dfd8694575d37a22b48;\\npub global CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_SECURE: Field =\\n 0x16818150403cb64eb84e5dccc9d68d33c5a8c8e70fb40de649e6b758db10e7fa;\\n\\nfn main(\\n // User Data Encryption Section.\\n user_data_encryption_verification_key: UltraHonkVerificationKey,\\n user_data_encryption_proof: UltraHonkProof,\\n user_data_encryption_public_inputs: [Field; 5], // ct0_key_hash, ct1_key_hash, pk_commitment, ct_commitment, k1_commitment\\n user_data_encryption_key_hash: Field,\\n // Crisp Section.\\n crisp_verification_key: UltraHonkVerificationKey,\\n crisp_proof: UltraHonkProof,\\n crisp_key_hash: Field,\\n prev_ct_commitment: pub Field,\\n digest_hi: pub Field,\\n digest_lo: pub Field,\\n slot_address: pub Field,\\n voting_power: pub Field,\\n is_first_vote: pub bool,\\n num_options: pub u32,\\n final_ct_commitment: pub Field,\\n ct_commitment: Field,\\n k1_commitment: Field,\\n) -> pub Field {\\n verify_honk_proof_non_zk(\\n user_data_encryption_verification_key,\\n user_data_encryption_proof,\\n user_data_encryption_public_inputs,\\n user_data_encryption_key_hash,\\n );\\n verify_honk_proof_non_zk(\\n crisp_verification_key,\\n crisp_proof,\\n [\\n prev_ct_commitment,\\n digest_hi,\\n digest_lo,\\n slot_address,\\n voting_power,\\n if is_first_vote { 1 } else { 0 },\\n num_options as Field,\\n final_ct_commitment,\\n ct_commitment,\\n k1_commitment,\\n ],\\n crisp_key_hash,\\n );\\n\\n // Verify that the ct_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(ct_commitment == user_data_encryption_public_inputs[3]);\\n\\n // Verify that the k1_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(k1_commitment == user_data_encryption_public_inputs[4]);\\n\\n let vk_hashes = [\\n user_data_encryption_key_hash,\\n crisp_key_hash,\\n user_data_encryption_public_inputs[0], // ct0_key_hash\\n user_data_encryption_public_inputs[1], // ct1_key_hash\\n ]\\n .as_vector();\\n\\n let chain_key_hash = compute_vk_hash(vk_hashes);\\n assert(\\n (chain_key_hash == CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_INSECURE)\\n | (chain_key_hash == CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_SECURE),\\n );\\n\\n user_data_encryption_public_inputs[2]\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/examples/CRISP/circuits/bin/fold_onchain/src/main.nr\",\"function_locations\":[{\"start\":1666,\"name\":\"main\"}]},\"53\":{\"source\":\"// Constants for UltraHonk recursive verifier inputs\\npub global PROOF_TYPE_HONK: u32 = 0; // identifier for UltraHonk verfier\\npub global RECURSIVE_PROOF_LENGTH: u32 = 410;\\npub global ULTRA_VK_LENGTH_IN_FIELDS: u32 = 115;\\n\\npub type UltraHonkProof = [Field; RECURSIVE_PROOF_LENGTH];\\npub type UltraHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\n// Constants for Rollup-UltraHonk recursive verifier inputs (N.B. this is equivalent to UH plus IPA claim and proof)\\npub global PROOF_TYPE_ROLLUP_HONK: u32 = 4; // identifier for rollup-UltraHonk verfier\\npub global PROOF_TYPE_ROOT_ROLLUP_HONK: u32 = 5; // identifier for root-rollup-UltraHonk verfier (closes the IPA accumulator)\\npub global IPA_CLAIM_SIZE: u32 = 6;\\npub global IPA_PROOF_LENGTH: u32 = 64;\\npub global RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 =\\n RECURSIVE_PROOF_LENGTH + IPA_CLAIM_SIZE + IPA_PROOF_LENGTH;\\n\\npub type RollupHonkProof = [Field; RECURSIVE_ROLLUP_HONK_PROOF_LENGTH];\\npub type RollupHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\npub global PROOF_TYPE_HONK_ZK: u32 = 6; // identifier for UltraHonk ZK verfier\\npub global RECURSIVE_ZK_PROOF_LENGTH: u32 = 450 + 8;\\n\\npub type UltraHonkZKProof = [Field; RECURSIVE_ZK_PROOF_LENGTH];\\n\\n// Verifies a non-zero-knowledge UltraHonk proof.\\n//\\n// Represents standard UltraHonk recursive verification for proofs that do not hide the witness.\\n// Use this only in situations where zero-knowledge is not required.\\npub fn verify_honk_proof_non_zk<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof with IPA (Inner Product Argument).\\n//\\n// This variant includes an IPA claim and proof appended to the standard UltraHonk proof,\\n// used to amortize IPA recursive verification costs in rollup circuits.\\npub fn verify_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof and closes the IPA accumulator in-circuit.\\n//\\n// Use this at the root of a rollup aggregation tree. The inner proof has the same RollupHonk shape\\n// as `verify_rolluphonk_proof`, but instead of propagating an accumulated IPA claim out as a public\\n// input, this variant performs a full native IPA verification inside the circuit. The outer circuit\\n// should therefore be proved as a standard (non-rollup) UltraHonk circuit, producing a proof\\n// suitable for verification by `verify_honk_proof` / `verify_honk_proof_non_zk`.\\n//\\n// When two RollupHonk inputs are verified this way in one circuit, their two IPA claims are first\\n// accumulated into one, then the accumulated claim is fully verified.\\npub fn verify_root_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROOT_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a zero-knowledge UltraHonk proof.\\n//\\n// This verifier is for UltraHonk proofs constructed with zero-knowledge, which hide the witness\\n// values from the verifier.\\n// Note: We intentionally choose the generic name \\\"verify_honk_proof\\\" for this function, as we\\n// want ZK to be the default unless the user explicitly opts out.\\npub fn verify_honk_proof<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkZKProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK_ZK,\\n );\\n}\\n\",\"path\":\"/home/ace/nargo/github.com/AztecProtocol/aztec-packages/v5.1.0/barretenberg/noir/bb_proof_verification/src/lib.nr\",\"function_locations\":[{\"start\":1646,\"name\":\"verify_honk_proof_non_zk\"},{\"start\":2262,\"name\":\"verify_rolluphonk_proof\"},{\"start\":3386,\"name\":\"verify_root_rolluphonk_proof\"},{\"start\":4087,\"name\":\"verify_honk_proof\"}]},\"87\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse crate::math::helpers::{compute_safe, flatten};\\nuse crate::math::polynomial::Polynomial;\\n\\n/// DOMAIN SEPARATORS\\n\\n// Domain separator - \\\"PK\\\"\\npub global DS_PK: [u8; 64] = [\\n 0x50, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_GENERATION\\\"\\npub global DS_PK_GENERATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_COMPUTATION\\\"\\npub global DS_SHARE_COMPUTATION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_ENCRYPTION\\\"\\npub global DS_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_AGGREGATION\\\"\\npub global DS_PK_AGGREGATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CIPHERTEXT\\\"\\npub global DS_CIPHERTEXT: [u8; 64] = [\\n 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"AGGREGATED_SHARES\\\"\\npub global DS_AGGREGATED_SHARES: [u8; 64] = [\\n 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45,\\n 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"VK_HASH\\\"\\npub global DS_VK_HASH: [u8; 64] = [\\n 0x56, 0x4b, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"RECURSIVE_AGGREGATION\\\"\\npub global DS_RECURSIVE_AGGREGATION: [u8; 64] = [\\n 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47,\\n 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_PK_GENERATION\\\"\\npub global DS_CLG_PK_GENERATION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_ENCRYPTION\\\"\\npub global DS_CLG_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_USER_DATA_ENCRYPTION\\\"\\npub global DS_CLG_USER_DATA_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e,\\n 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_DECRYPTION\\\"\\npub global DS_CLG_SHARE_DECRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"THRESHOLD_DECRYPTION_SHARE\\\"\\npub global DS_THRESHOLD_DECRYPTION_SHARE: [u8; 64] = [\\n 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"USER_DATA_ENCRYPTION_COMMITMENT\\\"\\npub global DS_USER_DATA_ENCRYPTION_COMMITMENT: [u8; 64] = [\\n 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n/// WRAPPERS\\n\\npub fn compute_commitment(inputs: [Field], domain_separator: [u8; 64]) -> Field {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 1])[0]\\n}\\n\\npub fn compute_single_polynomial_commitment<let N: u32, let BIT: u32>(\\n polynomial: Polynomial<N>,\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT>([].as_vector(), polynomial);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_multiple_polynomial_commitment<let N: u32, let L: u32, let BIT: u32>(\\n polynomials: [Polynomial<N>; L],\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT>([].as_vector(), polynomials);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_challenge<let L: u32>(inputs: [Field], domain_separator: [u8; 64]) -> [Field] {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 2 * L])\\n}\\n\\npub fn single_polynomial_payload<let N: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n input: Polynomial<N>,\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, [input])\\n}\\n\\npub fn multiple_polynomial_payload<let N: u32, let L: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n inputs: [Polynomial<N>; L],\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, inputs)\\n}\\n\\n/// COMMITMENTS\\n\\npub fn compute_dkg_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let mut payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n payload = multiple_polynomial_payload::<N, L, BIT_PK>(payload, pk1);\\n\\n compute_commitment(payload, DS_PK)\\n}\\n\\npub fn compute_threshold_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n compute_commitment(payload, DS_PK_GENERATION)\\n}\\n\\npub fn compute_share_computation_sk_commitment<let N: u32, let BIT_SK: u32>(\\n sk: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_SK>([].as_vector(), sk);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_computation_e_sm_commitment<let N: u32, let L: u32, let BIT_E_SM: u32>(\\n e_sm: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_E_SM>([].as_vector(), e_sm);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_encryption_commitment_from_message<let N: u32, let BIT_MSG: u32>(\\n message: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_MSG>([].as_vector(), message);\\n compute_commitment(payload, DS_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_aggregated_shares_commitment<let N: u32, let L: u32, let BIT_MSG: u32>(\\n agg_shares: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_MSG>([].as_vector(), agg_shares);\\n compute_commitment(payload, DS_AGGREGATED_SHARES)\\n}\\n\\n/// Commitment to a threshold decryption share: all CRT limbs, first `K` coefficients per limb\\n/// (same layout as `Polynomial<K>` in decrypted_shares_aggregation).\\n///\\n/// `NATIVE_BIT_WIDTH` must cover native coefficients in \\\\([0, q_l)\\\\) per limb (not centered `d` bounds).\\npub fn compute_threshold_decryption_share_commitment<let K: u32, let L: u32, let NATIVE_BIT_WIDTH: u32>(\\n d_share_limbs: [Polynomial<K>; L],\\n) -> Field {\\n let payload =\\n multiple_polynomial_payload::<K, L, NATIVE_BIT_WIDTH>([].as_vector(), d_share_limbs);\\n compute_commitment(payload, DS_THRESHOLD_DECRYPTION_SHARE)\\n}\\n\\npub fn compute_pk_aggregation_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_pk0 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk0, DS_PK_AGGREGATION);\\n let commit_pk1 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk1, DS_PK_AGGREGATION);\\n\\n let inputs = [commit_pk0, commit_pk1].as_vector();\\n\\n compute_commitment(inputs, DS_PK_AGGREGATION)\\n}\\n\\npub fn compute_recursive_aggregation_commitment(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_RECURSIVE_AGGREGATION)\\n}\\n\\npub fn compute_vk_hash(vk_hashes: [Field]) -> Field {\\n compute_commitment(vk_hashes, DS_VK_HASH)\\n}\\n\\npub fn compute_ciphertext_commitment<let N: u32, let L: u32, let BIT_CT: u32>(\\n ct0: [Polynomial<N>; L],\\n ct1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_ct0 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct0, DS_CIPHERTEXT);\\n let commit_ct1 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct1, DS_CIPHERTEXT);\\n\\n let inputs = [commit_ct0, commit_ct1].as_vector();\\n\\n compute_commitment(inputs, DS_CIPHERTEXT)\\n}\\n\\n/// COMMITMENTS FOR CHALLENGES\\n\\npub fn compute_threshold_pk_challenge(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_CLG_PK_GENERATION)\\n}\\n\\npub fn compute_share_encryption_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_threshold_share_decryption_challenge<let L: u32>(payload: [Field]) -> Field {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_DECRYPTION)[0]\\n}\\n\\npub fn compute_user_data_encryption_ct0_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\\npub fn compute_user_data_encryption_ct1_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/commitments.nr\",\"function_locations\":[{\"start\":7767,\"name\":\"compute_commitment\"},{\"start\":7995,\"name\":\"compute_single_polynomial_commitment\"},{\"start\":8298,\"name\":\"compute_multiple_polynomial_commitment\"},{\"start\":8535,\"name\":\"compute_challenge\"},{\"start\":8745,\"name\":\"single_polynomial_payload\"},{\"start\":8944,\"name\":\"multiple_polynomial_payload\"},{\"start\":9157,\"name\":\"compute_dkg_pk_commitment\"},{\"start\":9484,\"name\":\"compute_threshold_pk_commitment\"},{\"start\":9734,\"name\":\"compute_share_computation_sk_commitment\"},{\"start\":10005,\"name\":\"compute_share_computation_e_sm_commitment\"},{\"start\":10277,\"name\":\"compute_share_encryption_commitment_from_message\"},{\"start\":10553,\"name\":\"compute_aggregated_shares_commitment\"},{\"start\":11134,\"name\":\"compute_threshold_decryption_share_commitment\"},{\"start\":11466,\"name\":\"compute_pk_aggregation_commitment\"},{\"start\":11855,\"name\":\"compute_recursive_aggregation_commitment\"},{\"start\":11970,\"name\":\"compute_vk_hash\"},{\"start\":12169,\"name\":\"compute_ciphertext_commitment\"},{\"start\":12568,\"name\":\"compute_threshold_pk_challenge\"},{\"start\":12710,\"name\":\"compute_share_encryption_challenge\"},{\"start\":12867,\"name\":\"compute_threshold_share_decryption_challenge\"},{\"start\":13027,\"name\":\"compute_user_data_encryption_ct0_challenge\"},{\"start\":13188,\"name\":\"compute_user_data_encryption_ct1_challenge\"}]},\"89\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\n//! Helper functions for circuit construction and cryptographic operations.\\nuse crate::math::polynomial::Polynomial;\\nuse crate::math::safe::SafeSponge;\\n\\n/// Compute hex-aligned packing parameters for a given `BIT`.\\n///\\n/// # Purpose\\n/// Returns `(nibble_bits, group)` for use by pack/flatten so layout stays consistent.\\n/// - `nibble_bits`: ceil (`BIT`) to the next multiple of 4 (nibble alignment).\\n/// - Examples: `BIT = 7 -> 8`, `BIT = 8 -> 8`, `BIT = 9 -> 12`, `BIT = 10 -> 12`, `BIT = 11 -> 12`,\\n/// `BIT=16 -> 16`, `BIT = 17 -> 20`.\\n/// - `group`: max number of encoded limbs that fit in one BN254 field element,\\n/// when each limb uses an extra 4 bits (see below).\\n///\\n/// # Rationale\\n/// - We align to nibbles so powers of two are hex-friendly and deterministic.\\n/// - We reserve one extra nibble (4 bits) per stored value to lift signed\\n/// coefficients into the non-negative range (e.g., store `v + 2^nibble_bits`),\\n/// which implies a radix of `2^(nibble_bits + 4)`.\\n///\\n/// # Safety\\n/// - Asserts `nibble_bits + 4 <= 254` to avoid mod-p wrap on BN254.\\n/// - Ensures at least one limb fits: `group >= 1`.\\nfn packing_layout<let BIT: u32>() -> (u32, u32) {\\n // Ceil BIT up to the next multiple of 4 (nibble alignment).\\n let nibble_bits = ((BIT + 3) / 4) * 4;\\n\\n // Each stored limb uses an extra nibble because negative coefficients\\n // will be shifted to positive, so radix = 2^(nibble_bits+4).\\n assert(nibble_bits + 4 <= 254);\\n\\n // Maximum limbs that fit in one BN254 element without wrap.\\n let group = 254 / (nibble_bits + 4);\\n assert(group >= 1);\\n (nibble_bits, group)\\n}\\n\\n/// Flatten `L` polynomials into a single linear stream of packed `Field` carriers.\\n///\\n/// ## What this does\\n/// - For each CRT limb `j` in `0..L`, it packs the coefficients of `poly[j]`\\n/// with `pack::<A, BIT>` and appends all resulting carriers to `inputs`.\\n/// - The packing layout (nibble-aligned width and `group` size) is taken from\\n/// `packing_layout::<BIT>()` and must match what `pack` uses.\\n///\\n/// ## Determinism & order\\n/// - Preserves a stable order: iterate `j = 0..L`, then for each `j` append\\n/// carriers in ascending chunk index `i = 0..num_chunks`.\\n/// - This ensures transcripts remain deterministic across runs.\\n///\\n/// ## Generics\\n/// - `A`: polynomial degree (number of coefficients per polynomial).\\n/// - `L`: number of CRT bases (polynomials).\\n/// - `BIT`: per-coefficient bit bound used by the packing layout (compile-time).\\n///\\n/// ## Returns\\n/// - The same `inputs` vector, extended with all carriers in deterministic order.\\npub fn flatten<let A: u32, let L: u32, let BIT: u32>(\\n mut inputs: [Field],\\n poly: [Polynomial<A>; L],\\n) -> [Field] {\\n for j in 0..L {\\n // Pack its A coefficients into `num_chunks` carriers using the same BIT layout.\\n let packed = pack::<A, BIT>(poly[j].coefficients);\\n\\n // Append carriers in-order to `inputs` to keep a stable transcript layout.\\n for i in 0..packed.len() {\\n inputs = inputs.push_back(packed[i]);\\n }\\n }\\n\\n // Return the extended input stream.\\n inputs\\n}\\n\\n/// Pack `A` values into a `[Field]` vector of carriers using the shared hex-aligned layout.\\n///\\n/// ## What this does\\n/// - Computes `(nibble_bits, group)` via `packing_layout::<BIT>()`.\\n/// - Encodes each value as a limb `digit = v + 2^nibble_bits` and concatenates\\n/// limbs in base `radix = 2^(nibble_bits + 4)` (one extra nibble of headroom).\\n/// - Packs up to `group` limbs per carrier (fits within BN254 254-bit capacity).\\n/// - Pads the last, partial carrier with `digit = 2^nibble_bits` to keep a stable layout.\\n///\\n/// ## Determinism & order\\n/// - Processes values in increasing index order and emits carriers in chunk order\\n/// (`chunk = 0..num_chunks`). Padding is deterministic.\\n///\\n/// ## Generics\\n/// - `A`: number of input values.\\n/// - `BIT`: per-value bit bound; rounded up to `nibble_bits` by `packing_layout`.\\n///\\n/// ## Preconditions / Notes\\n/// - Call with the raw coefficients whose magnitudes already satisfy the BIT bound\\n/// (as enforced by the upstream range checks); `pack` performs the signed -> unsigned\\n/// shift internally via `v + base`.\\n/// - `group >= 1` is enforced by `packing_layout::<BIT>()`.\\n/// - Padding with `digit = 2^nibble_bits` encodes `zero limb` consistently.\\n///\\n/// ## Returns\\n/// - A `[Field]` vector where each element is a concatenation of up to `group` limbs,\\n/// suitable for hashing or transcript I/O.\\npub fn pack<let A: u32, let BIT: u32>(values: [Field; A]) -> [Field] {\\n // Layout parameters: nibble-aligned width and limbs-per-carrier group size.\\n let (nibble_bits, group) = packing_layout::<BIT>();\\n\\n let base = 2.pow_32(nibble_bits as Field); // 2^nibble_bits\\n let radix = 2.pow_32((nibble_bits + 4) as Field); // 2^(nibble_bits + 4)\\n\\n // Number of chunks to emit: ceil(A / group).\\n let num_chunks = (A + group - 1) / group;\\n let mut out: [Field] = [].as_vector();\\n\\n // Process in fixed-size chunks of `group` limbs.\\n for chunk in 0..num_chunks {\\n // How many real values go into this chunk.\\n let remain = A - (chunk * group);\\n let take = if remain < group { remain } else { group };\\n\\n // Build field element accumulator (big-endian concatenation in `radix`).\\n let mut acc = 0;\\n for i in 0..take {\\n let v = values[chunk * group + i];\\n acc = acc * radix + (v + base);\\n }\\n\\n // Pad remaining limb slots with the canonical zero-limb `digit = base`.\\n for _ in 0..(group - take) {\\n acc = acc * radix + base;\\n }\\n\\n out = out.push_back(acc);\\n }\\n out\\n}\\n\\n/// Computes a cryptographic hash using the SAFE (Sponge API for Field Elements) protocol.\\n///\\n/// This is a convenience wrapper around the SAFE sponge API that handles the full\\n/// lifecycle: initialization, absorption, squeezing, and finalization. It's designed\\n/// for use in Fiat-Shamir challenge generation and commitment schemes within zero-knowledge circuits.\\n///\\n/// # Arguments\\n/// * `domain_separator` - A 64-byte domain separator used to differentiate between\\n/// different protocol instances and prevent cross-protocol attacks.\\n/// * `inputs` - Vector of field elements to be absorbed into the sponge.\\n/// * `io_pattern` - A 2-element array encoding the I/O pattern:\\n/// - `io_pattern[0]`: Encoded ABSORB operation (MSB=1, lower 31 bits = length)\\n/// - `io_pattern[1]`: Encoded SQUEEZE operation (MSB=0, lower 31 bits = length)\\n///\\n/// # Returns\\n/// A vector of field elements squeezed from the sponge, with length determined by\\n/// the SQUEEZE operation in the IO pattern.\\npub fn compute_safe(domain_separator: [u8; 64], inputs: [Field], io_pattern: [u32; 2]) -> [Field] {\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(inputs);\\n let digests = sponge.squeeze();\\n sponge.finish();\\n\\n digests\\n}\\n\\n#[test]\\nfn test_flatten() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([1, 2, 3]); // degree 2\\n let poly2 = Polynomial::new([4, -16, 6]); // degree 2\\n let poly3 = Polynomial::new([-7, 8, 9]); // degree 2\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 4>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n assert(result[0] == 0x11121310101010101010101010101010101010101010101010101010101010);\\n assert(result[1] == 0x14001610101010101010101010101010101010101010101010101010101010); // -16 became 00 at 0x 14 00 16,\\n assert(result[2] == 0x09181910101010101010101010101010101010101010101010101010101010); // -7 became 09 at 0x 09 18 19(16 - 7 = 9)\\n}\\n\\n#[test]\\nfn test_flatten_big() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([\\n 1791218451968394,\\n 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n 5430119342984413,\\n 704811298945172,\\n 8901715723925099,\\n 21888242871839275222246405745257275088548364400416034343698203098124042812559,\\n 21888242871839275222246405745257275088548364400416034343698200215091693880034,\\n ]);\\n let poly2 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698200314078269634250,\\n 21888242871839275222246405745257275088548364400416034343698200967285641915872,\\n 2909990636858607,\\n 7896103832076587,\\n 2078397209533893,\\n 21888242871839275222246405745257275088548364400416034343698199792421452734531,\\n 614400389245817,\\n 8290314119277588,\\n ]);\\n let poly3 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698201373175279892906,\\n 21888242871839275222246405745257275088548364400416034343698201087241869723721,\\n 6768789983786188,\\n 635797784303388,\\n 7610153424227556,\\n 4633893206538324,\\n 2016269760615332,\\n 21888242871839275222246405745257275088548364400416034343698201007080554428142,\\n ]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 54>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n\\n // For the first index of result operation goes like this,\\n\\n // First four index of poly1\\n // 1791218451968394,\\n // 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n // 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n // 5430119342984413,\\n\\n // base + 1791218451968394 = 0x1065d1a8b8b718a\\n // base - 5921327228407753 = 0xeaf69591f3b037 (negative coefficient shifted)\\n // base - 3644467483862151 = 0xf30d604a3a9b79 (negative coefficient shifted)\\n // base + 5430119342984413 = 0x1134aaa2e86ccdd\\n assert(result[0] == 0x1065d1a8b8b718a0eaf69591f3b0370f30d604a3a9b791134aaa2e86ccdd);\\n assert(result[1] == 0x1028105ab1b789411fa010339db66b0fc220f1326bc8e0f1e3f4cc1e02e1);\\n assert(result[2] == 0x0f23dfbe7cd76c90f4901299312ddf10a569efe35acef11c0d76f005412b);\\n assert(result[3] == 0x107624a8f605dc50f0638a368960421022ecb3cf36b7911d73ff2c27ec14);\\n assert(result[4] == 0x0f6013a24e1b9a90f4fd2c158a08481180c2dba8af4cc10242413515171c);\\n assert(result[5] == 0x11b0964eb898ce411076805680b85410729c962da53a40f4b44412d0f6ed);\\n}\\n\\n#[test]\\nfn test_flatten_small() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([712345, 104857, 999999, 500001, 123, 654321, 77]);\\n let poly2 = Polynomial::new([1, 524287, 888888, 23456, 34567, 765432, 0]);\\n let poly3 = Polynomial::new([444444, 333333, 222222, 111111, 987654, 246810, 13579]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 20>(inputs, polynomials);\\n\\n assert(result[0] == 0x1ade991199991f423f17a12110007b19fbf110004d100000100000100000);\\n assert(result[1] == 0x10000117ffff1d9038105ba01087071badf8100000100000100000100000);\\n assert(result[2] == 0x16c81c15161513640e11b2071f120613c41a10350b100000100000100000);\\n}\\n\\n#[test]\\nfn test_safe_hashing_with_safe_helper() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let digests1 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests1.len() == 1);\\n assert(digests1[0] != 0);\\n\\n // Test determinism\\n let digests2 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests2.len() == 1);\\n assert(digests2[0] != 0);\\n assert(digests2[0] == digests1[0]);\\n}\\n\\n#[test]\\nfn test_pack() {\\n // Test pack function directly with small values\\n let values = [1, 2, 3, 4];\\n let packed = pack::<4, 4>(values);\\n\\n // With BIT=4, nibble_bits=4, group should be floor(254/(4+4)) = 31\\n // So all 4 values should fit in one carrier\\n assert(packed.len() >= 1);\\n\\n // Test with negative values\\n let values_neg = [-1, 2, -3, 4];\\n let packed_neg = pack::<4, 4>(values_neg);\\n assert(packed_neg.len() >= 1);\\n}\\n\\n#[test]\\nfn test_pack_single_value() {\\n // Test packing a single value\\n let values = [42];\\n let packed = pack::<1, 8>(values);\\n assert(packed.len() == 1);\\n assert(packed[0] != 0);\\n}\\n\\n#[test]\\nfn test_pack_determinism() {\\n // Test that packing is deterministic\\n let values = [10, 20, 30];\\n let packed1 = pack::<3, 8>(values);\\n let packed2 = pack::<3, 8>(values);\\n\\n assert(packed1.len() == packed2.len());\\n for i in 0..packed1.len() {\\n assert(packed1[i] == packed2[i]);\\n }\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/helpers.nr\",\"function_locations\":[{\"start\":1374,\"name\":\"packing_layout\"},{\"start\":2905,\"name\":\"flatten\"},{\"start\":4755,\"name\":\"pack\"},{\"start\":7016,\"name\":\"compute_safe\"},{\"start\":7214,\"name\":\"test_flatten\"},{\"start\":8157,\"name\":\"test_flatten_big\"},{\"start\":11058,\"name\":\"test_flatten_small\"},{\"start\":11885,\"name\":\"test_safe_hashing_with_safe_helper\"},{\"start\":12731,\"name\":\"test_pack\"},{\"start\":13201,\"name\":\"test_pack_single_value\"},{\"start\":13397,\"name\":\"test_pack_determinism\"}]},\"97\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse keccak256::keccak256;\\nuse poseidon::poseidon2_permutation;\\n\\n/// SAFE (Sponge API for Field Elements)\\n///\\n/// This module provides a complete implementation of the SAFE API in Noir as defined in:\\n/// \\\"SAFE (Sponge API for Field Elements) - A Toolbox for ZK Hash Applications\\\"\\n/// see https://hackmd.io/bHgsH6mMStCVibM_wYvb2w#22-Sponge-state for more details.\\n///\\n/// SAFE provides a unified interface for cryptographic sponge functions that can be\\n/// instantiated with various permutations to create hash functions, MACs, authenticated\\n/// encryption schemes, and other cryptographic primitives for ZK proof systems.\\n///\\n/// This implementation follows the SAFE specification exactly, providing:\\n/// - Complete API: START, ABSORB, SQUEEZE, FINISH operations.\\n/// - Full security: Domain separation, tag computation, IO pattern validation.\\n/// - Poseidon2 integration: Field-friendly permutation for ZK systems.\\n/// - Specification compliance: All operations follow SAFE spec 2.4 exactly.\\n/// - Natural API design: Variable-length inputs, automatic length detection from IO patterns.\\n///\\n/// # API Design\\n///\\n/// The API is designed for natural usage while maintaining type safety:\\n/// - `absorb(input: [Field])`: Accepts variable-length arrays, no padding required.\\n/// - `squeeze()`: Returns a vector with field element(s).\\n/// - IO patterns automatically determine operation lengths for validation.\\n\\n/// Rate parameter for the sponge construction (number of field elements that can be absorbed per permutation call).\\nglobal RATE: u32 = 3;\\n\\n/// Capacity parameter for the sponge construction (security parameter, typically 1-2 field elements).\\nglobal CAPACITY: u32 = 1;\\n\\n/// Total state size (rate + capacity) in field elements.\\nglobal STATE_SIZE: u32 = RATE + CAPACITY;\\n\\n/// IO Pattern encoding constants (from SAFE spec 2.3).\\n///\\n/// These constants are used for encoding operation types in the 32-bit word format:\\n/// - MSB set to 1 for ABSORB operations\\n/// - MSB set to 0 for SQUEEZE operations\\n\\n/// Flag for ABSORB operations (MSB = 1)\\nglobal ABSORB_FLAG: u32 = 0x80000000;\\n\\n/// Flag for SQUEEZE operations (MSB = 0)\\nglobal SQUEEZE_FLAG: u32 = 0x00000000;\\n\\n/// SAFE Sponge State (following spec 2.2)\\n///\\n/// The sponge state consists of the permutation state, tag, position counters,\\n/// and IO pattern tracking as defined in the SAFE specification.\\n///\\n/// # Generic Parameters\\n/// - `L`: The length of the IO pattern array\\n///\\n/// # Fields\\n/// - `state`: Permutation state V in F^n (rate + capacity elements)\\n/// - `tag`: Parameter tag T used for instance differentiation\\n/// - `absorb_pos`: Current absorb position (<= n-c)\\n/// - `squeeze_pos`: Current squeeze position (<= n-c)\\n/// - `io_pattern`: Expected IO pattern for validation (encoded 32-bit words)\\n/// - `io_count`: Current operation count for pattern tracking\\npub struct SafeSponge<let L: u32> {\\n /// Permutation state V in F^n (rate + capacity elements).\\n state: [Field; STATE_SIZE],\\n /// Parameter tag T used for instance differentiation.\\n tag: Field,\\n /// Current absorb position (<= n-c).\\n absorb_pos: u32,\\n /// Current squeeze position (<= n-c).\\n squeeze_pos: u32,\\n /// Expected IO pattern for validation.\\n io_pattern: [u32; L],\\n /// Current operation count for pattern tracking (spec 2.4: io_count).\\n io_count: u32,\\n}\\n\\nimpl<let L: u32> SafeSponge<L> {\\n /// Initializes a new SAFE sponge instance with the given IO pattern and domain separator (following spec 2.4).\\n ///\\n /// # Arguments\\n /// - `io_pattern`: Array of 32-bit encoded operations defining the expected sequence of ABSORB/SQUEEZE calls.\\n /// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n /// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n ///\\n /// # Returns\\n /// A new `SafeSponge` instance with initialized state\\n pub fn start(io_pattern: [u32; L], domain_separator: [u8; 64]) -> SafeSponge<L> {\\n // Compute tag from IO pattern and domain separator (spec 2.3).\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n let mut state = [0; STATE_SIZE];\\n // Initialize capacity with tag (spec 2.4).\\n // Add T to the first 128 bits of the state.\\n state[0] = tag;\\n\\n SafeSponge { state, tag, absorb_pos: 0, squeeze_pos: 0, io_pattern, io_count: 0 }\\n }\\n\\n /// Absorbs field elements into the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to absorb is automatically validated against the IO pattern.\\n /// This method accepts variable-length arrays, making it natural to use without padding.\\n ///\\n /// # Arguments\\n /// - `input`: Array of field elements to absorb (variable length, must match IO pattern)\\n pub fn absorb(&mut self, input: [Field]) {\\n let length = input.len() as u32;\\n\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_absorb = (expected_encoded_word & ABSORB_FLAG) != 0;\\n let expected_length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type and length\\n assert(is_expected_absorb, \\\"Expected ABSORB operation\\\");\\n assert(expected_length == length, \\\"Length mismatch\\\");\\n\\n // Process each element naturally (no unnecessary iterations).\\n for i in 0..length {\\n // If absorb_pos == (n-c) then permute and reset (spec 2.4).\\n if self.absorb_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.absorb_pos = 0;\\n }\\n\\n // Add X[i] to state at absorb_pos (spec 2.4).\\n // Note: absorb_pos is the rate position, not capacity position.\\n self.state[self.absorb_pos + CAPACITY] =\\n self.state[self.absorb_pos + CAPACITY] + input[i];\\n self.absorb_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = ABSORB_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n\\n // Force permute at start of next SQUEEZE (spec 2.4).\\n self.squeeze_pos = RATE;\\n }\\n\\n /// Extracts field elements from the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to squeeze is automatically determined from the IO pattern.\\n pub fn squeeze(&mut self) -> [Field] {\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_squeeze = (expected_encoded_word & ABSORB_FLAG) == 0;\\n let length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type\\n assert(is_expected_squeeze, \\\"Expected SQUEEZE operation\\\");\\n\\n let mut output: [Field] = [].as_vector();\\n\\n // SQUEEZE implementation following spec 2.4.\\n // If length==0, loop won't execute (spec 2.4).\\n for _ in 0..length {\\n // If squeeze_pos==(n-c) then permute and reset (spec 2.4).\\n if self.squeeze_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.squeeze_pos = 0;\\n self.absorb_pos = 0;\\n }\\n // Set Y[i] to state element at squeeze_pos (spec 2.4).\\n output = output.push_back(self.state[self.squeeze_pos + CAPACITY]);\\n self.squeeze_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = SQUEEZE_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n output\\n }\\n\\n /// Finalizes the sponge instance, verifying that all expected operations have been performed and clearing the internal state for security (following spec 2.4).\\n ///\\n /// This function is used to ensure that the sponge instance has been used correctly and to prevent information leakage.\\n pub fn finish(&mut self) {\\n // Check that io_count equals the length of the IO pattern expected (spec 2.4).\\n assert(self.io_count == L, \\\"IO pattern not completed\\\");\\n\\n // Erase the state and its variables (spec 2.4).\\n self.state = [0; STATE_SIZE];\\n self.absorb_pos = 0;\\n self.squeeze_pos = 0;\\n self.io_count = 0;\\n }\\n\\n /// Permute the state using Poseidon2 (following spec 2.4).\\n ///\\n /// Applies the Poseidon2 permutation to the current state.\\n /// This is the core cryptographic primitive of the sponge construction.\\n ///\\n /// # Returns\\n /// New state after permutation\\n fn permute(self) -> [Field; STATE_SIZE] {\\n poseidon2_permutation(self.state)\\n }\\n}\\n\\n/// Computes a unique tag for a sponge instance based on its IO pattern and domain separator.\\n/// The tag is used to ensure that distinct instances behave like distinct functions.\\n///\\n/// # Arguments\\n/// - `io_pattern`: Array of 32-bit encoded operations defining the sponge's usage pattern.\\n/// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n/// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n///\\n/// # Returns\\n/// A field element representing the 128-bit tag.\\npub fn compute_tag<let L: u32>(io_pattern: [u32; L], domain_separator: [u8; 64]) -> Field {\\n // Step 1: Parse and aggregate consecutive operations of the same type\\n let mut encoded_words = [0; L]; // Support up to L operations.\\n let mut word_count = 0;\\n let mut current_absorb_sum = 0;\\n let mut current_squeeze_sum = 0;\\n let mut last_was_absorb = false;\\n\\n for i in 0..L {\\n if io_pattern[i] > 0 {\\n // Parse operation type from MSB and length from lower 31 bits\\n let is_absorb = (io_pattern[i] & ABSORB_FLAG) != 0;\\n let length = io_pattern[i] & 0x7FFFFFFF; // Clear MSB to get length\\n\\n if is_absorb {\\n if last_was_absorb {\\n // Aggregate consecutive ABSORB operations\\n current_absorb_sum += length;\\n } else {\\n // Start new ABSORB sequence\\n if current_squeeze_sum > 0 {\\n // Flush previous SQUEEZE sequence\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n current_squeeze_sum = 0;\\n }\\n current_absorb_sum = length;\\n }\\n last_was_absorb = true;\\n } else {\\n if !last_was_absorb {\\n // Aggregate consecutive SQUEEZE operations\\n current_squeeze_sum += length;\\n } else {\\n // Start new SQUEEZE sequence\\n if current_absorb_sum > 0 {\\n // Flush previous ABSORB sequence\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n current_absorb_sum = 0;\\n }\\n current_squeeze_sum = length;\\n }\\n last_was_absorb = false;\\n }\\n }\\n }\\n\\n // Flush remaining operations\\n if current_absorb_sum > 0 {\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n }\\n if current_squeeze_sum > 0 {\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n }\\n\\n // Step 2: Serialize to byte string and append domain separator (following SAFE spec 2.3).\\n // Buffer is 256 bytes: max 192 bytes for IO pattern (48 words) + 64 bytes for domain separator.\\n // Note: We must use a fixed-size array because Noir's keccak256 requires [u8; N], not [u8].\\n let max_io_pattern_bytes: u32 = 192; // 256 - 64 (domain separator)\\n let io_pattern_bytes = word_count * 4;\\n assert(\\n io_pattern_bytes <= max_io_pattern_bytes,\\n \\\"IO pattern too large: max 48 aggregated words supported\\\",\\n );\\n\\n let mut input_bytes = [0u8; 256];\\n let mut byte_count: u32 = 0;\\n\\n // Serialize encoded words to bytes (big-endian as per SAFE spec).\\n // Note: Noir requires compile-time loop bounds, so we iterate over L (the array size)\\n // instead of word_count (runtime value). The condition `i < word_count` ensures we only\\n // process valid encoded words. This is safe because word_count <= L always holds\\n // (we can have at most L encoded words from L input operations).\\n for i in 0..L {\\n if i < word_count {\\n let word = encoded_words[i];\\n input_bytes[byte_count] = (word >> 24) as u8;\\n input_bytes[byte_count + 1] = (word >> 16) as u8;\\n input_bytes[byte_count + 2] = (word >> 8) as u8;\\n input_bytes[byte_count + 3] = word as u8;\\n byte_count += 4;\\n }\\n }\\n\\n // Append full 64-byte domain separator.\\n for i in 0..64 {\\n input_bytes[byte_count] = domain_separator[i];\\n byte_count += 1;\\n }\\n\\n // Step 3: Hash with Keccak-256 and truncate to 128 bits.\\n // Note: The SAFE spec uses SHA3-256, but we use Keccak-256 for Noir compatibility.\\n // Keccak-256 differs from SHA3-256 in padding, but both provide equivalent security.\\n let hash_bytes = keccak256(input_bytes, byte_count);\\n\\n // Convert first 128 bits (16 bytes) to field element.\\n let mut tag_value: Field = 0;\\n for i in 0..16 {\\n tag_value = tag_value * 256 + (hash_bytes[i] as Field);\\n }\\n\\n tag_value\\n}\\n\\n#[test]\\nfn test_safe_hashing() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_merkle_node() {\\n // Verifies SAFE can be used for Merkle tree node hashing with pattern ABSORB(1) + ABSORB(1) + SQUEEZE(1).\\n // Tests the ability to absorb multiple inputs before squeezing output.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let left = [123].as_vector();\\n let right = [456].as_vector();\\n\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(left);\\n sponge.absorb(right);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(left);\\n sponge2.absorb(right);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_commitment_scheme() {\\n // Verifies SAFE can be used for commitment schemes with pattern ABSORB(3) + SQUEEZE(1).\\n // Tests the ability to create deterministic commitments from multiple field elements.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let values = [10, 20, 30].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(values);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(values);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_domain_separation() {\\n // Verifies that different domain separators produce different outputs for the same input.\\n // This is crucial for cross-protocol security and preventing collisions between different applications.\\n let elements = [1, 2, 3].as_vector();\\n let domain1 = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let domain2 = [\\n 0x41, 0x42, 0x43, 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n\\n let mut sponge1 = SafeSponge::start(io_pattern, domain1);\\n sponge1.absorb(elements);\\n let output1 = sponge1.squeeze();\\n sponge1.finish();\\n\\n let mut sponge2 = SafeSponge::start(io_pattern, domain2);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output1.len() == 1);\\n assert(output2.len() == 1);\\n assert(output1[0] != output2[0]); // Different domain separators should produce different outputs\\n}\\n\\n#[test]\\nfn test_multiple_squeeze() {\\n // Verifies that multiple field elements can be squeezed in a single operation.\\n // Tests pattern ABSORB(3) + SQUEEZE(2) to ensure proper state management.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(2)\\n let io_pattern = [0x80000003, 0x00000002];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 2);\\n assert(output[0] != 0);\\n assert(output[1] != 0);\\n assert(output[0] != output[1]); // Different squeeze outputs should be different\\n}\\n\\n#[test]\\nfn test_zero_length_operations() {\\n // Verifies that zero-length ABSORB and SQUEEZE operations are handled correctly.\\n // Tests pattern ABSORB(0) + SQUEEZE(1) to ensure proper state transitions.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(0), SQUEEZE(1)\\n let io_pattern = [0x80000000, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb([].as_vector());\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n}\\n\\n#[test]\\nfn test_tag_computation() {\\n // Verifies the tag computation algorithm using the example from the SAFE specification.\\n // Pattern: ABSORB(3), ABSORB(3), SQUEEZE(3)\\n // Should aggregate to: ABSORB(6), SQUEEZE(3)\\n // Encoded as: [0x80000006, 0x00000003]\\n // Tests determinism and pattern differentiation.\\n\\n let io_pattern = [0x80000003, 0x80000003, 0x00000003];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test determinism\\n let tag2 = compute_tag(io_pattern, domain_separator);\\n assert(tag == tag2);\\n\\n // Test that different patterns produce different tags\\n let io_pattern2 = [0x80000003, 0x00000003]; // ABSORB(3), SQUEEZE(3) - different pattern\\n let tag3 = compute_tag(io_pattern2, domain_separator);\\n assert(tag != tag3);\\n}\\n\\n#[test]\\nfn test_tag_computation_debug() {\\n println(\\\"=== SAFE Tag Computation Debug Test ===\\\");\\n\\n // Test your specific pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\n let io_pattern = [0x80000002, 0x00000002, 0x80000002];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n println(f\\\"Testing pattern: {io_pattern}\\\");\\n println(\\n f\\\"Expected to aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(2)\\\",\\n );\\n println(\\n f\\\"Expected encoded words: [0x80000002, 0x00000002, 0x80000002]\\\",\\n );\\n println(\\\"\\\");\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n println(f\\\"=== Expected Rust Output ===\\\");\\n println(\\\"Pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\\");\\n println(\\\"Domain separator: 0x41424344...\\\");\\n println(\\\"Tag: 0xce3bb9ee4b2d41c42e9cdda38afe8b6a\\\");\\n println(\\\"\\\");\\n\\n println(f\\\"=== Noir Output ===\\\");\\n println(f\\\"Tag: {tag}\\\");\\n println(\\\"\\\");\\n\\n println(\\\"Compare the tag values above with Rust script!\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_absorb_aggregation() {\\n // Test that consecutive ABSORB operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1) should aggregate to ABSORB(2), SQUEEZE(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(1) = [0x80000002, 0x00000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(2), SQUEEZE(1)\\n let aggregated_pattern = [0x80000002, 0x00000001];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Consecutive ABSORB operations should aggregate to the same tag\\\");\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive ABSORB operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive ABSORB Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001] (ABSORB(1), ABSORB(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000002, 0x00000001] (ABSORB(2), SQUEEZE(1))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_squeeze_aggregation() {\\n // Test that consecutive SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1) should aggregate to ABSORB(1), SQUEEZE(2)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x00000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(1), SQUEEZE(2) = [0x80000001, 0x00000002]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(1), SQUEEZE(2)\\n let aggregated_pattern = [0x80000001, 0x00000002];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(\\n tag == aggregated_tag,\\n \\\"Consecutive SQUEEZE operations should aggregate to the same tag\\\",\\n );\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive SQUEEZE operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive SQUEEZE Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x00000001, 0x00000001] (ABSORB(1), SQUEEZE(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000001, 0x00000002] (ABSORB(1), SQUEEZE(2))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_mixed_consecutive_aggregation() {\\n // Test that both consecutive ABSORB and SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n // Should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1) = [0x80000002, 0x00000002, 0x80000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag\\n let aggregated_pattern = [0x80000002, 0x00000002, 0x80000001]; // ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Mixed consecutive operations should aggregate to the same tag\\\");\\n\\n println(\\\"=== Mixed Consecutive Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001]\\\",\\n );\\n println(\\n f\\\" (ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1))\\\",\\n );\\n println(f\\\"Aggregated pattern: [0x80000002, 0x00000002, 0x80000001]\\\");\\n println(f\\\" (ABSORB(2), SQUEEZE(2), ABSORB(1))\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n}\\n\\n#[test]\\nfn test_large_io_pattern() {\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Create pattern with 48 alternating ABSORB(1) and SQUEEZE(1) operations\\n // This is the maximum supported (48 words * 4 bytes = 192 bytes, leaving 64 for domain separator)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1; // ABSORB(1)\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1; // SQUEEZE(1)\\n }\\n }\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n assert(tag != 0);\\n}\\n\\n#[test]\\nfn test_domain_separator_not_truncated() {\\n // This test verifies that the domain separator is always included in the tag computation,\\n // even for large IO patterns. If the domain separator were truncated, different domain\\n // separators would produce the same tag for large patterns.\\n\\n let domain_separator_a = [\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41,\\n ]; // All 'A's\\n\\n let domain_separator_b = [\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42,\\n ]; // All 'B's\\n\\n // Create pattern with 48 alternating operations (max supported: 192 bytes of IO pattern)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1;\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1;\\n }\\n }\\n\\n let tag_a = compute_tag(io_pattern, domain_separator_a);\\n let tag_b = compute_tag(io_pattern, domain_separator_b);\\n\\n // Tags MUST be different because domain separators are different.\\n // If they were the same, it would mean the domain separator was truncated/ignored.\\n assert(tag_a != tag_b, \\\"Domain separator must affect tag even for large IO patterns\\\");\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/safe.nr\",\"function_locations\":[{\"start\":4164,\"name\":\"SafeSponge<L>::start\"},{\"start\":5046,\"name\":\"SafeSponge<L>::absorb\"},{\"start\":6826,\"name\":\"SafeSponge<L>::squeeze\"},{\"start\":8494,\"name\":\"SafeSponge<L>::finish\"},{\"start\":9156,\"name\":\"SafeSponge<L>::permute\"},{\"start\":9830,\"name\":\"compute_tag\"},{\"start\":14128,\"name\":\"test_safe_hashing\"},{\"start\":15104,\"name\":\"test_merkle_node\"},{\"start\":16281,\"name\":\"test_commitment_scheme\"},{\"start\":17357,\"name\":\"test_domain_separation\"},{\"start\":18710,\"name\":\"test_multiple_squeeze\"},{\"start\":19639,\"name\":\"test_zero_length_operations\"},{\"start\":20415,\"name\":\"test_tag_computation\"},{\"start\":21477,\"name\":\"test_tag_computation_debug\"},{\"start\":22681,\"name\":\"test_consecutive_absorb_aggregation\"},{\"start\":24750,\"name\":\"test_consecutive_squeeze_aggregation\"},{\"start\":26760,\"name\":\"test_mixed_consecutive_aggregation\"},{\"start\":28520,\"name\":\"test_large_io_pattern\"},{\"start\":29333,\"name\":\"test_domain_separator_not_truncated\"}]}}}","{\"noir_version\":\"1.0.0-beta.26+40d6574f851d926f93e0c3a271bac3e6e82ac905\",\"hash\":\"2093582182953941705\",\"abi\":{\"parameters\":[{\"name\":\"ct0_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct0_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct0_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":4,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct0_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"ct1_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct1_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct1_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":3,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct1_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"}],\"return_type\":{\"abi_type\":{\"kind\":\"tuple\",\"fields\":[{\"kind\":\"field\"},{\"kind\":\"field\"},{\"kind\":\"field\"}]},\"visibility\":\"public\"},\"error_types\":{}},\"bytecode\":\"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\",\"debug_symbols\":\"tZbdioMwEIXfJddeZCb/+yrLUmybFkFUrC4spe++sW0SXUholb2aapwv5zjHkis52v143lXNqb2Qj88r2fdVXVfnXd0eyqFqG3f3eiuIv9wNvbXuFpmtu66u7G0zkI9mrOuCfJf1eH/o0pXNvQ5l71ZpQWxzdNUBT1Vtp1+3InbTdKtW+tkMlKrQL3ABgDQApEBPUIZFAlsQME1gLGhgXEIgIL5qAigwrwE4plzwzS7Ev7pAGVygZikXWYJWnsDS08wShIwEvYbAZCRouYqgQyb5Og2ch/fADSRTnQmlUsoPQ2keh6HVEsEyCGp8phRQERFmicjEUgI1T4QEHgdq3lABLBiZI/6qkBmE5MGIFDypQqURBkIqDBiTROjMB2bCB8YpxNcJ6nUjWsShGkypyCVLKD8QEDMfb2RTUvAEibCKIGn4r0p/H8g2pxv55nSj2JzurIrX0o1qc7pRb043ms3pzhrZnm7FREiWEItkfbmr8lD1iwMMoU55QcANsCDotioIc72u8EcRjyLdY25fNZXbtH9flfvaPs9Ap7E5zI5Ew0/nV/yhqevbgz2OvZ12v685Pb8=\",\"file_map\":{\"17\":{\"source\":\"// Exposed only for usage in `std::meta`\\npub(crate) mod poseidon2;\\n\\nuse crate::default::Default;\\nuse crate::embedded_curve_ops::{\\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\\n};\\nuse crate::meta::derive_via;\\nuse crate::static_assert;\\n\\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\\n\\n#[foreign(sha256_compression)]\\n// docs:start:sha256_compression\\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\\n// docs:end:sha256_compression\\n\\n#[foreign(keccakf1600)]\\n// docs:start:keccakf1600\\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\\n// docs:end:keccakf1600\\n\\n#[foreign(blake2s)]\\n// docs:start:blake2s\\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake2s\\n{}\\n\\n// docs:start:blake3\\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake3\\n{\\n if crate::runtime::is_unconstrained() {\\n // Temporary measure while Barretenberg is main proving system.\\n // Please open an issue if you're working on another proving system and running into problems due to this.\\n crate::static_assert(\\n N <= 1024,\\n \\\"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\\\",\\n );\\n }\\n __blake3(input)\\n}\\n\\n#[foreign(blake3)]\\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\\n\\n// docs:start:pedersen_commitment\\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\\n // docs:end:pedersen_commitment\\n pedersen_commitment_with_separator(input, 0)\\n}\\n\\n#[inline_always]\\npub fn pedersen_commitment_with_separator<let N: u32>(\\n input: [Field; N],\\n separator: u32,\\n) -> EmbeddedCurvePoint {\\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\\n for i in 0..N {\\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\\n }\\n let generators = derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n multi_scalar_mul(generators, points)\\n}\\n\\n// docs:start:pedersen_hash\\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\\n// docs:end:pedersen_hash\\n{\\n pedersen_hash_with_separator(input, 0)\\n}\\n\\n#[no_predicates]\\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\\n let mut generators: [EmbeddedCurvePoint; N + 1] =\\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\\n crate::assert_constant(separator);\\n let domain_generators: [EmbeddedCurvePoint; N] =\\n derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n\\n for i in 0..N {\\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\\n generators[i] = domain_generators[i];\\n }\\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\\n\\n let length_generator: [EmbeddedCurvePoint; 1] =\\n derive_generators(\\\"pedersen_hash_length\\\".as_bytes(), 0);\\n generators[N] = length_generator[0];\\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\\n}\\n\\n#[field(bn254)]\\n#[inline_always]\\npub fn derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {\\n crate::assert_constant(domain_separator_bytes);\\n crate::assert_constant(starting_index);\\n __derive_generators(domain_separator_bytes, starting_index)\\n}\\n\\n#[builtin(derive_pedersen_generators)]\\n#[field(bn254)]\\nfn __derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {}\\n\\npub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {\\n static_assert(\\n N == POSEIDON2_CONFIG_STATE_SIZE,\\n f\\\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\\\",\\n );\\n poseidon2_permutation_internal(input)\\n}\\n\\n#[foreign(poseidon2_permutation)]\\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\\n\\n#[foreign(poseidon2_config_state_size)]\\ncomptime fn poseidon2_config_state_size() -> u32 {}\\n\\n// Generic hashing support.\\n// Partially ported and impacted by rust.\\n\\n// Hash trait shall be implemented per type.\\n#[derive_via(derive_hash)]\\npub trait Hash {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher;\\n}\\n\\n// docs:start:derive_hash\\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\\n let name = quote { $crate::hash::Hash };\\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\\n let for_each_field = |name| quote { _self.$name.hash(_state); };\\n crate::meta::make_trait_impl(\\n s,\\n name,\\n signature,\\n for_each_field,\\n quote {},\\n |fields| fields,\\n )\\n}\\n// docs:end:derive_hash\\n\\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\\n// TODO: consider making the types generic here ([u8], [Field], etc.)\\npub trait Hasher {\\n fn finish(self) -> Field;\\n\\n /// Returns the hash value without consuming the hasher.\\n /// Override this for more efficient implementations that avoid copying.\\n /// TODO: deprecate finish() and replace it\\n fn finish_ref(&self) -> Field {\\n (*self).finish()\\n }\\n\\n fn write(&mut self, input: Field);\\n}\\n\\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\\npub trait BuildHasher {\\n type H: Hasher;\\n\\n fn build_hasher(self) -> H;\\n}\\n\\npub struct BuildHasherDefault<H>;\\n\\nimpl<H> BuildHasher for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n type H = H;\\n\\n fn build_hasher(_self: Self) -> H {\\n H::default()\\n }\\n}\\n\\nimpl<H> Default for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n fn default() -> Self {\\n BuildHasherDefault {}\\n }\\n}\\n\\nimpl Hash for Field {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self);\\n }\\n}\\n\\nimpl Hash for u8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u128 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for i8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u8 as Field);\\n }\\n}\\n\\nimpl Hash for i16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u16 as Field);\\n }\\n}\\n\\nimpl Hash for i32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u32 as Field);\\n }\\n}\\n\\nimpl Hash for i64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u64 as Field);\\n }\\n}\\n\\nimpl Hash for bool {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for () {\\n fn hash<H>(_self: Self, _state: &mut H)\\n where\\n H: Hasher,\\n {}\\n}\\n\\nimpl<T, let N: u32> Hash for [T; N]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<T> Hash for [T]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.len().hash(state);\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<A> Hash for (A,)\\nwhere\\n A: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n }\\n}\\n\\nimpl<A, B> Hash for (A, B)\\nwhere\\n A: Hash,\\n B: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n }\\n}\\n\\nimpl<A, B, C> Hash for (A, B, C)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D> Hash for (A, B, C, D)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F> Hash for (A, B, C, D, E, F)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G> Hash for (A, B, C, D, E, F, G)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_> Hash for (A, B, C, D, E, F, G, H_)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I> Hash for (A, B, C, D, E, F, G, H_, I)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J> Hash for (A, B, C, D, E, F, G, H_, I, J)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K> Hash for (A, B, C, D, E, F, G, H_, I, J, K)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K, L> Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n L: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n self.11.hash(state);\\n }\\n}\\n\\n// Some test vectors for Pedersen hash and Pedersen Commitment.\\n// They have been generated using the same functions so the tests are for now useless\\n// but they will be useful when we switch to Noir implementation.\\n#[test]\\nfn assert_pedersen() {\\n assert_eq(\\n pedersen_hash_with_separator([1], 1),\\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1], 1),\\n EmbeddedCurvePoint {\\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\\n },\\n );\\n\\n assert_eq(\\n pedersen_hash_with_separator([1, 2], 2),\\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2], 2),\\n EmbeddedCurvePoint {\\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3], 3),\\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3], 3),\\n EmbeddedCurvePoint {\\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\\n EmbeddedCurvePoint {\\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\\n EmbeddedCurvePoint {\\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\\n EmbeddedCurvePoint {\\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n EmbeddedCurvePoint {\\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n EmbeddedCurvePoint {\\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n EmbeddedCurvePoint {\\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n EmbeddedCurvePoint {\\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\\n },\\n );\\n}\\n\",\"path\":\"std/hash/mod.nr\",\"function_locations\":[{\"start\":572,\"name\":\"sha256_compression\"},{\"start\":707,\"name\":\"keccakf1600\"},{\"start\":852,\"name\":\"blake2s\"},{\"start\":950,\"name\":\"blake3\"},{\"start\":1437,\"name\":\"__blake3\"},{\"start\":1555,\"name\":\"pedersen_commitment\"},{\"start\":1784,\"name\":\"pedersen_commitment_with_separator\"},{\"start\":2188,\"name\":\"pedersen_hash\"},{\"start\":2345,\"name\":\"pedersen_hash_with_separator\"},{\"start\":3339,\"name\":\"derive_generators\"},{\"start\":3698,\"name\":\"__derive_generators\"},{\"start\":3776,\"name\":\"poseidon2_permutation\"},{\"start\":4132,\"name\":\"poseidon2_permutation_internal\"},{\"start\":4225,\"name\":\"poseidon2_config_state_size\"},{\"start\":4536,\"name\":\"derive_hash\"},{\"start\":5327,\"name\":\"Hasher::finish_ref\"},{\"start\":5761,\"name\":\"<impl BuildHasher for BuildHasherDefault<H>>::build_hasher\"},{\"start\":5893,\"name\":\"<impl Default for BuildHasherDefault<H>>::default\"},{\"start\":6025,\"name\":\"<impl Hash for Field>::hash\"},{\"start\":6155,\"name\":\"<impl Hash for u8>::hash\"},{\"start\":6295,\"name\":\"<impl Hash for u16>::hash\"},{\"start\":6435,\"name\":\"<impl Hash for u32>::hash\"},{\"start\":6575,\"name\":\"<impl Hash for u64>::hash\"},{\"start\":6716,\"name\":\"<impl Hash for u128>::hash\"},{\"start\":6855,\"name\":\"<impl Hash for i8>::hash\"},{\"start\":7001,\"name\":\"<impl Hash for i16>::hash\"},{\"start\":7148,\"name\":\"<impl Hash for i32>::hash\"},{\"start\":7295,\"name\":\"<impl Hash for i64>::hash\"},{\"start\":7443,\"name\":\"<impl Hash for bool>::hash\"},{\"start\":7590,\"name\":\"<impl Hash for ()>::hash\"},{\"start\":7722,\"name\":\"<impl Hash for [T; N]>::hash\"},{\"start\":7911,\"name\":\"<impl Hash for [T]>::hash\"},{\"start\":8133,\"name\":\"<impl Hash for (A,)>::hash\"},{\"start\":8302,\"name\":\"<impl Hash for (A, B)>::hash\"},{\"start\":8518,\"name\":\"<impl Hash for (A, B, C)>::hash\"},{\"start\":8781,\"name\":\"<impl Hash for (A, B, C, D)>::hash\"},{\"start\":9091,\"name\":\"<impl Hash for (A, B, C, D, E)>::hash\"},{\"start\":9448,\"name\":\"<impl Hash for (A, B, C, D, E, F)>::hash\"},{\"start\":9852,\"name\":\"<impl Hash for (A, B, C, D, E, F, G)>::hash\"},{\"start\":10306,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_)>::hash\"},{\"start\":10807,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I)>::hash\"},{\"start\":11355,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J)>::hash\"},{\"start\":11950,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K)>::hash\"},{\"start\":12593,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)>::hash\"},{\"start\":13187,\"name\":\"assert_pedersen\"}]},\"22\":{\"source\":\"pub mod hash;\\npub mod aes128;\\npub mod array;\\npub mod vector;\\npub mod ecdsa_secp256k1;\\npub mod ecdsa_secp256r1;\\npub mod embedded_curve_ops;\\npub mod field;\\npub mod collections;\\npub mod compat;\\npub mod convert;\\npub mod option;\\npub mod string;\\npub mod test;\\npub mod cmp;\\npub mod ops;\\npub mod default;\\npub mod prelude;\\npub mod runtime;\\npub mod meta;\\npub mod append;\\npub mod mem;\\npub mod panic;\\npub mod hint;\\n\\nmod integer;\\nmod primitive_docs;\\nmod internal;\\n\\n// Oracle calls are required to be wrapped in an unconstrained function\\n// Thus, the only argument to the `println` oracle is expected to always be an ident\\n#[oracle(print)]\\nunconstrained fn print_oracle<T>(with_newline: bool, input: T) {}\\n\\nunconstrained fn print_unconstrained<T>(with_newline: bool, input: T) {\\n print_oracle(with_newline, input);\\n}\\n\\n/// Print the given input to stdout followed by a newline\\npub fn println<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(true, input);\\n }\\n}\\n\\n/// Print the given input to stdout\\npub fn print<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(false, input);\\n }\\n}\\n\\n/// Asserts the validity of the provided proof and public inputs against the provided verification key and hash.\\n///\\n/// The ACVM cannot determine whether the provided proof is valid during execution as this requires knowledge of\\n/// the backend against which the program is being proven. However if an invalid proof if submitted, the program may\\n/// fail to prove or the backend may generate a proof which will subsequently fail to verify.\\n///\\n/// # Important Note\\n///\\n/// If you are not developing your own backend such as [Barretenberg](https://github.com/AztecProtocol/barretenberg)\\n/// you probably shouldn't need to interact with this function directly. It's easier and safer to use a verification\\n/// library which is published by the developers of the backend which will document or enforce any safety requirements.\\n///\\n/// If you use this directly, you're liable to introduce underconstrainedness bugs and *your circuit will be insecure*.\\n///\\n/// # Arguments\\n/// - verification_key: The verification key of the circuit to be verified.\\n/// - proof: The proof to be verified.\\n/// - public_inputs: The public inputs associated with `proof`\\n/// - key_hash: The hash of `verification_key` of the form expected by the backend.\\n/// - proof_type: An identifier for the proving scheme used to generate the proof to be verified. This allows\\n/// for a single backend to support verifying multiple proving schemes.\\n///\\n/// # Constraining `key_hash`\\n///\\n/// The Noir compiler does not by itself constrain that `key_hash` is a valid hash of `verification_key`.\\n/// This is because different backends may differ in how they hash their verification keys.\\n/// It is then the responsibility of either the noir developer (by explicitly hashing the verification key\\n/// in the correct manner) or by the proving system itself internally asserting the correctness of `key_hash`.\\npub fn verify_proof_with_type<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {\\n if !crate::runtime::is_unconstrained() {\\n crate::assert_constant(proof_type);\\n }\\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\\n}\\n\\n#[foreign(recursive_aggregation)]\\nfn verify_proof_internal<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {}\\n\\n/// Asserts that the given value is known at compile-time.\\n/// Useful for debugging for-loop bounds.\\n#[builtin(assert_constant)]\\npub fn assert_constant<T>(x: T) {}\\n\\n/// Asserts that the given value is both true and known at compile-time.\\n/// The message can be a string, a format string, or any value, as long as it is known at compile-time\\n#[builtin(static_assert)]\\npub fn static_assert<T>(predicate: bool, message: T) {}\\n\\n/// Force a field value to be a witness instead of a constant in the compiled output.\\n/// This is often only useful for debugging compiler optimizations.\\n///\\n/// This has no effect in unconstrained or comptime code.\\n#[builtin(as_witness)]\\npub fn as_witness(x: Field) {}\\n\",\"path\":\"std/lib.nr\",\"function_locations\":[{\"start\":689,\"name\":\"print_oracle\"},{\"start\":763,\"name\":\"print_unconstrained\"},{\"start\":893,\"name\":\"println\"},{\"start\":1076,\"name\":\"print\"},{\"start\":3277,\"name\":\"verify_proof_with_type\"},{\"start\":3694,\"name\":\"verify_proof_internal\"},{\"start\":3859,\"name\":\"assert_constant\"},{\"start\":4118,\"name\":\"static_assert\"},{\"start\":4389,\"name\":\"as_witness\"}]},\"52\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse bb_proof_verification::{UltraHonkProof, UltraHonkVerificationKey, verify_honk_proof_non_zk};\\nuse lib::math::commitments::{compute_commitment, DS_CIPHERTEXT, DS_PK_AGGREGATION};\\n\\nfn main(\\n // P3: ct0 inner proof.\\n ct0_verification_key: UltraHonkVerificationKey,\\n ct0_proof: UltraHonkProof,\\n ct0_public_inputs: [Field; 4], // pk0_commitment, ct0_commitment, k1_commitment, u_commitment\\n ct0_key_hash: pub Field,\\n // P3: ct1 inner proof.\\n ct1_verification_key: UltraHonkVerificationKey,\\n ct1_proof: UltraHonkProof,\\n ct1_public_inputs: [Field; 3], // pk1_commitment, ct1_commitment, u_commitment\\n ct1_key_hash: pub Field,\\n) -> pub (Field, Field, Field) {\\n verify_honk_proof_non_zk(\\n ct0_verification_key,\\n ct0_proof,\\n ct0_public_inputs,\\n ct0_key_hash,\\n );\\n verify_honk_proof_non_zk(\\n ct1_verification_key,\\n ct1_proof,\\n ct1_public_inputs,\\n ct1_key_hash,\\n );\\n\\n // Verify that the u_commitment from the ct0 proof is the same as the u_commitment from the ct1 proof.\\n assert(ct0_public_inputs[3] == ct1_public_inputs[2]);\\n\\n // Compute the ct commitment.\\n let ct_inputs = [ct0_public_inputs[1], ct1_public_inputs[1]].as_vector();\\n let ct_commitment = compute_commitment(ct_inputs, DS_CIPHERTEXT);\\n\\n // Threshold PK aggregation commitment (pk0 and pk1 limbs).\\n let pk_inputs = [ct0_public_inputs[0], ct1_public_inputs[0]].as_vector();\\n let pk_commitment = compute_commitment(pk_inputs, DS_PK_AGGREGATION);\\n\\n let k1_commitment = ct0_public_inputs[2];\\n\\n (pk_commitment, ct_commitment, k1_commitment)\\n}\\n\",\"path\":\"interfold/circuits/bin/threshold/user_data_encryption/src/main.nr\",\"function_locations\":[{\"start\":872,\"name\":\"main\"}]},\"53\":{\"source\":\"// Constants for UltraHonk recursive verifier inputs\\npub global PROOF_TYPE_HONK: u32 = 0; // identifier for UltraHonk verfier\\npub global RECURSIVE_PROOF_LENGTH: u32 = 410;\\npub global ULTRA_VK_LENGTH_IN_FIELDS: u32 = 115;\\n\\npub type UltraHonkProof = [Field; RECURSIVE_PROOF_LENGTH];\\npub type UltraHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\n// Constants for Rollup-UltraHonk recursive verifier inputs (N.B. this is equivalent to UH plus IPA claim and proof)\\npub global PROOF_TYPE_ROLLUP_HONK: u32 = 4; // identifier for rollup-UltraHonk verfier\\npub global PROOF_TYPE_ROOT_ROLLUP_HONK: u32 = 5; // identifier for root-rollup-UltraHonk verfier (closes the IPA accumulator)\\npub global IPA_CLAIM_SIZE: u32 = 6;\\npub global IPA_PROOF_LENGTH: u32 = 64;\\npub global RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 =\\n RECURSIVE_PROOF_LENGTH + IPA_CLAIM_SIZE + IPA_PROOF_LENGTH;\\n\\npub type RollupHonkProof = [Field; RECURSIVE_ROLLUP_HONK_PROOF_LENGTH];\\npub type RollupHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\npub global PROOF_TYPE_HONK_ZK: u32 = 6; // identifier for UltraHonk ZK verfier\\npub global RECURSIVE_ZK_PROOF_LENGTH: u32 = 450 + 8;\\n\\npub type UltraHonkZKProof = [Field; RECURSIVE_ZK_PROOF_LENGTH];\\n\\n// Verifies a non-zero-knowledge UltraHonk proof.\\n//\\n// Represents standard UltraHonk recursive verification for proofs that do not hide the witness.\\n// Use this only in situations where zero-knowledge is not required.\\npub fn verify_honk_proof_non_zk<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof with IPA (Inner Product Argument).\\n//\\n// This variant includes an IPA claim and proof appended to the standard UltraHonk proof,\\n// used to amortize IPA recursive verification costs in rollup circuits.\\npub fn verify_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof and closes the IPA accumulator in-circuit.\\n//\\n// Use this at the root of a rollup aggregation tree. The inner proof has the same RollupHonk shape\\n// as `verify_rolluphonk_proof`, but instead of propagating an accumulated IPA claim out as a public\\n// input, this variant performs a full native IPA verification inside the circuit. The outer circuit\\n// should therefore be proved as a standard (non-rollup) UltraHonk circuit, producing a proof\\n// suitable for verification by `verify_honk_proof` / `verify_honk_proof_non_zk`.\\n//\\n// When two RollupHonk inputs are verified this way in one circuit, their two IPA claims are first\\n// accumulated into one, then the accumulated claim is fully verified.\\npub fn verify_root_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROOT_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a zero-knowledge UltraHonk proof.\\n//\\n// This verifier is for UltraHonk proofs constructed with zero-knowledge, which hide the witness\\n// values from the verifier.\\n// Note: We intentionally choose the generic name \\\"verify_honk_proof\\\" for this function, as we\\n// want ZK to be the default unless the user explicitly opts out.\\npub fn verify_honk_proof<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkZKProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK_ZK,\\n );\\n}\\n\",\"path\":\"/home/ace/nargo/github.com/AztecProtocol/aztec-packages/v5.1.0/barretenberg/noir/bb_proof_verification/src/lib.nr\",\"function_locations\":[{\"start\":1646,\"name\":\"verify_honk_proof_non_zk\"},{\"start\":2262,\"name\":\"verify_rolluphonk_proof\"},{\"start\":3386,\"name\":\"verify_root_rolluphonk_proof\"},{\"start\":4087,\"name\":\"verify_honk_proof\"}]},\"87\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse crate::math::helpers::{compute_safe, flatten};\\nuse crate::math::polynomial::Polynomial;\\n\\n/// DOMAIN SEPARATORS\\n\\n// Domain separator - \\\"PK\\\"\\npub global DS_PK: [u8; 64] = [\\n 0x50, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_GENERATION\\\"\\npub global DS_PK_GENERATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_COMPUTATION\\\"\\npub global DS_SHARE_COMPUTATION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_ENCRYPTION\\\"\\npub global DS_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_AGGREGATION\\\"\\npub global DS_PK_AGGREGATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CIPHERTEXT\\\"\\npub global DS_CIPHERTEXT: [u8; 64] = [\\n 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"AGGREGATED_SHARES\\\"\\npub global DS_AGGREGATED_SHARES: [u8; 64] = [\\n 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45,\\n 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"VK_HASH\\\"\\npub global DS_VK_HASH: [u8; 64] = [\\n 0x56, 0x4b, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"RECURSIVE_AGGREGATION\\\"\\npub global DS_RECURSIVE_AGGREGATION: [u8; 64] = [\\n 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47,\\n 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_PK_GENERATION\\\"\\npub global DS_CLG_PK_GENERATION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_ENCRYPTION\\\"\\npub global DS_CLG_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_USER_DATA_ENCRYPTION\\\"\\npub global DS_CLG_USER_DATA_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e,\\n 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_DECRYPTION\\\"\\npub global DS_CLG_SHARE_DECRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"THRESHOLD_DECRYPTION_SHARE\\\"\\npub global DS_THRESHOLD_DECRYPTION_SHARE: [u8; 64] = [\\n 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"USER_DATA_ENCRYPTION_COMMITMENT\\\"\\npub global DS_USER_DATA_ENCRYPTION_COMMITMENT: [u8; 64] = [\\n 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n/// WRAPPERS\\n\\npub fn compute_commitment(inputs: [Field], domain_separator: [u8; 64]) -> Field {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 1])[0]\\n}\\n\\npub fn compute_single_polynomial_commitment<let N: u32, let BIT: u32>(\\n polynomial: Polynomial<N>,\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT>([].as_vector(), polynomial);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_multiple_polynomial_commitment<let N: u32, let L: u32, let BIT: u32>(\\n polynomials: [Polynomial<N>; L],\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT>([].as_vector(), polynomials);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_challenge<let L: u32>(inputs: [Field], domain_separator: [u8; 64]) -> [Field] {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 2 * L])\\n}\\n\\npub fn single_polynomial_payload<let N: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n input: Polynomial<N>,\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, [input])\\n}\\n\\npub fn multiple_polynomial_payload<let N: u32, let L: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n inputs: [Polynomial<N>; L],\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, inputs)\\n}\\n\\n/// COMMITMENTS\\n\\npub fn compute_dkg_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let mut payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n payload = multiple_polynomial_payload::<N, L, BIT_PK>(payload, pk1);\\n\\n compute_commitment(payload, DS_PK)\\n}\\n\\npub fn compute_threshold_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n compute_commitment(payload, DS_PK_GENERATION)\\n}\\n\\npub fn compute_share_computation_sk_commitment<let N: u32, let BIT_SK: u32>(\\n sk: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_SK>([].as_vector(), sk);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_computation_e_sm_commitment<let N: u32, let L: u32, let BIT_E_SM: u32>(\\n e_sm: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_E_SM>([].as_vector(), e_sm);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_encryption_commitment_from_message<let N: u32, let BIT_MSG: u32>(\\n message: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_MSG>([].as_vector(), message);\\n compute_commitment(payload, DS_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_aggregated_shares_commitment<let N: u32, let L: u32, let BIT_MSG: u32>(\\n agg_shares: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_MSG>([].as_vector(), agg_shares);\\n compute_commitment(payload, DS_AGGREGATED_SHARES)\\n}\\n\\n/// Commitment to a threshold decryption share: all CRT limbs, first `K` coefficients per limb\\n/// (same layout as `Polynomial<K>` in decrypted_shares_aggregation).\\n///\\n/// `NATIVE_BIT_WIDTH` must cover native coefficients in \\\\([0, q_l)\\\\) per limb (not centered `d` bounds).\\npub fn compute_threshold_decryption_share_commitment<let K: u32, let L: u32, let NATIVE_BIT_WIDTH: u32>(\\n d_share_limbs: [Polynomial<K>; L],\\n) -> Field {\\n let payload =\\n multiple_polynomial_payload::<K, L, NATIVE_BIT_WIDTH>([].as_vector(), d_share_limbs);\\n compute_commitment(payload, DS_THRESHOLD_DECRYPTION_SHARE)\\n}\\n\\npub fn compute_pk_aggregation_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_pk0 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk0, DS_PK_AGGREGATION);\\n let commit_pk1 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk1, DS_PK_AGGREGATION);\\n\\n let inputs = [commit_pk0, commit_pk1].as_vector();\\n\\n compute_commitment(inputs, DS_PK_AGGREGATION)\\n}\\n\\npub fn compute_recursive_aggregation_commitment(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_RECURSIVE_AGGREGATION)\\n}\\n\\npub fn compute_vk_hash(vk_hashes: [Field]) -> Field {\\n compute_commitment(vk_hashes, DS_VK_HASH)\\n}\\n\\npub fn compute_ciphertext_commitment<let N: u32, let L: u32, let BIT_CT: u32>(\\n ct0: [Polynomial<N>; L],\\n ct1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_ct0 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct0, DS_CIPHERTEXT);\\n let commit_ct1 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct1, DS_CIPHERTEXT);\\n\\n let inputs = [commit_ct0, commit_ct1].as_vector();\\n\\n compute_commitment(inputs, DS_CIPHERTEXT)\\n}\\n\\n/// COMMITMENTS FOR CHALLENGES\\n\\npub fn compute_threshold_pk_challenge(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_CLG_PK_GENERATION)\\n}\\n\\npub fn compute_share_encryption_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_threshold_share_decryption_challenge<let L: u32>(payload: [Field]) -> Field {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_DECRYPTION)[0]\\n}\\n\\npub fn compute_user_data_encryption_ct0_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\\npub fn compute_user_data_encryption_ct1_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\",\"path\":\"interfold/circuits/lib/src/math/commitments.nr\",\"function_locations\":[{\"start\":7767,\"name\":\"compute_commitment\"},{\"start\":7995,\"name\":\"compute_single_polynomial_commitment\"},{\"start\":8298,\"name\":\"compute_multiple_polynomial_commitment\"},{\"start\":8535,\"name\":\"compute_challenge\"},{\"start\":8745,\"name\":\"single_polynomial_payload\"},{\"start\":8944,\"name\":\"multiple_polynomial_payload\"},{\"start\":9157,\"name\":\"compute_dkg_pk_commitment\"},{\"start\":9484,\"name\":\"compute_threshold_pk_commitment\"},{\"start\":9734,\"name\":\"compute_share_computation_sk_commitment\"},{\"start\":10005,\"name\":\"compute_share_computation_e_sm_commitment\"},{\"start\":10277,\"name\":\"compute_share_encryption_commitment_from_message\"},{\"start\":10553,\"name\":\"compute_aggregated_shares_commitment\"},{\"start\":11134,\"name\":\"compute_threshold_decryption_share_commitment\"},{\"start\":11466,\"name\":\"compute_pk_aggregation_commitment\"},{\"start\":11855,\"name\":\"compute_recursive_aggregation_commitment\"},{\"start\":11970,\"name\":\"compute_vk_hash\"},{\"start\":12169,\"name\":\"compute_ciphertext_commitment\"},{\"start\":12568,\"name\":\"compute_threshold_pk_challenge\"},{\"start\":12710,\"name\":\"compute_share_encryption_challenge\"},{\"start\":12867,\"name\":\"compute_threshold_share_decryption_challenge\"},{\"start\":13027,\"name\":\"compute_user_data_encryption_ct0_challenge\"},{\"start\":13188,\"name\":\"compute_user_data_encryption_ct1_challenge\"}]},\"89\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\n//! Helper functions for circuit construction and cryptographic operations.\\nuse crate::math::polynomial::Polynomial;\\nuse crate::math::safe::SafeSponge;\\n\\n/// Compute hex-aligned packing parameters for a given `BIT`.\\n///\\n/// # Purpose\\n/// Returns `(nibble_bits, group)` for use by pack/flatten so layout stays consistent.\\n/// - `nibble_bits`: ceil (`BIT`) to the next multiple of 4 (nibble alignment).\\n/// - Examples: `BIT = 7 -> 8`, `BIT = 8 -> 8`, `BIT = 9 -> 12`, `BIT = 10 -> 12`, `BIT = 11 -> 12`,\\n/// `BIT=16 -> 16`, `BIT = 17 -> 20`.\\n/// - `group`: max number of encoded limbs that fit in one BN254 field element,\\n/// when each limb uses an extra 4 bits (see below).\\n///\\n/// # Rationale\\n/// - We align to nibbles so powers of two are hex-friendly and deterministic.\\n/// - We reserve one extra nibble (4 bits) per stored value to lift signed\\n/// coefficients into the non-negative range (e.g., store `v + 2^nibble_bits`),\\n/// which implies a radix of `2^(nibble_bits + 4)`.\\n///\\n/// # Safety\\n/// - Asserts `nibble_bits + 4 <= 254` to avoid mod-p wrap on BN254.\\n/// - Ensures at least one limb fits: `group >= 1`.\\nfn packing_layout<let BIT: u32>() -> (u32, u32) {\\n // Ceil BIT up to the next multiple of 4 (nibble alignment).\\n let nibble_bits = ((BIT + 3) / 4) * 4;\\n\\n // Each stored limb uses an extra nibble because negative coefficients\\n // will be shifted to positive, so radix = 2^(nibble_bits+4).\\n assert(nibble_bits + 4 <= 254);\\n\\n // Maximum limbs that fit in one BN254 element without wrap.\\n let group = 254 / (nibble_bits + 4);\\n assert(group >= 1);\\n (nibble_bits, group)\\n}\\n\\n/// Flatten `L` polynomials into a single linear stream of packed `Field` carriers.\\n///\\n/// ## What this does\\n/// - For each CRT limb `j` in `0..L`, it packs the coefficients of `poly[j]`\\n/// with `pack::<A, BIT>` and appends all resulting carriers to `inputs`.\\n/// - The packing layout (nibble-aligned width and `group` size) is taken from\\n/// `packing_layout::<BIT>()` and must match what `pack` uses.\\n///\\n/// ## Determinism & order\\n/// - Preserves a stable order: iterate `j = 0..L`, then for each `j` append\\n/// carriers in ascending chunk index `i = 0..num_chunks`.\\n/// - This ensures transcripts remain deterministic across runs.\\n///\\n/// ## Generics\\n/// - `A`: polynomial degree (number of coefficients per polynomial).\\n/// - `L`: number of CRT bases (polynomials).\\n/// - `BIT`: per-coefficient bit bound used by the packing layout (compile-time).\\n///\\n/// ## Returns\\n/// - The same `inputs` vector, extended with all carriers in deterministic order.\\npub fn flatten<let A: u32, let L: u32, let BIT: u32>(\\n mut inputs: [Field],\\n poly: [Polynomial<A>; L],\\n) -> [Field] {\\n for j in 0..L {\\n // Pack its A coefficients into `num_chunks` carriers using the same BIT layout.\\n let packed = pack::<A, BIT>(poly[j].coefficients);\\n\\n // Append carriers in-order to `inputs` to keep a stable transcript layout.\\n for i in 0..packed.len() {\\n inputs = inputs.push_back(packed[i]);\\n }\\n }\\n\\n // Return the extended input stream.\\n inputs\\n}\\n\\n/// Pack `A` values into a `[Field]` vector of carriers using the shared hex-aligned layout.\\n///\\n/// ## What this does\\n/// - Computes `(nibble_bits, group)` via `packing_layout::<BIT>()`.\\n/// - Encodes each value as a limb `digit = v + 2^nibble_bits` and concatenates\\n/// limbs in base `radix = 2^(nibble_bits + 4)` (one extra nibble of headroom).\\n/// - Packs up to `group` limbs per carrier (fits within BN254 254-bit capacity).\\n/// - Pads the last, partial carrier with `digit = 2^nibble_bits` to keep a stable layout.\\n///\\n/// ## Determinism & order\\n/// - Processes values in increasing index order and emits carriers in chunk order\\n/// (`chunk = 0..num_chunks`). Padding is deterministic.\\n///\\n/// ## Generics\\n/// - `A`: number of input values.\\n/// - `BIT`: per-value bit bound; rounded up to `nibble_bits` by `packing_layout`.\\n///\\n/// ## Preconditions / Notes\\n/// - Call with the raw coefficients whose magnitudes already satisfy the BIT bound\\n/// (as enforced by the upstream range checks); `pack` performs the signed -> unsigned\\n/// shift internally via `v + base`.\\n/// - `group >= 1` is enforced by `packing_layout::<BIT>()`.\\n/// - Padding with `digit = 2^nibble_bits` encodes `zero limb` consistently.\\n///\\n/// ## Returns\\n/// - A `[Field]` vector where each element is a concatenation of up to `group` limbs,\\n/// suitable for hashing or transcript I/O.\\npub fn pack<let A: u32, let BIT: u32>(values: [Field; A]) -> [Field] {\\n // Layout parameters: nibble-aligned width and limbs-per-carrier group size.\\n let (nibble_bits, group) = packing_layout::<BIT>();\\n\\n let base = 2.pow_32(nibble_bits as Field); // 2^nibble_bits\\n let radix = 2.pow_32((nibble_bits + 4) as Field); // 2^(nibble_bits + 4)\\n\\n // Number of chunks to emit: ceil(A / group).\\n let num_chunks = (A + group - 1) / group;\\n let mut out: [Field] = [].as_vector();\\n\\n // Process in fixed-size chunks of `group` limbs.\\n for chunk in 0..num_chunks {\\n // How many real values go into this chunk.\\n let remain = A - (chunk * group);\\n let take = if remain < group { remain } else { group };\\n\\n // Build field element accumulator (big-endian concatenation in `radix`).\\n let mut acc = 0;\\n for i in 0..take {\\n let v = values[chunk * group + i];\\n acc = acc * radix + (v + base);\\n }\\n\\n // Pad remaining limb slots with the canonical zero-limb `digit = base`.\\n for _ in 0..(group - take) {\\n acc = acc * radix + base;\\n }\\n\\n out = out.push_back(acc);\\n }\\n out\\n}\\n\\n/// Computes a cryptographic hash using the SAFE (Sponge API for Field Elements) protocol.\\n///\\n/// This is a convenience wrapper around the SAFE sponge API that handles the full\\n/// lifecycle: initialization, absorption, squeezing, and finalization. It's designed\\n/// for use in Fiat-Shamir challenge generation and commitment schemes within zero-knowledge circuits.\\n///\\n/// # Arguments\\n/// * `domain_separator` - A 64-byte domain separator used to differentiate between\\n/// different protocol instances and prevent cross-protocol attacks.\\n/// * `inputs` - Vector of field elements to be absorbed into the sponge.\\n/// * `io_pattern` - A 2-element array encoding the I/O pattern:\\n/// - `io_pattern[0]`: Encoded ABSORB operation (MSB=1, lower 31 bits = length)\\n/// - `io_pattern[1]`: Encoded SQUEEZE operation (MSB=0, lower 31 bits = length)\\n///\\n/// # Returns\\n/// A vector of field elements squeezed from the sponge, with length determined by\\n/// the SQUEEZE operation in the IO pattern.\\npub fn compute_safe(domain_separator: [u8; 64], inputs: [Field], io_pattern: [u32; 2]) -> [Field] {\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(inputs);\\n let digests = sponge.squeeze();\\n sponge.finish();\\n\\n digests\\n}\\n\\n#[test]\\nfn test_flatten() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([1, 2, 3]); // degree 2\\n let poly2 = Polynomial::new([4, -16, 6]); // degree 2\\n let poly3 = Polynomial::new([-7, 8, 9]); // degree 2\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 4>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n assert(result[0] == 0x11121310101010101010101010101010101010101010101010101010101010);\\n assert(result[1] == 0x14001610101010101010101010101010101010101010101010101010101010); // -16 became 00 at 0x 14 00 16,\\n assert(result[2] == 0x09181910101010101010101010101010101010101010101010101010101010); // -7 became 09 at 0x 09 18 19(16 - 7 = 9)\\n}\\n\\n#[test]\\nfn test_flatten_big() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([\\n 1791218451968394,\\n 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n 5430119342984413,\\n 704811298945172,\\n 8901715723925099,\\n 21888242871839275222246405745257275088548364400416034343698203098124042812559,\\n 21888242871839275222246405745257275088548364400416034343698200215091693880034,\\n ]);\\n let poly2 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698200314078269634250,\\n 21888242871839275222246405745257275088548364400416034343698200967285641915872,\\n 2909990636858607,\\n 7896103832076587,\\n 2078397209533893,\\n 21888242871839275222246405745257275088548364400416034343698199792421452734531,\\n 614400389245817,\\n 8290314119277588,\\n ]);\\n let poly3 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698201373175279892906,\\n 21888242871839275222246405745257275088548364400416034343698201087241869723721,\\n 6768789983786188,\\n 635797784303388,\\n 7610153424227556,\\n 4633893206538324,\\n 2016269760615332,\\n 21888242871839275222246405745257275088548364400416034343698201007080554428142,\\n ]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 54>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n\\n // For the first index of result operation goes like this,\\n\\n // First four index of poly1\\n // 1791218451968394,\\n // 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n // 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n // 5430119342984413,\\n\\n // base + 1791218451968394 = 0x1065d1a8b8b718a\\n // base - 5921327228407753 = 0xeaf69591f3b037 (negative coefficient shifted)\\n // base - 3644467483862151 = 0xf30d604a3a9b79 (negative coefficient shifted)\\n // base + 5430119342984413 = 0x1134aaa2e86ccdd\\n assert(result[0] == 0x1065d1a8b8b718a0eaf69591f3b0370f30d604a3a9b791134aaa2e86ccdd);\\n assert(result[1] == 0x1028105ab1b789411fa010339db66b0fc220f1326bc8e0f1e3f4cc1e02e1);\\n assert(result[2] == 0x0f23dfbe7cd76c90f4901299312ddf10a569efe35acef11c0d76f005412b);\\n assert(result[3] == 0x107624a8f605dc50f0638a368960421022ecb3cf36b7911d73ff2c27ec14);\\n assert(result[4] == 0x0f6013a24e1b9a90f4fd2c158a08481180c2dba8af4cc10242413515171c);\\n assert(result[5] == 0x11b0964eb898ce411076805680b85410729c962da53a40f4b44412d0f6ed);\\n}\\n\\n#[test]\\nfn test_flatten_small() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([712345, 104857, 999999, 500001, 123, 654321, 77]);\\n let poly2 = Polynomial::new([1, 524287, 888888, 23456, 34567, 765432, 0]);\\n let poly3 = Polynomial::new([444444, 333333, 222222, 111111, 987654, 246810, 13579]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 20>(inputs, polynomials);\\n\\n assert(result[0] == 0x1ade991199991f423f17a12110007b19fbf110004d100000100000100000);\\n assert(result[1] == 0x10000117ffff1d9038105ba01087071badf8100000100000100000100000);\\n assert(result[2] == 0x16c81c15161513640e11b2071f120613c41a10350b100000100000100000);\\n}\\n\\n#[test]\\nfn test_safe_hashing_with_safe_helper() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let digests1 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests1.len() == 1);\\n assert(digests1[0] != 0);\\n\\n // Test determinism\\n let digests2 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests2.len() == 1);\\n assert(digests2[0] != 0);\\n assert(digests2[0] == digests1[0]);\\n}\\n\\n#[test]\\nfn test_pack() {\\n // Test pack function directly with small values\\n let values = [1, 2, 3, 4];\\n let packed = pack::<4, 4>(values);\\n\\n // With BIT=4, nibble_bits=4, group should be floor(254/(4+4)) = 31\\n // So all 4 values should fit in one carrier\\n assert(packed.len() >= 1);\\n\\n // Test with negative values\\n let values_neg = [-1, 2, -3, 4];\\n let packed_neg = pack::<4, 4>(values_neg);\\n assert(packed_neg.len() >= 1);\\n}\\n\\n#[test]\\nfn test_pack_single_value() {\\n // Test packing a single value\\n let values = [42];\\n let packed = pack::<1, 8>(values);\\n assert(packed.len() == 1);\\n assert(packed[0] != 0);\\n}\\n\\n#[test]\\nfn test_pack_determinism() {\\n // Test that packing is deterministic\\n let values = [10, 20, 30];\\n let packed1 = pack::<3, 8>(values);\\n let packed2 = pack::<3, 8>(values);\\n\\n assert(packed1.len() == packed2.len());\\n for i in 0..packed1.len() {\\n assert(packed1[i] == packed2[i]);\\n }\\n}\\n\",\"path\":\"interfold/circuits/lib/src/math/helpers.nr\",\"function_locations\":[{\"start\":1374,\"name\":\"packing_layout\"},{\"start\":2905,\"name\":\"flatten\"},{\"start\":4755,\"name\":\"pack\"},{\"start\":7016,\"name\":\"compute_safe\"},{\"start\":7214,\"name\":\"test_flatten\"},{\"start\":8157,\"name\":\"test_flatten_big\"},{\"start\":11058,\"name\":\"test_flatten_small\"},{\"start\":11885,\"name\":\"test_safe_hashing_with_safe_helper\"},{\"start\":12731,\"name\":\"test_pack\"},{\"start\":13201,\"name\":\"test_pack_single_value\"},{\"start\":13397,\"name\":\"test_pack_determinism\"}]},\"97\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse keccak256::keccak256;\\nuse poseidon::poseidon2_permutation;\\n\\n/// SAFE (Sponge API for Field Elements)\\n///\\n/// This module provides a complete implementation of the SAFE API in Noir as defined in:\\n/// \\\"SAFE (Sponge API for Field Elements) - A Toolbox for ZK Hash Applications\\\"\\n/// see https://hackmd.io/bHgsH6mMStCVibM_wYvb2w#22-Sponge-state for more details.\\n///\\n/// SAFE provides a unified interface for cryptographic sponge functions that can be\\n/// instantiated with various permutations to create hash functions, MACs, authenticated\\n/// encryption schemes, and other cryptographic primitives for ZK proof systems.\\n///\\n/// This implementation follows the SAFE specification exactly, providing:\\n/// - Complete API: START, ABSORB, SQUEEZE, FINISH operations.\\n/// - Full security: Domain separation, tag computation, IO pattern validation.\\n/// - Poseidon2 integration: Field-friendly permutation for ZK systems.\\n/// - Specification compliance: All operations follow SAFE spec 2.4 exactly.\\n/// - Natural API design: Variable-length inputs, automatic length detection from IO patterns.\\n///\\n/// # API Design\\n///\\n/// The API is designed for natural usage while maintaining type safety:\\n/// - `absorb(input: [Field])`: Accepts variable-length arrays, no padding required.\\n/// - `squeeze()`: Returns a vector with field element(s).\\n/// - IO patterns automatically determine operation lengths for validation.\\n\\n/// Rate parameter for the sponge construction (number of field elements that can be absorbed per permutation call).\\nglobal RATE: u32 = 3;\\n\\n/// Capacity parameter for the sponge construction (security parameter, typically 1-2 field elements).\\nglobal CAPACITY: u32 = 1;\\n\\n/// Total state size (rate + capacity) in field elements.\\nglobal STATE_SIZE: u32 = RATE + CAPACITY;\\n\\n/// IO Pattern encoding constants (from SAFE spec 2.3).\\n///\\n/// These constants are used for encoding operation types in the 32-bit word format:\\n/// - MSB set to 1 for ABSORB operations\\n/// - MSB set to 0 for SQUEEZE operations\\n\\n/// Flag for ABSORB operations (MSB = 1)\\nglobal ABSORB_FLAG: u32 = 0x80000000;\\n\\n/// Flag for SQUEEZE operations (MSB = 0)\\nglobal SQUEEZE_FLAG: u32 = 0x00000000;\\n\\n/// SAFE Sponge State (following spec 2.2)\\n///\\n/// The sponge state consists of the permutation state, tag, position counters,\\n/// and IO pattern tracking as defined in the SAFE specification.\\n///\\n/// # Generic Parameters\\n/// - `L`: The length of the IO pattern array\\n///\\n/// # Fields\\n/// - `state`: Permutation state V in F^n (rate + capacity elements)\\n/// - `tag`: Parameter tag T used for instance differentiation\\n/// - `absorb_pos`: Current absorb position (<= n-c)\\n/// - `squeeze_pos`: Current squeeze position (<= n-c)\\n/// - `io_pattern`: Expected IO pattern for validation (encoded 32-bit words)\\n/// - `io_count`: Current operation count for pattern tracking\\npub struct SafeSponge<let L: u32> {\\n /// Permutation state V in F^n (rate + capacity elements).\\n state: [Field; STATE_SIZE],\\n /// Parameter tag T used for instance differentiation.\\n tag: Field,\\n /// Current absorb position (<= n-c).\\n absorb_pos: u32,\\n /// Current squeeze position (<= n-c).\\n squeeze_pos: u32,\\n /// Expected IO pattern for validation.\\n io_pattern: [u32; L],\\n /// Current operation count for pattern tracking (spec 2.4: io_count).\\n io_count: u32,\\n}\\n\\nimpl<let L: u32> SafeSponge<L> {\\n /// Initializes a new SAFE sponge instance with the given IO pattern and domain separator (following spec 2.4).\\n ///\\n /// # Arguments\\n /// - `io_pattern`: Array of 32-bit encoded operations defining the expected sequence of ABSORB/SQUEEZE calls.\\n /// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n /// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n ///\\n /// # Returns\\n /// A new `SafeSponge` instance with initialized state\\n pub fn start(io_pattern: [u32; L], domain_separator: [u8; 64]) -> SafeSponge<L> {\\n // Compute tag from IO pattern and domain separator (spec 2.3).\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n let mut state = [0; STATE_SIZE];\\n // Initialize capacity with tag (spec 2.4).\\n // Add T to the first 128 bits of the state.\\n state[0] = tag;\\n\\n SafeSponge { state, tag, absorb_pos: 0, squeeze_pos: 0, io_pattern, io_count: 0 }\\n }\\n\\n /// Absorbs field elements into the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to absorb is automatically validated against the IO pattern.\\n /// This method accepts variable-length arrays, making it natural to use without padding.\\n ///\\n /// # Arguments\\n /// - `input`: Array of field elements to absorb (variable length, must match IO pattern)\\n pub fn absorb(&mut self, input: [Field]) {\\n let length = input.len() as u32;\\n\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_absorb = (expected_encoded_word & ABSORB_FLAG) != 0;\\n let expected_length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type and length\\n assert(is_expected_absorb, \\\"Expected ABSORB operation\\\");\\n assert(expected_length == length, \\\"Length mismatch\\\");\\n\\n // Process each element naturally (no unnecessary iterations).\\n for i in 0..length {\\n // If absorb_pos == (n-c) then permute and reset (spec 2.4).\\n if self.absorb_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.absorb_pos = 0;\\n }\\n\\n // Add X[i] to state at absorb_pos (spec 2.4).\\n // Note: absorb_pos is the rate position, not capacity position.\\n self.state[self.absorb_pos + CAPACITY] =\\n self.state[self.absorb_pos + CAPACITY] + input[i];\\n self.absorb_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = ABSORB_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n\\n // Force permute at start of next SQUEEZE (spec 2.4).\\n self.squeeze_pos = RATE;\\n }\\n\\n /// Extracts field elements from the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to squeeze is automatically determined from the IO pattern.\\n pub fn squeeze(&mut self) -> [Field] {\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_squeeze = (expected_encoded_word & ABSORB_FLAG) == 0;\\n let length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type\\n assert(is_expected_squeeze, \\\"Expected SQUEEZE operation\\\");\\n\\n let mut output: [Field] = [].as_vector();\\n\\n // SQUEEZE implementation following spec 2.4.\\n // If length==0, loop won't execute (spec 2.4).\\n for _ in 0..length {\\n // If squeeze_pos==(n-c) then permute and reset (spec 2.4).\\n if self.squeeze_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.squeeze_pos = 0;\\n self.absorb_pos = 0;\\n }\\n // Set Y[i] to state element at squeeze_pos (spec 2.4).\\n output = output.push_back(self.state[self.squeeze_pos + CAPACITY]);\\n self.squeeze_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = SQUEEZE_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n output\\n }\\n\\n /// Finalizes the sponge instance, verifying that all expected operations have been performed and clearing the internal state for security (following spec 2.4).\\n ///\\n /// This function is used to ensure that the sponge instance has been used correctly and to prevent information leakage.\\n pub fn finish(&mut self) {\\n // Check that io_count equals the length of the IO pattern expected (spec 2.4).\\n assert(self.io_count == L, \\\"IO pattern not completed\\\");\\n\\n // Erase the state and its variables (spec 2.4).\\n self.state = [0; STATE_SIZE];\\n self.absorb_pos = 0;\\n self.squeeze_pos = 0;\\n self.io_count = 0;\\n }\\n\\n /// Permute the state using Poseidon2 (following spec 2.4).\\n ///\\n /// Applies the Poseidon2 permutation to the current state.\\n /// This is the core cryptographic primitive of the sponge construction.\\n ///\\n /// # Returns\\n /// New state after permutation\\n fn permute(self) -> [Field; STATE_SIZE] {\\n poseidon2_permutation(self.state)\\n }\\n}\\n\\n/// Computes a unique tag for a sponge instance based on its IO pattern and domain separator.\\n/// The tag is used to ensure that distinct instances behave like distinct functions.\\n///\\n/// # Arguments\\n/// - `io_pattern`: Array of 32-bit encoded operations defining the sponge's usage pattern.\\n/// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n/// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n///\\n/// # Returns\\n/// A field element representing the 128-bit tag.\\npub fn compute_tag<let L: u32>(io_pattern: [u32; L], domain_separator: [u8; 64]) -> Field {\\n // Step 1: Parse and aggregate consecutive operations of the same type\\n let mut encoded_words = [0; L]; // Support up to L operations.\\n let mut word_count = 0;\\n let mut current_absorb_sum = 0;\\n let mut current_squeeze_sum = 0;\\n let mut last_was_absorb = false;\\n\\n for i in 0..L {\\n if io_pattern[i] > 0 {\\n // Parse operation type from MSB and length from lower 31 bits\\n let is_absorb = (io_pattern[i] & ABSORB_FLAG) != 0;\\n let length = io_pattern[i] & 0x7FFFFFFF; // Clear MSB to get length\\n\\n if is_absorb {\\n if last_was_absorb {\\n // Aggregate consecutive ABSORB operations\\n current_absorb_sum += length;\\n } else {\\n // Start new ABSORB sequence\\n if current_squeeze_sum > 0 {\\n // Flush previous SQUEEZE sequence\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n current_squeeze_sum = 0;\\n }\\n current_absorb_sum = length;\\n }\\n last_was_absorb = true;\\n } else {\\n if !last_was_absorb {\\n // Aggregate consecutive SQUEEZE operations\\n current_squeeze_sum += length;\\n } else {\\n // Start new SQUEEZE sequence\\n if current_absorb_sum > 0 {\\n // Flush previous ABSORB sequence\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n current_absorb_sum = 0;\\n }\\n current_squeeze_sum = length;\\n }\\n last_was_absorb = false;\\n }\\n }\\n }\\n\\n // Flush remaining operations\\n if current_absorb_sum > 0 {\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n }\\n if current_squeeze_sum > 0 {\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n }\\n\\n // Step 2: Serialize to byte string and append domain separator (following SAFE spec 2.3).\\n // Buffer is 256 bytes: max 192 bytes for IO pattern (48 words) + 64 bytes for domain separator.\\n // Note: We must use a fixed-size array because Noir's keccak256 requires [u8; N], not [u8].\\n let max_io_pattern_bytes: u32 = 192; // 256 - 64 (domain separator)\\n let io_pattern_bytes = word_count * 4;\\n assert(\\n io_pattern_bytes <= max_io_pattern_bytes,\\n \\\"IO pattern too large: max 48 aggregated words supported\\\",\\n );\\n\\n let mut input_bytes = [0u8; 256];\\n let mut byte_count: u32 = 0;\\n\\n // Serialize encoded words to bytes (big-endian as per SAFE spec).\\n // Note: Noir requires compile-time loop bounds, so we iterate over L (the array size)\\n // instead of word_count (runtime value). The condition `i < word_count` ensures we only\\n // process valid encoded words. This is safe because word_count <= L always holds\\n // (we can have at most L encoded words from L input operations).\\n for i in 0..L {\\n if i < word_count {\\n let word = encoded_words[i];\\n input_bytes[byte_count] = (word >> 24) as u8;\\n input_bytes[byte_count + 1] = (word >> 16) as u8;\\n input_bytes[byte_count + 2] = (word >> 8) as u8;\\n input_bytes[byte_count + 3] = word as u8;\\n byte_count += 4;\\n }\\n }\\n\\n // Append full 64-byte domain separator.\\n for i in 0..64 {\\n input_bytes[byte_count] = domain_separator[i];\\n byte_count += 1;\\n }\\n\\n // Step 3: Hash with Keccak-256 and truncate to 128 bits.\\n // Note: The SAFE spec uses SHA3-256, but we use Keccak-256 for Noir compatibility.\\n // Keccak-256 differs from SHA3-256 in padding, but both provide equivalent security.\\n let hash_bytes = keccak256(input_bytes, byte_count);\\n\\n // Convert first 128 bits (16 bytes) to field element.\\n let mut tag_value: Field = 0;\\n for i in 0..16 {\\n tag_value = tag_value * 256 + (hash_bytes[i] as Field);\\n }\\n\\n tag_value\\n}\\n\\n#[test]\\nfn test_safe_hashing() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_merkle_node() {\\n // Verifies SAFE can be used for Merkle tree node hashing with pattern ABSORB(1) + ABSORB(1) + SQUEEZE(1).\\n // Tests the ability to absorb multiple inputs before squeezing output.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let left = [123].as_vector();\\n let right = [456].as_vector();\\n\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(left);\\n sponge.absorb(right);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(left);\\n sponge2.absorb(right);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_commitment_scheme() {\\n // Verifies SAFE can be used for commitment schemes with pattern ABSORB(3) + SQUEEZE(1).\\n // Tests the ability to create deterministic commitments from multiple field elements.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let values = [10, 20, 30].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(values);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(values);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_domain_separation() {\\n // Verifies that different domain separators produce different outputs for the same input.\\n // This is crucial for cross-protocol security and preventing collisions between different applications.\\n let elements = [1, 2, 3].as_vector();\\n let domain1 = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let domain2 = [\\n 0x41, 0x42, 0x43, 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n\\n let mut sponge1 = SafeSponge::start(io_pattern, domain1);\\n sponge1.absorb(elements);\\n let output1 = sponge1.squeeze();\\n sponge1.finish();\\n\\n let mut sponge2 = SafeSponge::start(io_pattern, domain2);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output1.len() == 1);\\n assert(output2.len() == 1);\\n assert(output1[0] != output2[0]); // Different domain separators should produce different outputs\\n}\\n\\n#[test]\\nfn test_multiple_squeeze() {\\n // Verifies that multiple field elements can be squeezed in a single operation.\\n // Tests pattern ABSORB(3) + SQUEEZE(2) to ensure proper state management.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(2)\\n let io_pattern = [0x80000003, 0x00000002];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 2);\\n assert(output[0] != 0);\\n assert(output[1] != 0);\\n assert(output[0] != output[1]); // Different squeeze outputs should be different\\n}\\n\\n#[test]\\nfn test_zero_length_operations() {\\n // Verifies that zero-length ABSORB and SQUEEZE operations are handled correctly.\\n // Tests pattern ABSORB(0) + SQUEEZE(1) to ensure proper state transitions.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(0), SQUEEZE(1)\\n let io_pattern = [0x80000000, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb([].as_vector());\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n}\\n\\n#[test]\\nfn test_tag_computation() {\\n // Verifies the tag computation algorithm using the example from the SAFE specification.\\n // Pattern: ABSORB(3), ABSORB(3), SQUEEZE(3)\\n // Should aggregate to: ABSORB(6), SQUEEZE(3)\\n // Encoded as: [0x80000006, 0x00000003]\\n // Tests determinism and pattern differentiation.\\n\\n let io_pattern = [0x80000003, 0x80000003, 0x00000003];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test determinism\\n let tag2 = compute_tag(io_pattern, domain_separator);\\n assert(tag == tag2);\\n\\n // Test that different patterns produce different tags\\n let io_pattern2 = [0x80000003, 0x00000003]; // ABSORB(3), SQUEEZE(3) - different pattern\\n let tag3 = compute_tag(io_pattern2, domain_separator);\\n assert(tag != tag3);\\n}\\n\\n#[test]\\nfn test_tag_computation_debug() {\\n println(\\\"=== SAFE Tag Computation Debug Test ===\\\");\\n\\n // Test your specific pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\n let io_pattern = [0x80000002, 0x00000002, 0x80000002];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n println(f\\\"Testing pattern: {io_pattern}\\\");\\n println(\\n f\\\"Expected to aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(2)\\\",\\n );\\n println(\\n f\\\"Expected encoded words: [0x80000002, 0x00000002, 0x80000002]\\\",\\n );\\n println(\\\"\\\");\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n println(f\\\"=== Expected Rust Output ===\\\");\\n println(\\\"Pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\\");\\n println(\\\"Domain separator: 0x41424344...\\\");\\n println(\\\"Tag: 0xce3bb9ee4b2d41c42e9cdda38afe8b6a\\\");\\n println(\\\"\\\");\\n\\n println(f\\\"=== Noir Output ===\\\");\\n println(f\\\"Tag: {tag}\\\");\\n println(\\\"\\\");\\n\\n println(\\\"Compare the tag values above with Rust script!\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_absorb_aggregation() {\\n // Test that consecutive ABSORB operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1) should aggregate to ABSORB(2), SQUEEZE(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(1) = [0x80000002, 0x00000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(2), SQUEEZE(1)\\n let aggregated_pattern = [0x80000002, 0x00000001];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Consecutive ABSORB operations should aggregate to the same tag\\\");\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive ABSORB operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive ABSORB Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001] (ABSORB(1), ABSORB(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000002, 0x00000001] (ABSORB(2), SQUEEZE(1))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_squeeze_aggregation() {\\n // Test that consecutive SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1) should aggregate to ABSORB(1), SQUEEZE(2)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x00000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(1), SQUEEZE(2) = [0x80000001, 0x00000002]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(1), SQUEEZE(2)\\n let aggregated_pattern = [0x80000001, 0x00000002];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(\\n tag == aggregated_tag,\\n \\\"Consecutive SQUEEZE operations should aggregate to the same tag\\\",\\n );\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive SQUEEZE operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive SQUEEZE Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x00000001, 0x00000001] (ABSORB(1), SQUEEZE(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000001, 0x00000002] (ABSORB(1), SQUEEZE(2))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_mixed_consecutive_aggregation() {\\n // Test that both consecutive ABSORB and SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n // Should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1) = [0x80000002, 0x00000002, 0x80000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag\\n let aggregated_pattern = [0x80000002, 0x00000002, 0x80000001]; // ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Mixed consecutive operations should aggregate to the same tag\\\");\\n\\n println(\\\"=== Mixed Consecutive Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001]\\\",\\n );\\n println(\\n f\\\" (ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1))\\\",\\n );\\n println(f\\\"Aggregated pattern: [0x80000002, 0x00000002, 0x80000001]\\\");\\n println(f\\\" (ABSORB(2), SQUEEZE(2), ABSORB(1))\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n}\\n\\n#[test]\\nfn test_large_io_pattern() {\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Create pattern with 48 alternating ABSORB(1) and SQUEEZE(1) operations\\n // This is the maximum supported (48 words * 4 bytes = 192 bytes, leaving 64 for domain separator)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1; // ABSORB(1)\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1; // SQUEEZE(1)\\n }\\n }\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n assert(tag != 0);\\n}\\n\\n#[test]\\nfn test_domain_separator_not_truncated() {\\n // This test verifies that the domain separator is always included in the tag computation,\\n // even for large IO patterns. If the domain separator were truncated, different domain\\n // separators would produce the same tag for large patterns.\\n\\n let domain_separator_a = [\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41,\\n ]; // All 'A's\\n\\n let domain_separator_b = [\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42,\\n ]; // All 'B's\\n\\n // Create pattern with 48 alternating operations (max supported: 192 bytes of IO pattern)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1;\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1;\\n }\\n }\\n\\n let tag_a = compute_tag(io_pattern, domain_separator_a);\\n let tag_b = compute_tag(io_pattern, domain_separator_b);\\n\\n // Tags MUST be different because domain separators are different.\\n // If they were the same, it would mean the domain separator was truncated/ignored.\\n assert(tag_a != tag_b, \\\"Domain separator must affect tag even for large IO patterns\\\");\\n}\\n\",\"path\":\"interfold/circuits/lib/src/math/safe.nr\",\"function_locations\":[{\"start\":4164,\"name\":\"SafeSponge<L>::start\"},{\"start\":5046,\"name\":\"SafeSponge<L>::absorb\"},{\"start\":6826,\"name\":\"SafeSponge<L>::squeeze\"},{\"start\":8494,\"name\":\"SafeSponge<L>::finish\"},{\"start\":9156,\"name\":\"SafeSponge<L>::permute\"},{\"start\":9830,\"name\":\"compute_tag\"},{\"start\":14128,\"name\":\"test_safe_hashing\"},{\"start\":15104,\"name\":\"test_merkle_node\"},{\"start\":16281,\"name\":\"test_commitment_scheme\"},{\"start\":17357,\"name\":\"test_domain_separation\"},{\"start\":18710,\"name\":\"test_multiple_squeeze\"},{\"start\":19639,\"name\":\"test_zero_length_operations\"},{\"start\":20415,\"name\":\"test_tag_computation\"},{\"start\":21477,\"name\":\"test_tag_computation_debug\"},{\"start\":22681,\"name\":\"test_consecutive_absorb_aggregation\"},{\"start\":24750,\"name\":\"test_consecutive_squeeze_aggregation\"},{\"start\":26760,\"name\":\"test_mixed_consecutive_aggregation\"},{\"start\":28520,\"name\":\"test_large_io_pattern\"},{\"start\":29333,\"name\":\"test_domain_separator_not_truncated\"}]}}}","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n broadcastVote,\n chainRpcUrl,\n getBlockAtTimestamp,\n getChainHead,\n getIndexedLogs,\n readContracts,\n getAllRoundResults,\n getCurrentRound,\n getEligibleAddresses,\n getRoundCiphertext,\n getRoundPublicKey,\n getRoundResult,\n getRoundStateLite,\n getTokenHolderHashes,\n getVoteStatus,\n requestNewRound,\n} from './api'\nimport { getOnChainRoundData, getOnchainVotingPower, getPreviousCiphertext, getRoundDetails, getRoundTokenDetails } from './state'\nimport { finishBallotProof, finishMaskProof, prepareBallot } from './vote'\n\nimport type {\n ChainHead,\n ContractRead,\n ContractReadResult,\n IndexedLog,\n LogQuery,\n BroadcastVoteRequest,\n BroadcastVoteResponse,\n CurrentRoundResponse,\n E3StateLiteResponse,\n JsonResponse,\n NewRoundRequest,\n OnChainRoundData,\n PrepareBallotRequest,\n PreparedBallot,\n ProofData,\n RoundDetails,\n SlotHead,\n TokenDetails,\n TokenHolder,\n VoteStatusResponse,\n WebResultResponse,\n} from './types'\n\n/**\n * Pass as the SDK's `rpcUrl` to read the chain through the CRISP server's own `/chain/rpc` route.\n *\n * A sentinel rather than a boolean flag so the parameter keeps one meaning — \"where chain reads\n * go\" — whether that is a URL you supply or the server you are already talking to.\n */\nexport const SERVER_RPC = 'server' as const\n\n/**\n * A class representing the CRISP SDK.\n */\nexport class CrispSDK {\n /**\n * The server URL for the CRISP SDK.\n * It's used by methods that communicate directly with the CRISP server.\n */\n private serverUrl: string\n\n /**\n * Endpoint used for direct chain reads, or `undefined` to use viem's default public RPC.\n */\n private rpcUrl: string | undefined\n\n /**\n * Create a new instance.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param rpcUrl - Endpoint for direct chain reads. Omit (or pass `null`) to keep viem's default\n * public RPC. Pass {@link SERVER_RPC} to read through the CRISP server's own\n * `/chain/rpc` route instead of a third-party endpoint. Any other string is used\n * as the endpoint URL directly.\n *\n * Routing through the server is opt-in rather than the default because it is a change of\n * transport, not a tuning knob: a caller who merely upgrades this package would have every chain\n * read redirected to a route their deployed server may not have — or may not be configured to\n * serve the contracts being read — turning a version bump into an outage.\n */\n constructor(serverUrl: string, rpcUrl?: string | null) {\n this.serverUrl = serverUrl\n this.rpcUrl = rpcUrl === SERVER_RPC ? chainRpcUrl(serverUrl) : (rpcUrl ?? undefined)\n }\n\n /**\n * Phase one: encrypt a ballot, before the voter signs anything.\n *\n * A ballot has to be encrypted before it can be signed, because the digest binds the ciphertext.\n * Take `ctCommitment` from the result, read the digest from\n * `CRISPProgram.ballotDigest(e3Id, slot, ctCommitment)`, have the voter sign it, then call\n * {@link finishBallot}.\n *\n * Masks and real votes take the same path. This method calls the same server API\n * (previous-ciphertext) for both, so the server cannot infer the ballot type from the request\n * pattern, and the encryption is identical either way.\n *\n * @param request - The ballot to encrypt.\n * @returns A promise that resolves to the prepared ballot.\n */\n async prepareBallot(request: PrepareBallotRequest): Promise<PreparedBallot> {\n const head = await getPreviousCiphertext(this.serverUrl, request.e3Id, request.slotAddress)\n\n // Branched rather than spread conditionally. The two halves of a slot head only mean anything\n // together and the type models them as a pair, which a conditional spread widens back into two\n // independent optional fields — the exact shape the pair exists to rule out.\n return head ? prepareBallot({ ...request, previousCiphertext: head.ciphertext, previousIndex: head.index }) : prepareBallot(request)\n }\n\n /**\n * Phase two: prove a prepared ballot.\n *\n * A mask passes no signature and gets the placeholder. It still carries the same digest as a\n * real vote, because the contract computes the digest for every input.\n *\n * @param prepared - The output of {@link prepareBallot}.\n * @param digest - The digest read from `CRISPProgram.ballotDigest`.\n * @param signature - The voter signature, omitted for a mask.\n * @returns A promise that resolves to the generated proof data.\n */\n async finishBallot(prepared: PreparedBallot, digest: `0x${string}`, signature?: `0x${string}`): Promise<ProofData> {\n return signature ? finishBallotProof(prepared, digest, signature) : finishMaskProof(prepared, digest)\n }\n\n /**\n * Get the current (most recent) round, optionally filtered by requester addresses.\n * @param requesters - Optional list of requester addresses to filter by\n * @returns The current round id, or undefined if no round exists\n */\n async getCurrentRound(requesters?: string[]): Promise<CurrentRoundResponse | undefined> {\n return getCurrentRound(this.serverUrl, requesters)\n }\n\n /**\n * Get the committee public key for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The committee public key bytes\n */\n async getRoundPublicKey(e3Id: bigint): Promise<Uint8Array> {\n return getRoundPublicKey(this.serverUrl, e3Id)\n }\n\n /**\n * Get the ciphertext output for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The ciphertext output bytes\n */\n async getRoundCiphertext(e3Id: bigint): Promise<Uint8Array> {\n return getRoundCiphertext(this.serverUrl, e3Id)\n }\n\n /**\n * Request a new E3 round. Requires the server's cron API key.\n * @param request - The new round request (cron API key, token address and balance threshold)\n * @returns The server confirmation message\n */\n async requestNewRound(request: NewRoundRequest): Promise<JsonResponse> {\n return requestNewRound(this.serverUrl, request)\n }\n\n /**\n * Broadcast an encrypted vote through the CRISP server, which relays it on-chain.\n * @param request - The vote request (round id and hex encoded proof)\n * @returns The broadcast result, including the transaction hash on success\n */\n async broadcastVote(request: BroadcastVoteRequest): Promise<BroadcastVoteResponse> {\n return broadcastVote(this.serverUrl, request)\n }\n\n /**\n * Get the vote status for an address in a specific round.\n * @param e3Id - The e3Id of the round\n * @param address - The voter address\n * @returns The vote status for the address\n */\n async getVoteStatus(e3Id: bigint, address: string): Promise<VoteStatusResponse> {\n return getVoteStatus(this.serverUrl, e3Id, address)\n }\n\n /**\n * Get the result for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The round result (tally, emojis, total votes, end time and requester)\n */\n async getRoundResult(e3Id: bigint): Promise<WebResultResponse> {\n return getRoundResult(this.serverUrl, e3Id)\n }\n\n /**\n * Get the results for all rounds, optionally filtered by requester addresses.\n * @param requesters - Optional list of requester addresses to filter by\n * @returns The results for all matching rounds\n */\n async getAllRoundResults(requesters?: string[]): Promise<WebResultResponse[]> {\n return getAllRoundResults(this.serverUrl, requesters)\n }\n\n /**\n * Get the lite state for a given round, as returned by the server (snake_case fields).\n * @param e3Id - The e3Id of the round\n * @returns The lite round state\n */\n async getRoundStateLite(e3Id: bigint): Promise<E3StateLiteResponse> {\n return getRoundStateLite(this.serverUrl, e3Id)\n }\n\n /**\n * Get the details of a specific round in a camelCase convenience format.\n * @param e3Id - The e3Id of the round\n * @returns The round details\n */\n async getRoundDetails(e3Id: bigint): Promise<RoundDetails> {\n return getRoundDetails(this.serverUrl, e3Id)\n }\n\n /**\n * Get the round data stored in the CRISPProgram contract, read directly from the chain.\n *\n * When the chain id is omitted it is looked up on the CRISP server.\n *\n * @param programAddress - The address of the CRISPProgram contract\n * @param e3Id - The e3Id of the round\n * @param chainId - The chain ID of the network the program is deployed on\n * @returns The on chain round data\n */\n async getOnChainRoundData(programAddress: string, e3Id: bigint, chainId?: number): Promise<OnChainRoundData> {\n const chain = chainId ?? Number((await getRoundDetails(this.serverUrl, e3Id)).chainId)\n\n return getOnChainRoundData(programAddress, e3Id, chain, this.rpcUrl)\n }\n\n /**\n * Get the voting power a slot may spend in a `CensusMode.ONCHAIN` round, read from the CRISP\n * program through this instance's configured endpoint.\n *\n * @param programAddress - The CRISP program address\n * @param e3Id - The e3Id of the round\n * @param slot - The slot address the ballot is written to\n * @param chainId - The chain the program is deployed on; looked up on the server when omitted\n * @returns The spendable voting power in ballot units\n */\n async getOnchainVotingPower(programAddress: string, e3Id: bigint, slot: string, chainId?: number): Promise<bigint> {\n const chain = chainId ?? Number((await getRoundDetails(this.serverUrl, e3Id)).chainId)\n\n return getOnchainVotingPower(programAddress, e3Id, slot, chain, this.rpcUrl)\n }\n\n /**\n * Get the token address, balance threshold and snapshot block for a specific round.\n * @param e3Id - The e3Id of the round\n * @returns The token details\n */\n async getRoundTokenDetails(e3Id: bigint): Promise<TokenDetails> {\n return getRoundTokenDetails(this.serverUrl, e3Id)\n }\n\n /**\n * Get the token holder hashes (hash(address, balance)) for a given round.\n * These are the Merkle tree leaves used for eligibility proofs.\n * @param e3Id - The e3Id of the round\n * @returns The list of token holder hashes\n */\n async getTokenHolderHashes(e3Id: bigint): Promise<string[]> {\n return getTokenHolderHashes(this.serverUrl, e3Id)\n }\n\n /**\n * Get the eligible addresses and their balances for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The list of eligible token holders\n */\n async getEligibleAddresses(e3Id: bigint): Promise<TokenHolder[]> {\n return getEligibleAddresses(this.serverUrl, e3Id)\n }\n\n /**\n * Get the chain head (block number, timestamp, chain id) as seen by the server.\n * @returns The current head\n */\n async getChainHead(): Promise<ChainHead> {\n return getChainHead(this.serverUrl)\n }\n\n /**\n * Read allowlisted contracts through the server, batched, without a provider key of your own.\n * @param calls - The calls to perform, in order\n * @returns One result per call, in the same order\n */\n async readContracts(calls: ContractRead[]): Promise<ContractReadResult[]> {\n return readContracts(this.serverUrl, calls)\n }\n\n /**\n * Query logs for an allowlisted contract over an arbitrary block range. The server windows the\n * range for you, so no chunking is needed on this side.\n * @param query - The log query\n * @returns The matching logs, ordered by block and log index\n */\n async getLogs(query: LogQuery): Promise<IndexedLog[]> {\n return getIndexedLogs(this.serverUrl, query)\n }\n\n /**\n * Resolve a unix timestamp to the last block at or before it.\n * @param timestamp - The unix timestamp\n * @returns The block number and its timestamp\n */\n async getBlockAtTimestamp(timestamp: bigint): Promise<{ blockNumber: bigint; timestamp: bigint }> {\n return getBlockAtTimestamp(this.serverUrl, timestamp)\n }\n\n /**\n * The server's read-only JSON-RPC URL, for pointing a standard Ethereum client at.\n * @returns The JSON-RPC URL\n */\n chainRpcUrl(): string {\n return chainRpcUrl(this.serverUrl)\n }\n\n /**\n * Get the previous ciphertext input for a slot address in a given round.\n * @param e3Id - The e3Id of the round\n * @param address - The address of the slot\n * @returns The slot head and its tree index, or undefined if the slot holds nothing usable\n */\n async getPreviousCiphertext(e3Id: bigint, address: string): Promise<SlotHead | undefined> {\n return getPreviousCiphertext(this.serverUrl, e3Id, address)\n }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport type { LeanIMTMerkleProof } from '@zk-kit/lean-imt'\n\n/**\n * Type representing the details of a specific round in a more convenient format\n * (camelCase view of the server's `state/lite` response)\n */\nexport type RoundDetails = {\n e3Id: bigint\n chainId: bigint\n interfoldAddress: string\n status: string\n voteCount: bigint\n startTime: bigint\n endTime: bigint\n /// The block the E3 was requested at\n startBlock: bigint\n /// The block the census was built at\n snapshotBlock: bigint\n committeePublicKey: Uint8Array\n emojis: [string, string]\n tokenAddress: string\n balanceThreshold: bigint\n numOptions: bigint\n requester: string\n creditMode: CreditMode\n credits?: bigint\n}\n\n/**\n * Type representing the round data stored in the CRISPProgram contract\n */\nexport type OnChainRoundData = {\n /// The merkle root of the census\n merkleRoot: bigint\n /// The hash of the E3 program params\n paramsHash: `0x${string}`\n /// The number of vote options\n numOptions: bigint\n /// The credit mode of the round\n creditMode: CreditMode\n /// The root of the merkle tree holding the encrypted votes\n inputRoot: bigint\n /// The number of votes published on chain\n numberOfVotes: bigint\n}\n\n/**\n * Type representing the token details required for participation in a round\n */\nexport type TokenDetails = {\n tokenAddress: string\n threshold: bigint\n snapshotBlock: bigint\n}\n\n/**\n * Type representing a Merkle proof\n */\nexport type MerkleProof = {\n leaf: bigint\n index: number\n proof: LeanIMTMerkleProof<bigint>\n length: number\n indices: number[]\n}\n\n/**\n * Type representing a vote\n */\nexport type Vote = number[]\n\n/**\n * Type representing a decoded tally: one total per option.\n *\n * @remarks\n * Uses `bigint` because an aggregated tally coefficient is a sum over all ballots,\n * so a total can exceed `Number.MAX_SAFE_INTEGER`. This matches the `BigUint` the\n * CRISP server returns and the `uint256` the CRISP contract returns.\n */\nexport type TallyResult = bigint[]\n\n/**\n * Type representing a vector with coefficients\n */\nexport type Polynomial = {\n coefficients: string[]\n}\n\n/**\n * Type representing cryptographic parameters\n */\nexport type GrecoCryptographicParams = {\n q_mod_t: string\n qis: string[]\n k0is: string[]\n}\n\n/**\n * Type representing Greco bounds\n */\nexport type GrecoBoundParams = {\n e_bound: string\n u_bound: string\n k1_low_bound: string\n k1_up_bound: string\n p1_bounds: string[]\n p2_bounds: string[]\n pk_bounds: string[]\n r1_low_bounds: string[]\n r1_up_bounds: string[]\n r2_bounds: string[]\n}\n\n/**\n * Type representing Greco parameters\n */\nexport type GrecoParams = {\n crypto: GrecoCryptographicParams\n bounds: GrecoBoundParams\n}\n\nexport type ProofData = {\n publicInputs: string[]\n proof: Uint8Array\n encryptedVote: Uint8Array\n /**\n * The tree index of the entry this input extends, plus one; zero when it extends nothing.\n *\n * `CRISPProgram` reads the parent's commitment from this and hands it to the circuit as\n * `prev_ct_commitment`, and the Secure Process walks each slot's chain by it. Offset by one so\n * that zero means \"no parent\", which is what index 0 would otherwise be ambiguous with.\n */\n parentIndexPlusOne: number\n}\n\n/**\n * Which circuit a ballot is built for.\n *\n * `merkle` proves membership of a census tree, and matches `CensusMode.TOKEN` and\n * `CensusMode.BY_REQUESTER`. `onchain` takes voting power as a public input that the contract\n * reads from the token, and matches `CensusMode.ONCHAIN`.\n */\nexport type CensusVariant = 'merkle' | 'onchain'\n\n/**\n * The two halves of a slot head, which only mean anything together.\n *\n * Modelled as a pair rather than two optional fields: a ciphertext without its index would be\n * proven against one entry and published against another, and the mismatch only surfaces as a\n * rejected proof.\n */\ntype SlotHeadInputs =\n | {\n /**\n * The ciphertext currently in the slot: the end of its chain of usable entries, not simply\n * the newest one published. An entry whose bytes do not reproduce its commitment is never\n * selected by the Secure Process and is never a valid parent, so building on it would have\n * this input dropped from the tally.\n */\n previousCiphertext: Uint8Array\n /** The tree index of `previousCiphertext`, which this input names as its parent. */\n previousIndex: number\n }\n | { previousCiphertext?: undefined; previousIndex?: undefined }\n\ntype PrepareBallotInputsBase = {\n publicKey: Uint8Array\n slotAddress: string\n isMaskVote: boolean\n /// Read for a mask, where there is no vote to take a length from.\n numOptions: number\n vote: Vote\n} & SlotHeadInputs\n\n/**\n * Everything needed to encrypt a ballot, before the voter has signed anything.\n */\nexport type PrepareBallotInputs =\n | (PrepareBallotInputsBase & { censusMode: 'merkle'; balance: bigint; merkleLeaves: string[] | bigint[] })\n | (PrepareBallotInputsBase & { censusMode: 'onchain'; votingPower: bigint })\n\n/**\n * A ballot that is encrypted but not yet signed.\n *\n * `ctCommitment` is the value to pass to `CRISPProgram.ballotDigest`. Reading the digest from the\n * contract rather than rebuilding the EIP-712 struct here keeps one implementation of the domain.\n */\nexport type PreparedBallot = {\n circuitInputs: any\n /**\n * The ciphertext to publish, which is the ballot itself for a vote or a re-vote, and the slot's\n * ciphertext plus the zero ballot for a mask over an occupied slot.\n */\n encryptedVote: Uint8Array\n /**\n * The commitment to `encryptedVote`: what the circuit returns, what the E3 program stores, and\n * what `CRISPProgram.ballotDigest` takes as its `ciphertextCommitment` argument.\n *\n * Since the digest is itself a circuit input, a caller has to know this value before proving,\n * which is why the wasm exports it rather than leaving it to be read off the finished proof.\n */\n ctCommitment: `0x${string}`\n /** The value {@link ProofData.parentIndexPlusOne} carries through to `encodeSolidityProof`. */\n parentIndexPlusOne: number\n censusMode: CensusVariant\n}\n\n/**\n * `Omit` that maps over each member of a union instead of collapsing it.\n *\n * A plain `Omit` on a discriminated union merges the members and loses the discriminant, which\n * would let a caller pass `censusMode: 'onchain'` with no `votingPower`.\n */\ntype DistributiveOmit<T, K extends keyof never> = T extends unknown ? Omit<T, K> : never\n\n/**\n * A {@link PrepareBallotInputs} plus the round it belongs to.\n *\n * The SDK resolves the slot head from the server, so callers pass neither part of it.\n */\nexport type PrepareBallotRequest = { e3Id: bigint } & DistributiveOmit<PrepareBallotInputs, 'previousCiphertext' | 'previousIndex'>\n\n/**\n * The end of a slot's chain of usable entries: what a new input extends.\n *\n * Not simply the newest entry published to the slot. An entry whose bytes do not reproduce its\n * commitment is never selected by the Secure Process and is never a valid parent, so the server\n * resolves the chain and answers with the entry that actually holds the slot.\n */\nexport type SlotHead = {\n ciphertext: Uint8Array\n /** The tree index of that entry. */\n index: number\n}\n\n/**\n * Type representing the current round returned by the CRISP server (`rounds/current`)\n */\nexport type CurrentRoundResponse = {\n id: string\n}\n\n/**\n * Type representing the lite state of a round returned by the CRISP server (`state/lite`)\n */\nexport type E3StateLiteResponse = {\n id: string\n chain_id: number\n interfold_address: string\n status: string\n vote_count: number\n start_time: number\n end_time: number\n start_block: number\n snapshot_block: number\n committee_public_key: number[]\n emojis: [string, string]\n token_address: string\n balance_threshold: string\n num_options: string\n requester: string\n credit_mode: CreditMode\n credits: string | null\n}\n\n/**\n * Type representing a generic message response from the CRISP server\n */\nexport type JsonResponse = {\n response: string\n}\n\n/**\n * Type representing a request to start a new E3 round (`rounds/request`)\n */\nexport type NewRoundRequest = {\n cronApiKey: string\n tokenAddress: string\n /** For an ONCHAIN round, doubles as the contract's `minVotingPower` floor in raw token units. */\n balanceThreshold: string\n /**\n * The census source, as a `CRISPProgram.CensusMode` discriminant: 0 (TOKEN, the default) or\n * 2 (ONCHAIN). ONCHAIN reads eligibility from the token per input — with a `SelfRegistry` as\n * the token, that is what lets voters register during the input window. Typed as the literals\n * the server accepts — any other explicit value is refused with HTTP 400.\n */\n censusMode?: 0 | 2\n}\n\n/**\n * Type representing a request to broadcast an encrypted vote (`voting/broadcast`)\n *\n * Carries no address: the slot is already inside the encoded proof, and every byte the relay\n * does not receive is a byte it cannot log against a masker's session.\n */\nexport type BroadcastVoteRequest = {\n e3Id: bigint\n encodedProof: string\n}\n\n/**\n * The status of a vote broadcast returned by the CRISP server\n */\nexport type VoteResponseStatus = 'success' | 'failed_broadcast'\n\n/**\n * Type representing the response to a vote broadcast (`voting/broadcast`)\n */\nexport type BroadcastVoteResponse = {\n status: VoteResponseStatus\n tx_hash: string | null\n message: string | null\n}\n\n/**\n * Type representing the slot activity of an address in a round (`voting/status`)\n *\n * @remarks\n * `slot_active` says the slot holds at least one published entry — not that its owner voted.\n * Masks are indistinguishable from votes by design, so activity is the only per-slot fact the\n * server can answer. A client that wants \"did I vote\" must remember its own submissions.\n */\nexport type VoteStatusResponse = {\n round_id: string\n address: string\n slot_active: boolean\n round_status: string | null\n}\n\n/**\n * Type representing the result of a round (`state/result` and `state/all`)\n */\nexport type WebResultResponse = {\n round_id: string\n tally: string[]\n option_1_emoji: string\n option_2_emoji: string\n total_votes: number\n end_time: number\n requester: string\n}\n\n/**\n * Type representing a token holder with their address and balance (`state/eligible-addresses`)\n */\nexport type TokenHolder = {\n address: string\n balance: string\n}\n\n/**\n * Enum representing the credit mode for a round, which can be either constant or custom.\n * In constant mode, all voters receive the same amount of credits, while in custom mode,\n * the credits can vary based on certain criteria (e.g., voter balance).\n */\nexport enum CreditMode {\n CONSTANT = 0,\n CUSTOM = 1,\n}\n\n/**\n * The chain head as reported by the CRISP server (`chain/head`).\n */\nexport type ChainHead = {\n blockNumber: bigint\n timestamp: bigint\n chainId: number\n}\n\n/**\n * One `eth_call` in a `chain/read` batch. The caller owns the ABI encoding; the server forwards\n * the calldata untouched, so a client can read any view function of an allowlisted contract\n * without the server needing to know its ABI.\n */\nexport type ContractRead = {\n address: string\n data: `0x${string}`\n /** Historical block to read at. Omit for latest. */\n blockNumber?: bigint\n}\n\n/**\n * The outcome of one call in a `chain/read` batch.\n *\n * A revert is reported per call rather than failing the batch, because probing a function a\n * contract may not implement is a normal thing to do (the IVotes and proxy probes both rely on\n * it) and one expected revert must not discard its siblings' results.\n */\nexport type ContractReadResult = {\n result?: `0x${string}`\n error?: string\n}\n\n/**\n * A log as returned by `chain/logs`.\n */\nexport type IndexedLog = {\n address: string\n topics: `0x${string}`[]\n data: `0x${string}`\n blockNumber?: bigint\n transactionHash?: string\n logIndex?: number\n}\n\n/**\n * A `chain/logs` query. The range is unbounded from the caller's side: the server splits it into\n * windows the upstream provider will accept.\n */\nexport type LogQuery = {\n address: string\n /** Positional topic filters; `null`/`undefined` in a position matches anything. */\n topics?: (string | null | undefined)[]\n fromBlock?: bigint\n toBlock?: bigint\n}\n"],"mappings":"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","names":["parseAbi","parseAbi","hexToBytes","hexToBytes","CreditMode"]}
|
|
1
|
+
{"version":3,"sources":["../src/circuits.ts","../src/constants.ts","../src/token.ts","../src/chain.ts","../src/state.ts","../src/api.ts","../src/utils.ts","../src/encoding.ts","../src/circuitInputs.ts","../src/vote.ts","../../../circuits/bin/fold/target/crisp_fold.json","../../../circuits/bin/fold_onchain/target/crisp_onchain_fold.json","../../../../../circuits/bin/threshold/target/user_data_encryption.json","../src/sdk.ts","../src/types.ts"],"sourcesContent":["// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport type { CompiledCircuit } from '@noir-lang/noir_js'\n\n/** BFV parameter sets the circuits can be compiled against. */\nexport type CircuitPreset = 'insecure-512' | 'secure-8192'\n\n/**\n * The circuits whose ABI is shaped by the BFV degree, and which therefore exist once per preset.\n *\n * The aggregation circuits — `crisp_fold`, `crisp_onchain_fold` and `user_data_encryption` — are\n * deliberately absent. Their parameters are proof and verification-key shaped (410/115 fields), not\n * polynomial shaped, so one compiled artifact serves both presets; the fold circuits assert\n * `chain_key_hash` against the insecure *or* the secure constant for exactly that reason. They ship\n * in the main entry point, which is why `verifyProof` works without a preset loaded.\n */\nexport type CircuitBundle = {\n readonly preset: CircuitPreset\n readonly crisp: CompiledCircuit\n readonly crispOnchain: CompiledCircuit\n readonly userDataEncryptionCt0: CompiledCircuit\n readonly userDataEncryptionCt1: CompiledCircuit\n}\n\nlet registered: CircuitBundle | null = null\n\n/**\n * Install the preset-bound circuits used by `generateProof`.\n *\n * The bundle is not bundled into the main entry point, because the secure-8192 artifacts are more\n * than an order of magnitude larger than the insecure-512 ones and no consumer needs both. Load the\n * one you want from its subpath and register it once at start-up:\n *\n * ```ts\n * import { setCircuits } from '@crisp-e3/sdk'\n * import { loadCircuits } from '@crisp-e3/sdk/insecure-512'\n *\n * setCircuits(await loadCircuits())\n * ```\n */\nexport const setCircuits = (bundle: CircuitBundle): void => {\n registered = bundle\n}\n\n/** The registered bundle, or `null` when none has been installed yet. */\nexport const getRegisteredCircuits = (): CircuitBundle | null => registered\n\n/** The preset currently installed, or `null` when none has been installed yet. */\nexport const registeredPreset = (): CircuitPreset | null => registered?.preset ?? null\n\n/**\n * The registered bundle, throwing a directed error when nothing has been installed.\n *\n * Proving cannot fall back to a default preset: a ballot proved against the wrong parameters fails\n * on chain rather than locally, so guessing here would move the failure somewhere much harder to\n * read.\n */\nexport const requireCircuits = (): CircuitBundle => {\n if (!registered) {\n throw new Error(\n 'No circuit preset registered. Import `loadCircuits` from \"@crisp-e3/sdk/insecure-512\" or ' +\n '\"@crisp-e3/sdk/secure-8192\" and pass the result to `setCircuits()` before proving.',\n )\n }\n\n return registered\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { hashMessage } from 'viem'\n\nexport const CRISP_SERVER_TOKEN_TREE_ENDPOINT = 'state/token-holders'\nexport const CRISP_SERVER_STATE_LITE_ENDPOINT = 'state/lite'\nexport const CRISP_SERVER_PREVIOUS_CIPHERTEXT_ENDPOINT = 'state/previous-ciphertext'\nexport const CRISP_SERVER_STATE_RESULT_ENDPOINT = 'state/result'\nexport const CRISP_SERVER_STATE_ALL_ENDPOINT = 'state/all'\nexport const CRISP_SERVER_ELIGIBLE_ADDRESSES_ENDPOINT = 'state/eligible-addresses'\nexport const CRISP_SERVER_VOTING_BROADCAST_ENDPOINT = 'voting/broadcast'\nexport const CRISP_SERVER_VOTING_STATUS_ENDPOINT = 'voting/status'\nexport const CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT = 'rounds/current'\nexport const CRISP_SERVER_ROUNDS_PUBLIC_KEY_ENDPOINT = 'rounds/public-key'\nexport const CRISP_SERVER_ROUNDS_CIPHERTEXT_ENDPOINT = 'rounds/ciphertext'\nexport const CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT = 'rounds/request'\n\n// Chain access. These let a client read the contracts CRISP already watches without holding a\n// hosted-provider key of its own — see the `/chain/*` routes on the server.\nexport const CRISP_SERVER_CHAIN_RPC_ENDPOINT = 'chain/rpc'\nexport const CRISP_SERVER_CHAIN_HEAD_ENDPOINT = 'chain/head'\nexport const CRISP_SERVER_CHAIN_READ_ENDPOINT = 'chain/read'\nexport const CRISP_SERVER_CHAIN_LOGS_ENDPOINT = 'chain/logs'\nexport const CRISP_SERVER_CHAIN_BLOCK_AT_TIMESTAMP_ENDPOINT = 'chain/block-at-timestamp'\n\nexport const MERKLE_TREE_MAX_DEPTH = 20 // static, hardcoded in the circuit.\n\n// @note Must stay aligned with CRISP circuits / threshold message layout (Rust & Noir MAX_MSG_NON_ZERO_COEFFS).\n// Vote payload uses only the first MAX_MSG_NON_ZERO_COEFFS polynomial coeffs, split evenly across options\n// (e.g. 2 options → 50 binary coeffs each within those 100).\nexport const MAX_MSG_NON_ZERO_COEFFS = 100\n// Hard limit on the maximum number of vote options supported.\nexport const MAX_VOTE_OPTIONS = 10\n\n/**\n * Message used by users to prove ownership of their Ethereum account\n * This message is signed by the user's private key to authenticate their identity\n * @notice Apps ideally want to use a different message to avoid signature reuse across different applications\n */\nexport const SIGNATURE_MESSAGE = 'CRISP: Sign this message to prove ownership of your Ethereum account'\nexport const SIGNATURE_MESSAGE_HASH = hashMessage(SIGNATURE_MESSAGE)\n\n// Placeholder signature for masking votes.\nexport const MASK_SIGNATURE =\n '0x8e7d77112641d59e9409ec3052041703bb9d9e6ed39bfcf75aefbcafe829ac6b21dd7648116ad5db0466fcb4bd468dcb28f6c069def8bc47cd9d859c85a016e31b'\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { CRISP_SERVER_TOKEN_TREE_ENDPOINT } from './constants'\n\nimport { parseAbi } from 'viem'\n\nimport { getPublicClient } from './chain'\n\n/**\n * Get the merkle tree data from the CRISP server\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n */\nexport const getTreeData = async (serverUrl: string, e3Id: bigint): Promise<bigint[]> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_TOKEN_TREE_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ round_id: e3Id.toString() }),\n })\n\n const hashes = (await response.json()) as string[]\n\n // Convert hex strings to BigInts\n return hashes.map((hash) => {\n // Ensure the hash is treated as a hex string\n if (!hash.startsWith('0x')) {\n return BigInt('0x' + hash)\n }\n return BigInt(hash)\n })\n}\n\n/**\n * Get the token balance at a specific block for a given address\n * @param voterAddress - The address of the voter\n * @param tokenAddress - The address of the token contract\n * @param snapshotBlock - The block number at which to get the balance\n * @param chainId - The chain ID of the network\n * @returns The token balance as a bigint\n */\nexport const getBalanceAt = async (voterAddress: string, tokenAddress: string, snapshotBlock: number, chainId: number): Promise<bigint> => {\n const publicClient = getPublicClient(chainId)\n\n const balance = (await publicClient.readContract({\n address: tokenAddress as `0x${string}`,\n abi: parseAbi(['function getPastVotes(address, uint256) view returns (uint256)']),\n functionName: 'getPastVotes',\n args: [voterAddress as `0x${string}`, BigInt(snapshotBlock)],\n })) as bigint\n\n return balance\n}\n\n/**\n * Get the total supply of a ERC20Votes Token at a specific block\n * @param tokenAddress The token address to query\n * @param snapshotBlock The block number at which to get the total supply\n * @param chainId The chain ID of the network\n * @returns The total supply as a bigint\n */\nexport const getTotalSupplyAt = async (tokenAddress: string, snapshotBlock: number, chainId: number): Promise<bigint> => {\n const publicClient = getPublicClient(chainId)\n\n const totalSupply = (await publicClient.readContract({\n address: tokenAddress as `0x${string}`,\n abi: parseAbi(['function getPastTotalSupply(uint256) view returns (uint256)']),\n functionName: 'getPastTotalSupply',\n args: [BigInt(snapshotBlock)],\n })) as bigint\n\n return totalSupply\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { createPublicClient, http } from 'viem'\nimport { localhost, mainnet, sepolia } from 'viem/chains'\n\nimport type { Chain, PublicClient } from 'viem'\n\n/**\n * The chain definition for a supported id, or `undefined` when it is not one we know.\n *\n * Unknown is not automatically fatal: with an explicit RPC URL the transport is fully determined,\n * and viem only needs the chain for conveniences like a default endpoint. Refusing outright would\n * mean this SDK could not talk to a network it had every means to reach.\n */\nconst resolveChain = (chainId: number): Chain | undefined => {\n switch (chainId) {\n case 1:\n return mainnet\n case 11155111:\n return sepolia\n case 31337:\n return localhost\n default:\n return undefined\n }\n}\n\n/**\n * Create a public client for reading contracts.\n *\n * Prefer passing `rpcUrl` — typically the CRISP server's own read-only endpoint, via\n * `chainRpcUrl(serverUrl)`. Without one, viem falls back to its default public endpoint for the\n * chain, which is a third-party service this SDK neither controls nor can observe: it is\n * rate-limited per IP, and a caller who has deliberately routed everything else through their own\n * infrastructure would still be depending on it here without knowing.\n *\n * @param chainId - The chain ID of the network\n * @param rpcUrl - Endpoint to read through. Omit only when the default public RPC is acceptable.\n * @returns The public client\n */\nexport const getPublicClient = (chainId: number, rpcUrl?: string): PublicClient => {\n const chain = resolveChain(chainId)\n\n if (!chain && !rpcUrl) {\n throw new Error(`Unsupported chainId ${chainId}: pass an rpcUrl to read through`)\n }\n\n return createPublicClient({\n transport: http(rpcUrl),\n chain,\n })\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { parseAbi } from 'viem'\n\nimport { CRISP_SERVER_PREVIOUS_CIPHERTEXT_ENDPOINT } from './constants'\nimport { getRoundStateLite } from './api'\nimport { getPublicClient } from './chain'\n\nimport type { CreditMode, OnChainRoundData, RoundDetails, SlotHead, TokenDetails } from './types'\n\n/**\n * Get the details of a specific round in a camelCase convenience format\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The round details\n */\nexport const getRoundDetails = async (serverUrl: string, e3Id: bigint): Promise<RoundDetails> => {\n const data = await getRoundStateLite(serverUrl, e3Id)\n\n return {\n e3Id: BigInt(data.id),\n tokenAddress: data.token_address,\n balanceThreshold: BigInt(data.balance_threshold),\n chainId: BigInt(data.chain_id),\n interfoldAddress: data.interfold_address,\n status: data.status,\n voteCount: BigInt(data.vote_count),\n startTime: BigInt(data.start_time),\n endTime: BigInt(data.end_time),\n startBlock: BigInt(data.start_block),\n snapshotBlock: BigInt(data.snapshot_block),\n committeePublicKey: new Uint8Array(data.committee_public_key),\n emojis: data.emojis,\n numOptions: BigInt(data.num_options),\n requester: data.requester,\n creditMode: data.credit_mode,\n credits: data.credits !== null ? BigInt(data.credits) : undefined,\n }\n}\n\n/**\n * Get the token address, balance threshold and snapshot block for a specific round\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The token address, balance threshold and snapshot block\n */\nexport const getRoundTokenDetails = async (serverUrl: string, e3Id: bigint): Promise<TokenDetails> => {\n const roundDetails = await getRoundDetails(serverUrl, e3Id)\n return {\n tokenAddress: roundDetails.tokenAddress,\n threshold: roundDetails.balanceThreshold,\n snapshotBlock: roundDetails.snapshotBlock,\n }\n}\n\n/**\n * Get the round data stored in the CRISPProgram contract, such as the merkle root\n * of the census and the merkle root of the encrypted votes published so far.\n *\n * Unlike {@link getRoundDetails}, this reads directly from the chain and so does not\n * depend on the CRISP server.\n *\n * @param programAddress - The address of the CRISPProgram contract\n * @param e3Id - The e3Id of the round\n * @param chainId - The chain ID of the network the program is deployed on\n * @param rpcUrl - Endpoint to read through. Omitted, viem's default public RPC for the chain is\n * used — a third-party service this SDK cannot observe or rate-limit.\n * @returns The on chain round data\n */\nexport const getOnChainRoundData = async (\n programAddress: string,\n e3Id: bigint,\n chainId: number,\n rpcUrl?: string,\n): Promise<OnChainRoundData> => {\n const publicClient = getPublicClient(chainId, rpcUrl)\n\n const [merkleRoot, paramsHash, numOptions, creditMode, inputRoot, numberOfVotes] = await publicClient.readContract({\n address: programAddress as `0x${string}`,\n abi: parseAbi([\n 'function getRoundData(uint256 e3Id) view returns (uint256 merkleRoot, bytes32 paramsHash, uint256 numOptions, uint8 creditMode, uint256 inputRoot, uint40 numberOfVotes)',\n ]),\n functionName: 'getRoundData',\n args: [e3Id],\n })\n\n return {\n merkleRoot,\n paramsHash,\n numOptions,\n creditMode: creditMode as CreditMode,\n inputRoot,\n numberOfVotes: BigInt(numberOfVotes),\n }\n}\n\n/**\n * Get the voting power a slot may spend in a `CensusMode.ONCHAIN` round, in ballot units.\n *\n * Read from the CRISP program rather than derived here. The contract scales raw token power by a\n * per-round divisor before handing it to the circuit as public input 4, and it is the same\n * contract that verifies the proof — so recomputing the value client-side would mean re-deriving\n * the round's snapshot, its divisor and the rounding, and any drift surfaces only as an opaque\n * verifier failure.\n *\n * @param programAddress - The CRISP program address\n * @param e3Id - The e3Id of the round\n * @param slot - The slot address the ballot is written to\n * @param chainId - The chain the program is deployed on\n * @param rpcUrl - Endpoint to read through; see {@link getOnChainRoundData}.\n * @returns The spendable voting power in ballot units, or 0 for a round that is not ONCHAIN\n */\nexport const getOnchainVotingPower = async (\n programAddress: string,\n e3Id: bigint,\n slot: string,\n chainId: number,\n rpcUrl?: string,\n): Promise<bigint> => {\n const publicClient = getPublicClient(chainId, rpcUrl)\n\n return publicClient.readContract({\n address: programAddress as `0x${string}`,\n abi: parseAbi(['function votingPowerOf(uint256 e3Id, address slot) view returns (uint256)']),\n functionName: 'votingPowerOf',\n args: [e3Id, slot as `0x${string}`],\n })\n}\n\n/**\n * Get the previous ciphertext for a slot from the CRISP server.\n * Returns undefined when the slot is empty (404).\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @param address - The address of the slot\n * @returns The end of the slot's chain of usable entries and its tree index, or undefined when the\n * slot holds nothing usable. The index is what a new input names as its parent.\n */\nexport const getPreviousCiphertext = async (serverUrl: string, e3Id: bigint, address: string): Promise<SlotHead | undefined> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_PREVIOUS_CIPHERTEXT_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ round_id: e3Id.toString(), address }),\n })\n\n if (response.status === 404) {\n return undefined\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch previous ciphertext: ${response.statusText}`)\n }\n\n const data = await response.json()\n\n return { ciphertext: new Uint8Array(data.ciphertext), index: Number(data.index) }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n CRISP_SERVER_ELIGIBLE_ADDRESSES_ENDPOINT,\n CRISP_SERVER_ROUNDS_CIPHERTEXT_ENDPOINT,\n CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT,\n CRISP_SERVER_ROUNDS_PUBLIC_KEY_ENDPOINT,\n CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT,\n CRISP_SERVER_STATE_ALL_ENDPOINT,\n CRISP_SERVER_STATE_LITE_ENDPOINT,\n CRISP_SERVER_STATE_RESULT_ENDPOINT,\n CRISP_SERVER_TOKEN_TREE_ENDPOINT,\n CRISP_SERVER_VOTING_BROADCAST_ENDPOINT,\n CRISP_SERVER_VOTING_STATUS_ENDPOINT,\n CRISP_SERVER_CHAIN_HEAD_ENDPOINT,\n CRISP_SERVER_CHAIN_READ_ENDPOINT,\n CRISP_SERVER_CHAIN_LOGS_ENDPOINT,\n CRISP_SERVER_CHAIN_BLOCK_AT_TIMESTAMP_ENDPOINT,\n CRISP_SERVER_CHAIN_RPC_ENDPOINT,\n} from './constants'\n\nimport type {\n ChainHead,\n ContractRead,\n ContractReadResult,\n IndexedLog,\n LogQuery,\n BroadcastVoteRequest,\n BroadcastVoteResponse,\n CurrentRoundResponse,\n E3StateLiteResponse,\n JsonResponse,\n NewRoundRequest,\n TokenHolder,\n VoteStatusResponse,\n WebResultResponse,\n} from './types'\n\n/**\n * POST a JSON body to a CRISP server endpoint and parse the JSON response.\n * @param serverUrl - The base URL of the CRISP server\n * @param endpoint - The endpoint path (without leading slash)\n * @param body - The request body to serialize as JSON\n * @returns The parsed JSON response\n * @throws If the server responds with a non-OK status\n */\nconst postJson = async <TResponse>(serverUrl: string, endpoint: string, body: unknown): Promise<TResponse> => {\n const response = await fetch(`${serverUrl}/${endpoint}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) {\n throw new Error(`CRISP server request to /${endpoint} failed (${response.status}): ${await response.text()}`)\n }\n\n return (await response.json()) as TResponse\n}\n\n/**\n * Get the current (most recent) round, optionally filtered by requester addresses.\n * Returns undefined when no current round exists (404).\n * @param serverUrl - The base URL of the CRISP server\n * @param requesters - Optional list of requester addresses to filter by (only the first is used by the server)\n * @returns The current round id, or undefined if none exists\n */\nexport const getCurrentRound = async (serverUrl: string, requesters: string[] = []): Promise<CurrentRoundResponse | undefined> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ requesters }),\n })\n\n if (response.status === 404) {\n return undefined\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch current round (${response.status}): ${await response.text()}`)\n }\n\n return (await response.json()) as CurrentRoundResponse\n}\n\n/**\n * Get the committee public key for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The committee public key bytes\n */\nexport const getRoundPublicKey = async (serverUrl: string, e3Id: bigint): Promise<Uint8Array> => {\n const data = await postJson<{ round_id: string; pk_bytes: number[] }>(serverUrl, CRISP_SERVER_ROUNDS_PUBLIC_KEY_ENDPOINT, {\n round_id: e3Id.toString(),\n pk_bytes: [],\n })\n\n return new Uint8Array(data.pk_bytes)\n}\n\n/**\n * Get the ciphertext output for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The ciphertext output bytes\n */\nexport const getRoundCiphertext = async (serverUrl: string, e3Id: bigint): Promise<Uint8Array> => {\n const data = await postJson<{ round_id: string; ct_bytes: number[] }>(serverUrl, CRISP_SERVER_ROUNDS_CIPHERTEXT_ENDPOINT, {\n round_id: e3Id.toString(),\n ct_bytes: [],\n })\n\n return new Uint8Array(data.ct_bytes)\n}\n\n/**\n * Request a new E3 round. Requires the server's cron API key.\n * @param serverUrl - The base URL of the CRISP server\n * @param request - The new round request (cron API key, token address and balance threshold)\n * @returns The server confirmation message\n */\nexport const requestNewRound = async (serverUrl: string, request: NewRoundRequest): Promise<JsonResponse> =>\n postJson<JsonResponse>(serverUrl, CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT, {\n cron_api_key: request.cronApiKey,\n token_address: request.tokenAddress,\n balance_threshold: request.balanceThreshold,\n census_mode: request.censusMode,\n })\n\n/**\n * Broadcast an encrypted vote through the CRISP server, which relays it on-chain.\n * @param serverUrl - The base URL of the CRISP server\n * @param request - The vote request (round id and hex encoded proof)\n * @returns The broadcast result, including the transaction hash on success\n */\nexport const broadcastVote = async (serverUrl: string, request: BroadcastVoteRequest): Promise<BroadcastVoteResponse> => {\n const response = await fetch(`${serverUrl}/${CRISP_SERVER_VOTING_BROADCAST_ENDPOINT}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n round_id: request.e3Id.toString(),\n encoded_proof: request.encodedProof,\n }),\n })\n\n // The server returns a structured VoteResponse body for broadcast failures (500) as well\n const data = (await response.json()) as BroadcastVoteResponse | string\n\n if (typeof data === 'string') {\n throw new Error(`Failed to broadcast vote (${response.status}): ${data}`)\n }\n\n return data\n}\n\n/**\n * Get the vote status for an address in a specific round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @param address - The voter address\n * @returns The vote status for the address\n */\nexport const getVoteStatus = async (serverUrl: string, e3Id: bigint, address: string): Promise<VoteStatusResponse> =>\n postJson<VoteStatusResponse>(serverUrl, CRISP_SERVER_VOTING_STATUS_ENDPOINT, { round_id: e3Id.toString(), address })\n\n/**\n * Get the result for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The round result (tally, emojis, total votes, end time and requester)\n */\nexport const getRoundResult = async (serverUrl: string, e3Id: bigint): Promise<WebResultResponse> =>\n postJson<WebResultResponse>(serverUrl, CRISP_SERVER_STATE_RESULT_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * Get the results for all rounds, optionally filtered by requester addresses.\n * @param serverUrl - The base URL of the CRISP server\n * @param requesters - Optional list of requester addresses to filter by\n * @returns The results for all matching rounds\n */\nexport const getAllRoundResults = async (serverUrl: string, requesters: string[] = []): Promise<WebResultResponse[]> =>\n postJson<WebResultResponse[]>(serverUrl, CRISP_SERVER_STATE_ALL_ENDPOINT, { requesters })\n\n/**\n * Get the lite state for a given round, as returned by the server (snake_case fields).\n * See `getRoundDetails` in `state.ts` for a camelCase convenience wrapper over this endpoint.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The lite round state\n */\nexport const getRoundStateLite = async (serverUrl: string, e3Id: bigint): Promise<E3StateLiteResponse> =>\n postJson<E3StateLiteResponse>(serverUrl, CRISP_SERVER_STATE_LITE_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * Get the token holder hashes (hash(address, balance)) for a given round.\n * These are the Merkle tree leaves used for eligibility proofs.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The list of token holder hashes\n */\nexport const getTokenHolderHashes = async (serverUrl: string, e3Id: bigint): Promise<string[]> =>\n postJson<string[]>(serverUrl, CRISP_SERVER_TOKEN_TREE_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * Get the eligible addresses and their balances for a given round.\n * @param serverUrl - The base URL of the CRISP server\n * @param e3Id - The e3Id of the round\n * @returns The list of eligible token holders\n */\nexport const getEligibleAddresses = async (serverUrl: string, e3Id: bigint): Promise<TokenHolder[]> =>\n postJson<TokenHolder[]>(serverUrl, CRISP_SERVER_ELIGIBLE_ADDRESSES_ENDPOINT, { round_id: e3Id.toString() })\n\n/**\n * The chain head (block number, timestamp, chain id) as seen by the CRISP server.\n *\n * One call in place of polling `eth_blockNumber` from every hook that wants to know whether\n * something has advanced, and it carries the timestamp so a caller deciding whether a voting\n * window has closed does not need a second round trip for the block.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @returns The current head\n */\nexport const getChainHead = async (serverUrl: string): Promise<ChainHead> => {\n const data = await postJson<{ block_number: number | string; timestamp: number | string; chain_id: number }>(\n serverUrl,\n CRISP_SERVER_CHAIN_HEAD_ENDPOINT,\n {},\n )\n\n return {\n blockNumber: BigInt(data.block_number),\n timestamp: BigInt(data.timestamp),\n chainId: Number(data.chain_id),\n }\n}\n\n/**\n * Read allowlisted contracts through the CRISP server, batched.\n *\n * Point reads are answered from the chain rather than from the server's index on purpose: they\n * are per-account and change constantly, and a stale answer here is not a slow UI but a wrong\n * balance or a voter wrongly told they cannot vote.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param calls - The calls to perform, in order\n * @returns One result per call, in the same order\n */\nexport const readContracts = async (serverUrl: string, calls: ContractRead[]): Promise<ContractReadResult[]> => {\n if (calls.length === 0) return []\n\n const data = await postJson<{ result: string | null; error: string | null }[]>(serverUrl, CRISP_SERVER_CHAIN_READ_ENDPOINT, {\n calls: calls.map((call) => ({\n address: call.address,\n data: call.data,\n block_number: call.blockNumber !== undefined ? Number(call.blockNumber) : undefined,\n })),\n })\n\n return data.map((entry) => ({\n result: entry.result ? (entry.result as `0x${string}`) : undefined,\n error: entry.error ?? undefined,\n }))\n}\n\n/**\n * Query logs for an allowlisted contract over an arbitrary block range.\n *\n * The range needs no chunking by the caller: the server splits it into windows the upstream\n * provider accepts, which is the whole reason clients otherwise carry range-splitting code.\n *\n * It is still BOUNDED — the server refuses a span wider than a million blocks, and `fromBlock`\n * defaults to 0, so a query naming only an address is rejected on a long-lived chain. Pass the\n * contract's deployment block as `fromBlock`; that is the intended usage and always in range.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param query - The log query\n * @returns The matching logs, ordered by block and log index\n */\nexport const getIndexedLogs = async (serverUrl: string, query: LogQuery): Promise<IndexedLog[]> => {\n const data = await postJson<\n {\n address: string\n topics: string[]\n data: string\n block_number: number | null\n transaction_hash: string | null\n log_index: number | null\n }[]\n >(serverUrl, CRISP_SERVER_CHAIN_LOGS_ENDPOINT, {\n address: query.address,\n topics: (query.topics ?? []).map((topic) => topic ?? null),\n from_block: query.fromBlock !== undefined ? Number(query.fromBlock) : undefined,\n to_block: query.toBlock !== undefined ? Number(query.toBlock) : undefined,\n })\n\n return data.map((log) => ({\n address: log.address,\n topics: log.topics as `0x${string}`[],\n data: log.data as `0x${string}`,\n blockNumber: log.block_number !== null ? BigInt(log.block_number) : undefined,\n transactionHash: log.transaction_hash ?? undefined,\n logIndex: log.log_index ?? undefined,\n }))\n}\n\n/**\n * The last block at or before a timestamp.\n *\n * Clients need this to turn a proposal's snapshot timepoint into a block. Done client-side it is\n * a binary search costing `O(log n)` block fetches per lookup; the server spends those on its own\n * connection instead.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param timestamp - The unix timestamp to resolve\n * @returns The block at or before the timestamp, and that block's timestamp\n */\nexport const getBlockAtTimestamp = async (serverUrl: string, timestamp: bigint): Promise<{ blockNumber: bigint; timestamp: bigint }> => {\n const data = await postJson<{ block_number: number | string; timestamp: number | string }>(\n serverUrl,\n CRISP_SERVER_CHAIN_BLOCK_AT_TIMESTAMP_ENDPOINT,\n { timestamp: Number(timestamp) },\n )\n\n return { blockNumber: BigInt(data.block_number), timestamp: BigInt(data.timestamp) }\n}\n\n/**\n * The URL of the server's read-only JSON-RPC endpoint.\n *\n * Point a standard Ethereum client at this to read the allowlisted contracts without a\n * hosted-provider key. It serves reads only — transactions are signed and broadcast by the\n * user's wallet, which brings its own transport.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @returns The JSON-RPC URL\n */\nexport const chainRpcUrl = (serverUrl: string): string => `${serverUrl.replace(/\\/+$/, '')}/${CRISP_SERVER_CHAIN_RPC_ENDPOINT}`\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { poseidon2 } from 'poseidon-lite'\nimport { LeanIMT } from '@zk-kit/lean-imt'\nimport type { MerkleProof } from './types'\nimport { MAX_MSG_NON_ZERO_COEFFS, MERKLE_TREE_MAX_DEPTH, SIGNATURE_MESSAGE_HASH } from './constants'\nimport { publicKeyToAddress } from 'viem/utils'\nimport { hexToBytes, recoverPublicKey } from 'viem'\n\n/**\n * Hash a leaf node for the Merkle tree\n * @param address The voter's address\n * @param balance The voter's balance\n * @returns The hashed leaf as a bigint\n */\nexport const hashLeaf = (address: string, balance: bigint): bigint => {\n return poseidon2([address.toLowerCase(), balance])\n}\n\n/**\n * Generate a new LeanIMT with the leaves provided\n * @param leaves The leaves of the Merkle tree\n * @returns the generated Merkle tree\n */\nexport const generateMerkleTree = (leaves: bigint[]): LeanIMT => {\n return new LeanIMT((a, b) => poseidon2([a, b]), leaves)\n}\n\n/**\n * Generate a Merkle proof for a given address to prove inclusion in the voters' list\n * @param balance The voter's balance\n * @param address The voter's address\n * @param leaves The leaves of the Merkle tree\n */\nexport const generateMerkleProof = (balance: bigint, address: string, leaves: bigint[] | string[]): MerkleProof => {\n const leaf = hashLeaf(address.toLowerCase(), balance)\n\n const index = leaves.findIndex((l) => BigInt(l) === leaf)\n\n if (index === -1) {\n throw new Error('Leaf not found in the tree')\n }\n\n const tree = generateMerkleTree(leaves.map((l) => BigInt(l)))\n\n const proof = tree.generateProof(index)\n\n // Pad siblings with zeros\n const paddedSiblings = [...proof.siblings, ...Array(MERKLE_TREE_MAX_DEPTH - proof.siblings.length).fill(0n)]\n // Pad indices with zeros\n const indices = proof.siblings.map((_, i) => Number((BigInt(proof.index) >> BigInt(i)) & 1n))\n const paddedIndices = [...indices, ...Array(MERKLE_TREE_MAX_DEPTH - indices.length).fill(0)]\n\n return {\n leaf,\n index,\n proof: {\n ...proof,\n siblings: paddedSiblings,\n },\n // Original length before padding\n length: proof.siblings.length,\n indices: paddedIndices,\n }\n}\n\n/**\n * Convert a number to its binary representation\n * @param number The number to convert to binary\n * @returns The binary representation of the number as a string\n */\nexport const toBinary = (number: number): string => {\n if (number < 0) {\n throw new Error('Value cannot be negative')\n }\n\n return number.toString(2)\n}\n\n/**\n * Given a signature, extract the signature components for the Noir signature verification circuit.\n * @param signature The signature to extract the components from.\n * @returns The extracted signature components.\n */\nexport const extractSignatureComponents = async (\n signature: `0x${string}`,\n messageHash: `0x${string}` = SIGNATURE_MESSAGE_HASH,\n): Promise<{\n messageHash: Uint8Array\n publicKeyX: Uint8Array\n publicKeyY: Uint8Array\n signature: Uint8Array\n}> => {\n const publicKey = await recoverPublicKey({ hash: messageHash, signature })\n const publicKeyBytes = hexToBytes(publicKey)\n const publicKeyX = publicKeyBytes.slice(1, 33)\n const publicKeyY = publicKeyBytes.slice(33, 65)\n\n // Extract r and s from signature (remove v)\n const sigBytes = hexToBytes(signature)\n const r = sigBytes.slice(0, 32) // First 32 bytes\n const s = sigBytes.slice(32, 64) // Next 32 bytes\n\n const signatureBytes = new Uint8Array(64)\n signatureBytes.set(r, 0)\n signatureBytes.set(s, 32)\n\n return {\n messageHash: hexToBytes(messageHash),\n publicKeyX: publicKeyX,\n publicKeyY: publicKeyY,\n signature: signatureBytes,\n }\n}\n\nexport const getAddressFromSignature = async (signature: `0x${string}`, messageHash?: `0x${string}`): Promise<string> => {\n const publicKey = await recoverPublicKey({ hash: messageHash || SIGNATURE_MESSAGE_HASH, signature })\n\n return publicKeyToAddress(publicKey)\n}\n\n/**\n * Get the maximum vote value for a given number of choices.\n * @param numChoices Number of choices.\n * @returns Maximum value per choice.\n */\nexport const getMaxVoteValue = (numChoices: number): number => {\n const segmentSize = Math.floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)\n return 2 ** segmentSize - 1\n}\n\n/**\n * Get a zero vote with the given number of choices.\n * @param numChoices Number of choices.\n * @returns A zero vote with the given number of choices.\n */\nexport const getZeroVote = (numChoices: number): number[] => {\n return Array(numChoices).fill(0)\n}\n\n/**\n * Decode bytes to a bigint array (little-endian, 8 bytes per value).\n *\n * @remarks\n * Returns `bigint` rather than `number`: a coefficient of an aggregated plaintext\n * is a sum over all ballots and can exceed `Number.MAX_SAFE_INTEGER`.\n *\n * @param data The bytes to decode (must be multiple of 8).\n * @returns Array of coefficients.\n */\nexport const decodeBytesToBigInts = (data: Uint8Array): bigint[] => {\n if (data.length % 8 !== 0) {\n throw new Error('Data length must be multiple of 8')\n }\n\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength)\n const arrayLength = data.length / 8\n const result: bigint[] = []\n\n for (let i = 0; i < arrayLength; i++) {\n result.push(view.getBigUint64(i * 8, true)) // true = little-endian\n }\n\n return result\n}\n\nexport const bigInt64ArrayToNumberArray = (bigInt64Array: BigInt64Array): number[] => {\n return Array.from(bigInt64Array).map(Number)\n}\n\nexport const numberArrayToBigInt64Array = (numberArray: number[]): BigInt64Array => {\n return BigInt64Array.from(numberArray.map(BigInt))\n}\n\n// Helper function to convert proof bytes to field elements\nexport const proofToFields = (proof: Uint8Array): string[] => {\n const fields: string[] = []\n for (let i = 0; i < proof.length; i += 32) {\n const chunk = proof.slice(i, i + 32)\n fields.push('0x' + Buffer.from(chunk).toString('hex'))\n }\n return fields\n}\n\n/**\n * Scale down the raw balance to 1 decimal precision\n * @param balance - The raw balance (with all tokens decimals)\n * @param decimals - The decimals of the token\n * @returns The balance as a .1 precision scaled value\n */\nexport const getScaledBalance = (balance: bigint, decimals: bigint): bigint => {\n const precision = decimals > 1n ? decimals - 1n : 0n\n\n return balance / 10n ** precision\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\n/**\n * Vote encoding and BFV encryption for the CRISP voting protocol.\n *\n * Encodes vote choices (numbers per option) into polynomial coefficient arrays\n * suitable for BFV homomorphic encryption. Each choice is represented as a\n * segment of binary digits within the first MAX_MSG_NON_ZERO_COEFFS coeffs, then\n * zero-padded to the BFV polynomial degree. Supports\n * encoding, encryption, decryption, and tally decoding.\n */\n\nimport { ZKInputsGenerator } from '@crisp-e3/zk-inputs'\nimport { registeredPreset, type CircuitPreset } from './circuits'\nimport { toBinary, numberArrayToBigInt64Array, decodeBytesToBigInts, getMaxVoteValue } from './utils'\nimport { MAX_MSG_NON_ZERO_COEFFS, MAX_VOTE_OPTIONS } from './constants'\nimport { hexToBytes } from 'viem'\nimport type { Hex } from 'viem'\nimport type { TallyResult, Vote } from './types'\n\nlet _zkInputsGenerator: InstanceType<typeof ZKInputsGenerator> | null = null\nlet _zkInputsGeneratorPreset: CircuitPreset | 'default' | null = null\nlet _zkInputsGeneratorPresetOverride: CircuitPreset | null = null\n\n/** Set or clear the BFV preset override for contexts that do not share the registered bundle. */\nexport const setZkInputsGeneratorPreset = (preset: CircuitPreset | null): void => {\n if (_zkInputsGeneratorPresetOverride !== preset) {\n _zkInputsGenerator = null\n _zkInputsGeneratorPreset = null\n _zkInputsGeneratorPresetOverride = preset\n }\n}\n\n/**\n * Returns the singleton ZK inputs generator instance for the registered BFV preset.\n */\nexport const getZkInputsGenerator = () => {\n const preset = _zkInputsGeneratorPresetOverride ?? registeredPreset()\n const targetPreset = preset ?? 'default'\n\n if (!_zkInputsGenerator || _zkInputsGeneratorPreset !== targetPreset) {\n _zkInputsGenerator = preset ? ZKInputsGenerator.fromPreset(preset) : ZKInputsGenerator.withDefaults()\n _zkInputsGeneratorPreset = targetPreset\n }\n\n return _zkInputsGenerator\n}\n\n/**\n * Encodes vote choices into a polynomial coefficient array for BFV encryption.\n * Each choice occupies floor(MAX_MSG_NON_ZERO_COEFFS / n) binary coefficients;\n * remaining slots in the first MAX_MSG_NON_ZERO_COEFFS coeffs are zero; then\n * the vector is padded to the BFV degree.\n *\n * @param vote - Array of numeric values per choice (e.g. [10, 5] for 2 options)\n * @returns Array of 0s and 1s representing coefficients\n * @throws If vote has fewer than 2 choices, any value exceeds max for its segment, or degree is too small\n */\nexport const encodeVote = (vote: Vote): number[] => {\n const numChoices = vote.length\n\n if (numChoices < 2) {\n throw new Error('Vote must have at least two choices')\n }\n\n // The Noir circuit asserts num_options <= MAX_OPTIONS, so a vote beyond this can never\n // produce a valid proof. Reject it here rather than encoding an unprovable vote.\n if (numChoices > MAX_VOTE_OPTIONS) {\n throw new Error(`Number of choices (${numChoices}) exceeds MAX_VOTE_OPTIONS (${MAX_VOTE_OPTIONS})`)\n }\n\n const bfvParams = getZkInputsGenerator().getBFVParams()\n const degree = bfvParams.degree\n if (degree < MAX_MSG_NON_ZERO_COEFFS) {\n throw new Error(`BFV degree (${degree}) must be at least MAX_MSG_NON_ZERO_COEFFS (${MAX_MSG_NON_ZERO_COEFFS})`)\n }\n\n const segmentSize = Math.floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)\n const maxValue = getMaxVoteValue(numChoices)\n const voteArray: number[] = []\n\n for (let choiceIdx = 0; choiceIdx < numChoices; choiceIdx += 1) {\n const value = vote[choiceIdx]\n\n if (value > maxValue) {\n throw new Error(`Vote value for choice ${choiceIdx} exceeds maximum (${maxValue})`)\n }\n\n const binary = toBinary(value).split('')\n\n for (let i = 0; i < segmentSize; i += 1) {\n const offset = segmentSize - binary.length\n voteArray.push(i < offset ? 0 : parseInt(binary[i - offset], 10))\n }\n }\n\n const msgCoeffsUsed = segmentSize * numChoices\n for (let i = msgCoeffsUsed; i < MAX_MSG_NON_ZERO_COEFFS; i += 1) {\n voteArray.push(0)\n }\n\n for (let i = 0; i < degree - MAX_MSG_NON_ZERO_COEFFS; i += 1) {\n voteArray.push(0)\n }\n\n return voteArray\n}\n\n/**\n * Encrypts an encoded vote using BFV homomorphic encryption.\n *\n * @param vote - Vote choices to encrypt\n * @param publicKey - BFV public key\n * @returns Encrypted ciphertext\n */\nexport const encryptVote = (vote: Vote, publicKey: Uint8Array): Uint8Array => {\n const encodedVote = encodeVote(vote)\n\n return getZkInputsGenerator().encryptVote(publicKey, numberArrayToBigInt64Array(encodedVote))\n}\n\n/**\n * Decodes raw tally bytes (or coefficients) into a total per choice.\n * Expects the same segment layout as used in encodeVote.\n *\n * Mirrors `crisp_utils::decode_tally` (Rust) and `CRISPProgram.decodeTally` (Solidity):\n * only the first MAX_MSG_NON_ZERO_COEFFS coefficients carry the payload, split into\n * `floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)` binary coefficients per choice, MSB first.\n *\n * @param tallyBytes - Hex string, or the polynomial coefficients from tally/decryption\n * @param numChoices - Number of vote options: an integer from 2 to MAX_VOTE_OPTIONS\n * @returns One total per choice\n * @throws If numChoices is outside 2..MAX_VOTE_OPTIONS or not an integer, or there are fewer\n * coefficients than the payload region\n */\nexport const decodeTally = (tallyBytes: string | number[] | bigint[], numChoices: number): TallyResult => {\n // `CRISPProgram.validate` rejects a round outside 2..MAX_VOTE_OPTIONS, and `encodeVote` refuses\n // to encode fewer than two choices, so no tally in that range can exist. `Number.isInteger` also\n // screens out NaN, Infinity, and fractions: a fractional count silently returns `ceil(numChoices)`\n // segments, and NaN passes both bound checks to return an empty tally.\n if (!Number.isInteger(numChoices) || numChoices < 2) {\n throw new Error(`Number of choices (${numChoices}) must be an integer of at least 2`)\n }\n\n // Rounds cannot exceed MAX_VOTE_OPTIONS (the circuit's MAX_OPTIONS), so a larger count\n // is a caller error rather than a tally to decode.\n if (numChoices > MAX_VOTE_OPTIONS) {\n throw new Error(`Number of choices (${numChoices}) exceeds MAX_VOTE_OPTIONS (${MAX_VOTE_OPTIONS})`)\n }\n\n let coefficients: bigint[]\n if (typeof tallyBytes === 'string') {\n const hexString = tallyBytes.startsWith('0x') ? tallyBytes : `0x${tallyBytes}`\n coefficients = decodeBytesToBigInts(hexToBytes(hexString as Hex))\n } else {\n coefficients = (tallyBytes as Array<number | bigint>).map(BigInt)\n }\n\n if (coefficients.length < MAX_MSG_NON_ZERO_COEFFS) {\n throw new Error(`decoded coefficient count (${coefficients.length}) is less than MAX_MSG_NON_ZERO_COEFFS (${MAX_MSG_NON_ZERO_COEFFS})`)\n }\n\n const segmentSize = Math.floor(MAX_MSG_NON_ZERO_COEFFS / numChoices)\n const results: TallyResult = []\n\n for (let choiceIdx = 0; choiceIdx < numChoices; choiceIdx++) {\n const segmentStart = choiceIdx * segmentSize\n\n let value = 0n\n for (let i = 0; i < segmentSize; i++) {\n value += coefficients[segmentStart + i] << BigInt(segmentSize - 1 - i)\n }\n\n results.push(value)\n }\n\n return results\n}\n\n/**\n * Decrypts a BFV-encrypted vote and decodes it to vote values.\n *\n * @param ciphertext - Encrypted vote\n * @param secretKey - BFV secret key\n * @param numChoices - Number of vote options\n * @returns One total per choice\n */\nexport const decryptVote = (ciphertext: Uint8Array, secretKey: Uint8Array, numChoices: number): TallyResult => {\n const decryptedVote = getZkInputsGenerator().decryptVote(secretKey, ciphertext)\n\n return decodeTally(\n Array.from(decryptedVote, (value) => BigInt(value)),\n numChoices,\n )\n}\n\n/**\n * Generates a BFV keypair for vote encryption and decryption.\n *\n * @returns Object with secretKey and publicKey as Uint8Arrays\n */\nexport const generateBFVKeys = (): { secretKey: Uint8Array; publicKey: Uint8Array } => {\n return getZkInputsGenerator().generateKeys()\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { getZkInputsGenerator, encodeVote } from './encoding'\nimport { extractSignatureComponents, generateMerkleProof, getZeroVote, numberArrayToBigInt64Array } from './utils'\nimport type { PreparedBallot, PrepareBallotInputs } from './types'\n\n/**\n * Split a 32-byte digest into the two 16-byte halves the circuit takes as public inputs.\n *\n * A Keccak digest is 256 bits and a field element holds fewer than 254, so it cannot cross the\n * circuit boundary in one piece. `crisp_lib::ecdsa::digest_from_halves` rebuilds the 32 bytes and\n * range-checks each half, and `CRISPProgram.publishInput` splits the same way.\n *\n * @param digest The 32-byte ballot digest.\n * @returns The high and low halves as hex field elements.\n */\nexport const splitDigest = (digest: `0x${string}`): { digestHi: `0x${string}`; digestLo: `0x${string}` } => {\n if (digest.length !== 66) {\n throw new Error(`Invalid digest: expected 32 bytes, got ${(digest.length - 2) / 2}`)\n }\n\n return {\n digestHi: `0x${digest.slice(2, 34)}`,\n digestLo: `0x${digest.slice(34, 66)}`,\n }\n}\n\n/**\n * Phase one of building a ballot: encrypt the vote and build every circuit input that does not\n * depend on the signature.\n *\n * Kept separate from the signature because the digest a voter signs binds the ciphertext, so the\n * ciphertext has to exist first. The returned `ctCommitment` is what `CRISPProgram.ballotDigest`\n * takes as its `ciphertextCommitment` argument.\n *\n * One path for all three operations. A first vote, a re-vote, and a mask reach the same generator\n * with the same arguments, differ only in `isMaskVote` — which stays private to the proof — and\n * produce the same shape of submission. Branching here would make the three tellable apart by\n * anything watching the client, which is what masks exist to prevent.\n *\n * Kept in a separate module so it can run in a worker.\n *\n * @param inputs The ballot to prepare.\n * @returns The partial circuit inputs, the ciphertext, and its commitment.\n */\nexport const prepareCircuitInputsImpl = async (inputs: PrepareBallotInputs): Promise<PreparedBallot> => {\n const zkInputsGenerator = getZkInputsGenerator()\n\n const numOptions = inputs.isMaskVote ? inputs.numOptions : inputs.vote.length\n const vote = inputs.isMaskVote ? getZeroVote(numOptions) : inputs.vote\n const encodedVote = encodeVote(vote)\n\n // Only a mask adds to what the slot already holds. A vote replaces it, so a voter cannot have\n // their old ballot counted alongside the new one. The circuit derives the same choice from\n // `is_mask_vote` and rejects any witness built the other way.\n const keepPrevious = inputs.isMaskVote && !!inputs.previousCiphertext\n\n const { inputs: circuitInputs, encryptedVote } = await zkInputsGenerator.generateInputs(\n inputs.previousCiphertext,\n inputs.publicKey,\n numberArrayToBigInt64Array(encodedVote),\n keepPrevious,\n )\n\n circuitInputs.slot_address = inputs.slotAddress.toLowerCase()\n circuitInputs.is_first_vote = !inputs.previousCiphertext\n circuitInputs.is_mask_vote = inputs.isMaskVote\n circuitInputs.num_options = numOptions.toString()\n\n if (inputs.censusMode === 'onchain') {\n circuitInputs.voting_power = inputs.votingPower.toString()\n } else {\n // Derived here rather than by the caller. The old API recovered the slot address from the\n // signature to build this, which is no longer possible: the signature now comes after the\n // ciphertext, and the caller states the slot address instead.\n const merkleProof = generateMerkleProof(inputs.balance, inputs.slotAddress, inputs.merkleLeaves)\n\n circuitInputs.balance = inputs.balance.toString()\n circuitInputs.merkle_root = merkleProof.proof.root.toString()\n circuitInputs.merkle_proof_length = merkleProof.length.toString()\n circuitInputs.merkle_proof_indices = merkleProof.indices.map((i) => i === 1)\n circuitInputs.merkle_proof_siblings = merkleProof.proof.siblings.map((s) => s.toString())\n }\n\n // The commitment to `encryptedVote`, which is the ciphertext this ballot publishes: the ballot\n // itself for a vote or a re-vote, the slot plus the zero ballot for a mask over an occupied slot.\n // The circuit returns the same value as `final_ct_commitment`, `CRISPProgram` stores it, and\n // `CRISPProgram.ballotDigest` is built over it — so it is what a voter has to sign, and it has to\n // be known before proving because the digest is itself a circuit input.\n //\n // Exported by the wasm alongside the witness. Recomputing it here would have to match\n // `compute_ciphertext_commitment` exactly, so it is carried across instead.\n const ctCommitment = `0x${BigInt(circuitInputs.sum_ct_commitment).toString(16).padStart(64, '0')}` as `0x${string}`\n\n // Zero when there is nothing to extend, which is what the contract reads as `is_first_vote`.\n //\n // Checked at runtime as well as in the type, because a caller reaching this through plain\n // JavaScript or a widened object gets no type error. Defaulting a missing index to zero would\n // name the slot's first entry as the parent, and the proof would be built against one commitment\n // while the contract supplied another — visible only as a rejected proof.\n if (inputs.previousCiphertext !== undefined) {\n const index = inputs.previousIndex\n // Non-negative and safe, not merely an integer. `-1` would come back out as zero, which the\n // contract reads as \"extends nothing\" — a re-vote silently published as a first vote against a\n // slot that already holds one. Anything at or above `MAX_SAFE_INTEGER` cannot represent\n // `index + 1` exactly, so the parent it names is not the parent it meant.\n if (!Number.isSafeInteger(index) || (index as number) < 0 || (index as number) + 1 > Number.MAX_SAFE_INTEGER) {\n throw new Error(\n `previousCiphertext needs a non-negative safe integer previousIndex; got ${String(index)}. Pass the slot head as a pair.`,\n )\n }\n }\n\n const parentIndexPlusOne = inputs.previousCiphertext !== undefined ? (inputs.previousIndex as number) + 1 : 0\n\n return { circuitInputs, encryptedVote, ctCommitment, parentIndexPlusOne, censusMode: inputs.censusMode }\n}\n\n/**\n * Phase two: attach the signed digest to a prepared ballot.\n *\n * The digest is a public input in both branches, because `CRISPProgram.publishInput` computes it\n * for every input. A mask carries the same digest as a real vote and only skips the signature\n * check inside the circuit, which is what keeps the two indistinguishable on chain.\n *\n * @param prepared The output of `prepareCircuitInputsImpl`.\n * @param digest The digest from `CRISPProgram.ballotDigest`.\n * @param signature The signature over that digest. A mask passes the placeholder signature.\n * @returns The complete circuit inputs.\n */\nexport const attachSignatureImpl = async (prepared: PreparedBallot, digest: `0x${string}`, signature: `0x${string}`): Promise<any> => {\n const { digestHi, digestLo } = splitDigest(digest)\n const components = await extractSignatureComponents(signature, digest)\n\n const circuitInputs = prepared.circuitInputs\n circuitInputs.digest_hi = digestHi\n circuitInputs.digest_lo = digestLo\n circuitInputs.public_key_x = Array.from(components.publicKeyX).map((b) => b.toString())\n circuitInputs.public_key_y = Array.from(components.publicKeyY).map((b) => b.toString())\n circuitInputs.signature = Array.from(components.signature).map((b) => b.toString())\n\n return circuitInputs\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { type Vote, type CensusVariant, type PrepareBallotInputs, type PreparedBallot, ProofData } from './types'\nimport { getMaxVoteValue, proofToFields } from './utils'\nimport { attachSignatureImpl, prepareCircuitInputsImpl } from './circuitInputs'\nimport { MASK_SIGNATURE } from './constants'\nexport { encodeVote, encryptVote, decodeTally, decryptVote, generateBFVKeys } from './encoding'\nexport { splitDigest } from './circuitInputs'\nimport { Noir, type CompiledCircuit } from '@noir-lang/noir_js'\nimport { Barretenberg, BackendType, UltraHonkBackend } from '@aztec/bb.js'\n// Only the aggregation circuits are imported here. Their ABI is proof and verification-key shaped\n// rather than polynomial shaped, so one artifact serves every preset and inlining them costs ~0.3MB.\n// The BFV-shaped circuits arrive through `setCircuits()` — see ./circuits.\nimport foldCircuit from '../../../circuits/bin/fold/target/crisp_fold.json'\nimport foldOnchainCircuit from '../../../circuits/bin/fold_onchain/target/crisp_onchain_fold.json'\nimport userDataEncryptionCircuit from '../../../../../circuits/bin/threshold/target/user_data_encryption.json'\nimport { requireCircuits } from './circuits'\nimport { bytesToHex, encodeAbiParameters, parseAbiParameters, numberToHex, getAddress } from 'viem/utils'\nimport { Hex } from 'viem'\n\n// Cached Barretenberg API instance — avoids re-initialising WASM + SRS on every proof.\nlet _bbApi: Barretenberg | null = null\nlet _bbApiInitPromise: Promise<Barretenberg> | null = null\n\nconst getBBApi = async (): Promise<Barretenberg> => {\n if (_bbApi) return _bbApi\n if (_bbApiInitPromise) return _bbApiInitPromise\n\n _bbApiInitPromise = (async () => {\n try {\n // Outside the browser, bb.js prefers its native Unix-socket backend, allows the bb\n // process only 5s to create the socket, and drops the timeout into an unhandled\n // rejection — callers then wait forever instead of failing. Pin Node to WASM. The\n // browser is unaffected: it already selects the (multi-threaded) worker backend.\n const backend = typeof window === 'undefined' ? { backend: BackendType.Wasm } : {}\n const api = await Barretenberg.new({ srsSize: 2 ** 21, ...backend })\n _bbApi = api\n return api\n } finally {\n _bbApiInitPromise = null\n }\n })()\n\n return _bbApiInitPromise\n}\n\n// Destroy the cached Barretenberg API and free its resources.\nexport const destroyBBApi = (): void => {\n _bbApiInitPromise = null\n if (_bbApi) {\n _bbApi.destroy()\n _bbApi = null\n }\n}\n\n/**\n * Encrypt a ballot and build every circuit input that does not depend on the signature.\n * Runs in a worker when available to avoid blocking the main thread.\n */\nexport const prepareCircuitInputs = async (inputs: PrepareBallotInputs): Promise<PreparedBallot> => {\n const preset = requireCircuits().preset\n\n if (typeof Worker !== 'undefined') {\n try {\n const worker = new Worker(new URL('./workers/generateCircuitInputs.worker.js', import.meta.url), { type: 'module' })\n return new Promise((resolve, reject) => {\n worker.onmessage = (e: MessageEvent<{ type: 'result'; prepared: PreparedBallot } | { type: 'error'; error: string }>) => {\n worker.terminate()\n if (e.data.type === 'result') {\n resolve(e.data.prepared)\n } else {\n reject(new Error(e.data.error))\n }\n }\n worker.onerror = (err) => {\n worker.terminate()\n reject(err)\n }\n worker.postMessage({ inputs, preset })\n })\n } catch {\n // Worker creation failed (e.g. bundler path resolution); fall back to main thread\n }\n }\n\n return prepareCircuitInputsImpl(inputs)\n}\n\n/**\n * Execute a circuit.\n * @param circuit - The circuit to execute.\n * @param inputs - The inputs to the circuit.\n * @returns The execute circuit result.\n */\nexport const executeCircuit = async (circuit: CompiledCircuit, inputs: any): Promise<{ witness: Uint8Array; returnValue: any }> => {\n const noir = new Noir(circuit as CompiledCircuit)\n\n return noir.execute(inputs)\n}\n\n/**\n * Generate a proof for the CRISP circuit given the circuit inputs.\n * @param circuitInputs - Inputs used in both the CRISP and GRECO circuits.\n * @returns The proof.\n */\nexport const generateProof = async (circuitInputs: any, censusMode: CensusVariant = 'merkle') => {\n const api = await getBBApi()\n\n const circuits = requireCircuits()\n const ballotCircuit = censusMode === 'onchain' ? circuits.crispOnchain : circuits.crisp\n const foldCircuitForMode = censusMode === 'onchain' ? foldOnchainCircuit : foldCircuit\n\n const { witness: userDataEncryptionCt0Witness } = await executeCircuit(circuits.userDataEncryptionCt0 as CompiledCircuit, {\n pk0is: circuitInputs.pk0is,\n ct0is: circuitInputs.ct0is,\n u: circuitInputs.u,\n e0: circuitInputs.e0,\n e0is: circuitInputs.e0is,\n e0_quotients: circuitInputs.e0_quotients,\n k1: circuitInputs.k1,\n r1is: circuitInputs.r1is,\n r2is: circuitInputs.r2is,\n })\n const { witness: userDataEncryptionCt1Witness } = await executeCircuit(circuits.userDataEncryptionCt1 as CompiledCircuit, {\n pk1is: circuitInputs.pk1is,\n ct1is: circuitInputs.ct1is,\n u: circuitInputs.u,\n e1: circuitInputs.e1,\n p1is: circuitInputs.p1is,\n p2is: circuitInputs.p2is,\n })\n // The two stacks share every input except how eligibility reaches the circuit: a census round\n // proves a Merkle path, an on-chain round takes the voting power the contract read.\n const eligibilityInputs =\n censusMode === 'onchain'\n ? { voting_power: circuitInputs.voting_power }\n : {\n merkle_root: circuitInputs.merkle_root,\n balance: circuitInputs.balance,\n merkle_proof_length: circuitInputs.merkle_proof_length,\n merkle_proof_indices: circuitInputs.merkle_proof_indices,\n merkle_proof_siblings: circuitInputs.merkle_proof_siblings,\n }\n\n const { witness: crispWitness, returnValue: crispReturnValue } = await executeCircuit(ballotCircuit as CompiledCircuit, {\n prev_ct0is: circuitInputs.prev_ct0is,\n prev_ct1is: circuitInputs.prev_ct1is,\n prev_ct_commitment: circuitInputs.prev_ct_commitment,\n sum_ct0is: circuitInputs.sum_ct0is,\n sum_ct1is: circuitInputs.sum_ct1is,\n sum_r0is: circuitInputs.sum_r0is,\n sum_r1is: circuitInputs.sum_r1is,\n ct0is: circuitInputs.ct0is,\n ct1is: circuitInputs.ct1is,\n k1: circuitInputs.k1,\n public_key_x: circuitInputs.public_key_x,\n public_key_y: circuitInputs.public_key_y,\n signature: circuitInputs.signature,\n digest_hi: circuitInputs.digest_hi,\n digest_lo: circuitInputs.digest_lo,\n slot_address: circuitInputs.slot_address,\n ...eligibilityInputs,\n is_first_vote: circuitInputs.is_first_vote,\n is_mask_vote: circuitInputs.is_mask_vote,\n num_options: circuitInputs.num_options,\n })\n\n const userDataEncryptionCt0Backend = new UltraHonkBackend((circuits.userDataEncryptionCt0 as CompiledCircuit).bytecode, api)\n const userDataEncryptionCt1Backend = new UltraHonkBackend((circuits.userDataEncryptionCt1 as CompiledCircuit).bytecode, api)\n const userDataEncryptionBackend = new UltraHonkBackend((userDataEncryptionCircuit as CompiledCircuit).bytecode, api)\n const crispBackend = new UltraHonkBackend((ballotCircuit as CompiledCircuit).bytecode, api)\n const foldBackend = new UltraHonkBackend((foldCircuitForMode as CompiledCircuit).bytecode, api)\n\n const { proof: userDataEncryptionCt0Proof, publicInputs: userDataEncryptionCt0PublicInputs } =\n await userDataEncryptionCt0Backend.generateProof(userDataEncryptionCt0Witness, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n const { proof: userDataEncryptionCt1Proof, publicInputs: userDataEncryptionCt1PublicInputs } =\n await userDataEncryptionCt1Backend.generateProof(userDataEncryptionCt1Witness, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n const { proof: crispProof, publicInputs: crispPublicInputs } = await crispBackend.generateProof(crispWitness, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n\n const userDataEncryptionCt0Artifacts = await userDataEncryptionCt0Backend.generateRecursiveProofArtifacts(\n userDataEncryptionCt0Proof,\n userDataEncryptionCt0PublicInputs.length,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n const userDataEncryptionCt1Artifacts = await userDataEncryptionCt1Backend.generateRecursiveProofArtifacts(\n userDataEncryptionCt1Proof,\n userDataEncryptionCt1PublicInputs.length,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n const crispArtifacts = await crispBackend.generateRecursiveProofArtifacts(crispProof, crispPublicInputs.length, {\n verifierTarget: 'noir-recursive-no-zk',\n })\n\n const { witness: userDataEncryptionWitness } = await executeCircuit(userDataEncryptionCircuit as CompiledCircuit, {\n ct0_verification_key: userDataEncryptionCt0Artifacts.vkAsFields,\n ct0_proof: proofToFields(userDataEncryptionCt0Proof),\n ct0_public_inputs: userDataEncryptionCt0PublicInputs,\n ct0_key_hash: userDataEncryptionCt0Artifacts.vkHash,\n ct1_verification_key: userDataEncryptionCt1Artifacts.vkAsFields,\n ct1_proof: proofToFields(userDataEncryptionCt1Proof),\n ct1_public_inputs: userDataEncryptionCt1PublicInputs,\n ct1_key_hash: userDataEncryptionCt1Artifacts.vkHash,\n })\n\n const { proof: userDataEncryptionProof, publicInputs: userDataEncryptionPublicInputs } = await userDataEncryptionBackend.generateProof(\n userDataEncryptionWitness,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n const userDataEncryptionArtifacts = await userDataEncryptionBackend.generateRecursiveProofArtifacts(\n userDataEncryptionProof,\n userDataEncryptionPublicInputs.length,\n {\n verifierTarget: 'noir-recursive-no-zk',\n },\n )\n\n const { witness: foldWitness } = await executeCircuit(foldCircuitForMode as CompiledCircuit, {\n user_data_encryption_verification_key: userDataEncryptionArtifacts.vkAsFields,\n user_data_encryption_proof: proofToFields(userDataEncryptionProof),\n user_data_encryption_public_inputs: userDataEncryptionPublicInputs,\n user_data_encryption_key_hash: userDataEncryptionArtifacts.vkHash,\n crisp_verification_key: crispArtifacts.vkAsFields,\n crisp_proof: proofToFields(crispProof),\n crisp_key_hash: crispArtifacts.vkHash,\n prev_ct_commitment: circuitInputs.prev_ct_commitment,\n digest_hi: circuitInputs.digest_hi,\n digest_lo: circuitInputs.digest_lo,\n slot_address: circuitInputs.slot_address,\n // Position 4 of the public inputs, and the only slot the two stacks disagree on.\n ...(censusMode === 'onchain' ? { voting_power: circuitInputs.voting_power } : { merkle_root: circuitInputs.merkle_root }),\n is_first_vote: circuitInputs.is_first_vote,\n num_options: circuitInputs.num_options,\n final_ct_commitment: crispReturnValue[0].toString(),\n ct_commitment: crispReturnValue[1].toString(),\n k1_commitment: crispReturnValue[2].toString(),\n })\n\n const proof = await foldBackend.generateProof(foldWitness, { verifierTarget: 'evm' })\n\n return proof\n}\n\n/**\n * Validate a vote.\n * @param vote - The vote to validate.\n * @param balance - The balance of the voter.\n */\nexport const validateVote = (vote: Vote, balance: bigint): void => {\n const numChoices = vote.length\n const maxValue = getMaxVoteValue(numChoices)\n\n for (let i = 0; i < vote.length; i++) {\n if (vote[i] < 0) {\n throw new Error(`Invalid vote: choice ${i} is negative`)\n }\n if (vote[i] > maxValue) {\n throw new Error(`Invalid vote: choice ${i} exceeds maximum encodable value`)\n }\n }\n\n if (numChoices === 2) {\n // Binary: mutually exclusive\n const nonZeroCount = vote.filter((v) => v > 0).length\n if (nonZeroCount > 1) {\n throw new Error('Invalid vote: for 2 options, only one choice can be non-zero')\n }\n const votedAmount = vote.find((v) => v > 0) ?? 0\n if (votedAmount > balance) {\n throw new Error('Invalid vote: vote exceeds balance')\n }\n } else {\n // 3+ options: split allowed, total capped\n const total = vote.reduce((sum, v) => sum + v, 0)\n if (total > balance) {\n throw new Error(`Invalid vote: total votes (${total}) exceed balance (${balance})`)\n }\n }\n}\n\n/**\n * Phase one: encrypt a ballot, before the voter signs anything.\n *\n * A ballot must be encrypted before it can be signed, because the digest binds the ciphertext.\n * Take `ctCommitment` from the result, read the digest from `CRISPProgram.ballotDigest`, have the\n * voter sign it, then call {@link finishBallotProof}.\n *\n * @param inputs - The ballot to encrypt.\n * @returns The prepared ballot.\n */\nexport const prepareBallot = async (inputs: PrepareBallotInputs): Promise<PreparedBallot> => {\n if (!inputs.isMaskVote) {\n validateVote(inputs.vote, inputs.censusMode === 'onchain' ? inputs.votingPower : inputs.balance)\n }\n\n // Through the worker wrapper, not the impl: BFV encryption is the heaviest step in the flow and\n // running it on the main thread freezes the browser for its duration. The wrapper falls back to\n // the main thread by itself where `Worker` is unavailable.\n return prepareCircuitInputs(inputs)\n}\n\n/**\n * Phase two: prove a prepared ballot, given the signature over its digest.\n *\n * Get the digest from `CRISPProgram.ballotDigest(e3Id, slot, prepared.ctCommitment)` and have the\n * voter sign it. Reading it from the contract rather than rebuilding the EIP-712 struct here means\n * there is only one implementation of the domain to keep correct.\n *\n * @param prepared The output of `prepareBallot`.\n * @param digest The ballot digest.\n * @param signature The voter signature over that digest.\n * @returns The proof.\n */\nexport const finishBallotProof = async (prepared: PreparedBallot, digest: `0x${string}`, signature: `0x${string}`): Promise<ProofData> => {\n const circuitInputs = await attachSignatureImpl(prepared, digest, signature)\n\n return {\n ...(await generateProof(circuitInputs, prepared.censusMode)),\n encryptedVote: prepared.encryptedVote,\n parentIndexPlusOne: prepared.parentIndexPlusOne,\n }\n}\n\n/**\n * Phase two for a mask.\n *\n * A mask carries the same digest as a real vote, because `CRISPProgram.publishInput` computes it\n * for every input regardless of branch. Only the signature is a placeholder, and the circuit does\n * not check it on the mask branch. Passing a real digest here is what keeps a mask and a vote\n * indistinguishable in the published public inputs.\n *\n * @param prepared The output of `prepareBallot` with `isMaskVote: true`.\n * @param digest The ballot digest, from the same contract call a real vote would use.\n * @returns The proof.\n */\nexport const finishMaskProof = async (prepared: PreparedBallot, digest: `0x${string}`): Promise<ProofData> => {\n return finishBallotProof(prepared, digest, MASK_SIGNATURE)\n}\n\n/**\n * Locally verify a Noir proof.\n * @param proof - The proof to verify.\n * @returns True if the proof is valid, false otherwise.\n */\nexport const verifyProof = async (proof: ProofData, censusMode: CensusVariant = 'merkle'): Promise<boolean> => {\n const api = await getBBApi()\n const circuit = censusMode === 'onchain' ? foldOnchainCircuit : foldCircuit\n const foldBackend = new UltraHonkBackend(circuit.bytecode, api)\n\n return foldBackend.verifyProof(proof, { verifierTarget: 'evm' })\n}\n\n/**\n * Encode the proof data into a format that can be used by the CRISP program in Solidity\n * to validate the proof.\n * @param proof The proof data.\n * @returns The encoded proof data as a hex string.\n */\nexport const encodeSolidityProof = ({ publicInputs, proof, encryptedVote, parentIndexPlusOne }: ProofData): Hex => {\n // Indices follow the fold circuit public inputs:\n // 0 prev_ct_commitment, 1 digest_hi, 2 digest_lo, 3 slot_address,\n // 4 merkle_root | voting_power, 5 is_first_vote, 6 num_options,\n // 7 final_ct_commitment, 8 committee public key\n const slotAddress = getAddress(numberToHex(BigInt(publicInputs[3]), { size: 20 }))\n const encryptedVoteCommitment = publicInputs[7] as `0x${string}`\n\n return encodeAbiParameters(parseAbiParameters('bytes, address, bytes32, bytes, uint40'), [\n bytesToHex(proof),\n slotAddress,\n encryptedVoteCommitment,\n bytesToHex(encryptedVote),\n parentIndexPlusOne,\n ])\n}\n","{\"noir_version\":\"1.0.0-beta.26+40d6574f851d926f93e0c3a271bac3e6e82ac905\",\"hash\":\"12034458935140291205\",\"abi\":{\"parameters\":[{\"name\":\"user_data_encryption_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":5,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"crisp_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"prev_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_hi\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_lo\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"slot_address\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"merkle_root\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"is_first_vote\",\"type\":{\"kind\":\"boolean\"},\"visibility\":\"public\"},{\"name\":\"num_options\",\"type\":{\"kind\":\"integer\",\"sign\":\"unsigned\",\"width\":32},\"visibility\":\"public\"},{\"name\":\"final_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"k1_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"}],\"return_type\":{\"abi_type\":{\"kind\":\"field\"},\"visibility\":\"public\"},\"error_types\":{}},\"bytecode\":\"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\",\"debug_symbols\":\"tZbdjqMwDIXfJddcxM6P43mV1aqiLR0hIVoxMNKqmnff0CEBKiWaTbVXbgn55HPsmNzFuTlO74e2v1w/xNuvuzgObde174fueqrH9tr7p/evSoS/h3FoGv9IbNb9rls9NP0o3vqp6yrxWXfT46WPW90/4lgPflVWounPPnrgpe2a+ddXte6W6a1gNS27wWkdAQZ3BMgRDAYCsVoJakfANEEpcgtBaQuRgPhTFQgYVCBoSqnI+eBMcBGRbIpgXvbB/lcfNEQftNEFPqBitRJMCcGwDQSrVBGBcCUUqSAVq0mWigirD07JEgLLqILRJU+WzrQUMAUvASWsQhztIZm+JKKghJxWSUSmMUlykEIg16ZwvEdQGmFB8oKw2xPK9GOEcbEkhjdZPCM4jWCwwU8G5hQCM2VVHA+plrBmAfQPXsQsLEpd4sUOAWkvckUFFftiW5GnomKmP8nq2BfWJIWgeb0i9uWKZIU4s54RxlQW2dNuIMxuKW3BvFASVSSQLZo48RvmCUVTj5WOBKeLVHD0AZ6m3m//rz61w+4OJNC/WQnlna+E9pZXwsyTrxJ2/phXgr6Dm2dyJfg7gJyT9RGWiEtUcwo+6iWaJXqYmuv6WQ9tfeya5fp1mfrT5jY2/rmFlXBfuw3XU3OehmbO+rHmdfwF\",\"file_map\":{\"17\":{\"source\":\"// Exposed only for usage in `std::meta`\\npub(crate) mod poseidon2;\\n\\nuse crate::default::Default;\\nuse crate::embedded_curve_ops::{\\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\\n};\\nuse crate::meta::derive_via;\\nuse crate::static_assert;\\n\\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\\n\\n#[foreign(sha256_compression)]\\n// docs:start:sha256_compression\\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\\n// docs:end:sha256_compression\\n\\n#[foreign(keccakf1600)]\\n// docs:start:keccakf1600\\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\\n// docs:end:keccakf1600\\n\\n#[foreign(blake2s)]\\n// docs:start:blake2s\\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake2s\\n{}\\n\\n// docs:start:blake3\\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake3\\n{\\n if crate::runtime::is_unconstrained() {\\n // Temporary measure while Barretenberg is main proving system.\\n // Please open an issue if you're working on another proving system and running into problems due to this.\\n crate::static_assert(\\n N <= 1024,\\n \\\"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\\\",\\n );\\n }\\n __blake3(input)\\n}\\n\\n#[foreign(blake3)]\\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\\n\\n// docs:start:pedersen_commitment\\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\\n // docs:end:pedersen_commitment\\n pedersen_commitment_with_separator(input, 0)\\n}\\n\\n#[inline_always]\\npub fn pedersen_commitment_with_separator<let N: u32>(\\n input: [Field; N],\\n separator: u32,\\n) -> EmbeddedCurvePoint {\\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\\n for i in 0..N {\\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\\n }\\n let generators = derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n multi_scalar_mul(generators, points)\\n}\\n\\n// docs:start:pedersen_hash\\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\\n// docs:end:pedersen_hash\\n{\\n pedersen_hash_with_separator(input, 0)\\n}\\n\\n#[no_predicates]\\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\\n let mut generators: [EmbeddedCurvePoint; N + 1] =\\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\\n crate::assert_constant(separator);\\n let domain_generators: [EmbeddedCurvePoint; N] =\\n derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n\\n for i in 0..N {\\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\\n generators[i] = domain_generators[i];\\n }\\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\\n\\n let length_generator: [EmbeddedCurvePoint; 1] =\\n derive_generators(\\\"pedersen_hash_length\\\".as_bytes(), 0);\\n generators[N] = length_generator[0];\\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\\n}\\n\\n#[field(bn254)]\\n#[inline_always]\\npub fn derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {\\n crate::assert_constant(domain_separator_bytes);\\n crate::assert_constant(starting_index);\\n __derive_generators(domain_separator_bytes, starting_index)\\n}\\n\\n#[builtin(derive_pedersen_generators)]\\n#[field(bn254)]\\nfn __derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {}\\n\\npub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {\\n static_assert(\\n N == POSEIDON2_CONFIG_STATE_SIZE,\\n f\\\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\\\",\\n );\\n poseidon2_permutation_internal(input)\\n}\\n\\n#[foreign(poseidon2_permutation)]\\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\\n\\n#[foreign(poseidon2_config_state_size)]\\ncomptime fn poseidon2_config_state_size() -> u32 {}\\n\\n// Generic hashing support.\\n// Partially ported and impacted by rust.\\n\\n// Hash trait shall be implemented per type.\\n#[derive_via(derive_hash)]\\npub trait Hash {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher;\\n}\\n\\n// docs:start:derive_hash\\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\\n let name = quote { $crate::hash::Hash };\\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\\n let for_each_field = |name| quote { _self.$name.hash(_state); };\\n crate::meta::make_trait_impl(\\n s,\\n name,\\n signature,\\n for_each_field,\\n quote {},\\n |fields| fields,\\n )\\n}\\n// docs:end:derive_hash\\n\\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\\n// TODO: consider making the types generic here ([u8], [Field], etc.)\\npub trait Hasher {\\n fn finish(self) -> Field;\\n\\n /// Returns the hash value without consuming the hasher.\\n /// Override this for more efficient implementations that avoid copying.\\n /// TODO: deprecate finish() and replace it\\n fn finish_ref(&self) -> Field {\\n (*self).finish()\\n }\\n\\n fn write(&mut self, input: Field);\\n}\\n\\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\\npub trait BuildHasher {\\n type H: Hasher;\\n\\n fn build_hasher(self) -> H;\\n}\\n\\npub struct BuildHasherDefault<H>;\\n\\nimpl<H> BuildHasher for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n type H = H;\\n\\n fn build_hasher(_self: Self) -> H {\\n H::default()\\n }\\n}\\n\\nimpl<H> Default for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n fn default() -> Self {\\n BuildHasherDefault {}\\n }\\n}\\n\\nimpl Hash for Field {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self);\\n }\\n}\\n\\nimpl Hash for u8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u128 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for i8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u8 as Field);\\n }\\n}\\n\\nimpl Hash for i16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u16 as Field);\\n }\\n}\\n\\nimpl Hash for i32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u32 as Field);\\n }\\n}\\n\\nimpl Hash for i64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u64 as Field);\\n }\\n}\\n\\nimpl Hash for bool {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for () {\\n fn hash<H>(_self: Self, _state: &mut H)\\n where\\n H: Hasher,\\n {}\\n}\\n\\nimpl<T, let N: u32> Hash for [T; N]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<T> Hash for [T]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.len().hash(state);\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<A> Hash for (A,)\\nwhere\\n A: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n }\\n}\\n\\nimpl<A, B> Hash for (A, B)\\nwhere\\n A: Hash,\\n B: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n }\\n}\\n\\nimpl<A, B, C> Hash for (A, B, C)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D> Hash for (A, B, C, D)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F> Hash for (A, B, C, D, E, F)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G> Hash for (A, B, C, D, E, F, G)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_> Hash for (A, B, C, D, E, F, G, H_)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I> Hash for (A, B, C, D, E, F, G, H_, I)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J> Hash for (A, B, C, D, E, F, G, H_, I, J)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K> Hash for (A, B, C, D, E, F, G, H_, I, J, K)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K, L> Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n L: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n self.11.hash(state);\\n }\\n}\\n\\n// Some test vectors for Pedersen hash and Pedersen Commitment.\\n// They have been generated using the same functions so the tests are for now useless\\n// but they will be useful when we switch to Noir implementation.\\n#[test]\\nfn assert_pedersen() {\\n assert_eq(\\n pedersen_hash_with_separator([1], 1),\\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1], 1),\\n EmbeddedCurvePoint {\\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\\n },\\n );\\n\\n assert_eq(\\n pedersen_hash_with_separator([1, 2], 2),\\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2], 2),\\n EmbeddedCurvePoint {\\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3], 3),\\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3], 3),\\n EmbeddedCurvePoint {\\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\\n EmbeddedCurvePoint {\\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\\n EmbeddedCurvePoint {\\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\\n EmbeddedCurvePoint {\\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n EmbeddedCurvePoint {\\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n EmbeddedCurvePoint {\\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n EmbeddedCurvePoint {\\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n EmbeddedCurvePoint {\\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\\n },\\n );\\n}\\n\",\"path\":\"std/hash/mod.nr\",\"function_locations\":[{\"start\":572,\"name\":\"sha256_compression\"},{\"start\":707,\"name\":\"keccakf1600\"},{\"start\":852,\"name\":\"blake2s\"},{\"start\":950,\"name\":\"blake3\"},{\"start\":1437,\"name\":\"__blake3\"},{\"start\":1555,\"name\":\"pedersen_commitment\"},{\"start\":1784,\"name\":\"pedersen_commitment_with_separator\"},{\"start\":2188,\"name\":\"pedersen_hash\"},{\"start\":2345,\"name\":\"pedersen_hash_with_separator\"},{\"start\":3339,\"name\":\"derive_generators\"},{\"start\":3698,\"name\":\"__derive_generators\"},{\"start\":3776,\"name\":\"poseidon2_permutation\"},{\"start\":4132,\"name\":\"poseidon2_permutation_internal\"},{\"start\":4225,\"name\":\"poseidon2_config_state_size\"},{\"start\":4536,\"name\":\"derive_hash\"},{\"start\":5327,\"name\":\"Hasher::finish_ref\"},{\"start\":5761,\"name\":\"<impl BuildHasher for BuildHasherDefault<H>>::build_hasher\"},{\"start\":5893,\"name\":\"<impl Default for BuildHasherDefault<H>>::default\"},{\"start\":6025,\"name\":\"<impl Hash for Field>::hash\"},{\"start\":6155,\"name\":\"<impl Hash for u8>::hash\"},{\"start\":6295,\"name\":\"<impl Hash for u16>::hash\"},{\"start\":6435,\"name\":\"<impl Hash for u32>::hash\"},{\"start\":6575,\"name\":\"<impl Hash for u64>::hash\"},{\"start\":6716,\"name\":\"<impl Hash for u128>::hash\"},{\"start\":6855,\"name\":\"<impl Hash for i8>::hash\"},{\"start\":7001,\"name\":\"<impl Hash for i16>::hash\"},{\"start\":7148,\"name\":\"<impl Hash for i32>::hash\"},{\"start\":7295,\"name\":\"<impl Hash for i64>::hash\"},{\"start\":7443,\"name\":\"<impl Hash for bool>::hash\"},{\"start\":7590,\"name\":\"<impl Hash for ()>::hash\"},{\"start\":7722,\"name\":\"<impl Hash for [T; N]>::hash\"},{\"start\":7911,\"name\":\"<impl Hash for [T]>::hash\"},{\"start\":8133,\"name\":\"<impl Hash for (A,)>::hash\"},{\"start\":8302,\"name\":\"<impl Hash for (A, B)>::hash\"},{\"start\":8518,\"name\":\"<impl Hash for (A, B, C)>::hash\"},{\"start\":8781,\"name\":\"<impl Hash for (A, B, C, D)>::hash\"},{\"start\":9091,\"name\":\"<impl Hash for (A, B, C, D, E)>::hash\"},{\"start\":9448,\"name\":\"<impl Hash for (A, B, C, D, E, F)>::hash\"},{\"start\":9852,\"name\":\"<impl Hash for (A, B, C, D, E, F, G)>::hash\"},{\"start\":10306,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_)>::hash\"},{\"start\":10807,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I)>::hash\"},{\"start\":11355,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J)>::hash\"},{\"start\":11950,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K)>::hash\"},{\"start\":12593,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)>::hash\"},{\"start\":13187,\"name\":\"assert_pedersen\"}]},\"22\":{\"source\":\"pub mod hash;\\npub mod aes128;\\npub mod array;\\npub mod vector;\\npub mod ecdsa_secp256k1;\\npub mod ecdsa_secp256r1;\\npub mod embedded_curve_ops;\\npub mod field;\\npub mod collections;\\npub mod compat;\\npub mod convert;\\npub mod option;\\npub mod string;\\npub mod test;\\npub mod cmp;\\npub mod ops;\\npub mod default;\\npub mod prelude;\\npub mod runtime;\\npub mod meta;\\npub mod append;\\npub mod mem;\\npub mod panic;\\npub mod hint;\\n\\nmod integer;\\nmod primitive_docs;\\nmod internal;\\n\\n// Oracle calls are required to be wrapped in an unconstrained function\\n// Thus, the only argument to the `println` oracle is expected to always be an ident\\n#[oracle(print)]\\nunconstrained fn print_oracle<T>(with_newline: bool, input: T) {}\\n\\nunconstrained fn print_unconstrained<T>(with_newline: bool, input: T) {\\n print_oracle(with_newline, input);\\n}\\n\\n/// Print the given input to stdout followed by a newline\\npub fn println<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(true, input);\\n }\\n}\\n\\n/// Print the given input to stdout\\npub fn print<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(false, input);\\n }\\n}\\n\\n/// Asserts the validity of the provided proof and public inputs against the provided verification key and hash.\\n///\\n/// The ACVM cannot determine whether the provided proof is valid during execution as this requires knowledge of\\n/// the backend against which the program is being proven. However if an invalid proof if submitted, the program may\\n/// fail to prove or the backend may generate a proof which will subsequently fail to verify.\\n///\\n/// # Important Note\\n///\\n/// If you are not developing your own backend such as [Barretenberg](https://github.com/AztecProtocol/barretenberg)\\n/// you probably shouldn't need to interact with this function directly. It's easier and safer to use a verification\\n/// library which is published by the developers of the backend which will document or enforce any safety requirements.\\n///\\n/// If you use this directly, you're liable to introduce underconstrainedness bugs and *your circuit will be insecure*.\\n///\\n/// # Arguments\\n/// - verification_key: The verification key of the circuit to be verified.\\n/// - proof: The proof to be verified.\\n/// - public_inputs: The public inputs associated with `proof`\\n/// - key_hash: The hash of `verification_key` of the form expected by the backend.\\n/// - proof_type: An identifier for the proving scheme used to generate the proof to be verified. This allows\\n/// for a single backend to support verifying multiple proving schemes.\\n///\\n/// # Constraining `key_hash`\\n///\\n/// The Noir compiler does not by itself constrain that `key_hash` is a valid hash of `verification_key`.\\n/// This is because different backends may differ in how they hash their verification keys.\\n/// It is then the responsibility of either the noir developer (by explicitly hashing the verification key\\n/// in the correct manner) or by the proving system itself internally asserting the correctness of `key_hash`.\\npub fn verify_proof_with_type<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {\\n if !crate::runtime::is_unconstrained() {\\n crate::assert_constant(proof_type);\\n }\\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\\n}\\n\\n#[foreign(recursive_aggregation)]\\nfn verify_proof_internal<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {}\\n\\n/// Asserts that the given value is known at compile-time.\\n/// Useful for debugging for-loop bounds.\\n#[builtin(assert_constant)]\\npub fn assert_constant<T>(x: T) {}\\n\\n/// Asserts that the given value is both true and known at compile-time.\\n/// The message can be a string, a format string, or any value, as long as it is known at compile-time\\n#[builtin(static_assert)]\\npub fn static_assert<T>(predicate: bool, message: T) {}\\n\\n/// Force a field value to be a witness instead of a constant in the compiled output.\\n/// This is often only useful for debugging compiler optimizations.\\n///\\n/// This has no effect in unconstrained or comptime code.\\n#[builtin(as_witness)]\\npub fn as_witness(x: Field) {}\\n\",\"path\":\"std/lib.nr\",\"function_locations\":[{\"start\":689,\"name\":\"print_oracle\"},{\"start\":763,\"name\":\"print_unconstrained\"},{\"start\":893,\"name\":\"println\"},{\"start\":1076,\"name\":\"print\"},{\"start\":3277,\"name\":\"verify_proof_with_type\"},{\"start\":3694,\"name\":\"verify_proof_internal\"},{\"start\":3859,\"name\":\"assert_constant\"},{\"start\":4118,\"name\":\"static_assert\"},{\"start\":4389,\"name\":\"as_witness\"}]},\"52\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse bb_proof_verification::{UltraHonkProof, UltraHonkVerificationKey, verify_honk_proof_non_zk};\\nuse interfold_lib::math::commitments::compute_vk_hash;\\n\\n/// Binds the four inner `vk_hash` witnesses. Regenerate with `pnpm compute:vk-hash` in\\n/// `examples/CRISP` after changing ct0 / ct1 / user_data_encryption / crisp (or the lib preset).\\n/// Insecure: `lib::configs::default` uses `insecure::*`; secure: uses `secure::*`.\\npub global CRISP_FOLD_EXPECTED_KEY_HASH_INSECURE: Field =\\n 0x0cfedc11fbb1437ca55ba6ae31fe3adb29eefba7a62ea8257d427ce1e1e32e6f;\\npub global CRISP_FOLD_EXPECTED_KEY_HASH_SECURE: Field =\\n 0x133970fec6679c0be03d6bf71981d9bdb9135f919b1c8c3fcc24aee68acb12ad;\\n\\nfn main(\\n // User Data Encryption Section.\\n user_data_encryption_verification_key: UltraHonkVerificationKey,\\n user_data_encryption_proof: UltraHonkProof,\\n user_data_encryption_public_inputs: [Field; 5], // ct0_key_hash, ct1_key_hash, pk_commitment, ct_commitment, k1_commitment\\n user_data_encryption_key_hash: Field,\\n // Crisp Section.\\n crisp_verification_key: UltraHonkVerificationKey,\\n crisp_proof: UltraHonkProof,\\n crisp_key_hash: Field,\\n prev_ct_commitment: pub Field,\\n digest_hi: pub Field,\\n digest_lo: pub Field,\\n slot_address: pub Field,\\n merkle_root: pub Field,\\n is_first_vote: pub bool,\\n num_options: pub u32,\\n final_ct_commitment: pub Field,\\n ct_commitment: Field,\\n k1_commitment: Field,\\n) -> pub Field {\\n verify_honk_proof_non_zk(\\n user_data_encryption_verification_key,\\n user_data_encryption_proof,\\n user_data_encryption_public_inputs,\\n user_data_encryption_key_hash,\\n );\\n verify_honk_proof_non_zk(\\n crisp_verification_key,\\n crisp_proof,\\n [\\n prev_ct_commitment,\\n digest_hi,\\n digest_lo,\\n slot_address,\\n merkle_root,\\n if is_first_vote { 1 } else { 0 },\\n num_options as Field,\\n final_ct_commitment,\\n ct_commitment,\\n k1_commitment,\\n ],\\n crisp_key_hash,\\n );\\n\\n // Verify that the ct_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(ct_commitment == user_data_encryption_public_inputs[3]);\\n\\n // Verify that the k1_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(k1_commitment == user_data_encryption_public_inputs[4]);\\n\\n let vk_hashes = [\\n user_data_encryption_key_hash,\\n crisp_key_hash,\\n user_data_encryption_public_inputs[0], // ct0_key_hash\\n user_data_encryption_public_inputs[1], // ct1_key_hash\\n ]\\n .as_vector();\\n\\n let chain_key_hash = compute_vk_hash(vk_hashes);\\n assert(\\n (chain_key_hash == CRISP_FOLD_EXPECTED_KEY_HASH_INSECURE)\\n | (chain_key_hash == CRISP_FOLD_EXPECTED_KEY_HASH_SECURE),\\n );\\n\\n user_data_encryption_public_inputs[2]\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/examples/CRISP/circuits/bin/fold/src/main.nr\",\"function_locations\":[{\"start\":1641,\"name\":\"main\"}]},\"53\":{\"source\":\"// Constants for UltraHonk recursive verifier inputs\\npub global PROOF_TYPE_HONK: u32 = 0; // identifier for UltraHonk verfier\\npub global RECURSIVE_PROOF_LENGTH: u32 = 410;\\npub global ULTRA_VK_LENGTH_IN_FIELDS: u32 = 115;\\n\\npub type UltraHonkProof = [Field; RECURSIVE_PROOF_LENGTH];\\npub type UltraHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\n// Constants for Rollup-UltraHonk recursive verifier inputs (N.B. this is equivalent to UH plus IPA claim and proof)\\npub global PROOF_TYPE_ROLLUP_HONK: u32 = 4; // identifier for rollup-UltraHonk verfier\\npub global PROOF_TYPE_ROOT_ROLLUP_HONK: u32 = 5; // identifier for root-rollup-UltraHonk verfier (closes the IPA accumulator)\\npub global IPA_CLAIM_SIZE: u32 = 6;\\npub global IPA_PROOF_LENGTH: u32 = 64;\\npub global RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 =\\n RECURSIVE_PROOF_LENGTH + IPA_CLAIM_SIZE + IPA_PROOF_LENGTH;\\n\\npub type RollupHonkProof = [Field; RECURSIVE_ROLLUP_HONK_PROOF_LENGTH];\\npub type RollupHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\npub global PROOF_TYPE_HONK_ZK: u32 = 6; // identifier for UltraHonk ZK verfier\\npub global RECURSIVE_ZK_PROOF_LENGTH: u32 = 450 + 8;\\n\\npub type UltraHonkZKProof = [Field; RECURSIVE_ZK_PROOF_LENGTH];\\n\\n// Verifies a non-zero-knowledge UltraHonk proof.\\n//\\n// Represents standard UltraHonk recursive verification for proofs that do not hide the witness.\\n// Use this only in situations where zero-knowledge is not required.\\npub fn verify_honk_proof_non_zk<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof with IPA (Inner Product Argument).\\n//\\n// This variant includes an IPA claim and proof appended to the standard UltraHonk proof,\\n// used to amortize IPA recursive verification costs in rollup circuits.\\npub fn verify_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof and closes the IPA accumulator in-circuit.\\n//\\n// Use this at the root of a rollup aggregation tree. The inner proof has the same RollupHonk shape\\n// as `verify_rolluphonk_proof`, but instead of propagating an accumulated IPA claim out as a public\\n// input, this variant performs a full native IPA verification inside the circuit. The outer circuit\\n// should therefore be proved as a standard (non-rollup) UltraHonk circuit, producing a proof\\n// suitable for verification by `verify_honk_proof` / `verify_honk_proof_non_zk`.\\n//\\n// When two RollupHonk inputs are verified this way in one circuit, their two IPA claims are first\\n// accumulated into one, then the accumulated claim is fully verified.\\npub fn verify_root_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROOT_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a zero-knowledge UltraHonk proof.\\n//\\n// This verifier is for UltraHonk proofs constructed with zero-knowledge, which hide the witness\\n// values from the verifier.\\n// Note: We intentionally choose the generic name \\\"verify_honk_proof\\\" for this function, as we\\n// want ZK to be the default unless the user explicitly opts out.\\npub fn verify_honk_proof<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkZKProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK_ZK,\\n );\\n}\\n\",\"path\":\"/home/ace/nargo/github.com/AztecProtocol/aztec-packages/v5.1.0/barretenberg/noir/bb_proof_verification/src/lib.nr\",\"function_locations\":[{\"start\":1646,\"name\":\"verify_honk_proof_non_zk\"},{\"start\":2262,\"name\":\"verify_rolluphonk_proof\"},{\"start\":3386,\"name\":\"verify_root_rolluphonk_proof\"},{\"start\":4087,\"name\":\"verify_honk_proof\"}]},\"87\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse crate::math::helpers::{compute_safe, flatten};\\nuse crate::math::polynomial::Polynomial;\\n\\n/// DOMAIN SEPARATORS\\n\\n// Domain separator - \\\"PK\\\"\\npub global DS_PK: [u8; 64] = [\\n 0x50, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_GENERATION\\\"\\npub global DS_PK_GENERATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_COMPUTATION\\\"\\npub global DS_SHARE_COMPUTATION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_ENCRYPTION\\\"\\npub global DS_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_AGGREGATION\\\"\\npub global DS_PK_AGGREGATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CIPHERTEXT\\\"\\npub global DS_CIPHERTEXT: [u8; 64] = [\\n 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"AGGREGATED_SHARES\\\"\\npub global DS_AGGREGATED_SHARES: [u8; 64] = [\\n 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45,\\n 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"VK_HASH\\\"\\npub global DS_VK_HASH: [u8; 64] = [\\n 0x56, 0x4b, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"RECURSIVE_AGGREGATION\\\"\\npub global DS_RECURSIVE_AGGREGATION: [u8; 64] = [\\n 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47,\\n 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_PK_GENERATION\\\"\\npub global DS_CLG_PK_GENERATION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_ENCRYPTION\\\"\\npub global DS_CLG_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_USER_DATA_ENCRYPTION\\\"\\npub global DS_CLG_USER_DATA_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e,\\n 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_DECRYPTION\\\"\\npub global DS_CLG_SHARE_DECRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"THRESHOLD_DECRYPTION_SHARE\\\"\\npub global DS_THRESHOLD_DECRYPTION_SHARE: [u8; 64] = [\\n 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"USER_DATA_ENCRYPTION_COMMITMENT\\\"\\npub global DS_USER_DATA_ENCRYPTION_COMMITMENT: [u8; 64] = [\\n 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n/// WRAPPERS\\n\\npub fn compute_commitment(inputs: [Field], domain_separator: [u8; 64]) -> Field {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 1])[0]\\n}\\n\\npub fn compute_single_polynomial_commitment<let N: u32, let BIT: u32>(\\n polynomial: Polynomial<N>,\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT>([].as_vector(), polynomial);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_multiple_polynomial_commitment<let N: u32, let L: u32, let BIT: u32>(\\n polynomials: [Polynomial<N>; L],\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT>([].as_vector(), polynomials);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_challenge<let L: u32>(inputs: [Field], domain_separator: [u8; 64]) -> [Field] {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 2 * L])\\n}\\n\\npub fn single_polynomial_payload<let N: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n input: Polynomial<N>,\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, [input])\\n}\\n\\npub fn multiple_polynomial_payload<let N: u32, let L: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n inputs: [Polynomial<N>; L],\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, inputs)\\n}\\n\\n/// COMMITMENTS\\n\\npub fn compute_dkg_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let mut payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n payload = multiple_polynomial_payload::<N, L, BIT_PK>(payload, pk1);\\n\\n compute_commitment(payload, DS_PK)\\n}\\n\\npub fn compute_threshold_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n compute_commitment(payload, DS_PK_GENERATION)\\n}\\n\\npub fn compute_share_computation_sk_commitment<let N: u32, let BIT_SK: u32>(\\n sk: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_SK>([].as_vector(), sk);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_computation_e_sm_commitment<let N: u32, let L: u32, let BIT_E_SM: u32>(\\n e_sm: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_E_SM>([].as_vector(), e_sm);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_encryption_commitment_from_message<let N: u32, let BIT_MSG: u32>(\\n message: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_MSG>([].as_vector(), message);\\n compute_commitment(payload, DS_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_aggregated_shares_commitment<let N: u32, let L: u32, let BIT_MSG: u32>(\\n agg_shares: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_MSG>([].as_vector(), agg_shares);\\n compute_commitment(payload, DS_AGGREGATED_SHARES)\\n}\\n\\n/// Commitment to a threshold decryption share: all CRT limbs, first `K` coefficients per limb\\n/// (same layout as `Polynomial<K>` in decrypted_shares_aggregation).\\n///\\n/// `NATIVE_BIT_WIDTH` must cover native coefficients in \\\\([0, q_l)\\\\) per limb (not centered `d` bounds).\\npub fn compute_threshold_decryption_share_commitment<let K: u32, let L: u32, let NATIVE_BIT_WIDTH: u32>(\\n d_share_limbs: [Polynomial<K>; L],\\n) -> Field {\\n let payload =\\n multiple_polynomial_payload::<K, L, NATIVE_BIT_WIDTH>([].as_vector(), d_share_limbs);\\n compute_commitment(payload, DS_THRESHOLD_DECRYPTION_SHARE)\\n}\\n\\npub fn compute_pk_aggregation_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_pk0 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk0, DS_PK_AGGREGATION);\\n let commit_pk1 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk1, DS_PK_AGGREGATION);\\n\\n let inputs = [commit_pk0, commit_pk1].as_vector();\\n\\n compute_commitment(inputs, DS_PK_AGGREGATION)\\n}\\n\\npub fn compute_recursive_aggregation_commitment(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_RECURSIVE_AGGREGATION)\\n}\\n\\npub fn compute_vk_hash(vk_hashes: [Field]) -> Field {\\n compute_commitment(vk_hashes, DS_VK_HASH)\\n}\\n\\npub fn compute_ciphertext_commitment<let N: u32, let L: u32, let BIT_CT: u32>(\\n ct0: [Polynomial<N>; L],\\n ct1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_ct0 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct0, DS_CIPHERTEXT);\\n let commit_ct1 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct1, DS_CIPHERTEXT);\\n\\n let inputs = [commit_ct0, commit_ct1].as_vector();\\n\\n compute_commitment(inputs, DS_CIPHERTEXT)\\n}\\n\\n/// COMMITMENTS FOR CHALLENGES\\n\\npub fn compute_threshold_pk_challenge(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_CLG_PK_GENERATION)\\n}\\n\\npub fn compute_share_encryption_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_threshold_share_decryption_challenge<let L: u32>(payload: [Field]) -> Field {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_DECRYPTION)[0]\\n}\\n\\npub fn compute_user_data_encryption_ct0_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\\npub fn compute_user_data_encryption_ct1_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/commitments.nr\",\"function_locations\":[{\"start\":7767,\"name\":\"compute_commitment\"},{\"start\":7995,\"name\":\"compute_single_polynomial_commitment\"},{\"start\":8298,\"name\":\"compute_multiple_polynomial_commitment\"},{\"start\":8535,\"name\":\"compute_challenge\"},{\"start\":8745,\"name\":\"single_polynomial_payload\"},{\"start\":8944,\"name\":\"multiple_polynomial_payload\"},{\"start\":9157,\"name\":\"compute_dkg_pk_commitment\"},{\"start\":9484,\"name\":\"compute_threshold_pk_commitment\"},{\"start\":9734,\"name\":\"compute_share_computation_sk_commitment\"},{\"start\":10005,\"name\":\"compute_share_computation_e_sm_commitment\"},{\"start\":10277,\"name\":\"compute_share_encryption_commitment_from_message\"},{\"start\":10553,\"name\":\"compute_aggregated_shares_commitment\"},{\"start\":11134,\"name\":\"compute_threshold_decryption_share_commitment\"},{\"start\":11466,\"name\":\"compute_pk_aggregation_commitment\"},{\"start\":11855,\"name\":\"compute_recursive_aggregation_commitment\"},{\"start\":11970,\"name\":\"compute_vk_hash\"},{\"start\":12169,\"name\":\"compute_ciphertext_commitment\"},{\"start\":12568,\"name\":\"compute_threshold_pk_challenge\"},{\"start\":12710,\"name\":\"compute_share_encryption_challenge\"},{\"start\":12867,\"name\":\"compute_threshold_share_decryption_challenge\"},{\"start\":13027,\"name\":\"compute_user_data_encryption_ct0_challenge\"},{\"start\":13188,\"name\":\"compute_user_data_encryption_ct1_challenge\"}]},\"89\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\n//! Helper functions for circuit construction and cryptographic operations.\\nuse crate::math::polynomial::Polynomial;\\nuse crate::math::safe::SafeSponge;\\n\\n/// Compute hex-aligned packing parameters for a given `BIT`.\\n///\\n/// # Purpose\\n/// Returns `(nibble_bits, group)` for use by pack/flatten so layout stays consistent.\\n/// - `nibble_bits`: ceil (`BIT`) to the next multiple of 4 (nibble alignment).\\n/// - Examples: `BIT = 7 -> 8`, `BIT = 8 -> 8`, `BIT = 9 -> 12`, `BIT = 10 -> 12`, `BIT = 11 -> 12`,\\n/// `BIT=16 -> 16`, `BIT = 17 -> 20`.\\n/// - `group`: max number of encoded limbs that fit in one BN254 field element,\\n/// when each limb uses an extra 4 bits (see below).\\n///\\n/// # Rationale\\n/// - We align to nibbles so powers of two are hex-friendly and deterministic.\\n/// - We reserve one extra nibble (4 bits) per stored value to lift signed\\n/// coefficients into the non-negative range (e.g., store `v + 2^nibble_bits`),\\n/// which implies a radix of `2^(nibble_bits + 4)`.\\n///\\n/// # Safety\\n/// - Asserts `nibble_bits + 4 <= 254` to avoid mod-p wrap on BN254.\\n/// - Ensures at least one limb fits: `group >= 1`.\\nfn packing_layout<let BIT: u32>() -> (u32, u32) {\\n // Ceil BIT up to the next multiple of 4 (nibble alignment).\\n let nibble_bits = ((BIT + 3) / 4) * 4;\\n\\n // Each stored limb uses an extra nibble because negative coefficients\\n // will be shifted to positive, so radix = 2^(nibble_bits+4).\\n assert(nibble_bits + 4 <= 254);\\n\\n // Maximum limbs that fit in one BN254 element without wrap.\\n let group = 254 / (nibble_bits + 4);\\n assert(group >= 1);\\n (nibble_bits, group)\\n}\\n\\n/// Flatten `L` polynomials into a single linear stream of packed `Field` carriers.\\n///\\n/// ## What this does\\n/// - For each CRT limb `j` in `0..L`, it packs the coefficients of `poly[j]`\\n/// with `pack::<A, BIT>` and appends all resulting carriers to `inputs`.\\n/// - The packing layout (nibble-aligned width and `group` size) is taken from\\n/// `packing_layout::<BIT>()` and must match what `pack` uses.\\n///\\n/// ## Determinism & order\\n/// - Preserves a stable order: iterate `j = 0..L`, then for each `j` append\\n/// carriers in ascending chunk index `i = 0..num_chunks`.\\n/// - This ensures transcripts remain deterministic across runs.\\n///\\n/// ## Generics\\n/// - `A`: polynomial degree (number of coefficients per polynomial).\\n/// - `L`: number of CRT bases (polynomials).\\n/// - `BIT`: per-coefficient bit bound used by the packing layout (compile-time).\\n///\\n/// ## Returns\\n/// - The same `inputs` vector, extended with all carriers in deterministic order.\\npub fn flatten<let A: u32, let L: u32, let BIT: u32>(\\n mut inputs: [Field],\\n poly: [Polynomial<A>; L],\\n) -> [Field] {\\n for j in 0..L {\\n // Pack its A coefficients into `num_chunks` carriers using the same BIT layout.\\n let packed = pack::<A, BIT>(poly[j].coefficients);\\n\\n // Append carriers in-order to `inputs` to keep a stable transcript layout.\\n for i in 0..packed.len() {\\n inputs = inputs.push_back(packed[i]);\\n }\\n }\\n\\n // Return the extended input stream.\\n inputs\\n}\\n\\n/// Pack `A` values into a `[Field]` vector of carriers using the shared hex-aligned layout.\\n///\\n/// ## What this does\\n/// - Computes `(nibble_bits, group)` via `packing_layout::<BIT>()`.\\n/// - Encodes each value as a limb `digit = v + 2^nibble_bits` and concatenates\\n/// limbs in base `radix = 2^(nibble_bits + 4)` (one extra nibble of headroom).\\n/// - Packs up to `group` limbs per carrier (fits within BN254 254-bit capacity).\\n/// - Pads the last, partial carrier with `digit = 2^nibble_bits` to keep a stable layout.\\n///\\n/// ## Determinism & order\\n/// - Processes values in increasing index order and emits carriers in chunk order\\n/// (`chunk = 0..num_chunks`). Padding is deterministic.\\n///\\n/// ## Generics\\n/// - `A`: number of input values.\\n/// - `BIT`: per-value bit bound; rounded up to `nibble_bits` by `packing_layout`.\\n///\\n/// ## Preconditions / Notes\\n/// - Call with the raw coefficients whose magnitudes already satisfy the BIT bound\\n/// (as enforced by the upstream range checks); `pack` performs the signed -> unsigned\\n/// shift internally via `v + base`.\\n/// - `group >= 1` is enforced by `packing_layout::<BIT>()`.\\n/// - Padding with `digit = 2^nibble_bits` encodes `zero limb` consistently.\\n///\\n/// ## Returns\\n/// - A `[Field]` vector where each element is a concatenation of up to `group` limbs,\\n/// suitable for hashing or transcript I/O.\\npub fn pack<let A: u32, let BIT: u32>(values: [Field; A]) -> [Field] {\\n // Layout parameters: nibble-aligned width and limbs-per-carrier group size.\\n let (nibble_bits, group) = packing_layout::<BIT>();\\n\\n let base = 2.pow_32(nibble_bits as Field); // 2^nibble_bits\\n let radix = 2.pow_32((nibble_bits + 4) as Field); // 2^(nibble_bits + 4)\\n\\n // Number of chunks to emit: ceil(A / group).\\n let num_chunks = (A + group - 1) / group;\\n let mut out: [Field] = [].as_vector();\\n\\n // Process in fixed-size chunks of `group` limbs.\\n for chunk in 0..num_chunks {\\n // How many real values go into this chunk.\\n let remain = A - (chunk * group);\\n let take = if remain < group { remain } else { group };\\n\\n // Build field element accumulator (big-endian concatenation in `radix`).\\n let mut acc = 0;\\n for i in 0..take {\\n let v = values[chunk * group + i];\\n acc = acc * radix + (v + base);\\n }\\n\\n // Pad remaining limb slots with the canonical zero-limb `digit = base`.\\n for _ in 0..(group - take) {\\n acc = acc * radix + base;\\n }\\n\\n out = out.push_back(acc);\\n }\\n out\\n}\\n\\n/// Computes a cryptographic hash using the SAFE (Sponge API for Field Elements) protocol.\\n///\\n/// This is a convenience wrapper around the SAFE sponge API that handles the full\\n/// lifecycle: initialization, absorption, squeezing, and finalization. It's designed\\n/// for use in Fiat-Shamir challenge generation and commitment schemes within zero-knowledge circuits.\\n///\\n/// # Arguments\\n/// * `domain_separator` - A 64-byte domain separator used to differentiate between\\n/// different protocol instances and prevent cross-protocol attacks.\\n/// * `inputs` - Vector of field elements to be absorbed into the sponge.\\n/// * `io_pattern` - A 2-element array encoding the I/O pattern:\\n/// - `io_pattern[0]`: Encoded ABSORB operation (MSB=1, lower 31 bits = length)\\n/// - `io_pattern[1]`: Encoded SQUEEZE operation (MSB=0, lower 31 bits = length)\\n///\\n/// # Returns\\n/// A vector of field elements squeezed from the sponge, with length determined by\\n/// the SQUEEZE operation in the IO pattern.\\npub fn compute_safe(domain_separator: [u8; 64], inputs: [Field], io_pattern: [u32; 2]) -> [Field] {\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(inputs);\\n let digests = sponge.squeeze();\\n sponge.finish();\\n\\n digests\\n}\\n\\n#[test]\\nfn test_flatten() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([1, 2, 3]); // degree 2\\n let poly2 = Polynomial::new([4, -16, 6]); // degree 2\\n let poly3 = Polynomial::new([-7, 8, 9]); // degree 2\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 4>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n assert(result[0] == 0x11121310101010101010101010101010101010101010101010101010101010);\\n assert(result[1] == 0x14001610101010101010101010101010101010101010101010101010101010); // -16 became 00 at 0x 14 00 16,\\n assert(result[2] == 0x09181910101010101010101010101010101010101010101010101010101010); // -7 became 09 at 0x 09 18 19(16 - 7 = 9)\\n}\\n\\n#[test]\\nfn test_flatten_big() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([\\n 1791218451968394,\\n 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n 5430119342984413,\\n 704811298945172,\\n 8901715723925099,\\n 21888242871839275222246405745257275088548364400416034343698203098124042812559,\\n 21888242871839275222246405745257275088548364400416034343698200215091693880034,\\n ]);\\n let poly2 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698200314078269634250,\\n 21888242871839275222246405745257275088548364400416034343698200967285641915872,\\n 2909990636858607,\\n 7896103832076587,\\n 2078397209533893,\\n 21888242871839275222246405745257275088548364400416034343698199792421452734531,\\n 614400389245817,\\n 8290314119277588,\\n ]);\\n let poly3 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698201373175279892906,\\n 21888242871839275222246405745257275088548364400416034343698201087241869723721,\\n 6768789983786188,\\n 635797784303388,\\n 7610153424227556,\\n 4633893206538324,\\n 2016269760615332,\\n 21888242871839275222246405745257275088548364400416034343698201007080554428142,\\n ]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 54>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n\\n // For the first index of result operation goes like this,\\n\\n // First four index of poly1\\n // 1791218451968394,\\n // 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n // 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n // 5430119342984413,\\n\\n // base + 1791218451968394 = 0x1065d1a8b8b718a\\n // base - 5921327228407753 = 0xeaf69591f3b037 (negative coefficient shifted)\\n // base - 3644467483862151 = 0xf30d604a3a9b79 (negative coefficient shifted)\\n // base + 5430119342984413 = 0x1134aaa2e86ccdd\\n assert(result[0] == 0x1065d1a8b8b718a0eaf69591f3b0370f30d604a3a9b791134aaa2e86ccdd);\\n assert(result[1] == 0x1028105ab1b789411fa010339db66b0fc220f1326bc8e0f1e3f4cc1e02e1);\\n assert(result[2] == 0x0f23dfbe7cd76c90f4901299312ddf10a569efe35acef11c0d76f005412b);\\n assert(result[3] == 0x107624a8f605dc50f0638a368960421022ecb3cf36b7911d73ff2c27ec14);\\n assert(result[4] == 0x0f6013a24e1b9a90f4fd2c158a08481180c2dba8af4cc10242413515171c);\\n assert(result[5] == 0x11b0964eb898ce411076805680b85410729c962da53a40f4b44412d0f6ed);\\n}\\n\\n#[test]\\nfn test_flatten_small() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([712345, 104857, 999999, 500001, 123, 654321, 77]);\\n let poly2 = Polynomial::new([1, 524287, 888888, 23456, 34567, 765432, 0]);\\n let poly3 = Polynomial::new([444444, 333333, 222222, 111111, 987654, 246810, 13579]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 20>(inputs, polynomials);\\n\\n assert(result[0] == 0x1ade991199991f423f17a12110007b19fbf110004d100000100000100000);\\n assert(result[1] == 0x10000117ffff1d9038105ba01087071badf8100000100000100000100000);\\n assert(result[2] == 0x16c81c15161513640e11b2071f120613c41a10350b100000100000100000);\\n}\\n\\n#[test]\\nfn test_safe_hashing_with_safe_helper() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let digests1 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests1.len() == 1);\\n assert(digests1[0] != 0);\\n\\n // Test determinism\\n let digests2 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests2.len() == 1);\\n assert(digests2[0] != 0);\\n assert(digests2[0] == digests1[0]);\\n}\\n\\n#[test]\\nfn test_pack() {\\n // Test pack function directly with small values\\n let values = [1, 2, 3, 4];\\n let packed = pack::<4, 4>(values);\\n\\n // With BIT=4, nibble_bits=4, group should be floor(254/(4+4)) = 31\\n // So all 4 values should fit in one carrier\\n assert(packed.len() >= 1);\\n\\n // Test with negative values\\n let values_neg = [-1, 2, -3, 4];\\n let packed_neg = pack::<4, 4>(values_neg);\\n assert(packed_neg.len() >= 1);\\n}\\n\\n#[test]\\nfn test_pack_single_value() {\\n // Test packing a single value\\n let values = [42];\\n let packed = pack::<1, 8>(values);\\n assert(packed.len() == 1);\\n assert(packed[0] != 0);\\n}\\n\\n#[test]\\nfn test_pack_determinism() {\\n // Test that packing is deterministic\\n let values = [10, 20, 30];\\n let packed1 = pack::<3, 8>(values);\\n let packed2 = pack::<3, 8>(values);\\n\\n assert(packed1.len() == packed2.len());\\n for i in 0..packed1.len() {\\n assert(packed1[i] == packed2[i]);\\n }\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/helpers.nr\",\"function_locations\":[{\"start\":1374,\"name\":\"packing_layout\"},{\"start\":2905,\"name\":\"flatten\"},{\"start\":4755,\"name\":\"pack\"},{\"start\":7016,\"name\":\"compute_safe\"},{\"start\":7214,\"name\":\"test_flatten\"},{\"start\":8157,\"name\":\"test_flatten_big\"},{\"start\":11058,\"name\":\"test_flatten_small\"},{\"start\":11885,\"name\":\"test_safe_hashing_with_safe_helper\"},{\"start\":12731,\"name\":\"test_pack\"},{\"start\":13201,\"name\":\"test_pack_single_value\"},{\"start\":13397,\"name\":\"test_pack_determinism\"}]},\"97\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse keccak256::keccak256;\\nuse poseidon::poseidon2_permutation;\\n\\n/// SAFE (Sponge API for Field Elements)\\n///\\n/// This module provides a complete implementation of the SAFE API in Noir as defined in:\\n/// \\\"SAFE (Sponge API for Field Elements) - A Toolbox for ZK Hash Applications\\\"\\n/// see https://hackmd.io/bHgsH6mMStCVibM_wYvb2w#22-Sponge-state for more details.\\n///\\n/// SAFE provides a unified interface for cryptographic sponge functions that can be\\n/// instantiated with various permutations to create hash functions, MACs, authenticated\\n/// encryption schemes, and other cryptographic primitives for ZK proof systems.\\n///\\n/// This implementation follows the SAFE specification exactly, providing:\\n/// - Complete API: START, ABSORB, SQUEEZE, FINISH operations.\\n/// - Full security: Domain separation, tag computation, IO pattern validation.\\n/// - Poseidon2 integration: Field-friendly permutation for ZK systems.\\n/// - Specification compliance: All operations follow SAFE spec 2.4 exactly.\\n/// - Natural API design: Variable-length inputs, automatic length detection from IO patterns.\\n///\\n/// # API Design\\n///\\n/// The API is designed for natural usage while maintaining type safety:\\n/// - `absorb(input: [Field])`: Accepts variable-length arrays, no padding required.\\n/// - `squeeze()`: Returns a vector with field element(s).\\n/// - IO patterns automatically determine operation lengths for validation.\\n\\n/// Rate parameter for the sponge construction (number of field elements that can be absorbed per permutation call).\\nglobal RATE: u32 = 3;\\n\\n/// Capacity parameter for the sponge construction (security parameter, typically 1-2 field elements).\\nglobal CAPACITY: u32 = 1;\\n\\n/// Total state size (rate + capacity) in field elements.\\nglobal STATE_SIZE: u32 = RATE + CAPACITY;\\n\\n/// IO Pattern encoding constants (from SAFE spec 2.3).\\n///\\n/// These constants are used for encoding operation types in the 32-bit word format:\\n/// - MSB set to 1 for ABSORB operations\\n/// - MSB set to 0 for SQUEEZE operations\\n\\n/// Flag for ABSORB operations (MSB = 1)\\nglobal ABSORB_FLAG: u32 = 0x80000000;\\n\\n/// Flag for SQUEEZE operations (MSB = 0)\\nglobal SQUEEZE_FLAG: u32 = 0x00000000;\\n\\n/// SAFE Sponge State (following spec 2.2)\\n///\\n/// The sponge state consists of the permutation state, tag, position counters,\\n/// and IO pattern tracking as defined in the SAFE specification.\\n///\\n/// # Generic Parameters\\n/// - `L`: The length of the IO pattern array\\n///\\n/// # Fields\\n/// - `state`: Permutation state V in F^n (rate + capacity elements)\\n/// - `tag`: Parameter tag T used for instance differentiation\\n/// - `absorb_pos`: Current absorb position (<= n-c)\\n/// - `squeeze_pos`: Current squeeze position (<= n-c)\\n/// - `io_pattern`: Expected IO pattern for validation (encoded 32-bit words)\\n/// - `io_count`: Current operation count for pattern tracking\\npub struct SafeSponge<let L: u32> {\\n /// Permutation state V in F^n (rate + capacity elements).\\n state: [Field; STATE_SIZE],\\n /// Parameter tag T used for instance differentiation.\\n tag: Field,\\n /// Current absorb position (<= n-c).\\n absorb_pos: u32,\\n /// Current squeeze position (<= n-c).\\n squeeze_pos: u32,\\n /// Expected IO pattern for validation.\\n io_pattern: [u32; L],\\n /// Current operation count for pattern tracking (spec 2.4: io_count).\\n io_count: u32,\\n}\\n\\nimpl<let L: u32> SafeSponge<L> {\\n /// Initializes a new SAFE sponge instance with the given IO pattern and domain separator (following spec 2.4).\\n ///\\n /// # Arguments\\n /// - `io_pattern`: Array of 32-bit encoded operations defining the expected sequence of ABSORB/SQUEEZE calls.\\n /// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n /// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n ///\\n /// # Returns\\n /// A new `SafeSponge` instance with initialized state\\n pub fn start(io_pattern: [u32; L], domain_separator: [u8; 64]) -> SafeSponge<L> {\\n // Compute tag from IO pattern and domain separator (spec 2.3).\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n let mut state = [0; STATE_SIZE];\\n // Initialize capacity with tag (spec 2.4).\\n // Add T to the first 128 bits of the state.\\n state[0] = tag;\\n\\n SafeSponge { state, tag, absorb_pos: 0, squeeze_pos: 0, io_pattern, io_count: 0 }\\n }\\n\\n /// Absorbs field elements into the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to absorb is automatically validated against the IO pattern.\\n /// This method accepts variable-length arrays, making it natural to use without padding.\\n ///\\n /// # Arguments\\n /// - `input`: Array of field elements to absorb (variable length, must match IO pattern)\\n pub fn absorb(&mut self, input: [Field]) {\\n let length = input.len() as u32;\\n\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_absorb = (expected_encoded_word & ABSORB_FLAG) != 0;\\n let expected_length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type and length\\n assert(is_expected_absorb, \\\"Expected ABSORB operation\\\");\\n assert(expected_length == length, \\\"Length mismatch\\\");\\n\\n // Process each element naturally (no unnecessary iterations).\\n for i in 0..length {\\n // If absorb_pos == (n-c) then permute and reset (spec 2.4).\\n if self.absorb_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.absorb_pos = 0;\\n }\\n\\n // Add X[i] to state at absorb_pos (spec 2.4).\\n // Note: absorb_pos is the rate position, not capacity position.\\n self.state[self.absorb_pos + CAPACITY] =\\n self.state[self.absorb_pos + CAPACITY] + input[i];\\n self.absorb_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = ABSORB_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n\\n // Force permute at start of next SQUEEZE (spec 2.4).\\n self.squeeze_pos = RATE;\\n }\\n\\n /// Extracts field elements from the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to squeeze is automatically determined from the IO pattern.\\n pub fn squeeze(&mut self) -> [Field] {\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_squeeze = (expected_encoded_word & ABSORB_FLAG) == 0;\\n let length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type\\n assert(is_expected_squeeze, \\\"Expected SQUEEZE operation\\\");\\n\\n let mut output: [Field] = [].as_vector();\\n\\n // SQUEEZE implementation following spec 2.4.\\n // If length==0, loop won't execute (spec 2.4).\\n for _ in 0..length {\\n // If squeeze_pos==(n-c) then permute and reset (spec 2.4).\\n if self.squeeze_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.squeeze_pos = 0;\\n self.absorb_pos = 0;\\n }\\n // Set Y[i] to state element at squeeze_pos (spec 2.4).\\n output = output.push_back(self.state[self.squeeze_pos + CAPACITY]);\\n self.squeeze_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = SQUEEZE_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n output\\n }\\n\\n /// Finalizes the sponge instance, verifying that all expected operations have been performed and clearing the internal state for security (following spec 2.4).\\n ///\\n /// This function is used to ensure that the sponge instance has been used correctly and to prevent information leakage.\\n pub fn finish(&mut self) {\\n // Check that io_count equals the length of the IO pattern expected (spec 2.4).\\n assert(self.io_count == L, \\\"IO pattern not completed\\\");\\n\\n // Erase the state and its variables (spec 2.4).\\n self.state = [0; STATE_SIZE];\\n self.absorb_pos = 0;\\n self.squeeze_pos = 0;\\n self.io_count = 0;\\n }\\n\\n /// Permute the state using Poseidon2 (following spec 2.4).\\n ///\\n /// Applies the Poseidon2 permutation to the current state.\\n /// This is the core cryptographic primitive of the sponge construction.\\n ///\\n /// # Returns\\n /// New state after permutation\\n fn permute(self) -> [Field; STATE_SIZE] {\\n poseidon2_permutation(self.state)\\n }\\n}\\n\\n/// Computes a unique tag for a sponge instance based on its IO pattern and domain separator.\\n/// The tag is used to ensure that distinct instances behave like distinct functions.\\n///\\n/// # Arguments\\n/// - `io_pattern`: Array of 32-bit encoded operations defining the sponge's usage pattern.\\n/// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n/// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n///\\n/// # Returns\\n/// A field element representing the 128-bit tag.\\npub fn compute_tag<let L: u32>(io_pattern: [u32; L], domain_separator: [u8; 64]) -> Field {\\n // Step 1: Parse and aggregate consecutive operations of the same type\\n let mut encoded_words = [0; L]; // Support up to L operations.\\n let mut word_count = 0;\\n let mut current_absorb_sum = 0;\\n let mut current_squeeze_sum = 0;\\n let mut last_was_absorb = false;\\n\\n for i in 0..L {\\n if io_pattern[i] > 0 {\\n // Parse operation type from MSB and length from lower 31 bits\\n let is_absorb = (io_pattern[i] & ABSORB_FLAG) != 0;\\n let length = io_pattern[i] & 0x7FFFFFFF; // Clear MSB to get length\\n\\n if is_absorb {\\n if last_was_absorb {\\n // Aggregate consecutive ABSORB operations\\n current_absorb_sum += length;\\n } else {\\n // Start new ABSORB sequence\\n if current_squeeze_sum > 0 {\\n // Flush previous SQUEEZE sequence\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n current_squeeze_sum = 0;\\n }\\n current_absorb_sum = length;\\n }\\n last_was_absorb = true;\\n } else {\\n if !last_was_absorb {\\n // Aggregate consecutive SQUEEZE operations\\n current_squeeze_sum += length;\\n } else {\\n // Start new SQUEEZE sequence\\n if current_absorb_sum > 0 {\\n // Flush previous ABSORB sequence\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n current_absorb_sum = 0;\\n }\\n current_squeeze_sum = length;\\n }\\n last_was_absorb = false;\\n }\\n }\\n }\\n\\n // Flush remaining operations\\n if current_absorb_sum > 0 {\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n }\\n if current_squeeze_sum > 0 {\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n }\\n\\n // Step 2: Serialize to byte string and append domain separator (following SAFE spec 2.3).\\n // Buffer is 256 bytes: max 192 bytes for IO pattern (48 words) + 64 bytes for domain separator.\\n // Note: We must use a fixed-size array because Noir's keccak256 requires [u8; N], not [u8].\\n let max_io_pattern_bytes: u32 = 192; // 256 - 64 (domain separator)\\n let io_pattern_bytes = word_count * 4;\\n assert(\\n io_pattern_bytes <= max_io_pattern_bytes,\\n \\\"IO pattern too large: max 48 aggregated words supported\\\",\\n );\\n\\n let mut input_bytes = [0u8; 256];\\n let mut byte_count: u32 = 0;\\n\\n // Serialize encoded words to bytes (big-endian as per SAFE spec).\\n // Note: Noir requires compile-time loop bounds, so we iterate over L (the array size)\\n // instead of word_count (runtime value). The condition `i < word_count` ensures we only\\n // process valid encoded words. This is safe because word_count <= L always holds\\n // (we can have at most L encoded words from L input operations).\\n for i in 0..L {\\n if i < word_count {\\n let word = encoded_words[i];\\n input_bytes[byte_count] = (word >> 24) as u8;\\n input_bytes[byte_count + 1] = (word >> 16) as u8;\\n input_bytes[byte_count + 2] = (word >> 8) as u8;\\n input_bytes[byte_count + 3] = word as u8;\\n byte_count += 4;\\n }\\n }\\n\\n // Append full 64-byte domain separator.\\n for i in 0..64 {\\n input_bytes[byte_count] = domain_separator[i];\\n byte_count += 1;\\n }\\n\\n // Step 3: Hash with Keccak-256 and truncate to 128 bits.\\n // Note: The SAFE spec uses SHA3-256, but we use Keccak-256 for Noir compatibility.\\n // Keccak-256 differs from SHA3-256 in padding, but both provide equivalent security.\\n let hash_bytes = keccak256(input_bytes, byte_count);\\n\\n // Convert first 128 bits (16 bytes) to field element.\\n let mut tag_value: Field = 0;\\n for i in 0..16 {\\n tag_value = tag_value * 256 + (hash_bytes[i] as Field);\\n }\\n\\n tag_value\\n}\\n\\n#[test]\\nfn test_safe_hashing() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_merkle_node() {\\n // Verifies SAFE can be used for Merkle tree node hashing with pattern ABSORB(1) + ABSORB(1) + SQUEEZE(1).\\n // Tests the ability to absorb multiple inputs before squeezing output.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let left = [123].as_vector();\\n let right = [456].as_vector();\\n\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(left);\\n sponge.absorb(right);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(left);\\n sponge2.absorb(right);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_commitment_scheme() {\\n // Verifies SAFE can be used for commitment schemes with pattern ABSORB(3) + SQUEEZE(1).\\n // Tests the ability to create deterministic commitments from multiple field elements.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let values = [10, 20, 30].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(values);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(values);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_domain_separation() {\\n // Verifies that different domain separators produce different outputs for the same input.\\n // This is crucial for cross-protocol security and preventing collisions between different applications.\\n let elements = [1, 2, 3].as_vector();\\n let domain1 = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let domain2 = [\\n 0x41, 0x42, 0x43, 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n\\n let mut sponge1 = SafeSponge::start(io_pattern, domain1);\\n sponge1.absorb(elements);\\n let output1 = sponge1.squeeze();\\n sponge1.finish();\\n\\n let mut sponge2 = SafeSponge::start(io_pattern, domain2);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output1.len() == 1);\\n assert(output2.len() == 1);\\n assert(output1[0] != output2[0]); // Different domain separators should produce different outputs\\n}\\n\\n#[test]\\nfn test_multiple_squeeze() {\\n // Verifies that multiple field elements can be squeezed in a single operation.\\n // Tests pattern ABSORB(3) + SQUEEZE(2) to ensure proper state management.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(2)\\n let io_pattern = [0x80000003, 0x00000002];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 2);\\n assert(output[0] != 0);\\n assert(output[1] != 0);\\n assert(output[0] != output[1]); // Different squeeze outputs should be different\\n}\\n\\n#[test]\\nfn test_zero_length_operations() {\\n // Verifies that zero-length ABSORB and SQUEEZE operations are handled correctly.\\n // Tests pattern ABSORB(0) + SQUEEZE(1) to ensure proper state transitions.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(0), SQUEEZE(1)\\n let io_pattern = [0x80000000, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb([].as_vector());\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n}\\n\\n#[test]\\nfn test_tag_computation() {\\n // Verifies the tag computation algorithm using the example from the SAFE specification.\\n // Pattern: ABSORB(3), ABSORB(3), SQUEEZE(3)\\n // Should aggregate to: ABSORB(6), SQUEEZE(3)\\n // Encoded as: [0x80000006, 0x00000003]\\n // Tests determinism and pattern differentiation.\\n\\n let io_pattern = [0x80000003, 0x80000003, 0x00000003];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test determinism\\n let tag2 = compute_tag(io_pattern, domain_separator);\\n assert(tag == tag2);\\n\\n // Test that different patterns produce different tags\\n let io_pattern2 = [0x80000003, 0x00000003]; // ABSORB(3), SQUEEZE(3) - different pattern\\n let tag3 = compute_tag(io_pattern2, domain_separator);\\n assert(tag != tag3);\\n}\\n\\n#[test]\\nfn test_tag_computation_debug() {\\n println(\\\"=== SAFE Tag Computation Debug Test ===\\\");\\n\\n // Test your specific pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\n let io_pattern = [0x80000002, 0x00000002, 0x80000002];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n println(f\\\"Testing pattern: {io_pattern}\\\");\\n println(\\n f\\\"Expected to aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(2)\\\",\\n );\\n println(\\n f\\\"Expected encoded words: [0x80000002, 0x00000002, 0x80000002]\\\",\\n );\\n println(\\\"\\\");\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n println(f\\\"=== Expected Rust Output ===\\\");\\n println(\\\"Pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\\");\\n println(\\\"Domain separator: 0x41424344...\\\");\\n println(\\\"Tag: 0xce3bb9ee4b2d41c42e9cdda38afe8b6a\\\");\\n println(\\\"\\\");\\n\\n println(f\\\"=== Noir Output ===\\\");\\n println(f\\\"Tag: {tag}\\\");\\n println(\\\"\\\");\\n\\n println(\\\"Compare the tag values above with Rust script!\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_absorb_aggregation() {\\n // Test that consecutive ABSORB operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1) should aggregate to ABSORB(2), SQUEEZE(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(1) = [0x80000002, 0x00000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(2), SQUEEZE(1)\\n let aggregated_pattern = [0x80000002, 0x00000001];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Consecutive ABSORB operations should aggregate to the same tag\\\");\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive ABSORB operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive ABSORB Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001] (ABSORB(1), ABSORB(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000002, 0x00000001] (ABSORB(2), SQUEEZE(1))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_squeeze_aggregation() {\\n // Test that consecutive SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1) should aggregate to ABSORB(1), SQUEEZE(2)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x00000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(1), SQUEEZE(2) = [0x80000001, 0x00000002]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(1), SQUEEZE(2)\\n let aggregated_pattern = [0x80000001, 0x00000002];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(\\n tag == aggregated_tag,\\n \\\"Consecutive SQUEEZE operations should aggregate to the same tag\\\",\\n );\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive SQUEEZE operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive SQUEEZE Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x00000001, 0x00000001] (ABSORB(1), SQUEEZE(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000001, 0x00000002] (ABSORB(1), SQUEEZE(2))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_mixed_consecutive_aggregation() {\\n // Test that both consecutive ABSORB and SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n // Should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1) = [0x80000002, 0x00000002, 0x80000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag\\n let aggregated_pattern = [0x80000002, 0x00000002, 0x80000001]; // ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Mixed consecutive operations should aggregate to the same tag\\\");\\n\\n println(\\\"=== Mixed Consecutive Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001]\\\",\\n );\\n println(\\n f\\\" (ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1))\\\",\\n );\\n println(f\\\"Aggregated pattern: [0x80000002, 0x00000002, 0x80000001]\\\");\\n println(f\\\" (ABSORB(2), SQUEEZE(2), ABSORB(1))\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n}\\n\\n#[test]\\nfn test_large_io_pattern() {\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Create pattern with 48 alternating ABSORB(1) and SQUEEZE(1) operations\\n // This is the maximum supported (48 words * 4 bytes = 192 bytes, leaving 64 for domain separator)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1; // ABSORB(1)\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1; // SQUEEZE(1)\\n }\\n }\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n assert(tag != 0);\\n}\\n\\n#[test]\\nfn test_domain_separator_not_truncated() {\\n // This test verifies that the domain separator is always included in the tag computation,\\n // even for large IO patterns. If the domain separator were truncated, different domain\\n // separators would produce the same tag for large patterns.\\n\\n let domain_separator_a = [\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41,\\n ]; // All 'A's\\n\\n let domain_separator_b = [\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42,\\n ]; // All 'B's\\n\\n // Create pattern with 48 alternating operations (max supported: 192 bytes of IO pattern)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1;\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1;\\n }\\n }\\n\\n let tag_a = compute_tag(io_pattern, domain_separator_a);\\n let tag_b = compute_tag(io_pattern, domain_separator_b);\\n\\n // Tags MUST be different because domain separators are different.\\n // If they were the same, it would mean the domain separator was truncated/ignored.\\n assert(tag_a != tag_b, \\\"Domain separator must affect tag even for large IO patterns\\\");\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/safe.nr\",\"function_locations\":[{\"start\":4164,\"name\":\"SafeSponge<L>::start\"},{\"start\":5046,\"name\":\"SafeSponge<L>::absorb\"},{\"start\":6826,\"name\":\"SafeSponge<L>::squeeze\"},{\"start\":8494,\"name\":\"SafeSponge<L>::finish\"},{\"start\":9156,\"name\":\"SafeSponge<L>::permute\"},{\"start\":9830,\"name\":\"compute_tag\"},{\"start\":14128,\"name\":\"test_safe_hashing\"},{\"start\":15104,\"name\":\"test_merkle_node\"},{\"start\":16281,\"name\":\"test_commitment_scheme\"},{\"start\":17357,\"name\":\"test_domain_separation\"},{\"start\":18710,\"name\":\"test_multiple_squeeze\"},{\"start\":19639,\"name\":\"test_zero_length_operations\"},{\"start\":20415,\"name\":\"test_tag_computation\"},{\"start\":21477,\"name\":\"test_tag_computation_debug\"},{\"start\":22681,\"name\":\"test_consecutive_absorb_aggregation\"},{\"start\":24750,\"name\":\"test_consecutive_squeeze_aggregation\"},{\"start\":26760,\"name\":\"test_mixed_consecutive_aggregation\"},{\"start\":28520,\"name\":\"test_large_io_pattern\"},{\"start\":29333,\"name\":\"test_domain_separator_not_truncated\"}]}}}","{\"noir_version\":\"1.0.0-beta.26+40d6574f851d926f93e0c3a271bac3e6e82ac905\",\"hash\":\"1039263030772024318\",\"abi\":{\"parameters\":[{\"name\":\"user_data_encryption_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":5,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"user_data_encryption_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"crisp_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"crisp_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"prev_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_hi\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"digest_lo\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"slot_address\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"voting_power\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"is_first_vote\",\"type\":{\"kind\":\"boolean\"},\"visibility\":\"public\"},{\"name\":\"num_options\",\"type\":{\"kind\":\"integer\",\"sign\":\"unsigned\",\"width\":32},\"visibility\":\"public\"},{\"name\":\"final_ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"ct_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"},{\"name\":\"k1_commitment\",\"type\":{\"kind\":\"field\"},\"visibility\":\"private\"}],\"return_type\":{\"abi_type\":{\"kind\":\"field\"},\"visibility\":\"public\"},\"error_types\":{}},\"bytecode\":\"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\",\"debug_symbols\":\"tZbdiuMwDIXfxde+sOQfWfMqy1LSNh0CIS2ZZmAp8+7rdGKnGbDpuuyVmjj+0DmSVd/Esd1P77tuOJ0/xNuvm9iPXd9377v+fGiu3XkIb29fUsTH3XVs2/BKPKyHXZdmbIereBumvpfis+mn+0cfl2a4x2szhlUlRTscQwzAU9e3868vue5W+a3gCJfd4B0ngMUNAUoEmwjEeiXoDQHzBK3JLwRtHCQC4rMqEKxeCAikcypKPniykaAV5gj2ZR/cf/XBmOSD8arCBzTAKwFqCA6jD+gs1xAs+0RwVSrIukjY1OJ5gl998NbVEBiTCrYme7JMoaWAKeoAVEAJ4mkLKfQlEcWeIG90FlFoTFIcS0qg7IrgLYLyCAcq+unArEKYnkZYz1GI5YcsfiI4j2Bw0U8G5hwCC2XVnA6pUbBmAfQPXqQsHCpT48UGAXkvSkUFnfrisSI/ioqF/iRnUl84mxWC9vWKuJcrUhTi7XpGGHNZFE87UZzdytTMLK1sIgD4qomTpkUgVE1edioRsGbq6bWrNNDWh9/hqTl04+YOJDB8KYUOzkthguVS2HnySeHmP3Mp6Dv4eZRLwd8B1JxsiLBEXKKejQzRLNEuMcD0XNfPZuyafd8u16/TNBwebmPXP5e4Eu9rl/F8aI/T2M5Z39eCjr8=\",\"file_map\":{\"17\":{\"source\":\"// Exposed only for usage in `std::meta`\\npub(crate) mod poseidon2;\\n\\nuse crate::default::Default;\\nuse crate::embedded_curve_ops::{\\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\\n};\\nuse crate::meta::derive_via;\\nuse crate::static_assert;\\n\\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\\n\\n#[foreign(sha256_compression)]\\n// docs:start:sha256_compression\\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\\n// docs:end:sha256_compression\\n\\n#[foreign(keccakf1600)]\\n// docs:start:keccakf1600\\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\\n// docs:end:keccakf1600\\n\\n#[foreign(blake2s)]\\n// docs:start:blake2s\\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake2s\\n{}\\n\\n// docs:start:blake3\\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake3\\n{\\n if crate::runtime::is_unconstrained() {\\n // Temporary measure while Barretenberg is main proving system.\\n // Please open an issue if you're working on another proving system and running into problems due to this.\\n crate::static_assert(\\n N <= 1024,\\n \\\"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\\\",\\n );\\n }\\n __blake3(input)\\n}\\n\\n#[foreign(blake3)]\\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\\n\\n// docs:start:pedersen_commitment\\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\\n // docs:end:pedersen_commitment\\n pedersen_commitment_with_separator(input, 0)\\n}\\n\\n#[inline_always]\\npub fn pedersen_commitment_with_separator<let N: u32>(\\n input: [Field; N],\\n separator: u32,\\n) -> EmbeddedCurvePoint {\\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\\n for i in 0..N {\\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\\n }\\n let generators = derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n multi_scalar_mul(generators, points)\\n}\\n\\n// docs:start:pedersen_hash\\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\\n// docs:end:pedersen_hash\\n{\\n pedersen_hash_with_separator(input, 0)\\n}\\n\\n#[no_predicates]\\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\\n let mut generators: [EmbeddedCurvePoint; N + 1] =\\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\\n crate::assert_constant(separator);\\n let domain_generators: [EmbeddedCurvePoint; N] =\\n derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n\\n for i in 0..N {\\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\\n generators[i] = domain_generators[i];\\n }\\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\\n\\n let length_generator: [EmbeddedCurvePoint; 1] =\\n derive_generators(\\\"pedersen_hash_length\\\".as_bytes(), 0);\\n generators[N] = length_generator[0];\\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\\n}\\n\\n#[field(bn254)]\\n#[inline_always]\\npub fn derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {\\n crate::assert_constant(domain_separator_bytes);\\n crate::assert_constant(starting_index);\\n __derive_generators(domain_separator_bytes, starting_index)\\n}\\n\\n#[builtin(derive_pedersen_generators)]\\n#[field(bn254)]\\nfn __derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {}\\n\\npub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {\\n static_assert(\\n N == POSEIDON2_CONFIG_STATE_SIZE,\\n f\\\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\\\",\\n );\\n poseidon2_permutation_internal(input)\\n}\\n\\n#[foreign(poseidon2_permutation)]\\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\\n\\n#[foreign(poseidon2_config_state_size)]\\ncomptime fn poseidon2_config_state_size() -> u32 {}\\n\\n// Generic hashing support.\\n// Partially ported and impacted by rust.\\n\\n// Hash trait shall be implemented per type.\\n#[derive_via(derive_hash)]\\npub trait Hash {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher;\\n}\\n\\n// docs:start:derive_hash\\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\\n let name = quote { $crate::hash::Hash };\\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\\n let for_each_field = |name| quote { _self.$name.hash(_state); };\\n crate::meta::make_trait_impl(\\n s,\\n name,\\n signature,\\n for_each_field,\\n quote {},\\n |fields| fields,\\n )\\n}\\n// docs:end:derive_hash\\n\\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\\n// TODO: consider making the types generic here ([u8], [Field], etc.)\\npub trait Hasher {\\n fn finish(self) -> Field;\\n\\n /// Returns the hash value without consuming the hasher.\\n /// Override this for more efficient implementations that avoid copying.\\n /// TODO: deprecate finish() and replace it\\n fn finish_ref(&self) -> Field {\\n (*self).finish()\\n }\\n\\n fn write(&mut self, input: Field);\\n}\\n\\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\\npub trait BuildHasher {\\n type H: Hasher;\\n\\n fn build_hasher(self) -> H;\\n}\\n\\npub struct BuildHasherDefault<H>;\\n\\nimpl<H> BuildHasher for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n type H = H;\\n\\n fn build_hasher(_self: Self) -> H {\\n H::default()\\n }\\n}\\n\\nimpl<H> Default for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n fn default() -> Self {\\n BuildHasherDefault {}\\n }\\n}\\n\\nimpl Hash for Field {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self);\\n }\\n}\\n\\nimpl Hash for u8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u128 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for i8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u8 as Field);\\n }\\n}\\n\\nimpl Hash for i16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u16 as Field);\\n }\\n}\\n\\nimpl Hash for i32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u32 as Field);\\n }\\n}\\n\\nimpl Hash for i64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u64 as Field);\\n }\\n}\\n\\nimpl Hash for bool {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for () {\\n fn hash<H>(_self: Self, _state: &mut H)\\n where\\n H: Hasher,\\n {}\\n}\\n\\nimpl<T, let N: u32> Hash for [T; N]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<T> Hash for [T]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.len().hash(state);\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<A> Hash for (A,)\\nwhere\\n A: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n }\\n}\\n\\nimpl<A, B> Hash for (A, B)\\nwhere\\n A: Hash,\\n B: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n }\\n}\\n\\nimpl<A, B, C> Hash for (A, B, C)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D> Hash for (A, B, C, D)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F> Hash for (A, B, C, D, E, F)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G> Hash for (A, B, C, D, E, F, G)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_> Hash for (A, B, C, D, E, F, G, H_)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I> Hash for (A, B, C, D, E, F, G, H_, I)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J> Hash for (A, B, C, D, E, F, G, H_, I, J)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K> Hash for (A, B, C, D, E, F, G, H_, I, J, K)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K, L> Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n L: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n self.11.hash(state);\\n }\\n}\\n\\n// Some test vectors for Pedersen hash and Pedersen Commitment.\\n// They have been generated using the same functions so the tests are for now useless\\n// but they will be useful when we switch to Noir implementation.\\n#[test]\\nfn assert_pedersen() {\\n assert_eq(\\n pedersen_hash_with_separator([1], 1),\\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1], 1),\\n EmbeddedCurvePoint {\\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\\n },\\n );\\n\\n assert_eq(\\n pedersen_hash_with_separator([1, 2], 2),\\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2], 2),\\n EmbeddedCurvePoint {\\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3], 3),\\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3], 3),\\n EmbeddedCurvePoint {\\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\\n EmbeddedCurvePoint {\\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\\n EmbeddedCurvePoint {\\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\\n EmbeddedCurvePoint {\\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n EmbeddedCurvePoint {\\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n EmbeddedCurvePoint {\\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n EmbeddedCurvePoint {\\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n EmbeddedCurvePoint {\\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\\n },\\n );\\n}\\n\",\"path\":\"std/hash/mod.nr\",\"function_locations\":[{\"start\":572,\"name\":\"sha256_compression\"},{\"start\":707,\"name\":\"keccakf1600\"},{\"start\":852,\"name\":\"blake2s\"},{\"start\":950,\"name\":\"blake3\"},{\"start\":1437,\"name\":\"__blake3\"},{\"start\":1555,\"name\":\"pedersen_commitment\"},{\"start\":1784,\"name\":\"pedersen_commitment_with_separator\"},{\"start\":2188,\"name\":\"pedersen_hash\"},{\"start\":2345,\"name\":\"pedersen_hash_with_separator\"},{\"start\":3339,\"name\":\"derive_generators\"},{\"start\":3698,\"name\":\"__derive_generators\"},{\"start\":3776,\"name\":\"poseidon2_permutation\"},{\"start\":4132,\"name\":\"poseidon2_permutation_internal\"},{\"start\":4225,\"name\":\"poseidon2_config_state_size\"},{\"start\":4536,\"name\":\"derive_hash\"},{\"start\":5327,\"name\":\"Hasher::finish_ref\"},{\"start\":5761,\"name\":\"<impl BuildHasher for BuildHasherDefault<H>>::build_hasher\"},{\"start\":5893,\"name\":\"<impl Default for BuildHasherDefault<H>>::default\"},{\"start\":6025,\"name\":\"<impl Hash for Field>::hash\"},{\"start\":6155,\"name\":\"<impl Hash for u8>::hash\"},{\"start\":6295,\"name\":\"<impl Hash for u16>::hash\"},{\"start\":6435,\"name\":\"<impl Hash for u32>::hash\"},{\"start\":6575,\"name\":\"<impl Hash for u64>::hash\"},{\"start\":6716,\"name\":\"<impl Hash for u128>::hash\"},{\"start\":6855,\"name\":\"<impl Hash for i8>::hash\"},{\"start\":7001,\"name\":\"<impl Hash for i16>::hash\"},{\"start\":7148,\"name\":\"<impl Hash for i32>::hash\"},{\"start\":7295,\"name\":\"<impl Hash for i64>::hash\"},{\"start\":7443,\"name\":\"<impl Hash for bool>::hash\"},{\"start\":7590,\"name\":\"<impl Hash for ()>::hash\"},{\"start\":7722,\"name\":\"<impl Hash for [T; N]>::hash\"},{\"start\":7911,\"name\":\"<impl Hash for [T]>::hash\"},{\"start\":8133,\"name\":\"<impl Hash for (A,)>::hash\"},{\"start\":8302,\"name\":\"<impl Hash for (A, B)>::hash\"},{\"start\":8518,\"name\":\"<impl Hash for (A, B, C)>::hash\"},{\"start\":8781,\"name\":\"<impl Hash for (A, B, C, D)>::hash\"},{\"start\":9091,\"name\":\"<impl Hash for (A, B, C, D, E)>::hash\"},{\"start\":9448,\"name\":\"<impl Hash for (A, B, C, D, E, F)>::hash\"},{\"start\":9852,\"name\":\"<impl Hash for (A, B, C, D, E, F, G)>::hash\"},{\"start\":10306,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_)>::hash\"},{\"start\":10807,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I)>::hash\"},{\"start\":11355,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J)>::hash\"},{\"start\":11950,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K)>::hash\"},{\"start\":12593,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)>::hash\"},{\"start\":13187,\"name\":\"assert_pedersen\"}]},\"22\":{\"source\":\"pub mod hash;\\npub mod aes128;\\npub mod array;\\npub mod vector;\\npub mod ecdsa_secp256k1;\\npub mod ecdsa_secp256r1;\\npub mod embedded_curve_ops;\\npub mod field;\\npub mod collections;\\npub mod compat;\\npub mod convert;\\npub mod option;\\npub mod string;\\npub mod test;\\npub mod cmp;\\npub mod ops;\\npub mod default;\\npub mod prelude;\\npub mod runtime;\\npub mod meta;\\npub mod append;\\npub mod mem;\\npub mod panic;\\npub mod hint;\\n\\nmod integer;\\nmod primitive_docs;\\nmod internal;\\n\\n// Oracle calls are required to be wrapped in an unconstrained function\\n// Thus, the only argument to the `println` oracle is expected to always be an ident\\n#[oracle(print)]\\nunconstrained fn print_oracle<T>(with_newline: bool, input: T) {}\\n\\nunconstrained fn print_unconstrained<T>(with_newline: bool, input: T) {\\n print_oracle(with_newline, input);\\n}\\n\\n/// Print the given input to stdout followed by a newline\\npub fn println<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(true, input);\\n }\\n}\\n\\n/// Print the given input to stdout\\npub fn print<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(false, input);\\n }\\n}\\n\\n/// Asserts the validity of the provided proof and public inputs against the provided verification key and hash.\\n///\\n/// The ACVM cannot determine whether the provided proof is valid during execution as this requires knowledge of\\n/// the backend against which the program is being proven. However if an invalid proof if submitted, the program may\\n/// fail to prove or the backend may generate a proof which will subsequently fail to verify.\\n///\\n/// # Important Note\\n///\\n/// If you are not developing your own backend such as [Barretenberg](https://github.com/AztecProtocol/barretenberg)\\n/// you probably shouldn't need to interact with this function directly. It's easier and safer to use a verification\\n/// library which is published by the developers of the backend which will document or enforce any safety requirements.\\n///\\n/// If you use this directly, you're liable to introduce underconstrainedness bugs and *your circuit will be insecure*.\\n///\\n/// # Arguments\\n/// - verification_key: The verification key of the circuit to be verified.\\n/// - proof: The proof to be verified.\\n/// - public_inputs: The public inputs associated with `proof`\\n/// - key_hash: The hash of `verification_key` of the form expected by the backend.\\n/// - proof_type: An identifier for the proving scheme used to generate the proof to be verified. This allows\\n/// for a single backend to support verifying multiple proving schemes.\\n///\\n/// # Constraining `key_hash`\\n///\\n/// The Noir compiler does not by itself constrain that `key_hash` is a valid hash of `verification_key`.\\n/// This is because different backends may differ in how they hash their verification keys.\\n/// It is then the responsibility of either the noir developer (by explicitly hashing the verification key\\n/// in the correct manner) or by the proving system itself internally asserting the correctness of `key_hash`.\\npub fn verify_proof_with_type<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {\\n if !crate::runtime::is_unconstrained() {\\n crate::assert_constant(proof_type);\\n }\\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\\n}\\n\\n#[foreign(recursive_aggregation)]\\nfn verify_proof_internal<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {}\\n\\n/// Asserts that the given value is known at compile-time.\\n/// Useful for debugging for-loop bounds.\\n#[builtin(assert_constant)]\\npub fn assert_constant<T>(x: T) {}\\n\\n/// Asserts that the given value is both true and known at compile-time.\\n/// The message can be a string, a format string, or any value, as long as it is known at compile-time\\n#[builtin(static_assert)]\\npub fn static_assert<T>(predicate: bool, message: T) {}\\n\\n/// Force a field value to be a witness instead of a constant in the compiled output.\\n/// This is often only useful for debugging compiler optimizations.\\n///\\n/// This has no effect in unconstrained or comptime code.\\n#[builtin(as_witness)]\\npub fn as_witness(x: Field) {}\\n\",\"path\":\"std/lib.nr\",\"function_locations\":[{\"start\":689,\"name\":\"print_oracle\"},{\"start\":763,\"name\":\"print_unconstrained\"},{\"start\":893,\"name\":\"println\"},{\"start\":1076,\"name\":\"print\"},{\"start\":3277,\"name\":\"verify_proof_with_type\"},{\"start\":3694,\"name\":\"verify_proof_internal\"},{\"start\":3859,\"name\":\"assert_constant\"},{\"start\":4118,\"name\":\"static_assert\"},{\"start\":4389,\"name\":\"as_witness\"}]},\"52\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse bb_proof_verification::{UltraHonkProof, UltraHonkVerificationKey, verify_honk_proof_non_zk};\\nuse interfold_lib::math::commitments::compute_vk_hash;\\n\\n/// Binds the four inner `vk_hash` witnesses. Regenerate with `pnpm compute:vk-hash` in\\n/// `examples/CRISP` after changing ct0 / ct1 / user_data_encryption / crisp_onchain (or the lib\\n/// preset). Insecure: `lib::configs::default` uses `insecure::*`; secure: uses `secure::*`.\\npub global CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_INSECURE: Field =\\n 0x06c830801c0712d55b8095ea55a13d5122694f33969a2dfd8694575d37a22b48;\\npub global CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_SECURE: Field =\\n 0x16818150403cb64eb84e5dccc9d68d33c5a8c8e70fb40de649e6b758db10e7fa;\\n\\nfn main(\\n // User Data Encryption Section.\\n user_data_encryption_verification_key: UltraHonkVerificationKey,\\n user_data_encryption_proof: UltraHonkProof,\\n user_data_encryption_public_inputs: [Field; 5], // ct0_key_hash, ct1_key_hash, pk_commitment, ct_commitment, k1_commitment\\n user_data_encryption_key_hash: Field,\\n // Crisp Section.\\n crisp_verification_key: UltraHonkVerificationKey,\\n crisp_proof: UltraHonkProof,\\n crisp_key_hash: Field,\\n prev_ct_commitment: pub Field,\\n digest_hi: pub Field,\\n digest_lo: pub Field,\\n slot_address: pub Field,\\n voting_power: pub Field,\\n is_first_vote: pub bool,\\n num_options: pub u32,\\n final_ct_commitment: pub Field,\\n ct_commitment: Field,\\n k1_commitment: Field,\\n) -> pub Field {\\n verify_honk_proof_non_zk(\\n user_data_encryption_verification_key,\\n user_data_encryption_proof,\\n user_data_encryption_public_inputs,\\n user_data_encryption_key_hash,\\n );\\n verify_honk_proof_non_zk(\\n crisp_verification_key,\\n crisp_proof,\\n [\\n prev_ct_commitment,\\n digest_hi,\\n digest_lo,\\n slot_address,\\n voting_power,\\n if is_first_vote { 1 } else { 0 },\\n num_options as Field,\\n final_ct_commitment,\\n ct_commitment,\\n k1_commitment,\\n ],\\n crisp_key_hash,\\n );\\n\\n // Verify that the ct_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(ct_commitment == user_data_encryption_public_inputs[3]);\\n\\n // Verify that the k1_commitment from the crisp proof matches the one computed from user data encryption.\\n assert(k1_commitment == user_data_encryption_public_inputs[4]);\\n\\n let vk_hashes = [\\n user_data_encryption_key_hash,\\n crisp_key_hash,\\n user_data_encryption_public_inputs[0], // ct0_key_hash\\n user_data_encryption_public_inputs[1], // ct1_key_hash\\n ]\\n .as_vector();\\n\\n let chain_key_hash = compute_vk_hash(vk_hashes);\\n assert(\\n (chain_key_hash == CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_INSECURE)\\n | (chain_key_hash == CRISP_ONCHAIN_FOLD_EXPECTED_KEY_HASH_SECURE),\\n );\\n\\n user_data_encryption_public_inputs[2]\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/examples/CRISP/circuits/bin/fold_onchain/src/main.nr\",\"function_locations\":[{\"start\":1666,\"name\":\"main\"}]},\"53\":{\"source\":\"// Constants for UltraHonk recursive verifier inputs\\npub global PROOF_TYPE_HONK: u32 = 0; // identifier for UltraHonk verfier\\npub global RECURSIVE_PROOF_LENGTH: u32 = 410;\\npub global ULTRA_VK_LENGTH_IN_FIELDS: u32 = 115;\\n\\npub type UltraHonkProof = [Field; RECURSIVE_PROOF_LENGTH];\\npub type UltraHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\n// Constants for Rollup-UltraHonk recursive verifier inputs (N.B. this is equivalent to UH plus IPA claim and proof)\\npub global PROOF_TYPE_ROLLUP_HONK: u32 = 4; // identifier for rollup-UltraHonk verfier\\npub global PROOF_TYPE_ROOT_ROLLUP_HONK: u32 = 5; // identifier for root-rollup-UltraHonk verfier (closes the IPA accumulator)\\npub global IPA_CLAIM_SIZE: u32 = 6;\\npub global IPA_PROOF_LENGTH: u32 = 64;\\npub global RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 =\\n RECURSIVE_PROOF_LENGTH + IPA_CLAIM_SIZE + IPA_PROOF_LENGTH;\\n\\npub type RollupHonkProof = [Field; RECURSIVE_ROLLUP_HONK_PROOF_LENGTH];\\npub type RollupHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\npub global PROOF_TYPE_HONK_ZK: u32 = 6; // identifier for UltraHonk ZK verfier\\npub global RECURSIVE_ZK_PROOF_LENGTH: u32 = 450 + 8;\\n\\npub type UltraHonkZKProof = [Field; RECURSIVE_ZK_PROOF_LENGTH];\\n\\n// Verifies a non-zero-knowledge UltraHonk proof.\\n//\\n// Represents standard UltraHonk recursive verification for proofs that do not hide the witness.\\n// Use this only in situations where zero-knowledge is not required.\\npub fn verify_honk_proof_non_zk<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof with IPA (Inner Product Argument).\\n//\\n// This variant includes an IPA claim and proof appended to the standard UltraHonk proof,\\n// used to amortize IPA recursive verification costs in rollup circuits.\\npub fn verify_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof and closes the IPA accumulator in-circuit.\\n//\\n// Use this at the root of a rollup aggregation tree. The inner proof has the same RollupHonk shape\\n// as `verify_rolluphonk_proof`, but instead of propagating an accumulated IPA claim out as a public\\n// input, this variant performs a full native IPA verification inside the circuit. The outer circuit\\n// should therefore be proved as a standard (non-rollup) UltraHonk circuit, producing a proof\\n// suitable for verification by `verify_honk_proof` / `verify_honk_proof_non_zk`.\\n//\\n// When two RollupHonk inputs are verified this way in one circuit, their two IPA claims are first\\n// accumulated into one, then the accumulated claim is fully verified.\\npub fn verify_root_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROOT_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a zero-knowledge UltraHonk proof.\\n//\\n// This verifier is for UltraHonk proofs constructed with zero-knowledge, which hide the witness\\n// values from the verifier.\\n// Note: We intentionally choose the generic name \\\"verify_honk_proof\\\" for this function, as we\\n// want ZK to be the default unless the user explicitly opts out.\\npub fn verify_honk_proof<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkZKProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK_ZK,\\n );\\n}\\n\",\"path\":\"/home/ace/nargo/github.com/AztecProtocol/aztec-packages/v5.1.0/barretenberg/noir/bb_proof_verification/src/lib.nr\",\"function_locations\":[{\"start\":1646,\"name\":\"verify_honk_proof_non_zk\"},{\"start\":2262,\"name\":\"verify_rolluphonk_proof\"},{\"start\":3386,\"name\":\"verify_root_rolluphonk_proof\"},{\"start\":4087,\"name\":\"verify_honk_proof\"}]},\"87\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse crate::math::helpers::{compute_safe, flatten};\\nuse crate::math::polynomial::Polynomial;\\n\\n/// DOMAIN SEPARATORS\\n\\n// Domain separator - \\\"PK\\\"\\npub global DS_PK: [u8; 64] = [\\n 0x50, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_GENERATION\\\"\\npub global DS_PK_GENERATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_COMPUTATION\\\"\\npub global DS_SHARE_COMPUTATION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_ENCRYPTION\\\"\\npub global DS_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_AGGREGATION\\\"\\npub global DS_PK_AGGREGATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CIPHERTEXT\\\"\\npub global DS_CIPHERTEXT: [u8; 64] = [\\n 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"AGGREGATED_SHARES\\\"\\npub global DS_AGGREGATED_SHARES: [u8; 64] = [\\n 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45,\\n 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"VK_HASH\\\"\\npub global DS_VK_HASH: [u8; 64] = [\\n 0x56, 0x4b, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"RECURSIVE_AGGREGATION\\\"\\npub global DS_RECURSIVE_AGGREGATION: [u8; 64] = [\\n 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47,\\n 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_PK_GENERATION\\\"\\npub global DS_CLG_PK_GENERATION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_ENCRYPTION\\\"\\npub global DS_CLG_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_USER_DATA_ENCRYPTION\\\"\\npub global DS_CLG_USER_DATA_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e,\\n 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_DECRYPTION\\\"\\npub global DS_CLG_SHARE_DECRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"THRESHOLD_DECRYPTION_SHARE\\\"\\npub global DS_THRESHOLD_DECRYPTION_SHARE: [u8; 64] = [\\n 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"USER_DATA_ENCRYPTION_COMMITMENT\\\"\\npub global DS_USER_DATA_ENCRYPTION_COMMITMENT: [u8; 64] = [\\n 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n/// WRAPPERS\\n\\npub fn compute_commitment(inputs: [Field], domain_separator: [u8; 64]) -> Field {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 1])[0]\\n}\\n\\npub fn compute_single_polynomial_commitment<let N: u32, let BIT: u32>(\\n polynomial: Polynomial<N>,\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT>([].as_vector(), polynomial);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_multiple_polynomial_commitment<let N: u32, let L: u32, let BIT: u32>(\\n polynomials: [Polynomial<N>; L],\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT>([].as_vector(), polynomials);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_challenge<let L: u32>(inputs: [Field], domain_separator: [u8; 64]) -> [Field] {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 2 * L])\\n}\\n\\npub fn single_polynomial_payload<let N: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n input: Polynomial<N>,\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, [input])\\n}\\n\\npub fn multiple_polynomial_payload<let N: u32, let L: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n inputs: [Polynomial<N>; L],\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, inputs)\\n}\\n\\n/// COMMITMENTS\\n\\npub fn compute_dkg_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let mut payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n payload = multiple_polynomial_payload::<N, L, BIT_PK>(payload, pk1);\\n\\n compute_commitment(payload, DS_PK)\\n}\\n\\npub fn compute_threshold_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n compute_commitment(payload, DS_PK_GENERATION)\\n}\\n\\npub fn compute_share_computation_sk_commitment<let N: u32, let BIT_SK: u32>(\\n sk: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_SK>([].as_vector(), sk);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_computation_e_sm_commitment<let N: u32, let L: u32, let BIT_E_SM: u32>(\\n e_sm: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_E_SM>([].as_vector(), e_sm);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_encryption_commitment_from_message<let N: u32, let BIT_MSG: u32>(\\n message: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_MSG>([].as_vector(), message);\\n compute_commitment(payload, DS_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_aggregated_shares_commitment<let N: u32, let L: u32, let BIT_MSG: u32>(\\n agg_shares: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_MSG>([].as_vector(), agg_shares);\\n compute_commitment(payload, DS_AGGREGATED_SHARES)\\n}\\n\\n/// Commitment to a threshold decryption share: all CRT limbs, first `K` coefficients per limb\\n/// (same layout as `Polynomial<K>` in decrypted_shares_aggregation).\\n///\\n/// `NATIVE_BIT_WIDTH` must cover native coefficients in \\\\([0, q_l)\\\\) per limb (not centered `d` bounds).\\npub fn compute_threshold_decryption_share_commitment<let K: u32, let L: u32, let NATIVE_BIT_WIDTH: u32>(\\n d_share_limbs: [Polynomial<K>; L],\\n) -> Field {\\n let payload =\\n multiple_polynomial_payload::<K, L, NATIVE_BIT_WIDTH>([].as_vector(), d_share_limbs);\\n compute_commitment(payload, DS_THRESHOLD_DECRYPTION_SHARE)\\n}\\n\\npub fn compute_pk_aggregation_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_pk0 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk0, DS_PK_AGGREGATION);\\n let commit_pk1 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk1, DS_PK_AGGREGATION);\\n\\n let inputs = [commit_pk0, commit_pk1].as_vector();\\n\\n compute_commitment(inputs, DS_PK_AGGREGATION)\\n}\\n\\npub fn compute_recursive_aggregation_commitment(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_RECURSIVE_AGGREGATION)\\n}\\n\\npub fn compute_vk_hash(vk_hashes: [Field]) -> Field {\\n compute_commitment(vk_hashes, DS_VK_HASH)\\n}\\n\\npub fn compute_ciphertext_commitment<let N: u32, let L: u32, let BIT_CT: u32>(\\n ct0: [Polynomial<N>; L],\\n ct1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_ct0 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct0, DS_CIPHERTEXT);\\n let commit_ct1 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct1, DS_CIPHERTEXT);\\n\\n let inputs = [commit_ct0, commit_ct1].as_vector();\\n\\n compute_commitment(inputs, DS_CIPHERTEXT)\\n}\\n\\n/// COMMITMENTS FOR CHALLENGES\\n\\npub fn compute_threshold_pk_challenge(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_CLG_PK_GENERATION)\\n}\\n\\npub fn compute_share_encryption_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_threshold_share_decryption_challenge<let L: u32>(payload: [Field]) -> Field {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_DECRYPTION)[0]\\n}\\n\\npub fn compute_user_data_encryption_ct0_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\\npub fn compute_user_data_encryption_ct1_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/commitments.nr\",\"function_locations\":[{\"start\":7767,\"name\":\"compute_commitment\"},{\"start\":7995,\"name\":\"compute_single_polynomial_commitment\"},{\"start\":8298,\"name\":\"compute_multiple_polynomial_commitment\"},{\"start\":8535,\"name\":\"compute_challenge\"},{\"start\":8745,\"name\":\"single_polynomial_payload\"},{\"start\":8944,\"name\":\"multiple_polynomial_payload\"},{\"start\":9157,\"name\":\"compute_dkg_pk_commitment\"},{\"start\":9484,\"name\":\"compute_threshold_pk_commitment\"},{\"start\":9734,\"name\":\"compute_share_computation_sk_commitment\"},{\"start\":10005,\"name\":\"compute_share_computation_e_sm_commitment\"},{\"start\":10277,\"name\":\"compute_share_encryption_commitment_from_message\"},{\"start\":10553,\"name\":\"compute_aggregated_shares_commitment\"},{\"start\":11134,\"name\":\"compute_threshold_decryption_share_commitment\"},{\"start\":11466,\"name\":\"compute_pk_aggregation_commitment\"},{\"start\":11855,\"name\":\"compute_recursive_aggregation_commitment\"},{\"start\":11970,\"name\":\"compute_vk_hash\"},{\"start\":12169,\"name\":\"compute_ciphertext_commitment\"},{\"start\":12568,\"name\":\"compute_threshold_pk_challenge\"},{\"start\":12710,\"name\":\"compute_share_encryption_challenge\"},{\"start\":12867,\"name\":\"compute_threshold_share_decryption_challenge\"},{\"start\":13027,\"name\":\"compute_user_data_encryption_ct0_challenge\"},{\"start\":13188,\"name\":\"compute_user_data_encryption_ct1_challenge\"}]},\"89\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\n//! Helper functions for circuit construction and cryptographic operations.\\nuse crate::math::polynomial::Polynomial;\\nuse crate::math::safe::SafeSponge;\\n\\n/// Compute hex-aligned packing parameters for a given `BIT`.\\n///\\n/// # Purpose\\n/// Returns `(nibble_bits, group)` for use by pack/flatten so layout stays consistent.\\n/// - `nibble_bits`: ceil (`BIT`) to the next multiple of 4 (nibble alignment).\\n/// - Examples: `BIT = 7 -> 8`, `BIT = 8 -> 8`, `BIT = 9 -> 12`, `BIT = 10 -> 12`, `BIT = 11 -> 12`,\\n/// `BIT=16 -> 16`, `BIT = 17 -> 20`.\\n/// - `group`: max number of encoded limbs that fit in one BN254 field element,\\n/// when each limb uses an extra 4 bits (see below).\\n///\\n/// # Rationale\\n/// - We align to nibbles so powers of two are hex-friendly and deterministic.\\n/// - We reserve one extra nibble (4 bits) per stored value to lift signed\\n/// coefficients into the non-negative range (e.g., store `v + 2^nibble_bits`),\\n/// which implies a radix of `2^(nibble_bits + 4)`.\\n///\\n/// # Safety\\n/// - Asserts `nibble_bits + 4 <= 254` to avoid mod-p wrap on BN254.\\n/// - Ensures at least one limb fits: `group >= 1`.\\nfn packing_layout<let BIT: u32>() -> (u32, u32) {\\n // Ceil BIT up to the next multiple of 4 (nibble alignment).\\n let nibble_bits = ((BIT + 3) / 4) * 4;\\n\\n // Each stored limb uses an extra nibble because negative coefficients\\n // will be shifted to positive, so radix = 2^(nibble_bits+4).\\n assert(nibble_bits + 4 <= 254);\\n\\n // Maximum limbs that fit in one BN254 element without wrap.\\n let group = 254 / (nibble_bits + 4);\\n assert(group >= 1);\\n (nibble_bits, group)\\n}\\n\\n/// Flatten `L` polynomials into a single linear stream of packed `Field` carriers.\\n///\\n/// ## What this does\\n/// - For each CRT limb `j` in `0..L`, it packs the coefficients of `poly[j]`\\n/// with `pack::<A, BIT>` and appends all resulting carriers to `inputs`.\\n/// - The packing layout (nibble-aligned width and `group` size) is taken from\\n/// `packing_layout::<BIT>()` and must match what `pack` uses.\\n///\\n/// ## Determinism & order\\n/// - Preserves a stable order: iterate `j = 0..L`, then for each `j` append\\n/// carriers in ascending chunk index `i = 0..num_chunks`.\\n/// - This ensures transcripts remain deterministic across runs.\\n///\\n/// ## Generics\\n/// - `A`: polynomial degree (number of coefficients per polynomial).\\n/// - `L`: number of CRT bases (polynomials).\\n/// - `BIT`: per-coefficient bit bound used by the packing layout (compile-time).\\n///\\n/// ## Returns\\n/// - The same `inputs` vector, extended with all carriers in deterministic order.\\npub fn flatten<let A: u32, let L: u32, let BIT: u32>(\\n mut inputs: [Field],\\n poly: [Polynomial<A>; L],\\n) -> [Field] {\\n for j in 0..L {\\n // Pack its A coefficients into `num_chunks` carriers using the same BIT layout.\\n let packed = pack::<A, BIT>(poly[j].coefficients);\\n\\n // Append carriers in-order to `inputs` to keep a stable transcript layout.\\n for i in 0..packed.len() {\\n inputs = inputs.push_back(packed[i]);\\n }\\n }\\n\\n // Return the extended input stream.\\n inputs\\n}\\n\\n/// Pack `A` values into a `[Field]` vector of carriers using the shared hex-aligned layout.\\n///\\n/// ## What this does\\n/// - Computes `(nibble_bits, group)` via `packing_layout::<BIT>()`.\\n/// - Encodes each value as a limb `digit = v + 2^nibble_bits` and concatenates\\n/// limbs in base `radix = 2^(nibble_bits + 4)` (one extra nibble of headroom).\\n/// - Packs up to `group` limbs per carrier (fits within BN254 254-bit capacity).\\n/// - Pads the last, partial carrier with `digit = 2^nibble_bits` to keep a stable layout.\\n///\\n/// ## Determinism & order\\n/// - Processes values in increasing index order and emits carriers in chunk order\\n/// (`chunk = 0..num_chunks`). Padding is deterministic.\\n///\\n/// ## Generics\\n/// - `A`: number of input values.\\n/// - `BIT`: per-value bit bound; rounded up to `nibble_bits` by `packing_layout`.\\n///\\n/// ## Preconditions / Notes\\n/// - Call with the raw coefficients whose magnitudes already satisfy the BIT bound\\n/// (as enforced by the upstream range checks); `pack` performs the signed -> unsigned\\n/// shift internally via `v + base`.\\n/// - `group >= 1` is enforced by `packing_layout::<BIT>()`.\\n/// - Padding with `digit = 2^nibble_bits` encodes `zero limb` consistently.\\n///\\n/// ## Returns\\n/// - A `[Field]` vector where each element is a concatenation of up to `group` limbs,\\n/// suitable for hashing or transcript I/O.\\npub fn pack<let A: u32, let BIT: u32>(values: [Field; A]) -> [Field] {\\n // Layout parameters: nibble-aligned width and limbs-per-carrier group size.\\n let (nibble_bits, group) = packing_layout::<BIT>();\\n\\n let base = 2.pow_32(nibble_bits as Field); // 2^nibble_bits\\n let radix = 2.pow_32((nibble_bits + 4) as Field); // 2^(nibble_bits + 4)\\n\\n // Number of chunks to emit: ceil(A / group).\\n let num_chunks = (A + group - 1) / group;\\n let mut out: [Field] = [].as_vector();\\n\\n // Process in fixed-size chunks of `group` limbs.\\n for chunk in 0..num_chunks {\\n // How many real values go into this chunk.\\n let remain = A - (chunk * group);\\n let take = if remain < group { remain } else { group };\\n\\n // Build field element accumulator (big-endian concatenation in `radix`).\\n let mut acc = 0;\\n for i in 0..take {\\n let v = values[chunk * group + i];\\n acc = acc * radix + (v + base);\\n }\\n\\n // Pad remaining limb slots with the canonical zero-limb `digit = base`.\\n for _ in 0..(group - take) {\\n acc = acc * radix + base;\\n }\\n\\n out = out.push_back(acc);\\n }\\n out\\n}\\n\\n/// Computes a cryptographic hash using the SAFE (Sponge API for Field Elements) protocol.\\n///\\n/// This is a convenience wrapper around the SAFE sponge API that handles the full\\n/// lifecycle: initialization, absorption, squeezing, and finalization. It's designed\\n/// for use in Fiat-Shamir challenge generation and commitment schemes within zero-knowledge circuits.\\n///\\n/// # Arguments\\n/// * `domain_separator` - A 64-byte domain separator used to differentiate between\\n/// different protocol instances and prevent cross-protocol attacks.\\n/// * `inputs` - Vector of field elements to be absorbed into the sponge.\\n/// * `io_pattern` - A 2-element array encoding the I/O pattern:\\n/// - `io_pattern[0]`: Encoded ABSORB operation (MSB=1, lower 31 bits = length)\\n/// - `io_pattern[1]`: Encoded SQUEEZE operation (MSB=0, lower 31 bits = length)\\n///\\n/// # Returns\\n/// A vector of field elements squeezed from the sponge, with length determined by\\n/// the SQUEEZE operation in the IO pattern.\\npub fn compute_safe(domain_separator: [u8; 64], inputs: [Field], io_pattern: [u32; 2]) -> [Field] {\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(inputs);\\n let digests = sponge.squeeze();\\n sponge.finish();\\n\\n digests\\n}\\n\\n#[test]\\nfn test_flatten() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([1, 2, 3]); // degree 2\\n let poly2 = Polynomial::new([4, -16, 6]); // degree 2\\n let poly3 = Polynomial::new([-7, 8, 9]); // degree 2\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 4>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n assert(result[0] == 0x11121310101010101010101010101010101010101010101010101010101010);\\n assert(result[1] == 0x14001610101010101010101010101010101010101010101010101010101010); // -16 became 00 at 0x 14 00 16,\\n assert(result[2] == 0x09181910101010101010101010101010101010101010101010101010101010); // -7 became 09 at 0x 09 18 19(16 - 7 = 9)\\n}\\n\\n#[test]\\nfn test_flatten_big() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([\\n 1791218451968394,\\n 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n 5430119342984413,\\n 704811298945172,\\n 8901715723925099,\\n 21888242871839275222246405745257275088548364400416034343698203098124042812559,\\n 21888242871839275222246405745257275088548364400416034343698200215091693880034,\\n ]);\\n let poly2 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698200314078269634250,\\n 21888242871839275222246405745257275088548364400416034343698200967285641915872,\\n 2909990636858607,\\n 7896103832076587,\\n 2078397209533893,\\n 21888242871839275222246405745257275088548364400416034343698199792421452734531,\\n 614400389245817,\\n 8290314119277588,\\n ]);\\n let poly3 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698201373175279892906,\\n 21888242871839275222246405745257275088548364400416034343698201087241869723721,\\n 6768789983786188,\\n 635797784303388,\\n 7610153424227556,\\n 4633893206538324,\\n 2016269760615332,\\n 21888242871839275222246405745257275088548364400416034343698201007080554428142,\\n ]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 54>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n\\n // For the first index of result operation goes like this,\\n\\n // First four index of poly1\\n // 1791218451968394,\\n // 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n // 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n // 5430119342984413,\\n\\n // base + 1791218451968394 = 0x1065d1a8b8b718a\\n // base - 5921327228407753 = 0xeaf69591f3b037 (negative coefficient shifted)\\n // base - 3644467483862151 = 0xf30d604a3a9b79 (negative coefficient shifted)\\n // base + 5430119342984413 = 0x1134aaa2e86ccdd\\n assert(result[0] == 0x1065d1a8b8b718a0eaf69591f3b0370f30d604a3a9b791134aaa2e86ccdd);\\n assert(result[1] == 0x1028105ab1b789411fa010339db66b0fc220f1326bc8e0f1e3f4cc1e02e1);\\n assert(result[2] == 0x0f23dfbe7cd76c90f4901299312ddf10a569efe35acef11c0d76f005412b);\\n assert(result[3] == 0x107624a8f605dc50f0638a368960421022ecb3cf36b7911d73ff2c27ec14);\\n assert(result[4] == 0x0f6013a24e1b9a90f4fd2c158a08481180c2dba8af4cc10242413515171c);\\n assert(result[5] == 0x11b0964eb898ce411076805680b85410729c962da53a40f4b44412d0f6ed);\\n}\\n\\n#[test]\\nfn test_flatten_small() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([712345, 104857, 999999, 500001, 123, 654321, 77]);\\n let poly2 = Polynomial::new([1, 524287, 888888, 23456, 34567, 765432, 0]);\\n let poly3 = Polynomial::new([444444, 333333, 222222, 111111, 987654, 246810, 13579]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 20>(inputs, polynomials);\\n\\n assert(result[0] == 0x1ade991199991f423f17a12110007b19fbf110004d100000100000100000);\\n assert(result[1] == 0x10000117ffff1d9038105ba01087071badf8100000100000100000100000);\\n assert(result[2] == 0x16c81c15161513640e11b2071f120613c41a10350b100000100000100000);\\n}\\n\\n#[test]\\nfn test_safe_hashing_with_safe_helper() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let digests1 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests1.len() == 1);\\n assert(digests1[0] != 0);\\n\\n // Test determinism\\n let digests2 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests2.len() == 1);\\n assert(digests2[0] != 0);\\n assert(digests2[0] == digests1[0]);\\n}\\n\\n#[test]\\nfn test_pack() {\\n // Test pack function directly with small values\\n let values = [1, 2, 3, 4];\\n let packed = pack::<4, 4>(values);\\n\\n // With BIT=4, nibble_bits=4, group should be floor(254/(4+4)) = 31\\n // So all 4 values should fit in one carrier\\n assert(packed.len() >= 1);\\n\\n // Test with negative values\\n let values_neg = [-1, 2, -3, 4];\\n let packed_neg = pack::<4, 4>(values_neg);\\n assert(packed_neg.len() >= 1);\\n}\\n\\n#[test]\\nfn test_pack_single_value() {\\n // Test packing a single value\\n let values = [42];\\n let packed = pack::<1, 8>(values);\\n assert(packed.len() == 1);\\n assert(packed[0] != 0);\\n}\\n\\n#[test]\\nfn test_pack_determinism() {\\n // Test that packing is deterministic\\n let values = [10, 20, 30];\\n let packed1 = pack::<3, 8>(values);\\n let packed2 = pack::<3, 8>(values);\\n\\n assert(packed1.len() == packed2.len());\\n for i in 0..packed1.len() {\\n assert(packed1[i] == packed2[i]);\\n }\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/helpers.nr\",\"function_locations\":[{\"start\":1374,\"name\":\"packing_layout\"},{\"start\":2905,\"name\":\"flatten\"},{\"start\":4755,\"name\":\"pack\"},{\"start\":7016,\"name\":\"compute_safe\"},{\"start\":7214,\"name\":\"test_flatten\"},{\"start\":8157,\"name\":\"test_flatten_big\"},{\"start\":11058,\"name\":\"test_flatten_small\"},{\"start\":11885,\"name\":\"test_safe_hashing_with_safe_helper\"},{\"start\":12731,\"name\":\"test_pack\"},{\"start\":13201,\"name\":\"test_pack_single_value\"},{\"start\":13397,\"name\":\"test_pack_determinism\"}]},\"97\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse keccak256::keccak256;\\nuse poseidon::poseidon2_permutation;\\n\\n/// SAFE (Sponge API for Field Elements)\\n///\\n/// This module provides a complete implementation of the SAFE API in Noir as defined in:\\n/// \\\"SAFE (Sponge API for Field Elements) - A Toolbox for ZK Hash Applications\\\"\\n/// see https://hackmd.io/bHgsH6mMStCVibM_wYvb2w#22-Sponge-state for more details.\\n///\\n/// SAFE provides a unified interface for cryptographic sponge functions that can be\\n/// instantiated with various permutations to create hash functions, MACs, authenticated\\n/// encryption schemes, and other cryptographic primitives for ZK proof systems.\\n///\\n/// This implementation follows the SAFE specification exactly, providing:\\n/// - Complete API: START, ABSORB, SQUEEZE, FINISH operations.\\n/// - Full security: Domain separation, tag computation, IO pattern validation.\\n/// - Poseidon2 integration: Field-friendly permutation for ZK systems.\\n/// - Specification compliance: All operations follow SAFE spec 2.4 exactly.\\n/// - Natural API design: Variable-length inputs, automatic length detection from IO patterns.\\n///\\n/// # API Design\\n///\\n/// The API is designed for natural usage while maintaining type safety:\\n/// - `absorb(input: [Field])`: Accepts variable-length arrays, no padding required.\\n/// - `squeeze()`: Returns a vector with field element(s).\\n/// - IO patterns automatically determine operation lengths for validation.\\n\\n/// Rate parameter for the sponge construction (number of field elements that can be absorbed per permutation call).\\nglobal RATE: u32 = 3;\\n\\n/// Capacity parameter for the sponge construction (security parameter, typically 1-2 field elements).\\nglobal CAPACITY: u32 = 1;\\n\\n/// Total state size (rate + capacity) in field elements.\\nglobal STATE_SIZE: u32 = RATE + CAPACITY;\\n\\n/// IO Pattern encoding constants (from SAFE spec 2.3).\\n///\\n/// These constants are used for encoding operation types in the 32-bit word format:\\n/// - MSB set to 1 for ABSORB operations\\n/// - MSB set to 0 for SQUEEZE operations\\n\\n/// Flag for ABSORB operations (MSB = 1)\\nglobal ABSORB_FLAG: u32 = 0x80000000;\\n\\n/// Flag for SQUEEZE operations (MSB = 0)\\nglobal SQUEEZE_FLAG: u32 = 0x00000000;\\n\\n/// SAFE Sponge State (following spec 2.2)\\n///\\n/// The sponge state consists of the permutation state, tag, position counters,\\n/// and IO pattern tracking as defined in the SAFE specification.\\n///\\n/// # Generic Parameters\\n/// - `L`: The length of the IO pattern array\\n///\\n/// # Fields\\n/// - `state`: Permutation state V in F^n (rate + capacity elements)\\n/// - `tag`: Parameter tag T used for instance differentiation\\n/// - `absorb_pos`: Current absorb position (<= n-c)\\n/// - `squeeze_pos`: Current squeeze position (<= n-c)\\n/// - `io_pattern`: Expected IO pattern for validation (encoded 32-bit words)\\n/// - `io_count`: Current operation count for pattern tracking\\npub struct SafeSponge<let L: u32> {\\n /// Permutation state V in F^n (rate + capacity elements).\\n state: [Field; STATE_SIZE],\\n /// Parameter tag T used for instance differentiation.\\n tag: Field,\\n /// Current absorb position (<= n-c).\\n absorb_pos: u32,\\n /// Current squeeze position (<= n-c).\\n squeeze_pos: u32,\\n /// Expected IO pattern for validation.\\n io_pattern: [u32; L],\\n /// Current operation count for pattern tracking (spec 2.4: io_count).\\n io_count: u32,\\n}\\n\\nimpl<let L: u32> SafeSponge<L> {\\n /// Initializes a new SAFE sponge instance with the given IO pattern and domain separator (following spec 2.4).\\n ///\\n /// # Arguments\\n /// - `io_pattern`: Array of 32-bit encoded operations defining the expected sequence of ABSORB/SQUEEZE calls.\\n /// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n /// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n ///\\n /// # Returns\\n /// A new `SafeSponge` instance with initialized state\\n pub fn start(io_pattern: [u32; L], domain_separator: [u8; 64]) -> SafeSponge<L> {\\n // Compute tag from IO pattern and domain separator (spec 2.3).\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n let mut state = [0; STATE_SIZE];\\n // Initialize capacity with tag (spec 2.4).\\n // Add T to the first 128 bits of the state.\\n state[0] = tag;\\n\\n SafeSponge { state, tag, absorb_pos: 0, squeeze_pos: 0, io_pattern, io_count: 0 }\\n }\\n\\n /// Absorbs field elements into the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to absorb is automatically validated against the IO pattern.\\n /// This method accepts variable-length arrays, making it natural to use without padding.\\n ///\\n /// # Arguments\\n /// - `input`: Array of field elements to absorb (variable length, must match IO pattern)\\n pub fn absorb(&mut self, input: [Field]) {\\n let length = input.len() as u32;\\n\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_absorb = (expected_encoded_word & ABSORB_FLAG) != 0;\\n let expected_length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type and length\\n assert(is_expected_absorb, \\\"Expected ABSORB operation\\\");\\n assert(expected_length == length, \\\"Length mismatch\\\");\\n\\n // Process each element naturally (no unnecessary iterations).\\n for i in 0..length {\\n // If absorb_pos == (n-c) then permute and reset (spec 2.4).\\n if self.absorb_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.absorb_pos = 0;\\n }\\n\\n // Add X[i] to state at absorb_pos (spec 2.4).\\n // Note: absorb_pos is the rate position, not capacity position.\\n self.state[self.absorb_pos + CAPACITY] =\\n self.state[self.absorb_pos + CAPACITY] + input[i];\\n self.absorb_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = ABSORB_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n\\n // Force permute at start of next SQUEEZE (spec 2.4).\\n self.squeeze_pos = RATE;\\n }\\n\\n /// Extracts field elements from the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to squeeze is automatically determined from the IO pattern.\\n pub fn squeeze(&mut self) -> [Field] {\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_squeeze = (expected_encoded_word & ABSORB_FLAG) == 0;\\n let length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type\\n assert(is_expected_squeeze, \\\"Expected SQUEEZE operation\\\");\\n\\n let mut output: [Field] = [].as_vector();\\n\\n // SQUEEZE implementation following spec 2.4.\\n // If length==0, loop won't execute (spec 2.4).\\n for _ in 0..length {\\n // If squeeze_pos==(n-c) then permute and reset (spec 2.4).\\n if self.squeeze_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.squeeze_pos = 0;\\n self.absorb_pos = 0;\\n }\\n // Set Y[i] to state element at squeeze_pos (spec 2.4).\\n output = output.push_back(self.state[self.squeeze_pos + CAPACITY]);\\n self.squeeze_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = SQUEEZE_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n output\\n }\\n\\n /// Finalizes the sponge instance, verifying that all expected operations have been performed and clearing the internal state for security (following spec 2.4).\\n ///\\n /// This function is used to ensure that the sponge instance has been used correctly and to prevent information leakage.\\n pub fn finish(&mut self) {\\n // Check that io_count equals the length of the IO pattern expected (spec 2.4).\\n assert(self.io_count == L, \\\"IO pattern not completed\\\");\\n\\n // Erase the state and its variables (spec 2.4).\\n self.state = [0; STATE_SIZE];\\n self.absorb_pos = 0;\\n self.squeeze_pos = 0;\\n self.io_count = 0;\\n }\\n\\n /// Permute the state using Poseidon2 (following spec 2.4).\\n ///\\n /// Applies the Poseidon2 permutation to the current state.\\n /// This is the core cryptographic primitive of the sponge construction.\\n ///\\n /// # Returns\\n /// New state after permutation\\n fn permute(self) -> [Field; STATE_SIZE] {\\n poseidon2_permutation(self.state)\\n }\\n}\\n\\n/// Computes a unique tag for a sponge instance based on its IO pattern and domain separator.\\n/// The tag is used to ensure that distinct instances behave like distinct functions.\\n///\\n/// # Arguments\\n/// - `io_pattern`: Array of 32-bit encoded operations defining the sponge's usage pattern.\\n/// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n/// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n///\\n/// # Returns\\n/// A field element representing the 128-bit tag.\\npub fn compute_tag<let L: u32>(io_pattern: [u32; L], domain_separator: [u8; 64]) -> Field {\\n // Step 1: Parse and aggregate consecutive operations of the same type\\n let mut encoded_words = [0; L]; // Support up to L operations.\\n let mut word_count = 0;\\n let mut current_absorb_sum = 0;\\n let mut current_squeeze_sum = 0;\\n let mut last_was_absorb = false;\\n\\n for i in 0..L {\\n if io_pattern[i] > 0 {\\n // Parse operation type from MSB and length from lower 31 bits\\n let is_absorb = (io_pattern[i] & ABSORB_FLAG) != 0;\\n let length = io_pattern[i] & 0x7FFFFFFF; // Clear MSB to get length\\n\\n if is_absorb {\\n if last_was_absorb {\\n // Aggregate consecutive ABSORB operations\\n current_absorb_sum += length;\\n } else {\\n // Start new ABSORB sequence\\n if current_squeeze_sum > 0 {\\n // Flush previous SQUEEZE sequence\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n current_squeeze_sum = 0;\\n }\\n current_absorb_sum = length;\\n }\\n last_was_absorb = true;\\n } else {\\n if !last_was_absorb {\\n // Aggregate consecutive SQUEEZE operations\\n current_squeeze_sum += length;\\n } else {\\n // Start new SQUEEZE sequence\\n if current_absorb_sum > 0 {\\n // Flush previous ABSORB sequence\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n current_absorb_sum = 0;\\n }\\n current_squeeze_sum = length;\\n }\\n last_was_absorb = false;\\n }\\n }\\n }\\n\\n // Flush remaining operations\\n if current_absorb_sum > 0 {\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n }\\n if current_squeeze_sum > 0 {\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n }\\n\\n // Step 2: Serialize to byte string and append domain separator (following SAFE spec 2.3).\\n // Buffer is 256 bytes: max 192 bytes for IO pattern (48 words) + 64 bytes for domain separator.\\n // Note: We must use a fixed-size array because Noir's keccak256 requires [u8; N], not [u8].\\n let max_io_pattern_bytes: u32 = 192; // 256 - 64 (domain separator)\\n let io_pattern_bytes = word_count * 4;\\n assert(\\n io_pattern_bytes <= max_io_pattern_bytes,\\n \\\"IO pattern too large: max 48 aggregated words supported\\\",\\n );\\n\\n let mut input_bytes = [0u8; 256];\\n let mut byte_count: u32 = 0;\\n\\n // Serialize encoded words to bytes (big-endian as per SAFE spec).\\n // Note: Noir requires compile-time loop bounds, so we iterate over L (the array size)\\n // instead of word_count (runtime value). The condition `i < word_count` ensures we only\\n // process valid encoded words. This is safe because word_count <= L always holds\\n // (we can have at most L encoded words from L input operations).\\n for i in 0..L {\\n if i < word_count {\\n let word = encoded_words[i];\\n input_bytes[byte_count] = (word >> 24) as u8;\\n input_bytes[byte_count + 1] = (word >> 16) as u8;\\n input_bytes[byte_count + 2] = (word >> 8) as u8;\\n input_bytes[byte_count + 3] = word as u8;\\n byte_count += 4;\\n }\\n }\\n\\n // Append full 64-byte domain separator.\\n for i in 0..64 {\\n input_bytes[byte_count] = domain_separator[i];\\n byte_count += 1;\\n }\\n\\n // Step 3: Hash with Keccak-256 and truncate to 128 bits.\\n // Note: The SAFE spec uses SHA3-256, but we use Keccak-256 for Noir compatibility.\\n // Keccak-256 differs from SHA3-256 in padding, but both provide equivalent security.\\n let hash_bytes = keccak256(input_bytes, byte_count);\\n\\n // Convert first 128 bits (16 bytes) to field element.\\n let mut tag_value: Field = 0;\\n for i in 0..16 {\\n tag_value = tag_value * 256 + (hash_bytes[i] as Field);\\n }\\n\\n tag_value\\n}\\n\\n#[test]\\nfn test_safe_hashing() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_merkle_node() {\\n // Verifies SAFE can be used for Merkle tree node hashing with pattern ABSORB(1) + ABSORB(1) + SQUEEZE(1).\\n // Tests the ability to absorb multiple inputs before squeezing output.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let left = [123].as_vector();\\n let right = [456].as_vector();\\n\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(left);\\n sponge.absorb(right);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(left);\\n sponge2.absorb(right);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_commitment_scheme() {\\n // Verifies SAFE can be used for commitment schemes with pattern ABSORB(3) + SQUEEZE(1).\\n // Tests the ability to create deterministic commitments from multiple field elements.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let values = [10, 20, 30].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(values);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(values);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_domain_separation() {\\n // Verifies that different domain separators produce different outputs for the same input.\\n // This is crucial for cross-protocol security and preventing collisions between different applications.\\n let elements = [1, 2, 3].as_vector();\\n let domain1 = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let domain2 = [\\n 0x41, 0x42, 0x43, 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n\\n let mut sponge1 = SafeSponge::start(io_pattern, domain1);\\n sponge1.absorb(elements);\\n let output1 = sponge1.squeeze();\\n sponge1.finish();\\n\\n let mut sponge2 = SafeSponge::start(io_pattern, domain2);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output1.len() == 1);\\n assert(output2.len() == 1);\\n assert(output1[0] != output2[0]); // Different domain separators should produce different outputs\\n}\\n\\n#[test]\\nfn test_multiple_squeeze() {\\n // Verifies that multiple field elements can be squeezed in a single operation.\\n // Tests pattern ABSORB(3) + SQUEEZE(2) to ensure proper state management.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(2)\\n let io_pattern = [0x80000003, 0x00000002];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 2);\\n assert(output[0] != 0);\\n assert(output[1] != 0);\\n assert(output[0] != output[1]); // Different squeeze outputs should be different\\n}\\n\\n#[test]\\nfn test_zero_length_operations() {\\n // Verifies that zero-length ABSORB and SQUEEZE operations are handled correctly.\\n // Tests pattern ABSORB(0) + SQUEEZE(1) to ensure proper state transitions.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(0), SQUEEZE(1)\\n let io_pattern = [0x80000000, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb([].as_vector());\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n}\\n\\n#[test]\\nfn test_tag_computation() {\\n // Verifies the tag computation algorithm using the example from the SAFE specification.\\n // Pattern: ABSORB(3), ABSORB(3), SQUEEZE(3)\\n // Should aggregate to: ABSORB(6), SQUEEZE(3)\\n // Encoded as: [0x80000006, 0x00000003]\\n // Tests determinism and pattern differentiation.\\n\\n let io_pattern = [0x80000003, 0x80000003, 0x00000003];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test determinism\\n let tag2 = compute_tag(io_pattern, domain_separator);\\n assert(tag == tag2);\\n\\n // Test that different patterns produce different tags\\n let io_pattern2 = [0x80000003, 0x00000003]; // ABSORB(3), SQUEEZE(3) - different pattern\\n let tag3 = compute_tag(io_pattern2, domain_separator);\\n assert(tag != tag3);\\n}\\n\\n#[test]\\nfn test_tag_computation_debug() {\\n println(\\\"=== SAFE Tag Computation Debug Test ===\\\");\\n\\n // Test your specific pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\n let io_pattern = [0x80000002, 0x00000002, 0x80000002];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n println(f\\\"Testing pattern: {io_pattern}\\\");\\n println(\\n f\\\"Expected to aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(2)\\\",\\n );\\n println(\\n f\\\"Expected encoded words: [0x80000002, 0x00000002, 0x80000002]\\\",\\n );\\n println(\\\"\\\");\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n println(f\\\"=== Expected Rust Output ===\\\");\\n println(\\\"Pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\\");\\n println(\\\"Domain separator: 0x41424344...\\\");\\n println(\\\"Tag: 0xce3bb9ee4b2d41c42e9cdda38afe8b6a\\\");\\n println(\\\"\\\");\\n\\n println(f\\\"=== Noir Output ===\\\");\\n println(f\\\"Tag: {tag}\\\");\\n println(\\\"\\\");\\n\\n println(\\\"Compare the tag values above with Rust script!\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_absorb_aggregation() {\\n // Test that consecutive ABSORB operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1) should aggregate to ABSORB(2), SQUEEZE(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(1) = [0x80000002, 0x00000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(2), SQUEEZE(1)\\n let aggregated_pattern = [0x80000002, 0x00000001];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Consecutive ABSORB operations should aggregate to the same tag\\\");\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive ABSORB operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive ABSORB Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001] (ABSORB(1), ABSORB(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000002, 0x00000001] (ABSORB(2), SQUEEZE(1))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_squeeze_aggregation() {\\n // Test that consecutive SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1) should aggregate to ABSORB(1), SQUEEZE(2)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x00000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(1), SQUEEZE(2) = [0x80000001, 0x00000002]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(1), SQUEEZE(2)\\n let aggregated_pattern = [0x80000001, 0x00000002];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(\\n tag == aggregated_tag,\\n \\\"Consecutive SQUEEZE operations should aggregate to the same tag\\\",\\n );\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive SQUEEZE operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive SQUEEZE Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x00000001, 0x00000001] (ABSORB(1), SQUEEZE(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000001, 0x00000002] (ABSORB(1), SQUEEZE(2))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_mixed_consecutive_aggregation() {\\n // Test that both consecutive ABSORB and SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n // Should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1) = [0x80000002, 0x00000002, 0x80000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag\\n let aggregated_pattern = [0x80000002, 0x00000002, 0x80000001]; // ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Mixed consecutive operations should aggregate to the same tag\\\");\\n\\n println(\\\"=== Mixed Consecutive Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001]\\\",\\n );\\n println(\\n f\\\" (ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1))\\\",\\n );\\n println(f\\\"Aggregated pattern: [0x80000002, 0x00000002, 0x80000001]\\\");\\n println(f\\\" (ABSORB(2), SQUEEZE(2), ABSORB(1))\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n}\\n\\n#[test]\\nfn test_large_io_pattern() {\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Create pattern with 48 alternating ABSORB(1) and SQUEEZE(1) operations\\n // This is the maximum supported (48 words * 4 bytes = 192 bytes, leaving 64 for domain separator)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1; // ABSORB(1)\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1; // SQUEEZE(1)\\n }\\n }\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n assert(tag != 0);\\n}\\n\\n#[test]\\nfn test_domain_separator_not_truncated() {\\n // This test verifies that the domain separator is always included in the tag computation,\\n // even for large IO patterns. If the domain separator were truncated, different domain\\n // separators would produce the same tag for large patterns.\\n\\n let domain_separator_a = [\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41,\\n ]; // All 'A's\\n\\n let domain_separator_b = [\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42,\\n ]; // All 'B's\\n\\n // Create pattern with 48 alternating operations (max supported: 192 bytes of IO pattern)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1;\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1;\\n }\\n }\\n\\n let tag_a = compute_tag(io_pattern, domain_separator_a);\\n let tag_b = compute_tag(io_pattern, domain_separator_b);\\n\\n // Tags MUST be different because domain separators are different.\\n // If they were the same, it would mean the domain separator was truncated/ignored.\\n assert(tag_a != tag_b, \\\"Domain separator must affect tag even for large IO patterns\\\");\\n}\\n\",\"path\":\"/home/ace/main/gnosis/interfold/circuits/lib/src/math/safe.nr\",\"function_locations\":[{\"start\":4164,\"name\":\"SafeSponge<L>::start\"},{\"start\":5046,\"name\":\"SafeSponge<L>::absorb\"},{\"start\":6826,\"name\":\"SafeSponge<L>::squeeze\"},{\"start\":8494,\"name\":\"SafeSponge<L>::finish\"},{\"start\":9156,\"name\":\"SafeSponge<L>::permute\"},{\"start\":9830,\"name\":\"compute_tag\"},{\"start\":14128,\"name\":\"test_safe_hashing\"},{\"start\":15104,\"name\":\"test_merkle_node\"},{\"start\":16281,\"name\":\"test_commitment_scheme\"},{\"start\":17357,\"name\":\"test_domain_separation\"},{\"start\":18710,\"name\":\"test_multiple_squeeze\"},{\"start\":19639,\"name\":\"test_zero_length_operations\"},{\"start\":20415,\"name\":\"test_tag_computation\"},{\"start\":21477,\"name\":\"test_tag_computation_debug\"},{\"start\":22681,\"name\":\"test_consecutive_absorb_aggregation\"},{\"start\":24750,\"name\":\"test_consecutive_squeeze_aggregation\"},{\"start\":26760,\"name\":\"test_mixed_consecutive_aggregation\"},{\"start\":28520,\"name\":\"test_large_io_pattern\"},{\"start\":29333,\"name\":\"test_domain_separator_not_truncated\"}]}}}","{\"noir_version\":\"1.0.0-beta.26+40d6574f851d926f93e0c3a271bac3e6e82ac905\",\"hash\":\"2093582182953941705\",\"abi\":{\"parameters\":[{\"name\":\"ct0_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct0_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct0_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":4,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct0_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"},{\"name\":\"ct1_verification_key\",\"type\":{\"kind\":\"array\",\"length\":115,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct1_proof\",\"type\":{\"kind\":\"array\",\"length\":410,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct1_public_inputs\",\"type\":{\"kind\":\"array\",\"length\":3,\"type\":{\"kind\":\"field\"}},\"visibility\":\"private\"},{\"name\":\"ct1_key_hash\",\"type\":{\"kind\":\"field\"},\"visibility\":\"public\"}],\"return_type\":{\"abi_type\":{\"kind\":\"tuple\",\"fields\":[{\"kind\":\"field\"},{\"kind\":\"field\"},{\"kind\":\"field\"}]},\"visibility\":\"public\"},\"error_types\":{}},\"bytecode\":\"H4sIAAAAAAAA/52ZZbQc1JJGU1WNu7tr8OAOIbgGdwkhhEBIIIJbcCeCu7u7u3MKd4K7u9t8Mz/O2bPevIFHfu2sdW93J/eu7trfjpEjTr5w1179Bpwx7NqV+vfqvctKA/dadeiA3j169e8/7MYN+vQeOmhwvz36dO/bd1Cfvr2G9Bs44OTRXQYPu2TTfkMG9Bk8uEslq+SVolKn0hiVxqw0VqWxK41TadxK41Uav9IElSasNFGliStNUmnSSpNVmrzSFJWmrDRVpakrTVNp2krTVZq+0gyVZqw0U6WZK81SadZKs1WavdIcleasNFeluSt1rTRPpXkrzVdp/koLVFqw0kKVulVauNIilRattFilxSstUWnJSktVWrrSMpWWrbRcpeUrrVBpxUrdK61UqUellSutUmnVSqtVWr3SGpXWrLRWpbUrrVNp3UrrVepZaf1KG1TasNJGlTautEmlTSttVmnzSltU2rLSVpW2rrRNpW0rbVepV6XtK/WutEOlPpV2rNS30k6V+lXaudIulfpX2rXSgEoDK+1WafdKg0bb6fUv7a1oSKWhlfaotGelvSrtXWmfSvtW2q/S/pUOqHRgpXJQw2END254SMNDGx7W8PCGRzQ8suFRDY9ueEzDYxse1/D4hic0HN5wRMORDUc1PLHhSQ1PbnhKw1Mbntaw/ajKGQ3PbHhWw7MbntPw3IbnNTy/4QUNL2x4UcOLG17S8NKGlzW8vOEVDa9seFXDqxte0/Dahtc1vL7hDQ1vbHhTw5sb3tLw1oa3Nby94R0N72x4V8O7G97T8N6G9zW8v+EDDR9s+FDDhxs+0vDRho81fLzhEw1Lw2z4ZMOnGj7d8JmGzzZ8ruHzDV9o+GLDlxq+3PCVhq82fK3h6IavN3yj4ZsN32r4dsN3Gr7b8L2G7zf8oOGHDT9q+HHDTxp+2vCzhp83/KLhlw2/avh1w28aftvwu4bfN/yh4Y8Nf2r4c8NfGv7a8LeGvzf8o+GfFdO6gA3s4AB3wGOAxwSPBR4bPA54XPB44PHBE4AnBE8Enhg8CXhS8GTgycFTgKcETwWeGjwNeFrwdODpwTOAZwTPBJ4ZPAt4VvBs4NnBc4DnBM8FnhvcFTwPeF7wfOD5wQuAFwQvBO4GXhi8CHhR8GLgxcFLgJcELwVeGrwMeFnwcuDlwSuAVwR3B68E7gFeGbwKeFXwauDVwWuA1wSvBV4bvA54XfB64J7g9cEbgDcEbwTeGLwJeFPwZuDNwVuAtwRvBd4avA14W/B24F7g7cG9wTuA+4B3BPcF7wTuB94ZvAu4P3hX8ADwQPBu4N3Bg8CDwUPAQ8F7gPcE7wXeG7wPeF/wfuD9wQeADwQfBB4GPhh8CPhQ8GHgw8FHgI8EHwU+GnwM+FjwceDjwSeAh4NHgEeCR4FPBJ8EPhl8CvhU8Gng08FngM8EnwU+G3wO+FzweeDzwReALwRfBL4YfAn4UvBl4MvBV4CvBF8Fvhp8Dfha8HXg68E3gG8E3wS+GXwL+FbwbeDbwXeA7wTfBb4bfA/4XvB94PvBD4AfBD8Efhj8CPhR8GPgx8FPgAs4wU+CnwI/DX4G/Cz4OfDz4BfAL4JfAr8MfgX8Kvg18Gjw6+A3wG+C3wK/DX4H/C74PfD74A/AH4I/An8M/gT8Kfgz8OfgL8Bfgr8Cfw3+Bvwt+Dvw9+AfwD+CfwL/DP4F/Cv4N/Dv4D/AuP8d97/j/nfc/47733H/O+5/x/3vuP8d97/j/nfc/47738fHG7RDABwC4BAAhwD4JF2GXdpj4IDBQ3oNGPLgzF3+/z/2j0b7dJiFwywcZuEwC4dZOMzCYRYOs3CYhcMsHGbhMAuHWTjMwmEWDrNwmIXDLBxm4TALh1k4zMJhFg6zcJiFwywcZuEwC4dZOMzCYRYOs3CYhcMsHGbhMAuHWTjMwmEWDrNwmIXDLBxm4TALh1k4zMJhFg6zcJiFwywcZuEwC4dZOMzCYRYOs3CYhcMsHGbhMAuHWTjMwmEWDrNwmIXDLBxm4TALh1k4zMJhFg6zcJiFwywcZuEwC4dZOMzCYRYOs3CYhcMsHGbhMAuHWTjMwmEWDrNwmIXDLBxm4TALh1k4zMJhFg6zcJiF830JZuEwC4dZOMzCYRYOs3CYhcMsHGbhMAuHWTjMwmEWDrNwmIXDLPxQpol0yIVDLhxy4ZALh1w45MIhFw65cMiFQy4ccuGQC4dcOOTCIRfOzy7IhUMuHHLhkAuHXDj/HyAXDrlwyIVDLhxy4ZALh1w45MIhFw65cMiFQy4ccuGQC4dcOOTCIRcOuXDIhUMuHHLhkAuHXDjkwiEXDrlwyIVDLhxy4ZALh1w45MIhFw65cMiFQy4ccuGQC4dcOOTCIRcOuXDIhUMuHHLhkAuHXDjkwiEXDrlwyIVDLhxy4ZALh1w45MIhFw65cMiFQy4ccuGQC4dcOOTCIRcOuXDIhUMuHHLhkAuHXDjkwiEXDrlwyIVDLhxy4ZALh1w45MIhFw65cMiFQy4ccuGQC4dcOOTCIRcOuXDIhUMuHHLhkAuHXDjkwiEXDrlwyIVDLhxyEZCLgFwE5CIgFwG5CMhFQC4CchGQi4BcBOQiIBeBuBBwi4BbBNwi4BaBuBBQgIACBBQgoAABBQgoQEABAgoQUICAAgQUIKAAAQUIKEBAAQIKEFCAgAIEFCCgAAEFCChAQAECChBQgIACBBQgoAABBQgoQEABAgoQUICAAgQUIKAAAQUIKEBAAQIKEFCAgAIEFCCgAAEFCChAQAECChBQgIACBBQgoAABBQgoQEABAgoQUICAAgQUIKAAAQUIKEBAAQIKEFCAgAIEFCCgAAEFCChAQAECChBQgIACBBQgoAABBQgoQEABAgoQUICAAgQUIKAAAQUIKEBAAQIKEFCAgAIEFCCgAAEFCChAQAECChBQgIACBBQgoAABBQgoQEABAgoQUICAAgQUIKAAAQUIKEBAAQIKEFCAgAIE4kLg/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7P3D/B+7/wP0fuP8D93/g/g/c/4H7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7v4P7vzMjPoQ6EIAOBKADAejM+p+Fksu7Dx7cZ9CQLfoMGjhq+MiRf/0dyjL6qoV2WHfQ293O7Xprz1VuHjZss63nXuSj1fe+bbcRPd7+ftRX+jK9pr98qC7/+8lH/K2HnfNfH/b7737Y6Yg91/xxvA2vevzwa9fs9k8edq6/8Wr/j6bUc+DgPv12GDhg4Z59Bu06dMj/NKWROBU6LCwT/puf3lwnZmfu7HTNzjzZmfefvPr5/vXVHzDvG90X/3374VNO++izk03Z5b5/9OrZdSb4N7+H//3q58/OAtlZMDsL/YPfp85sf+vfuMB/+vv095589r/15F3/yZP/5cP6RH/rJc7x108+ujNLF/PojDHmWGOPM+54408w4UQTTzLpZJNPMeVUU08z7XTTzzDjTDPPMutss88x51xzd51n3vnmX2DBhbotvMiiiy2+xJJLLb3Mssstv8KK3VfqsfIqq662+hprrrX2Ouuu13P9DTbcaONNNt1s8y223Grrbbbdrtf2vXfos2PfnfrtvEv/XQcM3G33QYOHDN1jz7323mff/fY/4MByUBlWDi6HlEPLYeXwckQ5shxVji7HlGPLceX4ckIZXkaUkWVUObGcVE4up5RTy2nl9HJGObOcVc4u55Rzy3nl/HJBubBcVC4ul5RLy2Xl8nJFubJcVa4u15Rry3Xl+nJDubHcVG4ut5Rby23l9nJHubPcVe4u95R7y33l/vJAebA8VB4uj5RHy2Pl8fJEKSXLk+Wp8nR5pjxbnivPlxfKi+Wl8nJ5pbxaXiujy+vljfJmeau8Xd4p75b3yvvlg/Jh+ah8XD4pn5bPyufli/Jl+ap8Xb4p35bvyvflh/Jj+an8XH4pv5bfyu/lj/JnWpc0S/O0SOukjZE2ZtpYaWOnjZM2btp4aeOnTZA2YdpEaROnTZI2adpkaZOnTZE2ZdpUaVOnTZM2bdp0adOnzZA2Y9pMaTOnzZI2a9psabOnzZE2Z9pcaXOndU2bJ23etPnS5k9bIG3BtIXSuqUtnLZI2qJpi6UtnrZE2pJpS6UtnbZM2rJpy6Utn7ZC2opp3dNWSuuRtnLaKmmrpq2WtnraGmlrpq2VtnbaOmnrpq2X1jNt/bQN0jZM2yht47RN0jZN2yxt87Qt0rZM2ypt67Rt0rZN2y6tV9r2ab3Tdkjrk7ZjWt+0ndL6pe2ctkta/7Rd0wakDUzbLW33tEFpg9OGpA1N2yNtz7S90vZO2ydt37T90vZPOyDtwLSD0oalHZx2SNqhaYelHZ52RNqRaUelHZ12TNqxacelHZ92QtrwtBFpI9NGpZ2YdlLayWmnpJ2adlra6WlnpJ2Zdlba2WnnpJ2bdl7a+WkXpF2YdlHaxWmXpF2adlna5WlXpF2ZdlXa1WnXpF2bdl3a9Wk3pN2YdlPazWm3pN2adlva7Wl3pN2Zdlfa3Wn3pN2bdl/a/WkPpD2Y9lDaw2mPpD2a9lja42lPpJW0THsy7am0p9OeSXs27bm059NeSHsx7aW0l9NeSXs17bW00Wmvp72R9mbaW2lvp72T9m7ae2nvp32Q9mHaR2kfp32S9mnaZ2mfp32R9mXaV2lfp32T9m3ad2nfp/2Q9mPaT2k/p/2S9mvab2m/p/2R9me63tB0HXh6pHfSx0gfM32s9LHTx0kfN3289PH1QaJPQr316Y5InzR9svTJ06dInzJ9qvSp06dJnzZ9uvTp02dInzF9pvSZ02dJnzV9tvTZ0+dInzN9rvS507umz5M+b/p86fOnL5C+YPpC6d3SF05fJH3R9MXSF09fIn3J9KXSl05fRtlftV+RX21fSV8lXwFf3V65XpVecV5NXileBV7hXb1dmV11XVFdLV0JXeVcwVydXHlcVVwxXA1c6VvFW6FbfVtZWzVbEVvtWslapVqBWl1aOVoVWvFZzVmpWYVZYVk9WRlZ9VjRWK1YiVhlWEFYHVj5V9VXsVeNV2lXRVchV/1W2Va1VpFWbVZJViVWAVbdVblViVVlVUFVHVX5VNVUsVSNVGlURVQhVP1T2VO1M32U2qaSpkqmAqa6pXKlKqXipJqkUqQKpMKjeqMyo+qioqJaohKiyqGCoTqh8qCqoGKgGqDSn4qfQp/6nrKeap4intqdkp1KnQKdupxynCqc4puam1KbCpvCmnqaMprqmaKZWpkSmcqYgpg6mPKXqpdilxqX0paKlkKW+pWylWqVIpXalJKUSpQClLqTcpMqk+KSmpJSkgqSwpF6kTKR6pCikFqQEpDKj4KPOo/yjqqOYo4ajtKNio1CjfqMsoxqjCKM2ouSi0qLAou6inKKKoriiZqJUokKicKIeogyiOqHoodahxKHyoaChjqG8oWqhWKFGoXShIqEQoT6g7KDaoMig9qCkoJKggKCuoFygSqB4oCagFKACoCGf+39mvm17mvU15avCV/LvQZ77fSa57XKa4zXBq/pXYu7hnbt65rVtaZrRNd2rslcS7kGcu3imsO1gmv81uatqVsLt4Zt7dmasbVea7TWVq2JWsu0Bmnt0JqftTprbNbGrGlZi7KGZO3Hmo21Fmsk1jasSVhLsAZg7b6ae7XyatzVpqspVwuuhlvttZpptc5qlNUWqwlWy6sGV+2smle1qmpM1Yaq6VSLqYZS7aOaRbWGagTV9qnJU0unBk7tmpoztWJqvNRmqalSC6WGSe2RmiG1Pmp01NaoiVHLogZF7YiaD7UaaizURqhpUIughkDtf5r9tPZp5NO2p0lPS54GPO12muu00mmc0yanKU4LnIY37W2a2bSuaVTTlqYJTcuZBjPtZJrHtIppDNMGpulLi5eGLu1bmrW0ZmnE0nalyUpLlQYq7VKao7RCaXzS5qSpSQuThiXtSZqRtB5pNNJWpIlIy5AGIe1Amn+0+mjs0cajaUeLjoYc7TeabbTWaKTRNqNJRkuMBhjtLppbtLJoXNGmoilFC4qGE+0lmkm0jmgU0RaiCUTLhwYP7RyaN7RqaMzQhqHpQouFhgrtE5oltEZohND2oMlBS4MGBu0KmhO0Img80GagqUALgYYB7QGaAWT/kn65vhRfZi+hl8dL32XtknU5utRcRi4Rl39Lu2Xbkmy5tZRaJi2BljdLl2XJkmM5sVRYBizfkDDJKPVupe+ZdZSUQYe7DuPhw/8LMdY0z6g/AAA=\",\"debug_symbols\":\"tZbdioMwEIXfJddeZCb/+yrLUmybFkFUrC4spe++sW0SXUholb2aapwv5zjHkis52v143lXNqb2Qj88r2fdVXVfnXd0eyqFqG3f3eiuIv9wNvbXuFpmtu66u7G0zkI9mrOuCfJf1eH/o0pXNvQ5l71ZpQWxzdNUBT1Vtp1+3InbTdKtW+tkMlKrQL3ABgDQApEBPUIZFAlsQME1gLGhgXEIgIL5qAigwrwE4plzwzS7Ev7pAGVygZikXWYJWnsDS08wShIwEvYbAZCRouYqgQyb5Og2ch/fADSRTnQmlUsoPQ2keh6HVEsEyCGp8phRQERFmicjEUgI1T4QEHgdq3lABLBiZI/6qkBmE5MGIFDypQqURBkIqDBiTROjMB2bCB8YpxNcJ6nUjWsShGkypyCVLKD8QEDMfb2RTUvAEibCKIGn4r0p/H8g2pxv55nSj2JzurIrX0o1qc7pRb043ms3pzhrZnm7FREiWEItkfbmr8lD1iwMMoU55QcANsCDotioIc72u8EcRjyLdY25fNZXbtH9flfvaPs9Ap7E5zI5Ew0/nV/yhqevbgz2OvZ12v685Pb8=\",\"file_map\":{\"17\":{\"source\":\"// Exposed only for usage in `std::meta`\\npub(crate) mod poseidon2;\\n\\nuse crate::default::Default;\\nuse crate::embedded_curve_ops::{\\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\\n};\\nuse crate::meta::derive_via;\\nuse crate::static_assert;\\n\\n/// The size of the state accepted by the backend in `poseidon2_permutation`.\\nglobal POSEIDON2_CONFIG_STATE_SIZE: u32 = poseidon2_config_state_size();\\n\\n#[foreign(sha256_compression)]\\n// docs:start:sha256_compression\\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\\n// docs:end:sha256_compression\\n\\n#[foreign(keccakf1600)]\\n// docs:start:keccakf1600\\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\\n// docs:end:keccakf1600\\n\\n#[foreign(blake2s)]\\n// docs:start:blake2s\\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake2s\\n{}\\n\\n// docs:start:blake3\\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\\n// docs:end:blake3\\n{\\n if crate::runtime::is_unconstrained() {\\n // Temporary measure while Barretenberg is main proving system.\\n // Please open an issue if you're working on another proving system and running into problems due to this.\\n crate::static_assert(\\n N <= 1024,\\n \\\"Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes\\\",\\n );\\n }\\n __blake3(input)\\n}\\n\\n#[foreign(blake3)]\\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\\n\\n// docs:start:pedersen_commitment\\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\\n // docs:end:pedersen_commitment\\n pedersen_commitment_with_separator(input, 0)\\n}\\n\\n#[inline_always]\\npub fn pedersen_commitment_with_separator<let N: u32>(\\n input: [Field; N],\\n separator: u32,\\n) -> EmbeddedCurvePoint {\\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\\n for i in 0..N {\\n points[i] = EmbeddedCurveScalar::from_field(input[i]);\\n }\\n let generators = derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n multi_scalar_mul(generators, points)\\n}\\n\\n// docs:start:pedersen_hash\\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\\n// docs:end:pedersen_hash\\n{\\n pedersen_hash_with_separator(input, 0)\\n}\\n\\n#[no_predicates]\\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\\n let mut generators: [EmbeddedCurvePoint; N + 1] =\\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\\n crate::assert_constant(separator);\\n let domain_generators: [EmbeddedCurvePoint; N] =\\n derive_generators(\\\"DEFAULT_DOMAIN_SEPARATOR\\\".as_bytes(), separator);\\n\\n for i in 0..N {\\n scalars[i] = EmbeddedCurveScalar::from_field(input[i]);\\n generators[i] = domain_generators[i];\\n }\\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\\n\\n let length_generator: [EmbeddedCurvePoint; 1] =\\n derive_generators(\\\"pedersen_hash_length\\\".as_bytes(), 0);\\n generators[N] = length_generator[0];\\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\\n}\\n\\n#[field(bn254)]\\n#[inline_always]\\npub fn derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {\\n crate::assert_constant(domain_separator_bytes);\\n crate::assert_constant(starting_index);\\n __derive_generators(domain_separator_bytes, starting_index)\\n}\\n\\n#[builtin(derive_pedersen_generators)]\\n#[field(bn254)]\\nfn __derive_generators<let N: u32, let M: u32>(\\n domain_separator_bytes: [u8; M],\\n starting_index: u32,\\n) -> [EmbeddedCurvePoint; N] {}\\n\\npub fn poseidon2_permutation<let N: u32>(input: [Field; N]) -> [Field; N] {\\n static_assert(\\n N == POSEIDON2_CONFIG_STATE_SIZE,\\n f\\\"the input length must equal the state size in the Poseidon2 config; expected {POSEIDON2_CONFIG_STATE_SIZE}, got {N}\\\",\\n );\\n poseidon2_permutation_internal(input)\\n}\\n\\n#[foreign(poseidon2_permutation)]\\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\\n\\n#[foreign(poseidon2_config_state_size)]\\ncomptime fn poseidon2_config_state_size() -> u32 {}\\n\\n// Generic hashing support.\\n// Partially ported and impacted by rust.\\n\\n// Hash trait shall be implemented per type.\\n#[derive_via(derive_hash)]\\npub trait Hash {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher;\\n}\\n\\n// docs:start:derive_hash\\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\\n let name = quote { $crate::hash::Hash };\\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\\n let for_each_field = |name| quote { _self.$name.hash(_state); };\\n crate::meta::make_trait_impl(\\n s,\\n name,\\n signature,\\n for_each_field,\\n quote {},\\n |fields| fields,\\n )\\n}\\n// docs:end:derive_hash\\n\\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\\n// TODO: consider making the types generic here ([u8], [Field], etc.)\\npub trait Hasher {\\n fn finish(self) -> Field;\\n\\n /// Returns the hash value without consuming the hasher.\\n /// Override this for more efficient implementations that avoid copying.\\n /// TODO: deprecate finish() and replace it\\n fn finish_ref(&self) -> Field {\\n (*self).finish()\\n }\\n\\n fn write(&mut self, input: Field);\\n}\\n\\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\\npub trait BuildHasher {\\n type H: Hasher;\\n\\n fn build_hasher(self) -> H;\\n}\\n\\npub struct BuildHasherDefault<H>;\\n\\nimpl<H> BuildHasher for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n type H = H;\\n\\n fn build_hasher(_self: Self) -> H {\\n H::default()\\n }\\n}\\n\\nimpl<H> Default for BuildHasherDefault<H>\\nwhere\\n H: Hasher + Default,\\n{\\n fn default() -> Self {\\n BuildHasherDefault {}\\n }\\n}\\n\\nimpl Hash for Field {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self);\\n }\\n}\\n\\nimpl Hash for u8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for u128 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for i8 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u8 as Field);\\n }\\n}\\n\\nimpl Hash for i16 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u16 as Field);\\n }\\n}\\n\\nimpl Hash for i32 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u32 as Field);\\n }\\n}\\n\\nimpl Hash for i64 {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as u64 as Field);\\n }\\n}\\n\\nimpl Hash for bool {\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n H::write(state, self as Field);\\n }\\n}\\n\\nimpl Hash for () {\\n fn hash<H>(_self: Self, _state: &mut H)\\n where\\n H: Hasher,\\n {}\\n}\\n\\nimpl<T, let N: u32> Hash for [T; N]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<T> Hash for [T]\\nwhere\\n T: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.len().hash(state);\\n for elem in self {\\n elem.hash(state);\\n }\\n }\\n}\\n\\nimpl<A> Hash for (A,)\\nwhere\\n A: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n }\\n}\\n\\nimpl<A, B> Hash for (A, B)\\nwhere\\n A: Hash,\\n B: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n }\\n}\\n\\nimpl<A, B, C> Hash for (A, B, C)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D> Hash for (A, B, C, D)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F> Hash for (A, B, C, D, E, F)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G> Hash for (A, B, C, D, E, F, G)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_> Hash for (A, B, C, D, E, F, G, H_)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I> Hash for (A, B, C, D, E, F, G, H_, I)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J> Hash for (A, B, C, D, E, F, G, H_, I, J)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K> Hash for (A, B, C, D, E, F, G, H_, I, J, K)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n }\\n}\\n\\nimpl<A, B, C, D, E, F, G, H_, I, J, K, L> Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)\\nwhere\\n A: Hash,\\n B: Hash,\\n C: Hash,\\n D: Hash,\\n E: Hash,\\n F: Hash,\\n G: Hash,\\n H_: Hash,\\n I: Hash,\\n J: Hash,\\n K: Hash,\\n L: Hash,\\n{\\n fn hash<H>(self, state: &mut H)\\n where\\n H: Hasher,\\n {\\n self.0.hash(state);\\n self.1.hash(state);\\n self.2.hash(state);\\n self.3.hash(state);\\n self.4.hash(state);\\n self.5.hash(state);\\n self.6.hash(state);\\n self.7.hash(state);\\n self.8.hash(state);\\n self.9.hash(state);\\n self.10.hash(state);\\n self.11.hash(state);\\n }\\n}\\n\\n// Some test vectors for Pedersen hash and Pedersen Commitment.\\n// They have been generated using the same functions so the tests are for now useless\\n// but they will be useful when we switch to Noir implementation.\\n#[test]\\nfn assert_pedersen() {\\n assert_eq(\\n pedersen_hash_with_separator([1], 1),\\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1], 1),\\n EmbeddedCurvePoint {\\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\\n },\\n );\\n\\n assert_eq(\\n pedersen_hash_with_separator([1, 2], 2),\\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2], 2),\\n EmbeddedCurvePoint {\\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3], 3),\\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3], 3),\\n EmbeddedCurvePoint {\\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\\n EmbeddedCurvePoint {\\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\\n EmbeddedCurvePoint {\\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\\n EmbeddedCurvePoint {\\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\\n EmbeddedCurvePoint {\\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\\n EmbeddedCurvePoint {\\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\\n EmbeddedCurvePoint {\\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\\n },\\n );\\n assert_eq(\\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\\n );\\n assert_eq(\\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\\n EmbeddedCurvePoint {\\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\\n },\\n );\\n}\\n\",\"path\":\"std/hash/mod.nr\",\"function_locations\":[{\"start\":572,\"name\":\"sha256_compression\"},{\"start\":707,\"name\":\"keccakf1600\"},{\"start\":852,\"name\":\"blake2s\"},{\"start\":950,\"name\":\"blake3\"},{\"start\":1437,\"name\":\"__blake3\"},{\"start\":1555,\"name\":\"pedersen_commitment\"},{\"start\":1784,\"name\":\"pedersen_commitment_with_separator\"},{\"start\":2188,\"name\":\"pedersen_hash\"},{\"start\":2345,\"name\":\"pedersen_hash_with_separator\"},{\"start\":3339,\"name\":\"derive_generators\"},{\"start\":3698,\"name\":\"__derive_generators\"},{\"start\":3776,\"name\":\"poseidon2_permutation\"},{\"start\":4132,\"name\":\"poseidon2_permutation_internal\"},{\"start\":4225,\"name\":\"poseidon2_config_state_size\"},{\"start\":4536,\"name\":\"derive_hash\"},{\"start\":5327,\"name\":\"Hasher::finish_ref\"},{\"start\":5761,\"name\":\"<impl BuildHasher for BuildHasherDefault<H>>::build_hasher\"},{\"start\":5893,\"name\":\"<impl Default for BuildHasherDefault<H>>::default\"},{\"start\":6025,\"name\":\"<impl Hash for Field>::hash\"},{\"start\":6155,\"name\":\"<impl Hash for u8>::hash\"},{\"start\":6295,\"name\":\"<impl Hash for u16>::hash\"},{\"start\":6435,\"name\":\"<impl Hash for u32>::hash\"},{\"start\":6575,\"name\":\"<impl Hash for u64>::hash\"},{\"start\":6716,\"name\":\"<impl Hash for u128>::hash\"},{\"start\":6855,\"name\":\"<impl Hash for i8>::hash\"},{\"start\":7001,\"name\":\"<impl Hash for i16>::hash\"},{\"start\":7148,\"name\":\"<impl Hash for i32>::hash\"},{\"start\":7295,\"name\":\"<impl Hash for i64>::hash\"},{\"start\":7443,\"name\":\"<impl Hash for bool>::hash\"},{\"start\":7590,\"name\":\"<impl Hash for ()>::hash\"},{\"start\":7722,\"name\":\"<impl Hash for [T; N]>::hash\"},{\"start\":7911,\"name\":\"<impl Hash for [T]>::hash\"},{\"start\":8133,\"name\":\"<impl Hash for (A,)>::hash\"},{\"start\":8302,\"name\":\"<impl Hash for (A, B)>::hash\"},{\"start\":8518,\"name\":\"<impl Hash for (A, B, C)>::hash\"},{\"start\":8781,\"name\":\"<impl Hash for (A, B, C, D)>::hash\"},{\"start\":9091,\"name\":\"<impl Hash for (A, B, C, D, E)>::hash\"},{\"start\":9448,\"name\":\"<impl Hash for (A, B, C, D, E, F)>::hash\"},{\"start\":9852,\"name\":\"<impl Hash for (A, B, C, D, E, F, G)>::hash\"},{\"start\":10306,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_)>::hash\"},{\"start\":10807,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I)>::hash\"},{\"start\":11355,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J)>::hash\"},{\"start\":11950,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K)>::hash\"},{\"start\":12593,\"name\":\"<impl Hash for (A, B, C, D, E, F, G, H_, I, J, K, L)>::hash\"},{\"start\":13187,\"name\":\"assert_pedersen\"}]},\"22\":{\"source\":\"pub mod hash;\\npub mod aes128;\\npub mod array;\\npub mod vector;\\npub mod ecdsa_secp256k1;\\npub mod ecdsa_secp256r1;\\npub mod embedded_curve_ops;\\npub mod field;\\npub mod collections;\\npub mod compat;\\npub mod convert;\\npub mod option;\\npub mod string;\\npub mod test;\\npub mod cmp;\\npub mod ops;\\npub mod default;\\npub mod prelude;\\npub mod runtime;\\npub mod meta;\\npub mod append;\\npub mod mem;\\npub mod panic;\\npub mod hint;\\n\\nmod integer;\\nmod primitive_docs;\\nmod internal;\\n\\n// Oracle calls are required to be wrapped in an unconstrained function\\n// Thus, the only argument to the `println` oracle is expected to always be an ident\\n#[oracle(print)]\\nunconstrained fn print_oracle<T>(with_newline: bool, input: T) {}\\n\\nunconstrained fn print_unconstrained<T>(with_newline: bool, input: T) {\\n print_oracle(with_newline, input);\\n}\\n\\n/// Print the given input to stdout followed by a newline\\npub fn println<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(true, input);\\n }\\n}\\n\\n/// Print the given input to stdout\\npub fn print<T>(input: T) {\\n // Safety: a print statement cannot be constrained\\n unsafe {\\n print_unconstrained(false, input);\\n }\\n}\\n\\n/// Asserts the validity of the provided proof and public inputs against the provided verification key and hash.\\n///\\n/// The ACVM cannot determine whether the provided proof is valid during execution as this requires knowledge of\\n/// the backend against which the program is being proven. However if an invalid proof if submitted, the program may\\n/// fail to prove or the backend may generate a proof which will subsequently fail to verify.\\n///\\n/// # Important Note\\n///\\n/// If you are not developing your own backend such as [Barretenberg](https://github.com/AztecProtocol/barretenberg)\\n/// you probably shouldn't need to interact with this function directly. It's easier and safer to use a verification\\n/// library which is published by the developers of the backend which will document or enforce any safety requirements.\\n///\\n/// If you use this directly, you're liable to introduce underconstrainedness bugs and *your circuit will be insecure*.\\n///\\n/// # Arguments\\n/// - verification_key: The verification key of the circuit to be verified.\\n/// - proof: The proof to be verified.\\n/// - public_inputs: The public inputs associated with `proof`\\n/// - key_hash: The hash of `verification_key` of the form expected by the backend.\\n/// - proof_type: An identifier for the proving scheme used to generate the proof to be verified. This allows\\n/// for a single backend to support verifying multiple proving schemes.\\n///\\n/// # Constraining `key_hash`\\n///\\n/// The Noir compiler does not by itself constrain that `key_hash` is a valid hash of `verification_key`.\\n/// This is because different backends may differ in how they hash their verification keys.\\n/// It is then the responsibility of either the noir developer (by explicitly hashing the verification key\\n/// in the correct manner) or by the proving system itself internally asserting the correctness of `key_hash`.\\npub fn verify_proof_with_type<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {\\n if !crate::runtime::is_unconstrained() {\\n crate::assert_constant(proof_type);\\n }\\n verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type);\\n}\\n\\n#[foreign(recursive_aggregation)]\\nfn verify_proof_internal<let N: u32, let M: u32, let K: u32>(\\n verification_key: [Field; N],\\n proof: [Field; M],\\n public_inputs: [Field; K],\\n key_hash: Field,\\n proof_type: u32,\\n) {}\\n\\n/// Asserts that the given value is known at compile-time.\\n/// Useful for debugging for-loop bounds.\\n#[builtin(assert_constant)]\\npub fn assert_constant<T>(x: T) {}\\n\\n/// Asserts that the given value is both true and known at compile-time.\\n/// The message can be a string, a format string, or any value, as long as it is known at compile-time\\n#[builtin(static_assert)]\\npub fn static_assert<T>(predicate: bool, message: T) {}\\n\\n/// Force a field value to be a witness instead of a constant in the compiled output.\\n/// This is often only useful for debugging compiler optimizations.\\n///\\n/// This has no effect in unconstrained or comptime code.\\n#[builtin(as_witness)]\\npub fn as_witness(x: Field) {}\\n\",\"path\":\"std/lib.nr\",\"function_locations\":[{\"start\":689,\"name\":\"print_oracle\"},{\"start\":763,\"name\":\"print_unconstrained\"},{\"start\":893,\"name\":\"println\"},{\"start\":1076,\"name\":\"print\"},{\"start\":3277,\"name\":\"verify_proof_with_type\"},{\"start\":3694,\"name\":\"verify_proof_internal\"},{\"start\":3859,\"name\":\"assert_constant\"},{\"start\":4118,\"name\":\"static_assert\"},{\"start\":4389,\"name\":\"as_witness\"}]},\"52\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse bb_proof_verification::{UltraHonkProof, UltraHonkVerificationKey, verify_honk_proof_non_zk};\\nuse lib::math::commitments::{compute_commitment, DS_CIPHERTEXT, DS_PK_AGGREGATION};\\n\\nfn main(\\n // P3: ct0 inner proof.\\n ct0_verification_key: UltraHonkVerificationKey,\\n ct0_proof: UltraHonkProof,\\n ct0_public_inputs: [Field; 4], // pk0_commitment, ct0_commitment, k1_commitment, u_commitment\\n ct0_key_hash: pub Field,\\n // P3: ct1 inner proof.\\n ct1_verification_key: UltraHonkVerificationKey,\\n ct1_proof: UltraHonkProof,\\n ct1_public_inputs: [Field; 3], // pk1_commitment, ct1_commitment, u_commitment\\n ct1_key_hash: pub Field,\\n) -> pub (Field, Field, Field) {\\n verify_honk_proof_non_zk(\\n ct0_verification_key,\\n ct0_proof,\\n ct0_public_inputs,\\n ct0_key_hash,\\n );\\n verify_honk_proof_non_zk(\\n ct1_verification_key,\\n ct1_proof,\\n ct1_public_inputs,\\n ct1_key_hash,\\n );\\n\\n // Verify that the u_commitment from the ct0 proof is the same as the u_commitment from the ct1 proof.\\n assert(ct0_public_inputs[3] == ct1_public_inputs[2]);\\n\\n // Compute the ct commitment.\\n let ct_inputs = [ct0_public_inputs[1], ct1_public_inputs[1]].as_vector();\\n let ct_commitment = compute_commitment(ct_inputs, DS_CIPHERTEXT);\\n\\n // Threshold PK aggregation commitment (pk0 and pk1 limbs).\\n let pk_inputs = [ct0_public_inputs[0], ct1_public_inputs[0]].as_vector();\\n let pk_commitment = compute_commitment(pk_inputs, DS_PK_AGGREGATION);\\n\\n let k1_commitment = ct0_public_inputs[2];\\n\\n (pk_commitment, ct_commitment, k1_commitment)\\n}\\n\",\"path\":\"interfold/circuits/bin/threshold/user_data_encryption/src/main.nr\",\"function_locations\":[{\"start\":872,\"name\":\"main\"}]},\"53\":{\"source\":\"// Constants for UltraHonk recursive verifier inputs\\npub global PROOF_TYPE_HONK: u32 = 0; // identifier for UltraHonk verfier\\npub global RECURSIVE_PROOF_LENGTH: u32 = 410;\\npub global ULTRA_VK_LENGTH_IN_FIELDS: u32 = 115;\\n\\npub type UltraHonkProof = [Field; RECURSIVE_PROOF_LENGTH];\\npub type UltraHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\n// Constants for Rollup-UltraHonk recursive verifier inputs (N.B. this is equivalent to UH plus IPA claim and proof)\\npub global PROOF_TYPE_ROLLUP_HONK: u32 = 4; // identifier for rollup-UltraHonk verfier\\npub global PROOF_TYPE_ROOT_ROLLUP_HONK: u32 = 5; // identifier for root-rollup-UltraHonk verfier (closes the IPA accumulator)\\npub global IPA_CLAIM_SIZE: u32 = 6;\\npub global IPA_PROOF_LENGTH: u32 = 64;\\npub global RECURSIVE_ROLLUP_HONK_PROOF_LENGTH: u32 =\\n RECURSIVE_PROOF_LENGTH + IPA_CLAIM_SIZE + IPA_PROOF_LENGTH;\\n\\npub type RollupHonkProof = [Field; RECURSIVE_ROLLUP_HONK_PROOF_LENGTH];\\npub type RollupHonkVerificationKey = [Field; ULTRA_VK_LENGTH_IN_FIELDS];\\n\\npub global PROOF_TYPE_HONK_ZK: u32 = 6; // identifier for UltraHonk ZK verfier\\npub global RECURSIVE_ZK_PROOF_LENGTH: u32 = 450 + 8;\\n\\npub type UltraHonkZKProof = [Field; RECURSIVE_ZK_PROOF_LENGTH];\\n\\n// Verifies a non-zero-knowledge UltraHonk proof.\\n//\\n// Represents standard UltraHonk recursive verification for proofs that do not hide the witness.\\n// Use this only in situations where zero-knowledge is not required.\\npub fn verify_honk_proof_non_zk<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof with IPA (Inner Product Argument).\\n//\\n// This variant includes an IPA claim and proof appended to the standard UltraHonk proof,\\n// used to amortize IPA recursive verification costs in rollup circuits.\\npub fn verify_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a non-zero-knowledge Rollup UltraHonk proof and closes the IPA accumulator in-circuit.\\n//\\n// Use this at the root of a rollup aggregation tree. The inner proof has the same RollupHonk shape\\n// as `verify_rolluphonk_proof`, but instead of propagating an accumulated IPA claim out as a public\\n// input, this variant performs a full native IPA verification inside the circuit. The outer circuit\\n// should therefore be proved as a standard (non-rollup) UltraHonk circuit, producing a proof\\n// suitable for verification by `verify_honk_proof` / `verify_honk_proof_non_zk`.\\n//\\n// When two RollupHonk inputs are verified this way in one circuit, their two IPA claims are first\\n// accumulated into one, then the accumulated claim is fully verified.\\npub fn verify_root_rolluphonk_proof<let N: u32>(\\n verification_key: RollupHonkVerificationKey,\\n proof: RollupHonkProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_ROOT_ROLLUP_HONK,\\n );\\n}\\n\\n// Verifies a zero-knowledge UltraHonk proof.\\n//\\n// This verifier is for UltraHonk proofs constructed with zero-knowledge, which hide the witness\\n// values from the verifier.\\n// Note: We intentionally choose the generic name \\\"verify_honk_proof\\\" for this function, as we\\n// want ZK to be the default unless the user explicitly opts out.\\npub fn verify_honk_proof<let N: u32>(\\n verification_key: UltraHonkVerificationKey,\\n proof: UltraHonkZKProof,\\n public_inputs: [Field; N],\\n key_hash: Field, // Hash of the verification key\\n) {\\n std::verify_proof_with_type(\\n verification_key,\\n proof,\\n public_inputs,\\n key_hash,\\n PROOF_TYPE_HONK_ZK,\\n );\\n}\\n\",\"path\":\"/home/ace/nargo/github.com/AztecProtocol/aztec-packages/v5.1.0/barretenberg/noir/bb_proof_verification/src/lib.nr\",\"function_locations\":[{\"start\":1646,\"name\":\"verify_honk_proof_non_zk\"},{\"start\":2262,\"name\":\"verify_rolluphonk_proof\"},{\"start\":3386,\"name\":\"verify_root_rolluphonk_proof\"},{\"start\":4087,\"name\":\"verify_honk_proof\"}]},\"87\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse crate::math::helpers::{compute_safe, flatten};\\nuse crate::math::polynomial::Polynomial;\\n\\n/// DOMAIN SEPARATORS\\n\\n// Domain separator - \\\"PK\\\"\\npub global DS_PK: [u8; 64] = [\\n 0x50, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_GENERATION\\\"\\npub global DS_PK_GENERATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_COMPUTATION\\\"\\npub global DS_SHARE_COMPUTATION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x55, 0x54, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"SHARE_ENCRYPTION\\\"\\npub global DS_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"PK_AGGREGATION\\\"\\npub global DS_PK_AGGREGATION: [u8; 64] = [\\n 0x50, 0x4b, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CIPHERTEXT\\\"\\npub global DS_CIPHERTEXT: [u8; 64] = [\\n 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"AGGREGATED_SHARES\\\"\\npub global DS_AGGREGATED_SHARES: [u8; 64] = [\\n 0x41, 0x47, 0x47, 0x52, 0x45, 0x47, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45,\\n 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"VK_HASH\\\"\\npub global DS_VK_HASH: [u8; 64] = [\\n 0x56, 0x4b, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"RECURSIVE_AGGREGATION\\\"\\npub global DS_RECURSIVE_AGGREGATION: [u8; 64] = [\\n 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x47, 0x47, 0x52, 0x45, 0x47,\\n 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_PK_GENERATION\\\"\\npub global DS_CLG_PK_GENERATION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x50, 0x4b, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f,\\n 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_ENCRYPTION\\\"\\npub global DS_CLG_SHARE_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_USER_DATA_ENCRYPTION\\\"\\npub global DS_CLG_USER_DATA_ENCRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e,\\n 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n// Domain separator - \\\"CLG_SHARE_DECRYPTION\\\"\\npub global DS_CLG_SHARE_DECRYPTION: [u8; 64] = [\\n 0x43, 0x4c, 0x47, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"THRESHOLD_DECRYPTION_SHARE\\\"\\npub global DS_THRESHOLD_DECRYPTION_SHARE: [u8; 64] = [\\n 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x5f, 0x44, 0x45, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n// Domain separator - \\\"USER_DATA_ENCRYPTION_COMMITMENT\\\"\\npub global DS_USER_DATA_ENCRYPTION_COMMITMENT: [u8; 64] = [\\n 0x55, 0x53, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50,\\n 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\\n];\\n\\n/// WRAPPERS\\n\\npub fn compute_commitment(inputs: [Field], domain_separator: [u8; 64]) -> Field {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 1])[0]\\n}\\n\\npub fn compute_single_polynomial_commitment<let N: u32, let BIT: u32>(\\n polynomial: Polynomial<N>,\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT>([].as_vector(), polynomial);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_multiple_polynomial_commitment<let N: u32, let L: u32, let BIT: u32>(\\n polynomials: [Polynomial<N>; L],\\n domain_separator: [u8; 64],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT>([].as_vector(), polynomials);\\n compute_commitment(payload, domain_separator)\\n}\\n\\npub fn compute_challenge<let L: u32>(inputs: [Field], domain_separator: [u8; 64]) -> [Field] {\\n compute_safe(domain_separator, inputs, [0x80000000 | inputs.len(), 2 * L])\\n}\\n\\npub fn single_polynomial_payload<let N: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n input: Polynomial<N>,\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, [input])\\n}\\n\\npub fn multiple_polynomial_payload<let N: u32, let L: u32, let BIT_POLY: u32>(\\n payload: [Field],\\n inputs: [Polynomial<N>; L],\\n) -> [Field] {\\n flatten::<_, _, BIT_POLY>(payload, inputs)\\n}\\n\\n/// COMMITMENTS\\n\\npub fn compute_dkg_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let mut payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n payload = multiple_polynomial_payload::<N, L, BIT_PK>(payload, pk1);\\n\\n compute_commitment(payload, DS_PK)\\n}\\n\\npub fn compute_threshold_pk_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_PK>([].as_vector(), pk0);\\n compute_commitment(payload, DS_PK_GENERATION)\\n}\\n\\npub fn compute_share_computation_sk_commitment<let N: u32, let BIT_SK: u32>(\\n sk: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_SK>([].as_vector(), sk);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_computation_e_sm_commitment<let N: u32, let L: u32, let BIT_E_SM: u32>(\\n e_sm: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_E_SM>([].as_vector(), e_sm);\\n compute_commitment(payload, DS_SHARE_COMPUTATION)\\n}\\n\\npub fn compute_share_encryption_commitment_from_message<let N: u32, let BIT_MSG: u32>(\\n message: Polynomial<N>,\\n) -> Field {\\n let payload = single_polynomial_payload::<N, BIT_MSG>([].as_vector(), message);\\n compute_commitment(payload, DS_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_aggregated_shares_commitment<let N: u32, let L: u32, let BIT_MSG: u32>(\\n agg_shares: [Polynomial<N>; L],\\n) -> Field {\\n let payload = multiple_polynomial_payload::<N, L, BIT_MSG>([].as_vector(), agg_shares);\\n compute_commitment(payload, DS_AGGREGATED_SHARES)\\n}\\n\\n/// Commitment to a threshold decryption share: all CRT limbs, first `K` coefficients per limb\\n/// (same layout as `Polynomial<K>` in decrypted_shares_aggregation).\\n///\\n/// `NATIVE_BIT_WIDTH` must cover native coefficients in \\\\([0, q_l)\\\\) per limb (not centered `d` bounds).\\npub fn compute_threshold_decryption_share_commitment<let K: u32, let L: u32, let NATIVE_BIT_WIDTH: u32>(\\n d_share_limbs: [Polynomial<K>; L],\\n) -> Field {\\n let payload =\\n multiple_polynomial_payload::<K, L, NATIVE_BIT_WIDTH>([].as_vector(), d_share_limbs);\\n compute_commitment(payload, DS_THRESHOLD_DECRYPTION_SHARE)\\n}\\n\\npub fn compute_pk_aggregation_commitment<let N: u32, let L: u32, let BIT_PK: u32>(\\n pk0: [Polynomial<N>; L],\\n pk1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_pk0 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk0, DS_PK_AGGREGATION);\\n let commit_pk1 = compute_multiple_polynomial_commitment::<N, L, BIT_PK>(pk1, DS_PK_AGGREGATION);\\n\\n let inputs = [commit_pk0, commit_pk1].as_vector();\\n\\n compute_commitment(inputs, DS_PK_AGGREGATION)\\n}\\n\\npub fn compute_recursive_aggregation_commitment(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_RECURSIVE_AGGREGATION)\\n}\\n\\npub fn compute_vk_hash(vk_hashes: [Field]) -> Field {\\n compute_commitment(vk_hashes, DS_VK_HASH)\\n}\\n\\npub fn compute_ciphertext_commitment<let N: u32, let L: u32, let BIT_CT: u32>(\\n ct0: [Polynomial<N>; L],\\n ct1: [Polynomial<N>; L],\\n) -> Field {\\n let commit_ct0 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct0, DS_CIPHERTEXT);\\n let commit_ct1 = compute_multiple_polynomial_commitment::<N, L, BIT_CT>(ct1, DS_CIPHERTEXT);\\n\\n let inputs = [commit_ct0, commit_ct1].as_vector();\\n\\n compute_commitment(inputs, DS_CIPHERTEXT)\\n}\\n\\n/// COMMITMENTS FOR CHALLENGES\\n\\npub fn compute_threshold_pk_challenge(payload: [Field]) -> Field {\\n compute_commitment(payload, DS_CLG_PK_GENERATION)\\n}\\n\\npub fn compute_share_encryption_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_ENCRYPTION)\\n}\\n\\npub fn compute_threshold_share_decryption_challenge<let L: u32>(payload: [Field]) -> Field {\\n compute_challenge::<L>(payload, DS_CLG_SHARE_DECRYPTION)[0]\\n}\\n\\npub fn compute_user_data_encryption_ct0_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\\npub fn compute_user_data_encryption_ct1_challenge<let L: u32>(payload: [Field]) -> [Field] {\\n compute_challenge::<L>(payload, DS_CLG_USER_DATA_ENCRYPTION)\\n}\\n\",\"path\":\"interfold/circuits/lib/src/math/commitments.nr\",\"function_locations\":[{\"start\":7767,\"name\":\"compute_commitment\"},{\"start\":7995,\"name\":\"compute_single_polynomial_commitment\"},{\"start\":8298,\"name\":\"compute_multiple_polynomial_commitment\"},{\"start\":8535,\"name\":\"compute_challenge\"},{\"start\":8745,\"name\":\"single_polynomial_payload\"},{\"start\":8944,\"name\":\"multiple_polynomial_payload\"},{\"start\":9157,\"name\":\"compute_dkg_pk_commitment\"},{\"start\":9484,\"name\":\"compute_threshold_pk_commitment\"},{\"start\":9734,\"name\":\"compute_share_computation_sk_commitment\"},{\"start\":10005,\"name\":\"compute_share_computation_e_sm_commitment\"},{\"start\":10277,\"name\":\"compute_share_encryption_commitment_from_message\"},{\"start\":10553,\"name\":\"compute_aggregated_shares_commitment\"},{\"start\":11134,\"name\":\"compute_threshold_decryption_share_commitment\"},{\"start\":11466,\"name\":\"compute_pk_aggregation_commitment\"},{\"start\":11855,\"name\":\"compute_recursive_aggregation_commitment\"},{\"start\":11970,\"name\":\"compute_vk_hash\"},{\"start\":12169,\"name\":\"compute_ciphertext_commitment\"},{\"start\":12568,\"name\":\"compute_threshold_pk_challenge\"},{\"start\":12710,\"name\":\"compute_share_encryption_challenge\"},{\"start\":12867,\"name\":\"compute_threshold_share_decryption_challenge\"},{\"start\":13027,\"name\":\"compute_user_data_encryption_ct0_challenge\"},{\"start\":13188,\"name\":\"compute_user_data_encryption_ct1_challenge\"}]},\"89\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\n//! Helper functions for circuit construction and cryptographic operations.\\nuse crate::math::polynomial::Polynomial;\\nuse crate::math::safe::SafeSponge;\\n\\n/// Compute hex-aligned packing parameters for a given `BIT`.\\n///\\n/// # Purpose\\n/// Returns `(nibble_bits, group)` for use by pack/flatten so layout stays consistent.\\n/// - `nibble_bits`: ceil (`BIT`) to the next multiple of 4 (nibble alignment).\\n/// - Examples: `BIT = 7 -> 8`, `BIT = 8 -> 8`, `BIT = 9 -> 12`, `BIT = 10 -> 12`, `BIT = 11 -> 12`,\\n/// `BIT=16 -> 16`, `BIT = 17 -> 20`.\\n/// - `group`: max number of encoded limbs that fit in one BN254 field element,\\n/// when each limb uses an extra 4 bits (see below).\\n///\\n/// # Rationale\\n/// - We align to nibbles so powers of two are hex-friendly and deterministic.\\n/// - We reserve one extra nibble (4 bits) per stored value to lift signed\\n/// coefficients into the non-negative range (e.g., store `v + 2^nibble_bits`),\\n/// which implies a radix of `2^(nibble_bits + 4)`.\\n///\\n/// # Safety\\n/// - Asserts `nibble_bits + 4 <= 254` to avoid mod-p wrap on BN254.\\n/// - Ensures at least one limb fits: `group >= 1`.\\nfn packing_layout<let BIT: u32>() -> (u32, u32) {\\n // Ceil BIT up to the next multiple of 4 (nibble alignment).\\n let nibble_bits = ((BIT + 3) / 4) * 4;\\n\\n // Each stored limb uses an extra nibble because negative coefficients\\n // will be shifted to positive, so radix = 2^(nibble_bits+4).\\n assert(nibble_bits + 4 <= 254);\\n\\n // Maximum limbs that fit in one BN254 element without wrap.\\n let group = 254 / (nibble_bits + 4);\\n assert(group >= 1);\\n (nibble_bits, group)\\n}\\n\\n/// Flatten `L` polynomials into a single linear stream of packed `Field` carriers.\\n///\\n/// ## What this does\\n/// - For each CRT limb `j` in `0..L`, it packs the coefficients of `poly[j]`\\n/// with `pack::<A, BIT>` and appends all resulting carriers to `inputs`.\\n/// - The packing layout (nibble-aligned width and `group` size) is taken from\\n/// `packing_layout::<BIT>()` and must match what `pack` uses.\\n///\\n/// ## Determinism & order\\n/// - Preserves a stable order: iterate `j = 0..L`, then for each `j` append\\n/// carriers in ascending chunk index `i = 0..num_chunks`.\\n/// - This ensures transcripts remain deterministic across runs.\\n///\\n/// ## Generics\\n/// - `A`: polynomial degree (number of coefficients per polynomial).\\n/// - `L`: number of CRT bases (polynomials).\\n/// - `BIT`: per-coefficient bit bound used by the packing layout (compile-time).\\n///\\n/// ## Returns\\n/// - The same `inputs` vector, extended with all carriers in deterministic order.\\npub fn flatten<let A: u32, let L: u32, let BIT: u32>(\\n mut inputs: [Field],\\n poly: [Polynomial<A>; L],\\n) -> [Field] {\\n for j in 0..L {\\n // Pack its A coefficients into `num_chunks` carriers using the same BIT layout.\\n let packed = pack::<A, BIT>(poly[j].coefficients);\\n\\n // Append carriers in-order to `inputs` to keep a stable transcript layout.\\n for i in 0..packed.len() {\\n inputs = inputs.push_back(packed[i]);\\n }\\n }\\n\\n // Return the extended input stream.\\n inputs\\n}\\n\\n/// Pack `A` values into a `[Field]` vector of carriers using the shared hex-aligned layout.\\n///\\n/// ## What this does\\n/// - Computes `(nibble_bits, group)` via `packing_layout::<BIT>()`.\\n/// - Encodes each value as a limb `digit = v + 2^nibble_bits` and concatenates\\n/// limbs in base `radix = 2^(nibble_bits + 4)` (one extra nibble of headroom).\\n/// - Packs up to `group` limbs per carrier (fits within BN254 254-bit capacity).\\n/// - Pads the last, partial carrier with `digit = 2^nibble_bits` to keep a stable layout.\\n///\\n/// ## Determinism & order\\n/// - Processes values in increasing index order and emits carriers in chunk order\\n/// (`chunk = 0..num_chunks`). Padding is deterministic.\\n///\\n/// ## Generics\\n/// - `A`: number of input values.\\n/// - `BIT`: per-value bit bound; rounded up to `nibble_bits` by `packing_layout`.\\n///\\n/// ## Preconditions / Notes\\n/// - Call with the raw coefficients whose magnitudes already satisfy the BIT bound\\n/// (as enforced by the upstream range checks); `pack` performs the signed -> unsigned\\n/// shift internally via `v + base`.\\n/// - `group >= 1` is enforced by `packing_layout::<BIT>()`.\\n/// - Padding with `digit = 2^nibble_bits` encodes `zero limb` consistently.\\n///\\n/// ## Returns\\n/// - A `[Field]` vector where each element is a concatenation of up to `group` limbs,\\n/// suitable for hashing or transcript I/O.\\npub fn pack<let A: u32, let BIT: u32>(values: [Field; A]) -> [Field] {\\n // Layout parameters: nibble-aligned width and limbs-per-carrier group size.\\n let (nibble_bits, group) = packing_layout::<BIT>();\\n\\n let base = 2.pow_32(nibble_bits as Field); // 2^nibble_bits\\n let radix = 2.pow_32((nibble_bits + 4) as Field); // 2^(nibble_bits + 4)\\n\\n // Number of chunks to emit: ceil(A / group).\\n let num_chunks = (A + group - 1) / group;\\n let mut out: [Field] = [].as_vector();\\n\\n // Process in fixed-size chunks of `group` limbs.\\n for chunk in 0..num_chunks {\\n // How many real values go into this chunk.\\n let remain = A - (chunk * group);\\n let take = if remain < group { remain } else { group };\\n\\n // Build field element accumulator (big-endian concatenation in `radix`).\\n let mut acc = 0;\\n for i in 0..take {\\n let v = values[chunk * group + i];\\n acc = acc * radix + (v + base);\\n }\\n\\n // Pad remaining limb slots with the canonical zero-limb `digit = base`.\\n for _ in 0..(group - take) {\\n acc = acc * radix + base;\\n }\\n\\n out = out.push_back(acc);\\n }\\n out\\n}\\n\\n/// Computes a cryptographic hash using the SAFE (Sponge API for Field Elements) protocol.\\n///\\n/// This is a convenience wrapper around the SAFE sponge API that handles the full\\n/// lifecycle: initialization, absorption, squeezing, and finalization. It's designed\\n/// for use in Fiat-Shamir challenge generation and commitment schemes within zero-knowledge circuits.\\n///\\n/// # Arguments\\n/// * `domain_separator` - A 64-byte domain separator used to differentiate between\\n/// different protocol instances and prevent cross-protocol attacks.\\n/// * `inputs` - Vector of field elements to be absorbed into the sponge.\\n/// * `io_pattern` - A 2-element array encoding the I/O pattern:\\n/// - `io_pattern[0]`: Encoded ABSORB operation (MSB=1, lower 31 bits = length)\\n/// - `io_pattern[1]`: Encoded SQUEEZE operation (MSB=0, lower 31 bits = length)\\n///\\n/// # Returns\\n/// A vector of field elements squeezed from the sponge, with length determined by\\n/// the SQUEEZE operation in the IO pattern.\\npub fn compute_safe(domain_separator: [u8; 64], inputs: [Field], io_pattern: [u32; 2]) -> [Field] {\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(inputs);\\n let digests = sponge.squeeze();\\n sponge.finish();\\n\\n digests\\n}\\n\\n#[test]\\nfn test_flatten() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([1, 2, 3]); // degree 2\\n let poly2 = Polynomial::new([4, -16, 6]); // degree 2\\n let poly3 = Polynomial::new([-7, 8, 9]); // degree 2\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 4>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n assert(result[0] == 0x11121310101010101010101010101010101010101010101010101010101010);\\n assert(result[1] == 0x14001610101010101010101010101010101010101010101010101010101010); // -16 became 00 at 0x 14 00 16,\\n assert(result[2] == 0x09181910101010101010101010101010101010101010101010101010101010); // -7 became 09 at 0x 09 18 19(16 - 7 = 9)\\n}\\n\\n#[test]\\nfn test_flatten_big() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([\\n 1791218451968394,\\n 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n 5430119342984413,\\n 704811298945172,\\n 8901715723925099,\\n 21888242871839275222246405745257275088548364400416034343698203098124042812559,\\n 21888242871839275222246405745257275088548364400416034343698200215091693880034,\\n ]);\\n let poly2 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698200314078269634250,\\n 21888242871839275222246405745257275088548364400416034343698200967285641915872,\\n 2909990636858607,\\n 7896103832076587,\\n 2078397209533893,\\n 21888242871839275222246405745257275088548364400416034343698199792421452734531,\\n 614400389245817,\\n 8290314119277588,\\n ]);\\n let poly3 = Polynomial::new([\\n 21888242871839275222246405745257275088548364400416034343698201373175279892906,\\n 21888242871839275222246405745257275088548364400416034343698201087241869723721,\\n 6768789983786188,\\n 635797784303388,\\n 7610153424227556,\\n 4633893206538324,\\n 2016269760615332,\\n 21888242871839275222246405745257275088548364400416034343698201007080554428142,\\n ]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 54>(inputs, polynomials);\\n\\n // Verify the flattened coefficients are in the correct positions\\n // Every value shifted 1 nibble incase of negative integers\\n\\n // For the first index of result operation goes like this,\\n\\n // First four index of poly1\\n // 1791218451968394,\\n // 21888242871839275222246405745257275088548364400416034343698198265248580087864,\\n // 21888242871839275222246405745257275088548364400416034343698200542108324633466,\\n // 5430119342984413,\\n\\n // base + 1791218451968394 = 0x1065d1a8b8b718a\\n // base - 5921327228407753 = 0xeaf69591f3b037 (negative coefficient shifted)\\n // base - 3644467483862151 = 0xf30d604a3a9b79 (negative coefficient shifted)\\n // base + 5430119342984413 = 0x1134aaa2e86ccdd\\n assert(result[0] == 0x1065d1a8b8b718a0eaf69591f3b0370f30d604a3a9b791134aaa2e86ccdd);\\n assert(result[1] == 0x1028105ab1b789411fa010339db66b0fc220f1326bc8e0f1e3f4cc1e02e1);\\n assert(result[2] == 0x0f23dfbe7cd76c90f4901299312ddf10a569efe35acef11c0d76f005412b);\\n assert(result[3] == 0x107624a8f605dc50f0638a368960421022ecb3cf36b7911d73ff2c27ec14);\\n assert(result[4] == 0x0f6013a24e1b9a90f4fd2c158a08481180c2dba8af4cc10242413515171c);\\n assert(result[5] == 0x11b0964eb898ce411076805680b85410729c962da53a40f4b44412d0f6ed);\\n}\\n\\n#[test]\\nfn test_flatten_small() {\\n // Create test polynomials\\n let poly1 = Polynomial::new([712345, 104857, 999999, 500001, 123, 654321, 77]);\\n let poly2 = Polynomial::new([1, 524287, 888888, 23456, 34567, 765432, 0]);\\n let poly3 = Polynomial::new([444444, 333333, 222222, 111111, 987654, 246810, 13579]);\\n\\n let polynomials = [poly1, poly2, poly3];\\n\\n // Initialize target array with zeros\\n let inputs: [Field] = [].as_vector();\\n\\n // Flatten the polynomials\\n let result = flatten::<_, _, 20>(inputs, polynomials);\\n\\n assert(result[0] == 0x1ade991199991f423f17a12110007b19fbf110004d100000100000100000);\\n assert(result[1] == 0x10000117ffff1d9038105ba01087071badf8100000100000100000100000);\\n assert(result[2] == 0x16c81c15161513640e11b2071f120613c41a10350b100000100000100000);\\n}\\n\\n#[test]\\nfn test_safe_hashing_with_safe_helper() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let digests1 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests1.len() == 1);\\n assert(digests1[0] != 0);\\n\\n // Test determinism\\n let digests2 = compute_safe(domain_separator, elements, io_pattern);\\n\\n assert(digests2.len() == 1);\\n assert(digests2[0] != 0);\\n assert(digests2[0] == digests1[0]);\\n}\\n\\n#[test]\\nfn test_pack() {\\n // Test pack function directly with small values\\n let values = [1, 2, 3, 4];\\n let packed = pack::<4, 4>(values);\\n\\n // With BIT=4, nibble_bits=4, group should be floor(254/(4+4)) = 31\\n // So all 4 values should fit in one carrier\\n assert(packed.len() >= 1);\\n\\n // Test with negative values\\n let values_neg = [-1, 2, -3, 4];\\n let packed_neg = pack::<4, 4>(values_neg);\\n assert(packed_neg.len() >= 1);\\n}\\n\\n#[test]\\nfn test_pack_single_value() {\\n // Test packing a single value\\n let values = [42];\\n let packed = pack::<1, 8>(values);\\n assert(packed.len() == 1);\\n assert(packed[0] != 0);\\n}\\n\\n#[test]\\nfn test_pack_determinism() {\\n // Test that packing is deterministic\\n let values = [10, 20, 30];\\n let packed1 = pack::<3, 8>(values);\\n let packed2 = pack::<3, 8>(values);\\n\\n assert(packed1.len() == packed2.len());\\n for i in 0..packed1.len() {\\n assert(packed1[i] == packed2[i]);\\n }\\n}\\n\",\"path\":\"interfold/circuits/lib/src/math/helpers.nr\",\"function_locations\":[{\"start\":1374,\"name\":\"packing_layout\"},{\"start\":2905,\"name\":\"flatten\"},{\"start\":4755,\"name\":\"pack\"},{\"start\":7016,\"name\":\"compute_safe\"},{\"start\":7214,\"name\":\"test_flatten\"},{\"start\":8157,\"name\":\"test_flatten_big\"},{\"start\":11058,\"name\":\"test_flatten_small\"},{\"start\":11885,\"name\":\"test_safe_hashing_with_safe_helper\"},{\"start\":12731,\"name\":\"test_pack\"},{\"start\":13201,\"name\":\"test_pack_single_value\"},{\"start\":13397,\"name\":\"test_pack_determinism\"}]},\"97\":{\"source\":\"// SPDX-License-Identifier: LGPL-3.0-only\\n//\\n// This file is provided WITHOUT ANY WARRANTY;\\n// without even the implied warranty of MERCHANTABILITY\\n// or FITNESS FOR A PARTICULAR PURPOSE.\\n\\nuse keccak256::keccak256;\\nuse poseidon::poseidon2_permutation;\\n\\n/// SAFE (Sponge API for Field Elements)\\n///\\n/// This module provides a complete implementation of the SAFE API in Noir as defined in:\\n/// \\\"SAFE (Sponge API for Field Elements) - A Toolbox for ZK Hash Applications\\\"\\n/// see https://hackmd.io/bHgsH6mMStCVibM_wYvb2w#22-Sponge-state for more details.\\n///\\n/// SAFE provides a unified interface for cryptographic sponge functions that can be\\n/// instantiated with various permutations to create hash functions, MACs, authenticated\\n/// encryption schemes, and other cryptographic primitives for ZK proof systems.\\n///\\n/// This implementation follows the SAFE specification exactly, providing:\\n/// - Complete API: START, ABSORB, SQUEEZE, FINISH operations.\\n/// - Full security: Domain separation, tag computation, IO pattern validation.\\n/// - Poseidon2 integration: Field-friendly permutation for ZK systems.\\n/// - Specification compliance: All operations follow SAFE spec 2.4 exactly.\\n/// - Natural API design: Variable-length inputs, automatic length detection from IO patterns.\\n///\\n/// # API Design\\n///\\n/// The API is designed for natural usage while maintaining type safety:\\n/// - `absorb(input: [Field])`: Accepts variable-length arrays, no padding required.\\n/// - `squeeze()`: Returns a vector with field element(s).\\n/// - IO patterns automatically determine operation lengths for validation.\\n\\n/// Rate parameter for the sponge construction (number of field elements that can be absorbed per permutation call).\\nglobal RATE: u32 = 3;\\n\\n/// Capacity parameter for the sponge construction (security parameter, typically 1-2 field elements).\\nglobal CAPACITY: u32 = 1;\\n\\n/// Total state size (rate + capacity) in field elements.\\nglobal STATE_SIZE: u32 = RATE + CAPACITY;\\n\\n/// IO Pattern encoding constants (from SAFE spec 2.3).\\n///\\n/// These constants are used for encoding operation types in the 32-bit word format:\\n/// - MSB set to 1 for ABSORB operations\\n/// - MSB set to 0 for SQUEEZE operations\\n\\n/// Flag for ABSORB operations (MSB = 1)\\nglobal ABSORB_FLAG: u32 = 0x80000000;\\n\\n/// Flag for SQUEEZE operations (MSB = 0)\\nglobal SQUEEZE_FLAG: u32 = 0x00000000;\\n\\n/// SAFE Sponge State (following spec 2.2)\\n///\\n/// The sponge state consists of the permutation state, tag, position counters,\\n/// and IO pattern tracking as defined in the SAFE specification.\\n///\\n/// # Generic Parameters\\n/// - `L`: The length of the IO pattern array\\n///\\n/// # Fields\\n/// - `state`: Permutation state V in F^n (rate + capacity elements)\\n/// - `tag`: Parameter tag T used for instance differentiation\\n/// - `absorb_pos`: Current absorb position (<= n-c)\\n/// - `squeeze_pos`: Current squeeze position (<= n-c)\\n/// - `io_pattern`: Expected IO pattern for validation (encoded 32-bit words)\\n/// - `io_count`: Current operation count for pattern tracking\\npub struct SafeSponge<let L: u32> {\\n /// Permutation state V in F^n (rate + capacity elements).\\n state: [Field; STATE_SIZE],\\n /// Parameter tag T used for instance differentiation.\\n tag: Field,\\n /// Current absorb position (<= n-c).\\n absorb_pos: u32,\\n /// Current squeeze position (<= n-c).\\n squeeze_pos: u32,\\n /// Expected IO pattern for validation.\\n io_pattern: [u32; L],\\n /// Current operation count for pattern tracking (spec 2.4: io_count).\\n io_count: u32,\\n}\\n\\nimpl<let L: u32> SafeSponge<L> {\\n /// Initializes a new SAFE sponge instance with the given IO pattern and domain separator (following spec 2.4).\\n ///\\n /// # Arguments\\n /// - `io_pattern`: Array of 32-bit encoded operations defining the expected sequence of ABSORB/SQUEEZE calls.\\n /// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n /// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n ///\\n /// # Returns\\n /// A new `SafeSponge` instance with initialized state\\n pub fn start(io_pattern: [u32; L], domain_separator: [u8; 64]) -> SafeSponge<L> {\\n // Compute tag from IO pattern and domain separator (spec 2.3).\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n let mut state = [0; STATE_SIZE];\\n // Initialize capacity with tag (spec 2.4).\\n // Add T to the first 128 bits of the state.\\n state[0] = tag;\\n\\n SafeSponge { state, tag, absorb_pos: 0, squeeze_pos: 0, io_pattern, io_count: 0 }\\n }\\n\\n /// Absorbs field elements into the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to absorb is automatically validated against the IO pattern.\\n /// This method accepts variable-length arrays, making it natural to use without padding.\\n ///\\n /// # Arguments\\n /// - `input`: Array of field elements to absorb (variable length, must match IO pattern)\\n pub fn absorb(&mut self, input: [Field]) {\\n let length = input.len() as u32;\\n\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_absorb = (expected_encoded_word & ABSORB_FLAG) != 0;\\n let expected_length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type and length\\n assert(is_expected_absorb, \\\"Expected ABSORB operation\\\");\\n assert(expected_length == length, \\\"Length mismatch\\\");\\n\\n // Process each element naturally (no unnecessary iterations).\\n for i in 0..length {\\n // If absorb_pos == (n-c) then permute and reset (spec 2.4).\\n if self.absorb_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.absorb_pos = 0;\\n }\\n\\n // Add X[i] to state at absorb_pos (spec 2.4).\\n // Note: absorb_pos is the rate position, not capacity position.\\n self.state[self.absorb_pos + CAPACITY] =\\n self.state[self.absorb_pos + CAPACITY] + input[i];\\n self.absorb_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = ABSORB_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n\\n // Force permute at start of next SQUEEZE (spec 2.4).\\n self.squeeze_pos = RATE;\\n }\\n\\n /// Extracts field elements from the sponge state, interleaving permutation calls as needed (following spec 2.4).\\n ///\\n /// The number of elements to squeeze is automatically determined from the IO pattern.\\n pub fn squeeze(&mut self) -> [Field] {\\n // Validate against IO pattern.\\n assert(self.io_count < L);\\n\\n // Parse expected operation from io_pattern (encoded word)\\n let expected_encoded_word = self.io_pattern[self.io_count];\\n let is_expected_squeeze = (expected_encoded_word & ABSORB_FLAG) == 0;\\n let length = expected_encoded_word & 0x7FFFFFFF;\\n\\n // Validate operation type\\n assert(is_expected_squeeze, \\\"Expected SQUEEZE operation\\\");\\n\\n let mut output: [Field] = [].as_vector();\\n\\n // SQUEEZE implementation following spec 2.4.\\n // If length==0, loop won't execute (spec 2.4).\\n for _ in 0..length {\\n // If squeeze_pos==(n-c) then permute and reset (spec 2.4).\\n if self.squeeze_pos == RATE {\\n // n-c = RATE.\\n self.state = self.permute();\\n self.squeeze_pos = 0;\\n self.absorb_pos = 0;\\n }\\n // Set Y[i] to state element at squeeze_pos (spec 2.4).\\n output = output.push_back(self.state[self.squeeze_pos + CAPACITY]);\\n self.squeeze_pos += 1;\\n }\\n\\n // Verify that the encoded word matches the expected pattern.\\n let encoded_word = SQUEEZE_FLAG | length;\\n assert(encoded_word == expected_encoded_word);\\n\\n self.io_count += 1;\\n output\\n }\\n\\n /// Finalizes the sponge instance, verifying that all expected operations have been performed and clearing the internal state for security (following spec 2.4).\\n ///\\n /// This function is used to ensure that the sponge instance has been used correctly and to prevent information leakage.\\n pub fn finish(&mut self) {\\n // Check that io_count equals the length of the IO pattern expected (spec 2.4).\\n assert(self.io_count == L, \\\"IO pattern not completed\\\");\\n\\n // Erase the state and its variables (spec 2.4).\\n self.state = [0; STATE_SIZE];\\n self.absorb_pos = 0;\\n self.squeeze_pos = 0;\\n self.io_count = 0;\\n }\\n\\n /// Permute the state using Poseidon2 (following spec 2.4).\\n ///\\n /// Applies the Poseidon2 permutation to the current state.\\n /// This is the core cryptographic primitive of the sponge construction.\\n ///\\n /// # Returns\\n /// New state after permutation\\n fn permute(self) -> [Field; STATE_SIZE] {\\n poseidon2_permutation(self.state)\\n }\\n}\\n\\n/// Computes a unique tag for a sponge instance based on its IO pattern and domain separator.\\n/// The tag is used to ensure that distinct instances behave like distinct functions.\\n///\\n/// # Arguments\\n/// - `io_pattern`: Array of 32-bit encoded operations defining the sponge's usage pattern.\\n/// Each word has MSB=1 for ABSORB operations, MSB=0 for SQUEEZE operations.\\n/// - `domain_separator`: 64-byte domain separator for cross-protocol security.\\n///\\n/// # Returns\\n/// A field element representing the 128-bit tag.\\npub fn compute_tag<let L: u32>(io_pattern: [u32; L], domain_separator: [u8; 64]) -> Field {\\n // Step 1: Parse and aggregate consecutive operations of the same type\\n let mut encoded_words = [0; L]; // Support up to L operations.\\n let mut word_count = 0;\\n let mut current_absorb_sum = 0;\\n let mut current_squeeze_sum = 0;\\n let mut last_was_absorb = false;\\n\\n for i in 0..L {\\n if io_pattern[i] > 0 {\\n // Parse operation type from MSB and length from lower 31 bits\\n let is_absorb = (io_pattern[i] & ABSORB_FLAG) != 0;\\n let length = io_pattern[i] & 0x7FFFFFFF; // Clear MSB to get length\\n\\n if is_absorb {\\n if last_was_absorb {\\n // Aggregate consecutive ABSORB operations\\n current_absorb_sum += length;\\n } else {\\n // Start new ABSORB sequence\\n if current_squeeze_sum > 0 {\\n // Flush previous SQUEEZE sequence\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n current_squeeze_sum = 0;\\n }\\n current_absorb_sum = length;\\n }\\n last_was_absorb = true;\\n } else {\\n if !last_was_absorb {\\n // Aggregate consecutive SQUEEZE operations\\n current_squeeze_sum += length;\\n } else {\\n // Start new SQUEEZE sequence\\n if current_absorb_sum > 0 {\\n // Flush previous ABSORB sequence\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n current_absorb_sum = 0;\\n }\\n current_squeeze_sum = length;\\n }\\n last_was_absorb = false;\\n }\\n }\\n }\\n\\n // Flush remaining operations\\n if current_absorb_sum > 0 {\\n encoded_words[word_count] = ABSORB_FLAG | current_absorb_sum;\\n word_count += 1;\\n }\\n if current_squeeze_sum > 0 {\\n encoded_words[word_count] = SQUEEZE_FLAG | current_squeeze_sum;\\n word_count += 1;\\n }\\n\\n // Step 2: Serialize to byte string and append domain separator (following SAFE spec 2.3).\\n // Buffer is 256 bytes: max 192 bytes for IO pattern (48 words) + 64 bytes for domain separator.\\n // Note: We must use a fixed-size array because Noir's keccak256 requires [u8; N], not [u8].\\n let max_io_pattern_bytes: u32 = 192; // 256 - 64 (domain separator)\\n let io_pattern_bytes = word_count * 4;\\n assert(\\n io_pattern_bytes <= max_io_pattern_bytes,\\n \\\"IO pattern too large: max 48 aggregated words supported\\\",\\n );\\n\\n let mut input_bytes = [0u8; 256];\\n let mut byte_count: u32 = 0;\\n\\n // Serialize encoded words to bytes (big-endian as per SAFE spec).\\n // Note: Noir requires compile-time loop bounds, so we iterate over L (the array size)\\n // instead of word_count (runtime value). The condition `i < word_count` ensures we only\\n // process valid encoded words. This is safe because word_count <= L always holds\\n // (we can have at most L encoded words from L input operations).\\n for i in 0..L {\\n if i < word_count {\\n let word = encoded_words[i];\\n input_bytes[byte_count] = (word >> 24) as u8;\\n input_bytes[byte_count + 1] = (word >> 16) as u8;\\n input_bytes[byte_count + 2] = (word >> 8) as u8;\\n input_bytes[byte_count + 3] = word as u8;\\n byte_count += 4;\\n }\\n }\\n\\n // Append full 64-byte domain separator.\\n for i in 0..64 {\\n input_bytes[byte_count] = domain_separator[i];\\n byte_count += 1;\\n }\\n\\n // Step 3: Hash with Keccak-256 and truncate to 128 bits.\\n // Note: The SAFE spec uses SHA3-256, but we use Keccak-256 for Noir compatibility.\\n // Keccak-256 differs from SHA3-256 in padding, but both provide equivalent security.\\n let hash_bytes = keccak256(input_bytes, byte_count);\\n\\n // Convert first 128 bits (16 bytes) to field element.\\n let mut tag_value: Field = 0;\\n for i in 0..16 {\\n tag_value = tag_value * 256 + (hash_bytes[i] as Field);\\n }\\n\\n tag_value\\n}\\n\\n#[test]\\nfn test_safe_hashing() {\\n // Verifies basic hash functionality with a simple ABSORB(3) + SQUEEZE(1) pattern.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_merkle_node() {\\n // Verifies SAFE can be used for Merkle tree node hashing with pattern ABSORB(1) + ABSORB(1) + SQUEEZE(1).\\n // Tests the ability to absorb multiple inputs before squeezing output.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let left = [123].as_vector();\\n let right = [456].as_vector();\\n\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(left);\\n sponge.absorb(right);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(left);\\n sponge2.absorb(right);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_commitment_scheme() {\\n // Verifies SAFE can be used for commitment schemes with pattern ABSORB(3) + SQUEEZE(1).\\n // Tests the ability to create deterministic commitments from multiple field elements.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let values = [10, 20, 30].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(values);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n\\n // Test determinism\\n let mut sponge2 = SafeSponge::start(io_pattern, domain_separator);\\n sponge2.absorb(values);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output2.len() == 1);\\n assert(output2[0] != 0);\\n}\\n\\n#[test]\\nfn test_domain_separation() {\\n // Verifies that different domain separators produce different outputs for the same input.\\n // This is crucial for cross-protocol security and preventing collisions between different applications.\\n let elements = [1, 2, 3].as_vector();\\n let domain1 = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let domain2 = [\\n 0x41, 0x42, 0x43, 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(3), SQUEEZE(1)\\n let io_pattern = [0x80000003, 0x00000001];\\n\\n let mut sponge1 = SafeSponge::start(io_pattern, domain1);\\n sponge1.absorb(elements);\\n let output1 = sponge1.squeeze();\\n sponge1.finish();\\n\\n let mut sponge2 = SafeSponge::start(io_pattern, domain2);\\n sponge2.absorb(elements);\\n let output2 = sponge2.squeeze();\\n sponge2.finish();\\n\\n assert(output1.len() == 1);\\n assert(output2.len() == 1);\\n assert(output1[0] != output2[0]); // Different domain separators should produce different outputs\\n}\\n\\n#[test]\\nfn test_multiple_squeeze() {\\n // Verifies that multiple field elements can be squeezed in a single operation.\\n // Tests pattern ABSORB(3) + SQUEEZE(2) to ensure proper state management.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n let elements = [1, 2, 3].as_vector();\\n\\n // Pattern: ABSORB(3), SQUEEZE(2)\\n let io_pattern = [0x80000003, 0x00000002];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb(elements);\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 2);\\n assert(output[0] != 0);\\n assert(output[1] != 0);\\n assert(output[0] != output[1]); // Different squeeze outputs should be different\\n}\\n\\n#[test]\\nfn test_zero_length_operations() {\\n // Verifies that zero-length ABSORB and SQUEEZE operations are handled correctly.\\n // Tests pattern ABSORB(0) + SQUEEZE(1) to ensure proper state transitions.\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Pattern: ABSORB(0), SQUEEZE(1)\\n let io_pattern = [0x80000000, 0x00000001];\\n let mut sponge = SafeSponge::start(io_pattern, domain_separator);\\n sponge.absorb([].as_vector());\\n let output = sponge.squeeze();\\n sponge.finish();\\n\\n assert(output.len() == 1);\\n assert(output[0] != 0);\\n}\\n\\n#[test]\\nfn test_tag_computation() {\\n // Verifies the tag computation algorithm using the example from the SAFE specification.\\n // Pattern: ABSORB(3), ABSORB(3), SQUEEZE(3)\\n // Should aggregate to: ABSORB(6), SQUEEZE(3)\\n // Encoded as: [0x80000006, 0x00000003]\\n // Tests determinism and pattern differentiation.\\n\\n let io_pattern = [0x80000003, 0x80000003, 0x00000003];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test determinism\\n let tag2 = compute_tag(io_pattern, domain_separator);\\n assert(tag == tag2);\\n\\n // Test that different patterns produce different tags\\n let io_pattern2 = [0x80000003, 0x00000003]; // ABSORB(3), SQUEEZE(3) - different pattern\\n let tag3 = compute_tag(io_pattern2, domain_separator);\\n assert(tag != tag3);\\n}\\n\\n#[test]\\nfn test_tag_computation_debug() {\\n println(\\\"=== SAFE Tag Computation Debug Test ===\\\");\\n\\n // Test your specific pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\n let io_pattern = [0x80000002, 0x00000002, 0x80000002];\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n println(f\\\"Testing pattern: {io_pattern}\\\");\\n println(\\n f\\\"Expected to aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(2)\\\",\\n );\\n println(\\n f\\\"Expected encoded words: [0x80000002, 0x00000002, 0x80000002]\\\",\\n );\\n println(\\\"\\\");\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n println(f\\\"=== Expected Rust Output ===\\\");\\n println(\\\"Pattern [2, 2, 2] (ABSORB(2), SQUEEZE(2), ABSORB(2))\\\");\\n println(\\\"Domain separator: 0x41424344...\\\");\\n println(\\\"Tag: 0xce3bb9ee4b2d41c42e9cdda38afe8b6a\\\");\\n println(\\\"\\\");\\n\\n println(f\\\"=== Noir Output ===\\\");\\n println(f\\\"Tag: {tag}\\\");\\n println(\\\"\\\");\\n\\n println(\\\"Compare the tag values above with Rust script!\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_absorb_aggregation() {\\n // Test that consecutive ABSORB operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1) should aggregate to ABSORB(2), SQUEEZE(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(1) = [0x80000002, 0x00000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(2), SQUEEZE(1)\\n let aggregated_pattern = [0x80000002, 0x00000001];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Consecutive ABSORB operations should aggregate to the same tag\\\");\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive ABSORB operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive ABSORB Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001] (ABSORB(1), ABSORB(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000002, 0x00000001] (ABSORB(2), SQUEEZE(1))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_consecutive_squeeze_aggregation() {\\n // Test that consecutive SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1) should aggregate to ABSORB(1), SQUEEZE(2)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), SQUEEZE(1), SQUEEZE(1)\\n let io_pattern = [0x80000001, 0x00000001, 0x00000001];\\n\\n // This should aggregate to: ABSORB(1), SQUEEZE(2) = [0x80000001, 0x00000002]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag ABSORB(1), SQUEEZE(2)\\n let aggregated_pattern = [0x80000001, 0x00000002];\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(\\n tag == aggregated_tag,\\n \\\"Consecutive SQUEEZE operations should aggregate to the same tag\\\",\\n );\\n\\n // Test that a different pattern produces a different tag\\n let different_pattern = [0x80000001, 0x00000001, 0x80000001]; // ABSORB(1), SQUEEZE(1), ABSORB(1)\\n let different_tag = compute_tag(different_pattern, domain_separator);\\n\\n // This should be different because it doesn't have consecutive SQUEEZE operations\\n assert(tag != different_tag, \\\"Different patterns should produce different tags\\\");\\n\\n println(\\\"=== Consecutive SQUEEZE Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x00000001, 0x00000001] (ABSORB(1), SQUEEZE(1), SQUEEZE(1))\\\",\\n );\\n println(\\n f\\\"Aggregated pattern: [0x80000001, 0x00000002] (ABSORB(1), SQUEEZE(2))\\\",\\n );\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n println(f\\\"Different pattern tag: {different_tag}\\\");\\n}\\n\\n#[test]\\nfn test_mixed_consecutive_aggregation() {\\n // Test that both consecutive ABSORB and SQUEEZE operations are properly aggregated\\n // Pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n // Should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Test pattern: ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1)\\n let io_pattern = [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001];\\n\\n // This should aggregate to: ABSORB(2), SQUEEZE(2), ABSORB(1) = [0x80000002, 0x00000002, 0x80000001]\\n let tag = compute_tag(io_pattern, domain_separator);\\n\\n // Test that the aggregated pattern produces the same tag\\n let aggregated_pattern = [0x80000002, 0x00000002, 0x80000001]; // ABSORB(2), SQUEEZE(2), ABSORB(1)\\n let aggregated_tag = compute_tag(aggregated_pattern, domain_separator);\\n\\n // The tags should be identical because the patterns are equivalent after aggregation\\n assert(tag == aggregated_tag, \\\"Mixed consecutive operations should aggregate to the same tag\\\");\\n\\n println(\\\"=== Mixed Consecutive Aggregation Test ===\\\");\\n println(\\n f\\\"Original pattern: [0x80000001, 0x80000001, 0x00000001, 0x00000001, 0x80000001]\\\",\\n );\\n println(\\n f\\\" (ABSORB(1), ABSORB(1), SQUEEZE(1), SQUEEZE(1), ABSORB(1))\\\",\\n );\\n println(f\\\"Aggregated pattern: [0x80000002, 0x00000002, 0x80000001]\\\");\\n println(f\\\" (ABSORB(2), SQUEEZE(2), ABSORB(1))\\\");\\n println(f\\\"Original tag: {tag}\\\");\\n println(f\\\"Aggregated tag: {aggregated_tag}\\\");\\n}\\n\\n#[test]\\nfn test_large_io_pattern() {\\n let domain_separator = [\\n 0x41, 0x42, 0x43, 0x44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\\n 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, 0, 0, 0, 0, 0,\\n 0, 0, 0, 0, 0, 0,\\n ];\\n\\n // Create pattern with 48 alternating ABSORB(1) and SQUEEZE(1) operations\\n // This is the maximum supported (48 words * 4 bytes = 192 bytes, leaving 64 for domain separator)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1; // ABSORB(1)\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1; // SQUEEZE(1)\\n }\\n }\\n\\n let tag = compute_tag(io_pattern, domain_separator);\\n assert(tag != 0);\\n}\\n\\n#[test]\\nfn test_domain_separator_not_truncated() {\\n // This test verifies that the domain separator is always included in the tag computation,\\n // even for large IO patterns. If the domain separator were truncated, different domain\\n // separators would produce the same tag for large patterns.\\n\\n let domain_separator_a = [\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,\\n 0x41, 0x41, 0x41, 0x41,\\n ]; // All 'A's\\n\\n let domain_separator_b = [\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,\\n 0x42, 0x42, 0x42, 0x42,\\n ]; // All 'B's\\n\\n // Create pattern with 48 alternating operations (max supported: 192 bytes of IO pattern)\\n let mut io_pattern = [0u32; 48];\\n for i in 0..48 {\\n if i % 2 == 0 {\\n io_pattern[i] = ABSORB_FLAG | 1;\\n } else {\\n io_pattern[i] = SQUEEZE_FLAG | 1;\\n }\\n }\\n\\n let tag_a = compute_tag(io_pattern, domain_separator_a);\\n let tag_b = compute_tag(io_pattern, domain_separator_b);\\n\\n // Tags MUST be different because domain separators are different.\\n // If they were the same, it would mean the domain separator was truncated/ignored.\\n assert(tag_a != tag_b, \\\"Domain separator must affect tag even for large IO patterns\\\");\\n}\\n\",\"path\":\"interfold/circuits/lib/src/math/safe.nr\",\"function_locations\":[{\"start\":4164,\"name\":\"SafeSponge<L>::start\"},{\"start\":5046,\"name\":\"SafeSponge<L>::absorb\"},{\"start\":6826,\"name\":\"SafeSponge<L>::squeeze\"},{\"start\":8494,\"name\":\"SafeSponge<L>::finish\"},{\"start\":9156,\"name\":\"SafeSponge<L>::permute\"},{\"start\":9830,\"name\":\"compute_tag\"},{\"start\":14128,\"name\":\"test_safe_hashing\"},{\"start\":15104,\"name\":\"test_merkle_node\"},{\"start\":16281,\"name\":\"test_commitment_scheme\"},{\"start\":17357,\"name\":\"test_domain_separation\"},{\"start\":18710,\"name\":\"test_multiple_squeeze\"},{\"start\":19639,\"name\":\"test_zero_length_operations\"},{\"start\":20415,\"name\":\"test_tag_computation\"},{\"start\":21477,\"name\":\"test_tag_computation_debug\"},{\"start\":22681,\"name\":\"test_consecutive_absorb_aggregation\"},{\"start\":24750,\"name\":\"test_consecutive_squeeze_aggregation\"},{\"start\":26760,\"name\":\"test_mixed_consecutive_aggregation\"},{\"start\":28520,\"name\":\"test_large_io_pattern\"},{\"start\":29333,\"name\":\"test_domain_separator_not_truncated\"}]}}}","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n broadcastVote,\n chainRpcUrl,\n getBlockAtTimestamp,\n getChainHead,\n getIndexedLogs,\n readContracts,\n getAllRoundResults,\n getCurrentRound,\n getEligibleAddresses,\n getRoundCiphertext,\n getRoundPublicKey,\n getRoundResult,\n getRoundStateLite,\n getTokenHolderHashes,\n getVoteStatus,\n requestNewRound,\n} from './api'\nimport { getOnChainRoundData, getOnchainVotingPower, getPreviousCiphertext, getRoundDetails, getRoundTokenDetails } from './state'\nimport { finishBallotProof, finishMaskProof, prepareBallot } from './vote'\n\nimport type {\n ChainHead,\n ContractRead,\n ContractReadResult,\n IndexedLog,\n LogQuery,\n BroadcastVoteRequest,\n BroadcastVoteResponse,\n CurrentRoundResponse,\n E3StateLiteResponse,\n JsonResponse,\n NewRoundRequest,\n OnChainRoundData,\n PrepareBallotRequest,\n PreparedBallot,\n ProofData,\n RoundDetails,\n SlotHead,\n TokenDetails,\n TokenHolder,\n VoteStatusResponse,\n WebResultResponse,\n} from './types'\n\n/**\n * Pass as the SDK's `rpcUrl` to read the chain through the CRISP server's own `/chain/rpc` route.\n *\n * A sentinel rather than a boolean flag so the parameter keeps one meaning — \"where chain reads\n * go\" — whether that is a URL you supply or the server you are already talking to.\n */\nexport const SERVER_RPC = 'server' as const\n\n/**\n * A class representing the CRISP SDK.\n */\nexport class CrispSDK {\n /**\n * The server URL for the CRISP SDK.\n * It's used by methods that communicate directly with the CRISP server.\n */\n private serverUrl: string\n\n /**\n * Endpoint used for direct chain reads, or `undefined` to use viem's default public RPC.\n */\n private rpcUrl: string | undefined\n\n /**\n * Create a new instance.\n *\n * @param serverUrl - The base URL of the CRISP server\n * @param rpcUrl - Endpoint for direct chain reads. Omit (or pass `null`) to keep viem's default\n * public RPC. Pass {@link SERVER_RPC} to read through the CRISP server's own\n * `/chain/rpc` route instead of a third-party endpoint. Any other string is used\n * as the endpoint URL directly.\n *\n * Routing through the server is opt-in rather than the default because it is a change of\n * transport, not a tuning knob: a caller who merely upgrades this package would have every chain\n * read redirected to a route their deployed server may not have — or may not be configured to\n * serve the contracts being read — turning a version bump into an outage.\n */\n constructor(serverUrl: string, rpcUrl?: string | null) {\n this.serverUrl = serverUrl\n this.rpcUrl = rpcUrl === SERVER_RPC ? chainRpcUrl(serverUrl) : (rpcUrl ?? undefined)\n }\n\n /**\n * Phase one: encrypt a ballot, before the voter signs anything.\n *\n * A ballot has to be encrypted before it can be signed, because the digest binds the ciphertext.\n * Take `ctCommitment` from the result, read the digest from\n * `CRISPProgram.ballotDigest(e3Id, slot, ctCommitment)`, have the voter sign it, then call\n * {@link finishBallot}.\n *\n * Masks and real votes take the same path. This method calls the same server API\n * (previous-ciphertext) for both, so the server cannot infer the ballot type from the request\n * pattern, and the encryption is identical either way.\n *\n * @param request - The ballot to encrypt.\n * @returns A promise that resolves to the prepared ballot.\n */\n async prepareBallot(request: PrepareBallotRequest): Promise<PreparedBallot> {\n const head = await getPreviousCiphertext(this.serverUrl, request.e3Id, request.slotAddress)\n\n // Branched rather than spread conditionally. The two halves of a slot head only mean anything\n // together and the type models them as a pair, which a conditional spread widens back into two\n // independent optional fields — the exact shape the pair exists to rule out.\n return head ? prepareBallot({ ...request, previousCiphertext: head.ciphertext, previousIndex: head.index }) : prepareBallot(request)\n }\n\n /**\n * Phase two: prove a prepared ballot.\n *\n * A mask passes no signature and gets the placeholder. It still carries the same digest as a\n * real vote, because the contract computes the digest for every input.\n *\n * @param prepared - The output of {@link prepareBallot}.\n * @param digest - The digest read from `CRISPProgram.ballotDigest`.\n * @param signature - The voter signature, omitted for a mask.\n * @returns A promise that resolves to the generated proof data.\n */\n async finishBallot(prepared: PreparedBallot, digest: `0x${string}`, signature?: `0x${string}`): Promise<ProofData> {\n return signature ? finishBallotProof(prepared, digest, signature) : finishMaskProof(prepared, digest)\n }\n\n /**\n * Get the current (most recent) round, optionally filtered by requester addresses.\n * @param requesters - Optional list of requester addresses to filter by\n * @returns The current round id, or undefined if no round exists\n */\n async getCurrentRound(requesters?: string[]): Promise<CurrentRoundResponse | undefined> {\n return getCurrentRound(this.serverUrl, requesters)\n }\n\n /**\n * Get the committee public key for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The committee public key bytes\n */\n async getRoundPublicKey(e3Id: bigint): Promise<Uint8Array> {\n return getRoundPublicKey(this.serverUrl, e3Id)\n }\n\n /**\n * Get the ciphertext output for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The ciphertext output bytes\n */\n async getRoundCiphertext(e3Id: bigint): Promise<Uint8Array> {\n return getRoundCiphertext(this.serverUrl, e3Id)\n }\n\n /**\n * Request a new E3 round. Requires the server's cron API key.\n * @param request - The new round request (cron API key, token address and balance threshold)\n * @returns The server confirmation message\n */\n async requestNewRound(request: NewRoundRequest): Promise<JsonResponse> {\n return requestNewRound(this.serverUrl, request)\n }\n\n /**\n * Broadcast an encrypted vote through the CRISP server, which relays it on-chain.\n * @param request - The vote request (round id and hex encoded proof)\n * @returns The broadcast result, including the transaction hash on success\n */\n async broadcastVote(request: BroadcastVoteRequest): Promise<BroadcastVoteResponse> {\n return broadcastVote(this.serverUrl, request)\n }\n\n /**\n * Get the vote status for an address in a specific round.\n * @param e3Id - The e3Id of the round\n * @param address - The voter address\n * @returns The vote status for the address\n */\n async getVoteStatus(e3Id: bigint, address: string): Promise<VoteStatusResponse> {\n return getVoteStatus(this.serverUrl, e3Id, address)\n }\n\n /**\n * Get the result for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The round result (tally, emojis, total votes, end time and requester)\n */\n async getRoundResult(e3Id: bigint): Promise<WebResultResponse> {\n return getRoundResult(this.serverUrl, e3Id)\n }\n\n /**\n * Get the results for all rounds, optionally filtered by requester addresses.\n * @param requesters - Optional list of requester addresses to filter by\n * @returns The results for all matching rounds\n */\n async getAllRoundResults(requesters?: string[]): Promise<WebResultResponse[]> {\n return getAllRoundResults(this.serverUrl, requesters)\n }\n\n /**\n * Get the lite state for a given round, as returned by the server (snake_case fields).\n * @param e3Id - The e3Id of the round\n * @returns The lite round state\n */\n async getRoundStateLite(e3Id: bigint): Promise<E3StateLiteResponse> {\n return getRoundStateLite(this.serverUrl, e3Id)\n }\n\n /**\n * Get the details of a specific round in a camelCase convenience format.\n * @param e3Id - The e3Id of the round\n * @returns The round details\n */\n async getRoundDetails(e3Id: bigint): Promise<RoundDetails> {\n return getRoundDetails(this.serverUrl, e3Id)\n }\n\n /**\n * Get the round data stored in the CRISPProgram contract, read directly from the chain.\n *\n * When the chain id is omitted it is looked up on the CRISP server.\n *\n * @param programAddress - The address of the CRISPProgram contract\n * @param e3Id - The e3Id of the round\n * @param chainId - The chain ID of the network the program is deployed on\n * @returns The on chain round data\n */\n async getOnChainRoundData(programAddress: string, e3Id: bigint, chainId?: number): Promise<OnChainRoundData> {\n const chain = chainId ?? Number((await getRoundDetails(this.serverUrl, e3Id)).chainId)\n\n return getOnChainRoundData(programAddress, e3Id, chain, this.rpcUrl)\n }\n\n /**\n * Get the voting power a slot may spend in a `CensusMode.ONCHAIN` round, read from the CRISP\n * program through this instance's configured endpoint.\n *\n * @param programAddress - The CRISP program address\n * @param e3Id - The e3Id of the round\n * @param slot - The slot address the ballot is written to\n * @param chainId - The chain the program is deployed on; looked up on the server when omitted\n * @returns The spendable voting power in ballot units\n */\n async getOnchainVotingPower(programAddress: string, e3Id: bigint, slot: string, chainId?: number): Promise<bigint> {\n const chain = chainId ?? Number((await getRoundDetails(this.serverUrl, e3Id)).chainId)\n\n return getOnchainVotingPower(programAddress, e3Id, slot, chain, this.rpcUrl)\n }\n\n /**\n * Get the token address, balance threshold and snapshot block for a specific round.\n * @param e3Id - The e3Id of the round\n * @returns The token details\n */\n async getRoundTokenDetails(e3Id: bigint): Promise<TokenDetails> {\n return getRoundTokenDetails(this.serverUrl, e3Id)\n }\n\n /**\n * Get the token holder hashes (hash(address, balance)) for a given round.\n * These are the Merkle tree leaves used for eligibility proofs.\n * @param e3Id - The e3Id of the round\n * @returns The list of token holder hashes\n */\n async getTokenHolderHashes(e3Id: bigint): Promise<string[]> {\n return getTokenHolderHashes(this.serverUrl, e3Id)\n }\n\n /**\n * Get the eligible addresses and their balances for a given round.\n * @param e3Id - The e3Id of the round\n * @returns The list of eligible token holders\n */\n async getEligibleAddresses(e3Id: bigint): Promise<TokenHolder[]> {\n return getEligibleAddresses(this.serverUrl, e3Id)\n }\n\n /**\n * Get the chain head (block number, timestamp, chain id) as seen by the server.\n * @returns The current head\n */\n async getChainHead(): Promise<ChainHead> {\n return getChainHead(this.serverUrl)\n }\n\n /**\n * Read allowlisted contracts through the server, batched, without a provider key of your own.\n * @param calls - The calls to perform, in order\n * @returns One result per call, in the same order\n */\n async readContracts(calls: ContractRead[]): Promise<ContractReadResult[]> {\n return readContracts(this.serverUrl, calls)\n }\n\n /**\n * Query logs for an allowlisted contract over an arbitrary block range. The server windows the\n * range for you, so no chunking is needed on this side.\n * @param query - The log query\n * @returns The matching logs, ordered by block and log index\n */\n async getLogs(query: LogQuery): Promise<IndexedLog[]> {\n return getIndexedLogs(this.serverUrl, query)\n }\n\n /**\n * Resolve a unix timestamp to the last block at or before it.\n * @param timestamp - The unix timestamp\n * @returns The block number and its timestamp\n */\n async getBlockAtTimestamp(timestamp: bigint): Promise<{ blockNumber: bigint; timestamp: bigint }> {\n return getBlockAtTimestamp(this.serverUrl, timestamp)\n }\n\n /**\n * The server's read-only JSON-RPC URL, for pointing a standard Ethereum client at.\n * @returns The JSON-RPC URL\n */\n chainRpcUrl(): string {\n return chainRpcUrl(this.serverUrl)\n }\n\n /**\n * Get the previous ciphertext input for a slot address in a given round.\n * @param e3Id - The e3Id of the round\n * @param address - The address of the slot\n * @returns The slot head and its tree index, or undefined if the slot holds nothing usable\n */\n async getPreviousCiphertext(e3Id: bigint, address: string): Promise<SlotHead | undefined> {\n return getPreviousCiphertext(this.serverUrl, e3Id, address)\n }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport type { LeanIMTMerkleProof } from '@zk-kit/lean-imt'\n\n/**\n * Type representing the details of a specific round in a more convenient format\n * (camelCase view of the server's `state/lite` response)\n */\nexport type RoundDetails = {\n e3Id: bigint\n chainId: bigint\n interfoldAddress: string\n status: string\n voteCount: bigint\n startTime: bigint\n endTime: bigint\n /// The block the E3 was requested at\n startBlock: bigint\n /// The block the census was built at\n snapshotBlock: bigint\n committeePublicKey: Uint8Array\n emojis: [string, string]\n tokenAddress: string\n balanceThreshold: bigint\n numOptions: bigint\n requester: string\n creditMode: CreditMode\n credits?: bigint\n}\n\n/**\n * Type representing the round data stored in the CRISPProgram contract\n */\nexport type OnChainRoundData = {\n /// The merkle root of the census\n merkleRoot: bigint\n /// The hash of the E3 program params\n paramsHash: `0x${string}`\n /// The number of vote options\n numOptions: bigint\n /// The credit mode of the round\n creditMode: CreditMode\n /// The root of the merkle tree holding the encrypted votes\n inputRoot: bigint\n /// The number of votes published on chain\n numberOfVotes: bigint\n}\n\n/**\n * Type representing the token details required for participation in a round\n */\nexport type TokenDetails = {\n tokenAddress: string\n threshold: bigint\n snapshotBlock: bigint\n}\n\n/**\n * Type representing a Merkle proof\n */\nexport type MerkleProof = {\n leaf: bigint\n index: number\n proof: LeanIMTMerkleProof<bigint>\n length: number\n indices: number[]\n}\n\n/**\n * Type representing a vote\n */\nexport type Vote = number[]\n\n/**\n * Type representing a decoded tally: one total per option.\n *\n * @remarks\n * Uses `bigint` because an aggregated tally coefficient is a sum over all ballots,\n * so a total can exceed `Number.MAX_SAFE_INTEGER`. This matches the `BigUint` the\n * CRISP server returns and the `uint256` the CRISP contract returns.\n */\nexport type TallyResult = bigint[]\n\n/**\n * Type representing a vector with coefficients\n */\nexport type Polynomial = {\n coefficients: string[]\n}\n\n/**\n * Type representing cryptographic parameters\n */\nexport type GrecoCryptographicParams = {\n q_mod_t: string\n qis: string[]\n k0is: string[]\n}\n\n/**\n * Type representing Greco bounds\n */\nexport type GrecoBoundParams = {\n e_bound: string\n u_bound: string\n k1_low_bound: string\n k1_up_bound: string\n p1_bounds: string[]\n p2_bounds: string[]\n pk_bounds: string[]\n r1_low_bounds: string[]\n r1_up_bounds: string[]\n r2_bounds: string[]\n}\n\n/**\n * Type representing Greco parameters\n */\nexport type GrecoParams = {\n crypto: GrecoCryptographicParams\n bounds: GrecoBoundParams\n}\n\nexport type ProofData = {\n publicInputs: string[]\n proof: Uint8Array\n encryptedVote: Uint8Array\n /**\n * The tree index of the entry this input extends, plus one; zero when it extends nothing.\n *\n * `CRISPProgram` reads the parent's commitment from this and hands it to the circuit as\n * `prev_ct_commitment`, and the Secure Process walks each slot's chain by it. Offset by one so\n * that zero means \"no parent\", which is what index 0 would otherwise be ambiguous with.\n */\n parentIndexPlusOne: number\n}\n\n/**\n * Which circuit a ballot is built for.\n *\n * `merkle` proves membership of a census tree, and matches `CensusMode.TOKEN` and\n * `CensusMode.BY_REQUESTER`. `onchain` takes voting power as a public input that the contract\n * reads from the token, and matches `CensusMode.ONCHAIN`.\n */\nexport type CensusVariant = 'merkle' | 'onchain'\n\n/**\n * The two halves of a slot head, which only mean anything together.\n *\n * Modelled as a pair rather than two optional fields: a ciphertext without its index would be\n * proven against one entry and published against another, and the mismatch only surfaces as a\n * rejected proof.\n */\ntype SlotHeadInputs =\n | {\n /**\n * The ciphertext currently in the slot: the end of its chain of usable entries, not simply\n * the newest one published. An entry whose bytes do not reproduce its commitment is never\n * selected by the Secure Process and is never a valid parent, so building on it would have\n * this input dropped from the tally.\n */\n previousCiphertext: Uint8Array\n /** The tree index of `previousCiphertext`, which this input names as its parent. */\n previousIndex: number\n }\n | { previousCiphertext?: undefined; previousIndex?: undefined }\n\ntype PrepareBallotInputsBase = {\n publicKey: Uint8Array\n slotAddress: string\n isMaskVote: boolean\n /// Read for a mask, where there is no vote to take a length from.\n numOptions: number\n vote: Vote\n} & SlotHeadInputs\n\n/**\n * Everything needed to encrypt a ballot, before the voter has signed anything.\n */\nexport type PrepareBallotInputs =\n | (PrepareBallotInputsBase & { censusMode: 'merkle'; balance: bigint; merkleLeaves: string[] | bigint[] })\n | (PrepareBallotInputsBase & { censusMode: 'onchain'; votingPower: bigint })\n\n/**\n * A ballot that is encrypted but not yet signed.\n *\n * `ctCommitment` is the value to pass to `CRISPProgram.ballotDigest`. Reading the digest from the\n * contract rather than rebuilding the EIP-712 struct here keeps one implementation of the domain.\n */\nexport type PreparedBallot = {\n circuitInputs: any\n /**\n * The ciphertext to publish, which is the ballot itself for a vote or a re-vote, and the slot's\n * ciphertext plus the zero ballot for a mask over an occupied slot.\n */\n encryptedVote: Uint8Array\n /**\n * The commitment to `encryptedVote`: what the circuit returns, what the E3 program stores, and\n * what `CRISPProgram.ballotDigest` takes as its `ciphertextCommitment` argument.\n *\n * Since the digest is itself a circuit input, a caller has to know this value before proving,\n * which is why the wasm exports it rather than leaving it to be read off the finished proof.\n */\n ctCommitment: `0x${string}`\n /** The value {@link ProofData.parentIndexPlusOne} carries through to `encodeSolidityProof`. */\n parentIndexPlusOne: number\n censusMode: CensusVariant\n}\n\n/**\n * `Omit` that maps over each member of a union instead of collapsing it.\n *\n * A plain `Omit` on a discriminated union merges the members and loses the discriminant, which\n * would let a caller pass `censusMode: 'onchain'` with no `votingPower`.\n */\ntype DistributiveOmit<T, K extends keyof never> = T extends unknown ? Omit<T, K> : never\n\n/**\n * A {@link PrepareBallotInputs} plus the round it belongs to.\n *\n * The SDK resolves the slot head from the server, so callers pass neither part of it.\n */\nexport type PrepareBallotRequest = { e3Id: bigint } & DistributiveOmit<PrepareBallotInputs, 'previousCiphertext' | 'previousIndex'>\n\n/**\n * The end of a slot's chain of usable entries: what a new input extends.\n *\n * Not simply the newest entry published to the slot. An entry whose bytes do not reproduce its\n * commitment is never selected by the Secure Process and is never a valid parent, so the server\n * resolves the chain and answers with the entry that actually holds the slot.\n */\nexport type SlotHead = {\n ciphertext: Uint8Array\n /** The tree index of that entry. */\n index: number\n}\n\n/**\n * Type representing the current round returned by the CRISP server (`rounds/current`)\n */\nexport type CurrentRoundResponse = {\n id: string\n}\n\n/**\n * Type representing the lite state of a round returned by the CRISP server (`state/lite`)\n */\nexport type E3StateLiteResponse = {\n id: string\n chain_id: number\n interfold_address: string\n status: string\n vote_count: number\n start_time: number\n end_time: number\n start_block: number\n snapshot_block: number\n committee_public_key: number[]\n emojis: [string, string]\n token_address: string\n balance_threshold: string\n num_options: string\n requester: string\n credit_mode: CreditMode\n credits: string | null\n}\n\n/**\n * Type representing a generic message response from the CRISP server\n */\nexport type JsonResponse = {\n response: string\n}\n\n/**\n * Type representing a request to start a new E3 round (`rounds/request`)\n */\nexport type NewRoundRequest = {\n cronApiKey: string\n tokenAddress: string\n /** For an ONCHAIN round, doubles as the contract's `minVotingPower` floor in raw token units. */\n balanceThreshold: string\n /**\n * The census source, as a `CRISPProgram.CensusMode` discriminant: 0 (TOKEN, the default) or\n * 2 (ONCHAIN). ONCHAIN reads eligibility from the token per input — with a `SelfRegistry` as\n * the token, that is what lets voters register during the input window. Typed as the literals\n * the server accepts — any other explicit value is refused with HTTP 400.\n */\n censusMode?: 0 | 2\n}\n\n/**\n * Type representing a request to broadcast an encrypted vote (`voting/broadcast`)\n *\n * Carries no address: the slot is already inside the encoded proof, and every byte the relay\n * does not receive is a byte it cannot log against a masker's session.\n */\nexport type BroadcastVoteRequest = {\n e3Id: bigint\n encodedProof: string\n}\n\n/**\n * The status of a vote broadcast returned by the CRISP server\n */\nexport type VoteResponseStatus = 'success' | 'failed_broadcast'\n\n/**\n * Type representing the response to a vote broadcast (`voting/broadcast`)\n */\nexport type BroadcastVoteResponse = {\n status: VoteResponseStatus\n tx_hash: string | null\n message: string | null\n}\n\n/**\n * Type representing the slot activity of an address in a round (`voting/status`)\n *\n * @remarks\n * `slot_active` says the slot holds at least one published entry — not that its owner voted.\n * Masks are indistinguishable from votes by design, so activity is the only per-slot fact the\n * server can answer. A client that wants \"did I vote\" must remember its own submissions.\n */\nexport type VoteStatusResponse = {\n round_id: string\n address: string\n slot_active: boolean\n round_status: string | null\n}\n\n/**\n * Type representing the result of a round (`state/result` and `state/all`)\n */\nexport type WebResultResponse = {\n round_id: string\n tally: string[]\n option_1_emoji: string\n option_2_emoji: string\n total_votes: number\n end_time: number\n requester: string\n}\n\n/**\n * Type representing a token holder with their address and balance (`state/eligible-addresses`)\n */\nexport type TokenHolder = {\n address: string\n balance: string\n}\n\n/**\n * Enum representing the credit mode for a round, which can be either constant or custom.\n * In constant mode, all voters receive the same amount of credits, while in custom mode,\n * the credits can vary based on certain criteria (e.g., voter balance).\n */\nexport enum CreditMode {\n CONSTANT = 0,\n CUSTOM = 1,\n}\n\n/**\n * The chain head as reported by the CRISP server (`chain/head`).\n */\nexport type ChainHead = {\n blockNumber: bigint\n timestamp: bigint\n chainId: number\n}\n\n/**\n * One `eth_call` in a `chain/read` batch. The caller owns the ABI encoding; the server forwards\n * the calldata untouched, so a client can read any view function of an allowlisted contract\n * without the server needing to know its ABI.\n */\nexport type ContractRead = {\n address: string\n data: `0x${string}`\n /** Historical block to read at. Omit for latest. */\n blockNumber?: bigint\n}\n\n/**\n * The outcome of one call in a `chain/read` batch.\n *\n * A revert is reported per call rather than failing the batch, because probing a function a\n * contract may not implement is a normal thing to do (the IVotes and proxy probes both rely on\n * it) and one expected revert must not discard its siblings' results.\n */\nexport type ContractReadResult = {\n result?: `0x${string}`\n error?: string\n}\n\n/**\n * A log as returned by `chain/logs`.\n */\nexport type IndexedLog = {\n address: string\n topics: `0x${string}`[]\n data: `0x${string}`\n blockNumber?: bigint\n transactionHash?: string\n logIndex?: number\n}\n\n/**\n * A `chain/logs` query. The range is unbounded from the caller's side: the server splits it into\n * windows the upstream provider will accept.\n */\nexport type LogQuery = {\n address: string\n /** Positional topic filters; `null`/`undefined` in a position matches anything. */\n topics?: (string | null | undefined)[]\n fromBlock?: bigint\n toBlock?: bigint\n}\n"],"mappings":"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","names":["parseAbi","parseAbi","hexToBytes","hexToBytes","CreditMode"]}
|