Skip to content

feat: integrate recursive aggregation into zk flow [skip-line-limit]#1392

Merged
cedoor merged 53 commits into
mainfrom
feat/aggregation-integration
Mar 14, 2026
Merged

feat: integrate recursive aggregation into zk flow [skip-line-limit]#1392
cedoor merged 53 commits into
mainfrom
feat/aggregation-integration

Conversation

@cedoor

@cedoor cedoor commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Motivation

Each node generates inner proofs across circuits C0–C4 (DKG) and C6 (decryption). Before submission for cross-node aggregation, these must be recursively aggregated. This PR introduces NodeProofAggregator and the cross-node aggregation flow.

Architecture — Complete Flow

Phase 1: DKG (C0–C4)

  1. Each node generates proofs C0–C4 + wrapper
    Each inner proof is wrapped (single-element RecursiveAggregation) in the same thread that generates it — fully parallel, no cost on the aggregator side.

  2. Each node folds all its wrappers and sends to aggregator
    Local NodeProofAggregator receives DKGInnerProofReady (wrapped proof, seq, total_expected), folds them in seq order, and publishes DKGRecursiveAggregationComplete — one aggregated proof per node.

  3. Aggregator folds proofs aggregated from H nodes
    The aggregator collects the aggregated proofs from honest nodes and folds them into one DKG proof.

Phase 2: Decryption (C6)

  1. Each node generates proof C6 + wrapper and sends to aggregator
    Each node produces its C6 proof (threshold share decryption), wraps it, and sends it to the aggregator.

  2. Aggregator folds wrappers from all H nodes
    The aggregator receives the C6 wrappers from honest nodes and folds them into a single proof (c6_aggregated_proof in PlaintextAggregated).


DKG: Sequence index assignment

Circuit seq
C0 — PkBfv 0
C1 — PkGeneration 1
C2a — SkShareComputation 2
C2b — ESmShareComputation 3
C3a[i] — SkShareEncryption 4 + i
C3b[j] — ESmShareEncryption 4 + sk_enc_count + j
C4a — DkgShareDecryption (SK) 4 + sk_enc_count + esm_enc_count
C4b — DkgShareDecryption (ESM) 4 + sk_enc_count + esm_enc_count + 1

total_expected = 4 + sk_enc_count + esm_enc_count + 2

DKG: Fold rule (per-node)

  • Proof arrives → buffer[seq]
  • While buffer[next_to_aggregate] ready and no fold in progress:
    • First proof → store as accumulated, decrement remaining
    • Otherwise → dispatch fold(accumulated, next), set fold_correlation
  • Fold response → update accumulated, clear fold_correlation, decrement remaining
    • If remaining == 0 → publish DKGRecursiveAggregationComplete

Closes #1174

Follow up task -> Post all proofs on-chain and verify them in 2 phases: dkg & decryption.

Summary by CodeRabbit

  • New Features
    • End-to-end ZK wrapper + fold proof workflow with incremental recursive folding and automatic node- and cross-node aggregation.
    • New actor coordinating per-node folding and emitted events when node- and cross-node aggregated proofs are ready.
  • Chores
    • Event payloads and public events extended to carry wrapped/aggregated proofs and sequencing metadata.
    • Aggregation orchestration integrated into aggregator flows and publishing paths; new state machine support for multi-step proof folding.

@vercel

vercel Bot commented Mar 6, 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 14, 2026 3:37pm
enclave-docs Ready Ready Preview, Comment Mar 14, 2026 3:37pm

Request Review

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

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 wrapper/fold recursive proof aggregation: switches wrapper Noir circuits to ZK proofs, introduces FoldProofs ZkRequest/ZkResponse and wrapped_proof(s) fields, adds node- and cross-node folding actors/state (NodeProofAggregator, ProofFoldState), propagates wrapped proofs through actors/events, and wires publish orchestration for combined aggregated proofs.

Changes

Cohort / File(s) Summary
Noir wrapper & threshold circuits
circuits/bin/recursive_aggregation/wrapper/.../src/main.nr
Switched proof types from UltraHonkProofUltraHonkZKProof, changed verify_honk_proof_non_zkverify_honk_proof, reduced pub global N_PROOFS from 2→1 where adjusted, and added public-input aggregation/commitment return where applicable.
Aggregator core
crates/aggregator/src/lib.rs, crates/aggregator/src/proof_fold.rs
Added proof_fold module and ProofFoldState with stateful sequential folding, correlation tracking, publish/response handling, and public result field.
PublicKeyAggregator (cross-node DKG)
crates/aggregator/src/publickey_aggregator.rs
Added per-node DKG proof buffering, honest/dishonest tracking, cross_node_fold: ProofFoldState, handlers for DKGRecursiveAggregationComplete and ComputeResponse, and publish orchestration to include optional dkg_aggregated_proof.
ThresholdPlaintextAggregator (C6/C7)
crates/aggregator/src/threshold_plaintext_aggregator.rs
Added storage for wrapped C6 proofs, c6_fold: ProofFoldState, deferred C7 publishing until C6 fold completes, c7_proofs_pending, and try_publish_complete to emit combined PlaintextAggregated with c6_aggregated_proof.
ZK request/response & prover
crates/events/.../compute_request/zk.rs, crates/events/.../compute_request/mod.rs, crates/multithread/src/multithread.rs
Introduced ZkRequest::FoldProofs and ZkResponse::FoldProofs, added wrapped_proof/wrapped_proofs across responses, and added wrapper/fold proof generation and handling in the prover/multithread flow.
Node-level aggregation actor
crates/zk-prover/src/actors/node_proof_aggregator.rs, crates/zk-prover/src/actors/mod.rs
New NodeProofAggregator actor to incrementally fold per-E3 inner DKG proofs, buffer out-of-order sequences, dispatch FoldProofs requests, map correlations, and publish DKGRecursiveAggregationComplete.
ProofRequestActor & actor plumbing
crates/zk-prover/src/actors/proof_request.rs
Added NodeAggregationMeta and node_agg_meta, extended correlation entries with sequence indexes, propagated wrapped_proof(s) and seq metadata, and updated many handler signatures to carry wrapped proofs.
Events & types
crates/events/src/enclave_event/*.rs, crates/events/src/enclave_event/mod.rs
Added DKGInnerProofReady and DKGRecursiveAggregationComplete events; added optional c6_aggregated_proof and dkg_aggregated_proof fields to aggregated events; wired new variants into EnclaveEventData.
zk-prover recursive aggregation refactor
crates/zk-prover/src/circuits/recursive_aggregation/mod.rs, crates/zk-prover/src/traits.rs
Refactored wrapper/fold helpers to generate single-proof wrappers and separate fold calls; removed Provable::aggregate_proof in favor of explicit wrapper+fold helpers and added target_evm flag for folding.
Tests, CI & scripts
crates/tests/tests/integration.rs, .github/workflows/ci.yml, scripts/build-circuits.ts
Updated tests to include new optional aggregated fields (set to None), added CI artifact paths for new circuit targets, and extended build script to copy/alias share_computation wrapper artifacts for wrapper aliases.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant ProofRequestActor
    participant Multithread
    participant Bus
    participant NodeProofAggregator
    participant PublicKeyAggregator

    ProofRequestActor->>Multithread: ZkRequest (generate proof + wrapped_proof)
    Multithread-->>ProofRequestActor: ZkResponse { proof, wrapped_proof }
    ProofRequestActor->>Bus: DKGInnerProofReady(e3, seq, wrapped_proof)
    Bus->>NodeProofAggregator: DKGInnerProofReady
    NodeProofAggregator->>NodeProofAggregator: buffer by seq / try_advance()
    alt need folding
        NodeProofAggregator->>Multithread: ComputeRequest::zk FoldProofs(proof1, proof2)
        Multithread-->>NodeProofAggregator: ComputeResponse FoldProofs { proof }
        NodeProofAggregator->>NodeProofAggregator: update accumulated / continue or complete
    end
    NodeProofAggregator->>Bus: DKGRecursiveAggregationComplete(e3, aggregated_proof)
    Bus->>PublicKeyAggregator: DKGRecursiveAggregationComplete
    PublicKeyAggregator->>PublicKeyAggregator: try_start_cross_node_fold() -> publish PublicKeyAggregated { dkg_aggregated_proof? }
Loading
sequenceDiagram
    autonumber
    participant ProofRequestActor
    participant Multithread
    participant Bus
    participant ThresholdPlaintextAggregator

    ProofRequestActor->>Multithread: ZkRequest::ThresholdShareDecryption (produce proof + wrapped_proofs)
    Multithread-->>ProofRequestActor: ZkResponse { proofs, wrapped_proofs }
    ProofRequestActor->>Bus: DecryptionshareCreated { wrapped_proofs }
    Bus->>ThresholdPlaintextAggregator: DecryptionshareCreated
    ThresholdPlaintextAggregator->>ThresholdPlaintextAggregator: add_share(..., wrapped_proofs)
    ThresholdPlaintextAggregator->>ThresholdPlaintextAggregator: on C6 verify -> start c6_fold
    ThresholdPlaintextAggregator->>Multithread: ComputeRequest::zk FoldProofs
    Multithread-->>ThresholdPlaintextAggregator: ComputeResponse FoldProofs { proof }
    ThresholdPlaintextAggregator->>ThresholdPlaintextAggregator: try_publish_complete() -> Publish PlaintextAggregated { c6_aggregated_proof? }
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

  • #1174: Phase 2 (wrapper + cross-node folding) — this PR implements wrapper proofs, FoldProofs, node- and cross-node folding and publication flows aligning with that objective.

Possibly related PRs

  • #1372: Modifies ZK proof pipeline (wrapped/fold proofs, ZkRequest/ZkResponse, prover actors) — strong code-level overlap.
  • #1365: Recursive-aggregation/folding circuits and zk-prover helpers — directly related to wrapper/fold logic.
  • #1377: Cross-node C6/C7 folding and ThresholdPlaintextAggregator changes — closely overlaps orchestration and publish sequencing.

Suggested reviewers

  • 0xjei
  • hmzakhalid
  • ctrlc03

Poem

🐰 I fold each proof with nimble paws and cheer,

Wrapped bits hop in order, sequence clear,
Nodes pass parcels, folding two by two,
One aggregated bloom — a proof made new,
The rabbit claps: the chain can now draw near.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.19% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Most changes are within scope for the recursive aggregation feature. However, several changes appear tangential: E3 duration config updates in example files, generic circuit artifact build configurations, MAX_VOTE_BITS updates, and test-only duration changes don't directly implement the aggregation logic. Clarify whether E3 duration changes and build script updates are necessary for the aggregation feature, or if they should be separated into distinct PRs for clearer scope management.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: integrate recursive aggregation into zk flow' directly reflects the main objective of integrating recursive proof aggregation into the ZK workflow.
Linked Issues check ✅ Passed The PR implements both phases of issue #1174: Phase 1 aggregates C0-C4 proofs via NodeProofAggregator with DKGRecursiveAggregationComplete publication, and Phase 2 aggregates C6 wrapper proofs into PlaintextAggregated, meeting core coding requirements.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/aggregation-integration
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

You can disable poems in the walkthrough.

Disable the reviews.poem setting to disable the poems in the walkthrough.

@cedoor cedoor force-pushed the feat/aggregation-integration branch from 4a3b93f to f7ce4de Compare March 9, 2026 08:36
@ctrlc03 ctrlc03 force-pushed the feat/aggregation-integration branch from d180c9e to 0b36612 Compare March 9, 2026 17:24
@cedoor cedoor force-pushed the feat/aggregation-integration branch from f33a90f to 93d5a58 Compare March 10, 2026 13:41
@0xjei 0xjei self-requested a review March 10, 2026 20:52
@0xjei

0xjei commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Motivation

Each DKG node generates inner proofs across circuits C0-C4. Before submission for cross-node aggregation, these must be recursively aggregated into a single node-level proof. This PR introduces NodeProofAggregator to do this.

Architecture

Wrapper generation in the compute thread. Each inner proof is wrapped (single-element RecursiveAggregation) in the same thread that generates it — fully parallel, no cost on the aggregator side.

One unified event stream. Each inner proof emits DKGInnerProofReady immediately on completion, carrying the wrapped proof, a deterministic seq index, and total_expected.

Reorder buffer + sequential fold. NodeProofAggregator holds a BTreeMap<usize, Proof> per E3 and folds in strict seq order. Out-of-order arrivals wait in the buffer. When remaining == 0, DKGRecursiveAggregationComplete is published.

Sequence index assignment

Circuit seq
C0 — PkBfv 0
C1 — PkGeneration 1
C2a — SkShareComputation 2
C2b — ESmShareComputation 3
C3a[i] — SkShareEncryption 4 + i
C3b[j] — ESmShareEncryption 4 + sk_enc_count + j
C4a — DkgShareDecryption (SK) 4 + sk_enc_count + esm_enc_count
C4b — DkgShareDecryption (ESM) 4 + sk_enc_count + esm_enc_count + 1

total_expected = 4 + sk_enc_count + esm_enc_count + 2

Fold rule

* Proof arrives → `buffer[seq]`

* While `buffer[next_to_aggregate]` ready and not `in_flight`:
  
  * First proof → store as `accumulated`, decrement `remaining`
  * Otherwise → dispatch `fold(accumulated, next)`, set `in_flight`

* Fold response → update `accumulated`, `in_flight = false`, decrement `remaining`
  
  * If `remaining == 0` → publish `DKGRecursiveAggregationComplete`

Closes #1174

the #1174 refers to all circuits but this design refers just to the DKG phase. What are the steps from C5 to C7?

@cedoor cedoor changed the title feat: integrate recursive aggregation into zk flow feat: integrate recursive aggregation into zk flow [skip-line-limit] Mar 11, 2026

@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

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.

Implement code to run the actual aggregation for all circuits

3 participants