Skip to main content

dory_pcs/
lib.rs

1//! # dory
2//!
3//! A high performance and modular implementation of the Dory polynomial commitment scheme.
4//!
5//! Dory is a transparent polynomial commitment scheme with excellent asymptotic
6//! performance, based on the work of Jonathan Lee
7//! ([eprint 2020/1274](https://eprint.iacr.org/2020/1274)).
8//!
9//! ## Key Features
10//!
11//! - **Transparent setup** with automatic disk persistence
12//! - **Logarithmic proof size**: O(log n) group elements
13//! - **Logarithmic verification**: O(log n) GT exps and 5 pairings
14//! - **Performance optimizations**: Optional prepared point caching (~20-30% speedup) and parallelization
15//! - **Flexible matrix layouts**: Supports both square and non-square matrices (nu ≤ sigma)
16//! - **Homomorphic properties**: Com(r₁·P₁ + r₂·P₂ + ... + rₙ·Pₙ) = r₁·Com(P₁) + r₂·Com(P₂) + ... + rₙ·Com(Pₙ)
17//!
18//! ## Structure
19//!
20//! ### Core Modules
21//! - [`primitives`] - Core traits and abstractions
22//!   - [`primitives::arithmetic`] - Field, group, and pairing curve traits
23//!   - [`primitives::poly`] - Multilinear polynomial traits and operations
24//!   - [`primitives::transcript`] - Fiat-Shamir transcript trait
25//!   - [`primitives::serialization`] - Serialization abstractions
26//! - [`mod@setup`] - Transparent setup generation for prover and verifier
27//! - [`evaluation_proof`] - Evaluation proof creation and verification
28//! - [`reduce_and_fold`] - Inner product protocol state machines (prover/verifier)
29//! - [`messages`] - Protocol message structures (VMV, reduce rounds, scalar product)
30//! - [`proof`] - Complete proof data structure
31//! - [`error`] - Error types
32//!
33//! ### Backend Implementations
34//! - `backends` - Concrete backend implementations (available with feature flags)
35//!   - `backends::arkworks` - Arkworks backend with BN254 curve (requires `arkworks` feature)
36//!
37//! ## Usage
38//!
39//! ### Basic Example
40//!
41//! ```ignore
42//! use dory_pcs::{setup, prove, verify};
43//! use dory_pcs::backends::arkworks::{BN254, G1Routines, G2Routines, Blake2bTranscript};
44//!
45//! // 1. Generate setup (automatically loads from/saves to disk)
46//! let (prover_setup, verifier_setup) = setup::<BN254, _>(&mut rng, max_log_n);
47//!
48//! // 2. Commit to polynomial
49//! let (tier_2_commitment, tier_1_commitments) = polynomial
50//!     .commit::<BN254, G1Routines>(nu, sigma, &prover_setup)?;
51//!
52//! // 3. Generate evaluation proof
53//! let mut prover_transcript = Blake2bTranscript::new(b"domain-separation");
54//! let proof = prove::<_, BN254, G1Routines, G2Routines, _, _>(
55//!     &polynomial, &point, tier_1_commitments, nu, sigma,
56//!     &prover_setup, &mut prover_transcript
57//! )?;
58//!
59//! // 4. Verify
60//! let mut verifier_transcript = Blake2bTranscript::new(b"domain-separation");
61//! verify::<_, BN254, G1Routines, G2Routines, _>(
62//!     tier_2_commitment, evaluation, &point, &proof,
63//!     verifier_setup, &mut verifier_transcript
64//! )?;
65//! ```
66//!
67//! ### Performance Optimization
68//!
69//! Enable prepared point caching for ~20-30% pairing speedup (requires `cache` feature):
70//! ```ignore
71//! use dory_pcs::backends::arkworks::init_cache;
72//!
73//! let (prover_setup, verifier_setup) = setup::<BN254, _>(&mut rng, max_log_n);
74//! init_cache(&prover_setup.g1_vec, &prover_setup.g2_vec);
75//! // Subsequent operations will automatically use cached prepared points
76//! ```
77//!
78//! ### Examples
79//!
80//! See the `examples/` directory for complete demonstrations:
81//! - `basic_e2e.rs` - Standard square matrix workflow
82//! - `homomorphic.rs` - Homomorphic combination of multiple polynomials
83//! - `non_square.rs` - Non-square matrix layout (nu < sigma)
84//!
85//! ## Feature Flags
86//!
87//! - `backends` - Enable concrete backends (currently Arkworks BN254, includes `disk-persistence`)
88//! - `cache` - Enable prepared point caching (~20-30% speedup, requires `parallel`)
89//! - `parallel` - Enable Rayon parallelization for MSMs and pairings
90//! - `disk-persistence` - Enable automatic setup caching to disk
91
92/// Error types for Dory PCS operations
93pub mod error;
94pub mod evaluation_proof;
95pub mod messages;
96pub mod primitives;
97pub mod proof;
98pub mod reduce_and_fold;
99pub mod setup;
100
101#[cfg(feature = "arkworks")]
102pub mod backends;
103
104pub use error::DoryError;
105pub use evaluation_proof::create_evaluation_proof;
106pub use messages::{FirstReduceMessage, ScalarProductMessage, SecondReduceMessage, VMVMessage};
107use primitives::arithmetic::{DoryRoutines, Field, Group, PairingCurve};
108pub use primitives::poly::{MultilinearLagrange, Polynomial};
109use primitives::serialization::{DoryDeserialize, DorySerialize};
110pub use proof::DoryProof;
111pub use reduce_and_fold::{DoryProverState, DoryVerifierState};
112pub use setup::{ProverSetup, VerifierSetup};
113
114/// Generate or load prover and verifier setups from disk
115///
116/// Creates or loads the transparent setup parameters for Dory PCS.
117/// First attempts to load from disk; if not found, generates new setup and saves to disk.
118///
119/// Supports polynomials up to 2^max_log_n coefficients arranged as 2^ν × 2^σ matrices
120/// where ν + σ = max_log_n and ν ≤ σ (flexible matrix layouts including square and non-square).
121///
122/// Setup file location (OS-dependent):
123/// - Linux: `~/.cache/dory/dory_{max_log_n}.urs`
124/// - macOS: `~/Library/Caches/dory/dory_{max_log_n}.urs`
125/// - Windows: `{FOLDERID_LocalAppData}\dory\dory_{max_log_n}.urs`
126///
127/// # Parameters
128/// - `rng`: Random number generator for setup generation (used only if not found on disk)
129/// - `max_log_n`: Maximum log₂ of polynomial size
130///
131/// # Returns
132/// `(ProverSetup, VerifierSetup)` - Setup parameters for proving and verification
133///
134/// # Performance
135/// To enable prepared point caching (~20-30% speedup), use the `cache` feature and call
136/// `init_cache(&prover_setup.g1_vec, &prover_setup.g2_vec)` after setup.
137///
138/// # Panics
139/// Panics if the setup file exists on disk but is corrupted or cannot be deserialized.
140pub fn setup<E: PairingCurve, R: rand_core::RngCore>(
141    rng: &mut R,
142    max_log_n: usize,
143) -> (ProverSetup<E>, VerifierSetup<E>)
144where
145    ProverSetup<E>: DorySerialize + DoryDeserialize,
146    VerifierSetup<E>: DorySerialize + DoryDeserialize,
147{
148    #[cfg(feature = "disk-persistence")]
149    {
150        // Try to load from disk
151        match setup::load_setup::<E>(max_log_n) {
152            Ok(saved) => return saved,
153            Err(DoryError::InvalidURS(msg)) if msg.contains("not found") => {
154                // File doesn't exist, we'll generate new setup
155                tracing::debug!("Setup file not found, will generate new one");
156            }
157            Err(e) => {
158                // File exists but is corrupted - unrecoverable
159                panic!("Failed to load setup from disk: {e}");
160            }
161        }
162
163        // Setup not found on disk - generate new setup
164        tracing::info!(
165            "Setup not found on disk, generating new setup for max_log_n={}",
166            max_log_n
167        );
168        let prover_setup = ProverSetup::new(rng, max_log_n);
169        let verifier_setup = prover_setup.to_verifier_setup();
170
171        // Save to disk
172        setup::save_setup(&prover_setup, &verifier_setup, max_log_n);
173
174        (prover_setup, verifier_setup)
175    }
176
177    #[cfg(not(feature = "disk-persistence"))]
178    {
179        tracing::info!("Generating new setup for max_log_n={}", max_log_n);
180
181        let prover_setup = ProverSetup::new(rng, max_log_n);
182        let verifier_setup = prover_setup.to_verifier_setup();
183
184        (prover_setup, verifier_setup)
185    }
186}
187
188/// Force generate new prover and verifier setups and save to disk
189///
190/// Always generates fresh setup parameters, ignoring any saved values on disk.
191/// Saves the newly generated setup to disk, overwriting any existing setup file
192/// for the given max_log_n.
193///
194/// Use this when you want to explicitly regenerate the setup (e.g., for testing
195/// or when you suspect the saved setup file is corrupted).
196///
197/// # Parameters
198/// - `rng`: Random number generator for setup generation
199/// - `max_log_n`: Maximum log₂ of polynomial size
200///
201/// # Returns
202/// `(ProverSetup, VerifierSetup)` - Newly generated setup parameters
203///
204/// # Availability
205/// This function is only available when the `disk-persistence` feature is enabled.
206#[cfg(feature = "disk-persistence")]
207pub fn generate_urs<E: PairingCurve, R: rand_core::RngCore>(
208    rng: &mut R,
209    max_log_n: usize,
210) -> (ProverSetup<E>, VerifierSetup<E>)
211where
212    ProverSetup<E>: DorySerialize + DoryDeserialize,
213    VerifierSetup<E>: DorySerialize + DoryDeserialize,
214{
215    tracing::info!("Force-generating new setup for max_log_n={}", max_log_n);
216
217    let prover_setup = ProverSetup::new(rng, max_log_n);
218    let verifier_setup = prover_setup.to_verifier_setup();
219
220    // Overwrites existing
221    setup::save_setup(&prover_setup, &verifier_setup, max_log_n);
222
223    (prover_setup, verifier_setup)
224}
225
226/// Evaluate a polynomial at a point and create proof
227///
228/// Creates an evaluation proof for a polynomial at a given point using precomputed
229/// tier-1 commitments (row commitments).
230///
231/// # Workflow
232/// 1. Call `polynomial.commit(nu, sigma, setup)` to get `(tier_2, row_commitments)`
233/// 2. Call this function with the `row_commitments` to create the proof
234/// 3. Use `tier_2` for verification via the `verify()` function
235///
236/// # Parameters
237/// - `polynomial`: Polynomial implementing MultilinearLagrange trait
238/// - `point`: Evaluation point (length must equal nu + sigma)
239/// - `row_commitments`: Tier-1 commitments (row commitments in G1) from `polynomial.commit()`
240/// - `nu`: Log₂ of number of rows (constraint: nu ≤ sigma for non-square matrices)
241/// - `sigma`: Log₂ of number of columns
242/// - `setup`: Prover setup
243/// - `transcript`: Fiat-Shamir transcript
244///
245/// # Returns
246/// The evaluation proof containing VMV message, reduce messages, and final message
247///
248/// # Homomorphic Properties
249/// Proofs can be created for homomorphically combined polynomials. If you have
250/// commitments Com(P₁), Com(P₂), ..., Com(Pₙ) and want to prove evaluation of
251/// r₁·P₁ + r₂·P₂ + ... + rₙ·Pₙ, you can:
252/// 1. Combine tier-2 commitments: r₁·Com(P₁) + r₂·Com(P₂) + ... + rₙ·Com(Pₙ)
253/// 2. Combine tier-1 commitments element-wise
254/// 3. Generate proof using this function with the combined polynomial
255///
256/// See `examples/homomorphic.rs` for a complete demonstration.
257///
258/// # Errors
259/// Returns `DoryError` if:
260/// - Point dimension doesn't match nu + sigma
261/// - Polynomial size doesn't match 2^(nu + sigma)
262/// - Number of row commitments doesn't match 2^nu
263#[allow(clippy::type_complexity)]
264#[tracing::instrument(skip_all, name = "prove")]
265pub fn prove<F, E, M1, M2, P, T>(
266    polynomial: &P,
267    point: &[F],
268    row_commitments: Vec<E::G1>,
269    nu: usize,
270    sigma: usize,
271    setup: &ProverSetup<E>,
272    transcript: &mut T,
273) -> Result<DoryProof<E::G1, E::G2, E::GT>, DoryError>
274where
275    F: Field,
276    E: PairingCurve,
277    E::G1: Group<Scalar = F>,
278    E::G2: Group<Scalar = F>,
279    E::GT: Group<Scalar = F>,
280    M1: DoryRoutines<E::G1>,
281    M2: DoryRoutines<E::G2>,
282    P: MultilinearLagrange<F>,
283    T: primitives::transcript::Transcript<Curve = E>,
284{
285    // Create evaluation proof using row_commitments
286    evaluation_proof::create_evaluation_proof::<F, E, M1, M2, T, P>(
287        polynomial,
288        point,
289        Some(row_commitments),
290        nu,
291        sigma,
292        setup,
293        transcript,
294    )
295}
296
297/// Verify an evaluation proof
298///
299/// Verifies that a committed polynomial evaluates to the claimed value at the given point.
300/// The matrix dimensions (nu, sigma) are extracted from the proof.
301///
302/// Works with both square and non-square matrix layouts (nu ≤ sigma), and can verify
303/// proofs for homomorphically combined polynomials.
304///
305/// # Parameters
306/// - `commitment`: Polynomial commitment (in GT) - can be a combined commitment for homomorphic proofs
307/// - `evaluation`: Claimed evaluation result
308/// - `point`: Evaluation point (length must equal proof.nu + proof.sigma)
309/// - `proof`: Evaluation proof to verify (contains nu and sigma)
310/// - `setup`: Verifier setup
311/// - `transcript`: Fiat-Shamir transcript
312///
313/// # Returns
314/// `Ok(())` if proof is valid, `Err(DoryError)` otherwise
315///
316/// # Errors
317/// Returns `DoryError::InvalidProof` if the proof is invalid, or other variants
318/// if the input parameters are incorrect (e.g., point dimension mismatch).
319#[tracing::instrument(skip_all, name = "verify")]
320pub fn verify<F, E, M1, M2, T>(
321    commitment: E::GT,
322    evaluation: F,
323    point: &[F],
324    proof: &DoryProof<E::G1, E::G2, E::GT>,
325    setup: VerifierSetup<E>,
326    transcript: &mut T,
327) -> Result<(), DoryError>
328where
329    F: Field,
330    E: PairingCurve + Clone,
331    E::G1: Group<Scalar = F>,
332    E::G2: Group<Scalar = F>,
333    E::GT: Group<Scalar = F>,
334    M1: DoryRoutines<E::G1>,
335    M2: DoryRoutines<E::G2>,
336    T: primitives::transcript::Transcript<Curve = E>,
337{
338    evaluation_proof::verify_evaluation_proof::<F, E, M1, M2, T>(
339        commitment, evaluation, point, proof, setup, transcript,
340    )
341}