Skip to content

feat: link c4 and c6#1492

Merged
0xjei merged 5 commits into
mainfrom
feat/link-c4-c6
Mar 30, 2026
Merged

feat: link c4 and c6#1492
0xjei merged 5 commits into
mainfrom
feat/link-c4-c6

Conversation

@ctrlc03

@ctrlc03 ctrlc03 commented Mar 28, 2026

Copy link
Copy Markdown
Collaborator

fix #1451

Summary by CodeRabbit

  • New Features

    • Added public-input extraction for proofs and two new cross-circuit commitment verification links.
  • Bug Fixes

    • Refined proof-type classification and tightened consistency checks for malformed or short signaling data.
    • Improved aggregation logging to show additional buffer and fold metrics.
  • Refactor

    • Updated commitment-link registration and cleaned up related naming and imports.

@vercel

vercel Bot commented Mar 28, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
crisp Ready Ready Preview, Comment Mar 30, 2026 10:20am
enclave-docs Ready Ready Preview, Comment Mar 30, 2026 10:20am

Request Review

@coderabbitai

coderabbitai Bot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Splits C4 into C4a/C4b, adds public-input extraction APIs, and implements two cross-circuit commitment-consistency links (C4a→C6 and C4b→C6). Enums, proof signing sites, link registry, tests, and small aggregator/logging tweaks updated accordingly.

Changes

Cohort / File(s) Summary
Proof types & extraction
crates/events/src/enclave_event/signed_proof.rs, crates/events/src/enclave_event/proof.rs
Split C4DkgShareDecryptionC4aSkShareDecryption + C4bESmShareDecryption, renumbered discriminants, updated circuit mappings; added Proof::extract_input and CircuitName::input_layout.
Input layout & constants
crates/zk-helpers/src/circuits/output_layout.rs
Added CircuitInputLayout enum with extract_field and new public input field constants SHARE_ENCRYPTION_INPUTS and THRESHOLD_SHARE_DECRYPTION_INPUTS.
New commitment links
crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs, crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs
Added C4aToC6SkCommitmentLink and C4bToC6ESmCommitmentLink implementing CommitmentLink; extract commitment from C4 outputs and compare with C6 inputs; includes unit tests.
Links registry & existing link tweak
crates/zk-prover/src/actors/commitment_links/mod.rs, crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
Exported new modules, extended default_links() to register the new links; normalized C1→C5 name arrow and changed empty-source consistency behavior.
Proof signing & aggregator logging
crates/zk-prover/src/actors/proof_request.rs, crates/zk-prover/src/actors/node_proof_aggregator.rs
Updated signing sites to use new C4a/C4b variants; aggregator logging now reports buffered and folded counts.

Sequence Diagram(s)

sequenceDiagram
    participant Verifier
    participant C4a as C4a (SK)
    participant C4b as C4b (ESm)
    participant C6 as C6 (Threshold)
    participant Cache as Per-Party Cache

    Verifier->>C4a: verify C4a proof
    C4a-->>Verifier: public_signals (commitment)
    Verifier->>Cache: store C4a commitment

    Verifier->>C4b: verify C4b proof(s)
    C4b-->>Verifier: public_signals (commitment)
    Verifier->>Cache: store C4b commitment(s)

    Verifier->>C6: verify C6 proof
    C6-->>Verifier: public_signals (expected_sk_commitment, expected_e_sm_commitment)

    Verifier->>Cache: retrieve C4a commitment
    Verifier->>Verifier: compare C6.expected_sk_commitment == cached C4a
    alt match
        Verifier->>Verifier: SK consistency passes
    else mismatch
        Verifier->>Verifier: mark sender dishonest
    end

    Verifier->>Cache: retrieve C4b commitments
    Verifier->>Verifier: compare C6.expected_e_sm_commitment == cached C4b
    alt match
        Verifier->>Verifier: ESm consistency passes
    else mismatch
        Verifier->>Verifier: mark sender dishonest
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

ciphernode

Suggested reviewers

  • hmzakhalid
  • ctrlc03

"I hopped through circuits, byte by byte,
Split one proof into two and set links right.
I cached commitments with a careful tap,
Then matched them in C6 — a rhythmic clap.
Hop hooray, the proofs align — happy rabbit night!" 🐰

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.34% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive Changes partially address issue #1451: new commitment links validate C4→C6 consistency, but cross-circuit caching per party and dishonest sender marking are not demonstrated in provided code. Verify that per-party C4 commitment caching and dishonest sender marking logic exist in NodeProofAggregator or related verification handlers not shown in this PR summary.
Out of Scope Changes check ❓ Inconclusive Most changes are scoped to linking C4 and C6; however, updates to c1_to_c5.rs (name format, consistency check behavior) appear tangential to the C4→C6 linking objective. Clarify whether c1_to_c5.rs changes are dependencies for C4→C6 linking or separate refactoring; if unrelated, move to a dedicated PR.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title 'feat: link c4 and c6' is concise and directly summarizes the primary change of linking C4 and C6 proofs through commitment verification logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/link-c4-c6

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

🧹 Nitpick comments (3)
crates/zk-prover/src/actors/commitment_links/c0_to_c3.rs (1)

53-56: Consider documenting the vacuous consistency behavior.

Returning true when source_values is empty aligns with the trait contract (nothing to check → vacuously consistent). However, this means that if C0 extraction fails (e.g., malformed proof, too-short signals), the consistency check will pass silently.

Ensure the calling code handles extraction failures separately before invoking check_consistency, or add a brief doc comment here noting this expectation. Based on context snippet 1, the trait leaves this decision to implementations, which is fine—just worth documenting.

📝 Optional: Add doc comment
 /// C3 has no outputs (`CircuitOutputLayout::None`), so all public_signals are
 /// inputs. The layout is `[expected_pk_commitment, expected_message_commitment]`,
 /// making `expected_pk_commitment` the first 32 bytes.
+///
+/// Returns `true` (vacuously consistent) if `source_values` is empty; callers
+/// should verify extraction succeeded before relying on this result.
 fn check_c3_pk_commitment(source_values: &[FieldValue], target_public_signals: &[u8]) -> bool {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/zk-prover/src/actors/commitment_links/c0_to_c3.rs` around lines 53 -
56, Add a brief doc comment above the function check_c3_pk_commitment
documenting that it returns true when source_values is empty (vacuous
consistency) and that extraction/validation of C0 must be performed by the
caller before invoking check_c3_pk_commitment; state that this function assumes
valid, non-empty source_values represent extracted C0 data and does not itself
treat extraction failures or malformed/too-short signals.
crates/zk-helpers/src/circuits/output_layout.rs (1)

143-151: Consider adding unit tests for CircuitInputLayout::extract_field.

While CircuitOutputLayout has comprehensive tests (lines 181-316), the new CircuitInputLayout lacks dedicated tests. Adding tests would validate the head-extraction logic and catch any off-by-one issues.

📝 Example test to add
#[test]
fn extract_input_field_from_head() {
    let layout = CircuitInputLayout::Fixed {
        fields: THRESHOLD_SHARE_DECRYPTION_INPUTS,
    };
    // 2 inputs + some output bytes
    let mut signals = vec![0xAAu8; 96];
    signals[0..32].copy_from_slice(&[0x11; 32]); // expected_sk_commitment
    signals[32..64].copy_from_slice(&[0x22; 32]); // expected_e_sm_commitment
    
    assert_eq!(
        layout.extract_field(&signals, "expected_sk_commitment").unwrap(),
        &[0x11; 32]
    );
    assert_eq!(
        layout.extract_field(&signals, "expected_e_sm_commitment").unwrap(),
        &[0x22; 32]
    );
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/zk-helpers/src/circuits/output_layout.rs` around lines 143 - 151, The
new CircuitInputLayout::extract_field logic currently has no unit tests — add
tests mirroring the existing CircuitOutputLayout tests to validate head
extraction and catch off-by-one errors: create a Fixed CircuitInputLayout using
THRESHOLD_SHARE_DECRYPTION_INPUTS (or SHARE_ENCRYPTION_INPUTS), build a signals
Vec with known 32-byte chunks at the head, then call
layout.extract_field(&signals, "<field_name>") for each field and assert the
returned slice matches the expected bytes; include cases for multiple fields and
out-of-range/missing names to ensure error paths are covered.
crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs (1)

16-58: Consider extracting shared logic between C4a and C4b links.

C4aToC6SkCommitmentLink and C4bToC6ESmCommitmentLink share nearly identical structure — only the link name and target field name differ. A parameterized helper or macro could reduce duplication.

♻️ Optional: Shared implementation approach
// In mod.rs or a shared module:
struct C4ToC6Link {
    name: &'static str,
    source_proof_type: ProofType,
    target_field: &'static str,
}

impl CommitmentLink for C4ToC6Link {
    fn name(&self) -> &'static str { self.name }
    fn source_proof_type(&self) -> ProofType { self.source_proof_type }
    fn target_proof_type(&self) -> ProofType { ProofType::C6ThresholdShareDecryption }
    fn scope(&self) -> LinkScope { LinkScope::SameParty }
    
    fn extract_source_values(&self, public_signals: &[u8]) -> Vec<FieldValue> {
        // Shared extraction logic
    }
    
    fn check_consistency(&self, source_values: &[FieldValue], target_public_signals: &[u8]) -> bool {
        // Use self.target_field for extraction
    }
}

// Then instantiate:
pub const C4A_TO_C6: C4ToC6Link = C4ToC6Link {
    name: "C4a->C6 sk_commitment",
    source_proof_type: ProofType::C4aSkShareDecryption,
    target_field: "expected_sk_commitment",
};

This is optional since the current approach is clear and the duplication is limited to two files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs` around lines 16 -
58, The two structs C4aToC6SkCommitmentLink and C4bToC6ESmCommitmentLink share
almost identical CommitmentLink impls; extract the common logic into a
parameterized helper type (e.g., a C4ToC6Link struct with fields name: &'static
str, source_proof_type: ProofType, target_field: &'static str) and implement
CommitmentLink for it using shared extract_source_values and check_consistency
logic that reads target_field; then replace the concrete structs with
constants/instances of C4ToC6Link (setting name, source_proof_type to
ProofType::C4aSkShareDecryption or ProofType::C4bESmShareDecryption, and
target_field to "expected_sk_commitment" or "expected_e_sm_commitment").
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/events/src/enclave_event/signed_proof.rs`:
- Around line 42-51: The enum discriminants in ProofType (variants
C4aSkShareDecryption, C4bESmShareDecryption, C6ThresholdShareDecryption,
C7DecryptedSharesAggregation, C5PkAggregation) changed numeric values and will
corrupt bincode-deserialized events (ProofVerificationPassed,
ProofVerificationFailed, ProofFailureAccusation) stored in sled; fix by either
restoring stable discriminant values on ProofType to match previous numeric
mapping or implement a startup migration that reads stored event blobs, detects
old discriminant numbers and rewrites them to the new discriminants before
normal deserialization; locate ProofType and the event
serialization/deserialization code paths and add the migration routine or apply
serde versioning/aliasing so old discriminants map to the correct variants.

In `@crates/zk-prover/src/actors/node_proof_aggregator.rs`:
- Line 146: The calculation of folded using let folded = state.total_expected -
state.remaining - buffered can underflow; change the computation in
node_proof_aggregator.rs to do safe arithmetic (e.g., compute sum =
state.remaining.saturating_add(buffered) or checked_add, then folded =
state.total_expected.saturating_sub(sum) or use checked_sub with a fallback) so
folded never underflows — update the logic around the folded variable to use
saturating/checked ops on state.total_expected, state.remaining, and buffered.

---

Nitpick comments:
In `@crates/zk-helpers/src/circuits/output_layout.rs`:
- Around line 143-151: The new CircuitInputLayout::extract_field logic currently
has no unit tests — add tests mirroring the existing CircuitOutputLayout tests
to validate head extraction and catch off-by-one errors: create a Fixed
CircuitInputLayout using THRESHOLD_SHARE_DECRYPTION_INPUTS (or
SHARE_ENCRYPTION_INPUTS), build a signals Vec with known 32-byte chunks at the
head, then call layout.extract_field(&signals, "<field_name>") for each field
and assert the returned slice matches the expected bytes; include cases for
multiple fields and out-of-range/missing names to ensure error paths are
covered.

In `@crates/zk-prover/src/actors/commitment_links/c0_to_c3.rs`:
- Around line 53-56: Add a brief doc comment above the function
check_c3_pk_commitment documenting that it returns true when source_values is
empty (vacuous consistency) and that extraction/validation of C0 must be
performed by the caller before invoking check_c3_pk_commitment; state that this
function assumes valid, non-empty source_values represent extracted C0 data and
does not itself treat extraction failures or malformed/too-short signals.

In `@crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs`:
- Around line 16-58: The two structs C4aToC6SkCommitmentLink and
C4bToC6ESmCommitmentLink share almost identical CommitmentLink impls; extract
the common logic into a parameterized helper type (e.g., a C4ToC6Link struct
with fields name: &'static str, source_proof_type: ProofType, target_field:
&'static str) and implement CommitmentLink for it using shared
extract_source_values and check_consistency logic that reads target_field; then
replace the concrete structs with constants/instances of C4ToC6Link (setting
name, source_proof_type to ProofType::C4aSkShareDecryption or
ProofType::C4bESmShareDecryption, and target_field to "expected_sk_commitment"
or "expected_e_sm_commitment").
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0e7163e6-e6f7-4e50-a852-364b376d0b90

📥 Commits

Reviewing files that changed from the base of the PR and between a8c3fc8 and c8923dd.

📒 Files selected for processing (10)
  • crates/events/src/enclave_event/proof.rs
  • crates/events/src/enclave_event/signed_proof.rs
  • crates/zk-helpers/src/circuits/output_layout.rs
  • crates/zk-prover/src/actors/commitment_links/c0_to_c3.rs
  • crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
  • crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/mod.rs
  • crates/zk-prover/src/actors/node_proof_aggregator.rs
  • crates/zk-prover/src/actors/proof_request.rs

Comment thread crates/events/src/enclave_event/signed_proof.rs Outdated
Comment thread crates/zk-prover/src/actors/node_proof_aggregator.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: 1

🧹 Nitpick comments (1)
crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs (1)

35-43: Consider defensive length check before copy_from_slice.

copy_from_slice will panic if bytes.len() != FIELD_BYTE_LEN. While the layout extraction should return correct sizes, a defensive check would prevent panics if layout definitions change or have bugs.

♻️ Suggested defensive check
     fn extract_source_values(&self, public_signals: &[u8]) -> Vec<FieldValue> {
         let layout = CircuitName::DkgShareDecryption.output_layout();
         let Some(bytes) = layout.extract_field(public_signals, "commitment") else {
             return vec![];
         };
+        if bytes.len() != FIELD_BYTE_LEN {
+            return vec![];
+        }
         let mut value = [0u8; FIELD_BYTE_LEN];
         value.copy_from_slice(bytes);
         vec![value]
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs` around lines 35 -
43, The extract_source_values function can panic on value.copy_from_slice(bytes)
if bytes.len() != FIELD_BYTE_LEN; add a defensive length check after obtaining
bytes from layout.extract_field
(CircuitName::DkgShareDecryption.output_layout()) to verify bytes.len() ==
FIELD_BYTE_LEN and, on mismatch, return an empty Vec<FieldValue> (or otherwise
handle the error consistently with surrounding code) instead of calling
copy_from_slice; keep references to FIELD_BYTE_LEN and the copy_from_slice call
when implementing the guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs`:
- Around line 45-57: Add a doc comment to the function check_consistency in
c4b_to_c6.rs explaining the intentional behavior: it returns true when
source_values is empty or when extract_field cannot find
"expected_e_sm_commitment" because the system tolerates incomplete/asynchronous
proof arrival (e.g., C6 before C4b) and consistency checks are deferred rather
than treated as failures; reference the
CircuitName::ThresholdShareDecryption.input_layout and the use of
layout.extract_field(target_public_signals, "expected_e_sm_commitment") so
future readers understand the design assumption and where this behavior
originates.

---

Nitpick comments:
In `@crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs`:
- Around line 35-43: The extract_source_values function can panic on
value.copy_from_slice(bytes) if bytes.len() != FIELD_BYTE_LEN; add a defensive
length check after obtaining bytes from layout.extract_field
(CircuitName::DkgShareDecryption.output_layout()) to verify bytes.len() ==
FIELD_BYTE_LEN and, on mismatch, return an empty Vec<FieldValue> (or otherwise
handle the error consistently with surrounding code) instead of calling
copy_from_slice; keep references to FIELD_BYTE_LEN and the copy_from_slice call
when implementing the guard.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f02df87e-0168-4905-bc64-f34a305990e0

📥 Commits

Reviewing files that changed from the base of the PR and between c8923dd and f281bc1.

📒 Files selected for processing (9)
  • crates/events/src/enclave_event/proof.rs
  • crates/events/src/enclave_event/signed_proof.rs
  • crates/zk-helpers/src/circuits/output_layout.rs
  • crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
  • crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/mod.rs
  • crates/zk-prover/src/actors/node_proof_aggregator.rs
  • crates/zk-prover/src/actors/proof_request.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/zk-prover/src/actors/node_proof_aggregator.rs
  • crates/events/src/enclave_event/signed_proof.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • crates/zk-prover/src/actors/proof_request.rs
  • crates/zk-helpers/src/circuits/output_layout.rs
  • crates/zk-prover/src/actors/commitment_links/mod.rs
  • crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
  • crates/events/src/enclave_event/proof.rs
  • crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs

Comment thread crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs
@0xjei 0xjei self-requested a review March 30, 2026 08:51

@0xjei 0xjei 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, I really liked the design; can you just double-check my comments? I think we are 98% done here! good job

Comment thread crates/events/src/enclave_event/proof.rs Outdated
Comment thread crates/events/src/enclave_event/signed_proof.rs Outdated
Comment thread crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
Comment thread crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
Comment thread crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
Comment thread crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
Comment thread crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs

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

🧹 Nitpick comments (1)
crates/zk-helpers/src/circuits/output_layout.rs (1)

143-147: Consider adding unit tests for CircuitInputLayout extraction.

CircuitOutputLayout has thorough test coverage (lines 181-316), but the new CircuitInputLayout::extract_field method lacks dedicated tests in this file. While it's exercised via the commitment link tests, adding direct unit tests here would improve coverage and documentation.

📝 Example test structure
#[test]
fn extract_input_field_from_head() {
    let layout = CircuitInputLayout::Fixed {
        fields: THRESHOLD_SHARE_DECRYPTION_INPUTS,
    };
    // C6 has 2 inputs at head + outputs at tail
    let mut signals = vec![0u8; 96]; // 2 inputs + 1 output
    signals[0..32].copy_from_slice(&[0x11; 32]); // expected_sk_commitment
    signals[32..64].copy_from_slice(&[0x22; 32]); // expected_e_sm_commitment
    
    assert_eq!(
        layout.extract_field(&signals, "expected_sk_commitment").unwrap(),
        &[0x11; 32]
    );
    assert_eq!(
        layout.extract_field(&signals, "expected_e_sm_commitment").unwrap(),
        &[0x22; 32]
    );
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/zk-helpers/src/circuits/output_layout.rs` around lines 143 - 147, Add
direct unit tests for CircuitInputLayout::extract_field to mirror the
CircuitOutputLayout coverage: create tests that instantiate
CircuitInputLayout::Fixed (using THRESHOLD_SHARE_DECRYPTION_INPUTS) and any
Variable/Head/Tail variants used by your code, construct a signals Vec<u8> with
appropriate lengths (e.g., 32-byte field chunks), populate head and tail regions
with distinct byte patterns, call layout.extract_field(&signals, "field_name")
for each expected field (e.g., "expected_sk_commitment",
"expected_e_sm_commitment") and assert the returned slice equals the bytes you
set; include cases for head fields, tail fields, and error paths (missing field)
to fully exercise CircuitInputLayout::extract_field.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/zk-helpers/src/circuits/output_layout.rs`:
- Around line 143-147: Add direct unit tests for
CircuitInputLayout::extract_field to mirror the CircuitOutputLayout coverage:
create tests that instantiate CircuitInputLayout::Fixed (using
THRESHOLD_SHARE_DECRYPTION_INPUTS) and any Variable/Head/Tail variants used by
your code, construct a signals Vec<u8> with appropriate lengths (e.g., 32-byte
field chunks), populate head and tail regions with distinct byte patterns, call
layout.extract_field(&signals, "field_name") for each expected field (e.g.,
"expected_sk_commitment", "expected_e_sm_commitment") and assert the returned
slice equals the bytes you set; include cases for head fields, tail fields, and
error paths (missing field) to fully exercise CircuitInputLayout::extract_field.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 31fb9338-98ca-4b13-aa34-101e0c37163c

📥 Commits

Reviewing files that changed from the base of the PR and between f281bc1 and 35360db.

📒 Files selected for processing (9)
  • crates/events/src/enclave_event/proof.rs
  • crates/events/src/enclave_event/signed_proof.rs
  • crates/zk-helpers/src/circuits/output_layout.rs
  • crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
  • crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/mod.rs
  • crates/zk-prover/src/actors/node_proof_aggregator.rs
  • crates/zk-prover/src/actors/proof_request.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • crates/zk-prover/src/actors/node_proof_aggregator.rs
  • crates/zk-prover/src/actors/commitment_links/mod.rs
  • crates/zk-prover/src/actors/proof_request.rs
  • crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
  • crates/events/src/enclave_event/proof.rs

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

🧹 Nitpick comments (1)
crates/zk-helpers/src/circuits/output_layout.rs (1)

113-141: LGTM! Consider adding unit tests for CircuitInputLayout::extract_field.

The CircuitInputLayout enum correctly mirrors CircuitOutputLayout but extracts from the HEAD of public_signals instead of the TAIL. The byte offset calculation (idx * FIELD_BYTE_LEN) and bounds checking are correct.

However, while CircuitOutputLayout has comprehensive test coverage (lines 181-316), CircuitInputLayout::extract_field lacks corresponding tests.

🧪 Suggested test additions
#[test]
fn extract_input_field_from_head() {
    let layout = CircuitInputLayout::Fixed {
        fields: THRESHOLD_SHARE_DECRYPTION_INPUTS,
    };
    // C6 inputs: [expected_sk_commitment, expected_e_sm_commitment] + outputs
    let mut signals = vec![0u8; 96]; // 2 inputs + 1 output
    signals[0..32].copy_from_slice(&[0x11; 32]); // expected_sk_commitment
    signals[32..64].copy_from_slice(&[0x22; 32]); // expected_e_sm_commitment

    assert_eq!(
        layout.extract_field(&signals, "expected_sk_commitment").unwrap(),
        &[0x11; 32]
    );
    assert_eq!(
        layout.extract_field(&signals, "expected_e_sm_commitment").unwrap(),
        &[0x22; 32]
    );
}

#[test]
fn input_layout_none_returns_none() {
    let layout = CircuitInputLayout::None;
    let signals = vec![0u8; 64];
    assert!(layout.extract_field(&signals, "anything").is_none());
}

#[test]
fn input_signals_too_short_returns_none() {
    let layout = CircuitInputLayout::Fixed {
        fields: THRESHOLD_SHARE_DECRYPTION_INPUTS,
    };
    // Need 64 bytes for 2 inputs, only 32 available
    let signals = vec![0u8; 32];
    assert!(layout.extract_field(&signals, "expected_e_sm_commitment").is_none());
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/zk-helpers/src/circuits/output_layout.rs` around lines 113 - 141, Add
unit tests for CircuitInputLayout::extract_field to mirror the existing
CircuitOutputLayout coverage: create tests named extract_input_field_from_head
(build a Fixed layout using THRESHOLD_SHARE_DECRYPTION_INPUTS, populate a
signals vec with two FIELD_BYTE_LEN fields at the head and assert extracted
slices for "expected_sk_commitment" and "expected_e_sm_commitment" match),
input_layout_none_returns_none (use CircuitInputLayout::None and assert
extract_field returns None), and input_signals_too_short_returns_none (use Fixed
layout but provide a signals vec shorter than the required idx*FIELD_BYTE_LEN +
FIELD_BYTE_LEN and assert extract_field returns None); ensure tests reference
CircuitInputLayout, CircuitInputLayout::extract_field,
THRESHOLD_SHARE_DECRYPTION_INPUTS, and FIELD_BYTE_LEN so they catch regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/zk-helpers/src/circuits/output_layout.rs`:
- Around line 113-141: Add unit tests for CircuitInputLayout::extract_field to
mirror the existing CircuitOutputLayout coverage: create tests named
extract_input_field_from_head (build a Fixed layout using
THRESHOLD_SHARE_DECRYPTION_INPUTS, populate a signals vec with two
FIELD_BYTE_LEN fields at the head and assert extracted slices for
"expected_sk_commitment" and "expected_e_sm_commitment" match),
input_layout_none_returns_none (use CircuitInputLayout::None and assert
extract_field returns None), and input_signals_too_short_returns_none (use Fixed
layout but provide a signals vec shorter than the required idx*FIELD_BYTE_LEN +
FIELD_BYTE_LEN and assert extract_field returns None); ensure tests reference
CircuitInputLayout, CircuitInputLayout::extract_field,
THRESHOLD_SHARE_DECRYPTION_INPUTS, and FIELD_BYTE_LEN so they catch regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 159cbf20-8b4e-4808-a503-3d84755648ad

📥 Commits

Reviewing files that changed from the base of the PR and between 35360db and 6967068.

📒 Files selected for processing (9)
  • crates/events/src/enclave_event/proof.rs
  • crates/events/src/enclave_event/signed_proof.rs
  • crates/zk-helpers/src/circuits/output_layout.rs
  • crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs
  • crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/c4b_to_c6.rs
  • crates/zk-prover/src/actors/commitment_links/mod.rs
  • crates/zk-prover/src/actors/node_proof_aggregator.rs
  • crates/zk-prover/src/actors/proof_request.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/zk-prover/src/actors/node_proof_aggregator.rs
  • crates/zk-prover/src/actors/commitment_links/c4a_to_c6.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/zk-prover/src/actors/proof_request.rs
  • crates/events/src/enclave_event/proof.rs
  • crates/zk-prover/src/actors/commitment_links/c1_to_c5.rs

@0xjei 0xjei merged commit 07574da into main Mar 30, 2026
33 checks passed
@github-actions github-actions Bot deleted the feat/link-c4-c6 branch April 7, 2026 03:21
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.

Cross-circuit check: C4→C6 — verify C6 expected_sk/e_sm_commitment match C4 return values

2 participants