@ -21,11 +21,8 @@ use cccs::CCCS;
use lcccs ::LCCCS ;
use lcccs ::LCCCS ;
use nimfs ::NIMFS ;
use nimfs ::NIMFS ;
use crate ::arith ::{
ccs ::CCS ,
r1cs ::{ extract_w_x , R1CS } ,
} ;
use crate ::commitment ::CommitmentScheme ;
use crate ::commitment ::CommitmentScheme ;
use crate ::constants ::N_BITS_RO ;
use crate ::folding ::circuits ::{
use crate ::folding ::circuits ::{
cyclefold ::{ fold_cyclefold_circuit , CycleFoldCircuit } ,
cyclefold ::{ fold_cyclefold_circuit , CycleFoldCircuit } ,
CF2 ,
CF2 ,
@ -37,7 +34,13 @@ use crate::folding::nova::{
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 ;
use crate ::FoldingScheme ;
use crate ::{
arith ::{
ccs ::CCS ,
r1cs ::{ extract_w_x , R1CS } ,
} ,
FoldingScheme , MultiFolding ,
} ;
/// 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) ]
@ -70,6 +73,8 @@ 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) ]
@ -136,6 +141,8 @@ 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 > ,
@ -152,6 +159,180 @@ where
pub cf_U_i : CommittedInstance < C2 > ,
pub cf_U_i : CommittedInstance < C2 > ,
}
}
impl < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > MultiFolding < 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 RunningInstance = ( LCCCS < C1 > , Witness < C1 ::ScalarField > ) ;
type IncomingInstance = ( CCCS < C1 > , Witness < C1 ::ScalarField > ) ;
type MultiInstance = ( Vec < Self ::RunningInstance > , Vec < Self ::IncomingInstance > ) ;
/// Creates a new LCCS instance for the given state, which satisfies the HyperNova.CCS. This
/// method can be used to generate the 'other' LCCS instances to be folded in the multi-folding
/// step.
fn new_running_instance (
& self ,
mut rng : impl RngCore ,
state : Vec < C1 ::ScalarField > ,
external_inputs : Vec < C1 ::ScalarField > ,
) -> Result < Self ::RunningInstance , Error > {
let r1cs_z = self . new_instance_generic ( state , external_inputs ) ? ;
// 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_lcccs ::< _ , _ , CS1 > ( & mut rng , & self . cs_params , & r1cs_z ) ? ;
#[ cfg(test) ]
U_i . check_relation ( & self . ccs , & W_i ) ? ;
Ok ( ( U_i , W_i ) )
}
/// Creates a new CCCS instance for the given state, which satisfies the HyperNova.CCS. This
/// method can be used to generate the 'other' CCCS instances to be folded in the multi-folding
/// step.
fn new_incoming_instance (
& self ,
mut rng : impl RngCore ,
state : Vec < C1 ::ScalarField > ,
external_inputs : Vec < C1 ::ScalarField > ,
) -> Result < Self ::IncomingInstance , Error > {
let r1cs_z = self . new_instance_generic ( state , external_inputs ) ? ;
// 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 ::< _ , _ , CS1 > ( & mut rng , & self . cs_params , & r1cs_z ) ? ;
#[ cfg(test) ]
u_i . check_relation ( & self . ccs , & w_i ) ? ;
Ok ( ( u_i , w_i ) )
}
}
impl < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > 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 > ,
{
/// internal helper for new_running_instance & new_incoming_instance methods, returns the R1CS
/// z=[u,x,w] vector to be used to create the LCCCS & CCCS fresh instances.
fn new_instance_generic (
& self ,
state : Vec < C1 ::ScalarField > ,
external_inputs : Vec < C1 ::ScalarField > ,
) -> Result < Vec < C1 ::ScalarField > , Error > {
// prepare the initial dummy instances
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 ( _ , cf_U_i ) : ( NovaWitness < C2 > , CommittedInstance < C2 > ) = self . cf_r1cs . dummy_instance ( ) ;
let sponge = PoseidonSponge ::< C1 ::ScalarField > ::new ( & self . poseidon_config ) ;
u_i . x = vec ! [
U_i . hash (
& sponge ,
self . pp_hash ,
C1 ::ScalarField ::zero ( ) , // i
self . z_0 . clone ( ) ,
state . clone ( ) ,
) ,
cf_U_i . hash_cyclefold ( & sponge , self . pp_hash ) ,
] ;
let us = vec ! [ u_i . clone ( ) ; self . nu - 1 ] ;
let z_i1 = self
. F
. step_native ( 0 , state . clone ( ) , external_inputs . clone ( ) ) ? ;
// compute u_{i+1}.x
let U_i1 = LCCCS ::dummy ( self . ccs . l , self . ccs . t , self . ccs . s ) ;
let u_i1_x = U_i1 . hash (
& sponge ,
self . pp_hash ,
C1 ::ScalarField ::one ( ) , // i+1, where i=0
self . z_0 . clone ( ) ,
z_i1 . clone ( ) ,
) ;
let cf_u_i1_x = cf_U_i . hash_cyclefold ( & sponge , self . pp_hash ) ;
let augmented_f_circuit = AugmentedFCircuit ::< C1 , C2 , GC2 , FC > {
_c2 : PhantomData ,
_gc2 : PhantomData ,
poseidon_config : self . poseidon_config . clone ( ) ,
ccs : self . ccs . clone ( ) ,
pp_hash : Some ( self . pp_hash ) ,
mu : self . mu ,
nu : self . nu ,
i : Some ( C1 ::ScalarField ::zero ( ) ) ,
i_usize : Some ( 0 ) ,
z_0 : Some ( self . z_0 . clone ( ) ) ,
z_i : Some ( state . clone ( ) ) ,
external_inputs : Some ( external_inputs ) ,
U_i : Some ( U_i . clone ( ) ) ,
Us : None ,
u_i_C : Some ( u_i . C ) ,
us : Some ( us ) ,
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 ,
} ;
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
#[ cfg(test) ]
assert_eq ! ( r1cs_x_i1 [ 0 ] , augmented_f_circuit . x . unwrap ( ) ) ;
let r1cs_z = [
vec ! [ C1 ::ScalarField ::one ( ) ] ,
r1cs_x_i1 . clone ( ) ,
r1cs_w_i1 . clone ( ) ,
]
. concat ( ) ;
Ok ( r1cs_z )
}
}
impl < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > FoldingScheme < C1 , C2 , FC >
impl < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > FoldingScheme < C1 , C2 , FC >
for HyperNova < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 >
for HyperNova < C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 >
where
where
@ -170,25 +351,37 @@ 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 > ,
{
{
type PreprocessorParam = PreprocessorParam < C1 , C2 , FC , CS1 , CS2 > ;
/// Reuse Nova's PreprocessorParam, together with two usize values, which are mu & nu
/// respectively, which indicate the amount of LCCCS & CCCS instances to be folded at each
/// folding step.
type PreprocessorParam = ( PreprocessorParam < C1 , C2 , FC , CS1 , CS2 > , usize , usize ) ;
type ProverParam = ProverParams < C1 , C2 , CS1 , CS2 > ;
type ProverParam = ProverParams < C1 , C2 , CS1 , CS2 > ;
type VerifierParam = VerifierParams < C1 , C2 , CS1 , CS2 > ;
type VerifierParam = VerifierParams < C1 , C2 , CS1 , CS2 > ;
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 =
( Vec < Self ::RunningInstance > , Vec < Self ::IncomingInstance > ) ;
type CFInstance = ( CommittedInstance < C2 > , NovaWitness < C2 > ) ;
type CFInstance = ( CommittedInstance < C2 > , NovaWitness < 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 {
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 > ::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 ( ) ;
let cf_circuit = CycleFoldCircuit ::< C1 , GC1 > ::empty ( mu + nu ) ;
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
@ -215,6 +408,8 @@ 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 > {
let vp = VerifierParams ::< C1 , C2 , CS1 , CS2 > {
poseidon_config : prep_param . poseidon_config . clone ( ) ,
poseidon_config : prep_param . poseidon_config . clone ( ) ,
@ -228,11 +423,15 @@ where
/// Initializes the HyperNova+CycleFold's IVC for the given parameters and initial state `z_0`.
/// Initializes the HyperNova+CycleFold's IVC for the given parameters and initial state `z_0`.
fn init (
fn init (
params : ( Self ::ProverParam , Self ::VerifierParam ) ,
params : & ( Self ::ProverParam , Self ::VerifierParam ) ,
F : FC ,
F : FC ,
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 {
return Err ( Error ::CantBeZero ( "mu,nu" . to_string ( ) ) ) ;
}
// `sponge` is for digest computation.
// `sponge` is for digest computation.
let sponge = PoseidonSponge ::< C1 ::ScalarField > ::new ( & pp . poseidon_config ) ;
let sponge = PoseidonSponge ::< C1 ::ScalarField > ::new ( & pp . poseidon_config ) ;
@ -242,10 +441,12 @@ where
& 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 ( ) ;
let cf_circuit = CycleFoldCircuit ::< C1 , GC1 > ::empty ( pp . mu + pp . nu ) ;
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
@ -282,6 +483,8 @@ 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 ,
@ -300,10 +503,42 @@ where
& mut self ,
& mut self ,
mut rng : impl RngCore ,
mut rng : impl RngCore ,
external_inputs : Vec < C1 ::ScalarField > ,
external_inputs : Vec < C1 ::ScalarField > ,
other_instances : Option < Self ::MultiCommittedInstanceWithWitness > ,
) -> Result < ( ) , Error > {
) -> Result < ( ) , Error > {
// `sponge` is for digest computation.
// `sponge` is for digest computation.
let sponge = PoseidonSponge ::< C1 ::ScalarField > ::new ( & self . poseidon_config ) ;
let sponge = PoseidonSponge ::< C1 ::ScalarField > ::new ( & self . poseidon_config ) ;
let other_instances = other_instances . ok_or ( Error ::MissingOtherInstances ) ? ;
#[ allow(clippy::type_complexity) ]
let ( lcccs , cccs ) : (
Vec < ( LCCCS < C1 > , Witness < C1 ::ScalarField > ) > ,
Vec < ( CCCS < C1 > , Witness < C1 ::ScalarField > ) > ,
) = other_instances ;
// 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
// in the couple of following checks.
if lcccs . len ( ) + 1 ! = self . mu {
return Err ( Error ::NotSameLength (
"other_instances.lcccs.len()" . to_string ( ) ,
lcccs . len ( ) ,
"hypernova.mu" . to_string ( ) ,
self . mu ,
) ) ;
}
if cccs . len ( ) + 1 ! = self . nu {
return Err ( Error ::NotSameLength (
"other_instances.cccs.len()" . to_string ( ) ,
cccs . len ( ) ,
"hypernova.nu" . to_string ( ) ,
self . nu ,
) ) ;
}
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 augmented_f_circuit : AugmentedFCircuit < C1 , C2 , GC2 , FC > ;
let augmented_f_circuit : AugmentedFCircuit < C1 , C2 , GC2 , FC > ;
if self . z_i . len ( ) ! = self . F . state_len ( ) {
if self . z_i . len ( ) ! = self . F . state_len ( ) {
@ -361,13 +596,17 @@ where
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 ( ) ) ,
z_i : Some ( self . z_i . clone ( ) ) ,
z_i : Some ( self . z_i . clone ( ) ) ,
external_inputs : Some ( external_inputs . clone ( ) ) ,
external_inputs : Some ( external_inputs . clone ( ) ) ,
u_i_C : Some ( self . u_i . C ) ,
U_i : Some ( self . U_i . clone ( ) ) ,
U_i : Some ( self . U_i . clone ( ) ) ,
Us : Some ( Us . clone ( ) ) ,
u_i_C : Some ( self . u_i . C ) ,
us : Some ( us . clone ( ) ) ,
U_i1_C : Some ( U_i1 . C ) ,
U_i1_C : Some ( U_i1 . C ) ,
F : self . F . clone ( ) ,
F : self . F . clone ( ) ,
x : Some ( u_i1_x ) ,
x : Some ( u_i1_x ) ,
@ -383,15 +622,15 @@ where
let mut transcript_p : PoseidonSponge < C1 ::ScalarField > =
let mut transcript_p : PoseidonSponge < C1 ::ScalarField > =
PoseidonSponge ::< C1 ::ScalarField > ::new ( & self . poseidon_config ) ;
PoseidonSponge ::< C1 ::ScalarField > ::new ( & self . poseidon_config ) ;
transcript_p . absorb ( & self . pp_hash ) ;
transcript_p . absorb ( & self . pp_hash ) ;
let ( rho_bit s , nimfs_proof ) ;
( nimfs_proof , U_i1 , W_i1 , rho_bit s ) =
let ( rho_power s , nimfs_proof ) ;
( nimfs_proof , U_i1 , W_i1 , rho_power s ) =
NIMFS ::< C1 , PoseidonSponge < C1 ::ScalarField > > ::prove (
NIMFS ::< C1 , PoseidonSponge < C1 ::ScalarField > > ::prove (
& mut transcript_p ,
& mut transcript_p ,
& self . ccs ,
& self . ccs ,
& [ self . U_i . clone ( ) ] ,
& [ self . u_i . clone ( ) ] ,
& [ self . W_i . clone ( ) ] ,
& [ self . w_i . clone ( ) ] ,
& [ vec ! [ self . U_i . clone ( ) ] , Us . clone ( ) ] . concat ( ) ,
& [ vec ! [ self . u_i . clone ( ) ] , us . clone ( ) ] . concat ( ) ,
& [ vec ! [ self . W_i . clone ( ) ] , Ws ] . concat ( ) ,
& [ vec ! [ self . w_i . clone ( ) ] , ws ] . concat ( ) ,
) ? ;
) ? ;
// sanity check: check the folded instance relation
// sanity check: check the folded instance relation
@ -406,29 +645,60 @@ where
z_i1 . clone ( ) ,
z_i1 . clone ( ) ,
) ;
) ;
let rho_Fq = C2 ::ScalarField ::from_bigint ( BigInteger ::from_bits_le ( & rho_bits ) )
. ok_or ( Error ::OutOfBounds ) ? ;
let rho_powers_Fq : Vec < C1 ::BaseField > = rho_powers
. iter ( )
. map ( | rho_i | {
C1 ::BaseField ::from_bigint ( BigInteger ::from_bits_le (
& rho_i . into_bigint ( ) . to_bits_le ( ) ,
) )
. unwrap ( )
} )
. collect ( ) ;
let rho_powers_bits : Vec < Vec < bool > > = rho_powers
. iter ( )
. map ( | rho_i | rho_i . into_bigint ( ) . to_bits_le ( ) [ . . N_BITS_RO ] . to_vec ( ) )
. collect ( ) ;
// CycleFold part:
// CycleFold part:
// get the vector used as public inputs 'x' in the CycleFold circuit
// cyclefold circuit for cmW
// get the vector used as public inputs 'x' in the CycleFold circuit.
// Place the random values and the points coordinates as the public input x:
// In Nova, this is: x == [r, p1, p2, p3].
// 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],
// where each p_i is in fact p_i.to_constraint_field()
let cf_u_i_x = [
let cf_u_i_x = [
vec ! [ rho_Fq ] ,
rho_powers_Fq ,
get_cm_coordinates ( & self . U_i . C ) ,
get_cm_coordinates ( & self . U_i . C ) ,
Us . iter ( )
. flat_map ( | Us_i | get_cm_coordinates ( & Us_i . C ) )
. collect ( ) ,
get_cm_coordinates ( & self . u_i . C ) ,
get_cm_coordinates ( & self . u_i . C ) ,
us . iter ( )
. flat_map ( | us_i | get_cm_coordinates ( & us_i . C ) )
. collect ( ) ,
get_cm_coordinates ( & U_i1 . C ) ,
get_cm_coordinates ( & U_i1 . C ) ,
]
]
. concat ( ) ;
. concat ( ) ;
let cf_circuit = CycleFoldCircuit ::< C1 , GC1 > {
let cf_circuit = CycleFoldCircuit ::< C1 , GC1 > {
_gc : PhantomData ,
_gc : PhantomData ,
r_bits : Some ( rho_bits . clone ( ) ) ,
p1 : Some ( self . U_i . clone ( ) . C ) ,
p2 : Some ( self . u_i . clone ( ) . C ) ,
n_points : self . mu + self . nu ,
r_bits : Some ( rho_powers_bits . clone ( ) ) ,
points : Some (
[
vec ! [ self . U_i . clone ( ) . C ] ,
Us . iter ( ) . map ( | Us_i | Us_i . C ) . collect ( ) ,
vec ! [ self . u_i . clone ( ) . C ] ,
us . iter ( ) . map ( | us_i | us_i . C ) . collect ( ) ,
]
. concat ( ) ,
) ,
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 ::< C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > (
fold_cyclefold_circuit ::< C1 , GC1 , C2 , GC2 , FC , CS1 , CS2 > (
self . mu + self . nu ,
& mut transcript_p ,
& mut transcript_p ,
self . cf_r1cs . clone ( ) ,
self . cf_r1cs . clone ( ) ,
self . cf_cs_params . clone ( ) ,
self . cf_cs_params . clone ( ) ,
@ -447,13 +717,17 @@ where
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 ( ) ) ,
z_i : Some ( self . z_i . clone ( ) ) ,
z_i : Some ( self . z_i . clone ( ) ) ,
external_inputs : Some ( external_inputs ) ,
external_inputs : Some ( external_inputs ) ,
u_i_C : Some ( self . u_i . C ) ,
U_i : Some ( self . U_i . clone ( ) ) ,
U_i : Some ( self . U_i . clone ( ) ) ,
Us : Some ( Us . clone ( ) ) ,
u_i_C : Some ( self . u_i . C ) ,
us : Some ( us . clone ( ) ) ,
U_i1_C : Some ( U_i1 . C ) ,
U_i1_C : Some ( U_i1 . C ) ,
F : self . F . clone ( ) ,
F : self . F . clone ( ) ,
x : Some ( u_i1_x ) ,
x : Some ( u_i1_x ) ,
@ -618,31 +892,48 @@ mod tests {
type HN < CS1 , CS2 > =
type HN < CS1 , CS2 > =
HyperNova < Projective , GVar , Projective2 , GVar2 , CubicFCircuit < Fr > , CS1 , CS2 > ;
HyperNova < Projective , GVar , Projective2 , GVar2 , CubicFCircuit < Fr > , CS1 , CS2 > ;
let ( mu , nu ) = ( 2 , 3 ) ;
let prep_param =
let prep_param =
PreprocessorParam ::< Projective , Projective2 , CubicFCircuit < Fr > , CS1 , CS2 > ::new (
PreprocessorParam ::< Projective , Projective2 , CubicFCircuit < Fr > , CS1 , CS2 > ::new (
poseidon_config . clone ( ) ,
poseidon_config . clone ( ) ,
F_circuit ,
F_circuit ,
) ;
) ;
let ( prover_params , verifier_params ) = HN ::preprocess ( & mut rng , & prep_param ) . unwrap ( ) ;
let hypernova_params = HN ::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 = HN ::init (
( prover_params , verifier_params . clone ( ) ) ,
F_circuit ,
z_0 . clone ( ) ,
)
. unwrap ( ) ;
let mut hypernova = HN ::init ( & hypernova_params , F_circuit , z_0 . clone ( ) ) . unwrap ( ) ;
let num_steps : usize = 3 ;
let num_steps : usize = 3 ;
for _ in 0 . . num_steps {
for _ in 0 . . num_steps {
hypernova . prove_step ( & mut rng , vec ! [ ] ) . unwrap ( ) ;
// prepare some new instances to fold in the multifolding step
let mut lcccs = vec ! [ ] ;
for j in 0 . . mu - 1 {
let instance_state = vec ! [ Fr ::from ( j as u32 + 85_ u32 ) ] ;
let ( U , W ) = hypernova
. new_running_instance ( & mut rng , instance_state , vec ! [ ] )
. unwrap ( ) ;
lcccs . push ( ( U , W ) ) ;
}
let mut cccs = vec ! [ ] ;
for j in 0 . . nu - 1 {
let instance_state = vec ! [ Fr ::from ( j as u32 + 15_ u32 ) ] ;
let ( u , w ) = hypernova
. new_incoming_instance ( & mut rng , instance_state , vec ! [ ] )
. unwrap ( ) ;
cccs . push ( ( u , w ) ) ;
}
dbg ! ( & hypernova . i ) ;
hypernova
. prove_step ( & mut rng , vec ! [ ] , Some ( ( lcccs , cccs ) ) )
. unwrap ( ) ;
}
}
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 ( ) ;
HN ::verify (
HN ::verify (
verifier_params ,
hypernova_params . 1 , // verifier_params
z_0 ,
z_0 ,
hypernova . z_i ,
hypernova . z_i ,
hypernova . i ,
hypernova . i ,