Skip to content

Commit 7d76948

Browse files
author
Colin Roberts
committed
docs: arith module
1 parent 5bead4e commit 7d76948

File tree

5 files changed

+250
-23
lines changed

5 files changed

+250
-23
lines changed

folding-schemes/src/arith/ccs/circuits.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
//! Circuit implementations for Customizable Constraint Systems (CCS).
2+
//!
3+
//! This module provides the circuit (gadget) variants of CCS components for use in
4+
//! constraint system implementations. These are used when CCS operations need to
5+
//! be performed inside another constraint system.
6+
17
use super::CCS;
28
use crate::utils::gadgets::SparseMatrixVar;
39
use ark_ff::PrimeField;
@@ -8,10 +14,11 @@ use ark_r1cs_std::{
814
use ark_relations::r1cs::{Namespace, SynthesisError};
915
use ark_std::borrow::Borrow;
1016

11-
/// CCSMatricesVar contains the matrices 'M' of the CCS without the rest of CCS parameters.
17+
/// [`CCSMatricesVar`] contains the matrices 'M' of the CCS without the rest of CCS parameters.
1218
#[derive(Debug, Clone)]
1319
pub struct CCSMatricesVar<F: PrimeField> {
14-
// we only need native representation, so the constraint field==F
20+
/// Vector of sparse matrices in their circuit representation
21+
/// We only need native representation, so the constraint field equals F
1522
pub M: Vec<SparseMatrixVar<FpVar<F>>>,
1623
}
1724

folding-schemes/src/arith/ccs/mod.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
//! Implementation of Customizable Constraint Systems (CCS).
2+
//!
3+
//! This module provides an implementation of CCS as defined in the
4+
//! [CCS paper](https://eprint.iacr.org/2023/552). CCS is a generalization
5+
//! of constraint systems that allows for flexible constraint expressions
6+
//! via configurable matrix operations.
7+
//!
8+
//! # Structure
9+
//!
10+
//! A CCS consists of:
11+
//! * A set of sparse matrices M₁...Mₜ ∈ F^{m×n}
12+
//! * A collection of multisets S₁...Sₘ containing indices into these matrices
13+
//! * A vector of coefficients c₁...cₘ
14+
//!
15+
//! # Example
16+
//!
17+
//! A simple R1CS constraint system can be represented as a CCS with:
18+
//! * Three matrices A, B, C
19+
//! * Two multisets S₁ = {0,1}, S₂ = {2}
20+
//! * Coefficients c₁ = 1, c₂ = -1
21+
//!
22+
//! # Organization
23+
//!
24+
//! * [`CCS`] - The main CCS type implementing the [`Arith`] trait
25+
//! * [`circuits`] - Circuit implementations for CCS operations
26+
127
use ark_ff::PrimeField;
228
use ark_std::log2;
329

@@ -42,6 +68,13 @@ pub struct CCS<F: PrimeField> {
4268

4369
impl<F: PrimeField> CCS<F> {
4470
/// Evaluates the CCS relation at a given vector of assignments `z`
71+
///
72+
/// # Errors
73+
///
74+
/// Returns an error if:
75+
/// * Vector operations fail due to mismatched dimensions
76+
/// * Matrix-vector multiplication fails
77+
/// * Vector addition or hadamard multiplication fails
4578
pub fn eval_at_z(&self, z: &[F]) -> Result<Vec<F>, Error> {
4679
let mut result = vec![F::zero(); self.m];
4780

@@ -51,7 +84,7 @@ impl<F: PrimeField> CCS<F> {
5184

5285
// complete the hadamard chain
5386
let mut hadamard_result = vec![F::one(); self.m];
54-
for M_j in vec_M_j.into_iter() {
87+
for M_j in vec_M_j {
5588
hadamard_result = hadamard(&hadamard_result, &mat_vec_mul(M_j, z)?)?;
5689
}
5790

@@ -67,7 +100,7 @@ impl<F: PrimeField> CCS<F> {
67100

68101
/// returns a tuple containing (w, x) (witness and public inputs respectively)
69102
pub fn split_z(&self, z: &[F]) -> (Vec<F>, Vec<F>) {
70-
(z[self.l + 1..].to_vec(), z[1..self.l + 1].to_vec())
103+
(z[self.l + 1..].to_vec(), z[1..=self.l].to_vec())
71104
}
72105
}
73106

@@ -101,7 +134,7 @@ impl<F: PrimeField> From<R1CS<F>> for CCS<F> {
101134
fn from(r1cs: R1CS<F>) -> Self {
102135
let m = r1cs.num_constraints();
103136
let n = r1cs.num_variables();
104-
CCS {
137+
Self {
105138
m,
106139
n,
107140
l: r1cs.num_public_inputs(),
@@ -130,6 +163,7 @@ pub mod tests {
130163
pub fn get_test_ccs<F: PrimeField>() -> CCS<F> {
131164
get_test_r1cs::<F>().into()
132165
}
166+
133167
pub fn get_test_z<F: PrimeField>(input: usize) -> Vec<F> {
134168
r1cs_get_test_z(input)
135169
}

folding-schemes/src/arith/mod.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,48 @@
1+
//! Trait definitions and implementations for arithmetic constraint systems.
2+
//!
3+
//! This module provides core abstractions for working with different types of arithmetic
4+
//! constraint systems like R1CS (Rank-1 Constraint Systems) and CCS (Customizable Constraint Systems).
5+
//! The key trait [`Arith`] defines a generic interface that constraint systems must implement,
6+
//! allowing the rest of the library to work with different constraint system implementations in a
7+
//! uniform way.
8+
//!
9+
//! # Key Traits
10+
//!
11+
//! * [`Arith`] - Core trait defining operations that constraint systems must support
12+
//! * [`ArithGadget`] - In-circuit counterpart operations for constraint systems
13+
//! * [`ArithSampler`] - Optional trait for sampling random satisfying witness-instance pairs
14+
//! * [`ArithSerializer`] - Serialization support for constraint systems
15+
//!
16+
//! # Modules
17+
//!
18+
//! * [`ccs`] - Implementation of Customizable Constraint Systems (CCS)
19+
//! * [`r1cs`] - Implementation of Rank-1 Constraint Systems (R1CS)
20+
//!
21+
//! # Examples of Supported Systems
22+
//!
23+
//! The module supports various constraint system types including:
24+
//!
25+
//! * Plain R1CS - Traditional rank-1 constraint systems
26+
//! * Nova's Relaxed R1CS - Modified R1CS with relaxation terms
27+
//! * ProtoGalaxy's Relaxed R1CS - Alternative relaxation approach
28+
//! * CCS - Customizable constraint systems with different witness/instance types
29+
//!
30+
//! Each system can define its own witness (`W`) and instance (`U`) types while implementing
31+
//! the common [`Arith`] interface, allowing for flexible constraint system implementations
32+
//! while maintaining a consistent API.
33+
//!
34+
//! # Evaluation Types
35+
//!
36+
//! Different constraint systems can have different evaluation semantics:
37+
//!
38+
//! * Plain R1CS evaluates to `Az ∘ Bz - Cz`
39+
//! * Nova's Relaxed R1CS evaluates to `Az ∘ Bz - uCz`
40+
//! * ProtoGalaxy's version evaluates to `Az ∘ Bz - Cz`
41+
//! * CCS can have various evaluation forms
42+
//!
43+
//! The [`Arith`] trait's associated `Evaluation` type allows each system to define its own
44+
//! evaluation result type while maintaining type safety.
45+
146
use ark_ec::CurveGroup;
247
use ark_relations::r1cs::SynthesisError;
348
use ark_std::rand::RngCore;
@@ -42,6 +87,7 @@ pub mod r1cs;
4287
/// elements, [`crate::folding::hypernova::Witness`] and [`crate::folding::hypernova::lcccs::LCCCS`],
4388
/// or [`crate::folding::hypernova::Witness`] and [`crate::folding::hypernova::cccs::CCCS`].
4489
pub trait Arith<W, U>: Clone {
90+
/// The type for the output of the relation's evalation.
4591
type Evaluation;
4692

4793
/// Returns a dummy witness and instance
@@ -64,11 +110,16 @@ pub trait Arith<W, U>: Clone {
64110
/// - Evaluating the relaxed R1CS in Nova at `W = (w, e, ...)` and
65111
/// `U = (u, x, ...)` returns `Az ∘ Bz - uCz`, where `z = [u, x, w]`.
66112
///
67-
/// - Evaluating the relaxed R1CS in ProtoGalaxy at `W = (w, ...)` and
113+
/// - Evaluating the relaxed R1CS in [`crate::folding::protogalaxy`] at `W = (w, ...)` and
68114
/// `U = (x, e, β, ...)` returns `Az ∘ Bz - Cz`, where `z = [1, x, w]`.
69115
///
70116
/// However, we use `Self::Evaluation` to represent the evaluation result
71117
/// for future extensibility.
118+
///
119+
/// # Errors
120+
/// Returns an error if:
121+
/// - The dimensions of vectors don't match the expected sizes
122+
/// - The evaluation calculations fail
72123
fn eval_relation(&self, w: &W, u: &U) -> Result<Self::Evaluation, Error>;
73124

74125
/// Checks if the evaluation result is valid. The witness `w` and instance
@@ -82,16 +133,27 @@ pub trait Arith<W, U>: Clone {
82133
/// - The evaluation `v` of relaxed R1CS in Nova at satisfying `W` and `U`
83134
/// should be equal to the error term `e` in the witness.
84135
///
85-
/// - The evaluation `v` of relaxed R1CS in ProtoGalaxy at satisfying `W`
136+
/// - The evaluation `v` of relaxed R1CS in [`crate::folding::protogalaxy`] at satisfying `W`
86137
/// and `U` should satisfy `e = Σ pow_i(β) v_i`, where `e` is the error
87138
/// term in the committed instance.
139+
///
140+
/// # Errors
141+
/// Returns an error if:
142+
/// - The evaluation result is not valid for the given witness and instance
143+
/// - The evaluation result fails to satisfy the constraint system requirements
88144
fn check_evaluation(w: &W, u: &U, v: Self::Evaluation) -> Result<(), Error>;
89145

90146
/// Checks if witness `w` and instance `u` satisfy the constraint system
91147
/// `self` by first computing the evaluation result and then checking the
92148
/// validity of the evaluation result.
93149
///
94150
/// Used only for testing.
151+
///
152+
/// # Errors
153+
/// Returns an error if:
154+
/// - The evaluation fails (`eval_relation` errors)
155+
/// - The evaluation check fails (`check_evaluation` errors)
156+
/// - The witness and instance do not satisfy the constraint system
95157
fn check_relation(&self, w: &W, u: &U) -> Result<(), Error> {
96158
let e = self.eval_relation(w, u)?;
97159
Self::check_evaluation(w, u, e)
@@ -125,6 +187,12 @@ pub trait ArithSerializer {
125187
/// [HyperNova]: https://eprint.iacr.org/2023/573.pdf
126188
pub trait ArithSampler<C: CurveGroup, W, U>: Arith<W, U> {
127189
/// Samples a random witness and instance that satisfy the constraint system.
190+
///
191+
/// # Errors
192+
/// Returns an error if:
193+
/// - Sampling of random values fails
194+
/// - The commitment scheme operations fail
195+
/// - The sampled values do not satisfy the constraint system
128196
fn sample_witness_instance<CS: CommitmentScheme<C, true>>(
129197
&self,
130198
params: &CS::ProverParams,
@@ -135,15 +203,28 @@ pub trait ArithSampler<C: CurveGroup, W, U>: Arith<W, U> {
135203
/// `ArithGadget` defines the in-circuit counterparts of operations specified in
136204
/// `Arith` on constraint systems.
137205
pub trait ArithGadget<WVar, UVar> {
206+
/// The type for the output of the relation's evalation.
138207
type Evaluation;
139208

140209
/// Evaluates the constraint system `self` at witness `w` and instance `u`.
141210
/// Returns the evaluation result.
211+
///
212+
/// # Errors
213+
/// Returns a `SynthesisError` if:
214+
/// - Circuit constraint generation fails
215+
/// - Variable allocation fails
216+
/// - Required witness values are missing
142217
fn eval_relation(&self, w: &WVar, u: &UVar) -> Result<Self::Evaluation, SynthesisError>;
143218

144219
/// Generates constraints for enforcing that witness `w` and instance `u`
145220
/// satisfy the constraint system `self` by first computing the evaluation
146221
/// result and then checking the validity of the evaluation result.
222+
///
223+
/// # Errors
224+
/// Returns a `SynthesisError` if:
225+
/// - The evaluation fails (`eval_relation` errors)
226+
/// - The enforcement of evaluation constraints fails
227+
/// - Circuit constraint generation fails
147228
fn enforce_relation(&self, w: &WVar, u: &UVar) -> Result<(), SynthesisError> {
148229
let e = self.eval_relation(w, u)?;
149230
Self::enforce_evaluation(w, u, e)
@@ -152,5 +233,10 @@ pub trait ArithGadget<WVar, UVar> {
152233
/// Generates constraints for enforcing that the evaluation result is valid.
153234
/// The witness `w` and instance `u` are also parameters, because the
154235
/// validity check may need information contained in `w` and/or `u`.
236+
///
237+
/// # Errors
238+
/// Returns a `SynthesisError` if:
239+
/// - Circuit constraint generation fails for the evaluation check
240+
/// - The enforcement of evaluation constraints fails
155241
fn enforce_evaluation(w: &WVar, u: &UVar, e: Self::Evaluation) -> Result<(), SynthesisError>;
156242
}

folding-schemes/src/arith/r1cs/circuits.rs

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
//! Circuit implementations for Rank-1 Constraint Systems (R1CS).
2+
//!
3+
//! This module provides an in-circuit representation of R1CS for use within other circuits.
4+
//! It includes support for both native field operations and non-native field arithmetic
5+
//! through generic matrix and vector operations.
6+
17
use crate::{
28
arith::ArithGadget,
39
utils::gadgets::{EquivalenceGadget, MatrixGadget, SparseMatrixVar, VectorGadget},
@@ -11,19 +17,44 @@ use super::R1CS;
1117

1218
/// An in-circuit representation of the `R1CS` struct.
1319
///
14-
/// `M` is for the modulo operation involved in the satisfiability check when
15-
/// the underlying `FVar` is `NonNativeUintVar`.
20+
/// This gadget allows R1CS operations to be performed within another constraint system.
21+
///
22+
/// # Type Parameters
23+
///
24+
/// * `M` - Type for the modulo operation in satisfiability checks when `FVar` is `NonNativeUintVar`
25+
/// * `FVar` - Variable type representing field elements in the circuit
1626
#[derive(Debug, Clone)]
1727
pub struct R1CSMatricesVar<M, FVar> {
28+
/// Phantom data for the modulo type
1829
_m: PhantomData<M>,
30+
/// In-circuit representation of matrix A
1931
pub A: SparseMatrixVar<FVar>,
32+
/// In-circuit representation of matrix B
2033
pub B: SparseMatrixVar<FVar>,
34+
/// In-circuit representation of matrix C
2135
pub C: SparseMatrixVar<FVar>,
2236
}
2337

2438
impl<F: PrimeField, ConstraintF: PrimeField, FVar: AllocVar<F, ConstraintF>>
2539
AllocVar<R1CS<F>, ConstraintF> for R1CSMatricesVar<F, FVar>
2640
{
41+
/// Creates a new circuit representation of R1CS matrices
42+
///
43+
/// # Type Parameters
44+
///
45+
/// * `T` - Type that can be borrowed as `R1CS<F>`
46+
///
47+
/// # Arguments
48+
///
49+
/// * `cs` - Constraint system handle
50+
/// * `f` - Function that returns the R1CS to be converted to circuit form
51+
/// * `_mode` - Allocation mode (unused as matrices are allocated as constants)
52+
///
53+
/// # Errors
54+
///
55+
/// Returns a `SynthesisError` if:
56+
/// * Matrix conversion to circuit form fails
57+
/// * Circuit variable allocation fails
2758
fn new_variable<T: Borrow<R1CS<F>>>(
2859
cs: impl Into<Namespace<ConstraintF>>,
2960
f: impl FnOnce() -> Result<T, SynthesisError>,
@@ -32,11 +63,12 @@ impl<F: PrimeField, ConstraintF: PrimeField, FVar: AllocVar<F, ConstraintF>>
3263
f().and_then(|val| {
3364
let cs = cs.into();
3465

66+
// TODO (autoparallel): How expensive are these clones? Is there a cheaper way to do this?
3567
Ok(Self {
3668
_m: PhantomData,
3769
A: SparseMatrixVar::<FVar>::new_constant(cs.clone(), &val.borrow().A)?,
3870
B: SparseMatrixVar::<FVar>::new_constant(cs.clone(), &val.borrow().B)?,
39-
C: SparseMatrixVar::<FVar>::new_constant(cs.clone(), &val.borrow().C)?,
71+
C: SparseMatrixVar::<FVar>::new_constant(cs, &val.borrow().C)?,
4072
})
4173
})
4274
}
@@ -47,6 +79,24 @@ where
4779
SparseMatrixVar<FVar>: MatrixGadget<FVar>,
4880
[FVar]: VectorGadget<FVar>,
4981
{
82+
/// Evaluates the R1CS matrices at given circuit variable assignments
83+
///
84+
/// # Arguments
85+
///
86+
/// * `z` - Vector of circuit variables to evaluate at
87+
///
88+
/// # Returns
89+
///
90+
/// Returns a tuple (AzBz, uCz) where:
91+
/// * AzBz is the Hadamard product of Az and Bz
92+
/// * uCz is Cz scaled by z[0]
93+
///
94+
/// # Errors
95+
///
96+
/// Returns a `SynthesisError` if:
97+
/// * Matrix-vector multiplication fails
98+
/// * Hadamard product computation fails
99+
/// * Vector operations fail
50100
pub fn eval_at_z(&self, z: &[FVar]) -> Result<(Vec<FVar>, Vec<FVar>), SynthesisError> {
51101
// Multiply Cz by z[0] (u) here, allowing this method to be reused for
52102
// both relaxed and unrelaxed R1CS.
@@ -225,7 +275,7 @@ pub mod tests {
225275
impl<F: PrimeField> ConstraintSynthesizer<F> for Sha256TestCircuit<F> {
226276
fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
227277
let x = Vec::<UInt8<F>>::new_witness(cs.clone(), || Ok(self.x))?;
228-
let y = Vec::<UInt8<F>>::new_input(cs.clone(), || Ok(self.y))?;
278+
let y = Vec::<UInt8<F>>::new_input(cs, || Ok(self.y))?;
229279

230280
let unitVar = UnitVar::default();
231281
let comp_y = <Sha256Gadget<F> as CRHSchemeGadget<Sha256, F>>::evaluate(&unitVar, &x)?;
@@ -289,15 +339,14 @@ pub mod tests {
289339
let cs = ConstraintSystem::<Fq>::new_ref();
290340
let wVar = WitnessVar::new_witness(cs.clone(), || Ok(&w))?;
291341
let uVar = CommittedInstanceVar::new_witness(cs.clone(), || Ok(&u))?;
292-
let r1csVar = R1CSMatricesVar::<Fq, FpVar<Fq>>::new_witness(cs.clone(), || Ok(&r1cs))?;
342+
let r1csVar = R1CSMatricesVar::<Fq, FpVar<Fq>>::new_witness(cs, || Ok(&r1cs))?;
293343
r1csVar.enforce_relation(&wVar, &uVar)?;
294344

295345
// non-natively
296346
let cs = ConstraintSystem::<Fr>::new_ref();
297347
let wVar = CycleFoldWitnessVar::new_witness(cs.clone(), || Ok(w))?;
298348
let uVar = CycleFoldCommittedInstanceVar::<_, GVar2>::new_witness(cs.clone(), || Ok(u))?;
299-
let r1csVar =
300-
R1CSMatricesVar::<Fq, NonNativeUintVar<Fr>>::new_witness(cs.clone(), || Ok(r1cs))?;
349+
let r1csVar = R1CSMatricesVar::<Fq, NonNativeUintVar<Fr>>::new_witness(cs, || Ok(r1cs))?;
301350
r1csVar.enforce_relation(&wVar, &uVar)?;
302351
Ok(())
303352
}

0 commit comments

Comments
 (0)