Generalized CycleFold (#120)

* Support randomness of arbitrary length

* Rename `N_BITS_RO` to `NOVA_N_BITS_RO`

* Compute `r_nonnat` inside `NIFSFullGadget::fold_committed_instance`

* Format

* Use `CycleFold{CommittedInstance, Witness}` in the context of cyclefold

* Format

* Fix the creation of dummy witness

* Make clippy happy

* Improve docs
This commit is contained in:
winderica
2024-08-05 11:11:49 +01:00
committed by GitHub
parent 18a3e0aa93
commit ecaecd483c
13 changed files with 554 additions and 486 deletions

View File

@@ -2,4 +2,4 @@
// From [Srinath Setty](https://microsoft.com/en-us/research/people/srinath/): In Nova, soundness // From [Srinath Setty](https://microsoft.com/en-us/research/people/srinath/): In Nova, soundness
// error ≤ 2/|S|, where S is the subset of the field F from which the challenges are drawn. In this // error ≤ 2/|S|, where S is the subset of the field F from which the challenges are drawn. In this
// case, we keep the size of S close to 2^128. // case, we keep the size of S close to 2^128.
pub const N_BITS_RO: usize = 128; pub const NOVA_N_BITS_RO: usize = 128;

View File

@@ -1,8 +1,8 @@
/// Contains [CycleFold](https://eprint.iacr.org/2023/1192.pdf) related circuits and functions that /// Contains [CycleFold](https://eprint.iacr.org/2023/1192.pdf) related circuits and functions that
/// are shared across the different folding schemes /// are shared across the different folding schemes
use ark_crypto_primitives::sponge::{Absorb, CryptographicSponge}; use ark_crypto_primitives::sponge::{Absorb, CryptographicSponge};
use ark_ec::{CurveGroup, Group}; use ark_ec::{AffineRepr, CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField}; use ark_ff::{BigInteger, Field, PrimeField};
use ark_r1cs_std::{ use ark_r1cs_std::{
alloc::{AllocVar, AllocationMode}, alloc::{AllocVar, AllocationMode},
boolean::Boolean, boolean::Boolean,
@@ -20,25 +20,22 @@ use ark_std::rand::RngCore;
use ark_std::Zero; use ark_std::Zero;
use core::{borrow::Borrow, marker::PhantomData}; use core::{borrow::Borrow, marker::PhantomData};
use super::{nonnative::uint::NonNativeUintVar, CF2}; use super::{nonnative::uint::NonNativeUintVar, CF1, CF2};
use crate::arith::r1cs::{extract_w_x, R1CS}; use crate::arith::r1cs::{extract_w_x, R1CS};
use crate::commitment::CommitmentScheme; use crate::commitment::CommitmentScheme;
use crate::constants::N_BITS_RO; use crate::constants::NOVA_N_BITS_RO;
use crate::folding::nova::{nifs::NIFS, CommittedInstance, Witness}; use crate::folding::nova::nifs::NIFS;
use crate::frontend::FCircuit; use crate::transcript::{AbsorbNonNative, AbsorbNonNativeGadget, Transcript, TranscriptVar};
use crate::transcript::{AbsorbNonNativeGadget, Transcript, TranscriptVar};
use crate::Error; use crate::Error;
/// Public inputs length for the CycleFoldCircuit: /// Re-export the Nova committed instance as `CycleFoldCommittedInstance` and
/// For Nova this is: |[r, p1.x,y, p2.x,y, p3.x,y]| /// witness as `CycleFoldWitness`, for clarity and consistency
/// In general, |[r * (n_points-1), (p_i.x,y)*n_points, p_folded.x,y]|, thus, io len is: pub use crate::folding::nova::{
/// (n_points-1) + 2*n_points + 2 CommittedInstance as CycleFoldCommittedInstance, Witness as CycleFoldWitness,
pub fn cf_io_len(n_points: usize) -> usize { };
(n_points - 1) + 2 * n_points + 2
}
/// CycleFoldCommittedInstanceVar is the CycleFold CommittedInstance representation in the Nova /// CycleFoldCommittedInstanceVar is the CycleFold CommittedInstance represented
/// circuit. /// in folding verifier circuit
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CycleFoldCommittedInstanceVar<C: CurveGroup, GC: CurveVar<C, CF2<C>>> pub struct CycleFoldCommittedInstanceVar<C: CurveGroup, GC: CurveVar<C, CF2<C>>>
where where
@@ -49,14 +46,14 @@ where
pub cmW: GC, pub cmW: GC,
pub x: Vec<NonNativeUintVar<CF2<C>>>, pub x: Vec<NonNativeUintVar<CF2<C>>>,
} }
impl<C, GC> AllocVar<CommittedInstance<C>, CF2<C>> for CycleFoldCommittedInstanceVar<C, GC> impl<C, GC> AllocVar<CycleFoldCommittedInstance<C>, CF2<C>> for CycleFoldCommittedInstanceVar<C, GC>
where where
C: CurveGroup, C: CurveGroup,
GC: CurveVar<C, CF2<C>>, GC: CurveVar<C, CF2<C>>,
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField, <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{ {
fn new_variable<T: Borrow<CommittedInstance<C>>>( fn new_variable<T: Borrow<CycleFoldCommittedInstance<C>>>(
cs: impl Into<Namespace<CF2<C>>>, cs: impl Into<Namespace<CF2<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode, mode: AllocationMode,
@@ -74,6 +71,29 @@ where
} }
} }
impl<C: CurveGroup> AbsorbNonNative<C::BaseField> for CycleFoldCommittedInstance<C>
where
C::BaseField: PrimeField + Absorb,
{
// Compatible with the in-circuit `CycleFoldCommittedInstanceVar::to_native_sponge_field_elements`
fn to_native_sponge_field_elements(&self, dest: &mut Vec<C::BaseField>) {
[self.u].to_native_sponge_field_elements(dest);
self.x.to_native_sponge_field_elements(dest);
let (cmE_x, cmE_y) = match self.cmE.into_affine().xy() {
Some((&x, &y)) => (x, y),
None => (C::BaseField::zero(), C::BaseField::zero()),
};
let (cmW_x, cmW_y) = match self.cmW.into_affine().xy() {
Some((&x, &y)) => (x, y),
None => (C::BaseField::zero(), C::BaseField::zero()),
};
cmE_x.to_sponge_field_elements(dest);
cmE_y.to_sponge_field_elements(dest);
cmW_x.to_sponge_field_elements(dest);
cmW_y.to_sponge_field_elements(dest);
}
}
impl<C, GC> AbsorbNonNativeGadget<C::BaseField> for CycleFoldCommittedInstanceVar<C, GC> impl<C, GC> AbsorbNonNativeGadget<C::BaseField> for CycleFoldCommittedInstanceVar<C, GC>
where where
C: CurveGroup, C: CurveGroup,
@@ -107,6 +127,25 @@ where
} }
} }
impl<C: CurveGroup> CycleFoldCommittedInstance<C>
where
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField + Absorb,
{
/// hash_cyclefold implements the committed instance hash compatible with the
/// in-circuit implementation `CycleFoldCommittedInstanceVar::hash`.
/// Returns `H(U_i)`, where `U_i` is a `CycleFoldCommittedInstance`.
pub fn hash_cyclefold<T: Transcript<C::BaseField>>(
&self,
sponge: &T,
pp_hash: C::BaseField, // public params hash
) -> C::BaseField {
let mut sponge = sponge.clone();
sponge.absorb(&pp_hash);
sponge.absorb_nonnative(self);
sponge.squeeze_field_elements(1)[0]
}
}
impl<C, GC> CycleFoldCommittedInstanceVar<C, GC> impl<C, GC> CycleFoldCommittedInstanceVar<C, GC>
where where
C: CurveGroup, C: CurveGroup,
@@ -114,11 +153,13 @@ where
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField + Absorb, <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField + Absorb,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{ {
/// hash implements the committed instance hash compatible with the native implementation from /// hash implements the committed instance hash compatible with the native
/// CommittedInstance.hash_cyclefold. Returns `H(U_i)`, where `U` is the `CommittedInstance` /// implementation `CycleFoldCommittedInstance::hash_cyclefold`.
/// for CycleFold. Additionally it returns the vector of the field elements from the self /// Returns `H(U_i)`, where `U` is a `CycleFoldCommittedInstanceVar`.
/// parameters, so they can be reused in other gadgets avoiding recalculating (reconstraining) ///
/// them. /// Additionally it returns the vector of the field elements from the self
/// parameters, so they can be reused in other gadgets without recalculating
/// (reconstraining) them.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn hash<S: CryptographicSponge, T: TranscriptVar<CF2<C>, S>>( pub fn hash<S: CryptographicSponge, T: TranscriptVar<CF2<C>, S>>(
self, self,
@@ -147,13 +188,14 @@ where
pub cmW: GC, pub cmW: GC,
} }
impl<C, GC> AllocVar<CommittedInstance<C>, CF2<C>> for CommittedInstanceInCycleFoldVar<C, GC> impl<C, GC> AllocVar<CycleFoldCommittedInstance<C>, CF2<C>>
for CommittedInstanceInCycleFoldVar<C, GC>
where where
C: CurveGroup, C: CurveGroup,
GC: CurveVar<C, CF2<C>>, GC: CurveVar<C, CF2<C>>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{ {
fn new_variable<T: Borrow<CommittedInstance<C>>>( fn new_variable<T: Borrow<CycleFoldCommittedInstance<C>>>(
cs: impl Into<Namespace<CF2<C>>>, cs: impl Into<Namespace<CF2<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode, mode: AllocationMode,
@@ -189,25 +231,29 @@ where
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{ {
pub fn fold_committed_instance( pub fn fold_committed_instance(
// assumes that r_bits is equal to r_nonnat just that in a different format
r_bits: Vec<Boolean<CF2<C>>>, r_bits: Vec<Boolean<CF2<C>>>,
r_nonnat: NonNativeUintVar<CF2<C>>,
cmT: GC, cmT: GC,
ci1: CycleFoldCommittedInstanceVar<C, GC>, ci1: CycleFoldCommittedInstanceVar<C, GC>,
// ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method) // ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method)
ci2: CycleFoldCommittedInstanceVar<C, GC>, ci2: CycleFoldCommittedInstanceVar<C, GC>,
) -> Result<CycleFoldCommittedInstanceVar<C, GC>, SynthesisError> { ) -> Result<CycleFoldCommittedInstanceVar<C, GC>, SynthesisError> {
// r_nonnat is equal to r_bits just that in a different format
let r_nonnat = {
let mut bits = r_bits.clone();
bits.resize(CF1::<C>::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
};
Ok(CycleFoldCommittedInstanceVar { Ok(CycleFoldCommittedInstanceVar {
cmE: cmT.scalar_mul_le(r_bits.iter())? + ci1.cmE, cmE: cmT.scalar_mul_le(r_bits.iter())? + ci1.cmE,
cmW: ci1.cmW + ci2.cmW.scalar_mul_le(r_bits.iter())?, cmW: ci1.cmW + ci2.cmW.scalar_mul_le(r_bits.iter())?,
u: ci1.u.add_no_align(&r_nonnat).modulo::<C::ScalarField>()?, u: ci1.u.add_no_align(&r_nonnat).modulo::<CF1<C>>()?,
x: ci1 x: ci1
.x .x
.iter() .iter()
.zip(ci2.x) .zip(ci2.x)
.map(|(a, b)| { .map(|(a, b)| {
a.add_no_align(&r_nonnat.mul_no_align(&b)?) a.add_no_align(&r_nonnat.mul_no_align(&b)?)
.modulo::<C::ScalarField>() .modulo::<CF1<C>>()
}) })
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?,
}) })
@@ -216,14 +262,13 @@ where
pub fn verify( pub fn verify(
// assumes that r_bits is equal to r_nonnat just that in a different format // assumes that r_bits is equal to r_nonnat just that in a different format
r_bits: Vec<Boolean<CF2<C>>>, r_bits: Vec<Boolean<CF2<C>>>,
r_nonnat: NonNativeUintVar<CF2<C>>,
cmT: GC, cmT: GC,
ci1: CycleFoldCommittedInstanceVar<C, GC>, ci1: CycleFoldCommittedInstanceVar<C, GC>,
// ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method) // ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method)
ci2: CycleFoldCommittedInstanceVar<C, GC>, ci2: CycleFoldCommittedInstanceVar<C, GC>,
ci3: CycleFoldCommittedInstanceVar<C, GC>, ci3: CycleFoldCommittedInstanceVar<C, GC>,
) -> Result<(), SynthesisError> { ) -> Result<(), SynthesisError> {
let ci = Self::fold_committed_instance(r_bits, r_nonnat, cmT, ci1, ci2)?; let ci = Self::fold_committed_instance(r_bits, cmT, ci1, ci2)?;
ci.cmE.enforce_equal(&ci3.cmE)?; ci.cmE.enforce_equal(&ci3.cmE)?;
ci.u.enforce_equal_unaligned(&ci3.u)?; ci.u.enforce_equal_unaligned(&ci3.u)?;
@@ -253,15 +298,15 @@ where
pub fn get_challenge_native<T: Transcript<C::BaseField>>( pub fn get_challenge_native<T: Transcript<C::BaseField>>(
transcript: &mut T, transcript: &mut T,
pp_hash: C::BaseField, // public params hash pp_hash: C::BaseField, // public params hash
U_i: CommittedInstance<C>, U_i: CycleFoldCommittedInstance<C>,
u_i: CommittedInstance<C>, u_i: CycleFoldCommittedInstance<C>,
cmT: C, cmT: C,
) -> Vec<bool> { ) -> Vec<bool> {
transcript.absorb(&pp_hash); transcript.absorb(&pp_hash);
transcript.absorb_nonnative(&U_i); transcript.absorb_nonnative(&U_i);
transcript.absorb_nonnative(&u_i); transcript.absorb_nonnative(&u_i);
transcript.absorb_point(&cmT); transcript.absorb_point(&cmT);
transcript.squeeze_bits(N_BITS_RO) transcript.squeeze_bits(NOVA_N_BITS_RO)
} }
// compatible with the native get_challenge_native // compatible with the native get_challenge_native
@@ -276,63 +321,101 @@ where
transcript.absorb(&U_i_vec)?; transcript.absorb(&U_i_vec)?;
transcript.absorb_nonnative(&u_i)?; transcript.absorb_nonnative(&u_i)?;
transcript.absorb_point(&cmT)?; transcript.absorb_point(&cmT)?;
transcript.squeeze_bits(N_BITS_RO) transcript.squeeze_bits(NOVA_N_BITS_RO)
} }
} }
pub trait CycleFoldConfig {
/// `N_INPUT_POINTS` specifies the number of input points that are folded in
/// [`CycleFoldCircuit`] via random linear combinations.
const N_INPUT_POINTS: usize;
/// `RANDOMNESS_BIT_LENGTH` is the (maximum) bit length of randomness `r`.
const RANDOMNESS_BIT_LENGTH: usize;
/// `FIELD_CAPACITY` is the maximum number of bits that can be stored in a
/// field element.
///
/// E.g., given a randomness `r` with `RANDOMNESS_BIT_LENGTH` bits, we need
/// `RANDOMNESS_BIT_LENGTH / FIELD_CAPACITY` field elements to represent `r`
/// compactly in-circuit.
const FIELD_CAPACITY: usize = CF2::<Self::C>::MODULUS_BIT_SIZE as usize - 1;
/// Public inputs length for the CycleFoldCircuit.
/// * For Nova this is: `|[r, p1.x,y, p2.x,y, p3.x,y]|`
/// * In general, `|[r * (n_points-1), (p_i.x,y)*n_points, p_folded.x,y]|`.
///
/// Thus, `IO_LEN` is:
/// `RANDOMNESS_BIT_LENGTH / FIELD_CAPACITY * (N_INPUT_POINTS - 1) + 2 * N_INPUT_POINTS + 2`
const IO_LEN: usize = {
Self::RANDOMNESS_BIT_LENGTH.div_ceil(Self::FIELD_CAPACITY) * (Self::N_INPUT_POINTS - 1)
+ 2 * Self::N_INPUT_POINTS
+ 2
};
type F: Field;
type C: CurveGroup<BaseField = Self::F>;
}
/// CycleFoldCircuit contains the constraints that check the correct fold of the committed /// CycleFoldCircuit contains the constraints that check the correct fold of the committed
/// instances from Curve1. Namely, it checks the random linear combinations of the elliptic curve /// instances from Curve1. Namely, it checks the random linear combinations of the elliptic curve
/// (Curve1) points of u_i, U_i leading to U_{i+1} /// (Curve1) points of u_i, U_i leading to U_{i+1}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CycleFoldCircuit<C: CurveGroup, GC: CurveVar<C, CF2<C>>> { pub struct CycleFoldCircuit<CFG: CycleFoldConfig, GC: CurveVar<CFG::C, CFG::F>> {
pub _gc: PhantomData<GC>, pub _gc: PhantomData<GC>,
/// number of points being folded
pub n_points: usize,
/// r_bits is a vector containing the r_bits, one for each point except for the first one. They /// r_bits is a vector containing the r_bits, one for each point except for the first one. They
/// are used for the scalar multiplication of the points. The r_bits are the bit /// are used for the scalar multiplication of the points. The r_bits are the bit
/// representation of each power of r (in Fr, while the CycleFoldCircuit is in Fq). /// representation of each power of r (in Fr, while the CycleFoldCircuit is in Fq).
pub r_bits: Option<Vec<Vec<bool>>>, pub r_bits: Option<Vec<Vec<bool>>>,
/// points to be folded in the CycleFoldCircuit /// points to be folded in the CycleFoldCircuit
pub points: Option<Vec<C>>, pub points: Option<Vec<CFG::C>>,
pub x: Option<Vec<CF2<C>>>, // public inputs (cf_u_{i+1}.x) /// public inputs (cf_u_{i+1}.x)
pub x: Option<Vec<CFG::F>>,
} }
impl<C: CurveGroup, GC: CurveVar<C, CF2<C>>> CycleFoldCircuit<C, GC> {
impl<CFG: CycleFoldConfig, GC: CurveVar<CFG::C, CFG::F>> CycleFoldCircuit<CFG, GC> {
/// n_points indicates the number of points being folded in the CycleFoldCircuit /// n_points indicates the number of points being folded in the CycleFoldCircuit
pub fn empty(n_points: usize) -> Self { pub fn empty() -> Self {
Self { Self {
_gc: PhantomData, _gc: PhantomData,
n_points,
r_bits: None, r_bits: None,
points: None, points: None,
x: None, x: None,
} }
} }
} }
impl<C, GC> ConstraintSynthesizer<CF2<C>> for CycleFoldCircuit<C, GC>
impl<CFG: CycleFoldConfig, GC: CurveVar<CFG::C, CFG::F>> ConstraintSynthesizer<CFG::F>
for CycleFoldCircuit<CFG, GC>
where where
C: CurveGroup, GC: ToConstraintFieldGadget<CFG::F>,
GC: CurveVar<C, CF2<C>> + ToConstraintFieldGadget<CF2<C>>, CFG::F: PrimeField,
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField, for<'a> &'a GC: GroupOpsBounds<'a, CFG::C, GC>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{ {
fn generate_constraints(self, cs: ConstraintSystemRef<CF2<C>>) -> Result<(), SynthesisError> { fn generate_constraints(self, cs: ConstraintSystemRef<CFG::F>) -> Result<(), SynthesisError> {
let r_bits: Vec<Vec<Boolean<CF2<C>>>> = self let r_bits: Vec<Vec<Boolean<CFG::F>>> = self
.r_bits .r_bits
// n_points-1, bcs is one for each point except for the first one // n_points-1, bcs is one for each point except for the first one
.unwrap_or(vec![vec![false; N_BITS_RO]; self.n_points - 1]) .unwrap_or(vec![
vec![false; CFG::RANDOMNESS_BIT_LENGTH];
CFG::N_INPUT_POINTS - 1
])
.iter() .iter()
.map(|r_bits_i| { .map(|r_bits_i| {
Vec::<Boolean<CF2<C>>>::new_witness(cs.clone(), || Ok(r_bits_i.clone())) Vec::<Boolean<CFG::F>>::new_witness(cs.clone(), || Ok(r_bits_i.clone()))
}) })
.collect::<Result<Vec<Vec<Boolean<CF2<C>>>>, SynthesisError>>()?; .collect::<Result<_, _>>()?;
let points = Vec::<GC>::new_witness(cs.clone(), || { let points = Vec::<GC>::new_witness(cs.clone(), || {
Ok(self.points.unwrap_or(vec![C::zero(); self.n_points])) Ok(self
.points
.unwrap_or(vec![CFG::C::zero(); CFG::N_INPUT_POINTS]))
})?; })?;
#[cfg(test)] #[cfg(test)]
{ {
assert_eq!(self.n_points, points.len()); assert_eq!(CFG::N_INPUT_POINTS, points.len());
assert_eq!(self.n_points - 1, r_bits.len()); assert_eq!(CFG::N_INPUT_POINTS - 1, r_bits.len());
for r_bits_i in &r_bits {
assert_eq!(r_bits_i.len(), CFG::RANDOMNESS_BIT_LENGTH);
}
} }
// Fold the original points of the instances natively in CycleFold. // Fold the original points of the instances natively in CycleFold.
@@ -343,36 +426,37 @@ where
let mut p_folded: GC = points[0].clone(); let mut p_folded: GC = points[0].clone();
// iter over n_points-1 because the first point is not multiplied by r^i (it is multiplied // iter over n_points-1 because the first point is not multiplied by r^i (it is multiplied
// by r^0=1) // by r^0=1)
for i in 0..self.n_points - 1 { for i in 0..CFG::N_INPUT_POINTS - 1 {
p_folded += points[i + 1].scalar_mul_le(r_bits[i].iter())?; p_folded += points[i + 1].scalar_mul_le(r_bits[i].iter())?;
} }
let x = Vec::<FpVar<CF2<C>>>::new_input(cs.clone(), || { let x = Vec::<FpVar<CFG::F>>::new_input(cs.clone(), || {
Ok(self Ok(self.x.unwrap_or(vec![CFG::F::zero(); CFG::IO_LEN]))
.x
.unwrap_or(vec![CF2::<C>::zero(); cf_io_len(self.n_points)]))
})?; })?;
#[cfg(test)] #[cfg(test)]
assert_eq!(x.len(), cf_io_len(self.n_points)); // non-constrained sanity check assert_eq!(x.len(), CFG::IO_LEN); // non-constrained sanity check
// Check that the points coordinates are placed as the public input x: // Check that the points coordinates are placed as the public input x:
// In Nova, this is: x == [r, p1, p2, p3] (wheere p3 is the p_folded). // In Nova, this is: x == [r, p1, p2, p3] (wheere p3 is the p_folded).
// In multifolding schemes such as HyperNova, this is: // In multifolding schemes such as HyperNova, this is:
// computed_x = [r_0, r_1, r_2, ..., r_n, p_0, p_1, p_2, ..., p_n, p_folded], // computed_x = [r_0, r_1, r_2, ..., r_n, p_0, p_1, p_2, ..., p_n, p_folded],
// where each p_i is in fact p_i.to_constraint_field() // where each p_i is in fact p_i.to_constraint_field()
let computed_x: Vec<FpVar<CF2<C>>> = [ let computed_x: Vec<FpVar<CFG::F>> = r_bits
r_bits .iter()
.iter() .map(|r_bits_i| {
.map(|r_bits_i| Boolean::le_bits_to_fp_var(r_bits_i)) r_bits_i
.collect::<Result<Vec<FpVar<CF2<C>>>, SynthesisError>>()?, .chunks(CFG::FIELD_CAPACITY)
points .map(Boolean::le_bits_to_fp_var)
.iter() .collect::<Result<Vec<_>, _>>()
.map(|p_i| Ok(p_i.to_constraint_field()?[..2].to_vec())) })
.collect::<Result<Vec<Vec<FpVar<CF2<C>>>>, SynthesisError>>()? .chain(
.concat(), points
p_folded.to_constraint_field()?[..2].to_vec(), .iter()
] .chain(&[p_folded])
.concat(); .map(|p_i| Ok(p_i.to_constraint_field()?[..2].to_vec())),
)
.collect::<Result<Vec<_>, _>>()?
.concat();
computed_x.enforce_equal(&x)?; computed_x.enforce_equal(&x)?;
Ok(()) Ok(())
@@ -383,35 +467,33 @@ where
/// scheme struct because it is used both by Nova & HyperNova's CycleFold. /// scheme struct because it is used both by Nova & HyperNova's CycleFold.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn fold_cyclefold_circuit<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool>( pub fn fold_cyclefold_circuit<CFG, C1, GC1, C2, GC2, CS2, const H: bool>(
_n_points: usize,
transcript: &mut impl Transcript<C1::ScalarField>, transcript: &mut impl Transcript<C1::ScalarField>,
cf_r1cs: R1CS<C2::ScalarField>, cf_r1cs: R1CS<C2::ScalarField>,
cf_cs_params: CS2::ProverParams, cf_cs_params: CS2::ProverParams,
pp_hash: C1::ScalarField, // public params hash pp_hash: C1::ScalarField, // public params hash
cf_W_i: Witness<C2>, // witness of the running instance cf_W_i: CycleFoldWitness<C2>, // witness of the running instance
cf_U_i: CommittedInstance<C2>, // running instance cf_U_i: CycleFoldCommittedInstance<C2>, // running instance
cf_u_i_x: Vec<C2::ScalarField>, cf_u_i_x: Vec<C2::ScalarField>,
cf_circuit: CycleFoldCircuit<C1, GC1>, cf_circuit: CycleFoldCircuit<CFG, GC1>,
mut rng: impl RngCore, mut rng: impl RngCore,
) -> Result< ) -> Result<
( (
Witness<C2>, CycleFoldWitness<C2>,
CommittedInstance<C2>, // u_i CycleFoldCommittedInstance<C2>, // u_i
Witness<C2>, // W_i1 CycleFoldWitness<C2>, // W_i1
CommittedInstance<C2>, // U_i1 CycleFoldCommittedInstance<C2>, // U_i1
C2, // cmT C2, // cmT
C2::ScalarField, // r_Fq C2::ScalarField, // r_Fq
), ),
Error, Error,
> >
where where
CFG: CycleFoldConfig<C = C1, F = CF2<C1>>,
C1: CurveGroup, C1: CurveGroup,
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>, GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
C2: CurveGroup, C2: CurveGroup,
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>, GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
FC: FCircuit<C1::ScalarField>,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>, CS2: CommitmentScheme<C2, H>,
<C1 as CurveGroup>::BaseField: PrimeField, <C1 as CurveGroup>::BaseField: PrimeField,
<C2 as CurveGroup>::BaseField: PrimeField, <C2 as CurveGroup>::BaseField: PrimeField,
@@ -431,11 +513,12 @@ where
} }
#[cfg(test)] #[cfg(test)]
assert_eq!(cf_x_i.len(), cf_io_len(_n_points)); assert_eq!(cf_x_i.len(), CFG::IO_LEN);
// fold cyclefold instances // fold cyclefold instances
let cf_w_i = Witness::<C2>::new::<H>(cf_w_i.clone(), cf_r1cs.A.n_rows, &mut rng); let cf_w_i = CycleFoldWitness::<C2>::new::<H>(cf_w_i.clone(), cf_r1cs.A.n_rows, &mut rng);
let cf_u_i: CommittedInstance<C2> = cf_w_i.commit::<CS2, H>(&cf_cs_params, cf_x_i.clone())?; let cf_u_i: CycleFoldCommittedInstance<C2> =
cf_w_i.commit::<CS2, H>(&cf_cs_params, cf_x_i.clone())?;
// compute T* and cmT* for CycleFoldCircuit // compute T* and cmT* for CycleFoldCircuit
let (cf_T, cf_cmT) = NIFS::<C2, CS2, H>::compute_cyclefold_cmT( let (cf_T, cf_cmT) = NIFS::<C2, CS2, H>::compute_cyclefold_cmT(
@@ -478,11 +561,22 @@ pub mod tests {
use crate::transcript::poseidon::poseidon_canonical_config; use crate::transcript::poseidon::poseidon_canonical_config;
use crate::utils::get_cm_coordinates; use crate::utils::get_cm_coordinates;
struct TestCycleFoldConfig<C: CurveGroup> {
_c: PhantomData<C>,
}
impl<C: CurveGroup> CycleFoldConfig for TestCycleFoldConfig<C> {
const RANDOMNESS_BIT_LENGTH: usize = NOVA_N_BITS_RO;
const N_INPUT_POINTS: usize = 2;
type C = C;
type F = C::BaseField;
}
#[test] #[test]
fn test_committed_instance_cyclefold_var() { fn test_committed_instance_cyclefold_var() {
let mut rng = ark_std::test_rng(); let mut rng = ark_std::test_rng();
let ci = CommittedInstance::<Projective> { let ci = CycleFoldCommittedInstance::<Projective> {
cmE: Projective::rand(&mut rng), cmE: Projective::rand(&mut rng),
u: Fr::rand(&mut rng), u: Fr::rand(&mut rng),
cmW: Projective::rand(&mut rng), cmW: Projective::rand(&mut rng),
@@ -516,9 +610,8 @@ pub mod tests {
get_cm_coordinates(&ci3.cmW), get_cm_coordinates(&ci3.cmW),
] ]
.concat(); .concat();
let cfW_circuit = CycleFoldCircuit::<Projective, GVar> { let cfW_circuit = CycleFoldCircuit::<TestCycleFoldConfig<Projective>, GVar> {
_gc: PhantomData, _gc: PhantomData,
n_points: 2,
r_bits: Some(vec![r_bits.clone()]), r_bits: Some(vec![r_bits.clone()]),
points: Some(vec![ci1.clone().cmW, ci2.clone().cmW]), points: Some(vec![ci1.clone().cmW, ci2.clone().cmW]),
x: Some(cfW_u_i_x.clone()), x: Some(cfW_u_i_x.clone()),
@@ -535,9 +628,8 @@ pub mod tests {
get_cm_coordinates(&ci3.cmE), get_cm_coordinates(&ci3.cmE),
] ]
.concat(); .concat();
let cfE_circuit = CycleFoldCircuit::<Projective, GVar> { let cfE_circuit = CycleFoldCircuit::<TestCycleFoldConfig<Projective>, GVar> {
_gc: PhantomData, _gc: PhantomData,
n_points: 2,
r_bits: Some(vec![r_bits.clone()]), r_bits: Some(vec![r_bits.clone()]),
points: Some(vec![ci1.clone().cmE, cmT]), points: Some(vec![ci1.clone().cmE, cmT]),
x: Some(cfE_u_i_x.clone()), x: Some(cfE_u_i_x.clone()),
@@ -548,11 +640,10 @@ pub mod tests {
#[test] #[test]
fn test_nifs_full_gadget() { fn test_nifs_full_gadget() {
let (_, _, _, _, ci1, _, ci2, _, ci3, _, cmT, r_bits, r_Fr) = prepare_simple_fold_inputs(); let (_, _, _, _, ci1, _, ci2, _, ci3, _, cmT, r_bits, _) = prepare_simple_fold_inputs();
let cs = ConstraintSystem::<Fq>::new_ref(); let cs = ConstraintSystem::<Fq>::new_ref();
let r_nonnatVar = NonNativeUintVar::<Fq>::new_witness(cs.clone(), || Ok(r_Fr)).unwrap();
let r_bitsVar = Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(r_bits)).unwrap(); let r_bitsVar = Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(r_bits)).unwrap();
let ci1Var = let ci1Var =
@@ -572,15 +663,8 @@ pub mod tests {
.unwrap(); .unwrap();
let cmTVar = GVar::new_witness(cs.clone(), || Ok(cmT)).unwrap(); let cmTVar = GVar::new_witness(cs.clone(), || Ok(cmT)).unwrap();
NIFSFullGadget::<Projective, GVar>::verify( NIFSFullGadget::<Projective, GVar>::verify(r_bitsVar, cmTVar, ci1Var, ci2Var, ci3Var)
r_bitsVar, .unwrap();
r_nonnatVar,
cmTVar,
ci1Var,
ci2Var,
ci3Var,
)
.unwrap();
assert!(cs.is_satisfied().unwrap()); assert!(cs.is_satisfied().unwrap());
} }
@@ -590,20 +674,20 @@ pub mod tests {
let poseidon_config = poseidon_canonical_config::<Fq>(); let poseidon_config = poseidon_canonical_config::<Fq>();
let mut transcript = PoseidonSponge::<Fq>::new(&poseidon_config); let mut transcript = PoseidonSponge::<Fq>::new(&poseidon_config);
let u_i = CommittedInstance::<Projective> { let u_i = CycleFoldCommittedInstance::<Projective> {
cmE: Projective::zero(), // zero on purpose, so we test also the zero point case cmE: Projective::zero(), // zero on purpose, so we test also the zero point case
u: Fr::zero(), u: Fr::zero(),
cmW: Projective::rand(&mut rng), cmW: Projective::rand(&mut rng),
x: std::iter::repeat_with(|| Fr::rand(&mut rng)) x: std::iter::repeat_with(|| Fr::rand(&mut rng))
.take(7) // 7 = cf_io_len .take(TestCycleFoldConfig::<Projective>::IO_LEN)
.collect(), .collect(),
}; };
let U_i = CommittedInstance::<Projective> { let U_i = CycleFoldCommittedInstance::<Projective> {
cmE: Projective::rand(&mut rng), cmE: Projective::rand(&mut rng),
u: Fr::rand(&mut rng), u: Fr::rand(&mut rng),
cmW: Projective::rand(&mut rng), cmW: Projective::rand(&mut rng),
x: std::iter::repeat_with(|| Fr::rand(&mut rng)) x: std::iter::repeat_with(|| Fr::rand(&mut rng))
.take(7) // 7 = cf_io_len .take(TestCycleFoldConfig::<Projective>::IO_LEN)
.collect(), .collect(),
}; };
let cmT = Projective::rand(&mut rng); let cmT = Projective::rand(&mut rng);
@@ -657,12 +741,12 @@ pub mod tests {
let poseidon_config = poseidon_canonical_config::<Fq>(); let poseidon_config = poseidon_canonical_config::<Fq>();
let sponge = PoseidonSponge::<Fq>::new(&poseidon_config); let sponge = PoseidonSponge::<Fq>::new(&poseidon_config);
let U_i = CommittedInstance::<Projective> { let U_i = CycleFoldCommittedInstance::<Projective> {
cmE: Projective::rand(&mut rng), cmE: Projective::rand(&mut rng),
u: Fr::rand(&mut rng), u: Fr::rand(&mut rng),
cmW: Projective::rand(&mut rng), cmW: Projective::rand(&mut rng),
x: std::iter::repeat_with(|| Fr::rand(&mut rng)) x: std::iter::repeat_with(|| Fr::rand(&mut rng))
.take(7) // 7 = cf_io_len in Nova .take(TestCycleFoldConfig::<Projective>::IO_LEN)
.collect(), .collect(),
}; };
let pp_hash = Fq::from(42u32); // only for test let pp_hash = Fq::from(42u32); // only for test

View File

@@ -26,7 +26,7 @@ pub struct CCCS<C: CurveGroup> {
} }
impl<F: PrimeField> CCS<F> { impl<F: PrimeField> CCS<F> {
pub fn to_cccs<R: Rng, C: CurveGroup, CS: CommitmentScheme<C, H>, const H: bool>( pub fn to_cccs<R: Rng, C, CS: CommitmentScheme<C, H>, const H: bool>(
&self, &self,
rng: &mut R, rng: &mut R,
cs_params: &CS::ProverParams, cs_params: &CS::ProverParams,

View File

@@ -26,20 +26,21 @@ use super::{
cccs::CCCS, cccs::CCCS,
lcccs::LCCCS, lcccs::LCCCS,
nimfs::{NIMFSProof, NIMFS}, nimfs::{NIMFSProof, NIMFS},
Witness, HyperNovaCycleFoldConfig, Witness,
}; };
use crate::constants::N_BITS_RO; use crate::constants::NOVA_N_BITS_RO;
use crate::folding::{ use crate::folding::{
circuits::cyclefold::{
cf_io_len, CycleFoldChallengeGadget, CycleFoldCommittedInstanceVar, NIFSFullGadget,
},
circuits::{ circuits::{
cyclefold::{
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
CycleFoldConfig, NIFSFullGadget,
},
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
sum_check::{IOPProofVar, SumCheckVerifierGadget, VPAuxInfoVar}, sum_check::{IOPProofVar, SumCheckVerifierGadget, VPAuxInfoVar},
utils::EqEvalGadget, utils::EqEvalGadget,
CF1, CF2, CF1, CF2,
}, },
nova::{get_r1cs_from_cs, CommittedInstance}, nova::get_r1cs_from_cs,
}; };
use crate::frontend::FCircuit; use crate::frontend::FCircuit;
use crate::utils::virtual_polynomial::VPAuxInfo; use crate::utils::virtual_polynomial::VPAuxInfo;
@@ -313,7 +314,7 @@ where
let rho_scalar_raw = C::ScalarField::from_le_bytes_mod_order(b"rho"); let rho_scalar_raw = C::ScalarField::from_le_bytes_mod_order(b"rho");
let rho_scalar: FpVar<CF1<C>> = FpVar::<CF1<C>>::new_constant(cs.clone(), rho_scalar_raw)?; let rho_scalar: FpVar<CF1<C>> = FpVar::<CF1<C>>::new_constant(cs.clone(), rho_scalar_raw)?;
transcript.absorb(&rho_scalar)?; transcript.absorb(&rho_scalar)?;
let rho_bits: Vec<Boolean<CF1<C>>> = transcript.get_challenge_nbits(N_BITS_RO)?; let rho_bits: Vec<Boolean<CF1<C>>> = transcript.get_challenge_nbits(NOVA_N_BITS_RO)?;
let rho = Boolean::le_bits_to_fp_var(&rho_bits)?; let rho = Boolean::le_bits_to_fp_var(&rho_bits)?;
// Self::fold will return the folded instance, together with the rho's powers vector so // Self::fold will return the folded instance, together with the rho's powers vector so
@@ -342,7 +343,7 @@ where
let mut v_folded: Vec<FpVar<CF1<C>>> = vec![FpVar::zero(); sigmas[0].len()]; let mut v_folded: Vec<FpVar<CF1<C>>> = vec![FpVar::zero(); sigmas[0].len()];
let mut rho_vec: Vec<Vec<Boolean<CF1<C>>>> = let mut rho_vec: Vec<Vec<Boolean<CF1<C>>>> =
vec![vec![Boolean::FALSE; N_BITS_RO]; lcccs.len() + cccs.len() - 1]; vec![vec![Boolean::FALSE; NOVA_N_BITS_RO]; lcccs.len() + cccs.len() - 1];
let mut rho_i = FpVar::one(); let mut rho_i = FpVar::one();
for i in 0..(lcccs.len() + cccs.len()) { for i in 0..(lcccs.len() + cccs.len()) {
let u: FpVar<CF1<C>>; let u: FpVar<CF1<C>>;
@@ -381,12 +382,12 @@ where
// compute the next power of rho // compute the next power of rho
rho_i *= rho.clone(); rho_i *= rho.clone();
// crop the size of rho_i to N_BITS_RO // crop the size of rho_i to NOVA_N_BITS_RO
let rho_i_bits = rho_i.to_bits_le()?; let rho_i_bits = rho_i.to_bits_le()?;
rho_i = Boolean::le_bits_to_fp_var(&rho_i_bits[..N_BITS_RO])?; rho_i = Boolean::le_bits_to_fp_var(&rho_i_bits[..NOVA_N_BITS_RO])?;
if i < lcccs.len() + cccs.len() - 1 { if i < lcccs.len() + cccs.len() - 1 {
// store the cropped rho_i into the rho_vec // store the cropped rho_i into the rho_vec
rho_vec[i] = rho_i_bits[..N_BITS_RO].to_vec(); rho_vec[i] = rho_i_bits[..NOVA_N_BITS_RO].to_vec();
} }
} }
@@ -456,12 +457,32 @@ fn compute_c_gadget<F: PrimeField>(
Ok(c) Ok(c)
} }
/// `AugmentedFCircuit` enhances the original step function `F`, so that it can
/// be used in recursive arguments such as IVC.
///
/// The method for converting `F` to `AugmentedFCircuit` (`F'`) is defined in
/// [Nova](https://eprint.iacr.org/2021/370.pdf), where `AugmentedFCircuit` not
/// only invokes `F`, but also adds additional constraints for verifying the
/// correct folding of primary instances (i.e., the instances over `C1`).
/// In the paper, the primary instances are Nova's `CommittedInstance`, but we
/// extend this method to support using HyperNova's `LCCCS` and `CCCS` instances
/// as primary instances.
///
/// Furthermore, to reduce circuit size over `C2`, we implement the constraints
/// defined in [CycleFold](https://eprint.iacr.org/2023/1192.pdf). These extra
/// constraints verify the correct folding of CycleFold instances.
///
/// For multi-instance folding, one needs to specify the const generics below:
/// * `MU` - the number of LCCCS instances to be folded
/// * `NU` - the number of CCCS instances to be folded
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AugmentedFCircuit< pub struct AugmentedFCircuit<
C1: CurveGroup, C1: CurveGroup,
C2: CurveGroup, C2: CurveGroup,
GC2: CurveVar<C2, CF2<C2>>, GC2: CurveVar<C2, CF2<C2>>,
FC: FCircuit<CF1<C1>>, FC: FCircuit<CF1<C1>>,
const MU: usize,
const NU: usize,
> where > where
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>, for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
{ {
@@ -470,8 +491,6 @@ pub struct AugmentedFCircuit<
pub poseidon_config: PoseidonConfig<CF1<C1>>, pub poseidon_config: PoseidonConfig<CF1<C1>>,
pub ccs: CCS<C1::ScalarField>, // CCS of the AugmentedFCircuit pub ccs: CCS<C1::ScalarField>, // CCS of the AugmentedFCircuit
pub pp_hash: Option<CF1<C1>>, pub pp_hash: Option<CF1<C1>>,
pub mu: usize, // max number of LCCCS instances to be folded
pub nu: usize, // max number of CCCS instances to be folded
pub i: Option<CF1<C1>>, pub i: Option<CF1<C1>>,
pub i_usize: Option<usize>, pub i_usize: Option<usize>,
pub z_0: Option<Vec<C1::ScalarField>>, pub z_0: Option<Vec<C1::ScalarField>>,
@@ -487,13 +506,13 @@ pub struct AugmentedFCircuit<
pub nimfs_proof: Option<NIMFSProof<C1>>, pub nimfs_proof: Option<NIMFSProof<C1>>,
// cyclefold verifier on C1 // cyclefold verifier on C1
pub cf_u_i_cmW: Option<C2>, // input, cf_u_i.cmW pub cf_u_i_cmW: Option<C2>, // input, cf_u_i.cmW
pub cf_U_i: Option<CommittedInstance<C2>>, // input, RelaxedR1CS CycleFold instance pub cf_U_i: Option<CycleFoldCommittedInstance<C2>>, // input, RelaxedR1CS CycleFold instance
pub cf_x: Option<CF1<C1>>, // public input (cf_u_{i+1}.x[1]) pub cf_x: Option<CF1<C1>>, // public input (cf_u_{i+1}.x[1])
pub cf_cmT: Option<C2>, pub cf_cmT: Option<C2>,
} }
impl<C1, C2, GC2, FC> AugmentedFCircuit<C1, C2, GC2, FC> impl<C1, C2, GC2, FC, const MU: usize, const NU: usize> AugmentedFCircuit<C1, C2, GC2, FC, MU, NU>
where where
C1: CurveGroup, C1: CurveGroup,
C2: CurveGroup, C2: CurveGroup,
@@ -510,10 +529,8 @@ where
poseidon_config: &PoseidonConfig<CF1<C1>>, poseidon_config: &PoseidonConfig<CF1<C1>>,
F_circuit: FC, F_circuit: FC,
ccs: CCS<C1::ScalarField>, ccs: CCS<C1::ScalarField>,
mu: usize,
nu: usize,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
if mu < 1 || nu < 1 { if MU < 1 || NU < 1 {
return Err(Error::CantBeZero("mu,nu".to_string())); return Err(Error::CantBeZero("mu,nu".to_string()));
} }
Ok(Self { Ok(Self {
@@ -522,8 +539,6 @@ where
poseidon_config: poseidon_config.clone(), poseidon_config: poseidon_config.clone(),
ccs, ccs,
pp_hash: None, pp_hash: None,
mu,
nu,
i: None, i: None,
i_usize: None, i_usize: None,
z_0: None, z_0: None,
@@ -548,8 +563,6 @@ where
poseidon_config: &PoseidonConfig<CF1<C1>>, poseidon_config: &PoseidonConfig<CF1<C1>>,
F: FC, // FCircuit F: FC, // FCircuit
ccs: Option<CCS<C1::ScalarField>>, ccs: Option<CCS<C1::ScalarField>>,
mu: usize,
nu: usize,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let initial_ccs = CCS { let initial_ccs = CCS {
// m, n, s, s_prime and M will be overwritten by the `upper_bound_ccs' method // m, n, s, s_prime and M will be overwritten by the `upper_bound_ccs' method
@@ -565,7 +578,7 @@ where
c: vec![C1::ScalarField::one(), C1::ScalarField::one().neg()], c: vec![C1::ScalarField::one(), C1::ScalarField::one().neg()],
M: vec![], M: vec![],
}; };
let mut augmented_f_circuit = Self::default(poseidon_config, F, initial_ccs, mu, nu)?; let mut augmented_f_circuit = Self::default(poseidon_config, F, initial_ccs)?;
if ccs.is_some() { if ccs.is_some() {
augmented_f_circuit.ccs = ccs.unwrap(); augmented_f_circuit.ccs = ccs.unwrap();
} else { } else {
@@ -590,10 +603,10 @@ where
let n_iters = 2; let n_iters = 2;
for _ in 0..n_iters { for _ in 0..n_iters {
let Us = vec![U_i.clone(); self.mu - 1]; let Us = vec![U_i.clone(); MU - 1];
let Ws = vec![W_i.clone(); self.mu - 1]; let Ws = vec![W_i.clone(); MU - 1];
let us = vec![u_i.clone(); self.nu - 1]; let us = vec![u_i.clone(); NU - 1];
let ws = vec![w_i.clone(); self.nu - 1]; let ws = vec![w_i.clone(); NU - 1];
let all_Us = [vec![U_i.clone()], Us.clone()].concat(); let all_Us = [vec![U_i.clone()], Us.clone()].concat();
let all_us = [vec![u_i.clone()], us.clone()].concat(); let all_us = [vec![u_i.clone()], us.clone()].concat();
@@ -618,8 +631,6 @@ where
poseidon_config: self.poseidon_config.clone(), poseidon_config: self.poseidon_config.clone(),
ccs: ccs.clone(), ccs: ccs.clone(),
pp_hash: Some(C1::ScalarField::zero()), pp_hash: Some(C1::ScalarField::zero()),
mu: self.mu,
nu: self.nu,
i: Some(C1::ScalarField::zero()), i: Some(C1::ScalarField::zero()),
i_usize: Some(0), i_usize: Some(0),
z_0: Some(z_0.clone()), z_0: Some(z_0.clone()),
@@ -677,7 +688,8 @@ where
} }
} }
impl<C1, C2, GC2, FC> ConstraintSynthesizer<CF1<C1>> for AugmentedFCircuit<C1, C2, GC2, FC> impl<C1, C2, GC2, FC, const MU: usize, const NU: usize> ConstraintSynthesizer<CF1<C1>>
for AugmentedFCircuit<C1, C2, GC2, FC, MU, NU>
where where
C1: CurveGroup, C1: CurveGroup,
C2: CurveGroup, C2: CurveGroup,
@@ -719,20 +731,21 @@ where
let U_i = let U_i =
LCCCSVar::<C1>::new_witness(cs.clone(), || Ok(self.U_i.unwrap_or(U_dummy.clone())))?; LCCCSVar::<C1>::new_witness(cs.clone(), || Ok(self.U_i.unwrap_or(U_dummy.clone())))?;
let Us = Vec::<LCCCSVar<C1>>::new_witness(cs.clone(), || { let Us = Vec::<LCCCSVar<C1>>::new_witness(cs.clone(), || {
Ok(self.Us.unwrap_or(vec![U_dummy.clone(); self.mu - 1])) Ok(self.Us.unwrap_or(vec![U_dummy.clone(); MU - 1]))
})?; })?;
let us = Vec::<CCCSVar<C1>>::new_witness(cs.clone(), || { let us = Vec::<CCCSVar<C1>>::new_witness(cs.clone(), || {
Ok(self.us.unwrap_or(vec![u_dummy.clone(); self.mu - 1])) Ok(self.us.unwrap_or(vec![u_dummy.clone(); MU - 1]))
})?; })?;
let U_i1_C = NonNativeAffineVar::new_witness(cs.clone(), || { let U_i1_C = NonNativeAffineVar::new_witness(cs.clone(), || {
Ok(self.U_i1_C.unwrap_or_else(C1::zero)) Ok(self.U_i1_C.unwrap_or_else(C1::zero))
})?; })?;
let nimfs_proof_dummy = NIMFSProof::<C1>::dummy(&self.ccs, self.mu, self.nu); let nimfs_proof_dummy = NIMFSProof::<C1>::dummy(&self.ccs, MU, NU);
let nimfs_proof = ProofVar::<C1>::new_witness(cs.clone(), || { let nimfs_proof = ProofVar::<C1>::new_witness(cs.clone(), || {
Ok(self.nimfs_proof.unwrap_or(nimfs_proof_dummy)) Ok(self.nimfs_proof.unwrap_or(nimfs_proof_dummy))
})?; })?;
let cf_u_dummy = CommittedInstance::dummy(cf_io_len(self.mu + self.nu)); let cf_u_dummy =
CycleFoldCommittedInstance::dummy(HyperNovaCycleFoldConfig::<C1, MU, NU>::IO_LEN);
let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || { let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || {
Ok(self.cf_U_i.unwrap_or(cf_u_dummy.clone())) Ok(self.cf_U_i.unwrap_or(cf_u_dummy.clone()))
})?; })?;
@@ -861,20 +874,9 @@ where
cf_u_i.clone(), cf_u_i.clone(),
cf_cmT.clone(), cf_cmT.clone(),
)?; )?;
// Convert cf_r_bits to a `NonNativeFieldVar`
let cf_r_nonnat = {
let mut bits = cf_r_bits.clone();
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
};
// Fold cf1_u_i & cf_U_i into cf1_U_{i+1} // Fold cf1_u_i & cf_U_i into cf1_U_{i+1}
let cf_U_i1 = NIFSFullGadget::<C2, GC2>::fold_committed_instance( let cf_U_i1 =
cf_r_bits, NIFSFullGadget::<C2, GC2>::fold_committed_instance(cf_r_bits, cf_cmT, cf_U_i, cf_u_i)?;
cf_r_nonnat,
cf_cmT,
cf_U_i,
cf_u_i,
)?;
// Back to Primary Part // Back to Primary Part
// P.4.b compute and check the second output of F' // P.4.b compute and check the second output of F'
@@ -909,9 +911,12 @@ mod tests {
}, },
commitment::{pedersen::Pedersen, CommitmentScheme}, commitment::{pedersen::Pedersen, CommitmentScheme},
folding::{ folding::{
circuits::cyclefold::{fold_cyclefold_circuit, CycleFoldCircuit}, circuits::cyclefold::{fold_cyclefold_circuit, CycleFoldWitness},
hypernova::utils::{compute_c, compute_sigmas_thetas}, hypernova::{
nova::{traits::NovaR1CS, Witness as NovaWitness}, utils::{compute_c, compute_sigmas_thetas},
HyperNovaCycleFoldCircuit,
},
nova::traits::NovaR1CS,
}, },
frontend::tests::CubicFCircuit, frontend::tests::CubicFCircuit,
transcript::poseidon::poseidon_canonical_config, transcript::poseidon::poseidon_canonical_config,
@@ -1179,25 +1184,25 @@ mod tests {
let poseidon_config = poseidon_canonical_config::<Fr>(); let poseidon_config = poseidon_canonical_config::<Fr>();
let sponge = PoseidonSponge::<Fr>::new(&poseidon_config); let sponge = PoseidonSponge::<Fr>::new(&poseidon_config);
let mu = 3; const MU: usize = 3;
let nu = 3; const NU: usize = 3;
let start = Instant::now(); let start = Instant::now();
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap(); let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
let mut augmented_f_circuit = AugmentedFCircuit::< let mut augmented_f_circuit =
Projective, AugmentedFCircuit::<Projective, Projective2, GVar2, CubicFCircuit<Fr>, MU, NU>::empty(
Projective2, &poseidon_config,
GVar2, F_circuit,
CubicFCircuit<Fr>, None,
>::empty(&poseidon_config, F_circuit, None, mu, nu) )
.unwrap(); .unwrap();
let ccs = augmented_f_circuit.ccs.clone(); let ccs = augmented_f_circuit.ccs.clone();
println!("AugmentedFCircuit & CCS generation: {:?}", start.elapsed()); println!("AugmentedFCircuit & CCS generation: {:?}", start.elapsed());
println!("CCS m x n: {} x {}", ccs.m, ccs.n); println!("CCS m x n: {} x {}", ccs.m, ccs.n);
// CycleFold circuit // CycleFold circuit
let cs2 = ConstraintSystem::<Fq>::new_ref(); let cs2 = ConstraintSystem::<Fq>::new_ref();
let cf_circuit = CycleFoldCircuit::<Projective, GVar>::empty(mu + nu); let cf_circuit = HyperNovaCycleFoldCircuit::<Projective, GVar, MU, NU>::empty();
cf_circuit.generate_constraints(cs2.clone()).unwrap(); cf_circuit.generate_constraints(cs2.clone()).unwrap();
cs2.finalize(); cs2.finalize();
let cs2 = cs2 let cs2 = cs2
@@ -1224,8 +1229,10 @@ mod tests {
let U_dummy = LCCCS::<Projective>::dummy(ccs.l, ccs.t, ccs.s); let U_dummy = LCCCS::<Projective>::dummy(ccs.l, ccs.t, ccs.s);
let w_dummy = W_dummy.clone(); let w_dummy = W_dummy.clone();
let u_dummy = CCCS::<Projective>::dummy(ccs.l); let u_dummy = CCCS::<Projective>::dummy(ccs.l);
let (cf_W_dummy, cf_U_dummy): (NovaWitness<Projective2>, CommittedInstance<Projective2>) = let (cf_W_dummy, cf_U_dummy): (
cf_r1cs.dummy_instance(); CycleFoldWitness<Projective2>,
CycleFoldCommittedInstance<Projective2>,
) = cf_r1cs.dummy_instance();
// set the initial dummy instances // set the initial dummy instances
let mut W_i = W_dummy.clone(); let mut W_i = W_dummy.clone();
@@ -1245,10 +1252,10 @@ mod tests {
let start = Instant::now(); let start = Instant::now();
// for this test, let Us & us be just an array of copies of the U_i & u_i respectively // for this test, let Us & us be just an array of copies of the U_i & u_i respectively
let Us = vec![U_i.clone(); mu - 1]; let Us = vec![U_i.clone(); MU - 1];
let Ws = vec![W_i.clone(); mu - 1]; let Ws = vec![W_i.clone(); MU - 1];
let us = vec![u_i.clone(); nu - 1]; let us = vec![u_i.clone(); NU - 1];
let ws = vec![w_i.clone(); nu - 1]; let ws = vec![w_i.clone(); NU - 1];
let all_Us = [vec![U_i.clone()], Us.clone()].concat(); let all_Us = [vec![U_i.clone()], Us.clone()].concat();
let all_us = [vec![u_i.clone()], us.clone()].concat(); let all_us = [vec![u_i.clone()], us.clone()].concat();
let all_Ws = [vec![W_i.clone()], Ws].concat(); let all_Ws = [vec![W_i.clone()], Ws].concat();
@@ -1268,35 +1275,39 @@ mod tests {
// input in the AugmentedFCircuit // input in the AugmentedFCircuit
let cf_u_i1_x = cf_U_i.hash_cyclefold(&sponge, pp_hash); let cf_u_i1_x = cf_U_i.hash_cyclefold(&sponge, pp_hash);
augmented_f_circuit = augmented_f_circuit = AugmentedFCircuit::<
AugmentedFCircuit::<Projective, Projective2, GVar2, CubicFCircuit<Fr>> { Projective,
_c2: PhantomData, Projective2,
_gc2: PhantomData, GVar2,
poseidon_config: poseidon_config.clone(), CubicFCircuit<Fr>,
ccs: ccs.clone(), MU,
pp_hash: Some(pp_hash), NU,
mu, > {
nu, _c2: PhantomData,
i: Some(Fr::zero()), _gc2: PhantomData,
i_usize: Some(0), poseidon_config: poseidon_config.clone(),
z_0: Some(z_0.clone()), ccs: ccs.clone(),
z_i: Some(z_i.clone()), pp_hash: Some(pp_hash),
external_inputs: Some(vec![]), i: Some(Fr::zero()),
U_i: Some(U_i.clone()), i_usize: Some(0),
Us: Some(Us.clone()), z_0: Some(z_0.clone()),
u_i_C: Some(u_i.C), z_i: Some(z_i.clone()),
us: Some(us.clone()), external_inputs: Some(vec![]),
U_i1_C: Some(U_i1.C), U_i: Some(U_i.clone()),
F: F_circuit, Us: Some(Us.clone()),
x: Some(u_i1_x), u_i_C: Some(u_i.C),
nimfs_proof: None, us: Some(us.clone()),
U_i1_C: Some(U_i1.C),
F: F_circuit,
x: Some(u_i1_x),
nimfs_proof: None,
// cyclefold values // cyclefold values
cf_u_i_cmW: None, cf_u_i_cmW: None,
cf_U_i: None, cf_U_i: None,
cf_x: Some(cf_u_i1_x), cf_x: Some(cf_u_i1_x),
cf_cmT: None, cf_cmT: None,
}; };
} else { } else {
let mut transcript_p: PoseidonSponge<Fr> = let mut transcript_p: PoseidonSponge<Fr> =
PoseidonSponge::<Fr>::new(&poseidon_config.clone()); PoseidonSponge::<Fr>::new(&poseidon_config.clone());
@@ -1328,7 +1339,7 @@ mod tests {
.collect(); .collect();
let rho_powers_bits: Vec<Vec<bool>> = rho_powers let rho_powers_bits: Vec<Vec<bool>> = rho_powers
.iter() .iter()
.map(|rho_i| rho_i.into_bigint().to_bits_le()[..N_BITS_RO].to_vec()) .map(|rho_i| rho_i.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec())
.collect(); .collect();
// CycleFold part: // CycleFold part:
@@ -1348,9 +1359,8 @@ mod tests {
] ]
.concat(); .concat();
let cf_circuit = CycleFoldCircuit::<Projective, GVar> { let cf_circuit = HyperNovaCycleFoldCircuit::<Projective, GVar, MU, NU> {
_gc: PhantomData, _gc: PhantomData,
n_points: mu + nu,
r_bits: Some(rho_powers_bits.clone()), r_bits: Some(rho_powers_bits.clone()),
points: Some( points: Some(
[ [
@@ -1367,24 +1377,22 @@ mod tests {
// ensure that the CycleFoldCircuit is well defined // ensure that the CycleFoldCircuit is well defined
assert_eq!( assert_eq!(
cf_circuit.r_bits.clone().unwrap().len(), cf_circuit.r_bits.clone().unwrap().len(),
cf_circuit.n_points - 1 HyperNovaCycleFoldConfig::<Projective, MU, NU>::N_INPUT_POINTS - 1
); );
assert_eq!( assert_eq!(
cf_circuit.points.clone().unwrap().len(), cf_circuit.points.clone().unwrap().len(),
cf_circuit.n_points HyperNovaCycleFoldConfig::<Projective, MU, NU>::N_INPUT_POINTS
); );
let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = fold_cyclefold_circuit::< let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = fold_cyclefold_circuit::<
HyperNovaCycleFoldConfig<Projective, MU, NU>,
Projective, Projective,
GVar, GVar,
Projective2, Projective2,
GVar2, GVar2,
CubicFCircuit<Fr>,
Pedersen<Projective>,
Pedersen<Projective2>, Pedersen<Projective2>,
false, false,
>( >(
mu + nu,
&mut transcript_p, &mut transcript_p,
cf_r1cs.clone(), cf_r1cs.clone(),
cf_pedersen_params.clone(), cf_pedersen_params.clone(),
@@ -1401,35 +1409,39 @@ mod tests {
// AugmentedFCircuit // AugmentedFCircuit
let cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, pp_hash); let cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, pp_hash);
augmented_f_circuit = augmented_f_circuit = AugmentedFCircuit::<
AugmentedFCircuit::<Projective, Projective2, GVar2, CubicFCircuit<Fr>> { Projective,
_c2: PhantomData, Projective2,
_gc2: PhantomData, GVar2,
poseidon_config: poseidon_config.clone(), CubicFCircuit<Fr>,
ccs: ccs.clone(), MU,
pp_hash: Some(pp_hash), NU,
mu, > {
nu, _c2: PhantomData,
i: Some(iFr), _gc2: PhantomData,
i_usize: Some(i), poseidon_config: poseidon_config.clone(),
z_0: Some(z_0.clone()), ccs: ccs.clone(),
z_i: Some(z_i.clone()), pp_hash: Some(pp_hash),
external_inputs: Some(vec![]), i: Some(iFr),
U_i: Some(U_i.clone()), i_usize: Some(i),
Us: Some(Us.clone()), z_0: Some(z_0.clone()),
u_i_C: Some(u_i.C), z_i: Some(z_i.clone()),
us: Some(us.clone()), external_inputs: Some(vec![]),
U_i1_C: Some(U_i1.C), U_i: Some(U_i.clone()),
F: F_circuit, Us: Some(Us.clone()),
x: Some(u_i1_x), u_i_C: Some(u_i.C),
nimfs_proof: Some(nimfs_proof), us: Some(us.clone()),
U_i1_C: Some(U_i1.C),
F: F_circuit,
x: Some(u_i1_x),
nimfs_proof: Some(nimfs_proof),
// cyclefold values // cyclefold values
cf_u_i_cmW: Some(cf_u_i.cmW), cf_u_i_cmW: Some(cf_u_i.cmW),
cf_U_i: Some(cf_U_i), cf_U_i: Some(cf_U_i),
cf_x: Some(cf_u_i1_x), cf_x: Some(cf_u_i1_x),
cf_cmT: Some(cf_cmT), cf_cmT: Some(cf_cmT),
}; };
// assign the next round instances // assign the next round instances
cf_W_i = cf_W_i1; cf_W_i = cf_W_i1;

View File

@@ -30,7 +30,7 @@ pub struct LCCCS<C: CurveGroup> {
} }
impl<F: PrimeField> CCS<F> { impl<F: PrimeField> CCS<F> {
pub fn to_lcccs<R: Rng, C: CurveGroup, CS: CommitmentScheme<C, H>, const H: bool>( pub fn to_lcccs<R: Rng, C, CS: CommitmentScheme<C, H>, const H: bool>(
&self, &self,
rng: &mut R, rng: &mut R,
cs_params: &CS::ProverParams, cs_params: &CS::ProverParams,

View File

@@ -6,31 +6,29 @@ use ark_crypto_primitives::sponge::{
use ark_ec::{CurveGroup, Group}; use ark_ec::{CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField}; use ark_ff::{BigInteger, PrimeField};
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
use ark_std::rand::RngCore; use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero};
use ark_std::{One, Zero};
use core::marker::PhantomData;
use std::fmt::Debug;
pub mod cccs; pub mod cccs;
pub mod circuits; pub mod circuits;
use circuits::AugmentedFCircuit;
pub mod lcccs; pub mod lcccs;
pub mod nimfs; pub mod nimfs;
pub mod utils; pub mod utils;
use cccs::CCCS; use cccs::CCCS;
use circuits::AugmentedFCircuit;
use lcccs::LCCCS; use lcccs::LCCCS;
use nimfs::NIMFS; use nimfs::NIMFS;
use crate::commitment::CommitmentScheme; use crate::commitment::CommitmentScheme;
use crate::constants::N_BITS_RO; use crate::constants::NOVA_N_BITS_RO;
use crate::folding::circuits::{ use crate::folding::circuits::{
cyclefold::{fold_cyclefold_circuit, CycleFoldCircuit}, cyclefold::{
fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig,
CycleFoldWitness,
},
CF2, CF2,
}; };
use crate::folding::nova::{ use crate::folding::nova::{get_r1cs_from_cs, traits::NovaR1CS, PreprocessorParam};
get_r1cs_from_cs, traits::NovaR1CS, CommittedInstance, PreprocessorParam,
Witness as NovaWitness,
};
use crate::frontend::FCircuit; use crate::frontend::FCircuit;
use crate::utils::{get_cm_coordinates, pp_hash}; use crate::utils::{get_cm_coordinates, pp_hash};
use crate::Error; use crate::Error;
@@ -42,6 +40,22 @@ use crate::{
FoldingScheme, MultiFolding, FoldingScheme, MultiFolding,
}; };
struct HyperNovaCycleFoldConfig<C: CurveGroup, const MU: usize, const NU: usize> {
_c: PhantomData<C>,
}
impl<C: CurveGroup, const MU: usize, const NU: usize> CycleFoldConfig
for HyperNovaCycleFoldConfig<C, MU, NU>
{
const RANDOMNESS_BIT_LENGTH: usize = NOVA_N_BITS_RO;
const N_INPUT_POINTS: usize = MU + NU;
type C = C;
type F = C::BaseField;
}
type HyperNovaCycleFoldCircuit<C, GC, const MU: usize, const NU: usize> =
CycleFoldCircuit<HyperNovaCycleFoldConfig<C, MU, NU>, GC>;
/// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment. /// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment.
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Witness<F: PrimeField> { pub struct Witness<F: PrimeField> {
@@ -73,8 +87,6 @@ where
pub cf_cs_params: CS2::ProverParams, pub cf_cs_params: CS2::ProverParams,
// if ccs is set, it will be used, if not, it will be computed at runtime // if ccs is set, it will be used, if not, it will be computed at runtime
pub ccs: Option<CCS<C1::ScalarField>>, pub ccs: Option<CCS<C1::ScalarField>>,
pub mu: usize,
pub nu: usize,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -114,9 +126,23 @@ where
/// Implements HyperNova+CycleFold's IVC, described in /// Implements HyperNova+CycleFold's IVC, described in
/// [HyperNova](https://eprint.iacr.org/2023/573.pdf) and /// [HyperNova](https://eprint.iacr.org/2023/573.pdf) and
/// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait /// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait
///
/// For multi-instance folding, one needs to specify the const generics below:
/// * `MU` - the number of LCCCS instances to be folded
/// * `NU` - the number of CCCS instances to be folded
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> pub struct HyperNova<
where C1,
GC1,
C2,
GC2,
FC,
CS1,
CS2,
const MU: usize,
const NU: usize,
const H: bool,
> where
C1: CurveGroup, C1: CurveGroup,
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>, GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
C2: CurveGroup, C2: CurveGroup,
@@ -142,8 +168,6 @@ where
pub F: FC, pub F: FC,
/// public params hash /// public params hash
pub pp_hash: C1::ScalarField, pub pp_hash: C1::ScalarField,
pub mu: usize, // number of LCCCS instances to be folded
pub nu: usize, // number of CCCS instances to be folded
pub i: C1::ScalarField, pub i: C1::ScalarField,
/// initial state /// initial state
pub z_0: Vec<C1::ScalarField>, pub z_0: Vec<C1::ScalarField>,
@@ -156,12 +180,12 @@ where
pub u_i: CCCS<C1>, pub u_i: CCCS<C1>,
/// CycleFold running instance /// CycleFold running instance
pub cf_W_i: NovaWitness<C2>, pub cf_W_i: CycleFoldWitness<C2>,
pub cf_U_i: CommittedInstance<C2>, pub cf_U_i: CycleFoldCommittedInstance<C2>,
} }
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> MultiFolding<C1, C2, FC> impl<C1, GC1, C2, GC2, FC, CS1, CS2, const MU: usize, const NU: usize, const H: bool>
for HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, H> MultiFolding<C1, C2, FC> for HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, MU, NU, H>
where where
C1: CurveGroup, C1: CurveGroup,
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>, GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
@@ -227,7 +251,8 @@ where
} }
} }
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, H> impl<C1, GC1, C2, GC2, FC, CS1, CS2, const MU: usize, const NU: usize, const H: bool>
HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, MU, NU, H>
where where
C1: CurveGroup, C1: CurveGroup,
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>, GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
@@ -254,7 +279,8 @@ where
// prepare the initial dummy instances // prepare the initial dummy instances
let U_i = LCCCS::<C1>::dummy(self.ccs.l, self.ccs.t, self.ccs.s); let U_i = LCCCS::<C1>::dummy(self.ccs.l, self.ccs.t, self.ccs.s);
let mut u_i = CCCS::<C1>::dummy(self.ccs.l); let mut u_i = CCCS::<C1>::dummy(self.ccs.l);
let (_, cf_U_i): (NovaWitness<C2>, CommittedInstance<C2>) = self.cf_r1cs.dummy_instance(); let (_, cf_U_i): (CycleFoldWitness<C2>, CycleFoldCommittedInstance<C2>) =
self.cf_r1cs.dummy_instance();
let sponge = PoseidonSponge::<C1::ScalarField>::new(&self.poseidon_config); let sponge = PoseidonSponge::<C1::ScalarField>::new(&self.poseidon_config);
@@ -268,7 +294,7 @@ where
), ),
cf_U_i.hash_cyclefold(&sponge, self.pp_hash), cf_U_i.hash_cyclefold(&sponge, self.pp_hash),
]; ];
let us = vec![u_i.clone(); self.nu - 1]; let us = vec![u_i.clone(); NU - 1];
let z_i1 = self let z_i1 = self
.F .F
@@ -285,14 +311,12 @@ where
); );
let cf_u_i1_x = cf_U_i.hash_cyclefold(&sponge, self.pp_hash); let cf_u_i1_x = cf_U_i.hash_cyclefold(&sponge, self.pp_hash);
let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> { let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC, MU, NU> {
_c2: PhantomData, _c2: PhantomData,
_gc2: PhantomData, _gc2: PhantomData,
poseidon_config: self.poseidon_config.clone(), poseidon_config: self.poseidon_config.clone(),
ccs: self.ccs.clone(), ccs: self.ccs.clone(),
pp_hash: Some(self.pp_hash), pp_hash: Some(self.pp_hash),
mu: self.mu,
nu: self.nu,
i: Some(C1::ScalarField::zero()), i: Some(C1::ScalarField::zero()),
i_usize: Some(0), i_usize: Some(0),
z_0: Some(self.z_0.clone()), z_0: Some(self.z_0.clone()),
@@ -334,8 +358,8 @@ where
} }
} }
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> FoldingScheme<C1, C2, FC> impl<C1, GC1, C2, GC2, FC, CS1, CS2, const MU: usize, const NU: usize, const H: bool>
for HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, H> FoldingScheme<C1, C2, FC> for HyperNova<C1, GC1, C2, GC2, FC, CS1, CS2, MU, NU, H>
where where
C1: CurveGroup, C1: CurveGroup,
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>, GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
@@ -352,37 +376,32 @@ where
for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>, for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>, for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
{ {
/// Reuse Nova's PreprocessorParam, together with two usize values, which are mu & nu /// Reuse Nova's PreprocessorParam.
/// respectively, which indicate the amount of LCCCS & CCCS instances to be folded at each type PreprocessorParam = PreprocessorParam<C1, C2, FC, CS1, CS2, H>;
/// folding step.
type PreprocessorParam = (PreprocessorParam<C1, C2, FC, CS1, CS2, H>, usize, usize);
type ProverParam = ProverParams<C1, C2, CS1, CS2, H>; type ProverParam = ProverParams<C1, C2, CS1, CS2, H>;
type VerifierParam = VerifierParams<C1, C2, CS1, CS2, H>; type VerifierParam = VerifierParams<C1, C2, CS1, CS2, H>;
type RunningInstance = (LCCCS<C1>, Witness<C1::ScalarField>); type RunningInstance = (LCCCS<C1>, Witness<C1::ScalarField>);
type IncomingInstance = (CCCS<C1>, Witness<C1::ScalarField>); type IncomingInstance = (CCCS<C1>, Witness<C1::ScalarField>);
type MultiCommittedInstanceWithWitness = type MultiCommittedInstanceWithWitness =
(Vec<Self::RunningInstance>, Vec<Self::IncomingInstance>); (Vec<Self::RunningInstance>, Vec<Self::IncomingInstance>);
type CFInstance = (CommittedInstance<C2>, NovaWitness<C2>); type CFInstance = (CycleFoldCommittedInstance<C2>, CycleFoldWitness<C2>);
fn preprocess( fn preprocess(
mut rng: impl RngCore, mut rng: impl RngCore,
prep_param: &Self::PreprocessorParam, prep_param: &Self::PreprocessorParam,
) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> {
let (prep_param, mu, nu) = prep_param; if MU < 1 || NU < 1 {
if *mu < 1 || *nu < 1 {
return Err(Error::CantBeZero("mu,nu".to_string())); return Err(Error::CantBeZero("mu,nu".to_string()));
} }
let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC>::empty( let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC, MU, NU>::empty(
&prep_param.poseidon_config, &prep_param.poseidon_config,
prep_param.F.clone(), prep_param.F.clone(),
None, None,
*mu,
*nu,
)?; )?;
let ccs = augmented_f_circuit.ccs.clone(); let ccs = augmented_f_circuit.ccs.clone();
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty(mu + nu); let cf_circuit = HyperNovaCycleFoldCircuit::<C1, GC1, MU, NU>::empty();
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?; let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
// if cs params exist, use them, if not, generate new ones // if cs params exist, use them, if not, generate new ones
@@ -409,8 +428,6 @@ where
cs_params: cs_pp.clone(), cs_params: cs_pp.clone(),
cf_cs_params: cf_cs_pp.clone(), cf_cs_params: cf_cs_pp.clone(),
ccs: Some(ccs.clone()), ccs: Some(ccs.clone()),
mu: *mu,
nu: *nu,
}; };
let vp = VerifierParams::<C1, C2, CS1, CS2, H> { let vp = VerifierParams::<C1, C2, CS1, CS2, H> {
poseidon_config: prep_param.poseidon_config.clone(), poseidon_config: prep_param.poseidon_config.clone(),
@@ -429,7 +446,7 @@ where
z_0: Vec<C1::ScalarField>, z_0: Vec<C1::ScalarField>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let (pp, vp) = params; let (pp, vp) = params;
if pp.mu < 1 || pp.nu < 1 { if MU < 1 || NU < 1 {
return Err(Error::CantBeZero("mu,nu".to_string())); return Err(Error::CantBeZero("mu,nu".to_string()));
} }
@@ -438,16 +455,14 @@ where
// prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS // prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS
// and R1CS respectively // and R1CS respectively
let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC>::empty( let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC, MU, NU>::empty(
&pp.poseidon_config, &pp.poseidon_config,
F.clone(), F.clone(),
pp.ccs.clone(), pp.ccs.clone(),
pp.mu,
pp.nu,
)?; )?;
let ccs = augmented_f_circuit.ccs.clone(); let ccs = augmented_f_circuit.ccs.clone();
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty(pp.mu + pp.nu); let cf_circuit = HyperNovaCycleFoldCircuit::<C1, GC1, MU, NU>::empty();
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?; let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
// compute the public params hash // compute the public params hash
@@ -458,7 +473,7 @@ where
let U_dummy = LCCCS::<C1>::dummy(ccs.l, ccs.t, ccs.s); let U_dummy = LCCCS::<C1>::dummy(ccs.l, ccs.t, ccs.s);
let w_dummy = W_dummy.clone(); let w_dummy = W_dummy.clone();
let mut u_dummy = CCCS::<C1>::dummy(ccs.l); let mut u_dummy = CCCS::<C1>::dummy(ccs.l);
let (cf_W_dummy, cf_U_dummy): (NovaWitness<C2>, CommittedInstance<C2>) = let (cf_W_dummy, cf_U_dummy): (CycleFoldWitness<C2>, CycleFoldCommittedInstance<C2>) =
cf_r1cs.dummy_instance(); cf_r1cs.dummy_instance();
u_dummy.x = vec![ u_dummy.x = vec![
U_dummy.hash( U_dummy.hash(
@@ -484,8 +499,6 @@ where
cf_cs_params: pp.cf_cs_params.clone(), cf_cs_params: pp.cf_cs_params.clone(),
F, F,
pp_hash, pp_hash,
mu: pp.mu,
nu: pp.nu,
i: C1::ScalarField::zero(), i: C1::ScalarField::zero(),
z_0: z_0.clone(), z_0: z_0.clone(),
z_i: z_0, z_i: z_0,
@@ -536,27 +549,27 @@ where
// recall, mu & nu is the number of all the LCCCS & CCCS respectively, including the // recall, mu & nu is the number of all the LCCCS & CCCS respectively, including the
// running and incoming instances that are not part of the 'other_instances', hence the +1 // running and incoming instances that are not part of the 'other_instances', hence the +1
// in the couple of following checks. // in the couple of following checks.
if lcccs.len() + 1 != self.mu { if lcccs.len() + 1 != MU {
return Err(Error::NotSameLength( return Err(Error::NotSameLength(
"other_instances.lcccs.len()".to_string(), "other_instances.lcccs.len()".to_string(),
lcccs.len(), lcccs.len(),
"hypernova.mu".to_string(), "hypernova.mu".to_string(),
self.mu, MU,
)); ));
} }
if cccs.len() + 1 != self.nu { if cccs.len() + 1 != NU {
return Err(Error::NotSameLength( return Err(Error::NotSameLength(
"other_instances.cccs.len()".to_string(), "other_instances.cccs.len()".to_string(),
cccs.len(), cccs.len(),
"hypernova.nu".to_string(), "hypernova.nu".to_string(),
self.nu, NU,
)); ));
} }
let (Us, Ws): (Vec<LCCCS<C1>>, Vec<Witness<C1::ScalarField>>) = lcccs.into_iter().unzip(); let (Us, Ws): (Vec<LCCCS<C1>>, Vec<Witness<C1::ScalarField>>) = lcccs.into_iter().unzip();
let (us, ws): (Vec<CCCS<C1>>, Vec<Witness<C1::ScalarField>>) = cccs.into_iter().unzip(); let (us, ws): (Vec<CCCS<C1>>, Vec<Witness<C1::ScalarField>>) = cccs.into_iter().unzip();
let augmented_f_circuit: AugmentedFCircuit<C1, C2, GC2, FC>; let augmented_f_circuit: AugmentedFCircuit<C1, C2, GC2, FC, MU, NU>;
if self.z_i.len() != self.F.state_len() { if self.z_i.len() != self.F.state_len() {
return Err(Error::NotSameLength( return Err(Error::NotSameLength(
@@ -608,14 +621,12 @@ where
// input in the AugmentedFCircuit // input in the AugmentedFCircuit
cf_u_i1_x = self.cf_U_i.hash_cyclefold(&sponge, self.pp_hash); cf_u_i1_x = self.cf_U_i.hash_cyclefold(&sponge, self.pp_hash);
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> { augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC, MU, NU> {
_c2: PhantomData, _c2: PhantomData,
_gc2: PhantomData, _gc2: PhantomData,
poseidon_config: self.poseidon_config.clone(), poseidon_config: self.poseidon_config.clone(),
ccs: self.ccs.clone(), ccs: self.ccs.clone(),
pp_hash: Some(self.pp_hash), pp_hash: Some(self.pp_hash),
mu: self.mu,
nu: self.nu,
i: Some(C1::ScalarField::zero()), i: Some(C1::ScalarField::zero()),
i_usize: Some(0), i_usize: Some(0),
z_0: Some(self.z_0.clone()), z_0: Some(self.z_0.clone()),
@@ -674,7 +685,7 @@ where
.collect(); .collect();
let rho_powers_bits: Vec<Vec<bool>> = rho_powers let rho_powers_bits: Vec<Vec<bool>> = rho_powers
.iter() .iter()
.map(|rho_i| rho_i.into_bigint().to_bits_le()[..N_BITS_RO].to_vec()) .map(|rho_i| rho_i.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec())
.collect(); .collect();
// CycleFold part: // CycleFold part:
@@ -698,9 +709,8 @@ where
] ]
.concat(); .concat();
let cf_circuit = CycleFoldCircuit::<C1, GC1> { let cf_circuit = HyperNovaCycleFoldCircuit::<C1, GC1, MU, NU> {
_gc: PhantomData, _gc: PhantomData,
n_points: self.mu + self.nu,
r_bits: Some(rho_powers_bits.clone()), r_bits: Some(rho_powers_bits.clone()),
points: Some( points: Some(
[ [
@@ -714,30 +724,34 @@ where
x: Some(cf_u_i_x.clone()), x: Some(cf_u_i_x.clone()),
}; };
let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = fold_cyclefold_circuit::<
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2, H>( HyperNovaCycleFoldConfig<C1, MU, NU>,
self.mu + self.nu, C1,
&mut transcript_p, GC1,
self.cf_r1cs.clone(), C2,
self.cf_cs_params.clone(), GC2,
self.pp_hash, CS2,
self.cf_W_i.clone(), // CycleFold running instance witness H,
self.cf_U_i.clone(), // CycleFold running instance >(
cf_u_i_x, &mut transcript_p,
cf_circuit, self.cf_r1cs.clone(),
&mut rng, self.cf_cs_params.clone(),
)?; self.pp_hash,
self.cf_W_i.clone(), // CycleFold running instance witness
self.cf_U_i.clone(), // CycleFold running instance
cf_u_i_x,
cf_circuit,
&mut rng,
)?;
cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash); cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash);
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> { augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC, MU, NU> {
_c2: PhantomData, _c2: PhantomData,
_gc2: PhantomData, _gc2: PhantomData,
poseidon_config: self.poseidon_config.clone(), poseidon_config: self.poseidon_config.clone(),
ccs: self.ccs.clone(), ccs: self.ccs.clone(),
pp_hash: Some(self.pp_hash), pp_hash: Some(self.pp_hash),
mu: self.mu,
nu: self.nu,
i: Some(self.i), i: Some(self.i),
i_usize: Some(i_usize), i_usize: Some(i_usize),
z_0: Some(self.z_0.clone()), z_0: Some(self.z_0.clone()),
@@ -920,37 +934,21 @@ mod tests {
) { ) {
let mut rng = ark_std::test_rng(); let mut rng = ark_std::test_rng();
let (mu, nu) = (2, 3); const MU: usize = 2;
const NU: usize = 3;
type HN<CS1, CS2, const H: bool> =
HyperNova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2, MU, NU, H>;
let prep_param = let prep_param =
PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2, H>::new( PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2, H>::new(
poseidon_config.clone(), poseidon_config.clone(),
F_circuit, F_circuit,
); );
let hypernova_params = HyperNova::< let hypernova_params = HN::preprocess(&mut rng, &prep_param).unwrap();
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
CS1,
CS2,
H,
>::preprocess(&mut rng, &(prep_param, mu, nu))
.unwrap();
let z_0 = vec![Fr::from(3_u32)]; let z_0 = vec![Fr::from(3_u32)];
let mut hypernova = HyperNova::< let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone()).unwrap();
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
CS1,
CS2,
H,
>::init(&hypernova_params, F_circuit, z_0.clone())
.unwrap();
let (w_i_blinding, W_i_blinding) = if H { let (w_i_blinding, W_i_blinding) = if H {
(Fr::rand(&mut rng), Fr::rand(&mut rng)) (Fr::rand(&mut rng), Fr::rand(&mut rng))
@@ -964,7 +962,7 @@ mod tests {
for _ in 0..num_steps { for _ in 0..num_steps {
// prepare some new instances to fold in the multifolding step // prepare some new instances to fold in the multifolding step
let mut lcccs = vec![]; let mut lcccs = vec![];
for j in 0..mu - 1 { for j in 0..MU - 1 {
let instance_state = vec![Fr::from(j as u32 + 85_u32)]; let instance_state = vec![Fr::from(j as u32 + 85_u32)];
let (U, W) = hypernova let (U, W) = hypernova
.new_running_instance(&mut rng, instance_state, vec![]) .new_running_instance(&mut rng, instance_state, vec![])
@@ -972,7 +970,7 @@ mod tests {
lcccs.push((U, W)); lcccs.push((U, W));
} }
let mut cccs = vec![]; let mut cccs = vec![];
for j in 0..nu - 1 { for j in 0..NU - 1 {
let instance_state = vec![Fr::from(j as u32 + 15_u32)]; let instance_state = vec![Fr::from(j as u32 + 15_u32)];
let (u, w) = hypernova let (u, w) = hypernova
.new_incoming_instance(&mut rng, instance_state, vec![]) .new_incoming_instance(&mut rng, instance_state, vec![])
@@ -988,7 +986,7 @@ mod tests {
assert_eq!(Fr::from(num_steps as u32), hypernova.i); assert_eq!(Fr::from(num_steps as u32), hypernova.i);
let (running_instance, incoming_instance, cyclefold_instance) = hypernova.instances(); let (running_instance, incoming_instance, cyclefold_instance) = hypernova.instances();
HyperNova::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2, H>::verify( HN::verify(
hypernova_params.1, // verifier_params hypernova_params.1, // verifier_params
z_0, z_0,
hypernova.z_i, hypernova.z_i,

View File

@@ -12,7 +12,7 @@ use super::{
Witness, Witness,
}; };
use crate::arith::ccs::CCS; use crate::arith::ccs::CCS;
use crate::constants::N_BITS_RO; use crate::constants::NOVA_N_BITS_RO;
use crate::transcript::Transcript; use crate::transcript::Transcript;
use crate::utils::sum_check::structs::{IOPProof as SumCheckProof, IOPProverMessage}; use crate::utils::sum_check::structs::{IOPProof as SumCheckProof, IOPProverMessage};
use crate::utils::sum_check::{IOPSumCheck, SumCheck}; use crate::utils::sum_check::{IOPSumCheck, SumCheck};
@@ -123,10 +123,12 @@ where
// compute the next power of rho // compute the next power of rho
rho_i *= rho; rho_i *= rho;
// crop the size of rho_i to N_BITS_RO // crop the size of rho_i to NOVA_N_BITS_RO
let rho_i_bits = rho_i.into_bigint().to_bits_le(); let rho_i_bits = rho_i.into_bigint().to_bits_le();
rho_i = C::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_i_bits[..N_BITS_RO])) rho_i = C::ScalarField::from_bigint(BigInteger::from_bits_le(
.unwrap(); &rho_i_bits[..NOVA_N_BITS_RO],
))
.unwrap();
if i < lcccs.len() + cccs.len() - 1 { if i < lcccs.len() + cccs.len() - 1 {
// store the cropped rho_i into the rho_powers vector // store the cropped rho_i into the rho_powers vector
rho_powers[i] = rho_i; rho_powers[i] = rho_i;
@@ -181,10 +183,12 @@ where
// compute the next power of rho // compute the next power of rho
rho_i *= rho; rho_i *= rho;
// crop the size of rho_i to N_BITS_RO // crop the size of rho_i to NOVA_N_BITS_RO
let rho_i_bits = rho_i.into_bigint().to_bits_le(); let rho_i_bits = rho_i.into_bigint().to_bits_le();
rho_i = C::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_i_bits[..N_BITS_RO])) rho_i = C::ScalarField::from_bigint(BigInteger::from_bits_le(
.unwrap(); &rho_i_bits[..NOVA_N_BITS_RO],
))
.unwrap();
} }
Witness { Witness {
w: w_folded, w: w_folded,
@@ -272,7 +276,7 @@ where
// Step 6: Get the folding challenge // Step 6: Get the folding challenge
let rho_scalar = C::ScalarField::from_le_bytes_mod_order(b"rho"); let rho_scalar = C::ScalarField::from_le_bytes_mod_order(b"rho");
transcript.absorb(&rho_scalar); transcript.absorb(&rho_scalar);
let rho_bits: Vec<bool> = transcript.get_challenge_nbits(N_BITS_RO); let rho_bits: Vec<bool> = transcript.get_challenge_nbits(NOVA_N_BITS_RO);
let rho: C::ScalarField = let rho: C::ScalarField =
C::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap(); C::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
@@ -391,7 +395,7 @@ where
// Step 6: Get the folding challenge // Step 6: Get the folding challenge
let rho_scalar = C::ScalarField::from_le_bytes_mod_order(b"rho"); let rho_scalar = C::ScalarField::from_le_bytes_mod_order(b"rho");
transcript.absorb(&rho_scalar); transcript.absorb(&rho_scalar);
let rho_bits: Vec<bool> = transcript.get_challenge_nbits(N_BITS_RO); let rho_bits: Vec<bool> = transcript.get_challenge_nbits(NOVA_N_BITS_RO);
let rho: C::ScalarField = let rho: C::ScalarField =
C::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap(); C::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();

View File

@@ -20,11 +20,12 @@ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace,
use ark_std::{fmt::Debug, One, Zero}; use ark_std::{fmt::Debug, One, Zero};
use core::{borrow::Borrow, marker::PhantomData}; use core::{borrow::Borrow, marker::PhantomData};
use super::{CommittedInstance, NOVA_CF_N_POINTS}; use super::{CommittedInstance, NovaCycleFoldConfig};
use crate::constants::N_BITS_RO; use crate::constants::NOVA_N_BITS_RO;
use crate::folding::circuits::{ use crate::folding::circuits::{
cyclefold::{ cyclefold::{
cf_io_len, CycleFoldChallengeGadget, CycleFoldCommittedInstanceVar, NIFSFullGadget, CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
CycleFoldConfig, NIFSFullGadget,
}, },
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
CF1, CF2, CF1, CF2,
@@ -196,7 +197,7 @@ where
transcript.absorb(&U_i); transcript.absorb(&U_i);
transcript.absorb(&u_i); transcript.absorb(&u_i);
transcript.absorb_nonnative(&cmT); transcript.absorb_nonnative(&cmT);
transcript.squeeze_bits(N_BITS_RO) transcript.squeeze_bits(NOVA_N_BITS_RO)
} }
// compatible with the native get_challenge_native // compatible with the native get_challenge_native
@@ -211,13 +212,22 @@ where
transcript.absorb(&U_i_vec)?; transcript.absorb(&U_i_vec)?;
transcript.absorb(&u_i)?; transcript.absorb(&u_i)?;
transcript.absorb_nonnative(&cmT)?; transcript.absorb_nonnative(&cmT)?;
transcript.squeeze_bits(N_BITS_RO) transcript.squeeze_bits(NOVA_N_BITS_RO)
} }
} }
/// AugmentedFCircuit implements the F' circuit (augmented F) defined in /// `AugmentedFCircuit` enhances the original step function `F`, so that it can
/// [Nova](https://eprint.iacr.org/2021/370.pdf) together with the extra constraints defined in /// be used in recursive arguments such as IVC.
/// [CycleFold](https://eprint.iacr.org/2023/1192.pdf). ///
/// The method for converting `F` to `AugmentedFCircuit` (`F'`) is defined in
/// [Nova](https://eprint.iacr.org/2021/370.pdf), where `AugmentedFCircuit` not
/// only invokes `F`, but also adds additional constraints for verifying the
/// correct folding of primary instances (i.e., Nova's `CommittedInstance`s over
/// `C1`).
///
/// Furthermore, to reduce circuit size over `C2`, we implement the constraints
/// defined in [CycleFold](https://eprint.iacr.org/2023/1192.pdf). These extra
/// constraints verify the correct folding of CycleFold instances.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AugmentedFCircuit< pub struct AugmentedFCircuit<
C1: CurveGroup, C1: CurveGroup,
@@ -246,9 +256,9 @@ pub struct AugmentedFCircuit<
// cyclefold verifier on C1 // cyclefold verifier on C1
// Here 'cf1, cf2' are for each of the CycleFold circuits, corresponding to the fold of cmW and // Here 'cf1, cf2' are for each of the CycleFold circuits, corresponding to the fold of cmW and
// cmE respectively // cmE respectively
pub cf1_u_i_cmW: Option<C2>, // input pub cf1_u_i_cmW: Option<C2>, // input
pub cf2_u_i_cmW: Option<C2>, // input pub cf2_u_i_cmW: Option<C2>, // input
pub cf_U_i: Option<CommittedInstance<C2>>, // input pub cf_U_i: Option<CycleFoldCommittedInstance<C2>>, // input
pub cf1_cmT: Option<C2>, pub cf1_cmT: Option<C2>,
pub cf2_cmT: Option<C2>, pub cf2_cmT: Option<C2>,
pub cf_x: Option<CF1<C1>>, // public input (u_{i+1}.x[1]) pub cf_x: Option<CF1<C1>>, // public input (u_{i+1}.x[1])
@@ -337,7 +347,7 @@ where
let cmT = let cmT =
NonNativeAffineVar::new_witness(cs.clone(), || Ok(self.cmT.unwrap_or_else(C1::zero)))?; NonNativeAffineVar::new_witness(cs.clone(), || Ok(self.cmT.unwrap_or_else(C1::zero)))?;
let cf_u_dummy = CommittedInstance::dummy(cf_io_len(NOVA_CF_N_POINTS)); let cf_u_dummy = CycleFoldCommittedInstance::dummy(NovaCycleFoldConfig::<C1>::IO_LEN);
let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || { let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || {
Ok(self.cf_U_i.unwrap_or(cf_u_dummy.clone())) Ok(self.cf_U_i.unwrap_or(cf_u_dummy.clone()))
})?; })?;
@@ -481,19 +491,9 @@ where
cf1_u_i.clone(), cf1_u_i.clone(),
cf1_cmT.clone(), cf1_cmT.clone(),
)?; )?;
// Convert cf1_r_bits to a `NonNativeFieldVar`
let cf1_r_nonnat = {
let mut bits = cf1_r_bits.clone();
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
};
// Fold cf1_u_i & cf_U_i into cf1_U_{i+1} // Fold cf1_u_i & cf_U_i into cf1_U_{i+1}
let cf1_U_i1 = NIFSFullGadget::<C2, GC2>::fold_committed_instance( let cf1_U_i1 = NIFSFullGadget::<C2, GC2>::fold_committed_instance(
cf1_r_bits, cf1_r_bits, cf1_cmT, cf_U_i, cf1_u_i,
cf1_r_nonnat,
cf1_cmT,
cf_U_i,
cf1_u_i,
)?; )?;
// same for cf2_r: // same for cf2_r:
@@ -504,16 +504,8 @@ where
cf2_u_i.clone(), cf2_u_i.clone(),
cf2_cmT.clone(), cf2_cmT.clone(),
)?; )?;
let cf2_r_nonnat = {
let mut bits = cf2_r_bits.clone();
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
};
let cf_U_i1 = NIFSFullGadget::<C2, GC2>::fold_committed_instance( let cf_U_i1 = NIFSFullGadget::<C2, GC2>::fold_committed_instance(
cf2_r_bits, cf2_r_bits, cf2_cmT, cf1_U_i1, // the output from NIFS.V(cf1_r, cf_U, cfE_u)
cf2_r_nonnat,
cf2_cmT,
cf1_U_i1, // the output from NIFS.V(cf1_r, cf_U, cfE_u)
cf2_u_i, cf2_u_i,
)?; )?;
@@ -566,7 +558,7 @@ pub mod tests {
assert_eq!(ciVar.x.value().unwrap(), ci.x); assert_eq!(ciVar.x.value().unwrap(), ci.x);
// the values cmE and cmW are checked in the CycleFold's circuit // the values cmE and cmW are checked in the CycleFold's circuit
// CommittedInstanceInCycleFoldVar in // CommittedInstanceInCycleFoldVar in
// nova::cyclefold::tests::test_committed_instance_cyclefold_var // cyclefold::tests::test_committed_instance_cyclefold_var
} }
#[test] #[test]

View File

@@ -22,14 +22,18 @@ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace,
use ark_std::{log2, Zero}; use ark_std::{log2, Zero};
use core::{borrow::Borrow, marker::PhantomData}; use core::{borrow::Borrow, marker::PhantomData};
use super::{circuits::ChallengeGadget, nifs::NIFS}; use super::{
circuits::{ChallengeGadget, CommittedInstanceVar},
nifs::NIFS,
CommittedInstance, Nova, Witness,
};
use crate::arith::r1cs::R1CS; use crate::arith::r1cs::R1CS;
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme}; use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
use crate::folding::circuits::{ use crate::folding::circuits::{
cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness},
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
CF1, CF2, CF1, CF2,
}; };
use crate::folding::nova::{circuits::CommittedInstanceVar, CommittedInstance, Nova, Witness};
use crate::frontend::FCircuit; use crate::frontend::FCircuit;
use crate::transcript::{Transcript, TranscriptVar}; use crate::transcript::{Transcript, TranscriptVar};
use crate::utils::{ use crate::utils::{
@@ -156,7 +160,7 @@ where
} }
} }
/// In-circuit representation of the Witness associated to the CommittedInstance, but with /// In-circuit representation of the Witness associated to the CycleFoldCommittedInstance, but with
/// non-native representation, since it is used to represent the CycleFold witness. /// non-native representation, since it is used to represent the CycleFold witness.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CycleFoldWitnessVar<C: CurveGroup> { pub struct CycleFoldWitnessVar<C: CurveGroup> {
@@ -166,12 +170,12 @@ pub struct CycleFoldWitnessVar<C: CurveGroup> {
pub rW: NonNativeUintVar<CF2<C>>, pub rW: NonNativeUintVar<CF2<C>>,
} }
impl<C> AllocVar<Witness<C>, CF2<C>> for CycleFoldWitnessVar<C> impl<C> AllocVar<CycleFoldWitness<C>, CF2<C>> for CycleFoldWitnessVar<C>
where where
C: CurveGroup, C: CurveGroup,
<C as ark_ec::CurveGroup>::BaseField: PrimeField, <C as ark_ec::CurveGroup>::BaseField: PrimeField,
{ {
fn new_variable<T: Borrow<Witness<C>>>( fn new_variable<T: Borrow<CycleFoldWitness<C>>>(
cs: impl Into<Namespace<CF2<C>>>, cs: impl Into<Namespace<CF2<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>, f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode, mode: AllocationMode,
@@ -237,8 +241,8 @@ where
pub cmT: Option<C1>, pub cmT: Option<C1>,
pub r: Option<C1::ScalarField>, pub r: Option<C1::ScalarField>,
/// CycleFold running instance /// CycleFold running instance
pub cf_U_i: Option<CommittedInstance<C2>>, pub cf_U_i: Option<CycleFoldCommittedInstance<C2>>,
pub cf_W_i: Option<Witness<C2>>, pub cf_W_i: Option<CycleFoldWitness<C2>>,
/// KZG challenges /// KZG challenges
pub kzg_c_W: Option<C1::ScalarField>, pub kzg_c_W: Option<C1::ScalarField>,
@@ -447,14 +451,19 @@ where
{ {
// imports here instead of at the top of the file, so we avoid having multiple // imports here instead of at the top of the file, so we avoid having multiple
// `#[cfg(not(test))]` // `#[cfg(not(test))]`
use super::NOVA_CF_N_POINTS;
use crate::commitment::pedersen::PedersenGadget; use crate::commitment::pedersen::PedersenGadget;
use crate::folding::circuits::cyclefold::{cf_io_len, CycleFoldCommittedInstanceVar}; use crate::folding::{
circuits::cyclefold::{CycleFoldCommittedInstanceVar, CycleFoldConfig},
nova::NovaCycleFoldConfig,
};
use ark_r1cs_std::ToBitsGadget; use ark_r1cs_std::ToBitsGadget;
let cf_u_dummy_native = CommittedInstance::<C2>::dummy(cf_io_len(NOVA_CF_N_POINTS)); let cf_u_dummy_native =
let w_dummy_native = CycleFoldCommittedInstance::<C2>::dummy(NovaCycleFoldConfig::<C1>::IO_LEN);
Witness::<C2>::dummy(self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l, self.cf_E_len); let w_dummy_native = CycleFoldWitness::<C2>::dummy(
self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l,
self.cf_E_len,
);
let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || { let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || {
Ok(self.cf_U_i.unwrap_or_else(|| cf_u_dummy_native.clone())) Ok(self.cf_U_i.unwrap_or_else(|| cf_u_dummy_native.clone()))
})?; })?;

View File

@@ -4,7 +4,7 @@ use ark_crypto_primitives::sponge::{
poseidon::{PoseidonConfig, PoseidonSponge}, poseidon::{PoseidonConfig, PoseidonSponge},
Absorb, CryptographicSponge, Absorb, CryptographicSponge,
}; };
use ark_ec::{AffineRepr, CurveGroup, Group}; use ark_ec::{CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField}; use ark_ff::{BigInteger, PrimeField};
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
@@ -15,7 +15,10 @@ use ark_std::{One, UniformRand, Zero};
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::commitment::CommitmentScheme; use crate::commitment::CommitmentScheme;
use crate::folding::circuits::cyclefold::{fold_cyclefold_circuit, CycleFoldCircuit}; use crate::folding::circuits::cyclefold::{
fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig,
CycleFoldWitness,
};
use crate::folding::circuits::CF2; use crate::folding::circuits::CF2;
use crate::frontend::FCircuit; use crate::frontend::FCircuit;
use crate::transcript::{AbsorbNonNative, Transcript}; use crate::transcript::{AbsorbNonNative, Transcript};
@@ -24,6 +27,7 @@ use crate::Error;
use crate::FoldingScheme; use crate::FoldingScheme;
use crate::{ use crate::{
arith::r1cs::{extract_r1cs, extract_w_x, R1CS}, arith::r1cs::{extract_r1cs, extract_w_x, R1CS},
constants::NOVA_N_BITS_RO,
utils::{get_cm_coordinates, pp_hash}, utils::{get_cm_coordinates, pp_hash},
}; };
@@ -33,13 +37,23 @@ pub mod decider_eth_circuit;
pub mod nifs; pub mod nifs;
pub mod serialize; pub mod serialize;
pub mod traits; pub mod traits;
use circuits::{AugmentedFCircuit, ChallengeGadget}; use circuits::{AugmentedFCircuit, ChallengeGadget};
use nifs::NIFS; use nifs::NIFS;
use traits::NovaR1CS; use traits::NovaR1CS;
/// Number of points to be folded in the CycleFold circuit, in Nova's case, this is a fixed amount: struct NovaCycleFoldConfig<C: CurveGroup> {
/// 2 points to be folded. _c: PhantomData<C>,
const NOVA_CF_N_POINTS: usize = 2_usize; }
impl<C: CurveGroup> CycleFoldConfig for NovaCycleFoldConfig<C> {
const RANDOMNESS_BIT_LENGTH: usize = NOVA_N_BITS_RO;
const N_INPUT_POINTS: usize = 2;
type C = C;
type F = C::BaseField;
}
type NovaCycleFoldCircuit<C, GC> = CycleFoldCircuit<NovaCycleFoldConfig<C>, GC>;
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct CommittedInstance<C: CurveGroup> { pub struct CommittedInstance<C: CurveGroup> {
@@ -84,30 +98,6 @@ where
} }
} }
impl<C: CurveGroup> AbsorbNonNative<C::BaseField> for CommittedInstance<C>
where
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField + Absorb,
{
// Compatible with the in-circuit `CycleFoldCommittedInstanceVar::to_native_sponge_field_elements`
// in `cyclefold.rs`.
fn to_native_sponge_field_elements(&self, dest: &mut Vec<C::BaseField>) {
[self.u].to_native_sponge_field_elements(dest);
self.x.to_native_sponge_field_elements(dest);
let (cmE_x, cmE_y) = match self.cmE.into_affine().xy() {
Some((&x, &y)) => (x, y),
None => (C::BaseField::zero(), C::BaseField::zero()),
};
let (cmW_x, cmW_y) = match self.cmW.into_affine().xy() {
Some((&x, &y)) => (x, y),
None => (C::BaseField::zero(), C::BaseField::zero()),
};
cmE_x.to_sponge_field_elements(dest);
cmE_y.to_sponge_field_elements(dest);
cmW_x.to_sponge_field_elements(dest);
cmW_y.to_sponge_field_elements(dest);
}
}
impl<C: CurveGroup> CommittedInstance<C> impl<C: CurveGroup> CommittedInstance<C>
where where
<C as Group>::ScalarField: Absorb, <C as Group>::ScalarField: Absorb,
@@ -135,25 +125,6 @@ where
} }
} }
impl<C: CurveGroup> CommittedInstance<C>
where
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField + Absorb,
{
/// hash_cyclefold implements the committed instance hash compatible with the gadget implemented in
/// nova/cyclefold.rs::CycleFoldCommittedInstanceVar.hash.
/// Returns `H(U_i)`, where `U_i` is the `CommittedInstance` for CycleFold.
pub fn hash_cyclefold<T: Transcript<C::BaseField>>(
&self,
sponge: &T,
pp_hash: C::BaseField, // public params hash
) -> C::BaseField {
let mut sponge = sponge.clone();
sponge.absorb(&pp_hash);
sponge.absorb_nonnative(self);
sponge.squeeze_field_elements(1)[0]
}
}
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Witness<C: CurveGroup> { pub struct Witness<C: CurveGroup> {
pub E: Vec<C::ScalarField>, pub E: Vec<C::ScalarField>,
@@ -342,8 +313,8 @@ where
pub U_i: CommittedInstance<C1>, pub U_i: CommittedInstance<C1>,
/// CycleFold running instance /// CycleFold running instance
pub cf_W_i: Witness<C2>, pub cf_W_i: CycleFoldWitness<C2>,
pub cf_U_i: CommittedInstance<C2>, pub cf_U_i: CycleFoldCommittedInstance<C2>,
} }
impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> FoldingScheme<C1, C2, FC> impl<C1, GC1, C2, GC2, FC, CS1, CS2, const H: bool> FoldingScheme<C1, C2, FC>
@@ -370,7 +341,7 @@ where
type RunningInstance = (CommittedInstance<C1>, Witness<C1>); type RunningInstance = (CommittedInstance<C1>, Witness<C1>);
type IncomingInstance = (CommittedInstance<C1>, Witness<C1>); type IncomingInstance = (CommittedInstance<C1>, Witness<C1>);
type MultiCommittedInstanceWithWitness = (); type MultiCommittedInstanceWithWitness = ();
type CFInstance = (CommittedInstance<C2>, Witness<C2>); type CFInstance = (CycleFoldCommittedInstance<C2>, CycleFoldWitness<C2>);
fn preprocess( fn preprocess(
mut rng: impl RngCore, mut rng: impl RngCore,
@@ -428,7 +399,7 @@ where
let augmented_F_circuit = let augmented_F_circuit =
AugmentedFCircuit::<C1, C2, GC2, FC>::empty(&pp.poseidon_config, F.clone()); AugmentedFCircuit::<C1, C2, GC2, FC>::empty(&pp.poseidon_config, F.clone());
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty(NOVA_CF_N_POINTS); let cf_circuit = NovaCycleFoldCircuit::<C1, GC1>::empty();
augmented_F_circuit.generate_constraints(cs.clone())?; augmented_F_circuit.generate_constraints(cs.clone())?;
cs.finalize(); cs.finalize();
@@ -619,16 +590,14 @@ where
] ]
.concat(); .concat();
let cfW_circuit = CycleFoldCircuit::<C1, GC1> { let cfW_circuit = NovaCycleFoldCircuit::<C1, GC1> {
_gc: PhantomData, _gc: PhantomData,
n_points: NOVA_CF_N_POINTS,
r_bits: Some(vec![r_bits.clone()]), r_bits: Some(vec![r_bits.clone()]),
points: Some(vec![self.U_i.clone().cmW, self.u_i.clone().cmW]), points: Some(vec![self.U_i.clone().cmW, self.u_i.clone().cmW]),
x: Some(cfW_u_i_x.clone()), x: Some(cfW_u_i_x.clone()),
}; };
let cfE_circuit = CycleFoldCircuit::<C1, GC1> { let cfE_circuit = NovaCycleFoldCircuit::<C1, GC1> {
_gc: PhantomData, _gc: PhantomData,
n_points: NOVA_CF_N_POINTS,
r_bits: Some(vec![r_bits.clone()]), r_bits: Some(vec![r_bits.clone()]),
points: Some(vec![self.U_i.clone().cmE, cmT]), points: Some(vec![self.U_i.clone().cmE, cmT]),
x: Some(cfE_u_i_x.clone()), x: Some(cfE_u_i_x.clone()),
@@ -855,24 +824,23 @@ where
fn fold_cyclefold_circuit<T: Transcript<C1::ScalarField>>( fn fold_cyclefold_circuit<T: Transcript<C1::ScalarField>>(
&self, &self,
transcript: &mut T, transcript: &mut T,
cf_W_i: Witness<C2>, // witness of the running instance cf_W_i: CycleFoldWitness<C2>, // witness of the running instance
cf_U_i: CommittedInstance<C2>, // running instance cf_U_i: CycleFoldCommittedInstance<C2>, // running instance
cf_u_i_x: Vec<C2::ScalarField>, cf_u_i_x: Vec<C2::ScalarField>,
cf_circuit: CycleFoldCircuit<C1, GC1>, cf_circuit: NovaCycleFoldCircuit<C1, GC1>,
rng: &mut impl RngCore, rng: &mut impl RngCore,
) -> Result< ) -> Result<
( (
Witness<C2>, CycleFoldWitness<C2>,
CommittedInstance<C2>, // u_i CycleFoldCommittedInstance<C2>, // u_i
Witness<C2>, // W_i1 CycleFoldWitness<C2>, // W_i1
CommittedInstance<C2>, // U_i1 CycleFoldCommittedInstance<C2>, // U_i1
C2, // cmT C2, // cmT
C2::ScalarField, // r_Fq C2::ScalarField, // r_Fq
), ),
Error, Error,
> { > {
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2, H>( fold_cyclefold_circuit::<NovaCycleFoldConfig<C1>, C1, GC1, C2, GC2, CS2, H>(
NOVA_CF_N_POINTS,
transcript, transcript,
self.cf_r1cs.clone(), self.cf_r1cs.clone(),
self.cf_cs_pp.clone(), self.cf_cs_pp.clone(),
@@ -920,7 +888,7 @@ where
{ {
let augmented_F_circuit = let augmented_F_circuit =
AugmentedFCircuit::<C1, C2, GC2, FC>::empty(poseidon_config, F_circuit); AugmentedFCircuit::<C1, C2, GC2, FC>::empty(poseidon_config, F_circuit);
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty(NOVA_CF_N_POINTS); let cf_circuit = NovaCycleFoldCircuit::<C1, GC1>::empty();
let r1cs = get_r1cs_from_cs::<C1::ScalarField>(augmented_F_circuit)?; let r1cs = get_r1cs_from_cs::<C1::ScalarField>(augmented_F_circuit)?;
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?; let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
Ok((r1cs, cf_r1cs)) Ok((r1cs, cf_r1cs))

View File

@@ -6,6 +6,7 @@ use std::marker::PhantomData;
use super::{CommittedInstance, Witness}; use super::{CommittedInstance, Witness};
use crate::arith::r1cs::R1CS; use crate::arith::r1cs::R1CS;
use crate::commitment::CommitmentScheme; use crate::commitment::CommitmentScheme;
use crate::folding::circuits::cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness};
use crate::transcript::Transcript; use crate::transcript::Transcript;
use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, vec_sub}; use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, vec_sub};
use crate::Error; use crate::Error;
@@ -110,10 +111,10 @@ where
pub fn compute_cyclefold_cmT( pub fn compute_cyclefold_cmT(
cs_prover_params: &CS::ProverParams, cs_prover_params: &CS::ProverParams,
r1cs: &R1CS<C::ScalarField>, // R1CS over C2.Fr=C1.Fq (here C=C2) r1cs: &R1CS<C::ScalarField>, // R1CS over C2.Fr=C1.Fq (here C=C2)
w1: &Witness<C>, w1: &CycleFoldWitness<C>,
ci1: &CommittedInstance<C>, ci1: &CycleFoldCommittedInstance<C>,
w2: &Witness<C>, w2: &CycleFoldWitness<C>,
ci2: &CommittedInstance<C>, ci2: &CycleFoldCommittedInstance<C>,
) -> Result<(Vec<C::ScalarField>, C), Error> ) -> Result<(Vec<C::ScalarField>, C), Error>
where where
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField, <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,

View File

@@ -10,14 +10,14 @@ use ark_relations::r1cs::ConstraintSystem;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write};
use std::marker::PhantomData; use std::marker::PhantomData;
use super::{circuits::AugmentedFCircuit, Nova, ProverParams}; use super::{
use super::{CommittedInstance, Witness}; circuits::AugmentedFCircuit, CommittedInstance, Nova, NovaCycleFoldCircuit, ProverParams,
use crate::folding::{ Witness,
circuits::{cyclefold::CycleFoldCircuit, CF2},
nova::NOVA_CF_N_POINTS,
}; };
use crate::{ use crate::{
arith::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1, arith::r1cs::extract_r1cs,
commitment::CommitmentScheme,
folding::circuits::{CF1, CF2},
frontend::FCircuit, frontend::FCircuit,
}; };
@@ -138,7 +138,7 @@ where
let cs2 = ConstraintSystem::<C1::BaseField>::new_ref(); let cs2 = ConstraintSystem::<C1::BaseField>::new_ref();
let augmented_F_circuit = let augmented_F_circuit =
AugmentedFCircuit::<C1, C2, GC2, FC>::empty(&poseidon_config, f_circuit.clone()); AugmentedFCircuit::<C1, C2, GC2, FC>::empty(&poseidon_config, f_circuit.clone());
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty(NOVA_CF_N_POINTS); let cf_circuit = NovaCycleFoldCircuit::<C1, GC1>::empty();
augmented_F_circuit augmented_F_circuit
.generate_constraints(cs.clone()) .generate_constraints(cs.clone())

View File

@@ -226,7 +226,7 @@ pub mod tests {
#[test] #[test]
fn test_transcript_and_transcriptvar_nbits() { fn test_transcript_and_transcriptvar_nbits() {
let nbits = crate::constants::N_BITS_RO; let nbits = crate::constants::NOVA_N_BITS_RO;
// use 'native' transcript // use 'native' transcript
let config = poseidon_canonical_config::<Fq>(); let config = poseidon_canonical_config::<Fq>();