Skip to content

refactor: pass public key commitment [skip-line-limit]#1142

Merged
ctrlc03 merged 13 commits into
mainfrom
refactor/public-key
Jan 2, 2026
Merged

refactor: pass public key commitment [skip-line-limit]#1142
ctrlc03 merged 13 commits into
mainfrom
refactor/public-key

Conversation

@cedoor

@cedoor cedoor commented Dec 23, 2025

Copy link
Copy Markdown
Contributor

Closes #1065
Closes #1066

Summary by CodeRabbit

  • New Features

    • Public-key commitment computation is exposed via SDK, WASM and helper APIs; events and messages now include a 32-byte public-key hash.
  • Improvements

    • Activation flow simplified — raw public key material is no longer submitted; registry, indexer, CLI, tooling and tests propagate and store the 32‑byte hash.
    • Examples and tests updated to compute and validate the commitment.
  • Breaking Changes

    • Activation APIs now accept only the E3 ID.
    • Contract/event interfaces require a 32‑byte public-key hash.

✏️ Tip: You can customize this high-level summary in your review settings.

@cedoor cedoor requested review from ctrlc03 and hmzakhalid December 23, 2025 16:57
@vercel

vercel Bot commented Dec 23, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Review Updated (UTC)
crisp Skipped Skipped Jan 2, 2026 2:57pm
enclave-docs Skipped Skipped Jan 2, 2026 2:57pm

@coderabbitai

coderabbitai Bot commented Dec 23, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Aggregator now computes a 32-byte public-key commitment (Greco conversion) and includes it in PublicKeyAggregated; this commitment is exposed via WASM/SDK, propagated to indexer and EVM registry, added to contracts/ABIs, and tests/clients updated; Enclave.activate no longer accepts raw public keys.

Changes

Cohort / File(s) Summary
BFV helpers & Greco conversion
crates/bfv-helpers/src/client.rs, crates/bfv-helpers/src/utils/greco.rs
New public compute_pk_commitment and bfv_public_key_to_greco APIs, coefficient-centering helpers and tests; imports adjusted to expose PublicKey.
Aggregator & Events
crates/aggregator/src/publickey_aggregator.rs, crates/aggregator/Cargo.toml, crates/events/src/enclave_event/publickey_aggregated.rs
Aggregator imports compute_pk_commitment, computes/stores public_key_hash, updates local state and PublicKeyAggregated event (adds public_key_hash field); workspace dependency added.
WASM & SDK
crates/wasm/src/lib.rs, packages/enclave-sdk/src/enclave-sdk.ts, packages/enclave-sdk/src/contract-client.ts
WASM exposes compute_pk_commitment; SDK adds computePublicKeyCommitment; activateE3 signature simplified (publicKey removed) and internal calls updated.
EVM / Registry & Contracts
crates/evm/src/ciphernode_registry_sol.rs, crates/evm-helpers/src/contracts.rs, crates/evm-helpers/src/events.rs, packages/enclave-contracts/contracts/..., packages/enclave-contracts/artifacts/...
publishCommittee gains bytes32 publicKeyHash param; activate drops publicKey arg; E3Activated uses bytes32 committeePublicKey; ABIs, artifacts and contract implementations updated.
Indexer & Handlers
crates/indexer/src/indexer.rs, crates/indexer/tests/*, crates/indexer/Cargo.toml
Added CommitteePublished listener storing published public key temporarily; E3Activated handler retrieves that stored key; added dev deps for tests.
CRISP circuit & verifier
examples/CRISP/circuits/src/main.nr, examples/CRISP/packages/crisp-contracts/*, examples/CRISP/packages/crisp-sdk/src/vote.ts
pk_commitment made a public input; verifier VK and constants updated; public-input indexing and proof encoding shifted to include commitment.
Mocks, tests & scripts
packages/enclave-contracts/contracts/test/*, crates/tests/*, packages/enclave-contracts/test/*, examples/CRISP/*, tests/integration/*
Tests and mocks compute/pass publicKeyHash, use activate(e3Id) (no raw key), update fixtures and assertions to use commitments; CI/test scripts remove public-key-file handling.
UI & client call sites
templates/default/client/src/pages/steps/ActivateE3.tsx, templates/default/tests/integration.spec.ts
Frontend and integration tests updated to call SDK activateE3(e3Id) without public key; consumption of event publicKey bytes adjusted.
Tooling / tasks
packages/enclave-contracts/tasks/enclave.ts, packages/enclave-contracts/test/Enclave.spec.ts
publishCommittee task requires publicKeyHash; activateE3 task no longer accepts publicKey options; tests adapted to new signatures.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Aggregator
  participant BFVHelpers as BFV‑Helpers (WASM/Rust)
  participant Indexer
  participant Registry as CiphernodeRegistry
  participant Enclave

  Aggregator->>BFVHelpers: compute_pk_commitment(pubkey, degree, plaintext_modulus, moduli)
  Note right of BFVHelpers `#d6f5d6`: deserialize BFV PK → Greco\ncompute bigint commitment → 32‑byte hash
  BFVHelpers-->>Aggregator: public_key_hash (32 bytes)
  Aggregator->>Indexer: emit PublicKeyAggregated(pubkey, nodes, public_key_hash)
  Indexer->>Registry: publishCommittee(e3Id, nodes, publicKey, public_key_hash)
  Registry-->>Indexer: txReceipt
  Note right of Registry `#f0e6d6`: stores publicKeyHash in registry state
  Indexer->>Enclave: activate(e3Id)
  Enclave->>Registry: committeePublicKey(e3Id)
  Registry-->>Enclave: publicKeyHash
  Enclave-->>Indexer: activation receipt / E3Activated(event committeePublicKey = hash)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • 0xjei
  • hmzakhalid

Poem

🐰 I hopped through Greco, nibbling each byte,
Centered coefficients in the pale moonlight.
Thirty‑two tiny bytes tucked safe in a stash,
Activate by id — no raw key to stash.
Carrots, hashes, and a very happy dash!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: pass public key commitment' accurately summarizes the main objective of the PR - moving from passing raw public keys to passing their commitments.
Linked Issues check ✅ Passed The PR successfully addresses both linked issues: #1065 by computing and publishing public key commitments on-chain with GRECO conversion support, and #1066 by integrating commitments into CRISP verification with commitment-based proof validation.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the two linked issues. Import updates, function signature changes, event modifications, and integration points are all aligned with implementing public key commitment handling across the codebase.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01a21a6 and f947c8b.

📒 Files selected for processing (2)
  • templates/default/server/index.ts
  • templates/default/tests/integration.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • templates/default/server/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • templates/default/tests/integration.spec.ts
⏰ 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: build_sdk
  • GitHub Check: build_enclave_cli
  • GitHub Check: integration_prebuild
  • GitHub Check: test_net
  • GitHub Check: rust_integration
  • GitHub Check: rust_unit

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/enclave-sdk/src/contract-client.ts (1)

160-163: Update JSDoc to reflect the new parameter.

The JSDoc comment still shows the old contract signature without the publicKeyHash parameter. This creates a mismatch between documentation and implementation.

🔎 Proposed fix to update the JSDoc comment
  /**
   * Activate an E3 computation
-  * activate(uint256 e3Id, bytes memory publicKey)
+  * activate(uint256 e3Id, bytes memory publicKey, bytes32 publicKeyHash)
   */
packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json (1)

340-367: Breaking change to activate function signature requires documentation update.

The activate function now requires a third parameter publicKeyHash (bytes32). All code callers have been updated correctly, but the documentation in docs/pages/building-with-enclave.mdx (lines 77-79) still shows the old signature with only two parameters. Update the documentation to reflect the new function signature:

function activate(
    uint256 e3Id,
    bytes calldata publicKey,
    bytes32 publicKeyHash
) external
🧹 Nitpick comments (5)
examples/CRISP/packages/crisp-sdk/src/vote.ts (1)

283-284: Code changes correctly implement the new public inputs structure.

The indexing changes are accurate and consistent:

  • proof.publicInputs[0]: public key commitment (now being passed to setCommitteePublicKey in tests)
  • proof.publicInputs[1]: slot address (correctly extracted for Solidity encoding)
  • proof.publicInputs.slice(3): vote data (correctly extracted from index 3 onward)

This structure is confirmed by the circuit definition (main.nr with pk_commitment, slot_address, and is_first_vote as public inputs) and verified across all integration points: proof generation, JavaScript verification, and Solidity contract verification.

Consider adding a documentation comment above line 283 explaining the public inputs structure for clarity and add bounds validation before accessing array indices as a defensive coding practice:

// Public inputs: [pkCommitment, slotAddress, isFirstVote, ...voteData]
if (proof.publicInputs.length < 4) {
  throw new Error(`Invalid proof: expected at least 4 public inputs, got ${proof.publicInputs.length}`)
}
const vote = proof.publicInputs.slice(3) as `0x${string}`[]
const slotAddress = getAddress(numberToHex(BigInt(proof.publicInputs[1]), { size: 20 }))
examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol (1)

20-22: Clarify parameter naming: publicKeyHash vs committeePublicKey.

The parameter is named publicKeyHash but the storage variable is committeePublicKey. Are these semantically identical? Consider aligning the parameter name with the variable name to avoid confusion.

🔎 Suggested refactor for naming consistency
-  function setCommitteePublicKey(bytes32 publicKeyHash) external {
-    committeePublicKey = publicKeyHash;
+  function setCommitteePublicKey(bytes32 _committeePublicKey) external {
+    committeePublicKey = _committeePublicKey;
crates/bfv-helpers/Cargo.toml (1)

17-22: Consider pinning greco to the same revision for consistency.

The zkfhe-shared dependency is pinned to a specific revision, but greco from the same repository (zkfhe-generator) uses a floating git reference. If these packages need to stay in sync, this inconsistency could lead to version mismatches or build reproducibility issues.

🔎 Suggested fix
-greco = { package = "zkfhe-greco", git = "https://github.com/gnosisguild/zkfhe-generator" }
+greco = { package = "zkfhe-greco", git = "https://github.com/gnosisguild/zkfhe-generator", rev = "e2c02e6ef42348b2141293cc75f61a211c801a94" }
packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol (1)

256-260: Naming inconsistency: c.publicKey stores publicKeyHash, not the public key.

The field c.publicKey (type bytes32) now stores publicKeyHash rather than a hash of the public key computed internally. This naming is misleading. Additionally, storing the same value in both c.publicKey and publicKeyHashes[e3Id] appears redundant.

Consider renaming c.publicKey to c.publicKeyHash in the Committee struct for clarity, or consolidate the storage.

crates/events/src/enclave_event/publickey_aggregated.rs (1)

17-22: Consider adding hex formatting for public_key_hash debug output.

The pubkey field uses hexf formatter for readable debug output, but public_key_hash will display as a decimal byte array. For consistency and improved debugging experience, consider adding the same formatter.

🔎 Suggested change
 #[derive(Derivative, Message, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[derivative(Debug)]
 #[rtype(result = "()")]
 pub struct PublicKeyAggregated {
     #[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
     pub pubkey: Vec<u8>,
+    #[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
     pub public_key_hash: [u8; 32],
     pub e3_id: E3id,
     pub nodes: OrderedSet<String>,
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad8c74b and da1110e.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • examples/CRISP/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (32)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/bfv-helpers/Cargo.toml
  • crates/bfv-helpers/src/client.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/tests/Cargo.toml
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/circuits/src/main.nr
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
  • examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-sdk/src/vote.ts
  • examples/CRISP/server/src/cli/approve.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/indexer.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • packages/enclave-contracts/tasks/enclave.ts
  • packages/enclave-contracts/test/Enclave.spec.ts
  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
  • packages/enclave-sdk/src/contract-client.ts
  • packages/enclave-sdk/src/enclave-sdk.ts
🧰 Additional context used
🧠 Learnings (25)
📚 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/token_holders/etherscan.rs
  • examples/CRISP/server/src/cli/approve.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/server/src/cli/commands.rs
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • examples/CRISP/server/src/server/indexer.rs
  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2024-10-22T02:36:01.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/Cargo.toml:0-0
Timestamp: 2024-10-22T02:36:01.448Z
Learning: In `packages/ciphernode/data/Cargo.toml`, `actix-rt` is only used in tests and should remain in `[dev-dependencies]`.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • crates/tests/Cargo.toml
📚 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/server/src/server/token_holders/etherscan.rs
  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
  • crates/tests/tests/integration_legacy.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/bfv-helpers/src/client.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/token_holders/etherscan.rs
  • crates/tests/Cargo.toml
  • crates/aggregator/Cargo.toml
📚 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/token_holders/etherscan.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/server/src/cli/commands.rs
  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2025-10-04T14:18:45.636Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 660
File: crates/support-scripts/src/program_dev.rs:17-18
Timestamp: 2025-10-04T14:18:45.636Z
Learning: In crates/support-scripts/src/program_dev.rs, the #[allow(dead_code)] attribute on ProgramSupportDev is intentionally kept even though the struct appears to be referenced elsewhere, as confirmed by the maintainer.

Applied to files:

  • examples/CRISP/server/src/cli/approve.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/events/src/enclave_event/publickey_aggregated.rs
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • crates/tests/tests/integration_legacy.rs
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2024-10-29T01:04:19.137Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/keyshare/src/keyshare.rs:53-70
Timestamp: 2024-10-29T01:04:19.137Z
Learning: In the `Keyshare` struct within `packages/ciphernode/keyshare/src/keyshare.rs`, the `self.secret` field is stored in encrypted form and is not considered sensitive.

Applied to files:

  • crates/events/src/enclave_event/publickey_aggregated.rs
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • crates/evm-helpers/src/contracts.rs
📚 Learning: 2025-09-19T11:16:53.825Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 752
File: packages/enclave-contracts/contracts/Enclave.sol:15-17
Timestamp: 2025-09-19T11:16:53.825Z
Learning: The Enclave contract in the gnosisguild/enclave repository has not been deployed yet as of September 2025, so storage layout considerations for upgradeable contracts don't apply to current changes.

Applied to files:

  • crates/evm-helpers/src/contracts.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:

  • crates/evm-helpers/src/contracts.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/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 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-contracts/tests/crisp.contracts.test.ts
📚 Learning: 2024-10-16T09:52:53.807Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/src/data_store.rs:74-75
Timestamp: 2024-10-16T09:52:53.807Z
Learning: In this project, the actor model handles potential errors internally, so methods like `checkpoint` in the `Checkpoint` trait do not need to explicitly handle or propagate errors.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 133
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:137-139
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, using the same RNG instance `rng_test` for generating multiple key shares without advancing its state is acceptable.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
  • crates/bfv-helpers/src/utils/greco.rs
📚 Learning: 2025-09-11T13:21:31.031Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/tasks/utils.ts:7-8
Timestamp: 2025-09-11T13:21:31.031Z
Learning: In Hardhat v3, the task API syntax has changed significantly from v2. The new syntax uses:
- `.addOption({ name, description, defaultValue, type })` instead of `.addOptionalParam()`
- `.setAction(async () => ({ default: (args, hre) => { ... } }))` instead of direct `.setAction((args, hre) => { ... })`
- `.build()` is required to finalize task definitions
- `ArgumentType.STRING` is used for option types instead of `types.string`

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
📚 Learning: 2025-09-11T13:09:03.800Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/scripts/deployAndSave/naiveRegistryFilter.ts:30-31
Timestamp: 2025-09-11T13:09:03.800Z
Learning: In Hardhat v3 deployment scripts, use `(await signer.provider?.getNetwork())?.name ?? "localhost"` instead of `hre.globalOptions.network` to reliably get the network name, as `hre.globalOptions.network` can be undefined in some contexts.

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
📚 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:

  • crates/bfv-helpers/src/utils/greco.rs
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed to support multiple network connections: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3. Similarly, `.revertedWithoutReason(ethers)` replaces `.revertedWithoutReason`.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 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:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 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:

  • crates/bfv-helpers/src/client.rs
📚 Learning: 2024-10-08T07:15:06.690Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/evm/src/ciphernode_registry_sol.rs:133-143
Timestamp: 2024-10-08T07:15:06.690Z
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:

  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2025-08-29T16:46:50.289Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 666
File: examples/CRISP/contracts/CRISPChecker.sol:9-9
Timestamp: 2025-08-29T16:46:50.289Z
Learning: In hashcloak/semaphore-contracts-noir package, the interface is still named ISemaphore, not ISemaphoreNoir. The Noir support was added via Noir verifier contracts while keeping the original ISemaphore interface name.

Applied to files:

  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 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-contracts/contracts/CRISPProgram.sol
🧬 Code graph analysis (6)
examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (1)
examples/CRISP/packages/crisp-contracts/tests/utils.ts (2)
  • deployMockEnclave (43-47)
  • deployCRISPProgram (69-87)
crates/tests/tests/integration_legacy.rs (2)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/trbfv/src/trbfv_config.rs (1)
  • params (34-36)
examples/CRISP/server/src/cli/commands.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/aggregator/src/publickey_aggregator.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
examples/CRISP/server/src/server/indexer.rs (2)
examples/CRISP/crates/crisp-constants/src/lib.rs (1)
  • get_default_paramset (10-13)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/bfv-helpers/src/client.rs (3)
crates/bfv-helpers/src/utils/greco.rs (1)
  • bfv_public_key_to_greco (233-283)
crates/bfv-helpers/src/lib.rs (1)
  • build_bfv_params_arc (278-300)
crates/utils/src/utility_types.rs (1)
  • from_bytes (25-27)
⏰ 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: build_crisp_sdk
  • GitHub Check: build_sdk
  • GitHub Check: build_ciphernode_image
  • GitHub Check: test_net
  • GitHub Check: integration_prebuild
  • GitHub Check: build_enclave_cli
  • GitHub Check: rust_integration
  • GitHub Check: rust_unit
  • GitHub Check: Build & Push Image
🔇 Additional comments (52)
examples/CRISP/server/src/server/token_holders/etherscan.rs (1)

10-10: Clean import refactor with correct scoping.

The changes properly add the eyre import (necessary for error handling with .context() calls throughout the file) and scope the CONFIG import to the test module only, which is correct since it's exclusively used in integration tests. No behavioral changes or public API impact.

Also applies to: 625-625

packages/enclave-sdk/src/enclave-sdk.ts (1)

329-329: LGTM!

The method signature and forwarding call correctly include the new publicKeyHash parameter, maintaining consistency with the contract-client.ts changes. The implementation properly threads the parameter through the SDK layer.

Also applies to: 334-334

examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (1)

137-138: LGTM - E3 data fetch for committee public key.

The retrieval pattern is consistent with the existing decodeTally function. Since validateInput is called via authorized contracts after E3 initialization, the E3 should always exist at this point.

examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol (4)

17-17: Consistent with the global constant update.

The publicInputsSize correctly matches the updated NUMBER_OF_PUBLIC_INPUTS constant at line 10. This ensures internal consistency within the verification key structure.


18-129: Verification key coordinates updated - auto-generated changes.

The verification key G1 point coordinates have been updated across multiple selectors and permutation polynomials. These changes are expected when the circuit is modified (adding a public input changes the constraint system).

Note that t1 through t4 (precomputed table commitments) and lagrangeFirst remained unchanged, which is expected as they may be circuit-independent or use standard values.

Since these values are auto-generated by the circuit compiler, manual validation is not practical. The key verification is ensuring the circuit compilation was successful and the VK_HASH correctly represents this new verification key.


10-11: Verify circuit regeneration and VK_HASH correspondence with updated verification key.

The public input count increased from 2066 to 2067 to add public key commitment. The constants are correctly propagated: NUMBER_OF_PUBLIC_INPUTS = 2067 (line 10) is passed to the HonkVerifier constructor (line 2415) and used in publicInputsSize (line 17). Calling code in CRISPProgram.sol (line 151) passes public inputs as a variable-sized array rather than a hardcoded count, so integration is not impacted by this change.

However, verify that:

  1. The circuit was correctly regenerated with the new public key commitment as a public input
  2. The new VK_HASH corresponds to the regenerated verification key

2415-2419: The verification key implementation is correct. The circuit source properly includes public input commitments (including the committee public key), the compilation process via compile_circuits.sh generates matching artifacts with the correct VK_HASH, and comprehensive test vectors in crisp.contracts.test.ts validate proof generation and verification with the updated public inputs. No further changes needed.

examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol (1)

14-14: LGTM! Mock enclave now exposes configurable committee public key.

The addition of the committeePublicKey state variable and its exposure through getE3 correctly enables tests to configure the committee public key for proof verification.

Also applies to: 38-38

examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (3)

26-27: LGTM! Mock enclave properly integrated for tally decoding test.

The mock enclave deployment and integration is correct. This test doesn't require setting the committee public key since it only validates tally decoding, not proof verification.


74-75: LGTM! Mock enclave correctly deployed for proof verification test.

The mock enclave is properly instantiated and passed to the CRISP program deployment, enabling the test to configure the committee public key for proof verification.


97-97: proof.publicInputs[0] correctly contains the public key commitment.

The Noir circuit (examples/CRISP/circuits/src/main.nr) explicitly defines pk_commitment: pub Field as the first public input, and the subsequent encodeSolidityProof function confirms that publicInputs[1] is the slot address, which validates that publicInputs[0] is indeed the public key commitment. The code is correct.

crates/aggregator/Cargo.toml (1)

21-21: LGTM!

The workspace dependency addition enables the compute_pk_commitment function usage for deriving public key hashes in the aggregator.

examples/CRISP/server/src/cli/approve.rs (1)

28-28: LGTM!

Removal of unused Provider import is a clean-up that reduces unnecessary dependencies in scope.

packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json (1)

425-437: New feeToken() view function added.

This addition appears unrelated to the PR's stated objective of passing public key commitment for proof verification. Verify this is intentionally bundled or if it should be in a separate PR.

packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol (1)

243-248: LGTM on the signature update.

The publishCommittee function now accepts publicKeyHash as an explicit parameter, aligning with the PR objective to pass public key commitment for proof verification. The TODO comments appropriately flag the need for future verification that the public key matches the committee.

packages/enclave-contracts/tasks/enclave.ts (2)

258-263: LGTM on the publicKeyHash option addition.

The new option with proper validation at lines 290-292 ensures the hash is provided when publishing committees.


346-347: Hash computation inconsistency between ethers.id() and Rust compute_pk_commitment: clarify usage.

ethers.id(publicKey) computes keccak256 of the UTF-8 string representation, while the Rust compute_pk_commitment expects raw bytes + BFV parameters (degree, plaintext_modulus, moduli). These produce different outputs.

The contract has no validation against compute_pk_commitment (noted in the CiphernodeRegistryOwnable TODO), so the hash is only used for consistency checking between publishCommittee and activate calls. Both tasks in enclave.ts use ethers.id() consistently with each other, so they work together.

However, if integration with Rust-generated keys is intended, clarify whether the hash should be computed via compute_pk_commitment instead, or document that these tasks are for development/testing only and incompatible with Rust-computed hashes.

crates/tests/Cargo.toml (1)

34-34: LGTM!

Adding e3-bfv-helpers enables test code to use compute_pk_commitment for verifying public key hash computations.

packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts (2)

31-31: Consistent hash computation with task implementation.

Using ethers.id(data) matches the pattern in activateE3 task. For testing purposes, this internal consistency is appropriate.


361-369: LGTM on test updates for publishCommittee.

The test correctly passes dataHash as the fourth argument and verifies that committeePublicKey returns the expected hash value.

examples/CRISP/circuits/src/main.nr (1)

54-56: LGTM!

Making pk_commitment a public input is correct for the proof verification flow. This allows the verifier to confirm that the commitment used in the proof matches the expected public key hash published on-chain.

crates/evm-helpers/src/contracts.rs (3)

10-10: LGTM!

The FixedBytes import is correctly added to support the new bytes32 parameter type.


78-78: LGTM!

The Solidity interface definition correctly reflects the updated activate function signature with the new publicKeyHash parameter.


141-146: LGTM!

The trait signature and implementation are consistent. The FixedBytes<32> type correctly maps to the Solidity bytes32 parameter.

Also applies to: 408-425

crates/aggregator/src/publickey_aggregator.rs (2)

9-9: LGTM!

The import correctly brings in the compute_pk_commitment function needed for deriving the public key hash.


185-210: LGTM!

The commitment computation is correctly placed after public key aggregation and before state update. The parameters passed (degree, plaintext, moduli) correctly reflect the FHE parameters used during key generation. The computed hash is properly included in the PublicKeyAggregated event.

Note that if compute_pk_commitment fails, the entire aggregation handler returns an error, which is appropriate behavior since the commitment is now a required part of the activation flow.

packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol (1)

158-164: LGTM!

The interface correctly adds the publicKeyHash parameter with appropriate documentation. This aligns with the contract implementation changes elsewhere in the PR.

crates/bfv-helpers/src/client.rs (2)

8-8: LGTM!

The import correctly brings in the Greco conversion utility needed for computing the public key commitment.


133-158: The implementation is sound and already defensive. The conversion at lines 152-155 uses .try_into() with explicit error handling rather than assuming the output is exactly 32 bytes, so the concern in the review comment is already addressed in the code.

crates/tests/tests/integration_legacy.rs (3)

11-11: LGTM!

The import correctly brings in compute_pk_commitment for test verification.


223-235: LGTM!

The test correctly computes the expected public_key_hash using the same parameters as the production aggregator code, ensuring the test validates the actual commitment computation logic.


572-593: LGTM!

The duplicate E3 ID test correctly verifies that different chain IDs produce independent public_key_hash values through separate aggregation flows.

Also applies to: 615-635

packages/enclave-contracts/contracts/interfaces/IEnclave.sol (1)

155-161: LGTM!

The interface correctly adds the publicKeyHash parameter to the activate function with appropriate documentation. This is consistent with the implementation changes in the Rust contract bindings and the registry interface.

examples/CRISP/server/src/server/indexer.rs (2)

17-20: LGTM! Imports correctly added for the new PK commitment flow.

The imports for FixedBytes, get_default_paramset, and compute_pk_commitment are necessary for computing and passing the public key commitment during activation.


359-376: LGTM! PK commitment computation and activation flow updated correctly.

The code properly:

  1. Retrieves BFV parameters from the default param set
  2. Computes the PK commitment using the public key and parameters
  3. Converts to FixedBytes and passes to the updated activate call

Error handling with map_err appropriately propagates commitment computation failures.

packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json (1)

375-380: LGTM! ABI correctly updated with new publicKeyHash parameter.

The publishCommittee function signature now includes the bytes32 publicKeyHash parameter, aligning with the interface changes across the PR.

crates/bfv-helpers/src/utils/greco.rs (4)

9-9: LGTM! PublicKey import added for the new conversion function.


185-220: LGTM! BFV to Greco coefficient conversion helpers implemented correctly.

The conversion logic properly:

  1. Centers coefficients from [0, qi) to [-(qi-1)/2, (qi-1)/2]
  2. Reverses coefficient order (matching Greco format)
  3. Reduces modulo ZKP modulus with correct handling of negative values

233-283: LGTM! bfv_public_key_to_greco function correctly converts BFV public keys to Greco format.

The implementation:

  1. Accesses pk0/pk1 polynomials from the public key structure
  2. Converts to power basis representation for coefficient extraction
  3. Iterates over moduli to extract and convert coefficients per RNS component
  4. Applies the Greco transformation (centering, reversing, ZKP modulus reduction)

385-472: LGTM! Comprehensive test validates the conversion against GrecoVectors reference.

The test correctly verifies that bfv_public_key_to_greco produces identical output to the established GrecoVectors::compute path, ensuring the new conversion is accurate.

packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol (2)

41-46: LGTM! Mock updated to match interface.

The publishCommittee signature correctly includes the new bytes32 parameter to comply with the updated ICiphernodeRegistry interface.


118-123: LGTM! Second mock also updated consistently.

MockCiphernodeRegistryEmptyKey.publishCommittee signature updated to match the interface change.

packages/enclave-contracts/test/Enclave.spec.ts (4)

58-58: Verify: ethers.id() vs ethers.keccak256() for dataHash computation.

ethers.id(data) computes keccak256 of the UTF-8 encoded string "0xda7a", not the bytes 0xda7a. If the intent is to hash the raw bytes, use ethers.keccak256(data) instead. Please confirm this is the intended behavior for test purposes.


76-77: LGTM! setupAndPublishCommittee correctly computes and passes publicKeyHash.

The helper function now derives publicKeyHash using ethers.id(publicKey) and passes it to registry.publishCommittee, aligning with the updated contract interface.


942-946: LGTM! All activate calls updated with the new dataHash parameter.

The test cases consistently pass dataHash as the third argument to enclave.activate(), matching the updated contract signature.

Also applies to: 978-984, 1003-1003, 1038-1040, 1060-1060, 1092-1094, 1117-1117, 1131-1133, 1173-1173, 1209-1211, 1244-1244


1601-1601: LGTM! Output expectation updated to use keccak256.

The assertion now expects ciphertextOutput to equal ethers.keccak256(data), reflecting the contract's storage of the hash.

examples/CRISP/server/src/cli/commands.rs (2)

15-15: LGTM! Imports added for the new PK commitment flow.

Also applies to: 19-19


211-222: LGTM! PK commitment computed and passed to activate.

The implementation correctly:

  1. Extracts BFV parameters from the generated key's parameters
  2. Computes the commitment using compute_pk_commitment
  3. Converts to FixedBytes for the contract call

The error handling with map_err provides a descriptive message for CLI users.

packages/enclave-contracts/contracts/Enclave.sol (1)

298-323: LGTM! Activation function updated to accept and verify publicKeyHash.

The changes correctly:

  1. Accept publicKeyHash as a parameter instead of computing on-chain
  2. Verify against the registry's stored committeePublicKey (renamed to registryPublicKeyHash for clarity)
  3. Store the provided hash as committeePublicKey
  4. Continue emitting the full publicKey in the event for off-chain consumers

This approach moves the hash computation off-chain while maintaining verification integrity through the registry check.

crates/evm/src/ciphernode_registry_sol.rs (3)

12-12: LGTM! FixedBytes import added for the new hash type.


406-424: LGTM! Handler correctly extracts and propagates public_key_hash.

The PublicKeyAggregated handler now extracts public_key_hash from the message and passes it through to publish_committee_to_registry.


487-514: LGTM! publish_committee_to_registry updated with public_key_hash parameter.

The function correctly:

  1. Accepts public_key_hash: [u8; 32] as a new parameter
  2. Converts to FixedBytes for the contract call
  3. Passes the hash to the updated publishCommittee contract method

Comment thread examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol Outdated
Comment thread packages/enclave-sdk/src/contract-client.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
packages/enclave-contracts/tasks/enclave.ts (1)

333-347: Refactor hash computation to use consistent mechanism across TypeScript and Rust codebases.

Line 346 uses ethers.id(publicKey) (Keccak256 hash), but the Rust server code uses compute_pk_commitment() with BFV parameters (degree, plaintext_modulus, moduli) to compute a different hash based on Greco bounds. These two approaches produce fundamentally different results. The contract will reject the activation with CommitteeSelectionFailed() because the hashes will not match what was stored by the registry.

The TypeScript task must either:

  1. Call compute_pk_commitment() with the same BFV parameters used by the Rust server, or
  2. Use a native TypeScript/JavaScript implementation of the same algorithm.
🧹 Nitpick comments (1)
crates/bfv-helpers/src/client.rs (1)

133-158: New compute_pk_commitment function looks correct.

The implementation follows the same pattern as bfv_verifiable_encrypt for parameter construction and bounds computation. The flow is clear: deserialize the public key, compute Greco bounds, convert to Greco representation, and compute the commitment.

A minor note: the variable public_key is shadowed on line 143 (parameter → deserialized PublicKey). This is a common Rust idiom for type refinement, but if you prefer explicit naming, consider renaming the deserialized key to pk for consistency with other functions in this file.

🔎 Optional: Avoid variable shadowing for clarity
 pub fn compute_pk_commitment(
     public_key: Vec<u8>,
     degree: usize,
     plaintext_modulus: u64,
     moduli: Vec<u64>,
 ) -> Result<[u8; 32]> {
     use shared::commitments::compute_pk_commitment as compute_pk_commitment_shared;

     let params = build_bfv_params_arc(degree, plaintext_modulus, &moduli, None);

-    let public_key = PublicKey::from_bytes(&public_key, &params)
+    let pk = PublicKey::from_bytes(&public_key, &params)
         .map_err(|e| anyhow!("Error deserializing public key: {}", e))?;

     let (_, bounds) = GrecoBounds::compute(&params, 0)?;
     let bit_pk = shared::template::calculate_bit_width(&bounds.pk_bounds[0].to_string())?;

-    let (pk0is, pk1is) = bfv_public_key_to_greco(&public_key, &params);
+    let (pk0is, pk1is) = bfv_public_key_to_greco(&pk, &params);
     let commitment_bigint = compute_pk_commitment_shared(&pk0is, &pk1is, bit_pk);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad8c74b and 95653a5.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • examples/CRISP/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/bfv-helpers/src/client.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/tests/Cargo.toml
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/circuits/src/main.nr
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
  • examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-sdk/src/vote.ts
  • examples/CRISP/server/src/cli/approve.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/indexer.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • packages/enclave-contracts/tasks/enclave.ts
  • packages/enclave-contracts/test/Enclave.spec.ts
  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
  • packages/enclave-sdk/src/contract-client.ts
  • packages/enclave-sdk/src/enclave-sdk.ts
🧰 Additional context used
🧠 Learnings (23)
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/tests/tests/integration_legacy.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/aggregator/src/publickey_aggregator.rs
📚 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:

  • crates/events/src/enclave_event/publickey_aggregated.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • examples/CRISP/server/src/server/indexer.rs
  • crates/tests/tests/integration_legacy.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/aggregator/src/publickey_aggregator.rs
  • examples/CRISP/server/src/cli/approve.rs
📚 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:

  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/tests/tests/integration_legacy.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/bfv-helpers/src/client.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:

  • crates/tests/Cargo.toml
  • crates/aggregator/Cargo.toml
📚 Learning: 2024-10-22T02:36:01.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/Cargo.toml:0-0
Timestamp: 2024-10-22T02:36:01.448Z
Learning: In `packages/ciphernode/data/Cargo.toml`, `actix-rt` is only used in tests and should remain in `[dev-dependencies]`.

Applied to files:

  • crates/tests/Cargo.toml
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 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:

  • packages/enclave-sdk/src/enclave-sdk.ts
📚 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/cli/commands.rs
  • crates/tests/tests/integration_legacy.rs
  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2024-10-16T09:51:10.038Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/committee_meta.rs:43-43
Timestamp: 2024-10-16T09:51:10.038Z
Learning: In `packages/ciphernode/router/src/committee_meta.rs`, avoid suggesting making the `on_event` method in `CommitteMetaFeature` asynchronous or adding error handling for the `write` operation to the data store.

Applied to files:

  • examples/CRISP/server/src/server/indexer.rs
  • crates/evm/src/ciphernode_registry_sol.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/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
📚 Learning: 2025-08-29T16:46:50.289Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 666
File: examples/CRISP/contracts/CRISPChecker.sol:9-9
Timestamp: 2025-08-29T16:46:50.289Z
Learning: In hashcloak/semaphore-contracts-noir package, the interface is still named ISemaphore, not ISemaphoreNoir. The Noir support was added via Noir verifier contracts while keeping the original ISemaphore interface name.

Applied to files:

  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 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-contracts/contracts/CRISPProgram.sol
📚 Learning: 2024-10-16T09:52:53.807Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/src/data_store.rs:74-75
Timestamp: 2024-10-16T09:52:53.807Z
Learning: In this project, the actor model handles potential errors internally, so methods like `checkpoint` in the `Checkpoint` trait do not need to explicitly handle or propagate errors.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 133
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:137-139
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, using the same RNG instance `rng_test` for generating multiple key shares without advancing its state is acceptable.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
  • crates/bfv-helpers/src/utils/greco.rs
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • crates/evm-helpers/src/contracts.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:

  • crates/bfv-helpers/src/utils/greco.rs
📚 Learning: 2024-11-05T06:56:49.157Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/enclave_node/src/aggregator.rs:0-0
Timestamp: 2024-11-05T06:56:49.157Z
Learning: `RegistryFilterSol` does not have a reader and does not require a repository reader or deploy block when calling `RegistryFilterSol::attach` in `packages/ciphernode/enclave_node/src/aggregator.rs`.

Applied to files:

  • crates/evm/src/ciphernode_registry_sol.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-contracts/tests/crisp.contracts.test.ts
📚 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:

  • crates/bfv-helpers/src/client.rs
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed to support multiple network connections: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3. Similarly, `.revertedWithoutReason(ethers)` replaces `.revertedWithoutReason`.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 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:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T13:21:31.031Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/tasks/utils.ts:7-8
Timestamp: 2025-09-11T13:21:31.031Z
Learning: In Hardhat v3, the task API syntax has changed significantly from v2. The new syntax uses:
- `.addOption({ name, description, defaultValue, type })` instead of `.addOptionalParam()`
- `.setAction(async () => ({ default: (args, hre) => { ... } }))` instead of direct `.setAction((args, hre) => { ... })`
- `.build()` is required to finalize task definitions
- `ArgumentType.STRING` is used for option types instead of `types.string`

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
📚 Learning: 2025-09-11T13:09:03.800Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/scripts/deployAndSave/naiveRegistryFilter.ts:30-31
Timestamp: 2025-09-11T13:09:03.800Z
Learning: In Hardhat v3 deployment scripts, use `(await signer.provider?.getNetwork())?.name ?? "localhost"` instead of `hre.globalOptions.network` to reliably get the network name, as `hre.globalOptions.network` can be undefined in some contexts.

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
🧬 Code graph analysis (7)
examples/CRISP/server/src/cli/commands.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
examples/CRISP/server/src/server/indexer.rs (2)
examples/CRISP/crates/crisp-constants/src/lib.rs (1)
  • get_default_paramset (10-13)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/tests/tests/integration_legacy.rs (2)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/trbfv/src/trbfv_config.rs (1)
  • params (34-36)
crates/aggregator/src/publickey_aggregator.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (1)
examples/CRISP/packages/crisp-contracts/tests/utils.ts (2)
  • deployMockEnclave (43-47)
  • deployCRISPProgram (69-87)
examples/CRISP/packages/crisp-sdk/src/vote.ts (1)
examples/CRISP/client/libs/crispSDKWorker.js (2)
  • proof (25-25)
  • slotAddress (14-14)
crates/bfv-helpers/src/client.rs (2)
crates/bfv-helpers/src/utils/greco.rs (1)
  • bfv_public_key_to_greco (233-283)
crates/bfv-helpers/src/lib.rs (1)
  • build_bfv_params_arc (278-300)
⏰ 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). (5)
  • GitHub Check: integration_prebuild
  • GitHub Check: build_enclave_cli
  • GitHub Check: rust_integration
  • GitHub Check: build_ciphernode_image
  • GitHub Check: rust_unit
🔇 Additional comments (55)
examples/CRISP/server/src/server/token_holders/etherscan.rs (1)

621-621: Redundant import statement; verify PR scope alignment.

Line 620's use super::*; already brings CONFIG into scope, making the explicit import on line 621 redundant. More importantly, this file's changes don't align with the PR objectives about public key commitment hashing—the Etherscan client is unrelated to proof verification or key management.

Can you clarify why this file is included in the PR? If the import is intentional for documentation purposes, consider removing the wildcard import to avoid confusion. Alternatively, if this file should not be part of the public key commitment refactor, it may have been included in error.

examples/CRISP/server/src/cli/approve.rs (1)

28-28: Good cleanup: unused import removed.

Removing the unused Provider import is good practice. The code only uses ProviderBuilder and relies on type inference for the provider instance.

Note: This change appears unrelated to the PR's stated objective of passing public key commitment for proof verification. If this is intentional cleanup alongside the main changes, that's fine.

crates/aggregator/Cargo.toml (1)

21-21: LGTM!

The addition of the e3-bfv-helpers workspace dependency is correct and necessary to enable public key commitment computation in the aggregator.

examples/CRISP/circuits/src/main.nr (1)

56-56: LGTM!

Exposing pk_commitment as a public input is correct and aligns with the PR's goal of enabling on-chain verification of the public key commitment.

examples/CRISP/server/src/cli/commands.rs (1)

212-222: LGTM!

The public key commitment computation is correctly implemented:

  • Uses compute_pk_commitment with appropriate BFV parameters
  • Proper error handling via map_err
  • Correctly converts the result to FixedBytes<32> for the contract call
packages/enclave-contracts/contracts/interfaces/IEnclave.sol (1)

155-161: LGTM!

The interface signature update correctly adds the publicKeyHash parameter to the activate function, with appropriate documentation.

packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json (2)

350-355: LGTM!

The ABI correctly reflects the updated activate function signature with the new publicKeyHash parameter of type bytes32.


425-437: LGTM!

The addition of the feeToken function to the ABI is correct and aligns with the interface definition.

packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol (1)

158-164: LGTM!

The publishCommittee signature update correctly adds the publicKeyHash parameter with appropriate documentation.

packages/enclave-contracts/tasks/enclave.ts (2)

258-263: LGTM!

The addition of the publicKeyHash option to the publishCommittee task is correctly implemented.


290-298: LGTM!

The validation guard and usage of publicKeyHash in the publishCommittee call are correctly implemented.

crates/events/src/enclave_event/publickey_aggregated.rs (1)

19-19: LGTM!

The addition of the public_key_hash field to the PublicKeyAggregated struct is correct and maintains proper serialization support.

crates/tests/Cargo.toml (1)

34-34: LGTM!

The e3-bfv-helpers dependency is correctly added with workspace configuration, maintaining alphabetical ordering with existing dependencies.

examples/CRISP/packages/crisp-sdk/src/vote.ts (1)

282-286: LGTM!

The index adjustments correctly reflect the new public inputs layout where publicKeyHash is now at index 0. The updated indices align with CRISPProgram.sol where:

  • noirPublicInputs[0] = committeePublicKey
  • noirPublicInputs[1] = slotAddress
  • noirPublicInputs[2] = isFirstVote
  • noirPublicInputs[3+] = vote bytes
packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts (5)

31-31: Verify: ethers.id() vs ethers.keccak256() behavioral difference.

ethers.id(data) computes the keccak256 of the UTF-8 string representation, while ethers.keccak256(data) hashes the raw bytes. For data = "0xda7a":

  • keccak256 would hash 2 bytes [0xda, 0x7a]
  • id hashes the 6-character string "0xda7a"

If this is intentional for test simplicity (since the actual publicKeyHash in production comes from compute_pk_commitment), the change is fine. Otherwise, this may cause unexpected behavior if tests are meant to mirror production hashing.


339-348: LGTM!

The publishCommittee call correctly passes dataHash as the new fourth parameter, consistent with the updated contract signature.


361-369: LGTM!

The test correctly verifies that committeePublicKey(request.e3Id) returns the provided dataHash, aligning with the new contract behavior where the hash is stored directly rather than computed.


381-394: LGTM!

The event assertion correctly passes dataHash to publishCommittee and verifies CommitteePublished emission with the expected arguments.


509-517: LGTM!

The committeePublicKey() getter test correctly uses dataHash and verifies the returned value matches.

examples/CRISP/server/src/server/indexer.rs (2)

17-20: LGTM!

The new imports are correctly added for:

  • FixedBytes for the 32-byte hash type
  • get_default_paramset for BFV parameters
  • compute_pk_commitment for deriving the public key hash

358-386: LGTM!

The handle_committee_time_expired function correctly:

  1. Retrieves BFV parameters from the default parameter set
  2. Computes the PK commitment hash from the public key
  3. Propagates errors with a descriptive message
  4. Passes the hash as FixedBytes<32> to the activate call

The error handling is appropriate, and the conversion from [u8; 32] to FixedBytes is correct.

Note that get_default_paramset() uses insecure parameters (as documented in crisp-constants/src/lib.rs). Ensure this is only used in development/testing contexts and not in production deployments.

packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol (1)

242-261: LGTM!

The publishCommittee function signature is correctly updated to accept a precomputed publicKeyHash. Key observations:

  1. The onlyOwner modifier ensures only trusted callers can provide this hash
  2. The TODO comment appropriately documents the trust assumption
  3. The CommitteePublished event correctly emits the full publicKey for transparency while storing the hash

This aligns with the PR objective of moving commitment computation off-chain.

examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol (2)

14-22: LGTM!

The mock contract is correctly updated with a committeePublicKey state variable and setter, enabling tests to configure the public key hash that getE3() returns.


38-38: LGTM!

The getE3 return now uses the configurable committeePublicKey state variable instead of a hardcoded zero value, allowing proper test simulation.

examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (1)

137-148: LGTM!

The validateInput function correctly:

  1. Fetches the E3 data to retrieve the committed public key
  2. Expands the public inputs array to accommodate committeePublicKey
  3. Reorders public inputs: [committeePublicKey, slotAddress, isFirstVote, ...vote]

This ensures the Noir proof is verified against the on-chain committed public key, aligning with the SDK's encodeSolidityProof changes.

examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (2)

74-75: LGTM!

The test correctly deploys mockEnclave and passes it to deployCRISPProgram, ensuring the program has a reference to the mock for getE3 calls.


97-98: LGTM!

Setting committeePublicKey from proof.publicInputs[0] before calling validateInput ensures the mock enclave returns the correct hash that matches the proof's committed public key. This is essential for the proof verification to succeed.

examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol (1)

10-17: Verification key updates align with circuit changes.

The increment of NUMBER_OF_PUBLIC_INPUTS from 2066 to 2067 correctly reflects the addition of the public key commitment as a new public input in the circuit. The updated VK_HASH and publicInputsSize are consistent with this change.

crates/tests/tests/integration_legacy.rs (2)

223-235: Test correctly computes and validates public key commitment.

The test properly derives public_key_hash using compute_pk_commitment with the correct BFV parameters (degree, plaintext, moduli) extracted from the params object, and includes it in the expected PublicKeyAggregated event for assertion.


572-593: Duplicate E3 ID test correctly validates public key hash for both chain IDs.

The test computes public_key_hash for each E3 request and properly asserts that the PublicKeyAggregated event contains the expected hash, validating the new field across different chain IDs.

packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol (2)

41-46: Mock contract signature updated to match interface.

The publishCommittee function signature correctly adds the bytes32 parameter for publicKeyHash, aligning with the updated ICiphernodeRegistry interface. The empty implementation is appropriate for a mock.


118-123: Consistent update applied to MockCiphernodeRegistryEmptyKey.

Both mock contracts now have consistent publishCommittee signatures matching the updated interface.

crates/aggregator/src/publickey_aggregator.rs (1)

185-210: Public key commitment computed and propagated correctly.

The compute_pk_commitment call uses the correct parameters from self.fhe.params and the error is properly propagated with ?. The commitment is computed before state update and included in the PublicKeyAggregated event.

crates/bfv-helpers/src/utils/greco.rs (3)

185-220: Coefficient conversion helpers are correctly implemented.

convert_bfv_coefficient_to_centered properly centers coefficients from [0, qi) to [-(qi-1)/2, (qi-1)/2]. convert_bfv_coefficients_to_greco correctly reverses, centers, and reduces mod ZKP modulus with proper handling of negative values.


233-283: BFV public key to Greco conversion is well-structured.

The function correctly accesses the public key polynomials via pk.c.c[0] and pk.c.c[1], converts to PowerBasis representation to extract coefficients, and applies the Greco format conversion for each modulus.


385-472: Comprehensive test validates against reference implementation.

The test compares the output of bfv_public_key_to_greco against GrecoVectors.compute().standard_form(), providing strong validation that the conversion matches the expected Greco format.

packages/enclave-sdk/src/enclave-sdk.ts (1)

329-335: SDK activateE3 method correctly updated with publicKeyHash parameter.

The new publicKeyHash parameter is appropriately placed and typed as `0x${string}`, consistent with other hex-encoded parameters in the SDK. The parameter is correctly forwarded to the contract client.

packages/enclave-sdk/src/contract-client.ts (1)

164-194: Contract client activateE3 correctly propagates publicKeyHash to contract call.

The method signature and simulateContract args array are updated to include publicKeyHash, matching the updated Enclave.activate function signature. The transaction simulation and execution flow remain correct.

packages/enclave-contracts/contracts/Enclave.sol (1)

298-324: Activation flow correctly validates publicKeyHash against registry.

The function now verifies the provided publicKeyHash against ciphernodeRegistry.committeePublicKey(e3Id) rather than computing keccak256(publicKey). This aligns with the new commitment scheme where the hash is a Greco/Poseidon-based commitment computed off-chain and stored in the registry during committee publication.

Note that publicKey is still accepted and emitted in the E3Activated event for off-chain consumers, but the on-chain verification relies on the registry-stored commitment. This trust model is appropriate since the registry value is set by the trusted aggregator during publishCommittee.

packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json (1)

375-380: LGTM!

The publishCommittee function signature correctly adds the new publicKeyHash parameter of type bytes32, aligning with the PR objective to propagate public key commitment through the registry flow.

crates/bfv-helpers/src/client.rs (1)

152-155: Potential issue: BigInt byte conversion may not always produce exactly 32 bytes.

BigInt::to_bytes_be() returns the minimal byte representation, which may be fewer than 32 bytes if there are leading zeros, or could potentially be more than 32 bytes if the commitment value is unexpectedly large. This would cause try_into() to fail.

Consider padding to ensure exactly 32 bytes:

🔎 Proposed fix: Pad bytes to 32
     let commitment_bigint = compute_pk_commitment_shared(&pk0is, &pk1is, bit_pk);

-    let bytes = commitment_bigint.to_bytes_be().1;
-    let public_key_hash: [u8; 32] = bytes
-        .try_into()
-        .map_err(|_| anyhow!("Commitment must be exactly 32 bytes"))?;
+    let bytes = commitment_bigint.to_bytes_be().1;
+    if bytes.len() > 32 {
+        return Err(anyhow!("Commitment exceeds 32 bytes"));
+    }
+    let mut public_key_hash = [0u8; 32];
+    public_key_hash[32 - bytes.len()..].copy_from_slice(&bytes);

     Ok(public_key_hash)
 }

Please verify that compute_pk_commitment_shared always returns a value that fits exactly in 32 bytes, or consider the padding approach above to handle variable-length BigInt representations.

crates/evm-helpers/src/contracts.rs (3)

10-10: LGTM!

The FixedBytes import is correctly added to support the new bytes32 parameter type.


78-78: LGTM!

The Solidity ABI definition correctly adds publicKeyHash as bytes32 to the activate function signature, matching the updated contract interface.


141-146: LGTM!

The EnclaveWrite::activate trait and its implementation are correctly updated to accept and forward the new pub_key_hash: FixedBytes<32> parameter. The implementation properly passes it to the contract call on line 421.

Also applies to: 408-425

crates/evm/src/ciphernode_registry_sol.rs (3)

12-12: LGTM!

The FixedBytes import is correctly added for the new parameter type.


406-432: LGTM!

The PublicKeyAggregated handler correctly extracts the new public_key_hash field from the message and passes it through to publish_committee_to_registry. The async block properly captures and forwards the hash.


487-515: LGTM!

The publish_committee_to_registry function is correctly updated:

  • New parameter public_key_hash: [u8; 32] added to signature
  • Conversion to FixedBytes on line 498
  • Contract call updated to include the hash on line 511

This aligns with the updated ICiphernodeRegistry interface.

packages/enclave-contracts/test/Enclave.spec.ts (8)

57-58: LGTM!

The dataHash computation using ethers.id(data) (which computes keccak256(toUtf8Bytes(data))) is consistent with how it's used in the test's activate calls.


64-78: LGTM!

The setupAndPublishCommittee helper is correctly updated to:

  1. Compute publicKeyHash using ethers.id(publicKey) on line 76
  2. Pass it as the 4th parameter to publishCommittee on line 77

This aligns with the updated registry interface.


938-984: LGTM!

The activate() test cases are correctly updated to use the new 3-parameter signature (e3Id, data, dataHash). The tests properly validate:

  • E3 does not exist (line 942-944)
  • E3 already activated (line 978-983)

1001-1004: LGTM!

All activate-related test scenarios are consistently updated with the new dataHash parameter:

  • E3NotReady checks
  • E3Expired checks
  • CommitteeSelectionFailed checks
  • Success path validations

Also applies to: 1036-1041, 1058-1061, 1090-1095, 1115-1118, 1129-1134


1171-1177: LGTM!

The remaining activate() tests for:

  • Setting committeePublicKey correctly
  • Return value validation via staticCall
  • E3Activated event emission

All correctly use the updated 3-parameter signature.

Also applies to: 1207-1212, 1242-1248


1309-1309: LGTM!

The publishInput() test scenarios correctly call activate() with the new signature before testing input publication.

Also applies to: 1343-1343, 1383-1383, 1404-1404, 1436-1436


1493-1493: LGTM!

The publishCiphertextOutput() tests correctly use the updated activate() signature.

Note on line 1601: The assertion expect(e3.ciphertextOutput).to.equal(ethers.keccak256(data)) uses keccak256 (raw bytes hash) rather than ethers.id (UTF-8 encoded hash), which is correct since ciphertextOutput stores the hash of the raw ciphertext bytes.

Also applies to: 1528-1528, 1567-1567, 1597-1601, 1627-1627, 1657-1657


1711-1711: LGTM!

The publishPlaintextOutput() tests correctly use the updated activate() signature throughout all test cases.

Also applies to: 1740-1740, 1775-1775, 1806-1806, 1838-1838, 1869-1869

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol (1)

242-261: Add validation to ensure the provided publicKeyHash matches the publicKey parameter.

The function accepts a pre-computed publicKeyHash without validating it against the provided publicKey. While the TODO comments acknowledge trusting the owner, this creates a risk of storing a mismatched hash if the caller provides incorrect values.

Since publicKey is available as a parameter and tests confirm keccak256 is the hash function used (via ethers.id()), add a validation check:

require(publicKeyHash == keccak256(publicKey), "Hash mismatch");

This prevents accidental consistency issues without additional computational overhead.

🧹 Nitpick comments (3)
examples/CRISP/packages/crisp-sdk/src/vote.ts (1)

283-284: Consider adding bounds validation for publicInputs array.

The function accesses proof.publicInputs[1] and proof.publicInputs.slice(3) without validating that the array has sufficient elements. If a malformed proof is passed, this could cause runtime errors or unexpected behavior.

Consider adding a defensive check:

🔎 Proposed defensive validation
 export const encodeSolidityProof = (proof: ProofData): Hex => {
+  if (proof.publicInputs.length < 4) {
+    throw new Error(`Invalid proof: expected at least 4 public inputs, got ${proof.publicInputs.length}`)
+  }
+
   const vote = proof.publicInputs.slice(3) as `0x${string}`[]
   const slotAddress = getAddress(numberToHex(BigInt(proof.publicInputs[1]), { size: 20 }))

   return encodeAbiParameters(parseAbiParameters('bytes, bytes32[], address'), [bytesToHex(proof.proof), vote, slotAddress])
 }
crates/events/src/enclave_event/publickey_aggregated.rs (1)

17-19: Consider adding hex formatting for public_key_hash in Debug output.

The pubkey field uses a custom hex formatter (e3_utils::formatters::hexf), but public_key_hash will display as an array of decimal numbers in debug output. For consistency and readability, consider applying the same formatter.

🔎 Proposed fix
     #[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
     pub pubkey: Vec<u8>,
+    #[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
     pub public_key_hash: [u8; 32],
packages/enclave-contracts/tasks/enclave.ts (1)

290-292: Strengthen publicKeyHash validation.

The validation only checks if publicKeyHash is truthy but doesn't verify it's a valid bytes32 format. Consider adding format validation to catch user errors early before the contract call.

🔎 Suggested validation enhancement
 if (!publicKeyHash) {
   throw new Error("publicKeyHash is required");
 }
+
+if (!/^0x[a-fA-F0-9]{64}$/.test(publicKeyHash)) {
+  throw new Error("publicKeyHash must be a valid bytes32 hex string (0x + 64 hex characters)");
+}

Additionally, consider adding documentation or a console message showing how to compute the hash (e.g., using ethers.id(publicKey)) since the task requires it as input rather than computing it automatically.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad8c74b and 95653a5.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • examples/CRISP/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/bfv-helpers/src/client.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/tests/Cargo.toml
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/circuits/src/main.nr
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
  • examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-sdk/src/vote.ts
  • examples/CRISP/server/src/cli/approve.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/indexer.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • packages/enclave-contracts/tasks/enclave.ts
  • packages/enclave-contracts/test/Enclave.spec.ts
  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
  • packages/enclave-sdk/src/contract-client.ts
  • packages/enclave-sdk/src/enclave-sdk.ts
🧰 Additional context used
🧠 Learnings (25)
📚 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:

  • crates/aggregator/Cargo.toml
  • crates/tests/Cargo.toml
📚 Learning: 2024-10-22T02:36:01.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/Cargo.toml:0-0
Timestamp: 2024-10-22T02:36:01.448Z
Learning: In `packages/ciphernode/data/Cargo.toml`, `actix-rt` is only used in tests and should remain in `[dev-dependencies]`.

Applied to files:

  • crates/tests/Cargo.toml
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/tests/tests/integration_legacy.rs
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2024-10-29T01:04:19.137Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/keyshare/src/keyshare.rs:53-70
Timestamp: 2024-10-29T01:04:19.137Z
Learning: In the `Keyshare` struct within `packages/ciphernode/keyshare/src/keyshare.rs`, the `self.secret` field is stored in encrypted form and is not considered sensitive.

Applied to files:

  • crates/events/src/enclave_event/publickey_aggregated.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/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
📚 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-contracts/contracts/CRISPProgram.sol
📚 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:

  • crates/tests/tests/integration_legacy.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • crates/bfv-helpers/src/client.rs
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
📚 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:

  • crates/tests/tests/integration_legacy.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/aggregator/src/publickey_aggregator.rs
  • examples/CRISP/server/src/cli/approve.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/indexer.rs
  • crates/evm/src/ciphernode_registry_sol.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:

  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/server/src/cli/commands.rs
  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2024-10-16T09:52:53.807Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/src/data_store.rs:74-75
Timestamp: 2024-10-16T09:52:53.807Z
Learning: In this project, the actor model handles potential errors internally, so methods like `checkpoint` in the `Checkpoint` trait do not need to explicitly handle or propagate errors.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 133
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:137-139
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, using the same RNG instance `rng_test` for generating multiple key shares without advancing its state is acceptable.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
  • crates/bfv-helpers/src/utils/greco.rs
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • crates/evm-helpers/src/contracts.rs
📚 Learning: 2025-09-19T11:16:53.825Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 752
File: packages/enclave-contracts/contracts/Enclave.sol:15-17
Timestamp: 2025-09-19T11:16:53.825Z
Learning: The Enclave contract in the gnosisguild/enclave repository has not been deployed yet as of September 2025, so storage layout considerations for upgradeable contracts don't apply to current changes.

Applied to files:

  • crates/evm-helpers/src/contracts.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:

  • crates/bfv-helpers/src/utils/greco.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/server/src/cli/commands.rs
📚 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:

  • crates/bfv-helpers/src/client.rs
📚 Learning: 2025-09-11T13:21:31.031Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/tasks/utils.ts:7-8
Timestamp: 2025-09-11T13:21:31.031Z
Learning: In Hardhat v3, the task API syntax has changed significantly from v2. The new syntax uses:
- `.addOption({ name, description, defaultValue, type })` instead of `.addOptionalParam()`
- `.setAction(async () => ({ default: (args, hre) => { ... } }))` instead of direct `.setAction((args, hre) => { ... })`
- `.build()` is required to finalize task definitions
- `ArgumentType.STRING` is used for option types instead of `types.string`

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
📚 Learning: 2025-09-11T13:09:03.800Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/scripts/deployAndSave/naiveRegistryFilter.ts:30-31
Timestamp: 2025-09-11T13:09:03.800Z
Learning: In Hardhat v3 deployment scripts, use `(await signer.provider?.getNetwork())?.name ?? "localhost"` instead of `hre.globalOptions.network` to reliably get the network name, as `hre.globalOptions.network` can be undefined in some contexts.

Applied to files:

  • packages/enclave-contracts/tasks/enclave.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:

  • packages/enclave-sdk/src/enclave-sdk.ts
📚 Learning: 2024-11-05T06:56:49.157Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/enclave_node/src/aggregator.rs:0-0
Timestamp: 2024-11-05T06:56:49.157Z
Learning: `RegistryFilterSol` does not have a reader and does not require a repository reader or deploy block when calling `RegistryFilterSol::attach` in `packages/ciphernode/enclave_node/src/aggregator.rs`.

Applied to files:

  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2024-10-16T09:51:10.038Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/committee_meta.rs:43-43
Timestamp: 2024-10-16T09:51:10.038Z
Learning: In `packages/ciphernode/router/src/committee_meta.rs`, avoid suggesting making the `on_event` method in `CommitteMetaFeature` asynchronous or adding error handling for the `write` operation to the data store.

Applied to files:

  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2024-10-08T07:15:06.690Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/evm/src/ciphernode_registry_sol.rs:133-143
Timestamp: 2024-10-08T07:15:06.690Z
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:

  • crates/evm/src/ciphernode_registry_sol.rs
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed to support multiple network connections: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3. Similarly, `.revertedWithoutReason(ethers)` replaces `.revertedWithoutReason`.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 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:

  • packages/enclave-contracts/test/Enclave.spec.ts
🧬 Code graph analysis (7)
examples/CRISP/packages/crisp-sdk/src/vote.ts (1)
examples/CRISP/client/libs/crispSDKWorker.js (2)
  • proof (25-25)
  • slotAddress (14-14)
crates/tests/tests/integration_legacy.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (1)
examples/CRISP/packages/crisp-contracts/tests/utils.ts (2)
  • deployMockEnclave (43-47)
  • deployCRISPProgram (69-87)
crates/aggregator/src/publickey_aggregator.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
examples/CRISP/server/src/cli/commands.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/bfv-helpers/src/client.rs (2)
crates/bfv-helpers/src/utils/greco.rs (1)
  • bfv_public_key_to_greco (233-283)
crates/bfv-helpers/src/lib.rs (1)
  • build_bfv_params_arc (278-300)
examples/CRISP/server/src/server/indexer.rs (2)
examples/CRISP/crates/crisp-constants/src/lib.rs (1)
  • get_default_paramset (10-13)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
⏰ 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). (5)
  • GitHub Check: integration_prebuild
  • GitHub Check: build_enclave_cli
  • GitHub Check: rust_integration
  • GitHub Check: build_ciphernode_image
  • GitHub Check: rust_unit
🔇 Additional comments (44)
examples/CRISP/server/src/cli/approve.rs (1)

28-28: Good cleanup: unused import removed.

The removal of the unused Provider import is appropriate since only ProviderBuilder is actually used in this function. This improves code clarity.

examples/CRISP/packages/crisp-sdk/src/vote.ts (1)

282-287: The code is correct. The public inputs are structured as: index 0 = pk_commitment, index 1 = slot_address, index 2 = is_first_vote, and index 3+ = vote data. Index 2 is intentionally skipped because is_first_vote is a circuit-internal boolean flag used to determine behavior but not needed for Solidity encoding. The indexing accurately reflects the circuit's public input order defined in circuits/src/main.nr.

Likely an incorrect or invalid review comment.

examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol (3)

17-17: LGTM: Verification key public inputs size updated consistently.

The publicInputsSize field correctly reflects the new count of 2067 public inputs, maintaining consistency with the constant defined at line 10.


18-128: Verification key regenerated for updated circuit.

All verification key G1 points have been updated following the circuit modification to include the public key commitment. The selective update pattern (changed selector and permutation points, unchanged table commitments at t1-t4 and lagrangeFirst) is consistent with adding a public input without modifying the lookup table structure.


10-11: Public input count incremented to accommodate public key commitment.

The increase from 2066 to 2067 public inputs and the updated VK hash are consistent with the PR objective of passing a public key commitment for proof verification. Integration tests in crisp.contracts.test.ts validate proof generation and verification with generateVoteProof(), which correctly includes the public key in the proof inputs passed to honkVerifier.verify().

examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol (3)

14-14: LGTM! Clean state variable addition.

The new public state variable properly stores the committee public key hash for the mock.


20-22: LGTM! Appropriate mock setter.

The setter function is simple and appropriate for a test mock. The lack of access control is acceptable since this is only used in tests.


38-38: LGTM! Correct integration of the state variable.

The change correctly returns the committeePublicKey state variable instead of a hardcoded zero value, aligning with the PR's objective to support public key commitment verification.

examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (3)

74-75: LGTM! Consistent mock setup.

The test now properly deploys and injects the mock enclave, consistent with the refactored architecture.


26-27: > Likely an incorrect or invalid review comment.


97-98: The test correctly uses proof.publicInputs[0] to set the committee public key. The first public input of the CRISP circuit is pk_commitment, the committee public key commitment, so the assumption is valid.

examples/CRISP/circuits/src/main.nr (1)

56-56: LGTM! Making pk_commitment a public input enables external verification.

This change correctly exposes the public key commitment as a public circuit input, allowing the verifier to supply and validate the commitment against on-chain data during proof verification.

crates/tests/Cargo.toml (1)

34-34: LGTM!

The e3-bfv-helpers dependency is correctly added as a workspace dependency to support compute_pk_commitment usage in tests.

examples/CRISP/server/src/server/token_holders/etherscan.rs (1)

621-621: LGTM!

The CONFIG import is correctly added to support the existing integration tests that reference configuration values like etherscan_api_key, chain_id, and http_rpc_url.

crates/aggregator/Cargo.toml (1)

21-21: LGTM!

The e3-bfv-helpers dependency is correctly added to support the compute_pk_commitment function used in the public key aggregation workflow.

packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts (2)

31-31: Verify the hash computation method change.

The hash computation changed from ethers.keccak256(data) to ethers.id(data). These produce different results:

  • ethers.keccak256("0xda7a") hashes the 2 raw bytes [0xda, 0x7a]
  • ethers.id("0xda7a") hashes the 6-character UTF-8 string "0xda7a"

Ensure this change aligns with how the contract and other components compute the public key hash.


346-348: LGTM! Test correctly updated for new publishCommittee signature.

The dataHash parameter is correctly passed to publishCommittee, and assertions are updated to verify that committeePublicKey returns the hash rather than the raw data.

Also applies to: 364-369

packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json (2)

350-355: LGTM! Interface correctly updated with publicKeyHash parameter.

The activate function signature now includes the bytes32 publicKeyHash parameter, aligning with the PR objective to pass public key commitment for verification.


425-437: Note: New feeToken() getter added.

This new view function appears unrelated to the public key commitment refactor. Ensure this addition is intentional for this PR.

crates/aggregator/src/publickey_aggregator.rs (3)

9-9: LGTM!

The compute_pk_commitment import is correctly added from the e3_bfv_helpers crate.


185-190: LGTM! Public key commitment computation is correctly integrated.

The commitment is computed with the appropriate BFV parameters (degree, plaintext modulus, moduli) immediately after aggregating the public key, ensuring the hash is available before broadcasting the event.


203-208: LGTM! Event correctly includes the new public_key_hash field.

The PublicKeyAggregated event is properly constructed with the computed commitment hash.

packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol (1)

158-164: Interface extension looks correct.

The publishCommittee function signature is properly extended to include the publicKeyHash parameter of type bytes32. The NatSpec documentation is also updated to describe the new parameter. This aligns with the PR objective to pass the public key commitment for proof verification.

packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json (1)

375-380: ABI artifact correctly updated.

The artifact correctly reflects the new publicKeyHash parameter of type bytes32 in the publishCommittee function. The buildInfoId update is expected as it's auto-generated during compilation.

Also applies to: 543-543

packages/enclave-sdk/src/enclave-sdk.ts (1)

329-335: SDK method signature correctly extended.

The activateE3 method properly accepts the new publicKeyHash parameter and forwards it to contractClient.activateE3. The type 0x${string} is appropriate for a bytes32 hex value in viem.

packages/enclave-contracts/contracts/interfaces/IEnclave.sol (1)

155-161: Interface extension is correct.

The activate function signature is properly extended to include the publicKeyHash parameter of type bytes32. The NatSpec documentation accurately describes the parameter as "Hash of the committee's public key."

packages/enclave-sdk/src/contract-client.ts (1)

164-186: Contract client correctly updated.

The activateE3 method signature and contract call arguments are properly extended to include publicKeyHash. The parameter order [e3Id, publicKey, publicKeyHash] correctly matches the Solidity function signature activate(uint256 e3Id, bytes calldata publicKey, bytes32 publicKeyHash).

packages/enclave-contracts/contracts/Enclave.sol (2)

310-316: Validation logic correctly validates externally provided hash.

The refactored validation:

  1. Retrieves the expected hash from ciphernodeRegistry.committeePublicKey(e3Id)
  2. Compares it against the caller-provided publicKeyHash
  3. Reverts with CommitteeSelectionFailed() if they don't match

This design correctly ensures that the activation caller provides a hash that matches what was registered during publishCommittee, maintaining the integrity of the public key commitment workflow.


298-324: No type mismatch. The committeePublicKey field is bytes32, not bytes.

The E3 struct definition (in packages/enclave-contracts/contracts/interfaces/IE3.sol) declares bytes32 committeePublicKey, making the assignment on line 319 type-safe. The hex"" initialization on line 257 is a bytes literal that implicitly converts to bytes32 (zero-padded). The concern about assigning bytes32 to a bytes field does not apply here.

examples/CRISP/server/src/server/indexer.rs (1)

363-380: PK commitment flow in indexer is correctly implemented.

The handle_committee_time_expired function properly computes the public key commitment using the default parameter set and passes it to the activate call. The implementation correctly:

  1. Retrieves the default BFV parameter set with all required fields
  2. Computes the commitment from the event's public key with properly typed parameters
  3. Wraps the result in FixedBytes for the contract call
examples/CRISP/server/src/cli/commands.rs (1)

211-222: PK commitment computation and activation flow is correct.

The implementation correctly:

  1. Uses BfvParameters methods with proper types: degree() returns usize, plaintext() returns u64, and moduli() returns a slice that's converted to Vec<u64>
  2. Passes these to compute_pk_commitment which expects exactly these types
  3. Handles errors appropriately with map_err

Note: compute_pk_commitment internally calls build_bfv_params_arc() which may panic on invalid parameters. This is a known limitation planned for refactoring to proper Result-based error handling.

crates/bfv-helpers/src/utils/greco.rs (2)

185-220: Well-structured BFV to Greco coefficient conversion helpers.

The conversion logic correctly handles:

  1. Centering coefficients around zero (line 192: if coeff > (qi / 2))
  2. Reversing coefficient order (line 207: .rev())
  3. Reducing modulo ZKP modulus with proper handling of negative values (lines 213-217)

233-283: LGTM - Correct implementation with good test coverage.

The function properly:

  1. Clones polynomials before mutating representation (lines 247-250)
  2. Extracts coefficients per modulus in the correct order
  3. Applies the Greco conversion format

The test at lines 385-472 validates correctness against the reference GrecoVectors implementation, ensuring coefficient-by-coefficient equality.

crates/tests/tests/integration_legacy.rs (2)

223-235: LGTM - Test correctly computes and verifies public key commitment.

The test properly:

  1. Computes the commitment using the same compute_pk_commitment function used in production
  2. Passes the required BFV parameters (degree, plaintext modulus, moduli)
  3. Includes the public_key_hash in the expected event for assertion

572-591: Consistent commitment computation across test scenarios.

The duplicate e3_id test correctly computes separate commitments for each chain's public key aggregation, ensuring the hash validation works across different E3 instances.

crates/bfv-helpers/src/client.rs (1)

133-158: Robust implementation with proper error handling.

The function correctly:

  1. Builds BFV parameters and deserializes the public key (lines 141-144)
  2. Computes Greco bounds and bit width (lines 146-147)
  3. Converts to Greco format and computes commitment (lines 149-150)
  4. Handles the BigInt to 32-byte conversion with proper error propagation (lines 152-155)

One consideration: to_bytes_be().1 returns the magnitude bytes without sign. Since the commitment is expected to be positive and exactly 32 bytes, this should work correctly, but the error at line 155 will catch any size mismatch.

crates/evm/src/ciphernode_registry_sol.rs (1)

406-432: LGTM - Clean propagation of public key hash to registry.

The handler correctly:

  1. Extracts public_key_hash from the PublicKeyAggregated message (line 409)
  2. Passes it through to the async contract call (lines 416-424)
  3. The function signature update at line 493 accepts [u8; 32] and converts to FixedBytes at line 498
crates/evm-helpers/src/contracts.rs (2)

78-78: Contract ABI updated correctly.

The activate function signature in the sol! macro now includes the publicKeyHash parameter:

function activate(uint256 e3Id, bytes calldata publicKey, bytes32 publicKeyHash)

This matches the updated Solidity contract interface.


141-146: Trait and implementation are consistent.

The EnclaveWrite::activate method signature correctly includes pub_key_hash: FixedBytes<32>, and the implementation at lines 408-425 properly passes this parameter to the contract call at line 421.

Also applies to: 408-425

packages/enclave-contracts/test/Enclave.spec.ts (2)

58-58: Verify hash function consistency between ethers.id and ethers.keccak256.

dataHash is computed using ethers.id(data) which is keccak256(toUtf8Bytes(data)), but at line 1601, the assertion uses ethers.keccak256(data) which hashes the raw bytes.

For data = "0xda7a":

  • ethers.id(data) = keccak256 of UTF-8 string "0xda7a"
  • ethers.keccak256(data) = keccak256 of bytes [0xda, 0x7a]

If this is intentional (ciphertextOutput stores a different hash than the activation hash), please confirm. Otherwise, consider using consistent hashing:

-  const dataHash = ethers.id(data);
+  const dataHash = ethers.keccak256(data);

64-78: Helper function correctly updated for new signature.

The setupAndPublishCommittee helper properly:

  1. Computes publicKeyHash using ethers.id(publicKey) (line 76)
  2. Passes it as the fourth parameter to publishCommittee (line 77)
packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol (1)

41-46: Mock contracts correctly updated to match interface.

Both MockCiphernodeRegistry and MockCiphernodeRegistryEmptyKey have their publishCommittee signatures updated to include the new bytes32 parameter, maintaining compatibility with the ICiphernodeRegistry interface.

Also applies to: 118-123

packages/enclave-contracts/tasks/enclave.ts (2)

258-263: Good addition of publicKeyHash parameter.

The new option is properly structured and documented. The description correctly identifies it as a bytes32 hash.


333-347: Consider documenting why hash handling differs between tasks.

The inconsistency is real: activateE3 computes publicKeyHash inline using ethers.id(publicKey) (line 346), while publishCommittee requires it as an input parameter. However, test evidence confirms that ethers.id() is the correct and expected method for computing the hash from publicKey—the test suite consistently uses this approach for both tasks. This appears to be intentional API design (convenience in activateE3 vs. explicit input in publishCommittee), but consider adding a comment explaining why the two tasks differ to help future maintainers understand the distinction.

Comment thread examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
Comment thread examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol Outdated
ctrlc03
ctrlc03 previously approved these changes Dec 24, 2025

@ctrlc03 ctrlc03 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol (1)

242-261: Contract trusts owner to provide correct publicKeyHash without validation.

The function accepts publicKeyHash as an external parameter without verifying it matches the provided publicKey or committee. While off-chain computation is supported (owner computes and provides the hash), there is no cryptographic proof that the hash actually corresponds to the public key or committee members.

The risk is partially mitigated by downstream validation in Enclave.sol (line 314), which checks publicKeyHash == registryPublicKeyHash, but this only validates consistency with stored values—not correctness of the original hash.

The TODO comments (lines 256-257) correctly identify the need for a proof mechanism to eliminate this trust assumption.

♻️ Duplicate comments (1)
examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (1)

140-141: Validate that committeePublicKey is set.

The E3 fetch is correct, but there's no validation that committeePublicKey has been initialized. If validateInput is called before the committee has been activated, committeePublicKey will be bytes32(0), causing an InvalidNoirProof error rather than a clear indication of the actual problem.

Add validation immediately after fetching E3:

 // Fetch E3 to get committee public key
 E3 memory e3 = enclave.getE3(e3Id);
+if (e3.committeePublicKey == bytes32(0)) revert CommitteePublicKeyNotSet();

Add the custom error at the contract level:

error CommitteePublicKeyNotSet();

The Noir circuit expects committeePublicKey (named pk_commitment in the circuit) as the first public input, which matches the implementation.

🧹 Nitpick comments (1)
crates/events/src/enclave_event/publickey_aggregated.rs (1)

16-22: LGTM - New field correctly added to the event struct.

The public_key_hash field is appropriately typed as [u8; 32] to hold the commitment hash. Consider adding the same hex formatter for public_key_hash as used for pubkey for consistent debug output, though this is optional.

Optional: Add hex formatting for public_key_hash
 pub struct PublicKeyAggregated {
     #[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
     pub pubkey: Vec<u8>,
+    #[derivative(Debug(format_with = "e3_utils::formatters::hexf"))]
     pub public_key_hash: [u8; 32],
     pub e3_id: E3id,
     pub nodes: OrderedSet<String>,
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95653a5 and b35f682.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • examples/CRISP/Cargo.lock is excluded by !**/*.lock
  • templates/default/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/bfv-helpers/src/client.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/tests/Cargo.toml
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/circuits/src/main.nr
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
  • examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-sdk/src/vote.ts
  • examples/CRISP/server/src/cli/approve.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/indexer.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • packages/enclave-contracts/tasks/enclave.ts
  • packages/enclave-contracts/test/Enclave.spec.ts
  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
  • packages/enclave-sdk/src/contract-client.ts
  • packages/enclave-sdk/src/enclave-sdk.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • crates/aggregator/Cargo.toml
  • packages/enclave-sdk/src/enclave-sdk.ts
  • crates/evm/src/ciphernode_registry_sol.rs
  • examples/CRISP/packages/crisp-sdk/src/vote.ts
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-sdk/src/contract-client.ts
  • examples/CRISP/server/src/cli/approve.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
🧰 Additional context used
🧠 Learnings (24)
📚 Learning: 2025-12-23T17:18:22.421Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 1142
File: examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol:141-147
Timestamp: 2025-12-23T17:18:22.421Z
Learning: For Solidity contracts that verify Noir circuit proofs, the verifier's public inputs array must include both the circuit's public inputs and the public outputs. Ensure the verification input array length equals pub_inputs + pub_outputs. Example: a Noir circuit with 3 public inputs and 2064 public outputs should pass an array of length 2067 (3 + 2064). Apply this consistently across all contract verifier implementations and adjust tests accordingly.

Applied to files:

  • examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol
📚 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/cli/commands.rs
  • crates/aggregator/src/publickey_aggregator.rs
  • examples/CRISP/server/src/server/indexer.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • examples/CRISP/server/src/cli/commands.rs
  • crates/evm-helpers/src/contracts.rs
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 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/cli/commands.rs
  • crates/tests/tests/integration_legacy.rs
📚 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:

  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/tests/tests/integration_legacy.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • crates/bfv-helpers/src/client.rs
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: tests/basic_integration/test.sh:103-114
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `tests/basic_integration/test.sh`, the user prefers not to refactor the ciphernode addition section to reduce duplication.

Applied to files:

  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/aggregator/src/publickey_aggregator.rs
  • crates/tests/tests/integration_legacy.rs
  • crates/events/src/enclave_event/publickey_aggregated.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:

  • crates/bfv-helpers/src/utils/greco.rs
📚 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:

  • crates/bfv-helpers/src/utils/greco.rs
  • crates/bfv-helpers/src/client.rs
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 133
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:137-139
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, using the same RNG instance `rng_test` for generating multiple key shares without advancing its state is acceptable.

Applied to files:

  • crates/bfv-helpers/src/utils/greco.rs
  • crates/tests/tests/integration_legacy.rs
📚 Learning: 2024-10-16T09:52:53.807Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/src/data_store.rs:74-75
Timestamp: 2024-10-16T09:52:53.807Z
Learning: In this project, the actor model handles potential errors internally, so methods like `checkpoint` in the `Checkpoint` trait do not need to explicitly handle or propagate errors.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
📚 Learning: 2024-10-12T10:24:07.572Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/core/src/events.rs:349-349
Timestamp: 2024-10-12T10:24:07.572Z
Learning: When reviewing `PlaintextAggregated` struct instantiations in the project, note that the `src_chain_id` field may not always need to be included. Avoid flagging its absence unless it is required in the specific context.

Applied to files:

  • crates/events/src/enclave_event/publickey_aggregated.rs
📚 Learning: 2024-10-29T01:04:19.137Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/keyshare/src/keyshare.rs:53-70
Timestamp: 2024-10-29T01:04:19.137Z
Learning: In the `Keyshare` struct within `packages/ciphernode/keyshare/src/keyshare.rs`, the `self.secret` field is stored in encrypted form and is not considered sensitive.

Applied to files:

  • crates/events/src/enclave_event/publickey_aggregated.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:

  • crates/tests/Cargo.toml
📚 Learning: 2024-10-22T02:36:01.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/Cargo.toml:0-0
Timestamp: 2024-10-22T02:36:01.448Z
Learning: In `packages/ciphernode/data/Cargo.toml`, `actix-rt` is only used in tests and should remain in `[dev-dependencies]`.

Applied to files:

  • crates/tests/Cargo.toml
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed to support multiple network connections: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3. Similarly, `.revertedWithoutReason(ethers)` replaces `.revertedWithoutReason`.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 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:

  • packages/enclave-contracts/test/Enclave.spec.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/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
📚 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-contracts/contracts/CRISPProgram.sol
📚 Learning: 2025-08-27T13:53:47.832Z
Learnt from: 0xjei
Repo: gnosisguild/enclave PR: 648
File: packages/circuits/crates/libs/polynomial/src/lib.nr:121-133
Timestamp: 2025-08-27T13:53:47.832Z
Learning: In Noir circuits, prefer relying on built-in array bounds checking rather than adding explicit preconditions for buffer overflow protection, as the language already provides safety guarantees that will fail the circuit on out-of-bounds access.

Applied to files:

  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 Learning: 2024-10-08T01:50:45.185Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/core/src/events.rs:323-323
Timestamp: 2024-10-08T01:50:45.185Z
Learning: When suggesting that instances of `E3Requested` should include `src_chain_id`, double-check to ensure that the field is actually missing before making the suggestion.

Applied to files:

  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 Learning: 2025-09-11T13:21:31.031Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/tasks/utils.ts:7-8
Timestamp: 2025-09-11T13:21:31.031Z
Learning: In Hardhat v3, the task API syntax has changed significantly from v2. The new syntax uses:
- `.addOption({ name, description, defaultValue, type })` instead of `.addOptionalParam()`
- `.setAction(async () => ({ default: (args, hre) => { ... } }))` instead of direct `.setAction((args, hre) => { ... })`
- `.build()` is required to finalize task definitions
- `ArgumentType.STRING` is used for option types instead of `types.string`

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
📚 Learning: 2025-09-11T13:09:03.800Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/scripts/deployAndSave/naiveRegistryFilter.ts:30-31
Timestamp: 2025-09-11T13:09:03.800Z
Learning: In Hardhat v3 deployment scripts, use `(await signer.provider?.getNetwork())?.name ?? "localhost"` instead of `hre.globalOptions.network` to reliably get the network name, as `hre.globalOptions.network` can be undefined in some contexts.

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
🧬 Code graph analysis (5)
examples/CRISP/server/src/cli/commands.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/aggregator/src/publickey_aggregator.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
examples/CRISP/server/src/server/indexer.rs (2)
examples/CRISP/crates/crisp-constants/src/lib.rs (1)
  • get_default_paramset (10-13)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/tests/tests/integration_legacy.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-158)
crates/bfv-helpers/src/client.rs (2)
crates/bfv-helpers/src/utils/greco.rs (1)
  • bfv_public_key_to_greco (233-283)
crates/bfv-helpers/src/lib.rs (1)
  • build_bfv_params_arc (278-300)
⏰ 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). (10)
  • GitHub Check: build_e3_support_dev
  • GitHub Check: integration_prebuild
  • GitHub Check: build_crisp_sdk
  • GitHub Check: build_enclave_cli
  • GitHub Check: build_sdk
  • GitHub Check: test_net
  • GitHub Check: rust_unit
  • GitHub Check: build_ciphernode_image
  • GitHub Check: rust_integration
  • GitHub Check: Build & Push Image
🔇 Additional comments (31)
examples/CRISP/server/src/server/token_holders/etherscan.rs (1)

621-621: LGTM! Import enables test access to CONFIG.

The explicit import of CONFIG in the tests module enables the integration tests to access configuration values. While use super::*; on line 620 already imports CONFIG from the parent module scope (line 16), the explicit import here adds clarity for test readers.

examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (2)

138-138: LGTM! Array size correctly updated.

The array size increase from 3 + vote.length to 4 + vote.length correctly accounts for the additional committeePublicKey public input.


143-148: Remove vote.length from public inputs array; include all 2048 output fields from the circuit return value.

The circuit returns ([Polynomial<512>; 2], [Polynomial<512>; 2]), which represents 2048 Field values. According to the Noir proof verification pattern, the public inputs array passed to the verifier must include both the 4 circuit public inputs (pk_commitment, merkle_root, slot_address, is_first_vote) AND all 2048 output fields from the circuit return value, for a total of 2052 values.

The current implementation uses 4 + vote.length instead. The vote array is part of the Solidity data structure but is not the circuit's output—including it in the public inputs will cause verification to fail if the verifier expects the actual polynomial coefficients.

Populate noirPublicInputs with the 2048 output fields from the proof instead of appending the vote array.

⛔ Skipped due to learnings
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 1142
File: examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol:141-147
Timestamp: 2025-12-23T17:18:22.421Z
Learning: When verifying Noir circuit proofs in Solidity, the public inputs array passed to the verifier must include both the circuit's public inputs AND public outputs. For example, if a Noir circuit has 3 public inputs and returns 2064 public output fields (-> pub [Field; 2064]), the verification array must contain all 2067 values (3 + 2064).
examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol (2)

14-22: LGTM - Mock contract properly extended.

The addition of committeePublicKey state variable and setter aligns with the PR's objective to pass public key commitments through the system. The mock implementation is appropriately simple for testing purposes.


38-38: LGTM - Proper integration with E3 struct.

The committeePublicKey is correctly used in the E3 struct construction, replacing the previous constant zero value with the configurable state variable.

crates/evm-helpers/src/contracts.rs (3)

10-10: LGTM - Proper type import and ABI extension.

The addition of FixedBytes to imports and the extension of the activate function signature with bytes32 publicKeyHash correctly align with the Solidity contract changes across the codebase.

Also applies to: 78-78


141-146: LGTM - Trait signature properly extended.

The activate method signature is correctly updated to include pub_key_hash: FixedBytes<32>, maintaining consistency with the contract ABI and enabling proper public key commitment propagation.


408-425: LGTM - Implementation correctly propagates public key hash.

The activate implementation properly accepts and passes the pub_key_hash parameter to the contract call, maintaining consistency with the trait signature and ABI definition.

packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol (1)

41-46: LGTM - Mock contracts consistently updated.

Both MockCiphernodeRegistry and MockCiphernodeRegistryEmptyKey variants are correctly updated with the new bytes32 parameter in publishCommittee, maintaining consistency with the ICiphernodeRegistry interface changes.

Also applies to: 118-123

crates/tests/Cargo.toml (1)

34-34: LGTM - Dependency addition enables PK commitment computation.

The addition of e3-bfv-helpers as a workspace dependency is appropriate for tests that need to compute public key commitments using compute_pk_commitment.

packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts (2)

346-346: LGTM - Consistent test updates.

All publishCommittee call sites are consistently updated to include dataHash as the final parameter, properly exercising the extended interface signature.

Also applies to: 365-365, 386-386, 513-513


31-31: The review comment is based on a false premise. The file CiphernodeRegistryOwnable.spec.ts has always used ethers.id(data) on line 31 since its initial introduction. There was no change from ethers.keccak256(data) to ethers.id(data).

The git history confirms the file was first introduced with this exact code, and no commits have modified this line. Other test files in the codebase (e.g., Enclave.spec.ts) consistently use ethers.id() for computing hashes of public key data.

Additionally, the contract's publishCommittee function does not validate the publicKeyHash parameter—it simply stores it (see TODO comment: "Currently we trust the owner to publish the correct committee"). The test uses mock data with ethers.id() for testing purposes, which is appropriate in this context.

Likely an incorrect or invalid review comment.

crates/aggregator/src/publickey_aggregator.rs (3)

9-9: LGTM - Proper import for PK commitment computation.

The import of compute_pk_commitment from e3_bfv_helpers::client enables the aggregator to compute the public key hash for inclusion in the aggregated event.


185-190: LGTM - Proper public key commitment computation.

The compute_pk_commitment invocation correctly passes the aggregated public key and FHE parameters to compute the 32-byte commitment hash. The computation placement (after aggregation, before state update and event emission) is appropriate.


203-209: LGTM - Event properly includes public key hash.

The PublicKeyAggregated event is correctly constructed with the computed public_key_hash, enabling downstream components to use the commitment for verification.

packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol (1)

158-164: LGTM - Interface properly extended with documentation.

The publishCommittee function signature is correctly extended with the publicKeyHash parameter, and the documentation is appropriately updated. This change is consistent with the broader refactoring to propagate public key commitments through the system.

examples/CRISP/circuits/src/main.nr (1)

56-56: The verifier contract correctly handles the new public input for pk_commitment.

The change from pk_commitment: Field to pk_commitment: pub Field properly exposes the public key commitment as a public input. The verifier implementation already passes the complete public inputs array to verification, which includes both the explicit public inputs (pk_commitment, merkle_root, slot_address, is_first_vote) and the circuit's public outputs (the ciphertext components). No additional changes are required.

examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol (1)

10-17: Verification key updated correctly for the new public input.

The NUMBER_OF_PUBLIC_INPUTS increase from 2067 to 2068 aligns with adding the publicKeyHash parameter to the circuit. The VK_HASH and all G1 point coordinates have been regenerated accordingly.

Based on learnings, the verifier's public inputs array length should equal pub_inputs + pub_outputs. Please confirm that the circuit now has 4 public inputs (previously 3) with 2064 public outputs, totaling 2068.

examples/CRISP/server/src/cli/commands.rs (1)

211-222: LGTM - PK commitment computation and activation correctly integrated.

The public key commitment is properly computed using the BFV parameters from the generated key, and the activation call correctly passes the new publicKeyHash parameter as FixedBytes. Error handling appropriately maps the Result to a displayable error string.

examples/CRISP/server/src/server/indexer.rs (1)

363-380: LGTM - Indexer correctly computes PK commitment for activation.

The implementation properly:

  1. Retrieves default BFV parameters via get_default_paramset()
  2. Computes the commitment using compute_pk_commitment with the public key from the event
  3. Passes the commitment as FixedBytes::from(public_key_hash) to the updated activate call

The error handling correctly wraps the commitment computation failure in an eyre error.

crates/bfv-helpers/src/utils/greco.rs (2)

185-220: LGTM - BFV to Greco coefficient conversion implemented correctly.

The centering logic properly:

  • Converts BFV coefficients from [0, qi) to centered form [-(qi-1)/2, (qi-1)/2]
  • Handles negative modulo reduction correctly by adding zkp_modulus when result is negative

The convert_bfv_coefficients_to_greco correctly applies the reverse operation to match Greco's expected coefficient ordering.


233-283: LGTM - Public key to Greco conversion correctly extracts and transforms coefficients.

The implementation properly:

  1. Accesses the internal polynomial structure via pk.c.c[0] and pk.c.c[1]
  2. Clones before calling change_representation (required since it mutates in-place)
  3. Extracts coefficients per-modulus and per-degree index
  4. Applies the Greco conversion for each modulus

The test at lines 385-472 provides good coverage by comparing against GrecoVectors::standard_form() output, ensuring the implementation matches the reference.

crates/tests/tests/integration_legacy.rs (2)

223-235: LGTM - Test correctly verifies PublicKeyAggregated with new field.

The test properly computes the expected public_key_hash using compute_pk_commitment and includes it in the expected PublicKeyAggregated event structure for assertion. This ensures the aggregation pipeline correctly produces the commitment hash.


572-634: LGTM - Cross-chain test correctly updated for public_key_hash.

The test for duplicate E3 IDs with different chain IDs properly:

  1. Computes separate public_key_hash values for each chain's public key
  2. Verifies both PublicKeyAggregated events include the correct hash

This ensures the commitment computation works correctly across different E3 instances.

packages/enclave-contracts/contracts/Enclave.sol (1)

298-324: Breaking API change - activate function now requires publicKeyHash parameter.

The refactored activate function correctly:

  1. Accepts bytes32 publicKeyHash as the third parameter
  2. Verifies it against the registry's stored commitment via ciphernodeRegistry.committeePublicKey(e3Id)
  3. Stores the hash instead of computing keccak256(publicKey) on-chain

This is more gas-efficient and enables off-chain commitment computation. The event correctly continues to emit the raw publicKey for clients. The E3 struct and IEnclave interface have been properly updated with the new function signature and bytes32 committeePublicKey field.

packages/enclave-contracts/test/Enclave.spec.ts (2)

942-946: LGTM: Activation signature updated correctly.

The test cases correctly pass the new dataHash parameter to activate(). The systematic updates across all test scenarios (E3NotReady, E3Expired, E3AlreadyActivated) maintain proper test coverage.

Also applies to: 978-983, 1003-1004


64-78: Helper function updated correctly.

The setupAndPublishCommittee helper properly computes publicKeyHash and passes it to publishCommittee. The implementation is consistent with the new API requirements.

packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol (1)

260-260: Good practice: Event emits original public key.

The event correctly emits the original publicKey bytes rather than the hash, maintaining transparency and enabling off-chain verification. The hash is stored in state for on-chain operations.

packages/enclave-contracts/tasks/enclave.ts (3)

258-263: Good validation added for required parameter.

The task properly validates that publicKeyHash is required and provides a clear error message. This prevents incomplete task execution and guides users to provide the necessary parameter.

Also applies to: 290-292


333-334: Hash computation uses ethers.id() - verify consistency.

The task computes publicKeyHash using ethers.id(publicKey), which is consistent with the test file (line 76 in Enclave.spec.ts). However, if the concern raised about ethers.id() vs ethers.keccak256() in the test file is valid, this task would inherit the same issue.

Ensure this hash function choice matches the contract's expectations for public key commitments.

Also applies to: 346-347


294-299: Contract call updated correctly.

The publishCommittee call now includes the publicKeyHash parameter, matching the updated contract signature. The implementation properly handles the new parameter flow.

Comment thread crates/bfv-helpers/src/client.rs
Comment thread packages/enclave-contracts/test/Enclave.spec.ts Outdated
Comment thread packages/enclave-contracts/test/Enclave.spec.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
crates/evm-helpers/src/contracts.rs (1)

10-10: Verify the necessity of the FixedBytes import.

The FixedBytes type is imported but doesn't appear to be used in the visible code. If it's not used elsewhere in this file, consider removing it to keep imports clean.

#!/bin/bash
# Search for FixedBytes usage in this file
rg -n '\bFixedBytes\b' crates/evm-helpers/src/contracts.rs
packages/enclave-contracts/contracts/Enclave.sol (1)

298-315: Consider validating the public key hash retrieved from the registry.

The activation function now retrieves publicKeyHash from ciphernodeRegistry.committeePublicKey(e3Id) and stores it directly without validation. If the registry returns bytes32(0) (e.g., if publishCommittee hasn't been called yet or failed), the activation would succeed with an invalid hash, potentially breaking downstream verification.

Consider adding validation:

bytes32 publicKeyHash = ciphernodeRegistry.committeePublicKey(e3Id);
require(publicKeyHash != bytes32(0), "Committee public key not published");
#!/bin/bash
# Verify if publishCommittee always sets a non-zero hash before activate can be called
ast-grep --pattern $'function publishCommittee($$$) {
  $$$
  committeePublicKey[$_] = $_;
  $$$
}'
examples/CRISP/server/src/cli/commands.rs (1)

15-15: Verify the necessity of new imports.

The imports for FixedBytes and compute_pk_commitment have been added, but neither appears to be used in the visible code of activate_e3_round. The function still generates and stores the public key for later decryption but no longer passes it to activate.

If these imports were added in anticipation of future use or are used elsewhere in the file, they're fine. Otherwise, consider removing unused imports.

#!/bin/bash
# Verify if these imports are used elsewhere in the file
rg -n '\bFixedBytes\b|\bcompute_pk_commitment\b' examples/CRISP/server/src/cli/commands.rs

Also applies to: 19-19

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a802da and 0f49e9e.

📒 Files selected for processing (17)
  • crates/evm-helpers/src/contracts.rs
  • crates/indexer/src/indexer.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/indexer.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/IE3.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • packages/enclave-contracts/tasks/enclave.ts
  • packages/enclave-contracts/test/Enclave.spec.ts
  • packages/enclave-sdk/src/contract-client.ts
  • packages/enclave-sdk/src/enclave-sdk.ts
  • templates/default/client/src/pages/steps/ActivateE3.tsx
  • templates/default/tests/integration.spec.ts
  • tests/integration/base.sh
  • tests/integration/persist.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/enclave-contracts/tasks/enclave.ts
  • packages/enclave-sdk/src/contract-client.ts
🧰 Additional context used
🧠 Learnings (14)
📚 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:

  • packages/enclave-sdk/src/enclave-sdk.ts
📚 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/cli/commands.rs
  • crates/evm-helpers/src/contracts.rs
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • examples/CRISP/server/src/cli/commands.rs
  • crates/evm-helpers/src/contracts.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/cli/commands.rs
📚 Learning: 2024-10-16T09:51:10.038Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/committee_meta.rs:43-43
Timestamp: 2024-10-16T09:51:10.038Z
Learning: In `packages/ciphernode/router/src/committee_meta.rs`, avoid suggesting making the `on_event` method in `CommitteMetaFeature` asynchronous or adding error handling for the `write` operation to the data store.

Applied to files:

  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
📚 Learning: 2025-12-23T17:18:22.421Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 1142
File: examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol:141-147
Timestamp: 2025-12-23T17:18:22.421Z
Learning: For Solidity contracts that verify Noir circuit proofs, the verifier's public inputs array must include both the circuit's public inputs and the public outputs. Ensure the verification input array length equals pub_inputs + pub_outputs. Example: a Noir circuit with 3 public inputs and 2064 public outputs should pass an array of length 2067 (3 + 2064). Apply this consistently across all contract verifier implementations and adjust tests accordingly.

Applied to files:

  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • packages/enclave-contracts/contracts/interfaces/IE3.sol
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
📚 Learning: 2024-10-23T01:59:27.215Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: tests/basic_integration/test.sh:21-21
Timestamp: 2024-10-23T01:59:27.215Z
Learning: In `tests/basic_integration/test.sh`, the hardcoded `CIPHERNODE_SECRET` is acceptable for testing purposes and does not need to be changed.

Applied to files:

  • tests/integration/base.sh
  • tests/integration/persist.sh
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: tests/basic_integration/test.sh:103-114
Timestamp: 2024-10-08T19:45:18.209Z
Learning: In `tests/basic_integration/test.sh`, the user prefers not to refactor the ciphernode addition section to reduce duplication.

Applied to files:

  • tests/integration/base.sh
  • packages/enclave-contracts/test/Enclave.spec.ts
  • tests/integration/persist.sh
📚 Learning: 2024-09-26T04:24:54.011Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: tests/basic_integration/test.sh:129-129
Timestamp: 2024-09-26T04:24:54.011Z
Learning: In `tests/basic_integration/test.sh`, it's acceptable to not add error handling for the `fake_encrypt.sh` script.

Applied to files:

  • tests/integration/base.sh
📚 Learning: 2025-10-10T12:56:40.538Z
Learnt from: 0xjei
Repo: gnosisguild/enclave PR: 830
File: templates/default/README.md:123-128
Timestamp: 2025-10-10T12:56:40.538Z
Learning: In the Enclave repository, the hard-coded Hardhat development private key `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` is acceptable in template README files and documentation for local testing/interaction purposes.

Applied to files:

  • tests/integration/base.sh
  • packages/enclave-contracts/test/Enclave.spec.ts
  • tests/integration/persist.sh
📚 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:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 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:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed to support multiple network connections: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3. Similarly, `.revertedWithoutReason(ethers)` replaces `.revertedWithoutReason`.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
🧬 Code graph analysis (3)
templates/default/client/src/pages/steps/ActivateE3.tsx (2)
packages/enclave-contracts/tasks/enclave.ts (1)
  • activateE3 (308-333)
packages/enclave-sdk/src/contract-client.ts (1)
  • activateE3 (164-194)
packages/enclave-sdk/src/enclave-sdk.ts (4)
crates/wasm/init_web.js (1)
  • initializeWasm (11-29)
crates/wasm/init_node.js (1)
  • initializeWasm (7-9)
crates/wasm/src/lib.rs (1)
  • compute_pk_commitment (59-68)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-159)
examples/CRISP/server/src/cli/commands.rs (2)
crates/wasm/src/lib.rs (1)
  • compute_pk_commitment (59-68)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-159)
⏰ 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). (11)
  • GitHub Check: build_e3_support_risc0
  • GitHub Check: integration_prebuild
  • GitHub Check: build_ciphernode_image
  • GitHub Check: build_sdk
  • GitHub Check: build_e3_support_dev
  • GitHub Check: rust_unit
  • GitHub Check: rust_integration
  • GitHub Check: test_net
  • GitHub Check: build_crisp_sdk
  • GitHub Check: build_enclave_cli
  • GitHub Check: Build & Push Image
🔇 Additional comments (19)
packages/enclave-contracts/contracts/interfaces/IE3.sol (1)

27-27: Documentation accurately reflects the refactoring to use public key commitment.

The documentation correctly describes that committeePublicKey now stores a hash/commitment of the public key rather than the raw public key. This aligns with the PR's refactoring objective.

All code consuming this field—including the CRISP on-chain proof verification flow—correctly handles it as a commitment hash. Specifically, CRISPProgram.sol properly passes e3.committeePublicKey as the first public input to the Noir verifier, which is the intended behavior for proof verification.

tests/integration/base.sh (1)

79-79: LGTM: Activation simplified to use commitment-based approach.

The removal of the --public-key-file parameter aligns with the PR objective to use public key commitments instead of passing raw public keys. The activation now relies on the public key hash that was computed and published during the key aggregation phase.

tests/integration/persist.sh (2)

52-58: Same parameter changes as in base.sh - ensure consistency.

These parameter changes are identical to tests/integration/base.sh. Please ensure these test scripts remain synchronized and that the new parameters (especially the plaintext modulus change from 1032193 to 1000) are compatible with the persistence testing flow.


84-84: LGTM: Consistent with commitment-based activation.

The removal of the --public-key-file parameter is consistent with the changes in base.sh and aligns with the PR's objective to use public key commitments.

crates/evm-helpers/src/contracts.rs (1)

78-78: LGTM! Activation signature successfully simplified.

The activation flow has been correctly updated to use a single-argument signature (e3_id only), removing the publicKey parameter from the Solidity ABI, trait definition, and implementation. This aligns with the PR's goal of using public key commitments stored in the registry instead of passing raw public keys during activation.

Also applies to: 140-141, 403-415

templates/default/client/src/pages/steps/ActivateE3.tsx (1)

74-74: LGTM! Activation call correctly updated.

The activateE3 call has been correctly updated to pass only e3State.id, removing the publicKey parameter. This aligns with the new single-argument activation API.

templates/default/tests/integration.spec.ts (1)

220-225: LGTM! Test correctly updated for single-argument activation.

The test has been correctly updated to extract only e3Id from state and pass it as the sole argument to activateE3. The publicKey is still properly retrieved from the state at line 235 for encryption purposes, maintaining the correct separation of concerns.

examples/CRISP/server/src/server/indexer.rs (1)

361-361: LGTM! Activation call correctly updated.

The activate call has been correctly updated to pass only event.e3Id. The surrounding context (handle_committee_time_expired is triggered after CommitteePublished event) ensures that the public key hash is already set in the registry before activation is attempted, maintaining the correct flow dependency.

packages/enclave-sdk/src/enclave-sdk.ts (2)

136-146: LGTM! New public key commitment computation method.

The new computePublicKeyCommitment method properly initializes WASM, fetches protocol parameters, and delegates to the wasm compute_pk_commitment function. The method signature and return type are appropriate for computing a 32-byte commitment from a public key.


342-348: LGTM! Activation method correctly simplified.

The activateE3 method signature has been correctly updated to accept only e3Id and gasLimit, removing the publicKey parameter. The contract client call is properly updated to match.

examples/CRISP/server/src/cli/commands.rs (1)

196-227: LGTM! Activation correctly updated while preserving key storage.

The activate call has been correctly updated to pass only e3_id. The function still properly generates and stores the public key (lines 214-217) for later decryption purposes, correctly separating the activation flow from key storage.

packages/enclave-contracts/contracts/interfaces/IEnclave.sol (1)

30-35: LGTM! Interface correctly updated for public key commitment.

The interface has been correctly updated: the E3Activated event now uses bytes32 for committeePublicKey (indicating a hash), the documentation clarifies this is a hash, and the activate function signature now accepts only e3Id. These changes align perfectly with the PR's goal of using public key commitments.

Note: This is a breaking change for any contracts implementing IEnclave. Based on the PR scope, all known implementations have been updated.

Also applies to: 155-155

packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol (2)

41-46: LGTM: Mock signature correctly extended.

The publishCommittee signature in both mock contracts has been correctly updated to accept the new publicKeyHash parameter, aligning with the updated ICiphernodeRegistry interface.

Also applies to: 120-125


92-92: Improved error handling in mock.

The addition of the CommitteeNotPublished error and the change from returning bytes32(0) to reverting provides more realistic mock behavior that better matches production contract semantics.

Also applies to: 106-108

packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json (2)

80-84: Correct type change for commitment-based approach.

The E3Activated event's committeePublicKey field type changed from bytes to bytes32 correctly reflects the new commitment-based architecture where only the hash (commitment) is stored on-chain rather than the full public key. This is more gas-efficient and enforces the fixed-size hash constraint.


415-427: New fee token getter added.

The feeToken() view function provides a standard way to query the configured fee token address. Implementation looks correct.

packages/enclave-contracts/test/Enclave.spec.ts (3)

941-943: Activation signature correctly updated.

All calls to activate() have been consistently updated from activate(e3Id, data) to activate(e3Id), aligning with the simplified contract interface where activation no longer requires passing the public key or data directly. The key commitment is now retrieved from the registry internally.

Also applies to: 975-979, 997-1000, 1034-1037, 1056-1059, 1090-1093, 1108-1111, 1153-1157, 1189-1190, 1222-1223


1574-1577: Correct hash function for ciphertext output verification.

Line 1576 correctly uses ethers.keccak256(data) to verify the ciphertext output hash. This treats data as hex bytes, which is appropriate for hashing binary data.


1284-1284: Consistent activation updates throughout test suite.

All remaining activate() calls have been consistently updated to use the single-argument signature. The refactoring is thorough and maintains consistency across all test cases.

Also applies to: 1318-1318, 1358-1358, 1379-1379, 1411-1411, 1468-1468, 1503-1503, 1542-1542, 1572-1572, 1602-1602, 1632-1632, 1686-1686, 1715-1715, 1750-1750, 1781-1781, 1813-1813, 1844-1844

Comment thread crates/indexer/src/indexer.rs Outdated
Comment thread packages/enclave-contracts/test/Enclave.spec.ts
Comment thread tests/integration/base.sh Outdated
@ctrlc03 ctrlc03 changed the title refactor: pass public key commitment for proof verification [skip-line-limit] refactor: pass public key commitment [skip-line-limit] Jan 2, 2026
@ctrlc03 ctrlc03 force-pushed the refactor/public-key branch from e6dc573 to 25a1916 Compare January 2, 2026 13:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (1)

140-143: Add validation for zero committeePublicKey.

The code fetches e3.committeePublicKey without validating it's been set. If committee selection hasn't completed, committeePublicKey will be bytes32(0), causing an InvalidNoirProof error instead of a clear indication of the actual problem. This concern was raised in a previous review and remains unaddressed.

🔎 Suggested validation
 // Fetch E3 to get committee public key
 E3 memory e3 = enclave.getE3(e3Id);
+if (e3.committeePublicKey == bytes32(0)) revert CommitteePublicKeyNotSet();
 
 noirPublicInputs[0] = e3.committeePublicKey;

Note: You'll need to add the custom error definition near the other error declarations:

error CommitteePublicKeyNotSet();
crates/indexer/src/indexer.rs (2)

389-391: Cleanup error is silently discarded.

The result of the temporary storage cleanup is discarded with let _ =. If cleanup fails, temporary keys will accumulate in the data store.

This issue was flagged in a previous review. Consider logging the error:

🔎 Proposed fix
 // Remove the temporary storage
 let mut db_clone = db.clone();
-let _ = db_clone.modify::<Vec<u8>, _>(&temp_key, |_| None).await;
+if let Err(e) = db_clone.modify::<Vec<u8>, _>(&temp_key, |_| None).await {
+    tracing::warn!("Failed to cleanup temporary key {}: {}", temp_key, e);
+}

366-380: Consider adding idempotency protection.

If E3Activated is replayed (due to retries, network issues, or re-indexing), the handler will fail with "CommitteePublished event not found" because the temp key was deleted after the first successful processing.

This was flagged in a previous review. Consider checking if the E3 already exists before processing:

let mut repo = E3Repository::new(db.clone(), e3_id);
if repo.get_e3().await.is_ok() {
    info!("E3Activated: E3 {} already processed, skipping", e3_id);
    return Ok(());
}
🧹 Nitpick comments (4)
examples/CRISP/server/src/server/token_holders/etherscan.rs (1)

621-621: Remove redundant import.

CONFIG is already imported at the file level (line 16) and brought into the tests module via use super::*; (line 620), making this explicit import unnecessary.

🔎 Proposed fix
-    use crate::server::CONFIG;
templates/default/client/src/pages/steps/ActivateE3.tsx (2)

14-20: Update component documentation to reflect API change.

The documentation states this component "handles the activation of the E3 using the Ciphernode Committee's shared public key," but line 74 shows that activateE3 is now called without passing the public key. Update the comment to reflect that activation now uses a public key commitment handled by the backend.

📝 Suggested documentation update
 /**
  * ActivateE3 component - Third step in the Enclave wizard flow
  *
- * This component handles the activation of the E3 using the Ciphernode Committee's
- * shared public key. It provides feedback on the activation process and displays
+ * This component handles the activation of the E3. The backend uses the Ciphernode 
+ * Committee's public key commitment for verification. It provides feedback on the 
+ * activation process and displays
  * the status of the activation.
  */

137-146: Clarify button state and messaging after API change.

The button is disabled when !e3State.publicKey and displays "Waiting for Committee Key..." (lines 144-145), yet the activation call on line 74 no longer passes the public key. This may confuse users who see the key-related messaging but don't understand why it's needed if not directly used.

If waiting for the public key is still required (e.g., the backend needs it available to compute the commitment), consider updating the UI text to clarify this:

💡 Suggested UI text clarification
               : !e3State.publicKey
-                ? 'Waiting for Committee Key...'
+                ? 'Waiting for Committee Key Setup...'
                 : 'Activate E3 Environment'}

Alternatively, if the public key check is no longer necessary after the API change, update the button's disabled condition:

           disabled={isRequesting || e3State.isActivated || !e3State.publicKey}
+          // Note: Verify if publicKey check is still needed after API refactoring
crates/wasm/src/lib.rs (1)

46-68: Consider documenting the expected commitment size.

The function documentation could mention that the returned commitment is 32 bytes, matching the bytes32 type used on-chain. This would help callers understand the expected output format.

📝 Suggested documentation enhancement
 #[wasm_bindgen]
 /// A function to compute the public key commitment for a given public key.
 ///
 /// # Arguments
 ///
 /// * `public_key` - The public key to compute the commitment for
+/// * `degree` - Polynomial degree for BFV parameters
+/// * `plaintext_modulus` - Plaintext modulus for BFV parameters
+/// * `moduli` - Moduli for BFV parameters
 ///
 /// # Returns
-/// Returns a `Result<Vec<u8>, JsValue>` containing the commitment and any errors.
+/// Returns a `Result<Vec<u8>, JsValue>` containing the 32-byte commitment and any errors.
 ///
 /// # Panics
 ///
 /// Panics if the public key cannot be computed
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6dc573 and 25a1916.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • examples/CRISP/Cargo.lock is excluded by !**/*.lock
  • templates/default/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (42)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/publickey_aggregator.rs
  • crates/bfv-helpers/src/client.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/evm-helpers/src/contracts.rs
  • crates/evm-helpers/src/events.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/indexer/Cargo.toml
  • crates/indexer/src/indexer.rs
  • crates/indexer/tests/fixtures/fake_enclave.sol
  • crates/indexer/tests/integration.rs
  • crates/tests/Cargo.toml
  • crates/tests/tests/integration_legacy.rs
  • crates/wasm/src/lib.rs
  • examples/CRISP/circuits/src/main.nr
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
  • examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol
  • examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-sdk/src/vote.ts
  • examples/CRISP/server/src/cli/approve.rs
  • examples/CRISP/server/src/cli/commands.rs
  • examples/CRISP/server/src/server/indexer.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json
  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol
  • packages/enclave-contracts/contracts/interfaces/IE3.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • packages/enclave-contracts/tasks/enclave.ts
  • packages/enclave-contracts/test/Enclave.spec.ts
  • packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts
  • packages/enclave-sdk/src/contract-client.ts
  • packages/enclave-sdk/src/enclave-sdk.ts
  • templates/default/client/src/pages/steps/ActivateE3.tsx
  • templates/default/tests/integration.spec.ts
  • tests/integration/base.sh
  • tests/integration/persist.sh
🚧 Files skipped from review as they are similar to previous changes (13)
  • tests/integration/persist.sh
  • crates/aggregator/Cargo.toml
  • crates/events/src/enclave_event/publickey_aggregated.rs
  • crates/evm-helpers/src/events.rs
  • packages/enclave-sdk/src/contract-client.ts
  • templates/default/tests/integration.spec.ts
  • examples/CRISP/packages/crisp-contracts/contracts/Mocks/MockEnclave.sol
  • crates/tests/Cargo.toml
  • examples/CRISP/server/src/server/indexer.rs
  • crates/indexer/tests/fixtures/fake_enclave.sol
  • packages/enclave-contracts/contracts/registry/CiphernodeRegistryOwnable.sol
  • tests/integration/base.sh
  • crates/indexer/Cargo.toml
🧰 Additional context used
🧠 Learnings (29)
📓 Common learnings
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-08T01:48:49.778Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.
📚 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:

  • crates/tests/tests/integration_legacy.rs
  • crates/indexer/tests/integration.rs
  • examples/CRISP/server/src/cli/approve.rs
  • crates/indexer/src/indexer.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • examples/CRISP/server/src/cli/commands.rs
📚 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:

  • crates/tests/tests/integration_legacy.rs
  • crates/indexer/tests/integration.rs
  • examples/CRISP/server/src/server/token_holders/etherscan.rs
  • crates/bfv-helpers/src/utils/greco.rs
  • crates/bfv-helpers/src/client.rs
  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2024-10-16T09:52:53.807Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/src/data_store.rs:74-75
Timestamp: 2024-10-16T09:52:53.807Z
Learning: In this project, the actor model handles potential errors internally, so methods like `checkpoint` in the `Checkpoint` trait do not need to explicitly handle or propagate errors.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
📚 Learning: 2024-10-03T23:02:41.732Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 133
File: packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs:137-139
Timestamp: 2024-10-03T23:02:41.732Z
Learning: In `packages/ciphernode/tests/tests/test_aggregation_and_decryption.rs`, using the same RNG instance `rng_test` for generating multiple key shares without advancing its state is acceptable.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
  • crates/indexer/tests/integration.rs
  • crates/bfv-helpers/src/utils/greco.rs
📚 Learning: 2024-10-08T01:48:49.778Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-08T01:48:49.778Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.

Applied to files:

  • crates/tests/tests/integration_legacy.rs
  • crates/evm/src/ciphernode_registry_sol.rs
  • crates/aggregator/src/publickey_aggregator.rs
📚 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:

  • crates/indexer/tests/integration.rs
  • crates/wasm/src/lib.rs
  • crates/bfv-helpers/src/client.rs
📚 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:

  • crates/indexer/tests/integration.rs
  • crates/wasm/src/lib.rs
  • packages/enclave-sdk/src/enclave-sdk.ts
  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2024-10-16T09:51:10.038Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/committee_meta.rs:43-43
Timestamp: 2024-10-16T09:51:10.038Z
Learning: In `packages/ciphernode/router/src/committee_meta.rs`, avoid suggesting making the `on_event` method in `CommitteMetaFeature` asynchronous or adding error handling for the `write` operation to the data store.

Applied to files:

  • crates/indexer/src/indexer.rs
  • crates/bfv-helpers/src/client.rs
  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
📚 Learning: 2025-12-17T05:58:25.984Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 1086
File: crates/events/src/eventstore.rs:21-29
Timestamp: 2025-12-17T05:58:25.984Z
Learning: In the EventStore implementation (crates/events/src/eventstore.rs), if log.append succeeds but index.insert fails in handle_store_event_requested, the event is persisted in the log but not indexed. This is intentional design: such events are ignored during sync operations, as the index is the source of truth for timestamp-based event retrieval.

Applied to files:

  • crates/indexer/src/indexer.rs
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • crates/indexer/src/indexer.rs
  • examples/CRISP/server/src/cli/commands.rs
  • crates/evm-helpers/src/contracts.rs
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2024-10-08T01:50:45.185Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/core/src/events.rs:323-323
Timestamp: 2024-10-08T01:50:45.185Z
Learning: When suggesting that instances of `E3Requested` should include `src_chain_id`, double-check to ensure that the field is actually missing before making the suggestion.

Applied to files:

  • crates/indexer/src/indexer.rs
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 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:

  • crates/indexer/src/indexer.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:

  • crates/indexer/src/indexer.rs
📚 Learning: 2025-04-30T06:25:14.721Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 372
File: packages/ciphernode/events/src/eventbus.rs:15-15
Timestamp: 2025-04-30T06:25:14.721Z
Learning: EnclaveEvent implements Display in packages/ciphernode/events/src/enclave_event/mod.rs, which satisfies the Event trait requirement. Static analysis tools may incorrectly flag implementations as missing when they do exist.

Applied to files:

  • crates/indexer/src/indexer.rs
📚 Learning: 2024-10-08T07:15:06.690Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/evm/src/ciphernode_registry_sol.rs:133-143
Timestamp: 2024-10-08T07:15:06.690Z
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:

  • crates/evm/src/ciphernode_registry_sol.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:

  • crates/evm/src/ciphernode_registry_sol.rs
  • examples/CRISP/server/src/cli/commands.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/packages/crisp-contracts/tests/crisp.contracts.test.ts
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
📚 Learning: 2025-09-19T11:16:53.825Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 752
File: packages/enclave-contracts/contracts/Enclave.sol:15-17
Timestamp: 2025-09-19T11:16:53.825Z
Learning: The Enclave contract in the gnosisguild/enclave repository has not been deployed yet as of September 2025, so storage layout considerations for upgradeable contracts don't apply to current changes.

Applied to files:

  • packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
📚 Learning: 2024-10-22T02:36:01.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/Cargo.toml:0-0
Timestamp: 2024-10-22T02:36:01.448Z
Learning: In `packages/ciphernode/data/Cargo.toml`, `actix-rt` is only used in tests and should remain in `[dev-dependencies]`.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/etherscan.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/token_holders/etherscan.rs
  • packages/enclave-contracts/test/Enclave.spec.ts
📚 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:

  • crates/bfv-helpers/src/utils/greco.rs
📚 Learning: 2025-12-23T17:18:22.421Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 1142
File: examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol:141-147
Timestamp: 2025-12-23T17:18:22.421Z
Learning: For Solidity contracts that verify Noir circuit proofs, the verifier's public inputs array must include both the circuit's public inputs and the public outputs. Ensure the verification input array length equals pub_inputs + pub_outputs. Example: a Noir circuit with 3 public inputs and 2064 public outputs should pass an array of length 2067 (3 + 2064). Apply this consistently across all contract verifier implementations and adjust tests accordingly.

Applied to files:

  • packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol
  • packages/enclave-contracts/contracts/interfaces/IE3.sol
  • packages/enclave-contracts/contracts/interfaces/IEnclave.sol
  • packages/enclave-contracts/contracts/Enclave.sol
  • packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol
📚 Learning: 2025-12-19T11:35:51.645Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 1109
File: examples/CRISP/server/src/server/routes/state.rs:33-37
Timestamp: 2025-12-19T11:35:51.645Z
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-contracts/contracts/CRISPProgram.sol
📚 Learning: 2025-09-11T13:21:31.031Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/tasks/utils.ts:7-8
Timestamp: 2025-09-11T13:21:31.031Z
Learning: In Hardhat v3, the task API syntax has changed significantly from v2. The new syntax uses:
- `.addOption({ name, description, defaultValue, type })` instead of `.addOptionalParam()`
- `.setAction(async () => ({ default: (args, hre) => { ... } }))` instead of direct `.setAction((args, hre) => { ... })`
- `.build()` is required to finalize task definitions
- `ArgumentType.STRING` is used for option types instead of `types.string`

Applied to files:

  • packages/enclave-contracts/tasks/enclave.ts
📚 Learning: 2025-10-10T12:56:40.538Z
Learnt from: 0xjei
Repo: gnosisguild/enclave PR: 830
File: templates/default/README.md:123-128
Timestamp: 2025-10-10T12:56:40.538Z
Learning: In the Enclave repository, the hard-coded Hardhat development private key `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` is acceptable in template README files and documentation for local testing/interaction purposes.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.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:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
📚 Learning: 2025-09-11T12:56:39.601Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 677
File: packages/enclave-contracts/test/Enclave.spec.ts:804-807
Timestamp: 2025-09-11T12:56:39.601Z
Learning: In Hardhat v3, the chai matchers syntax changed to support multiple network connections: `.to.not.be.revert(ethers)` is the correct new syntax, replacing the old `.to.not.be.reverted` (without parameters). The ethers object must be passed as a parameter to the revert/reverted matchers in Hardhat v3. Similarly, `.revertedWithoutReason(ethers)` replaces `.revertedWithoutReason`.

Applied to files:

  • packages/enclave-contracts/test/Enclave.spec.ts
🧬 Code graph analysis (7)
crates/tests/tests/integration_legacy.rs (2)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-171)
crates/wasm/src/lib.rs (1)
  • compute_pk_commitment (59-68)
crates/indexer/src/indexer.rs (2)
examples/CRISP/server/src/server/indexer.rs (2)
  • register_committee_published (318-354)
  • register_e3_activated (182-211)
packages/enclave-sdk/src/types.ts (1)
  • E3 (120-134)
examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (1)
examples/CRISP/packages/crisp-contracts/tests/utils.ts (2)
  • deployMockEnclave (43-47)
  • deployCRISPProgram (69-87)
packages/enclave-sdk/src/enclave-sdk.ts (4)
crates/wasm/init_web.js (1)
  • initializeWasm (11-29)
crates/wasm/init_node.js (1)
  • initializeWasm (7-9)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-171)
crates/wasm/src/lib.rs (1)
  • compute_pk_commitment (59-68)
crates/bfv-helpers/src/client.rs (3)
crates/bfv-helpers/src/utils/greco.rs (1)
  • bfv_public_key_to_greco (233-283)
crates/wasm/src/lib.rs (1)
  • compute_pk_commitment (59-68)
crates/bfv-helpers/src/lib.rs (1)
  • build_bfv_params_arc (278-300)
examples/CRISP/server/src/cli/commands.rs (1)
crates/indexer/src/indexer.rs (1)
  • contract (185-187)
crates/aggregator/src/publickey_aggregator.rs (1)
crates/bfv-helpers/src/client.rs (1)
  • compute_pk_commitment (133-171)
⏰ 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: build_e3_support_dev
  • GitHub Check: build_enclave_cli
  • GitHub Check: integration_prebuild
  • GitHub Check: build_sdk
  • GitHub Check: build_crisp_sdk
  • GitHub Check: rust_unit
  • GitHub Check: test_net
  • GitHub Check: build_ciphernode_image
  • GitHub Check: rust_integration
🔇 Additional comments (55)
examples/CRISP/server/src/cli/approve.rs (1)

28-28: LGTM: Import style improvement.

Removing the braces for a single import aligns with idiomatic Rust conventions and improves code consistency.

examples/CRISP/packages/crisp-contracts/contracts/CRISPProgram.sol (1)

138-149: Circuit correctly updated with 4 public inputs.

The Noir circuit in examples/CRISP/circuits/src/main.nr has been properly updated to accept the 4 public inputs matching the Solidity implementation: pk_commitment, merkle_root, slot_address, and is_first_vote, followed by the vote outputs array. The circuit and contract are aligned.

templates/default/client/src/pages/steps/ActivateE3.tsx (1)

66-69: The publicKey guard check is necessary and should be preserved.

Although activateE3() doesn't directly use the publicKey parameter, the check is still essential because the publicKey is required in the subsequent step (EnterInputs) to encrypt user inputs. The guard ensures the workflow is in a complete state before proceeding to activation, preventing a scenario where activation succeeds but the system isn't ready for the following encryption step.

examples/CRISP/packages/crisp-contracts/tests/crisp.contracts.test.ts (2)

74-75: LGTM! Test setup correctly wires the mock enclave.

The mock enclave deployment and injection into deployCRISPProgram aligns with the updated signature and enables the test to control the committee public key for proof verification.


97-97: No changes needed.

The code is correct as written. proof.publicInputs[0] contains the committee public key commitment (the first public input declared in the Noir circuit), and passing it to setCommitteePublicKey is the right approach for setting up the test enclave state before proof verification.

examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol (3)

14-17: Verification key publicInputsSize is consistent with the constant.

The publicInputsSize: uint256(2068) matches NUMBER_OF_PUBLIC_INPUTS at line 10, maintaining consistency within the verification key initialization.


10-11: Constants updated correctly for public key commitment support.

The increment from 2067 to 2068 public inputs is correct and aligns with the PR objective of adding committeePublicKey to the verification flow. The Noir circuit now passes 4 public inputs (pk_commitment, merkle_root, slot_address, is_first_vote) instead of 3, with the remaining 2064 fields representing public outputs, totaling 2068 values. This is confirmed by CRISPProgram.sol which constructs the public inputs array with exactly 4 fixed elements plus the vote array at indices 4 onwards.

The VK_HASH and G1Point coordinate updates require verification against circuit compilation output to ensure they match the updated circuit's verification key, which is not available in the repository.


18-129: G1Point coordinates are correctly auto-generated from the Noir circuit.

These precomputed elliptic curve points are auto-generated via the compilation pipeline: nargo compilebb write_vkbb write_solidity_verifier. The circuit includes pk_commitment (committeePublicKey) as a public input, and the verification key structure in loadVerificationKey() is guaranteed to match the circuit's compiled artifacts. The public inputs array passed to the verifier correctly includes both the circuit's 4 public inputs (committeePublicKey, merkleRoot, slotAddress, isFirstVote) and the circuit's public outputs (ciphertext components), per Noir verification specification.

crates/wasm/src/lib.rs (1)

46-68: LGTM! Clean WASM wrapper with proper error handling.

The function follows the established pattern in this file, properly delegates to the internal implementation, and handles errors appropriately.

packages/enclave-contracts/artifacts/contracts/interfaces/IEnclave.sol/IEnclave.json (2)

79-84: LGTM! ABI correctly reflects E3Activated event signature change.

The event ABI properly represents the change from bytes to bytes32 for the committeePublicKey parameter, matching the updated Solidity interface.


415-427: New feeToken() getter function added.

A view function to retrieve the fee token address has been added to the ABI. While not directly related to the publicKeyHash refactoring, this is a safe addition that exposes existing state.

packages/enclave-contracts/contracts/test/MockCiphernodeRegistry.sol (4)

41-46: LGTM! Mock signature updated to match interface changes.

The publishCommittee function signature correctly adds the bytes32 parameter for the public key hash, aligning with the updated ICiphernodeRegistry interface.


92-93: Good practice: custom error for clearer failure signaling.

The new CommitteeNotPublished error provides a clearer signal than returning a zero value, improving test reliability and gas efficiency.


120-125: LGTM! Consistent signature update across both mock contracts.

The publishCommittee signature in MockCiphernodeRegistryEmptyKey matches the update in MockCiphernodeRegistry, ensuring consistency.


106-108: Improved mock behavior: revert instead of returning zero.

The change from returning bytes32(0) to reverting with CommitteeNotPublished() makes the mock more realistic and prevents accidental use of zero as a valid public key hash. Tests using MockCiphernodeRegistryEmptyKey correctly expect this revert behavior.

packages/enclave-contracts/contracts/interfaces/IEnclave.sol (1)

148-155: Breaking change: activate() function signature simplified.

The publicKey parameter has been removed. The function now relies on the registry to provide the public key commitment internally, consistent with the shift to using public key hashes.

All callers have been properly updated to the new single-parameter signature across the codebase (tasks/enclave.ts and test files).

examples/CRISP/packages/crisp-sdk/src/vote.ts (1)

283-284: Indices are correct and align with the updated circuit structure.

The shift from slice(3) to slice(4) and from publicInputs[1] to publicInputs[2] correctly reflects the updated circuit layout where pk_commitment was added as the first public input. The circuit defines four public inputs in order: pk_commitment (index 0), merkle_root (index 1), slot_address (index 2), and is_first_vote (index 3), with the vote array starting at index 4. The indices in this code match both the circuit's public input ordering and the contract's verification setup.

packages/enclave-contracts/contracts/interfaces/IE3.sol (1)

27-27: Documentation update aligns with public key hash refactoring.

The NatSpec correctly reflects that committeePublicKey now stores a hash rather than the raw public key, consistent with the PR's shift to commitment-based verification.

examples/CRISP/circuits/src/main.nr (1)

56-56: Public input visibility enables on-chain commitment verification.

Making pk_commitment a public input allows the on-chain verifier to validate that proofs are generated against the correct committee public key. This change aligns with the PR objective to integrate public key commitments into CRISP's proof verification flow.

crates/indexer/tests/integration.rs (3)

46-47: Test uses appropriate insecure parameter set.

Using InsecureSet2048_1032193_1 for testing is appropriate as it provides faster test execution while maintaining the same API surface. The "Insecure" prefix clearly indicates this is not for production use.


97-107: Public key commitment computation correctly integrated.

The test properly generates a BFV keypair and computes the public key commitment using compute_pk_commitment with all required parameters (public key bytes, degree, plaintext modulus, and moduli). This accurately reflects the production flow introduced in this PR.


112-124: Test validates two-phase activation flow with public key commitment.

The test correctly implements the new flow:

  1. Publish committee public key via emitCommitteePublished (lines 112-118)
  2. Activate E3 with the 32-byte public key commitment via emitE3Activated (lines 120-129)

This two-phase approach mirrors the production behavior where the committee public key is published off-chain and referenced on-chain via its commitment hash.

packages/enclave-contracts/contracts/interfaces/ICiphernodeRegistry.sol (1)

159-164: Breaking API change to publishCommittee signature properly implemented.

The addition of the publicKeyHash parameter is a breaking API change to the function signature. All implementations and call sites have been updated:

  • Interface and concrete implementation include the new parameter
  • Test files (Enclave.spec.ts, CiphernodeRegistryOwnable.spec.ts) pass the computed hash
  • Hardhat task passes the hash as a required parameter
  • Rust integration code provides the hash parameter
  • Internal keccak256(publicKey) computation has been removed; hash computation responsibility is now on the caller (e.g., ethers.id(publicKey) in tests)
examples/CRISP/server/src/cli/commands.rs (1)

209-210: Activation signature correctly simplified to single e3_id parameter.

The removal of the pk_bytes parameter from contract.activate() is correct. However, note that the generated public key (lines 200-201) is stored locally in the database, not sent to the contract. The public key is retrieved from the smart contract's state via the /rounds/public-key API endpoint when needed by participants.

Likely an incorrect or invalid review comment.

packages/enclave-contracts/test/Registry/CiphernodeRegistryOwnable.spec.ts (3)

346-347: LGTM!

The publishCommittee calls have been correctly updated to include the new dataHash parameter, consistent with the updated contract interface.

Also applies to: 365-366, 386-387, 513-514


367-369: LGTM!

Test assertions correctly validate that committeePublicKey now stores the dataHash instead of the raw public key, aligning with the contract's updated behavior.

Also applies to: 515-517


31-31: The file CiphernodeRegistryOwnable.spec.ts was created with ethers.id(data) in the initial commit—this was not a change from ethers.keccak256(). The review comment's assumption about a transition between hash functions is unfounded.

While ethers.id() is semantically incorrect for hashing binary data (ethers.id() treats input as a UTF-8 string via keccak256(toUtf8Bytes(text)), whereas data = "0xda7a" represents raw bytes), this is an original design choice, not a problematic modification.

Likely an incorrect or invalid review comment.

packages/enclave-contracts/artifacts/contracts/interfaces/ICiphernodeRegistry.sol/ICiphernodeRegistry.json (1)

375-380: LGTM!

The ABI correctly reflects the addition of the publicKeyHash parameter to the publishCommittee function. The parameter is appropriately placed at the end of the parameter list, which is good practice for maintaining backward compatibility where possible.

crates/aggregator/src/publickey_aggregator.rs (2)

185-190: LGTM!

The compute_pk_commitment call correctly passes the aggregated public key and FHE parameters to generate the 32-byte commitment. Error handling via the ? operator is appropriate, and the pubkey.clone() is necessary since pubkey is used again for state update.


203-209: LGTM! The PublicKeyAggregated event structure is correctly implemented.

The event includes both the raw pubkey and the computed public_key_hash, allowing off-chain components to use the raw public key while on-chain components can verify the commitment. All four fields (pubkey, public_key_hash, e3_id, nodes) match the struct definition and are properly populated.

packages/enclave-sdk/src/enclave-sdk.ts (1)

136-146: LGTM!

The computePublicKeyCommitment method correctly initializes WASM, retrieves protocol parameters, and invokes the WASM binding. The parameter conversion using BigUint64Array.from for moduli is appropriate. The WASM binding correctly converts the fixed-size array [u8; 32] from the underlying function to Vec<u8> via .to_vec() before returning, which properly maps to the TypeScript Promise<Uint8Array> return type.

crates/tests/tests/integration_legacy.rs (4)

11-11: LGTM!

The import for compute_pk_commitment is correctly added to support the new public key hash computation in the tests.


224-236: LGTM!

The public key hash computation and its inclusion in the PublicKeyAggregated event are correctly implemented. The parameters passed to compute_pk_commitment (public key bytes, degree, plaintext modulus, and moduli) match the function signature and correctly derive the 32-byte commitment.


572-592: LGTM!

The pattern for computing and including public_key_hash in the duplicate E3 ID test is consistent with the other test cases.


615-635: LGTM!

The second E3 with a different chain ID correctly computes its own public_key_hash and includes it in the PublicKeyAggregated assertion.

crates/indexer/src/indexer.rs (3)

22-24: LGTM!

The CommitteePublished event is correctly added to the imports to support the new event handling flow.


334-358: LGTM!

The register_committee_published handler correctly stores the committee public key in temporary storage keyed by e3_id. This approach enables the E3Activated handler to retrieve the full public key while only the hash is passed on-chain.


491-499: LGTM!

The listener registration order is correct—register_committee_published is called before register_e3_activated, ensuring the temporary storage is populated before the activated event attempts to read it.

crates/bfv-helpers/src/client.rs (1)

133-171: LGTM!

The compute_pk_commitment function is well-implemented. The left-padding logic (lines 162-168) correctly handles BigInt values that produce fewer than 32 bytes, addressing the concern raised in a previous review. The function properly:

  1. Deserializes the BFV public key with appropriate error handling
  2. Computes Greco bounds and bit width for the commitment
  3. Converts the public key to Greco format and computes the commitment
  4. Ensures a consistent 32-byte output with proper padding
crates/evm/src/ciphernode_registry_sol.rs (3)

12-12: LGTM!

FixedBytes is correctly imported to support the 32-byte public key hash handling.


406-424: LGTM!

The PublicKeyAggregated handler correctly extracts public_key_hash from the message and passes it to publish_committee_to_registry. The async block properly captures and forwards all necessary data.


487-515: LGTM!

The publish_committee_to_registry function is correctly updated to:

  1. Accept the new public_key_hash: [u8; 32] parameter
  2. Convert it to FixedBytes for the contract call
  3. Pass it to the publishCommittee contract method

The implementation aligns with the updated contract interface.

crates/bfv-helpers/src/utils/greco.rs (4)

9-9: LGTM!

PublicKey is correctly added to the imports to support the new bfv_public_key_to_greco function.


185-220: LGTM!

The helper functions for BFV to Greco coefficient conversion are correctly implemented:

  • convert_bfv_coefficient_to_centered properly centers coefficients from [0, qi) to [-(qi-1)/2, (qi-1)/2]
  • convert_bfv_coefficients_to_greco correctly applies the centering, reversal, and modular reduction with proper handling of negative values

233-283: LGTM!

The bfv_public_key_to_greco function correctly:

  1. Accesses the internal polynomial structure of the PublicKey via pk.c.c[0] and pk.c.c[1]
  2. Converts polynomials to power basis representation for coefficient extraction
  3. Iterates over each modulus and extracts coefficients per degree
  4. Applies the Greco conversion (centering, reversing, modular reduction)

The implementation mirrors the inverse of greco_to_bfv_ciphertext and aligns with the GrecoVectors standard form output as validated by the test.


385-472: LGTM!

The test thoroughly validates bfv_public_key_to_greco by comparing its output against the expected values from GrecoVectors::compute. It checks both structure (vector lengths) and content (coefficient equality) for both pk0is and pk1is.

crates/evm-helpers/src/contracts.rs (3)

78-78: LGTM!

The Solidity ABI definition is correctly updated to reflect the simplified activate(uint256 e3Id) signature, removing the public key parameter as per the PR objectives.


140-141: LGTM!

The EnclaveWrite trait correctly reflects the simplified activate method signature. The documentation is appropriately updated.


403-415: LGTM!

The activate implementation is correctly updated to use the single-parameter contract call. Nonce handling, wallet address validation, and error propagation remain properly implemented.

packages/enclave-contracts/tasks/enclave.ts (3)

258-263: LGTM!

The new publicKeyHash option is correctly added with appropriate metadata (type STRING, description indicating bytes32 format).


265-299: LGTM!

The publishCommittee action correctly:

  1. Accepts the new publicKeyHash parameter
  2. Validates that publicKeyHash is provided (throws if missing)
  3. Passes it to the ciphernodeRegistry.publishCommittee call

The validation ensures the required parameter is not omitted.


308-333: LGTM!

The activateE3 task is correctly simplified:

  1. Removed publicKey and publicKeyFile options (no longer needed)
  2. Action signature now only accepts e3Id
  3. enclave.activate call uses only e3Id parameter

This aligns with the contract change where activation no longer requires the raw public key.

packages/enclave-contracts/test/Enclave.spec.ts (3)

63-77: LGTM: Test helper correctly updated for new contract signature.

The setupAndPublishCommittee helper now computes publicKeyHash and passes it as the fourth parameter to publishCommittee, which aligns with the updated contract interface described in the PR objectives.


941-1844: Excellent: All activate() calls correctly migrated to single-argument form.

All 27+ invocations of activate() throughout the test suite have been updated from activate(e3Id, data) to activate(e3Id), correctly reflecting the API change. Test coverage includes success paths, error cases (E3DoesNotExist, E3NotReady, E3Expired, E3AlreadyActivated, CommitteeNotPublished), static calls, and event emissions.


1576-1576: LGTM: Correct hash function for ciphertext output validation.

The assertion correctly uses ethers.keccak256(data) to verify the ciphertext output hash, which matches Solidity's keccak256 behavior for raw byte hashing.

Comment thread packages/enclave-contracts/contracts/interfaces/IEnclave.sol
Comment thread packages/enclave-sdk/src/enclave-sdk.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
packages/enclave-sdk/README.md (1)

247-261: Document the computePublicKeyCommitment utility with correct signature.

computePublicKeyCommitment is exposed as part of the SDK's public key commitment workflow, but it is missing from the Utilities section. Add documentation for this function to help developers understand how to compute public key commitments.

The function takes only a publicKey parameter; the degree, plaintextModulus, and moduli are automatically fetched from the protocol parameters internally.

🔎 Suggested addition to Utilities section
 #### Utilities

 ```typescript
 // Gas estimation
 const gas = await sdk.estimateGas(functionName, args, contractAddress, abi, value?);

 // Transaction waiting
 const receipt = await sdk.waitForTransaction(hash);

+// Compute public key commitment
+const publicKeyCommitment = await sdk.computePublicKeyCommitment(publicKey);

 // Configuration updates
 sdk.updateConfig(newConfig: Partial<SDKConfig>);

 // Cleanup
 sdk.cleanup();
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 25a1916 and 01a21a6.

📒 Files selected for processing (3)
  • crates/evm-helpers/tests/fixtures/fake_enclave.sol
  • docs/pages/setting-up-server.mdx
  • packages/enclave-sdk/README.md
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-12T10:24:07.572Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 139
File: packages/ciphernode/aggregator/src/publickey_aggregator.rs:46-46
Timestamp: 2024-10-08T01:48:49.778Z
Learning: In `packages/ciphernode/router/src/hooks.rs`, the `src_chain_id` parameter in `PublicKeyAggregator::new` is correctly handled, even if not explicitly provided during instantiation.
📚 Learning: 2024-10-22T03:39:29.448Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/evm/src/enclave_sol_reader.rs:87-89
Timestamp: 2024-10-22T03:39:29.448Z
Learning: In the `ciphernode` project, specifically in `packages/ciphernode/evm/src/enclave_sol_reader.rs`, the method `EnclaveSolReader::attach` should be retained even if it directly calls `EvmEventReader::attach` without additional processing. Avoid suggesting its removal in future reviews.

Applied to files:

  • crates/evm-helpers/tests/fixtures/fake_enclave.sol
⏰ 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). (10)
  • GitHub Check: build_crisp_sdk
  • GitHub Check: build_sdk
  • GitHub Check: build_e3_support_dev
  • GitHub Check: build_enclave_cli
  • GitHub Check: test_net
  • GitHub Check: rust_integration
  • GitHub Check: build_ciphernode_image
  • GitHub Check: integration_prebuild
  • GitHub Check: rust_unit
  • GitHub Check: Build & Push Image
🔇 Additional comments (4)
crates/evm-helpers/tests/fixtures/fake_enclave.sol (2)

10-10: LGTM! Type change aligns with commitment-based architecture.

The parameter type change from bytes to bytes32 correctly reflects the shift to passing a fixed-size public key commitment (hash) instead of the full public key, as outlined in the PR objectives.


17-19: LGTM! Function signature correctly updated.

The function signature and emit call are correctly updated to match the new bytes32 event parameter type, maintaining consistency with the E3Activated event declaration.

packages/enclave-sdk/README.md (1)

220-220: activateE3 signature correctly updated to remove publicKey parameter.

The API signature change aligns with the PR objective to use precomputed public key commitments instead of embedding keys at activation time.

docs/pages/setting-up-server.mdx (1)

268-268: The API signature change is correct, but the review comment misidentifies what was removed.

The activateE3(e3Id) call at line 268 is correct. However, the review comment incorrectly claims that the publicKey parameter was removed. The actual API signature is activateE3(e3Id: bigint, gasLimit?: bigint), where gasLimit is the optional second parameter—not publicKey. There is no evidence in the codebase that publicKey was ever a parameter for activateE3. Public key handling in the SDK is separate and applies to encryption methods like encryptNumber() and encryptVector(), not activation.

The code change itself is valid and requires no modifications.

Likely an incorrect or invalid review comment.

@vercel vercel Bot temporarily deployed to Preview – crisp January 2, 2026 14:57 Inactive
@vercel vercel Bot temporarily deployed to Preview – enclave-docs January 2, 2026 14:57 Inactive
@ctrlc03 ctrlc03 self-requested a review January 2, 2026 15:12
@ctrlc03 ctrlc03 merged commit 53d5dfe into main Jan 2, 2026
27 checks passed
@ctrlc03 ctrlc03 deleted the refactor/public-key branch January 2, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use commitments in crisp on-chain proof verification Publish new public key + hash onchain and add offchain greco conversion

2 participants