@crisp-e3/sdk 0.20.1 → 0.22.0
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.d.ts
CHANGED
|
@@ -267,13 +267,16 @@ type BroadcastVoteRequest = {
|
|
|
267
267
|
/**
|
|
268
268
|
* The status of a vote broadcast returned by the CRISP server
|
|
269
269
|
*/
|
|
270
|
-
type VoteResponseStatus = 'success' | 'failed_broadcast';
|
|
270
|
+
type VoteResponseStatus = 'success' | 'pending_commitment' | 'ready_for_commitment' | 'pending_availability' | 'failed_broadcast';
|
|
271
271
|
/**
|
|
272
272
|
* Type representing the response to a vote broadcast (`voting/broadcast`)
|
|
273
273
|
*/
|
|
274
274
|
type BroadcastVoteResponse = {
|
|
275
275
|
status: VoteResponseStatus;
|
|
276
276
|
tx_hash: string | null;
|
|
277
|
+
job_id: string | null;
|
|
278
|
+
/** Compact proof-commitment payload, present when the voter's wallet must submit it. */
|
|
279
|
+
encoded_proof: string | null;
|
|
277
280
|
message: string | null;
|
|
278
281
|
};
|
|
279
282
|
/**
|
|
@@ -459,12 +462,23 @@ declare const getRoundCiphertext: (serverUrl: string, e3Id: bigint) => Promise<U
|
|
|
459
462
|
*/
|
|
460
463
|
declare const requestNewRound: (serverUrl: string, request: NewRoundRequest) => Promise<JsonResponse>;
|
|
461
464
|
/**
|
|
462
|
-
*
|
|
465
|
+
* Stage an encrypted vote with the CRISP availability service.
|
|
466
|
+
*
|
|
467
|
+
* This call returns after the proof commitment is accepted or the server creates a 10-minute
|
|
468
|
+
* commitment payload for the voter's wallet. The server publishes the ciphertext to Avail and
|
|
469
|
+
* finalizes the input in the background after the commitment lands.
|
|
463
470
|
* @param serverUrl - The base URL of the CRISP server
|
|
464
471
|
* @param request - The vote request (round id and hex encoded proof)
|
|
465
472
|
* @returns The broadcast result, including the transaction hash on success
|
|
466
473
|
*/
|
|
467
474
|
declare const broadcastVote: (serverUrl: string, request: BroadcastVoteRequest) => Promise<BroadcastVoteResponse>;
|
|
475
|
+
/**
|
|
476
|
+
* Read a durable vote availability job without waiting for VectorX finalization.
|
|
477
|
+
* @param serverUrl The base URL of the CRISP server.
|
|
478
|
+
* @param jobId The job id returned by {@link broadcastVote}.
|
|
479
|
+
* @returns The current commitment or availability state.
|
|
480
|
+
*/
|
|
481
|
+
declare const getVoteAvailability: (serverUrl: string, jobId: string) => Promise<BroadcastVoteResponse>;
|
|
468
482
|
/**
|
|
469
483
|
* Get the vote status for an address in a specific round.
|
|
470
484
|
* @param serverUrl - The base URL of the CRISP server
|
|
@@ -861,6 +875,12 @@ declare class CrispSDK {
|
|
|
861
875
|
* @returns The broadcast result, including the transaction hash on success
|
|
862
876
|
*/
|
|
863
877
|
broadcastVote(request: BroadcastVoteRequest): Promise<BroadcastVoteResponse>;
|
|
878
|
+
/**
|
|
879
|
+
* Read a durable availability job without waiting for Avail or VectorX.
|
|
880
|
+
* @param jobId - The job id returned by `broadcastVote`
|
|
881
|
+
* @returns The job's current commitment or availability state
|
|
882
|
+
*/
|
|
883
|
+
getVoteAvailability(jobId: string): Promise<BroadcastVoteResponse>;
|
|
864
884
|
/**
|
|
865
885
|
* Get the vote status for an address in a specific round.
|
|
866
886
|
* @param e3Id - The e3Id of the round
|
|
@@ -974,4 +994,4 @@ declare class CrispSDK {
|
|
|
974
994
|
getPreviousCiphertext(e3Id: bigint, address: string): Promise<SlotHead | undefined>;
|
|
975
995
|
}
|
|
976
996
|
|
|
977
|
-
export { type BroadcastVoteRequest, type BroadcastVoteResponse, type CensusVariant, type ChainHead, type ContractRead, type ContractReadResult, CreditMode, CrispSDK, type CurrentRoundResponse, type E3StateLiteResponse, type IndexedLog, type JsonResponse, type LogQuery, MAX_MSG_NON_ZERO_COEFFS, MAX_VOTE_OPTIONS, MERKLE_TREE_MAX_DEPTH, type NewRoundRequest, type OnChainRoundData, type PrepareBallotInputs, type PrepareBallotRequest, type PreparedBallot, type ProofData, type RoundDetails, SERVER_RPC, SIGNATURE_MESSAGE, SIGNATURE_MESSAGE_HASH, type SlotHead, type TallyResult, type TokenDetails, type TokenHolder, type Vote, type VoteResponseStatus, type VoteStatusResponse, type WebResultResponse, broadcastVote, chainRpcUrl, decodeTally, decryptVote, destroyBBApi, encodeSolidityProof, encodeVote, encryptVote, finishBallotProof, finishMaskProof, generateBFVKeys, generateMerkleProof, generateMerkleTree, getAddressFromSignature, getAllRoundResults, getBalanceAt, getBlockAtTimestamp, getChainHead, getCurrentRound, getEligibleAddresses, getIndexedLogs, getMaxVoteValue, getOnChainRoundData, getOnchainVotingPower, getPreviousCiphertext, getRoundCiphertext, getRoundDetails, getRoundPublicKey, getRoundResult, getRoundStateLite, getRoundTokenDetails, getScaledBalance, getTokenHolderHashes, getTotalSupplyAt, getTreeData, getVoteStatus, getZeroVote, hashLeaf, prepareBallot, prepareCircuitInputs, readContracts, requestNewRound, splitDigest, validateVote, verifyProof };
|
|
997
|
+
export { type BroadcastVoteRequest, type BroadcastVoteResponse, type CensusVariant, type ChainHead, type ContractRead, type ContractReadResult, CreditMode, CrispSDK, type CurrentRoundResponse, type E3StateLiteResponse, type IndexedLog, type JsonResponse, type LogQuery, MAX_MSG_NON_ZERO_COEFFS, MAX_VOTE_OPTIONS, MERKLE_TREE_MAX_DEPTH, type NewRoundRequest, type OnChainRoundData, type PrepareBallotInputs, type PrepareBallotRequest, type PreparedBallot, type ProofData, type RoundDetails, SERVER_RPC, SIGNATURE_MESSAGE, SIGNATURE_MESSAGE_HASH, type SlotHead, type TallyResult, type TokenDetails, type TokenHolder, type Vote, type VoteResponseStatus, type VoteStatusResponse, type WebResultResponse, broadcastVote, chainRpcUrl, decodeTally, decryptVote, destroyBBApi, encodeSolidityProof, encodeVote, encryptVote, finishBallotProof, finishMaskProof, generateBFVKeys, generateMerkleProof, generateMerkleTree, getAddressFromSignature, getAllRoundResults, getBalanceAt, getBlockAtTimestamp, getChainHead, getCurrentRound, getEligibleAddresses, getIndexedLogs, getMaxVoteValue, getOnChainRoundData, getOnchainVotingPower, getPreviousCiphertext, getRoundCiphertext, getRoundDetails, getRoundPublicKey, getRoundResult, getRoundStateLite, getRoundTokenDetails, getScaledBalance, getTokenHolderHashes, getTotalSupplyAt, getTreeData, getVoteAvailability, getVoteStatus, getZeroVote, hashLeaf, prepareBallot, prepareCircuitInputs, readContracts, requestNewRound, splitDigest, validateVote, verifyProof };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ var CRISP_SERVER_STATE_RESULT_ENDPOINT = "state/result";
|
|
|
23
23
|
var CRISP_SERVER_STATE_ALL_ENDPOINT = "state/all";
|
|
24
24
|
var CRISP_SERVER_ELIGIBLE_ADDRESSES_ENDPOINT = "state/eligible-addresses";
|
|
25
25
|
var CRISP_SERVER_VOTING_BROADCAST_ENDPOINT = "voting/broadcast";
|
|
26
|
+
var CRISP_SERVER_VOTING_AVAILABILITY_ENDPOINT = "voting/availability";
|
|
26
27
|
var CRISP_SERVER_VOTING_STATUS_ENDPOINT = "voting/status";
|
|
27
28
|
var CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT = "rounds/current";
|
|
28
29
|
var CRISP_SERVER_ROUNDS_PUBLIC_KEY_ENDPOINT = "rounds/public-key";
|
|
@@ -124,6 +125,34 @@ var postJson = async (serverUrl, endpoint, body) => {
|
|
|
124
125
|
}
|
|
125
126
|
return await response.json();
|
|
126
127
|
};
|
|
128
|
+
var isLoopbackHost = (host) => {
|
|
129
|
+
const normalized = host.toLowerCase().replace(/^\[|\]$/g, "");
|
|
130
|
+
if (normalized === "localhost" || normalized === "::1") return true;
|
|
131
|
+
const octets = normalized.split(".");
|
|
132
|
+
return octets.length === 4 && octets[0] === "127" && octets.every((octet) => /^\d+$/.test(octet) && Number(octet) <= 255);
|
|
133
|
+
};
|
|
134
|
+
var authenticatedEndpointUrl = (serverUrl, endpoint) => {
|
|
135
|
+
let url;
|
|
136
|
+
try {
|
|
137
|
+
url = new URL(serverUrl);
|
|
138
|
+
} catch {
|
|
139
|
+
throw new Error("CRISP server URL must be an absolute HTTP or HTTPS URL");
|
|
140
|
+
}
|
|
141
|
+
if (url.username || url.password) {
|
|
142
|
+
throw new Error("CRISP server URL must not contain user information");
|
|
143
|
+
}
|
|
144
|
+
if (url.href.includes("?") || url.href.includes("#")) {
|
|
145
|
+
throw new Error("CRISP server URL must not contain a query or fragment");
|
|
146
|
+
}
|
|
147
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
148
|
+
throw new Error("CRISP server URL must use HTTP or HTTPS");
|
|
149
|
+
}
|
|
150
|
+
if (url.protocol === "http:" && !isLoopbackHost(url.hostname)) {
|
|
151
|
+
throw new Error("CRISP server URL must use HTTPS unless its host is loopback");
|
|
152
|
+
}
|
|
153
|
+
url.pathname = `${url.pathname.replace(/\/+$/, "")}/${endpoint.replace(/^\/+/, "")}`;
|
|
154
|
+
return url.toString();
|
|
155
|
+
};
|
|
127
156
|
var getCurrentRound = async (serverUrl, requesters = []) => {
|
|
128
157
|
const response = await fetch(`${serverUrl}/${CRISP_SERVER_ROUNDS_CURRENT_ENDPOINT}`, {
|
|
129
158
|
method: "POST",
|
|
@@ -154,12 +183,28 @@ var getRoundCiphertext = async (serverUrl, e3Id) => {
|
|
|
154
183
|
});
|
|
155
184
|
return new Uint8Array(data.ct_bytes);
|
|
156
185
|
};
|
|
157
|
-
var requestNewRound = async (serverUrl, request) =>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
186
|
+
var requestNewRound = async (serverUrl, request) => {
|
|
187
|
+
const endpointUrl = authenticatedEndpointUrl(serverUrl, CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT);
|
|
188
|
+
const response = await fetch(endpointUrl, {
|
|
189
|
+
method: "POST",
|
|
190
|
+
redirect: "error",
|
|
191
|
+
headers: {
|
|
192
|
+
"Content-Type": "application/json"
|
|
193
|
+
},
|
|
194
|
+
body: JSON.stringify({
|
|
195
|
+
cron_api_key: request.cronApiKey,
|
|
196
|
+
token_address: request.tokenAddress,
|
|
197
|
+
balance_threshold: request.balanceThreshold,
|
|
198
|
+
census_mode: request.censusMode
|
|
199
|
+
})
|
|
200
|
+
});
|
|
201
|
+
if (!response.ok) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`CRISP server request to /${CRISP_SERVER_ROUNDS_REQUEST_ENDPOINT} failed (${response.status}): ${await response.text()}`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
return await response.json();
|
|
207
|
+
};
|
|
163
208
|
var broadcastVote = async (serverUrl, request) => {
|
|
164
209
|
const response = await fetch(`${serverUrl}/${CRISP_SERVER_VOTING_BROADCAST_ENDPOINT}`, {
|
|
165
210
|
method: "POST",
|
|
@@ -177,6 +222,13 @@ var broadcastVote = async (serverUrl, request) => {
|
|
|
177
222
|
}
|
|
178
223
|
return data;
|
|
179
224
|
};
|
|
225
|
+
var getVoteAvailability = async (serverUrl, jobId) => {
|
|
226
|
+
const response = await fetch(`${serverUrl}/${CRISP_SERVER_VOTING_AVAILABILITY_ENDPOINT}/${encodeURIComponent(jobId)}`);
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
throw new Error(`Failed to read availability job (${response.status}): ${await response.text()}`);
|
|
229
|
+
}
|
|
230
|
+
return await response.json();
|
|
231
|
+
};
|
|
180
232
|
var getVoteStatus = async (serverUrl, e3Id, address) => postJson(serverUrl, CRISP_SERVER_VOTING_STATUS_ENDPOINT, { round_id: e3Id.toString(), address });
|
|
181
233
|
var getRoundResult = async (serverUrl, e3Id) => postJson(serverUrl, CRISP_SERVER_STATE_RESULT_ENDPOINT, { round_id: e3Id.toString() });
|
|
182
234
|
var getAllRoundResults = async (serverUrl, requesters = []) => postJson(serverUrl, CRISP_SERVER_STATE_ALL_ENDPOINT, { requesters });
|
|
@@ -323,13 +375,18 @@ var hashLeaf = (address, balance) => {
|
|
|
323
375
|
var generateMerkleTree = (leaves) => {
|
|
324
376
|
return new LeanIMT((a, b) => poseidon2([a, b]), leaves);
|
|
325
377
|
};
|
|
378
|
+
var parseMerkleLeaf = (leaf) => {
|
|
379
|
+
if (typeof leaf === "bigint" || leaf.startsWith("0x")) return BigInt(leaf);
|
|
380
|
+
return /^[0-9a-fA-F]{64}$/.test(leaf) ? BigInt(`0x${leaf}`) : BigInt(leaf);
|
|
381
|
+
};
|
|
326
382
|
var generateMerkleProof = (balance, address, leaves) => {
|
|
327
383
|
const leaf = hashLeaf(address.toLowerCase(), balance);
|
|
328
|
-
const
|
|
384
|
+
const parsedLeaves = leaves.map(parseMerkleLeaf);
|
|
385
|
+
const index = parsedLeaves.findIndex((candidate) => candidate === leaf);
|
|
329
386
|
if (index === -1) {
|
|
330
387
|
throw new Error("Leaf not found in the tree");
|
|
331
388
|
}
|
|
332
|
-
const tree = generateMerkleTree(
|
|
389
|
+
const tree = generateMerkleTree(parsedLeaves);
|
|
333
390
|
const proof = tree.generateProof(index);
|
|
334
391
|
const paddedSiblings = [...proof.siblings, ...Array(MERKLE_TREE_MAX_DEPTH - proof.siblings.length).fill(0n)];
|
|
335
392
|
const indices = proof.siblings.map((_, i) => Number(BigInt(proof.index) >> BigInt(i) & 1n));
|
|
@@ -578,7 +635,7 @@ var crisp_onchain_fold_default = { noir_version: "1.0.0-beta.26+40d6574f851d926f
|
|
|
578
635
|
var user_data_encryption_default = { 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: "/Users/hmza/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" }] } } };
|
|
579
636
|
|
|
580
637
|
// src/vote.ts
|
|
581
|
-
import { bytesToHex, encodeAbiParameters, parseAbiParameters, numberToHex, getAddress } from "viem/utils";
|
|
638
|
+
import { bytesToHex, encodeAbiParameters, parseAbiParameters, numberToHex, getAddress, keccak256 } from "viem/utils";
|
|
582
639
|
var _bbApi = null;
|
|
583
640
|
var _bbApiInitPromise = null;
|
|
584
641
|
var getBBApi = async () => {
|
|
@@ -815,12 +872,15 @@ var verifyProof = async (proof, censusMode = "merkle") => {
|
|
|
815
872
|
var encodeSolidityProof = ({ publicInputs, proof, encryptedVote, parentIndexPlusOne }) => {
|
|
816
873
|
const slotAddress = getAddress(numberToHex(BigInt(publicInputs[3]), { size: 20 }));
|
|
817
874
|
const encryptedVoteCommitment = publicInputs[7];
|
|
818
|
-
|
|
875
|
+
const encryptedVoteBytes = bytesToHex(encryptedVote);
|
|
876
|
+
const encryptedVoteHash = keccak256(encryptedVoteBytes);
|
|
877
|
+
return encodeAbiParameters(parseAbiParameters("bytes, address, bytes32, bytes32, uint40, bytes"), [
|
|
819
878
|
bytesToHex(proof),
|
|
820
879
|
slotAddress,
|
|
821
880
|
encryptedVoteCommitment,
|
|
822
|
-
|
|
823
|
-
parentIndexPlusOne
|
|
881
|
+
encryptedVoteHash,
|
|
882
|
+
parentIndexPlusOne,
|
|
883
|
+
encryptedVoteBytes
|
|
824
884
|
]);
|
|
825
885
|
};
|
|
826
886
|
|
|
@@ -927,6 +987,14 @@ var CrispSDK = class {
|
|
|
927
987
|
async broadcastVote(request) {
|
|
928
988
|
return broadcastVote(this.serverUrl, request);
|
|
929
989
|
}
|
|
990
|
+
/**
|
|
991
|
+
* Read a durable availability job without waiting for Avail or VectorX.
|
|
992
|
+
* @param jobId - The job id returned by `broadcastVote`
|
|
993
|
+
* @returns The job's current commitment or availability state
|
|
994
|
+
*/
|
|
995
|
+
async getVoteAvailability(jobId) {
|
|
996
|
+
return getVoteAvailability(this.serverUrl, jobId);
|
|
997
|
+
}
|
|
930
998
|
/**
|
|
931
999
|
* Get the vote status for an address in a specific round.
|
|
932
1000
|
* @param e3Id - The e3Id of the round
|
|
@@ -1122,6 +1190,7 @@ export {
|
|
|
1122
1190
|
getTokenHolderHashes,
|
|
1123
1191
|
getTotalSupplyAt,
|
|
1124
1192
|
getTreeData,
|
|
1193
|
+
getVoteAvailability,
|
|
1125
1194
|
getVoteStatus,
|
|
1126
1195
|
getZeroVote,
|
|
1127
1196
|
hashLeaf,
|