Skip to content

chore: pre check decrypted shares match c6 inputs#1500

Merged
ctrlc03 merged 5 commits intomainfrom
chore/pre-c7-check-ag
Apr 3, 2026
Merged

chore: pre check decrypted shares match c6 inputs#1500
ctrlc03 merged 5 commits intomainfrom
chore/pre-c7-check-ag

Conversation

@ctrlc03
Copy link
Copy Markdown
Collaborator

@ctrlc03 ctrlc03 commented Mar 30, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Stronger verification now removes and logs mismatched decryption shares so only validated shares are aggregated.
  • Chores

    • Added workspace dependencies to support polynomial and cryptographic operations.
    • Broadened internal handling to accept polynomial inputs in any representation.
  • Tests

    • Added a unit test for commitment computation and reduced an integration test timeout.

@ctrlc03 ctrlc03 requested review from 0xjei and cedoor March 30, 2026 17:27
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

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

Project Deployment Actions Updated (UTC)
crisp Ready Ready Preview, Comment Apr 3, 2026 9:59am
enclave-docs Ready Ready Preview, Comment Apr 3, 2026 9:59am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds per-party runtime verification that recomputes threshold-decryption share commitments from raw share bytes and compares them to C6 proof outputs; expands aggregator crate dependencies; broadens polynomial representation handling; adds a unit test for commitment computation; tweaks a small comment and shortens an integration test timeout.

Changes

Cohort / File(s) Summary
Aggregator verification
crates/aggregator/src/threshold_plaintext_aggregator.rs
Adds per-honest-party recomputation of d_commitment from share bytes (deserialize Poly, CRT reverse + centering, recompute commitment) and comparison to C6 proof public outputs; mismatched parties are marked dishonest/removed; adds verify_shares_match_c6_commitments and related imports/logging.
Aggregator dependencies
crates/aggregator/Cargo.toml
Adds workspace-managed dependencies: e3-polynomial, fhe-math, and num-bigint.
Polynomial conversion
crates/polynomial/src/crt_polynomial.rs
CrtPolynomial::from_fhe_polynomial now converts any non-PowerBasis fhe_math::rq::Poly to PowerBasis before building CRT limbs (accepts representations like NttShoup).
ZK helpers tests
crates/zk-helpers/src/circuits/threshold/share_decryption/computation.rs
Adds unit test test_d_commitment_matches_inputs_compute asserting computed d matches Inputs::compute(...).d, verifies CRT reverse+center variant, and checks Poly serialization round-trip preserves commitment computation.
Minor comment
crates/multithread/src/multithread.rs
Incremented an inline step-number comment from “4. Return response” to “5. Return response” (no logic change).
Integration test timeout
templates/default/tests/integration.spec.ts
Reduces duration constant from 500 to 450, affecting inputWindow and timeoutMs used for event waits.

Sequence Diagram(s)

sequenceDiagram
    participant Aggregator as Aggregator
    participant Party as PartyShare
    participant C6 as C6ProofStore
    participant BFV as BFVContext

    Aggregator->>Party: collect verified honest_shares (bytes + proof refs)
    loop per honest party
        Aggregator->>C6: extract d_commitment from C6 public outputs
        Aggregator->>BFV: build BFV params/context (moduli, d_bit)
        BFV-->>Aggregator: params/context
        Aggregator->>Party: deserialize share bytes -> Poly
        Aggregator->>Aggregator: Poly.reverse() + center(moduli) -> CRT poly
        Aggregator->>Aggregator: compute threshold decryption share commitment (d)
        Aggregator->>C6: compare computed d to extracted d_commitment
        alt mismatch
            Aggregator->>Aggregator: mark party dishonest, remove from honest_shares
        end
    end
    Aggregator->>Aggregator: ensure honest_shares.len() > threshold -> proceed or abort
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • 0xjei
  • cedoor

Poem

"I hopped through bytes with whiskers bright,
recomputing d by moonlit byte.
If commitments match, I give a cheer,
if not, I thump and stamp with ear.
Verified and snug — carrot tonight!" 🐇

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding a pre-check to verify that decrypted shares match C6 inputs, which is the primary functional addition across the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 chore/pre-c7-check-ag

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/aggregator/src/threshold_plaintext_aggregator.rs`:
- Around line 353-370: The code uses signed.recover_address() to decide who to
slash and publishes SignedProofFailed (with
ProofType::C6ThresholdShareDecryption) even though the SignedProofPayload
wrapper signature hasn't been verified or bound to the broadcaster, which allows
a malicious sender to blame an honest signer; change the logic in the loop over
state.c6_proofs so you only publish SignedProofFailed when the wrapper identity
is verified/bound to the committee sender (e.g., call verify_address() or
otherwise confirm the SignedProofPayload maps to the broadcaster or that
prover.verify() has validated the wrapper) — still exclude the mismatched share
locally, but gate calls to self.bus.publish(SignedProofFailed { ...
signed_payload: signed.clone() ... }) on a successful wrapper verification (and
keep using recover_address() only for logging when wrapper unverified).
🪄 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: 47e3ca38-2db4-4123-814b-3aa6ea32dc81

📥 Commits

Reviewing files that changed from the base of the PR and between 66780fa and bab67a8.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/threshold_plaintext_aggregator.rs
  • crates/multithread/src/multithread.rs

Comment thread crates/aggregator/src/threshold_plaintext_aggregator.rs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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/aggregator/src/threshold_plaintext_aggregator.rs (1)

488-490: Remove duplicated doc sentence fragment.

The first line is repeated/incomplete and can be collapsed into one clear summary line.

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

In `@crates/aggregator/src/threshold_plaintext_aggregator.rs` around lines 488 -
490, The doc comment contains a duplicated/incomplete first line; collapse them
into a single clear summary sentence that reads something like: "Verify that
each honest party's raw decryption share bytes deserialize and match the
`d_commitment` output in their verified C6 proof, returning the party IDs..."
Edit the comment above the relevant function (reference `d_commitment` and the
C6 proof verification in this file) to remove the repeated fragment and keep one
concise summary line.
🤖 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/aggregator/src/threshold_plaintext_aggregator.rs`:
- Around line 499-563: Several pre-check branches skip or continue without
marking the party as mismatched (so bad/missing data can still be treated as
honest); for each failing branch in the loop over (party_id, shares) —
specifically the None cases from c6_proofs.get(party_id), proofs.first(),
shares.first(), the missing d_commitment extract via
c6_output_layout.extract_field, and the Err case from crt.center(&moduli) — add
mismatched.insert(*party_id) before continuing (or return mismatched if the code
path earlier uses an early return like build_pair_for_preset), so failures in
e3_fhe_params::build_pair_for_preset, threshold_params.ctx_at_level(0),
c6_proofs.get, proofs.first, c6_output_layout.extract_field,
try_poly_from_bytes, and crt.center all mark the party via
mismatched.insert(*party_id) instead of silently continuing.

---

Nitpick comments:
In `@crates/aggregator/src/threshold_plaintext_aggregator.rs`:
- Around line 488-490: The doc comment contains a duplicated/incomplete first
line; collapse them into a single clear summary sentence that reads something
like: "Verify that each honest party's raw decryption share bytes deserialize
and match the `d_commitment` output in their verified C6 proof, returning the
party IDs..." Edit the comment above the relevant function (reference
`d_commitment` and the C6 proof verification in this file) to remove the
repeated fragment and keep one concise summary line.
🪄 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: b786bb3e-d42f-4120-bc83-959093076df3

📥 Commits

Reviewing files that changed from the base of the PR and between bab67a8 and 5205da6.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/threshold_plaintext_aggregator.rs
  • crates/multithread/src/multithread.rs
  • crates/polynomial/src/crt_polynomial.rs
  • crates/zk-helpers/src/circuits/threshold/share_decryption/computation.rs
  • templates/default/tests/integration.spec.ts
✅ Files skipped from review due to trivial changes (2)
  • crates/aggregator/Cargo.toml
  • crates/multithread/src/multithread.rs

Comment thread crates/aggregator/src/threshold_plaintext_aggregator.rs
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/aggregator/src/threshold_plaintext_aggregator.rs (1)

17-19: Unused imports detected.

ProofType, SignedProofFailed, and the error macro are imported but not used anywhere in this file. Consider removing them unless they're planned for immediate use.

🧹 Suggested cleanup
 use e3_events::{
-    prelude::*, trap, AggregationProofPending, AggregationProofSigned, BusHandle, CircuitName,
+    prelude::*, trap, AggregationProofPending, AggregationProofSigned, BusHandle, CircuitName,
     CommitteeMemberExpelled, ComputeRequest, ComputeResponse, ComputeResponseKind, CorrelationId,
-    DecryptedSharesAggregationProofRequest, DecryptionshareCreated, Die, E3id, EType, EnclaveEvent,
-    EnclaveEventData, EventContext, PartyProofsToVerify, PlaintextAggregated, Proof, ProofType,
-    Seed, Sequenced, ShareVerificationComplete, ShareVerificationDispatched, SignedProofFailed,
-    SignedProofPayload, TypedEvent, VerificationKind, ZkResponse,
+    DecryptedSharesAggregationProofRequest, DecryptionshareCreated, Die, E3id, EType, EnclaveEvent,
+    EnclaveEventData, EventContext, PartyProofsToVerify, PlaintextAggregated, Proof,
+    Seed, Sequenced, ShareVerificationComplete, ShareVerificationDispatched,
+    SignedProofPayload, TypedEvent, VerificationKind, ZkResponse,
 };
-use tracing::{debug, error, info, trace, warn};
+use tracing::{debug, info, trace, warn};

Also applies to: 30-30

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

In `@crates/aggregator/src/threshold_plaintext_aggregator.rs` around lines 17 -
19, The import list contains unused symbols—remove ProofType, SignedProofFailed,
and the error macro from the top-level use/import statement to eliminate dead
imports; locate the use block that currently lists EnclaveEventData,
EventContext, PartyProofsToVerify, PlaintextAggregated, Proof, ProofType, Seed,
Sequenced, ShareVerificationComplete, ShareVerificationDispatched,
SignedProofFailed, SignedProofPayload, TypedEvent, VerificationKind, ZkResponse
and delete ProofType, SignedProofFailed and the error macro from that list (or
re-add only when you immediately use them).
🤖 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/aggregator/src/threshold_plaintext_aggregator.rs`:
- Around line 17-19: The import list contains unused symbols—remove ProofType,
SignedProofFailed, and the error macro from the top-level use/import statement
to eliminate dead imports; locate the use block that currently lists
EnclaveEventData, EventContext, PartyProofsToVerify, PlaintextAggregated, Proof,
ProofType, Seed, Sequenced, ShareVerificationComplete,
ShareVerificationDispatched, SignedProofFailed, SignedProofPayload, TypedEvent,
VerificationKind, ZkResponse and delete ProofType, SignedProofFailed and the
error macro from that list (or re-add only when you immediately use them).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d2003d2b-04db-4a1f-b271-f160aa43fda8

📥 Commits

Reviewing files that changed from the base of the PR and between 5205da6 and 0c28d0b.

📒 Files selected for processing (2)
  • crates/aggregator/src/threshold_plaintext_aggregator.rs
  • templates/default/tests/integration.spec.ts

0xjei
0xjei previously approved these changes Apr 2, 2026
Copy link
Copy Markdown
Member

@0xjei 0xjei left a comment

Choose a reason for hiding this comment

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

utACK - just left a minor code reuse; but can be ignored

Comment thread crates/aggregator/src/threshold_plaintext_aggregator.rs Outdated
cedoor
cedoor previously approved these changes Apr 2, 2026
Copy link
Copy Markdown
Member

@cedoor cedoor left a comment

Choose a reason for hiding this comment

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

utACK

Comment thread crates/aggregator/src/threshold_plaintext_aggregator.rs Outdated
@ctrlc03 ctrlc03 force-pushed the chore/pre-c7-check-ag branch from 63bd400 to 344a1aa Compare April 3, 2026 09:58
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 (1)
crates/aggregator/src/threshold_plaintext_aggregator.rs (1)

501-516: ⚠️ Potential issue | 🟠 Major

Fail-open on setup failures undermines the pre-check.

When build_pair_for_preset, C6Bounds::compute, or C6Bits::compute fails, the method returns an empty mismatch set, effectively passing all shares through unchecked. Since this is a defense-in-depth check against proof/share substitution attacks, consider failing closed (return all party IDs as mismatched) rather than silently skipping verification.

🛡️ Proposed fail-closed fix
     fn verify_shares_match_c6_commitments(
         &self,
         honest_shares: &[(u64, Vec<ArcBytes>)],
         c6_proofs: &HashMap<u64, Vec<SignedProofPayload>>,
     ) -> BTreeSet<u64> {
         let mut mismatched = BTreeSet::new();
+        let all_party_ids: BTreeSet<u64> = honest_shares.iter().map(|(id, _)| *id).collect();

         let Ok((threshold_params, _)) = e3_fhe_params::build_pair_for_preset(self.params_preset)
         else {
             warn!("Could not build BFV params for d_commitment check — skipping");
-            return mismatched;
+            return all_party_ids;
         };

         let Ok(bounds) = C6Bounds::compute(self.params_preset, &()) else {
             warn!("Could not compute bounds for d_commitment check — skipping");
-            return mismatched;
+            return all_party_ids;
         };
         let Ok(bits) = C6Bits::compute(self.params_preset, &bounds) else {
             warn!("Could not compute bits for d_commitment check — skipping");
-            return mismatched;
+            return all_party_ids;
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/aggregator/src/threshold_plaintext_aggregator.rs` around lines 501 -
516, The current early-returns on Err from e3_fhe_params::build_pair_for_preset,
C6Bounds::compute, and C6Bits::compute leave the pre-check in a "fail-open"
state by returning the existing (empty) mismatched set; instead, on any such
failure populate and return mismatched as the full set of all participant/party
IDs (i.e., fail-closed), and include the error details in the warning log.
Concretely, inside the Err branches for build_pair_for_preset,
C6Bounds::compute, and C6Bits::compute, replace the return mismatched with code
that logs the error and constructs mismatched to contain all party IDs from the
aggregator state (use whatever field holds participants/party IDs in this
struct), then return that full mismatched set.
🤖 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/aggregator/src/threshold_plaintext_aggregator.rs`:
- Around line 584-597: The code silently truncates big-endian bytes from
computed.to_bytes_be() before padding, which can hide overflow; update the block
handling be_bytes/computed_padded (around computed.to_bytes_be(),
computed_padded, be_bytes, c6_d_bytes, and the mismatched insertion for
party_id) to assert that be_bytes.len() <= 32 (e.g., assert!(be_bytes.len() <=
32, "...")) and then copy the entire be_bytes slice into computed_padded without
the .min(32) truncation so any oversized BigInt fails loudly rather than being
silently truncated.
- Around line 532-558: The current verification only checks the first C6 proof
and share because the code uses proofs.first() and shares.first(); change this
to iterate over all ciphertext indices by zipping proofs and shares (e.g., for
(idx, (proof, share_bytes)) in proofs.iter().zip(shares.iter()).enumerate()),
call c6_output_layout.extract_field(&proof.payload.proof.public_signals,
"d_commitment") for each proof, and perform the commitment verification
per-index; on failure use warn! with the index (e.g., "Could not extract
d_commitment[{}] for party {} — marking as mismatched") and call
mismatched.insert(*party_id) to continue to the next party.

---

Duplicate comments:
In `@crates/aggregator/src/threshold_plaintext_aggregator.rs`:
- Around line 501-516: The current early-returns on Err from
e3_fhe_params::build_pair_for_preset, C6Bounds::compute, and C6Bits::compute
leave the pre-check in a "fail-open" state by returning the existing (empty)
mismatched set; instead, on any such failure populate and return mismatched as
the full set of all participant/party IDs (i.e., fail-closed), and include the
error details in the warning log. Concretely, inside the Err branches for
build_pair_for_preset, C6Bounds::compute, and C6Bits::compute, replace the
return mismatched with code that logs the error and constructs mismatched to
contain all party IDs from the aggregator state (use whatever field holds
participants/party IDs in this struct), then return that full mismatched set.
🪄 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: c6a028e2-ceea-43bf-a928-a240f414abd3

📥 Commits

Reviewing files that changed from the base of the PR and between 63bd400 and 344a1aa.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • crates/aggregator/Cargo.toml
  • crates/aggregator/src/threshold_plaintext_aggregator.rs
  • crates/multithread/src/multithread.rs
  • crates/polynomial/src/crt_polynomial.rs
  • crates/zk-helpers/src/circuits/threshold/share_decryption/computation.rs
  • templates/default/tests/integration.spec.ts
✅ Files skipped from review due to trivial changes (2)
  • crates/aggregator/Cargo.toml
  • crates/multithread/src/multithread.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • templates/default/tests/integration.spec.ts
  • crates/polynomial/src/crt_polynomial.rs
  • crates/zk-helpers/src/circuits/threshold/share_decryption/computation.rs

Comment thread crates/aggregator/src/threshold_plaintext_aggregator.rs
Comment thread crates/aggregator/src/threshold_plaintext_aggregator.rs
@ctrlc03 ctrlc03 merged commit 279c7a6 into main Apr 3, 2026
33 checks passed
@ctrlc03 ctrlc03 deleted the chore/pre-c7-check-ag branch April 3, 2026 15:28
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.

3 participants