mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-08 15:01:30 +01:00
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:
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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()))
|
||||||
})?;
|
})?;
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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>();
|
||||||
|
|||||||
Reference in New Issue
Block a user