@ -1,12 +1,42 @@
/// Implements the scheme described in [HyperNova](https://eprint.iacr.org/2023/573.pdf)
use crate ::ccs ::CCS ;
use ark_ff ::PrimeField ;
use ark_crypto_primitives ::sponge ::{ poseidon ::PoseidonConfig , Absorb } ;
use ark_ec ::{ CurveGroup , Group } ;
use ark_ff ::{ BigInteger , PrimeField } ;
use ark_r1cs_std ::{ groups ::GroupOpsBounds , prelude ::CurveVar , ToConstraintFieldGadget } ;
use ark_std ::rand ::RngCore ;
use ark_std ::{ One , Zero } ;
use core ::marker ::PhantomData ;
use std ::fmt ::Debug ;
pub mod cccs ;
pub mod circuits ;
use circuits ::AugmentedFCircuit ;
pub mod lcccs ;
pub mod nimfs ;
pub mod utils ;
use cccs ::CCCS ;
use lcccs ::LCCCS ;
use nimfs ::NIMFS ;
use crate ::commitment ::CommitmentScheme ;
use crate ::folding ::circuits ::{
cyclefold ::{ fold_cyclefold_circuit , CycleFoldCircuit } ,
CF2 ,
} ;
use crate ::folding ::nova ::{
get_r1cs_from_cs , traits ::NovaR1CS , CommittedInstance , Witness as NovaWitness ,
} ;
use crate ::frontend ::FCircuit ;
use crate ::utils ::get_cm_coordinates ;
use crate ::Error ;
use crate ::FoldingScheme ;
use crate ::{
ccs ::{
r1cs ::{ extract_w_x , R1CS } ,
CCS ,
} ,
transcript ::{ poseidon ::PoseidonTranscript , Transcript } ,
} ;
/// 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) ]
@ -25,3 +55,556 @@ impl Witness {
Witness ::< F > ::new ( vec ! [ F ::zero ( ) ; ccs . n - ccs . l - 1 ] )
}
}
#[ derive(Debug, Clone) ]
pub struct PreprocessorParam < C1 , C2 , FC , CS1 , CS2 >
where
C1 : CurveGroup ,
C2 : CurveGroup ,
FC : FCircuit < C1 ::ScalarField > ,
CS1 : CommitmentScheme < C1 > ,
CS2 : CommitmentScheme < C2 > ,
{
pub poseidon_config : PoseidonConfig < C1 ::ScalarField > ,
pub F : FC ,
// cs_params & cf_cs_params: if not provided, will be generated at the preprocess method
pub cs_params : Option < CS1 ::ProverParams > ,
pub cf_cs_params : Option < CS2 ::ProverParams > ,
}
#[ derive(Debug, Clone) ]
pub struct ProverParams < C1 , C2 , CS1 , CS2 >
where
C1 : CurveGroup ,
C2 : CurveGroup ,
CS1 : CommitmentScheme < C1 > ,
CS2 : CommitmentScheme < C2 > ,
{
pub poseidon_config : PoseidonConfig < C1 ::ScalarField > ,
pub cs_params : CS1 ::ProverParams ,
pub cf_cs_params : CS2 ::ProverParams ,
// if ccs is set, it will be used, if not, it will be computed at runtime
pub ccs : Option < CCS < C1 ::ScalarField > > ,
}
#[ derive(Debug, Clone) ]
pub struct VerifierParams <
C1 : CurveGroup ,
C2 : CurveGroup ,
CS1 : CommitmentScheme < C1 > ,
CS2 : CommitmentScheme < C2 > ,
> {
pub poseidon_config : PoseidonConfig < C1 ::ScalarField > ,
pub ccs : CCS < C1 ::ScalarField > ,
pub cf_r1cs : R1CS < C2 ::ScalarField > ,
pub cs_params : CS1 ::ProverParams ,
pub cf_cs_params : CS2 ::ProverParams ,
}
/// Implements HyperNova+CycleFold's IVC, described in
/// [HyperNova](https://eprint.iacr.org/2023/573.pdf) and
/// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait
#[ derive(Clone, Debug) ]
pub struct HyperNova < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 >
where
C1 : CurveGroup ,
GC1 : CurveVar < C1 , CF2 < C1 > > + ToConstraintFieldGadget < CF2 < C1 > > ,
C2 : CurveGroup ,
GC2 : CurveVar < C2 , CF2 < C2 > > ,
FC : FCircuit < C1 ::ScalarField > ,
CS1 : CommitmentScheme < C1 > ,
CS2 : CommitmentScheme < C2 > ,
{
_gc1 : PhantomData < GC1 > ,
_c2 : PhantomData < C2 > ,
_gc2 : PhantomData < GC2 > ,
/// CCS of the Augmented Function circuit
pub ccs : CCS < C1 ::ScalarField > ,
/// R1CS of the CycleFold circuit
pub cf_r1cs : R1CS < C2 ::ScalarField > ,
pub poseidon_config : PoseidonConfig < C1 ::ScalarField > ,
/// CommitmentScheme::ProverParams over C1
pub cs_params : CS1 ::ProverParams ,
/// CycleFold CommitmentScheme::ProverParams, over C2
pub cf_cs_params : CS2 ::ProverParams ,
/// F circuit, the circuit that is being folded
pub F : FC ,
pub i : C1 ::ScalarField ,
/// initial state
pub z_0 : Vec < C1 ::ScalarField > ,
/// current i-th state
pub z_i : Vec < C1 ::ScalarField > ,
/// HyperNova instances
pub W_i : Witness < C1 ::ScalarField > ,
pub U_i : LCCCS < C1 > ,
pub w_i : Witness < C1 ::ScalarField > ,
pub u_i : CCCS < C1 > ,
/// CycleFold running instance
pub cf_W_i : NovaWitness < C2 > ,
pub cf_U_i : CommittedInstance < C2 > ,
}
impl < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > FoldingScheme < C1 , C2 , FC >
for HyperNova < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 >
where
C1 : CurveGroup ,
GC1 : CurveVar < C1 , CF2 < C1 > > + ToConstraintFieldGadget < CF2 < C1 > > ,
C2 : CurveGroup ,
GC2 : CurveVar < C2 , CF2 < C2 > > + ToConstraintFieldGadget < CF2 < C2 > > ,
FC : FCircuit < C1 ::ScalarField > ,
CS1 : CommitmentScheme < C1 > ,
CS2 : CommitmentScheme < C2 > ,
< C1 as CurveGroup > ::BaseField : PrimeField ,
< C2 as CurveGroup > ::BaseField : PrimeField ,
< C1 as Group > ::ScalarField : Absorb ,
< C2 as Group > ::ScalarField : Absorb ,
C1 : CurveGroup < BaseField = C2 ::ScalarField , ScalarField = C2 ::BaseField > ,
for < 'a > & 'a GC1 : GroupOpsBounds < 'a , C1 , GC1 > ,
for < 'a > & 'a GC2 : GroupOpsBounds < 'a , C2 , GC2 > ,
{
type PreprocessorParam = PreprocessorParam < C1 , C2 , FC , CS1 , CS2 > ;
type ProverParam = ProverParams < C1 , C2 , CS1 , CS2 > ;
type VerifierParam = VerifierParams < C1 , C2 , CS1 , CS2 > ;
type RunningInstance = ( LCCCS < C1 > , Witness < C1 ::ScalarField > ) ;
type IncomingInstance = ( CCCS < C1 > , Witness < C1 ::ScalarField > ) ;
type CFInstance = ( CommittedInstance < C2 > , NovaWitness < C2 > ) ;
fn preprocess (
mut rng : impl RngCore ,
prep_param : & Self ::PreprocessorParam ,
) -> Result < ( Self ::ProverParam , Self ::VerifierParam ) , Error > {
let augmented_f_circuit = AugmentedFCircuit ::< C1 , C2 , GC2 , FC > ::empty (
& prep_param . poseidon_config ,
prep_param . F . clone ( ) ,
None ,
) ? ;
let ccs = augmented_f_circuit . ccs . clone ( ) ;
let cf_circuit = CycleFoldCircuit ::< C1 , GC1 > ::empty ( ) ;
let cf_r1cs = get_r1cs_from_cs ::< C2 ::ScalarField > ( cf_circuit ) ? ;
// if cs_params & cf_cs_params exist, use them, if not, generate new ones
let cs_params : CS1 ::ProverParams ;
let cf_cs_params : CS2 ::ProverParams ;
if prep_param . cs_params . is_some ( ) & & prep_param . cf_cs_params . is_some ( ) {
cs_params = prep_param . clone ( ) . cs_params . unwrap ( ) ;
cf_cs_params = prep_param . clone ( ) . cf_cs_params . unwrap ( ) ;
} else {
( cs_params , _ ) = CS1 ::setup ( & mut rng , ccs . n - ccs . l - 1 ) . unwrap ( ) ;
( cf_cs_params , _ ) = CS2 ::setup ( & mut rng , cf_r1cs . A . n_cols - cf_r1cs . l - 1 ) . unwrap ( ) ;
}
let pp = ProverParams ::< C1 , C2 , CS1 , CS2 > {
poseidon_config : prep_param . poseidon_config . clone ( ) ,
cs_params : cs_params . clone ( ) ,
cf_cs_params : cf_cs_params . clone ( ) ,
ccs : Some ( ccs . clone ( ) ) ,
} ;
let vp = VerifierParams ::< C1 , C2 , CS1 , CS2 > {
poseidon_config : prep_param . poseidon_config . clone ( ) ,
ccs ,
cf_r1cs ,
cs_params : cs_params . clone ( ) ,
cf_cs_params : cf_cs_params . clone ( ) ,
} ;
Ok ( ( pp , vp ) )
}
/// Initializes the HyperNova+CycleFold's IVC for the given parameters and initial state `z_0`.
fn init ( pp : & Self ::ProverParam , F : FC , z_0 : Vec < C1 ::ScalarField > ) -> Result < Self , Error > {
// prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS
// and R1CS respectively
let augmented_f_circuit = AugmentedFCircuit ::< C1 , C2 , GC2 , FC > ::empty (
& pp . poseidon_config ,
F . clone ( ) ,
pp . ccs . clone ( ) ,
) ? ;
let ccs = augmented_f_circuit . ccs . clone ( ) ;
let cf_circuit = CycleFoldCircuit ::< C1 , GC1 > ::empty ( ) ;
let cf_r1cs = get_r1cs_from_cs ::< C2 ::ScalarField > ( cf_circuit ) ? ;
// setup the dummy instances
let W_dummy = Witness ::< C1 ::ScalarField > ::dummy ( & ccs ) ;
let U_dummy = LCCCS ::< C1 > ::dummy ( ccs . l , ccs . t , ccs . s ) ;
let w_dummy = W_dummy . clone ( ) ;
let mut u_dummy = CCCS ::< C1 > ::dummy ( ccs . l ) ;
let ( cf_W_dummy , cf_U_dummy ) : ( NovaWitness < C2 > , CommittedInstance < C2 > ) =
cf_r1cs . dummy_instance ( ) ;
u_dummy . x = vec ! [
U_dummy . hash (
& pp . poseidon_config ,
C1 ::ScalarField ::zero ( ) ,
z_0 . clone ( ) ,
z_0 . clone ( ) ,
) ? ,
cf_U_dummy . hash_cyclefold ( & pp . poseidon_config ) ? ,
] ;
// W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the
// R1CS that we're working with.
Ok ( Self {
_gc1 : PhantomData ,
_c2 : PhantomData ,
_gc2 : PhantomData ,
ccs ,
cf_r1cs ,
poseidon_config : pp . poseidon_config . clone ( ) ,
cs_params : pp . cs_params . clone ( ) ,
cf_cs_params : pp . cf_cs_params . clone ( ) ,
F ,
i : C1 ::ScalarField ::zero ( ) ,
z_0 : z_0 . clone ( ) ,
z_i : z_0 ,
W_i : W_dummy ,
U_i : U_dummy ,
w_i : w_dummy ,
u_i : u_dummy ,
// cyclefold running instance
cf_W_i : cf_W_dummy ,
cf_U_i : cf_U_dummy ,
} )
}
/// Implements IVC.P of HyperNova+CycleFold
fn prove_step (
& mut self ,
mut rng : impl RngCore ,
external_inputs : Vec < C1 ::ScalarField > ,
) -> Result < ( ) , Error > {
let augmented_f_circuit : AugmentedFCircuit < C1 , C2 , GC2 , FC > ;
if self . z_i . len ( ) ! = self . F . state_len ( ) {
return Err ( Error ::NotSameLength (
"z_i.len()" . to_string ( ) ,
self . z_i . len ( ) ,
"F.state_len()" . to_string ( ) ,
self . F . state_len ( ) ,
) ) ;
}
if external_inputs . len ( ) ! = self . F . external_inputs_len ( ) {
return Err ( Error ::NotSameLength (
"F.external_inputs_len()" . to_string ( ) ,
self . F . external_inputs_len ( ) ,
"external_inputs.len()" . to_string ( ) ,
external_inputs . len ( ) ,
) ) ;
}
if self . i > C1 ::ScalarField ::from_le_bytes_mod_order ( & usize ::MAX . to_le_bytes ( ) ) {
return Err ( Error ::MaxStep ) ;
}
let mut i_bytes : [ u8 ; 8 ] = [ 0 ; 8 ] ;
i_bytes . copy_from_slice ( & self . i . into_bigint ( ) . to_bytes_le ( ) [ . . 8 ] ) ;
let i_usize : usize = usize ::from_le_bytes ( i_bytes ) ;
let z_i1 = self
. F
. step_native ( i_usize , self . z_i . clone ( ) , external_inputs . clone ( ) ) ? ;
// u_{i+1}.x[1] = H(cf_U_{i+1})
let cf_u_i1_x : C1 ::ScalarField ;
let ( U_i1 , W_i1 ) ;
if self . i = = C1 ::ScalarField ::zero ( ) {
W_i1 = Witness ::< C1 ::ScalarField > ::dummy ( & self . ccs ) ;
U_i1 = LCCCS ::dummy ( self . ccs . l , self . ccs . t , self . ccs . s ) ;
let u_i1_x = U_i1 . hash (
& self . poseidon_config ,
C1 ::ScalarField ::one ( ) ,
self . z_0 . clone ( ) ,
z_i1 . clone ( ) ,
) ? ;
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
// input in the AugmentedFCircuit
cf_u_i1_x = self . cf_U_i . hash_cyclefold ( & self . poseidon_config ) ? ;
augmented_f_circuit = AugmentedFCircuit ::< C1 , C2 , GC2 , FC > {
_c2 : PhantomData ,
_gc2 : PhantomData ,
poseidon_config : self . poseidon_config . clone ( ) ,
ccs : self . ccs . clone ( ) ,
i : Some ( C1 ::ScalarField ::zero ( ) ) ,
i_usize : Some ( 0 ) ,
z_0 : Some ( self . z_0 . clone ( ) ) ,
z_i : Some ( self . z_i . clone ( ) ) ,
external_inputs : Some ( external_inputs . clone ( ) ) ,
u_i_C : Some ( self . u_i . C ) ,
U_i : Some ( self . U_i . clone ( ) ) ,
U_i1_C : Some ( U_i1 . C ) ,
F : self . F . clone ( ) ,
x : Some ( u_i1_x ) ,
nimfs_proof : None ,
// cyclefold values
cf_u_i_cmW : None ,
cf_U_i : None ,
cf_x : Some ( cf_u_i1_x ) ,
cf_cmT : None ,
} ;
} else {
let mut transcript_p : PoseidonTranscript < C1 > =
PoseidonTranscript ::< C1 > ::new ( & self . poseidon_config ) ;
let ( rho_bits , nimfs_proof ) ;
( nimfs_proof , U_i1 , W_i1 , rho_bits ) = NIMFS ::< C1 , PoseidonTranscript < C1 > > ::prove (
& mut transcript_p ,
& self . ccs ,
& [ self . U_i . clone ( ) ] ,
& [ self . u_i . clone ( ) ] ,
& [ self . W_i . clone ( ) ] ,
& [ self . w_i . clone ( ) ] ,
) ? ;
// sanity check: check the folded instance relation
#[ cfg(test) ]
U_i1 . check_relation ( & self . ccs , & W_i1 ) ? ;
let u_i1_x = U_i1 . hash (
& self . poseidon_config ,
self . i + C1 ::ScalarField ::one ( ) ,
self . z_0 . clone ( ) ,
z_i1 . clone ( ) ,
) ? ;
let rho_Fq = C2 ::ScalarField ::from_bigint ( BigInteger ::from_bits_le ( & rho_bits ) )
. ok_or ( Error ::OutOfBounds ) ? ;
// CycleFold part:
// get the vector used as public inputs 'x' in the CycleFold circuit
// cyclefold circuit for cmW
let cf_u_i_x = [
vec ! [ rho_Fq ] ,
get_cm_coordinates ( & self . U_i . C ) ,
get_cm_coordinates ( & self . u_i . C ) ,
get_cm_coordinates ( & U_i1 . C ) ,
]
. concat ( ) ;
let cf_circuit = CycleFoldCircuit ::< C1 , GC1 > {
_gc : PhantomData ,
r_bits : Some ( rho_bits . clone ( ) ) ,
p1 : Some ( self . U_i . clone ( ) . C ) ,
p2 : Some ( self . u_i . clone ( ) . C ) ,
x : Some ( cf_u_i_x . clone ( ) ) ,
} ;
let ( _cf_w_i , cf_u_i , cf_W_i1 , cf_U_i1 , cf_cmT , _ ) =
fold_cyclefold_circuit ::< C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > (
& self . poseidon_config ,
self . cf_r1cs . clone ( ) ,
self . cf_cs_params . clone ( ) ,
self . cf_W_i . clone ( ) , // CycleFold running instance witness
self . cf_U_i . clone ( ) , // CycleFold running instance
cf_u_i_x ,
cf_circuit ,
) ? ;
cf_u_i1_x = cf_U_i1 . hash_cyclefold ( & self . poseidon_config ) ? ;
augmented_f_circuit = AugmentedFCircuit ::< C1 , C2 , GC2 , FC > {
_c2 : PhantomData ,
_gc2 : PhantomData ,
poseidon_config : self . poseidon_config . clone ( ) ,
ccs : self . ccs . clone ( ) ,
i : Some ( self . i ) ,
i_usize : Some ( i_usize ) ,
z_0 : Some ( self . z_0 . clone ( ) ) ,
z_i : Some ( self . z_i . clone ( ) ) ,
external_inputs : Some ( external_inputs ) ,
u_i_C : Some ( self . u_i . C ) ,
U_i : Some ( self . U_i . clone ( ) ) ,
U_i1_C : Some ( U_i1 . C ) ,
F : self . F . clone ( ) ,
x : Some ( u_i1_x ) ,
nimfs_proof : Some ( nimfs_proof ) ,
// cyclefold values
cf_u_i_cmW : Some ( cf_u_i . cmW ) ,
cf_U_i : Some ( self . cf_U_i . clone ( ) ) ,
cf_x : Some ( cf_u_i1_x ) ,
cf_cmT : Some ( cf_cmT ) ,
} ;
// assign the next round instances
self . cf_W_i = cf_W_i1 ;
self . cf_U_i = cf_U_i1 ;
}
let ( cs , _ ) = augmented_f_circuit . compute_cs_ccs ( ) ? ;
#[ cfg(test) ]
assert ! ( cs . is_satisfied ( ) ? ) ;
let ( r1cs_w_i1 , r1cs_x_i1 ) = extract_w_x ::< C1 ::ScalarField > ( & cs ) ; // includes 1 and public inputs
let r1cs_z = [
vec ! [ C1 ::ScalarField ::one ( ) ] ,
r1cs_x_i1 . clone ( ) ,
r1cs_w_i1 . clone ( ) ,
]
. concat ( ) ;
// compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we
// assign them directly to w_i, u_i.
let ( u_i , w_i ) = self
. ccs
. to_cccs ::< _ , C1 , CS1 > ( & mut rng , & self . cs_params , & r1cs_z ) ? ;
self . u_i = u_i . clone ( ) ;
self . w_i = w_i . clone ( ) ;
// set values for next iteration
self . i + = C1 ::ScalarField ::one ( ) ;
// assign z_{i+1} into z_i
self . z_i = z_i1 . clone ( ) ;
self . U_i = U_i1 . clone ( ) ;
self . W_i = W_i1 . clone ( ) ;
#[ cfg(test) ]
{
// check the new LCCCS instance relation
self . U_i . check_relation ( & self . ccs , & self . W_i ) ? ;
// check the new CCCS instance relation
self . u_i . check_relation ( & self . ccs , & self . w_i ) ? ;
}
Ok ( ( ) )
}
fn state ( & self ) -> Vec < C1 ::ScalarField > {
self . z_i . clone ( )
}
fn instances (
& self ,
) -> (
Self ::RunningInstance ,
Self ::IncomingInstance ,
Self ::CFInstance ,
) {
(
( self . U_i . clone ( ) , self . W_i . clone ( ) ) ,
( self . u_i . clone ( ) , self . w_i . clone ( ) ) ,
( self . cf_U_i . clone ( ) , self . cf_W_i . clone ( ) ) ,
)
}
/// Implements IVC.V of HyperNova+CycleFold. Notice that this method does not include the
/// commitments verification, which is done in the Decider.
fn verify (
vp : Self ::VerifierParam ,
z_0 : Vec < C1 ::ScalarField > , // initial state
z_i : Vec < C1 ::ScalarField > , // last state
num_steps : C1 ::ScalarField ,
running_instance : Self ::RunningInstance ,
incoming_instance : Self ::IncomingInstance ,
cyclefold_instance : Self ::CFInstance ,
) -> Result < ( ) , Error > {
if num_steps = = C1 ::ScalarField ::zero ( ) {
if z_0 ! = z_i {
return Err ( Error ::IVCVerificationFail ) ;
}
return Ok ( ( ) ) ;
}
let ( U_i , W_i ) = running_instance ;
let ( u_i , w_i ) = incoming_instance ;
let ( cf_U_i , cf_W_i ) = cyclefold_instance ;
if u_i . x . len ( ) ! = 2 | | U_i . x . len ( ) ! = 2 {
return Err ( Error ::IVCVerificationFail ) ;
}
// check that u_i's output points to the running instance
// u_i.X[0] == H(i, z_0, z_i, U_i)
let expected_u_i_x = U_i . hash ( & vp . poseidon_config , num_steps , z_0 , z_i . clone ( ) ) ? ;
if expected_u_i_x ! = u_i . x [ 0 ] {
return Err ( Error ::IVCVerificationFail ) ;
}
// u_i.X[1] == H(cf_U_i)
let expected_cf_u_i_x = cf_U_i . hash_cyclefold ( & vp . poseidon_config ) ? ;
if expected_cf_u_i_x ! = u_i . x [ 1 ] {
return Err ( Error ::IVCVerificationFail ) ;
}
// check LCCCS satisfiability
U_i . check_relation ( & vp . ccs , & W_i ) ? ;
// check CCCS satisfiability
u_i . check_relation ( & vp . ccs , & w_i ) ? ;
// check CycleFold's RelaxedR1CS satisfiability
vp . cf_r1cs
. check_relaxed_instance_relation ( & cf_W_i , & cf_U_i ) ? ;
Ok ( ( ) )
}
}
#[ cfg(test) ]
mod tests {
use crate ::commitment ::kzg ::KZG ;
use ark_bn254 ::{ constraints ::GVar , Bn254 , Fr , G1Projective as Projective } ;
use ark_grumpkin ::{ constraints ::GVar as GVar2 , Projective as Projective2 } ;
use super ::* ;
use crate ::commitment ::pedersen ::Pedersen ;
use crate ::frontend ::tests ::CubicFCircuit ;
use crate ::transcript ::poseidon ::poseidon_canonical_config ;
#[ test ]
pub fn test_ivc ( ) {
let poseidon_config = poseidon_canonical_config ::< Fr > ( ) ;
let F_circuit = CubicFCircuit ::< Fr > ::new ( ( ) ) . unwrap ( ) ;
// run the test using Pedersen commitments on both sides of the curve cycle
test_ivc_opt ::< Pedersen < Projective > , Pedersen < Projective2 > > (
poseidon_config . clone ( ) ,
F_circuit ,
) ;
// run the test using KZG for the commitments on the main curve, and Pedersen for the
// commitments on the secondary curve
test_ivc_opt ::< KZG < Bn254 > , Pedersen < Projective2 > > ( poseidon_config , F_circuit ) ;
}
// test_ivc allowing to choose the CommitmentSchemes
fn test_ivc_opt < CS1 : CommitmentScheme < Projective > , CS2 : CommitmentScheme < Projective2 > > (
poseidon_config : PoseidonConfig < Fr > ,
F_circuit : CubicFCircuit < Fr > ,
) {
let mut rng = ark_std ::test_rng ( ) ;
type HN < CS1 , CS2 > =
HyperNova < Projective , GVar , Projective2 , GVar2 , CubicFCircuit < Fr > , CS1 , CS2 > ;
let prep_param = PreprocessorParam ::< Projective , Projective2 , CubicFCircuit < Fr > , CS1 , CS2 > {
poseidon_config ,
F : F_circuit ,
cs_params : None ,
cf_cs_params : None ,
} ;
let ( prover_params , verifier_params ) = HN ::preprocess ( & mut rng , & prep_param ) . unwrap ( ) ;
let z_0 = vec ! [ Fr ::from ( 3_ u32 ) ] ;
let mut hypernova = HN ::init ( & prover_params , F_circuit , z_0 . clone ( ) ) . unwrap ( ) ;
let num_steps : usize = 3 ;
for _ in 0 . . num_steps {
hypernova . prove_step ( & mut rng , vec ! [ ] ) . unwrap ( ) ;
}
assert_eq ! ( Fr ::from ( num_steps as u32 ) , hypernova . i ) ;
let ( running_instance , incoming_instance , cyclefold_instance ) = hypernova . instances ( ) ;
HN ::verify (
verifier_params ,
z_0 ,
hypernova . z_i ,
hypernova . i ,
running_instance ,
incoming_instance ,
cyclefold_instance ,
)
. unwrap ( ) ;
}
}