Implement HyperNova's IVC into the FoldingScheme trait (#116)

- implement the IVC `FoldingScheme` trait for HyperNova
- refactor Nova's preprocess logic to make it simplier to use
- add to Decider trait (& Nova's DeciderEth) a preprocess method
- get rid of the `init_nova_ivc_params` and `init_ivc_and_decider_params` methods in `examples` since this is achieved with the `FS::preprocess` & `Decider::preprocess` methods
  - (update the examples code to the simplified interface using
    FS::preprocess & Decider::preprocess)
This commit is contained in:
2024-07-04 11:14:31 +02:00
committed by GitHub
parent 456dc9f7a1
commit b5667968f4
25 changed files with 1144 additions and 465 deletions

View File

@@ -596,7 +596,7 @@ where
/// Returns the cs (ConstraintSystem) and the CCS out of the AugmentedFCircuit
#[allow(clippy::type_complexity)]
fn compute_cs_ccs(
pub fn compute_cs_ccs(
&self,
) -> Result<(ConstraintSystem<C1::ScalarField>, CCS<C1::ScalarField>), Error> {
let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
@@ -720,8 +720,14 @@ where
z_0.clone(),
z_i1.clone(),
)?;
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(C1::ScalarField::zero())))?;
x.enforce_equal(&u_i1_x)?;
let (u_i1_x_base, _) = LCCCSVar::new_constant(cs.clone(), U_dummy)?.hash(
&crh_params,
FpVar::<CF1<C1>>::one(),
z_0.clone(),
z_i1.clone(),
)?;
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
// convert rho_bits to a `NonNativeFieldVar`
let rho_nonnat = {
@@ -817,15 +823,14 @@ mod tests {
utils::{compute_c, compute_sigmas_thetas},
Witness,
},
nova::{
get_cm_coordinates, traits::NovaR1CS, CommittedInstance, Witness as NovaWitness,
},
nova::{traits::NovaR1CS, CommittedInstance, Witness as NovaWitness},
},
frontend::tests::CubicFCircuit,
transcript::{
poseidon::{poseidon_canonical_config, PoseidonTranscript, PoseidonTranscriptVar},
Transcript,
},
utils::get_cm_coordinates,
};
#[test]
@@ -858,13 +863,17 @@ mod tests {
// Create the LCCCS instances out of z_lcccs
let mut lcccs_instances = Vec::new();
for z_i in z_lcccs.iter() {
let (inst, _) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap();
let (inst, _) = ccs
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
.unwrap();
lcccs_instances.push(inst);
}
// Create the CCCS instance out of z_cccs
let mut cccs_instances = Vec::new();
for z_i in z_cccs.iter() {
let (inst, _) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap();
let (inst, _) = ccs
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
.unwrap();
cccs_instances.push(inst);
}
@@ -950,7 +959,9 @@ mod tests {
let mut lcccs_instances = Vec::new();
let mut w_lcccs = Vec::new();
for z_i in z_lcccs.iter() {
let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap();
let (running_instance, w) = ccs
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
.unwrap();
lcccs_instances.push(running_instance);
w_lcccs.push(w);
}
@@ -958,7 +969,9 @@ mod tests {
let mut cccs_instances = Vec::new();
let mut w_cccs = Vec::new();
for z_i in z_cccs.iter() {
let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap();
let (new_instance, w) = ccs
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, z_i)
.unwrap();
cccs_instances.push(new_instance);
w_cccs.push(w);
}
@@ -996,9 +1009,7 @@ mod tests {
assert_eq!(folded_lcccs, folded_lcccs_v);
// Check that the folded LCCCS instance is a valid instance with respect to the folded witness
folded_lcccs
.check_relation(&pedersen_params, &ccs, &folded_witness)
.unwrap();
folded_lcccs.check_relation(&ccs, &folded_witness).unwrap();
// allocate circuit inputs
let cs = ConstraintSystem::<Fr>::new_ref();
@@ -1042,7 +1053,9 @@ mod tests {
let i = Fr::from(3_u32);
let z_0 = vec![Fr::from(3_u32)];
let z_i = vec![Fr::from(3_u32)];
let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
let (lcccs, _) = ccs
.to_lcccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &z1)
.unwrap();
let h = lcccs
.clone()
.hash(&poseidon_config, i, z_0.clone(), z_i.clone())
@@ -1104,11 +1117,11 @@ mod tests {
let mut z_i = z_0.clone();
// prepare the dummy instances
let W_dummy = Witness::<Fr>::new(vec![Fr::zero(); ccs.n - ccs.l - 1]);
let W_dummy = Witness::<Fr>::dummy(&ccs);
let U_dummy = LCCCS::<Projective>::dummy(ccs.l, ccs.t, ccs.s);
let w_dummy = W_dummy.clone();
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): (NovaWitness<Projective2>, CommittedInstance<Projective2>) =
cf_r1cs.dummy_instance();
// set the initial dummy instances
@@ -1116,8 +1129,8 @@ mod tests {
let mut U_i = U_dummy.clone();
let mut w_i = w_dummy.clone();
let mut u_i = u_dummy.clone();
let mut cf_W_i = cf_w_dummy.clone();
let mut cf_U_i = cf_u_dummy.clone();
let mut cf_W_i = cf_W_dummy.clone();
let mut cf_U_i = cf_U_dummy.clone();
u_i.x = vec![
U_i.hash(&poseidon_config, Fr::zero(), z_0.clone(), z_i.clone())
.unwrap(),
@@ -1128,28 +1141,19 @@ mod tests {
let mut iFr = Fr::zero();
for i in 0..n_steps {
let start = Instant::now();
let mut transcript_p: PoseidonTranscript<Projective> =
PoseidonTranscript::<Projective>::new(&poseidon_config.clone());
let (nimfs_proof, U_i1, W_i1, rho_bits) =
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
&mut transcript_p,
&ccs,
&[U_i.clone()],
&[u_i.clone()],
&[W_i.clone()],
&[w_i.clone()],
)
.unwrap();
// sanity check: check the folded instance relation
U_i1.check_relation(&pedersen_params, &ccs, &W_i1).unwrap();
let z_i1 = F_circuit.step_native(i, z_i.clone(), vec![]).unwrap();
let u_i1_x = U_i1
.hash(&poseidon_config, iFr + Fr::one(), z_0.clone(), z_i1.clone())
.unwrap();
let (U_i1, W_i1);
if i == 0 {
W_i1 = Witness::<Fr>::dummy(&ccs);
U_i1 = LCCCS::dummy(ccs.l, ccs.t, ccs.s);
let u_i1_x = U_i1
.hash(&poseidon_config, Fr::one(), z_0.clone(), z_i1.clone())
.unwrap();
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
// input in the AugmentedFCircuit
let cf_u_i1_x = cf_U_i.hash_cyclefold(&poseidon_config).unwrap();
@@ -1160,8 +1164,8 @@ mod tests {
_gc2: PhantomData,
poseidon_config: poseidon_config.clone(),
ccs: ccs.clone(),
i: Some(iFr),
i_usize: Some(i),
i: Some(Fr::zero()),
i_usize: Some(0),
z_0: Some(z_0.clone()),
z_i: Some(z_i.clone()),
external_inputs: Some(vec![]),
@@ -1170,7 +1174,7 @@ mod tests {
U_i1_C: Some(U_i1.C),
F: F_circuit,
x: Some(u_i1_x),
nimfs_proof: Some(nimfs_proof),
nimfs_proof: None,
// cyclefold values
cf_u_i_cmW: None,
@@ -1179,6 +1183,27 @@ mod tests {
cf_cmT: None,
};
} else {
let mut transcript_p: PoseidonTranscript<Projective> =
PoseidonTranscript::<Projective>::new(&poseidon_config.clone());
let (rho_bits, nimfs_proof);
(nimfs_proof, U_i1, W_i1, rho_bits) =
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
&mut transcript_p,
&ccs,
&[U_i.clone()],
&[u_i.clone()],
&[W_i.clone()],
&[w_i.clone()],
)
.unwrap();
// sanity check: check the folded instance relation
U_i1.check_relation(&ccs, &W_i1).unwrap();
let u_i1_x = U_i1
.hash(&poseidon_config, iFr + Fr::one(), z_0.clone(), z_i1.clone())
.unwrap();
let rho_Fq = Fq::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
// CycleFold part:
// get the vector used as public inputs 'x' in the CycleFold circuit
@@ -1260,8 +1285,10 @@ mod tests {
let r1cs_z = [vec![Fr::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.
(u_i, w_i) = ccs.to_cccs(&mut rng, &pedersen_params, &r1cs_z).unwrap();
u_i.check_relation(&pedersen_params, &ccs, &w_i).unwrap();
(u_i, w_i) = ccs
.to_cccs::<_, _, Pedersen<Projective>>(&mut rng, &pedersen_params, &r1cs_z)
.unwrap();
u_i.check_relation(&ccs, &w_i).unwrap();
// sanity checks
assert_eq!(w_i.w, r1cs_w_i1);
@@ -1284,9 +1311,9 @@ mod tests {
W_i = W_i1.clone();
// check the new LCCCS instance relation
U_i.check_relation(&pedersen_params, &ccs, &W_i).unwrap();
U_i.check_relation(&ccs, &W_i).unwrap();
// check the new CCCS instance relation
u_i.check_relation(&pedersen_params, &ccs, &w_i).unwrap();
u_i.check_relation(&ccs, &w_i).unwrap();
// check the CycleFold instance relation
cf_r1cs