feat: get previous ciphertext from server [skip-line-limit]#1109
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
WalkthroughAdds previous-ciphertext & slot-empty support and masking/update vote flows across CRISP: introduces a Vote type and ZERO_VOTE, moves per-vote message hashing/signing, exposes server endpoints, adds CrispSDK orchestrator that queries slot state and obtains or derives previous ciphertext, and extends ZK inputs (GRECO→BFV) with an update path. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client (Hook / Worker)
participant SDK as CrispSDK
participant Server as State API
participant Contract as CRISPProgram (on-chain)
participant ZK as ZK Inputs & Proof
Client->>+SDK: request generateVoteProof / generateMaskVoteProof (vote, e3Id, publicKey, slotAddress...)
SDK->>+Server: POST getIsSlotEmpty(e3Id, slotAddress)
Server->>+Contract: isSlotEmptyByAddress(e3Id, slotAddress)
Contract-->>-Server: is_empty
Server-->>-SDK: is_empty
alt slot not empty
SDK->>+Server: POST getPreviousCiphertext(e3Id, slotAddress)
Server->>Server: repo.get_ciphertext_input(index)
Server-->>-SDK: previousCiphertext
SDK->>SDK: isFirstVote = false
else slot empty
SDK->>SDK: previousCiphertext = encryptVote(ZERO_VOTE, publicKey)
SDK->>SDK: isFirstVote = true
end
SDK->>+ZK: generate_inputs_for_update(...) or generate_inputs(..., previousCiphertext, isFirstVote)
ZK->>ZK: build inputs (GRECO decode, BFV convert, ciphertext add)
ZK->>ZK: executeCircuit() / generate proof
ZK-->>-SDK: ProofData
SDK-->>-Client: ProofData
Client->>Client: broadcast proof on-chain
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
744a618 to
55c02a4
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (6)
examples/CRISP/crates/zk-inputs/src/lib.rs (2)
97-115: Minor: DuplicateGrecoBounds::computecalls.
GrecoBounds::computeis invoked twice: once at line 97 (discardingcrypto_params) and again at line 114. Consider computing once and reusing both values:- let (_, bounds) = GrecoBounds::compute(&self.bfv_params, 0)?; - - let bit_pk = shared::template::calculate_bit_width(&bounds.pk_bounds[0].to_string())?; - - // Compute the vectors of the GRECO inputs. - let greco_vectors = GrecoVectors::compute( - ... - ) - .with_context(|| "Failed to compute vectors")?; - - let (crypto_params, bounds) = GrecoBounds::compute(&self.bfv_params, 0) - .with_context(|| "Failed to compute bounds")?; + let (crypto_params, bounds) = GrecoBounds::compute(&self.bfv_params, 0) + .with_context(|| "Failed to compute bounds")?; + + let bit_pk = shared::template::calculate_bit_width(&bounds.pk_bounds[0].to_string())?; + + // Compute the vectors of the GRECO inputs. + let greco_vectors = GrecoVectors::compute( + ... + ) + .with_context(|| "Failed to compute vectors")?;Note: The same duplication exists in
generate_inputs(lines 169 and 186-187).
78-139: Add test coverage forgenerate_inputs_for_masking.The new method uses a different code path than
generate_inputs, specifically the GRECO ciphertext decoding and conversion (abi_decode_greco_ciphertextandgreco_to_bfv_ciphertext). The existing tests only covergenerate_inputs. Add tests to validate the GRECO decoding and conversion functionality ingenerate_inputs_for_masking.examples/CRISP/server/src/server/routes/state.rs (1)
74-84: Potential panic on slot index conversion.The conversion
.to::<u64>()on aU256value will panic if the value exceedsu64::MAX. While slot indices are unlikely to reach such values in practice, using a safer conversion would be more robust.Consider using a checked conversion:
let slot_index = match contract .get_slot_index_from_address(U256::from(incoming.round_id), address) .await { - Ok(index) => index.to::<u64>(), + Ok(index) => { + if index > U256::from(u64::MAX) { + error!("Slot index exceeds u64 range: {:?}", index); + return HttpResponse::InternalServerError() + .body("Slot index out of range"); + } + index.to::<u64>() + } Err(e) => { error!("Error getting slot index from address: {:?}", e); return HttpResponse::InternalServerError() .body("Failed to get slot index from address"); } };examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (1)
149-166: Redundant optional chaining and unclear error handling for vote updates.Two concerns with this block:
Line 156 has redundant optional chaining:
previousCiphertextFromServer && previousCiphertextFromServer?.ciphertext- the?.is unnecessary since the left side of&&already ensures the value is truthy.If
isVoteUpdateis true butgetPreviousCiphertextfails (returns undefined), the vote proceeds without the previous ciphertext. Should this be an error condition for vote updates?const previousCiphertextFromServer = isVoteUpdate ? await getPreviousCiphertext({ round_id: roundState.id, address: user.address, }) : undefined - const previousCiphertext = previousCiphertextFromServer && previousCiphertextFromServer?.ciphertext + const previousCiphertext = previousCiphertextFromServer?.ciphertext + + if (isVoteUpdate && !previousCiphertext) { + throw new Error('Failed to retrieve previous vote data for update.') + } const encodedProof = await handleProofGeneration(examples/CRISP/packages/crisp-sdk/src/vote.ts (2)
104-111: Clarify placeholder ciphertext semantics and isFirstVote couplingYou now always pass
encryptVote(zeroVote, proofInputs.publicKey)intogenerateInputsand setcrispInputs.is_first_vote = proofInputs.isFirstVote. The comment still talks about “previous ciphertext is not provided (is_first_vote is true)”, but there’s no previous-ciphertext wiring in this path anymore.I’d suggest:
- Updating the comment to explicitly describe that normal-vote proofs always start from a zero-vote ciphertext and rely purely on
isFirstVotefor circuit branching.- Double‑checking that all call sites reliably set
isFirstVotein line with how the circuit interpretsis_first_vote, since it’s no longer derived from data availability.Also applies to: 124-128
133-157: Tighten masking invariants around previousCiphertext and document fixed-signature / Merkle placeholdersNice consolidation of the masking inputs. A couple of robustness points to consider:
- For non‑first votes, silently defaulting to
encryptVote(zeroVote, publicKey)whenpreviousCiphertextis missing could make upstream bugs harder to spot. It may be safer to derive the base ciphertext fromisFirstVoteand throw if!isFirstVote && !previousCiphertext:- let crispInputs = await zkInputsGenerator.generateInputsForMasking( - proofInputs.previousCiphertext || encryptVote(zeroVote, proofInputs.publicKey), - proofInputs.publicKey, - encodedVote, - ) + const baseCiphertext = + proofInputs.isFirstVote + ? encryptVote(zeroVote, proofInputs.publicKey) + : proofInputs.previousCiphertext + + if (!baseCiphertext) { + throw new Error('Masking proof for non-first vote requires previousCiphertext') + } + + let crispInputs = await zkInputsGenerator.generateInputsForMasking( + baseCiphertext, + proofInputs.publicKey, + encodedVote, + )
You hard‑code
merkle_proof_length = '0'and zero‑fillmerkle_proof_indices/siblingstoMERKLE_TREE_MAX_DEPTH. It would be good to confirm that this depth matches the circuit’s compiled constant and that “no Merkle proof” is indeed represented exactly this way.Using fixed
MASK_SIGNATURE/SIGNATURE_MESSAGE_HASHwhile takingslot_addressandbalancefromproofInputsdecouples masking proofs from the user’s actual signature. Please confirm that the circuit / contract logic for masking flows is intentionally keyed off these constants (and/or other inputs) and does not expect a per-user signature as in the normal vote path.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
examples/CRISP/client/libs/crispWorker.js(2 hunks)examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts(1 hunks)examples/CRISP/client/src/hooks/enclave/useEnclaveServer.ts(3 hunks)examples/CRISP/client/src/hooks/voting/useVoteCasting.ts(6 hunks)examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx(2 hunks)examples/CRISP/client/src/model/vote.model.ts(1 hunks)examples/CRISP/crates/evm_helpers/src/lib.rs(4 hunks)examples/CRISP/crates/zk-inputs-wasm/src/lib.rs(2 hunks)examples/CRISP/crates/zk-inputs/src/lib.rs(2 hunks)examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol(2 hunks)examples/CRISP/packages/crisp-sdk/src/constants.ts(1 hunks)examples/CRISP/packages/crisp-sdk/src/types.ts(2 hunks)examples/CRISP/packages/crisp-sdk/src/vote.ts(5 hunks)examples/CRISP/server/src/server/models.rs(1 hunks)examples/CRISP/server/src/server/repo.rs(1 hunks)examples/CRISP/server/src/server/routes/state.rs(2 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2024-09-26T03:11:29.311Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-09-26T03:11:29.311Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
Applied to files:
examples/CRISP/server/src/server/models.rs
📚 Learning: 2024-10-22T03:30:45.478Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/src/repository.rs:58-60
Timestamp: 2024-10-22T03:30:45.478Z
Learning: In `packages/ciphernode/data/src/repository.rs`, the `write` method in `Repository<T>` must be synchronous and should not return errors.
Applied to files:
examples/CRISP/server/src/server/repo.rs
📚 Learning: 2025-11-12T10:08:30.720Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 996
File: examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol:144-169
Timestamp: 2025-11-12T10:08:30.720Z
Learning: In the CRISP program (examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol), there are plans to move the merkle tree from the Enclave contract to the program contract itself in the future, which would allow direct calls to validateInput to be stored in the merkle tree.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rs
📚 Learning: 2024-10-22T03:17:41.617Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/hooks.rs:0-0
Timestamp: 2024-10-22T03:17:41.617Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, in the `hydrate` methods of the `E3Feature` implementations, it's acceptable to return `Ok(())` when dependencies are missing, as the error is reported to the bus.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
🧬 Code graph analysis (7)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)
examples/CRISP/crates/zk-inputs/src/lib.rs (1)
generate_inputs_for_masking(78-139)
examples/CRISP/crates/zk-inputs/src/lib.rs (2)
crates/bfv-helpers/src/utils/greco.rs (2)
abi_decode_greco_ciphertext(125-183)greco_to_bfv_ciphertext(68-103)examples/CRISP/crates/zk-inputs/src/serialization.rs (2)
construct_inputs(60-261)serialize_inputs_to_json(270-272)
examples/CRISP/client/libs/crispWorker.js (3)
examples/CRISP/packages/crisp-sdk/src/index.ts (3)
hashLeaf(10-10)generateMaskVoteProof(14-14)generateVoteProof(13-13)examples/CRISP/packages/crisp-sdk/src/utils.ts (1)
hashLeaf(20-22)examples/CRISP/packages/crisp-sdk/src/vote.ts (2)
generateMaskVoteProof(203-209)generateVoteProof(176-201)
examples/CRISP/client/src/hooks/enclave/useEnclaveServer.ts (2)
examples/CRISP/client/src/hooks/generic/useFetchApi.tsx (1)
useApi(11-33)examples/CRISP/client/src/model/vote.model.ts (2)
GetPreviousCiphertextRequest(67-70)GetPreviousCiphertextResponse(72-74)
examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (3)
examples/CRISP/client/src/hooks/enclave/useEnclaveServer.ts (1)
useEnclaveServer(35-58)examples/CRISP/client/src/model/poll.model.ts (1)
Poll(32-36)packages/enclave-sdk/src/index.ts (1)
generateProof(69-69)
examples/CRISP/server/src/server/routes/state.rs (2)
examples/CRISP/crates/evm_helpers/src/lib.rs (2)
create_read(154-159)address(136-138)crates/config/src/app_config.rs (1)
address(298-300)
examples/CRISP/packages/crisp-sdk/src/types.ts (1)
examples/CRISP/packages/crisp-sdk/src/index.ts (1)
MaskVoteProofInputs(21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: crisp_unit
- GitHub Check: integration_prebuild
- GitHub Check: build_sdk
- GitHub Check: test_net
- GitHub Check: build_enclave_cli
- GitHub Check: rust_unit
- GitHub Check: rust_integration
- GitHub Check: build_ciphernode_image
- GitHub Check: Build & Push Image
🔇 Additional comments (18)
examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (1)
240-251: LGTM!The
getSlotIndexfunction correctly implements the inverse of the storage logic in_processVote, properly handling thestoredIndexPlusOne - 1offset pattern. TheSlotIsEmptyerror provides clear feedback when querying non-existent slots.examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)
75-98: LGTM!The WASM binding correctly mirrors the pattern of
generateInputs, delegating to the coregenerate_inputs_for_maskingmethod with appropriate type conversions and error handling.examples/CRISP/crates/evm_helpers/src/lib.rs (1)
37-45: LGTM!The generic refactoring cleanly separates read-only and write capabilities. The type aliases and separate impl blocks provide a clear API boundary while the generic
address()method remains available for both variants.Also applies to: 62-65, 106-116, 134-139
examples/CRISP/packages/crisp-sdk/src/constants.ts (1)
37-38: LGTM!The
zeroVoteconstant provides a clean baseline for masking operations, consistent with the BigInt usage pattern established byMAXIMUM_VOTE_VALUE.examples/CRISP/client/libs/crispWorker.js (1)
14-14: Rename fromaddresstoslotAddressaligns with SDK usage.The destructuring correctly renames
addresstoslotAddressand adds the newpreviousCiphertext,isFirstVote, andisMaskingfields needed for the branching proof generation logic.examples/CRISP/client/src/model/vote.model.ts (1)
67-74: New interfaces for previous ciphertext retrieval look correct.The
GetPreviousCiphertextRequestandGetPreviousCiphertextResponseinterfaces follow the existing naming conventions and field patterns used in this file. UsingUint8Arrayforciphertextis appropriate for binary data on the client side.examples/CRISP/server/src/server/models.rs (1)
108-117: New request/response structs align with client-side types.The
PreviousCiphertextRequestandPreviousCiphertextResponsestructs correctly mirror the client-side TypeScript interfaces. The response struct only derivingSerialize(notDeserialize) is appropriate for a response-only type.examples/CRISP/packages/crisp-sdk/src/types.ts (3)
180-180: Addition ofisFirstVotetoProofInputsis consistent with the proof generation flow.The
isFirstVoteboolean enables the circuit to distinguish between first votes and subsequent votes, supporting the masking functionality.
183-190:MaskVoteProofInputsupdated withisFirstVoteandmerkleRoot.Adding
isFirstVoteandmerkleRoottoMaskVoteProofInputsaligns with the circuit input requirements for the masking proof pathway. ThemerkleRootas abigintis appropriate for cryptographic use.
192-201:VoteProofInputsnow includesisFirstVote.The addition maintains consistency with the other proof input types and enables proper circuit behavior for both first and subsequent votes.
examples/CRISP/client/src/hooks/enclave/useEnclaveServer.ts (1)
45-46: LGTM!The new
getPreviousCiphertextfunction follows the established patterns in this hook, correctly using the typed request/response interfaces and POST method consistent with other endpoints.examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts (1)
40-49: LGTM!The updated
generateProofsignature correctly places the new required boolean parameters (isFirstVote,isMasking) before the optionalpreviousCiphertextparameter, maintaining proper TypeScript conventions.examples/CRISP/client/src/hooks/wasm/useWebAssembly.tsx (1)
26-46: LGTM!The updated
generateProoffunction signature and worker message payload correctly include the newisFirstVoteandisMaskingparameters, maintaining consistency with the type definition and enabling the worker to conditionally select the appropriate proof generation path.examples/CRISP/server/src/server/routes/state.rs (1)
42-98: LGTM on overall structure and error handling.The endpoint implementation correctly validates input, handles errors with appropriate HTTP status codes (400 for bad input, 404 for missing data, 500 for internal errors), and follows the patterns established by other handlers in this file.
examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (2)
72-95: LGTM on handleProofGeneration signature update.The callback correctly propagates
isFirstVoteandisMaskingparameters togenerateProof, maintaining consistency with the updated type definition.
243-256: LGTM on dependency array update.The
getPreviousCiphertextfunction is correctly added to theuseCallbackdependency array since it's used withincastVoteWithProof.examples/CRISP/packages/crisp-sdk/src/vote.ts (2)
10-17: New constants import is consistent with usagesAll imported constants (
MAXIMUM_VOTE_VALUE,HALF_LARGEST_MINIMUM_DEGREE,MASK_SIGNATURE,zeroVote,SIGNATURE_MESSAGE_HASH,MERKLE_TREE_MAX_DEPTH) are used below and match the surrounding patterns; no issues here.
203-208: Refactor of generateMaskVoteProof looks goodDelegating to
generateCircuitInputsForMaskingkeeps all masking‑specific input wiring in one place and avoids duplicating constants / Merkle placeholder setup. This improves maintainability of the masking path.
Pull request was converted to draft
df1962c to
de8e904
Compare
de8e904 to
26ade67
Compare
af323a8 to
e569105
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (7)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)
75-98: LGTM! New WASM binding for update input generation.The
generate_inputs_for_updatemethod correctly mirrors the existinggenerate_inputspattern and properly delegates to the core generator. The vote conversion fromVec<i64>toVec<u64>is consistent with the existing implementation.Consider adding a WASM test case for this new method similar to
test_js_inputs_generation_with_defaultsto verify the end-to-end flow with GRECO-encoded ciphertext.examples/CRISP/crates/zk-inputs/src/lib.rs (1)
97-115: RedundantGrecoBounds::computecall.
GrecoBounds::computeis invoked twice with identical parameters (lines 97 and 114). The first call extracts onlyboundsfor bit width calculation, but then bothcrypto_paramsandboundsare recomputed on line 114.Consider computing once and reusing:
🔎 Suggested refactor
- let (_, bounds) = GrecoBounds::compute(&self.bfv_params, 0)?; - - let bit_pk = shared::template::calculate_bit_width(&bounds.pk_bounds[0].to_string())?; - - // ... greco_vectors computation ... - - let (crypto_params, bounds) = GrecoBounds::compute(&self.bfv_params, 0) - .with_context(|| "Failed to compute bounds")?; + let (crypto_params, bounds) = GrecoBounds::compute(&self.bfv_params, 0) + .with_context(|| "Failed to compute bounds")?; + + let bit_pk = shared::template::calculate_bit_width(&bounds.pk_bounds[0].to_string())?;examples/CRISP/client/libs/crispSDKWorker.js (1)
16-21: Note: Hardcoded merkle leaves remain.The TODO comment indicates this is known technical debt. The first leaf correctly uses the dynamic
slotAddressandbalance, which is an improvement.Would you like me to open an issue to track implementing server-side merkle leaf retrieval?
examples/CRISP/server/src/server/routes/state.rs (1)
54-71: Consider extracting common helper for contract creation and address parsing.Both
handle_get_previous_ciphertextandhandle_is_slot_emptyduplicate the contract creation and address parsing logic. Extracting these into helper functions would reduce duplication.🔎 Suggested helpers
async fn get_crisp_contract() -> Result<CRISPContract<CRISPReadProvider>, HttpResponse> { CRISPContractFactory::create_read(&CONFIG.http_rpc_url, &CONFIG.e3_program_address) .await .map_err(|e| { error!("Failed to create CRISP contract: {:?}", e); HttpResponse::InternalServerError().body("Failed to create CRISP contract") }) } fn parse_address(address_str: &str) -> Result<Address, HttpResponse> { Address::from_str(address_str).map_err(|e| { error!("Invalid address format: {:?}", e); HttpResponse::BadRequest().body("Invalid address format") }) }Also applies to: 291-308
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (1)
12-12: Consider validatingENCLAVE_APIis defined.If
VITE_ENCLAVE_APIis not set in the environment,ENCLAVE_APIwill beundefined, and server calls in the worker will fail with unclear errors.🔎 Proposed validation
-const ENCLAVE_API = import.meta.env.VITE_ENCLAVE_API +const ENCLAVE_API = import.meta.env.VITE_ENCLAVE_API +if (!ENCLAVE_API) { + console.warn('VITE_ENCLAVE_API environment variable is not set') +}examples/CRISP/crates/evm_helpers/src/lib.rs (2)
120-131: Consider enriching error context for better diagnostics.The current error handling preserves the underlying error, which addresses the past review concern about swallowing errors. However, adding context via
.wrap_err()would provide clearer diagnostic information about which operation failed and with what parameters.🔎 Optional enhancement with error context
- match contract.getSlotIndex(e3_id, slot_address).call().await { - Ok(slot_index) => Ok(slot_index), - Err(e) => Err(eyre::eyre!("Failed to get slot index: {}", e)), - } + contract + .getSlotIndex(e3_id, slot_address) + .call() + .await + .wrap_err_with(|| format!( + "Failed to get slot index for e3_id={} slot_address={}", + e3_id, slot_address + ))This provides richer context including the parameters that caused the failure, which aids debugging when this method is called from server endpoints.
Based on past review.
134-145: Consider adding error context for consistency.Similar to
get_slot_index_from_address, adding context via.wrap_err_with()would improve debuggability by including the parameters that caused the failure.🔎 Optional enhancement with error context
- match contract.isSlotEmptyByAddress(e3_id, slot_address).call().await { - Ok(is_empty) => Ok(is_empty), - Err(e) => Err(eyre::eyre!("Failed to check if slot is empty: {}", e)), - } + contract + .isSlotEmptyByAddress(e3_id, slot_address) + .call() + .await + .wrap_err_with(|| format!( + "Failed to check if slot is empty for e3_id={} slot_address={}", + e3_id, slot_address + ))
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
examples/CRISP/client/libs/crispSDKWorker.js(1 hunks)examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts(2 hunks)examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx(3 hunks)examples/CRISP/client/src/hooks/voting/useVoteCasting.ts(5 hunks)examples/CRISP/client/src/model/vote.model.ts(1 hunks)examples/CRISP/crates/evm_helpers/src/lib.rs(4 hunks)examples/CRISP/crates/zk-inputs-wasm/src/lib.rs(2 hunks)examples/CRISP/crates/zk-inputs/src/lib.rs(2 hunks)examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol(2 hunks)examples/CRISP/packages/crisp-sdk/src/constants.ts(2 hunks)examples/CRISP/packages/crisp-sdk/src/state.ts(2 hunks)examples/CRISP/packages/crisp-sdk/src/types.ts(1 hunks)examples/CRISP/packages/crisp-sdk/src/vote.ts(5 hunks)examples/CRISP/packages/crisp-sdk/tests/vote.test.ts(9 hunks)examples/CRISP/server/src/server/models.rs(1 hunks)examples/CRISP/server/src/server/repo.rs(1 hunks)examples/CRISP/server/src/server/routes/state.rs(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- examples/CRISP/client/src/model/vote.model.ts
- examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
- examples/CRISP/server/src/server/repo.rs
- examples/CRISP/server/src/server/models.rs
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2024-10-22T03:17:41.617Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/hooks.rs:0-0
Timestamp: 2024-10-22T03:17:41.617Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, in the `hydrate` methods of the `E3Feature` implementations, it's acceptable to return `Ok(())` when dependencies are missing, as the error is reported to the bus.
Applied to files:
examples/CRISP/server/src/server/routes/state.rsexamples/CRISP/crates/evm_helpers/src/lib.rs
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2024-10-22T03:47:04.014Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/e3_request_router.rs:202-235
Timestamp: 2024-10-22T03:47:04.014Z
Learning: In `packages/ciphernode/router/src/e3_request_router.rs`, within the `E3RequestRouter::from_snapshot` method, errors during context restoration propagate upwards due to the `?` operator, and skipping contexts when `repositories.context(&e3_id).read().await?` returns `Ok(None)` is acceptable, as missing snapshots are expected.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/evm/src/ciphernode_registry_sol.rs:133-143
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/evm/src/ciphernode_registry_sol.rs`, the function `helpers::stream_from_evm` in Rust returns `()`, not a `Result`, so error handling with `if let Err(e) = ...` is not applicable.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rs
📚 Learning: 2024-11-05T06:49:46.285Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/enclave_node/src/datastore.rs:14-16
Timestamp: 2024-11-05T06:49:46.285Z
Learning: In `packages/ciphernode/enclave_node/src/datastore.rs`, for internal functions like `get_in_mem_store`, adding extensive documentation and error handling may not be necessary if they are not client-facing.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rs
📚 Learning: 2025-11-12T10:08:30.720Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 996
File: examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol:144-169
Timestamp: 2025-11-12T10:08:30.720Z
Learning: In the CRISP program (examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol), there are plans to move the merkle tree from the Enclave contract to the program contract itself in the future, which would allow direct calls to validateInput to be stored in the merkle tree.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rs
🧬 Code graph analysis (11)
examples/CRISP/packages/crisp-sdk/src/state.ts (1)
examples/CRISP/packages/crisp-sdk/src/constants.ts (2)
CRISP_SERVER_PREVIOUS_CIPHERTEXT_ENDPOINT(11-11)CRISP_SERVER_IS_SLOT_EMPTY_ENDPOINT(12-12)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)
examples/CRISP/crates/zk-inputs/src/lib.rs (1)
generate_inputs_for_update(78-139)
examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts (3)
examples/CRISP/client/src/model/vote.model.ts (1)
Vote(59-62)examples/CRISP/packages/crisp-sdk/src/types.ts (1)
Vote(70-79)examples/CRISP/packages/crisp-sdk/src/index.ts (1)
Vote(21-21)
examples/CRISP/server/src/server/routes/state.rs (2)
examples/CRISP/crates/evm_helpers/src/lib.rs (2)
create_read(168-173)address(150-152)crates/config/src/app_config.rs (1)
address(298-300)
examples/CRISP/crates/zk-inputs/src/lib.rs (2)
crates/bfv-helpers/src/utils/greco.rs (2)
abi_decode_greco_ciphertext(125-183)greco_to_bfv_ciphertext(68-103)examples/CRISP/crates/zk-inputs/src/serialization.rs (2)
construct_inputs(60-261)serialize_inputs_to_json(270-272)
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (2)
examples/CRISP/client/src/model/vote.model.ts (1)
Vote(59-62)examples/CRISP/packages/crisp-sdk/src/types.ts (1)
Vote(70-79)
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts (7)
examples/CRISP/packages/crisp-sdk/src/types.ts (1)
Signature(204-209)examples/CRISP/packages/crisp-sdk/src/constants.ts (3)
SIGNATURE_MESSAGE(33-33)SIGNATURE_MESSAGE_HASH(34-34)zeroVote(40-40)examples/CRISP/packages/crisp-sdk/src/index.ts (5)
SIGNATURE_MESSAGE(9-9)SIGNATURE_MESSAGE_HASH(9-9)encryptVote(17-17)generateVoteProof(13-13)generateMaskVoteProof(14-14)examples/CRISP/packages/crisp-sdk/tests/constants.ts (3)
ECDSA_PRIVATE_KEY(8-8)LEAVES(9-17)CRISP_SERVER_URL(7-7)examples/CRISP/packages/crisp-sdk/src/utils.ts (1)
extractSignatureComponents(89-118)examples/CRISP/packages/crisp-sdk/src/vote.ts (4)
encryptVote(126-130)generateCircuitInputs(146-180)generateVoteProof(214-255)generateMaskVoteProof(262-292)examples/CRISP/crates/evm_helpers/src/lib.rs (1)
address(150-152)
examples/CRISP/client/libs/crispSDKWorker.js (2)
examples/CRISP/packages/crisp-sdk/src/utils.ts (1)
hashLeaf(20-22)examples/CRISP/packages/crisp-sdk/src/vote.ts (2)
generateMaskVoteProof(262-292)generateVoteProof(214-255)
examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (5)
examples/CRISP/client/src/model/vote.model.ts (1)
Vote(59-62)examples/CRISP/packages/crisp-sdk/src/types.ts (1)
Vote(70-79)examples/CRISP/packages/crisp-sdk/src/vote.ts (1)
generateProof(198-207)packages/enclave-sdk/src/greco.ts (1)
generateProof(122-159)examples/CRISP/client/src/model/poll.model.ts (1)
Poll(32-36)
examples/CRISP/packages/crisp-sdk/src/vote.ts (4)
examples/CRISP/packages/crisp-sdk/src/types.ts (2)
Vote(70-79)ProofInputs(172-181)examples/CRISP/packages/crisp-sdk/src/constants.ts (3)
zeroVote(40-40)MASK_SIGNATURE(37-38)SIGNATURE_MESSAGE_HASH(34-34)examples/CRISP/packages/crisp-sdk/src/utils.ts (1)
extractSignatureComponents(89-118)examples/CRISP/packages/crisp-sdk/src/state.ts (2)
getIsSlotEmpty(93-109)getPreviousCiphertext(68-84)
examples/CRISP/packages/crisp-sdk/src/types.ts (2)
examples/CRISP/client/src/model/vote.model.ts (1)
Vote(59-62)examples/CRISP/packages/crisp-sdk/src/index.ts (3)
Vote(21-21)MaskVoteProofInputs(21-21)VoteProofInputs(21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: build_enclave_cli
- GitHub Check: build_sdk
- GitHub Check: build_crisp_sdk
- GitHub Check: integration_prebuild
- GitHub Check: rust_unit
- GitHub Check: rust_integration
- GitHub Check: test_net
- GitHub Check: Build & Push Image
🔇 Additional comments (24)
examples/CRISP/packages/crisp-sdk/src/constants.ts (1)
11-12: LGTM!The new endpoint constants and
zeroVotefollow existing conventions. ThezeroVotecorrectly usesbigintvalues consistent with the SDK'sVotetype definition.Also applies to: 39-40
examples/CRISP/packages/crisp-sdk/src/state.ts (1)
68-84: Good addition of error handling for HTTP responses.The new functions properly check
response.okbefore processing, which is an improvement overgetRoundDetails. The consistent request structure (POST with JSON body) aligns well with existing patterns.Also applies to: 93-109
examples/CRISP/client/libs/crispSDKWorker.js (1)
25-46: LGTM! Clean separation of masking vs regular vote proof generation.The conditional logic correctly routes to
generateMaskVoteProoforgenerateVoteProofbased on theisMaskingflag. The SDK functions now handlepreviousCiphertextfetching internally (viagetIsSlotEmptyandgetPreviousCiphertext), which addresses the previous review concern about undefinedpreviousCiphertextvalidation—this is no longer the worker's responsibility.examples/CRISP/server/src/server/routes/state.rs (2)
48-97: LGTM! Well-structured endpoint with proper error handling.The
handle_get_previous_ciphertextendpoint correctly:
- Creates a read-only contract instance
- Validates the address format
- Resolves the slot index from address
- Fetches the ciphertext from storage with appropriate 404 handling
310-322: LGTM! Clean implementation for slot-empty check.The
handle_is_slot_emptyendpoint properly queries the contract and returns the result with consistent error handling.examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts (2)
40-49: Signature updated to support server-driven masking flow.The updated
generateProofsignature properly reflects the new architecture where:
previousCiphertextis removed (now fetched internally by SDK)isMaskingflag enables conditional proof generationvoteandbalanceare passed for proof inputsNote: The
voteIdtype change frombiginttonumberis a breaking change for existing callers.
9-9: Type mismatch: clientVoteusesnumber, SDKVoteusesbigint.The client's
Votetype (from@/model/vote.model) has{ yes: number, no: number }, but the SDK expects{ yes: bigint, no: bigint }. Additionally,balanceis passed asnumberinstead ofbigintto SDK functions. BigInt values cannot be mixed with Number values in operations; they must be coerced to the same type. Convert both the Vote properties and balance to bigint before passing to SDK functions, or align the type definitions.⛔ Skipped due to learnings
Learnt from: ctrlc03 Repo: gnosisguild/enclave PR: 665 File: packages/enclave-sdk/src/contract-client.ts:110-118 Timestamp: 2025-08-28T08:58:17.434Z Learning: viem's TypeScript ABI inference maps uint32[2] to [number, number], not [bigint, bigint]. The library uses number type for uint32 values to align with traditional database patterns and avoid unnecessary BigInt conversion.examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (2)
119-124: Good improvement: Round-specific message signing.Using a dynamic message with the round ID (
Vote for round ${roundState.id}) and hashing it for proof generation is a sound approach that prevents cross-round replay of signatures.
68-83: LGTM!The
handleProofGenerationfunction correctly integrates the new parameters (vote,balance,messageHash,isMasking) and passes them to the proof generation call.examples/CRISP/packages/crisp-sdk/src/vote.ts (3)
146-180: LGTM!The
generateCircuitInputsfunction correctly handles both first-vote and update paths. The defensive check forpreviousCiphertexton non-first votes (line 161-163) is good practice even though callers should always provide it.
235-252: Verify theslotAddressusage is intentional.The function uses
voteProofInputs.slotAddressfor server calls (lines 236, 240) but then overrides it withaddress(derived from signature) in the circuit inputs (line 247). This means the server is queried for one address's slot, but the circuit proves for the signer's address.If this is intentional (e.g., the input
slotAddressis expected to match the derivedaddress), consider adding a validation check. Otherwise, consider using the derivedaddressconsistently for both server calls and circuit inputs.
262-292: LGTM!The
generateMaskVoteProoffunction correctly implements the masking flow:
- Uses the fixed
MASK_SIGNATUREfor signature components- Fetches previous ciphertext from server when slot is not empty
- Passes
zeroVoteto ensure no voting power is addedexamples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (1)
31-74: LGTM!The
generateProoffunction correctly passes all new parameters to the worker and handles responses appropriately. The early return when the worker is not initialized prevents runtime errors.examples/CRISP/packages/crisp-sdk/src/types.ts (1)
172-209: LGTM!The type definitions are well-structured:
ProofInputscorrectly makespreviousCiphertextrequired and uses the newSignaturetypeMaskVoteProofInputsandVoteProofInputsappropriately include server-related fields (serverUrl,e3Id)- The
Signaturetype cleanly encapsulates all signature componentsexamples/CRISP/packages/crisp-sdk/tests/vote.test.ts (3)
37-55: Good test setup with proper mock lifecycle management.The mock setup correctly uses
vi.clearAllMocks()inbeforeEachandvi.restoreAllMocks()inafterEachto ensure test isolation. The mock response objects are well-defined for both slot empty and previous ciphertext scenarios.
274-303: LGTM!This test correctly validates the mask vote proof generation when there's a previous vote in the slot. The chained mock setup (
mockResolvedValueOncetwice) properly simulates the sequential server calls forisSlotEmptyandgetPreviousCiphertext.
147-179: LGTM!This test correctly validates that when using a previous ciphertext with a zero vote (masking scenario), the circuit outputs the ciphertext addition. The intentional use of an invalid leaf (
merkleProof.leaf = 0n) tests the circuit's behavior when authentication fails, which is expected in masking operations.examples/CRISP/crates/evm_helpers/src/lib.rs (7)
29-30: LGTM! Contract interface additions are well-formed.The new view functions
getSlotIndexandisSlotEmptyByAddressare properly declared with appropriate types and modifiers.
38-46: LGTM! Read-only provider type is correctly composed.The
CRISPReadProviderproperly excludes theWalletFillerwhile maintaining the necessary fillers for read operations (gas estimation, nonce, chain ID).
63-66: LGTM! Generic design enables read/write flexibility.The default type parameter
P = CRISPWriteProvidermaintains backward compatibility while allowing read-only instances viaCRISPContract<CRISPReadProvider>.
68-87: LGTM! Write-capable constructor is properly scoped.The implementation correctly restricts wallet-requiring operations to
CRISPContract<CRISPWriteProvider>.
107-117: LGTM! Read-only constructor is correctly implemented.The method appropriately creates a provider without wallet authentication, enabling contract read operations without requiring a private key.
148-153: LGTM! Generic address getter is well-implemented.The method appropriately works for both read and write contract instances, providing access to the contract address without unnecessary cloning.
168-173: LGTM! Factory method completes the read/write separation.The
create_readmethod provides a convenient factory interface for read-only contract instances, maintaining consistency with the existingcreate_writepattern.
79c50db to
d3a7fc3
Compare
|
❌ License Header Check Failed Some files are missing the required SPDX license header. Please add the following header to the beginning of all You can run Or run |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (2)
examples/CRISP/crates/zk-inputs/src/lib.rs (1)
117-120: GRECO decoding functions can panic on invalid input.Per the past review comment,
abi_decode_greco_ciphertextandgreco_to_bfv_ciphertextpanic on invalid input or unexpected shape. The relevant code snippets show multiplepanic!and.expect()calls in these functions (crates/bfv-helpers/src/utils/greco.rs). This could cause the WASM module to abort unexpectedly when invalidprev_ciphertextis provided.Based on learnings, the team has accepted panics in some utility functions as a temporary solution pending refactoring to proper Result-based error handling. However, this remains a critical issue for production use.
Consider wrapping these calls with proper error handling to return a
Resultinstead of allowing panics to propagate through the WASM boundary.examples/CRISP/server/src/server/routes/state.rs (1)
47-47: Typo still present from previous review.The word "sucessfull" should be "successful" in the doc comment.
🧹 Nitpick comments (3)
examples/CRISP/crates/zk-inputs/src/lib.rs (1)
78-139: Missing test coverage forgenerate_inputs_for_update.The new
generate_inputs_for_updatemethod lacks test coverage. The test section (lines 254-471) only tests the existinggenerate_inputsmethod.Consider adding tests similar to the existing ones but using GRECO ABI-encoded ciphertexts. You'll need a helper to create GRECO-encoded ciphertexts for testing:
#[test] fn test_inputs_generation_for_update_with_defaults() { let generator = ZKInputsGenerator::with_defaults(); let public_key = generator.generate_public_key().expect("failed to generate public key"); let vote = create_vote_vector(); // Generate a GRECO ABI-encoded ciphertext let greco_encoded_ct = /* helper to create GRECO-encoded ciphertext */; let result = generator.generate_inputs_for_update(&greco_encoded_ct, &public_key, vote); assert!(result.is_ok()); let json_output = result.unwrap(); assert!(json_output.contains("params")); assert!(json_output.contains("pk0is")); }examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (1)
23-23: Consider usingZERO_VOTEconstant for consistency.The inline
{ yes: 0n, no: 0n }could be replaced with theZERO_VOTEconstant from@crisp-e3/sdkto align with the SDK's defined constants.🔎 Proposed fix
import { hashLeaf, generatePublicKey, SIGNATURE_MESSAGE, generateVoteProof, getAddressFromSignature, encodeSolidityProof, generateMerkleTree, SIGNATURE_MESSAGE_HASH, encryptVote, + ZERO_VOTE, } from '@crisp-e3/sdk'-const previousCiphertext = encryptVote({ yes: 0n, no: 0n }, publicKey) +const previousCiphertext = encryptVote(ZERO_VOTE, publicKey)examples/CRISP/client/libs/crispSDKWorker.js (1)
17-21: Reminder: Address the TODO for fetching merkle leaves from server.The comment indicates the leaves should be fetched from the server. Currently, only the first leaf is dynamically computed from
slotAddressandbalance, while the other two are hardcoded test values.Would you like me to open an issue to track this TODO?
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
examples/CRISP/client/libs/crispSDKWorker.js(1 hunks)examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts(2 hunks)examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx(3 hunks)examples/CRISP/client/src/hooks/voting/useVoteCasting.ts(5 hunks)examples/CRISP/client/src/model/vote.model.ts(1 hunks)examples/CRISP/crates/evm_helpers/src/lib.rs(4 hunks)examples/CRISP/crates/zk-inputs-wasm/src/lib.rs(2 hunks)examples/CRISP/crates/zk-inputs/src/lib.rs(2 hunks)examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol(2 hunks)examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts(3 hunks)examples/CRISP/packages/crisp-sdk/src/constants.ts(2 hunks)examples/CRISP/packages/crisp-sdk/src/index.ts(1 hunks)examples/CRISP/packages/crisp-sdk/src/sdk.ts(1 hunks)examples/CRISP/packages/crisp-sdk/src/state.ts(2 hunks)examples/CRISP/packages/crisp-sdk/src/types.ts(2 hunks)examples/CRISP/packages/crisp-sdk/src/vote.ts(5 hunks)examples/CRISP/packages/crisp-sdk/tests/state.test.ts(2 hunks)examples/CRISP/packages/crisp-sdk/tests/token.test.ts(1 hunks)examples/CRISP/packages/crisp-sdk/tests/vote.test.ts(8 hunks)examples/CRISP/server/src/server/models.rs(1 hunks)examples/CRISP/server/src/server/repo.rs(1 hunks)examples/CRISP/server/src/server/routes/state.rs(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- examples/CRISP/server/src/server/repo.rs
- examples/CRISP/client/src/model/vote.model.ts
- examples/CRISP/packages/crisp-sdk/src/state.ts
🧰 Additional context used
🧠 Learnings (22)
📓 Common learnings
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 1109
File: examples/CRISP/server/src/server/routes/state.rs:33-37
Timestamp: 2025-12-19T11:35:43.204Z
Learning: In the CRISP voting system (examples/CRISP), ciphertext data and slot states are public and stored on-chain in the CRISPProgram smart contract. The server endpoints `/previous-ciphertext` and `/is-slot-empty` expose public blockchain data that can already be accessed by anyone through the contract's external view functions (getSlotIndex, isSlotEmptyByAddress) or by reading contract state directly. Authentication is not needed for these endpoints since they only expose data that is already publicly available on the blockchain.
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.
Applied to files:
examples/CRISP/server/src/server/models.rs
📚 Learning: 2025-08-25T10:28:56.174Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 657
File: Cargo.toml:32-34
Timestamp: 2025-08-25T10:28:56.174Z
Learning: The examples/CRISP directory has its own Cargo.toml workspace configuration with members like "server", "wasm-crypto", "program/core", "program/client", etc. The root workspace intentionally excludes "examples/CRISP/server", "examples/CRISP/program", and "examples/CRISP/wasm-crypto" to prevent double workspace membership, which is the correct approach for self-contained example workspaces.
Applied to files:
examples/CRISP/server/src/server/models.rs
📚 Learning: 2025-12-19T11:35:43.204Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 1109
File: examples/CRISP/server/src/server/routes/state.rs:33-37
Timestamp: 2025-12-19T11:35:43.204Z
Learning: In the CRISP voting system (examples/CRISP), ciphertext data and slot states are public and stored on-chain in the CRISPProgram smart contract. The server endpoints `/previous-ciphertext` and `/is-slot-empty` expose public blockchain data that can already be accessed by anyone through the contract's external view functions (getSlotIndex, isSlotEmptyByAddress) or by reading contract state directly. Authentication is not needed for these endpoints since they only expose data that is already publicly available on the blockchain.
Applied to files:
examples/CRISP/client/libs/crispSDKWorker.jsexamples/CRISP/packages/crisp-sdk/src/sdk.tsexamples/CRISP/packages/crisp-sdk/tests/vote.test.tsexamples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.tsexamples/CRISP/packages/crisp-sdk/src/constants.tsexamples/CRISP/crates/evm_helpers/src/lib.rsexamples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.solexamples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2025-11-05T14:12:57.814Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 963
File: examples/CRISP/client/package.json:25-25
Timestamp: 2025-11-05T14:12:57.814Z
Learning: In the Enclave/CRISP codebase, `enclave-e3/sdk` and `crisp-e3/sdk` are different packages: `enclave-e3/sdk` is the general Enclave SDK, while `crisp-e3/sdk` is the CRISP-specific SDK. The CRISP client (`examples/CRISP/client`) intentionally depends on `enclave-e3/sdk`, not `crisp-e3/sdk`.
Applied to files:
examples/CRISP/packages/crisp-sdk/src/sdk.tsexamples/CRISP/packages/crisp-sdk/src/index.ts
📚 Learning: 2024-10-22T02:10:34.864Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:82-83
Timestamp: 2024-10-22T02:10:34.864Z
Learning: In the file `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, when reviewing test functions like `generate_pk_share`, minor performance optimizations (e.g., minimizing mutex locks) are not a priority.
Applied to files:
examples/CRISP/packages/crisp-sdk/tests/vote.test.tsexamples/CRISP/crates/zk-inputs/src/lib.rs
📚 Learning: 2024-09-26T04:12:09.345Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: tests/basic_integration/test.sh:103-114
Timestamp: 2024-09-26T04:12:09.345Z
Learning: In `tests/basic_integration/test.sh`, the user prefers not to refactor the ciphernode addition section to reduce duplication.
Applied to files:
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts
📚 Learning: 2025-11-08T01:31:47.505Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 969
File: packages/enclave-sdk/src/enclave-sdk.ts:101-103
Timestamp: 2025-11-08T01:31:47.505Z
Learning: In packages/enclave-sdk/src/enclave-sdk.ts, the TRBFV protocol parameter setup is intentionally incomplete as of PR #969. The constructor sets BFV_THRESHOLD parameters for TRBFV, but the encryption methods (encryptNumber, encryptVector, encryptNumberAndGenInputs, encryptVectorAndGenInputs) intentionally only support BFV and will throw "Protocol not supported" for TRBFV until future implementation is completed.
Applied to files:
examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
📚 Learning: 2025-11-12T10:08:30.720Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 996
File: examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol:144-169
Timestamp: 2025-11-12T10:08:30.720Z
Learning: In the CRISP program (examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol), there are plans to move the merkle tree from the Enclave contract to the program contract itself in the future, which would allow direct calls to validateInput to be stored in the merkle tree.
Applied to files:
examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.tsexamples/CRISP/crates/evm_helpers/src/lib.rsexamples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 Learning: 2025-05-07T15:18:20.056Z
Learnt from: 0xjei
Repo: gnosisguild/enclave PR: 388
File: packages/commons/src/bfv/mod.rs:38-48
Timestamp: 2025-05-07T15:18:20.056Z
Learning: The `build_bfv_params` and related functions in the commons BFV utilities intentionally use panic for error handling as a temporary solution. The team plans to refactor these to use proper Result-based error handling in the future.
Applied to files:
examples/CRISP/crates/zk-inputs/src/lib.rs
📚 Learning: 2024-10-28T12:04:26.578Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave_node/src/ciphernode.rs:26-28
Timestamp: 2024-10-28T12:04:26.578Z
Learning: In the `setup_ciphernode` function in `packages/ciphernode/enclave_node/src/ciphernode.rs`, panicking on errors during setup is acceptable.
Applied to files:
examples/CRISP/crates/zk-inputs/src/lib.rs
📚 Learning: 2025-09-22T15:08:29.814Z
Learnt from: ozgurarmanc
Repo: gnosisguild/enclave PR: 734
File: packages/circuits/crates/libs/polynomial/src/lib.nr:140-155
Timestamp: 2025-09-22T15:08:29.814Z
Learning: Greco (packages/circuits/crates/libs/greco/src/lib.nr) performs range_check_1bound/2bounds on all polynomials (u, e0/e1, k1, pk*, r*, p*) before serialization; packer/flatten rely on these bounds, so per-limb asserts inside packer are unnecessary in this crate’s flow.
Applied to files:
examples/CRISP/crates/zk-inputs/src/lib.rs
📚 Learning: 2024-10-22T03:30:21.818Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/enclave_node/src/shutdown.rs:12-12
Timestamp: 2024-10-22T03:30:21.818Z
Learning: In shutdown code (e.g., in `packages/ciphernode/enclave_node/src/shutdown.rs`), if signal creation fails, it's acceptable to panic rather than handle the error gracefully.
Applied to files:
examples/CRISP/crates/zk-inputs/src/lib.rs
📚 Learning: 2024-11-05T06:49:46.285Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/enclave_node/src/datastore.rs:14-16
Timestamp: 2024-11-05T06:49:46.285Z
Learning: In `packages/ciphernode/enclave_node/src/datastore.rs`, for internal functions like `get_in_mem_store`, adding extensive documentation and error handling may not be necessary if they are not client-facing.
Applied to files:
examples/CRISP/crates/zk-inputs/src/lib.rsexamples/CRISP/crates/evm_helpers/src/lib.rsexamples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2024-10-22T03:47:04.014Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/e3_request_router.rs:202-235
Timestamp: 2024-10-22T03:47:04.014Z
Learning: In `packages/ciphernode/router/src/e3_request_router.rs`, within the `E3RequestRouter::from_snapshot` method, errors during context restoration propagate upwards due to the `?` operator, and skipping contexts when `repositories.context(&e3_id).read().await?` returns `Ok(None)` is acceptable, as missing snapshots are expected.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/evm/src/ciphernode_registry_sol.rs:133-143
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/evm/src/ciphernode_registry_sol.rs`, the function `helpers::stream_from_evm` in Rust returns `()`, not a `Result`, so error handling with `if let Err(e) = ...` is not applicable.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rs
📚 Learning: 2024-10-22T03:17:41.617Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/hooks.rs:0-0
Timestamp: 2024-10-22T03:17:41.617Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, in the `hydrate` methods of the `E3Feature` implementations, it's acceptable to return `Ok(())` when dependencies are missing, as the error is reported to the bus.
Applied to files:
examples/CRISP/crates/evm_helpers/src/lib.rsexamples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2025-04-26T12:15:26.610Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 344
File: packages/ciphernode/enclave_core/src/nodes/server.rs:63-75
Timestamp: 2025-04-26T12:15:26.610Z
Learning: Authentication is not considered necessary for the internal server implementation in `packages/ciphernode/enclave_core/src/nodes/server.rs` as it likely binds to localhost and is for internal use only.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2024-10-29T01:03:50.414Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/config/src/app_config.rs:21-26
Timestamp: 2024-10-29T01:03:50.414Z
Learning: In `packages/ciphernode/config/src/app_config.rs`, the `rpc_url` field in the `ChainConfig` struct is not considered sensitive and does not need to be encrypted.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2024-10-23T01:59:42.967Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:274-274
Timestamp: 2024-10-23T01:59:42.967Z
Learning: In the `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs` file and other test files within this project, hardcoding `CIPHERNODE_SECRET` is acceptable for testing purposes.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2024-10-23T02:35:07.689Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/keyshare/src/keyshare.rs:58-65
Timestamp: 2024-10-23T02:35:07.689Z
Learning: In `packages/ciphernode/keyshare/src/keyshare.rs`, the data being decrypted in the `get_secret` method of the `Keyshare` struct is not sensitive, so wrapping it with `Zeroizing` is unnecessary.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.
Applied to files:
examples/CRISP/server/src/server/routes/state.rs
🧬 Code graph analysis (7)
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (2)
examples/CRISP/packages/crisp-sdk/src/types.ts (1)
Vote(70-79)examples/CRISP/client/src/model/vote.model.ts (1)
Vote(59-62)
examples/CRISP/client/libs/crispSDKWorker.js (2)
examples/CRISP/packages/crisp-sdk/src/index.ts (2)
hashLeaf(10-10)CrispSDK(20-20)examples/CRISP/packages/crisp-sdk/src/utils.ts (1)
hashLeaf(20-22)
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts (3)
examples/CRISP/packages/crisp-sdk/src/sdk.ts (1)
CrispSDK(11-69)examples/CRISP/packages/crisp-sdk/src/vote.ts (2)
encryptVote(125-129)generateCircuitInputs(145-181)examples/CRISP/packages/crisp-sdk/src/constants.ts (3)
ZERO_VOTE(40-40)SIGNATURE_MESSAGE_HASH(34-34)MASK_SIGNATURE(37-38)
examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (1)
examples/CRISP/packages/crisp-sdk/src/index.ts (2)
generatePublicKey(16-16)encryptVote(17-17)
examples/CRISP/crates/zk-inputs/src/lib.rs (3)
crates/bfv-helpers/src/utils/greco.rs (2)
abi_decode_greco_ciphertext(125-183)greco_to_bfv_ciphertext(68-103)examples/CRISP/crates/zk-inputs/src/ciphertext_addition.rs (1)
compute(63-230)examples/CRISP/crates/zk-inputs/src/serialization.rs (2)
construct_inputs(60-261)serialize_inputs_to_json(270-272)
examples/CRISP/packages/crisp-sdk/src/vote.ts (3)
examples/CRISP/packages/crisp-sdk/src/types.ts (2)
Vote(70-79)ProofInputs(172-182)examples/CRISP/packages/crisp-sdk/src/constants.ts (2)
ZERO_VOTE(40-40)SIGNATURE_MESSAGE_HASH(34-34)examples/CRISP/packages/crisp-sdk/src/utils.ts (1)
extractSignatureComponents(89-118)
examples/CRISP/packages/crisp-sdk/src/types.ts (2)
examples/CRISP/packages/crisp-sdk/src/index.ts (2)
Vote(22-22)MaskVoteProofInputs(22-22)examples/CRISP/client/src/model/vote.model.ts (1)
Vote(59-62)
🪛 GitHub Actions: License Header Check
examples/CRISP/packages/crisp-sdk/src/sdk.ts
[error] 1-1: Missing license header. Files missing license headers: 1. Expected header format: // SPDX-License-Identifier: LGPL-3.0-only
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: build_crisp_sdk
- GitHub Check: rust_unit
- GitHub Check: build_sdk
- GitHub Check: build_enclave_cli
- GitHub Check: rust_integration
- GitHub Check: integration_prebuild
- GitHub Check: test_net
🔇 Additional comments (27)
examples/CRISP/crates/zk-inputs-wasm/src/lib.rs (1)
75-98: LGTM - Consistent wrapper implementation.The new
generate_inputs_for_updatemethod follows the same pattern asgenerate_inputs, with consistent type conversions (i64→u64), delegation to the core generator, and error handling.examples/CRISP/crates/zk-inputs/src/lib.rs (1)
12-15: LGTM - Required imports for GRECO decoding.The new imports for
abi_decode_greco_ciphertextandgreco_to_bfv_ciphertextare necessary for the GRECO ABI-encoded ciphertext handling ingenerate_inputs_for_update.examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (2)
55-55: LGTM!The custom error
SlotIsEmpty()follows Solidity best practices for gas-efficient error handling.
182-200: LGTM!Both view functions correctly implement slot state queries:
getSlotIndexproperly handles the +1 encoding and reverts with a clear error when the slot is emptyisSlotEmptyByAddressprovides a non-reverting check for slot emptinessThe implementations are clean, well-documented, and correctly expose public on-chain data for masking operations.
examples/CRISP/server/src/server/routes/state.rs (4)
7-19: LGTM!The new imports are necessary and correctly structured for the previousCiphertext and slot-emptiness query functionality.
32-37: LGTM!The new routes are properly registered and align with the existing endpoint structure.
48-97: LGTM!The
handle_get_previous_ciphertextimplementation is well-structured with proper error handling:
- Validates address format with clear error messages
- Uses read-only contract for querying public on-chain data
- Returns appropriate HTTP status codes (400 for invalid input, 404 for not found, 500 for internal errors)
Based on learnings, authentication is not required as this endpoint exposes public blockchain data.
283-323: LGTM!The
handle_is_slot_emptyimplementation follows the same solid pattern ashandle_get_previous_ciphertext:
- Proper address validation
- Read-only contract usage for public data queries
- Appropriate error handling with clear status codes
examples/CRISP/server/src/server/models.rs (1)
108-128: LGTM!The new model structs are well-defined with appropriate traits and field types:
- Request types properly implement
Debug,Deserialize, andSerialize- Response types implement
Serializefor JSON serialization- Field types match the requirements for previousCiphertext and slot-emptiness queries
examples/CRISP/crates/evm_helpers/src/lib.rs (5)
29-30: LGTM!The sol! interface correctly declares the new view functions matching the CRISPProgram contract.
38-66: LGTM!The generic provider design cleanly separates read and write capabilities:
CRISPReadProvideromits the wallet filler for read-only operations- Generic
CRISPContract<P>with defaultCRISPWriteProvidermaintains backward compatibility- Using
Arc<P>is appropriate for shared provider instances
107-146: LGTM!The read-only implementation is well-structured:
new_read_onlycorrectly creates a provider without requiring a private key- Both query methods (
get_slot_index_from_addressandget_is_slot_empty_by_address) properly preserve error context by matching on the Result instead of using.ok()- Error messages are descriptive and helpful for debugging
This addresses the error handling concern from the previous review.
148-153: LGTM!The generic
address()accessor provides a clean way to retrieve the contract address for both read and write instances.
164-173: LGTM!The factory methods are well-structured:
create_writeexplicitly returnsCRISPContract<CRISPWriteProvider>create_readprovides a convenient way to create read-only instances- Both methods follow the factory pattern consistently
examples/CRISP/packages/crisp-sdk/src/index.ts (1)
20-20: LGTM!The CrispSDK export cleanly extends the public API surface, aligning with the existing export patterns.
examples/CRISP/packages/crisp-sdk/tests/token.test.ts (1)
29-29: LGTM!Using
mockResolvedValueOnceis the correct approach for a test that expects exactly one fetch call.examples/CRISP/packages/crisp-sdk/tests/state.test.ts (2)
49-49: LGTM!Consistent use of
mockResolvedValueOncefor the single expected fetch call.
90-90: LGTM!Consistent with the mock pattern in
getRoundDetailstest.examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (2)
64-66: LGTM!The test correctly passes the new required parameters (
isFirstVote,previousCiphertext,slotAddress) for the updatedgenerateVoteProofsignature.
97-99: LGTM!Consistent with the first test case - correctly exercises the verifier and encoder with the new proof input model.
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (1)
31-51: LGTM!The updated
generateProoffunction signature aligns with the new SDK API, properly passes all required parameters to the worker, and handles the uninitialized worker case gracefully.examples/CRISP/packages/crisp-sdk/src/constants.ts (2)
11-12: LGTM!The new endpoint constants follow the established naming convention and are correctly placed with the other server endpoint definitions.
39-40: LGTM!The
ZERO_VOTEconstant is well-named following SCREAMING_SNAKE_CASE convention and provides a reusable zero-vote representation for first-vote scenarios.examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts (1)
40-49: LGTM!The updated
generateProoftype signature correctly reflects the new API contract, with properly typed parameters for vote masking support.examples/CRISP/client/libs/crispSDKWorker.js (2)
27-48: Masking logic edge cases are properly handled by the SDK.The SDK's
generateMaskVoteProofandgenerateVoteProofmethods correctly handle edge cases: they check slot status to determine if previousCiphertext should be fetched from the server (vote-update scenarios) or initialized as a zero vote (first vote), and properly set theisFirstVoteflag accordingly. The client code correctly delegates to these SDK methods.
23-48: > Likely an incorrect or invalid review comment.examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (1)
138-140: The balance value of1nis intentional and represents the one-person-one-vote design of the CRISP protocol. As stated in the code comment, "vote is either 0 or 1," and theVotestructure encodes this as a binary choice: either{yes: 1n, no: 0n}or{yes: 0n, no: 1n}. This is not a placeholder for user's actual token balance; rather, it's the core voting weight for the Coercion-Resistant Impartial Selection Protocol, which uses fully homomorphic encryption for secret ballots.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts (1)
173-204: Inconsistent vote value used for previousCiphertext.Line 187 uses
encryptVote(vote, publicKey)wherevoteis{ yes: 10n, no: 0n }(set inbeforeAll), but this test is titled "if there is no previous ciphertext" and usesvote: ZERO_VOTEat line 179 for the circuit input. For consistency and clarity, line 187 should useZERO_VOTEinstead ofvote, or use thepreviousCiphertextthat matches the test scenario.🔎 Proposed fix
const crispInputs = await generateCircuitInputs({ vote: ZERO_VOTE, publicKey, signature: MASK_SIGNATURE, messageHash: SIGNATURE_MESSAGE_HASH, merkleProof, balance, slotAddress, isFirstVote: true, - previousCiphertext: encryptVote(vote, publicKey), + previousCiphertext: encryptVote(ZERO_VOTE, publicKey), })
🧹 Nitpick comments (1)
examples/CRISP/packages/crisp-sdk/src/sdk.ts (1)
35-74: Consider extracting the shared previousCiphertext logic.Both
generateMaskVoteProofandgenerateVoteProofcontain identical logic for determining and obtaining thepreviousCiphertext(lines 36-44 and 59-67). Extracting this into a private helper method would reduce duplication and improve maintainability.🔎 Proposed refactor to extract shared logic
+ private async getPreviousCiphertextForSlot( + e3Id: number, + slotAddress: string, + publicKey: Uint8Array + ): Promise<{ previousCiphertext: Uint8Array; isFirstVote: boolean }> { + const isSlotEmpty = await getIsSlotEmpty(this.serverUrl, e3Id, slotAddress) + + let previousCiphertext: Uint8Array + if (!isSlotEmpty) { + previousCiphertext = await getPreviousCiphertext(this.serverUrl, e3Id, slotAddress) + } else { + previousCiphertext = encryptVote(ZERO_VOTE, publicKey) + } + + return { previousCiphertext, isFirstVote: isSlotEmpty } + } + async generateMaskVoteProof(maskProofInputs: MaskVoteProofRequest): Promise<ProofData> { - // check if the slot is empty first - const isSlotEmpty = await getIsSlotEmpty(this.serverUrl, maskProofInputs.e3Id, maskProofInputs.slotAddress) - - let previousCiphertext: Uint8Array - if (!isSlotEmpty) { - previousCiphertext = await getPreviousCiphertext(this.serverUrl, maskProofInputs.e3Id, maskProofInputs.slotAddress) - } else { - previousCiphertext = encryptVote(ZERO_VOTE, maskProofInputs.publicKey) - } + const { previousCiphertext, isFirstVote } = await this.getPreviousCiphertextForSlot( + maskProofInputs.e3Id, + maskProofInputs.slotAddress, + maskProofInputs.publicKey + ) return generateMaskVoteProof({ ...maskProofInputs, previousCiphertext, - isFirstVote: isSlotEmpty, + isFirstVote, }) } async generateVoteProof(voteProofInputs: VoteProofRequest): Promise<ProofData> { - // check if the slot is empty first - const isSlotEmpty = await getIsSlotEmpty(this.serverUrl, voteProofInputs.e3Id, voteProofInputs.slotAddress) - - let previousCiphertext: Uint8Array - if (!isSlotEmpty) { - previousCiphertext = await getPreviousCiphertext(this.serverUrl, voteProofInputs.e3Id, voteProofInputs.slotAddress) - } else { - previousCiphertext = encryptVote(ZERO_VOTE, voteProofInputs.publicKey) - } + const { previousCiphertext, isFirstVote } = await this.getPreviousCiphertextForSlot( + voteProofInputs.e3Id, + voteProofInputs.slotAddress, + voteProofInputs.publicKey + ) return generateVoteProof({ ...voteProofInputs, previousCiphertext, - isFirstVote: isSlotEmpty, + isFirstVote, }) }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
examples/CRISP/packages/crisp-sdk/src/sdk.ts(1 hunks)examples/CRISP/packages/crisp-sdk/src/types.ts(2 hunks)examples/CRISP/packages/crisp-sdk/tests/vote.test.ts(8 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 1109
File: examples/CRISP/server/src/server/routes/state.rs:33-37
Timestamp: 2025-12-19T11:35:43.204Z
Learning: In the CRISP voting system (examples/CRISP), ciphertext data and slot states are public and stored on-chain in the CRISPProgram smart contract. The server endpoints `/previous-ciphertext` and `/is-slot-empty` expose public blockchain data that can already be accessed by anyone through the contract's external view functions (getSlotIndex, isSlotEmptyByAddress) or by reading contract state directly. Authentication is not needed for these endpoints since they only expose data that is already publicly available on the blockchain.
📚 Learning: 2025-11-05T14:12:57.814Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 963
File: examples/CRISP/client/package.json:25-25
Timestamp: 2025-11-05T14:12:57.814Z
Learning: In the Enclave/CRISP codebase, `enclave-e3/sdk` and `crisp-e3/sdk` are different packages: `enclave-e3/sdk` is the general Enclave SDK, while `crisp-e3/sdk` is the CRISP-specific SDK. The CRISP client (`examples/CRISP/client`) intentionally depends on `enclave-e3/sdk`, not `crisp-e3/sdk`.
Applied to files:
examples/CRISP/packages/crisp-sdk/src/sdk.ts
📚 Learning: 2025-12-19T11:35:43.204Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 1109
File: examples/CRISP/server/src/server/routes/state.rs:33-37
Timestamp: 2025-12-19T11:35:43.204Z
Learning: In the CRISP voting system (examples/CRISP), ciphertext data and slot states are public and stored on-chain in the CRISPProgram smart contract. The server endpoints `/previous-ciphertext` and `/is-slot-empty` expose public blockchain data that can already be accessed by anyone through the contract's external view functions (getSlotIndex, isSlotEmptyByAddress) or by reading contract state directly. Authentication is not needed for these endpoints since they only expose data that is already publicly available on the blockchain.
Applied to files:
examples/CRISP/packages/crisp-sdk/src/sdk.tsexamples/CRISP/packages/crisp-sdk/tests/vote.test.ts
📚 Learning: 2024-10-22T02:10:34.864Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:82-83
Timestamp: 2024-10-22T02:10:34.864Z
Learning: In the file `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, when reviewing test functions like `generate_pk_share`, minor performance optimizations (e.g., minimizing mutex locks) are not a priority.
Applied to files:
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts
📚 Learning: 2024-09-26T04:12:09.345Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: tests/basic_integration/test.sh:103-114
Timestamp: 2024-09-26T04:12:09.345Z
Learning: In `tests/basic_integration/test.sh`, the user prefers not to refactor the ciphernode addition section to reduce duplication.
Applied to files:
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts
🧬 Code graph analysis (3)
examples/CRISP/packages/crisp-sdk/src/sdk.ts (4)
examples/CRISP/packages/crisp-sdk/src/types.ts (2)
MaskVoteProofRequest(193-199)VoteProofRequest(201-210)examples/CRISP/packages/crisp-sdk/src/state.ts (2)
getIsSlotEmpty(93-109)getPreviousCiphertext(68-84)examples/CRISP/packages/crisp-sdk/src/vote.ts (3)
encryptVote(125-129)generateMaskVoteProof(251-265)generateVoteProof(215-244)examples/CRISP/packages/crisp-sdk/src/constants.ts (1)
ZERO_VOTE(40-40)
examples/CRISP/packages/crisp-sdk/tests/vote.test.ts (3)
examples/CRISP/packages/crisp-sdk/src/sdk.ts (1)
CrispSDK(17-75)examples/CRISP/packages/crisp-sdk/src/vote.ts (2)
encryptVote(125-129)generateCircuitInputs(145-181)examples/CRISP/packages/crisp-sdk/src/constants.ts (3)
ZERO_VOTE(40-40)SIGNATURE_MESSAGE_HASH(34-34)MASK_SIGNATURE(37-38)
examples/CRISP/packages/crisp-sdk/src/types.ts (2)
examples/CRISP/packages/crisp-sdk/src/index.ts (2)
Vote(22-22)MaskVoteProofInputs(22-22)examples/CRISP/client/src/model/vote.model.ts (1)
Vote(59-62)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: build_crisp_sdk
- GitHub Check: build_e3_support_dev
- GitHub Check: build_enclave_cli
- GitHub Check: build_sdk
- GitHub Check: rust_unit
- GitHub Check: integration_prebuild
- GitHub Check: test_net
- GitHub Check: rust_integration
🔇 Additional comments (1)
examples/CRISP/packages/crisp-sdk/src/types.ts (1)
193-210: LGTM! Well-designed API separation.The new
MaskVoteProofRequestandVoteProofRequesttypes cleanly separate the public API surface from internal implementation details. By excludingpreviousCiphertextandisFirstVotefrom the request types, the SDK correctly encapsulates the logic for determining these values, which improves the developer experience and reduces the chance of caller errors.
Get previous ciphertext from server and add masking specific logic
fix #1127 and #1091
Summary by CodeRabbit
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.