Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 149 additions & 58 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ arkworks = [
parallel = ["dep:rayon", "ark-ec?/parallel", "ark-ff?/parallel"]
cache = ["arkworks", "dep:once_cell", "parallel"]
disk-persistence = []
recursion = ["arkworks"]

[dependencies]
thiserror = "2.0"
Expand All @@ -71,6 +72,7 @@ rayon = { version = "1.10", optional = true }
[dev-dependencies]
rand = "0.8"
criterion = { version = "0.5", features = ["html_reports"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

[[example]]
name = "basic_e2e"
Expand All @@ -84,6 +86,10 @@ required-features = ["backends"]
name = "non_square"
required-features = ["backends"]

[[example]]
name = "recursion"
required-features = ["recursion"]

[[example]]
name = "homomorphic_mixed_sizes"
required-features = ["backends"]
Expand Down
60 changes: 58 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,45 @@ Com(r₁·P₁ + r₂·P₂ + ... + rₙ·Pₙ) = r₁·Com(P₁) + r₂·Com(P

This property enables efficient proof aggregation and batch verification. See `examples/homomorphic.rs` for a demonstration.

### Recursive Proof Composition

The `recursion` feature enables traced verification for building recursive SNARKs that compose Dory:

1. **Witness Generation**: Run verification while capturing traces of all arithmetic operations (GT exponentiations, scalar multiplications, pairings, etc.)

2. **Hint-Based Verification**: Re-run verification using pre-computed hints instead of performing expensive ops

```rust
use std::rc::Rc;
use dory_pcs::{verify_recursive, setup, prove};
use dory_pcs::backends::arkworks::{
SimpleWitnessBackend, SimpleWitnessGenerator, BN254, G1Routines, G2Routines,
};
use dory_pcs::recursion::TraceContext;

type Ctx = TraceContext<SimpleWitnessBackend, BN254, SimpleWitnessGenerator>;

// Phase 1: Witness generation - captures operation traces
let ctx = Rc::new(Ctx::for_witness_gen());
verify_recursive::<_, BN254, G1Routines, G2Routines, _, _, _>(
commitment, evaluation, &point, &proof, setup.clone(), &mut transcript, ctx.clone(),
)?;

let collection = Rc::try_unwrap(ctx).ok().unwrap().finalize().unwrap();
// collection contains detailed witnesses for each operation

// Convert to hints
let hints = collection.to_hints::<BN254>();

// Phase 2: Hint-based verification
let ctx = Rc::new(Ctx::for_hints(hints));
verify_recursive::<_, BN254, G1Routines, G2Routines, _, _, _>(
commitment, evaluation, &point, &proof, setup, &mut transcript, ctx,
)?;
```

See `examples/recursion.rs` for a complete demonstration.

## Usage

```rust
Expand Down Expand Up @@ -170,6 +209,11 @@ The repository includes three comprehensive examples demonstrating different asp
cargo run --example non_square --features backends
```

4. **`recursion`** - Trace generation and hint-based verification for recursive proof composition
```bash
cargo run --example recursion --features recursion
```

## Development Setup

After cloning the repository, install Git hooks to ensure code quality:
Expand Down Expand Up @@ -238,6 +282,7 @@ cargo bench --features backends,cache,parallel
- `cache` - Enable prepared point caching for ~20-30% pairing speedup. Requires `arkworks` and `parallel`.
- `parallel` - Enable parallelization using Rayon for MSMs and pairings. Works with both `arkworks` backend and enables parallel features in `ark-ec` and `ark-ff`.
- `disk-persistence` - Enable automatic setup caching to disk. When enabled, `setup()` will load from OS-specific cache directories if available, avoiding regeneration.
- `recursion` - Enable traced verification for recursive proof composition. Provides witness generation and hint-based verification modes.

## Project Structure

Expand All @@ -263,15 +308,25 @@ src/
├── reduce_and_fold.rs # Inner product protocol
├── messages.rs # Protocol messages
├── proof.rs # Proof structure
└── error.rs # Error types
├── error.rs # Error types
└── recursion/ # Recursive verification support
├── mod.rs # Module exports
├── witness.rs # WitnessBackend, OpId, OpType traits/types
├── context.rs # TraceContext for execution modes
├── trace.rs # TraceG1, TraceG2, TraceGT wrappers
├── collection.rs # WitnessCollection storage
├── collector.rs # WitnessCollector and generator traits
└── hint_map.rs # Lightweight HintMap storage

tests/arkworks/
├── mod.rs # Test utilities
├── setup.rs # Setup tests
├── commitment.rs # Commitment tests
├── evaluation.rs # Evaluation tests
├── integration.rs # End-to-end tests
└── soundness.rs # Soundness tests
├── soundness.rs # Soundness tests
├── recursion.rs # Trace and hint verification tests
└── witness.rs # Witness generation tests
```

## Test Coverage
Expand All @@ -285,6 +340,7 @@ The implementation includes comprehensive tests covering:
- Non-square matrix support (nu < sigma, nu = sigma - 1, and very rectangular cases)
- Soundness (tampering resistance for all proof components across 20+ attack vectors)
- Prepared point caching correctness
- Recursive verification (witness generation and hint-based verification)

## Acknowledgments

Expand Down
152 changes: 152 additions & 0 deletions examples/recursion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//! Recursion example: trace generation and hint-based verification
//!
//! This example demonstrates the recursion API workflow:
//! 1. Standard proof generation
//! 2. Witness-generating verification (captures operation traces)
//! 3. Converting witnesses to hints
//! 4. Hint-based verification
//!
//! The hint-based verification enables efficient recursive proof composition.
//!
//! Run with: `cargo run --features recursion --example recursion`

use std::rc::Rc;

use dory_pcs::backends::arkworks::{
ArkFr, ArkworksPolynomial, Blake2bTranscript, G1Routines, G2Routines, SimpleWitnessBackend,
SimpleWitnessGenerator, BN254,
};
use dory_pcs::primitives::arithmetic::Field;
use dory_pcs::primitives::poly::Polynomial;
use dory_pcs::recursion::TraceContext;
use dory_pcs::{prove, setup, verify, verify_recursive};
use rand::thread_rng;
use tracing::info;
use tracing_subscriber::EnvFilter;

type Ctx = TraceContext<SimpleWitnessBackend, BN254, SimpleWitnessGenerator>;

fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
)
.init();

info!("Dory PCS - Recursion API Example");
info!("=================================\n");

let mut rng = thread_rng();

// Step 1: Setup
let max_log_n = 8;
info!("1. Generating setup (max_log_n = {})...", max_log_n);
let (prover_setup, verifier_setup) = setup::<BN254, _>(&mut rng, max_log_n);
info!(" Setup complete\n");

// Step 2: Create polynomial
let nu = 3;
let sigma = 3;
let poly_size = 1 << (nu + sigma); // 64 coefficients
let num_vars = nu + sigma;

info!("2. Creating random polynomial...");
info!(" Matrix layout: {}x{}", 1 << nu, 1 << sigma);
info!(" Total coefficients: {}", poly_size);

let coefficients: Vec<ArkFr> = (0..poly_size).map(|_| ArkFr::random(&mut rng)).collect();
let poly = ArkworksPolynomial::new(coefficients);

// Step 3: Commit
info!("\n3. Computing commitment...");
let (tier_2, tier_1) = poly.commit::<BN254, G1Routines>(nu, sigma, &prover_setup)?;

// Step 4: Create evaluation proof
let point: Vec<ArkFr> = (0..num_vars).map(|_| ArkFr::random(&mut rng)).collect();
let evaluation = poly.evaluate(&point);

info!("4. Generating proof...");
let mut prover_transcript = Blake2bTranscript::new(b"dory-recursion-example");
let proof = prove::<_, BN254, G1Routines, G2Routines, _, _>(
&poly,
&point,
tier_1,
nu,
sigma,
&prover_setup,
&mut prover_transcript,
)?;

// Step 5: Standard verification)
info!("\n5. Standard verification...");
let mut std_transcript = Blake2bTranscript::new(b"dory-recursion-example");
verify::<_, BN254, G1Routines, G2Routines, _>(
tier_2,
evaluation,
&point,
&proof,
verifier_setup.clone(),
&mut std_transcript,
)?;
info!(" Standard verification passed\n");

// Step 6: Witness-generating verification
info!("6. Witness-generating verification...");
info!(" This captures traces of all arithmetic operations");

let ctx = Rc::new(Ctx::for_witness_gen());
let mut witness_transcript = Blake2bTranscript::new(b"dory-recursion-example");

verify_recursive::<_, BN254, G1Routines, G2Routines, _, _, _>(
tier_2,
evaluation,
&point,
&proof,
verifier_setup.clone(),
&mut witness_transcript,
ctx.clone(),
)?;

// Finalize and get witness collection
let collection = Rc::try_unwrap(ctx)
.ok()
.expect("should have sole ownership")
.finalize()
.expect("should have witnesses");

info!(" Witness collection stats:");
info!(" - GT exponentiation: {}", collection.gt_exp.len());
info!(" - G1 scalar mul: {}", collection.g1_scalar_mul.len());
info!(" - G2 scalar mul: {}", collection.g2_scalar_mul.len());
info!(" - GT multiplication: {}", collection.gt_mul.len());
info!(" - Single pairing: {}", collection.pairing.len());
info!(" - Multi-pairing: {}", collection.multi_pairing.len());
info!(" - G1 MSM: {}", collection.msm_g1.len());
info!(" - G2 MSM: {}", collection.msm_g2.len());
info!(" - Total operations: {}", collection.total_witnesses());
info!(" - Reduce-fold rounds: {}\n", collection.num_rounds);

// Step 7: Convert to hints
info!("7. Converting witnesses to hints...");
let hints = collection.to_hints::<BN254>();
info!(" HintMap entries: {} (one per operation)", hints.len());

// Step 8: Hint-based verification
info!("8. Hint-based verification...");

let ctx = Rc::new(Ctx::for_hints(hints));
let mut hint_transcript = Blake2bTranscript::new(b"dory-recursion-example");

verify_recursive::<_, BN254, G1Routines, G2Routines, _, _, _>(
tier_2,
evaluation,
&point,
&proof,
verifier_setup,
&mut hint_transcript,
ctx,
)?;
info!(" Hint-based verification passed\n");

Ok(())
}
Loading
Loading