Skip to content

feat: safe refactoring#1079

Merged
cedoor merged 10 commits into
mainfrom
feat/safe-rust
Dec 4, 2025
Merged

feat: safe refactoring#1079
cedoor merged 10 commits into
mainfrom
feat/safe-rust

Conversation

@0xjei

@0xjei 0xjei commented Dec 4, 2025

Copy link
Copy Markdown
Contributor
  • fixed bug for buffer overflow in word_count loop.
  • use keccak256 instead of sha256 (sha3 over sha2 family).
  • implement SAFE in Rust.

Summary by CodeRabbit

  • New Features

    • Added SAFE sponge crate with public API (start, absorb, squeeze, finish), IO-pattern support, domain separation, compute_tag, constants, and Field alias.
  • Improvements

    • Switched tag hashing from SHA-256 to Keccak-256; tightened serialization and IO-pattern bounds checks; updated CRISP verifier VK hash.
  • Tests

    • Added comprehensive tests including large IO-pattern and domain-separator cases.
  • Chores

    • Added SAFE crate to workspace; bumped CRISP packages and client SDK versions; adjusted publish script and build copy for workspace.

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

Closes #1064

@0xjei 0xjei requested a review from cedoor December 4, 2025 11:03
@vercel

vercel Bot commented Dec 4, 2025

Copy link
Copy Markdown

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

Project Deployment Preview Comments Updated (UTC)
crisp Ready Ready Preview Comment Dec 4, 2025 4:21pm
enclave-docs Ready Ready Preview Comment Dec 4, 2025 4:21pm

@coderabbitai

coderabbitai Bot commented Dec 4, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a new Rust SAFE sponge crate under crates/safe, replaces SHA‑256 with Keccak‑256 in the Noir SAFE circuit, tightens IO‑pattern serialization and runtime bounds checks, adds tests for large IO patterns and domain‑separator behavior, and updates build and example artifacts to include the new crate and version bumps.

Changes

Cohort / File(s) Summary
Workspace
\Cargo.toml``
Added crates/safe to the workspace members.
Circuit SAFE (Noir)
\circuits/crates/libs/safe/Nargo.toml`, `circuits/crates/libs/safe/src/lib.nr``
Replaced sha256 dependency with keccak256; switched compute_tag to Keccak‑256; added runtime bounds assertions and deterministic 4‑byte word serialization into a fixed 256‑byte buffer; appended domain separator byte‑wise; replaced sha256_var with keccak256; added tests for large IO patterns and domain‑separator behavior.
Rust SAFE crate
\crates/safe/Cargo.toml`, `crates/safe/src/lib.rs``
New crate manifest and SAFE sponge implementation: BN254 Field alias, RATE/CAPACITY/STATE_SIZE and flag constants, SafeSponge<const L> with start, absorb, squeeze, finish, compute_tag (Keccak‑256), Poseidon2 permutation integration, and tests.
Build context
\crates/Dockerfile``
Added copy step to include crates/safe/Cargo.toml into Docker build context so crates/safe is part of workspace during image build.
CRISP verifier
\examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol``
Replaced verification key data and updated VK_HASH constant; no signature or control‑flow changes.
CRISP packages (versions & deps)
\examples/CRISP/client/package.json`, `examples/CRISP/packages/crisp-contracts/package.json`, `examples/CRISP/packages/crisp-sdk/package.json`, `examples/CRISP/packages/crisp-zk-inputs/package.json``
Bumped package versions 0.4.10.4.2; updated @crisp-e3/sdk dependency to 0.4.2.
CRISP publish script
\examples/CRISP/scripts/publish.ts``
Git operations now detect repository root, add root pnpm-lock.yaml if present, run git commands from repo root, and remove per‑package commit block from the commit message.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client as Caller (API/User)
    participant Safe as SafeSponge::<L>
    participant Keccak as keccak256
    participant Poseidon as Poseidon2

    Client->>Safe: start(io_pattern, domain_separator)
    Note right of Safe: serialize IO pattern into fixed buffer\nperform runtime bounds checks
    Safe->>Keccak: keccak256(buffer[..byte_count])
    Keccak-->>Safe: 32-byte digest
    Safe->>Safe: truncate digest → 128-bit Field tag\ninitialize state with tag

    Client->>Safe: absorb(input_fields)
    Safe->>Safe: validate pattern, write into state
    Safe->>Poseidon: permute when rate full
    Poseidon-->>Safe: permuted state

    Client->>Safe: squeeze()
    Safe->>Safe: validate pattern, read outputs
    Safe->>Poseidon: permute as needed between squeezes
    Poseidon-->>Safe: permuted state

    Client->>Safe: finish()
    Safe->>Safe: assert IO pattern complete, clear state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect Noir compute_tag fixed-buffer serialization, boundary counting, and runtime assertions in circuits/crates/libs/safe/src/lib.nr.
  • Verify Keccak-256 substitution correctness and consistent 128-bit truncation across Noir and Rust implementations.
  • Review crates/safe/src/lib.rs for Poseidon2 integration, field arithmetic correctness, IO‑pattern enforcement, and secure state clearing.
  • Confirm workspace and Dockerfile updates correctly include crates/safe in builds and CI.
  • Sanity‑check updated verification key data and CRISP package version/dependency bumps.

Possibly related PRs

Suggested reviewers

  • ryardley

Poem

🐰 I hop through bytes and nibble on the tag,
Keccak hums softly while Poseidon waves a flag.
I pack the pattern, checks snug in my paw,
Absorb, permute, squeeze — a safe little draw.
🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes appear out of scope: keccak256 migration in Noir circuits, CRISPVerifier.sol VK updates, package version bumps, and Git script modifications are not directly required by #1064. Isolate circuit changes (Noir keccak256 migration, CRISPVerifier VK) and build/versioning changes into separate PRs focused on specific objectives.
Title check ❓ Inconclusive The title 'feat: safe refactoring' is vague and generic, failing to convey the specific nature of the changes (Rust crate implementation, keccak256 migration, bug fix). Use a more descriptive title such as 'feat: implement SAFE Rust crate with Poseidon2 and keccak256' or 'feat: add SAFE Rust crate with bug fixes and hash migration'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR successfully implements the core requirement from #1064: creates a Rust crate (crates/safe) implementing SAFE with Poseidon2 hashing for off-circuit use.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/safe-rust

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.

@0xjei 0xjei self-assigned this Dec 4, 2025
@0xjei 0xjei changed the title feat: SAFE refactoring feat: safe refactoring Dec 4, 2025
@theinterfold theinterfold deleted a comment from github-actions Bot Dec 4, 2025

@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

🧹 Nitpick comments (6)
crates/safe/Cargo.toml (2)

7-7: Repository URL should point to the main repository, not a subdirectory.

The repository field typically points to the root repository URL. Cargo/crates.io convention is to use the main repo URL.

-repository = "https://github.com/gnosisguild/enclave/crates/safe"
+repository = "https://github.com/gnosisguild/enclave"

10-13: Pin exact versions for cryptographic dependencies to match workspace strategy.

The ark-ff and ark-bn254 dependencies use semver ranges (0.5, 0.2) which allow patch variations, inconsistent with sha3 = "0.10.8" and the workspace's explicit pinning strategy. For cryptographic libraries, pin exact versions: ark-ff = "0.5.0", ark-bn254 = "0.5.0", and taceo-poseidon2 = "0.2.0".

crates/safe/src/lib.rs (4)

73-74: Clarify why the tag field is unused.

The tag field is stored but only used during initialization. If it's intentionally kept for future use or debugging, a brief comment would help. Otherwise, consider removing it or using it in finish() for verification.


124-124: Consider accepting &[Field] instead of Vec<Field> for the absorb input.

Taking Vec<Field> by value forces callers to allocate and transfer ownership. Accepting &[Field] would be more flexible and efficient, especially for callers who want to reuse the input buffer.

-    pub fn absorb(&mut self, input: Vec<Field>) {
-        let length = input.len() as u32;
+    pub fn absorb(&mut self, input: &[Field]) {
+        let length = input.len() as u32;
         // ...
-        for input in &input {
+        for elem in input {
             // ...
-            self.state[self.absorb_pos + CAPACITY] += input;
+            self.state[self.absorb_pos + CAPACITY] += elem;

This would require updating the test calls from sponge.absorb(elements.clone()) to sponge.absorb(&elements).


219-223: Consider using zeroize for secure memory erasure.

The state is reset to zero but standard assignment doesn't guarantee secure erasure—the compiler may optimize it away or old values may remain in memory. For cryptographic code, zeroize provides guaranteed secure erasure. The workspace already includes zeroize = "=1.8.1".

+use zeroize::Zeroize;

// In finish():
-    self.state = [Field::zero(); STATE_SIZE];
+    self.state.zeroize();

Note: This requires that Field (ark-bn254's Fr) implements Zeroize. If it doesn't, you may need to use zeroize::Zeroizing wrapper or manually zero the bytes.


259-259: Redundant .take(L) on fixed-size array.

The array io_pattern already has exactly L elements, so .take(L) is redundant.

-    for item in io_pattern.iter().take(L) {
+    for item in io_pattern.iter() {
📜 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 4af29b0 and a771860.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • Cargo.toml (1 hunks)
  • circuits/crates/libs/safe/Nargo.toml (1 hunks)
  • circuits/crates/libs/safe/src/lib.nr (4 hunks)
  • crates/safe/Cargo.toml (1 hunks)
  • crates/safe/src/lib.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 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:

  • Cargo.toml
  • crates/safe/Cargo.toml
📚 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:

  • circuits/crates/libs/safe/src/lib.nr
📚 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:

  • circuits/crates/libs/safe/src/lib.nr
📚 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:

  • circuits/crates/libs/safe/Nargo.toml
⏰ 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_sdk
  • GitHub Check: build_enclave_cli
  • GitHub Check: integration_prebuild
  • GitHub Check: test_contracts
  • GitHub Check: build_e3_support_dev
  • GitHub Check: test_net
  • GitHub Check: rust_integration
  • GitHub Check: crisp_rust_unit
  • GitHub Check: rust_unit
🔇 Additional comments (7)
Cargo.toml (1)

26-26: LGTM!

The new crates/safe workspace member is correctly added in alphabetical order, consistent with the existing member list.

circuits/crates/libs/safe/src/lib.nr (3)

292-305: Buffer overflow fix looks correct.

The serialization loop now properly uses the compile-time bound L with the runtime guard (i < word_count) & (byte_count + 4 <= 256). This correctly addresses the buffer overflow issue mentioned in the PR description while respecting Noir's compile-time loop constraint.


308-313: Domain separator bounds checking is correct.

The byte-by-byte appending with byte_count < 256 check prevents buffer overflow when the serialized IO pattern words consume most of the 256-byte buffer.


691-712: Good boundary test for large IO patterns.

This test validates the 256-byte buffer limit with 64 alternating ABSORB/SQUEEZE operations. The test correctly exercises the buffer overflow fix.

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

350-643: Comprehensive test coverage.

The tests thoroughly cover hashing, Merkle nodes, commitment schemes, domain separation, multiple squeezes, zero-length operations, tag computation, and consecutive operation aggregation. Good coverage of edge cases.

circuits/crates/libs/safe/Nargo.toml (1)

9-10: Dependency migration from SHA256 to Keccak256 is correct. Both keccak256 and poseidon at version v0.1.1 are available in their respective repositories and ready to use.

crates/safe/Cargo.toml (1)

14-14: The hex dependency is properly defined in the root workspace dependencies as hex = "=0.4.3". The configuration in crates/safe/Cargo.toml using workspace = true is correct and will not cause a build error.

Likely an incorrect or invalid review comment.

Comment thread circuits/crates/libs/safe/src/lib.nr Outdated
Comment thread crates/safe/src/lib.rs 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: 2

🧹 Nitpick comments (1)
crates/safe/src/lib.rs (1)

124-138: Consider taking &[Field] instead of Vec<Field> in absorb to avoid unnecessary cloning.

The docstring describes input as a “slice of field elements”, but the signature takes ownership of a Vec<Field>:

pub fn absorb(&mut self, input: Vec<Field>) {
    let length = input.len() as u32;
    ...
    for input in &input { ... }
}

Callers in this module have to clone their data (elements.clone(), values.clone(), etc.) just to satisfy the API, even though absorb only reads from the input. You can make this more flexible and allocation‑friendly by accepting a slice:

-    pub fn absorb(&mut self, input: Vec<Field>) {
-        let length = input.len() as u32;
+    pub fn absorb(&mut self, input: &[Field]) {
+        let length = input.len() as u32;
@@
-        for input in &input {
+        for input in input {

Call sites would then pass &elements / &values, avoiding extra allocations while matching the documentation wording.

📜 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 a771860 and 471176a.

📒 Files selected for processing (1)
  • crates/safe/src/lib.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 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/safe/src/lib.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build_enclave_cli
  • GitHub Check: build_sdk
  • GitHub Check: test_contracts
  • GitHub Check: integration_prebuild
  • GitHub Check: test_net
  • GitHub Check: rust_unit
  • GitHub Check: rust_integration
  • GitHub Check: crisp_rust_unit
🔇 Additional comments (1)
crates/safe/src/lib.rs (1)

350-643: Test coverage for SAFE + Keccak256 tag behavior looks strong.

The tests exercise:

  • Basic hashing and determinism (test_safe_hashing, test_merkle_node, test_commitment_scheme).
  • Domain separation influence (test_domain_separation).
  • Multiple squeezes and zero‑length operations.
  • Tag aggregation correctness for ABSORB and SQUEEZE runs, including mixed patterns.
  • A maximal‑size IO pattern hitting the former “word_count” / buffer edge case.

Given the core implementation changes, this level of coverage is solid and should catch most regressions around IO pattern handling and tag computation behavior.

Comment thread crates/safe/src/lib.rs
Comment thread crates/safe/src/lib.rs
@0xjei

0xjei commented Dec 4, 2025

Copy link
Copy Markdown
Contributor Author

ready @cedoor

cedoor
cedoor previously approved these changes Dec 4, 2025

@cedoor cedoor 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.

utACK

@vercel vercel Bot temporarily deployed to Preview – crisp December 4, 2025 15:38 Inactive
@vercel vercel Bot temporarily deployed to Preview – enclave-docs December 4, 2025 15:38 Inactive
@cedoor cedoor enabled auto-merge (squash) December 4, 2025 15:39
@cedoor cedoor self-requested a review December 4, 2025 15:39
cedoor
cedoor previously approved these changes Dec 4, 2025
@cedoor cedoor requested a review from ozgurarmanc December 4, 2025 15:44
ozgurarmanc
ozgurarmanc previously approved these changes Dec 4, 2025

@ozgurarmanc ozgurarmanc 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.

@cedoor Thanks for requesting review. I already reviewed the code today and couldn't catch anything. Nice job @0xjei !

@cedoor cedoor disabled auto-merge December 4, 2025 15:54
@cedoor cedoor enabled auto-merge (squash) December 4, 2025 16:05

@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

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

11-41: VK hash and VK points look consistent; please confirm they’re regenerated from the new circuit

The updated VK_HASH and all G1 points in loadVerificationKey() look like a fresh VK dump, and they are numerically consistent with the top‑level constants (N, LOG_N, NUMBER_OF_PUBLIC_INPUTS) and the BaseZKHonkVerifier constructor wiring.

Given these are opaque constants, the main risk is a mismatch between:

  • the Noir / Rust SAFE + Keccak circuit and proving key, and
  • this on‑chain verification key + VK_HASH domain separator.

Please double‑check that:

  • this VK was generated from the exact circuit/proving key that the SAFE/Keccak refactor now uses, and
  • VK_HASH is recomputed from the same preimage as whatever the off‑circuit tooling passes into proof generation.

If that’s already covered by your build scripts/tests (e.g. end‑to‑end proof verification against this contract), then this change looks good as‑is. Otherwise, consider adding a small regeneration/check script or CI step so future VK updates can’t drift silently.

Also applies to: 43-73, 75-89, 91-105, 107-121, 127-128

📜 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 a319f80 and ae85ffe.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • Cargo.toml (1 hunks)
  • circuits/crates/libs/safe/Nargo.toml (1 hunks)
  • circuits/crates/libs/safe/src/lib.nr (5 hunks)
  • crates/Dockerfile (1 hunks)
  • crates/safe/Cargo.toml (1 hunks)
  • crates/safe/src/lib.rs (1 hunks)
  • examples/CRISP/client/package.json (1 hunks)
  • examples/CRISP/packages/crisp-contracts/contracts/CRISPVerifier.sol (1 hunks)
  • examples/CRISP/packages/crisp-contracts/package.json (1 hunks)
  • examples/CRISP/packages/crisp-sdk/package.json (1 hunks)
  • examples/CRISP/packages/crisp-zk-inputs/package.json (1 hunks)
  • examples/CRISP/scripts/publish.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • examples/CRISP/client/package.json
  • examples/CRISP/packages/crisp-zk-inputs/package.json
  • examples/CRISP/scripts/publish.ts
  • circuits/crates/libs/safe/Nargo.toml
  • crates/Dockerfile
  • examples/CRISP/packages/crisp-sdk/package.json
🧰 Additional context used
🧠 Learnings (10)
📚 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/safe/Cargo.toml
  • 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:

  • circuits/crates/libs/safe/src/lib.nr
  • crates/safe/src/lib.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:

  • circuits/crates/libs/safe/src/lib.nr
  • crates/safe/src/lib.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:

  • circuits/crates/libs/safe/src/lib.nr
📚 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:

  • circuits/crates/libs/safe/src/lib.nr
📚 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/safe/src/lib.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/safe/src/lib.rs
📚 Learning: 2025-10-27T15:37:59.138Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 904
File: crates/net/src/bin/p2p_test.rs:22-45
Timestamp: 2025-10-27T15:37:59.138Z
Learning: In test files (especially integration test binaries like p2p_test.rs), suggesting correlation ID filtering for DHT events may be unnecessarily complex since test environments are typically more controlled and false positives are less of a concern.

Applied to files:

  • crates/safe/src/lib.rs
📚 Learning: 2024-10-08T19:45:18.209Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 133
File: packages/ciphernode/enclave/src/main.rs:5-18
Timestamp: 2024-10-08T19:45:18.209Z
Learning: Including the OWO ASCII art in `packages/ciphernode/enclave/src/main.rs` is acceptable, even if it increases the binary size.

Applied to files:

  • crates/safe/src/lib.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/safe/src/lib.rs
⏰ 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_sdk
  • GitHub Check: rust_integration
  • GitHub Check: build_enclave_cli
  • GitHub Check: crisp_unit
  • GitHub Check: test_net
  • GitHub Check: integration_prebuild
  • GitHub Check: build_ciphernode_image
  • GitHub Check: test_contracts
  • GitHub Check: rust_unit
🔇 Additional comments (15)
examples/CRISP/packages/crisp-contracts/package.json (1)

3-3: LGTM: Version bump aligns with new SAFE crate.

The patch version increment from 0.4.1 to 0.4.2 is appropriate for this PR's additions.

Cargo.toml (1)

26-26: LGTM: Workspace member addition is correct.

The new crates/safe member is properly integrated into the workspace and positioned alphabetically.

circuits/crates/libs/safe/src/lib.nr (4)

159-160: LGTM: IO pattern bounds check prevents index out of bounds.

The validation assert(self.io_count < L) correctly prevents accessing io_pattern[self.io_count] beyond array bounds and provides a clear error message.


290-322: LGTM: Buffer management correctly prevents domain separator truncation.

The fixed 256-byte buffer with explicit limits ensures:

  • Maximum 48 aggregated words (192 bytes) for IO patterns
  • Full 64-byte domain separator always included
  • Fail-fast assertion for oversized patterns

This addresses the previous domain separator truncation concern while working within Noir's fixed-size array constraints.


324-327: LGTM: Keccak-256 usage is correct and well-documented.

The switch to keccak256 with clarifying comments about the distinction from SHA3-256 ensures cross-implementation consistency between Noir and Rust.


701-762: LGTM: Excellent edge case coverage.

The new tests validate critical security properties:

  • test_large_io_pattern: Verifies 48-word limit works correctly
  • test_domain_separator_not_truncated: Regression test ensuring domain separators affect tags even at maximum pattern size

These directly test the fixes for the domain separator truncation issue.

crates/safe/src/lib.rs (8)

24-51: LGTM: Type definitions and constants are correct.

The BN254 field type and sponge parameters (RATE=3, CAPACITY=1) are properly defined and match the Noir implementation.


68-83: LGTM: SafeSponge struct correctly implements SAFE specification.

The structure properly tracks sponge state per SAFE spec 2.2, with all required fields for domain-separated operation.


95-112: LGTM: start method correctly initializes sponge state.

Tag computation and capacity initialization follow SAFE spec 2.4 exactly.


124-162: LGTM: absorb implementation follows SAFE spec correctly.

Proper validation, permutation handling, and state management per specification 2.4.


173-208: LGTM: squeeze implementation is correct and symmetric with absorb.

The IO pattern exhaustion check at Line 175 mirrors absorb's validation, providing consistent error handling.


218-227: LGTM: finish properly validates and clears state.

Completion check and state erasure follow SAFE spec 2.4 security requirements.


254-356: LGTM: compute_tag implementation is secure and correct.

The function properly:

  • Aggregates consecutive operations per SAFE spec 2.3
  • Uses fixed 256-byte buffer with 48-word limit
  • Always includes full 64-byte domain separator
  • Applies Keccak-256 and truncates to 128 bits

The implementation matches the Noir version and addresses previous domain separator truncation concerns.


358-717: LGTM: Excellent test coverage validates correctness and security.

The test suite comprehensively covers:

  • Basic functionality and determinism
  • Multiple operation patterns
  • Domain separation security
  • Edge cases (zero length, maximum size)
  • Regression tests for previous bugs
  • IO pattern exhaustion error handling

This provides high confidence in implementation correctness.

crates/safe/Cargo.toml (1)

9-14: Consider updating sha3 to a stable 0.11.x version when released.

The dependencies are generally current. However, sha3 is at 0.10.8 while version 0.11.0-rc.3 is available (released September 2025). The arkworks libraries (ark-ff, ark-bn254) are at stable 0.5.0 from October 2024, and taceo-poseidon2 is at 0.2.0 from November 2025. When sha3 0.11.x reaches stable release, plan an upgrade to ensure access to the latest cryptographic improvements.

@cedoor cedoor merged commit 8dec370 into main Dec 4, 2025
25 checks passed
@github-actions github-actions Bot deleted the feat/safe-rust branch December 12, 2025 02:52
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.

Create Rust crate for Safe + Poseidon2 hashing off-circuit

3 participants