From 43fab259b0f8c73d70d53200240c0d0695f82eea Mon Sep 17 00:00:00 2001 From: Kirill Karbushev Date: Thu, 14 Dec 2023 16:03:37 +0900 Subject: [PATCH] fix proof generation, so the hash check matches --- nova/src/circuit/augmented.rs | 33 ++++++--- nova/src/hash.rs | 2 +- nova/src/ivc.rs | 133 +++++++++++++++++++++------------- nova/src/proof.rs | 15 +++- nova/src/relaxed_r1cs.rs | 1 + nova/src/test.rs | 2 + 6 files changed, 120 insertions(+), 66 deletions(-) diff --git a/nova/src/circuit/augmented.rs b/nova/src/circuit/augmented.rs index 971f364a..7cbd07f8 100644 --- a/nova/src/circuit/augmented.rs +++ b/nova/src/circuit/augmented.rs @@ -19,10 +19,8 @@ pub struct AugmentedFCircuit> { pub z_i: Option>, pub u_single: Option>, pub u_range: Option>, - pub u_range_next: Option>, // Remove pub commit_t: Option, pub f: PhantomData, - pub x: C::Base, // Remove } impl> Default for AugmentedFCircuit { @@ -34,10 +32,8 @@ impl> Default for AugmentedFCircu z_i: Some(DenseVectors::zero(1)), u_single: Some(RelaxedR1csInstance::dummy(2)), u_range: Some(RelaxedR1csInstance::dummy(2)), - u_range_next: Some(RelaxedR1csInstance::dummy(2)), commit_t: Some(C::Affine::ADDITIVE_IDENTITY), f: Default::default(), - x: C::Base::zero(), } } } @@ -94,7 +90,7 @@ impl> AugmentedFCircuit { let not_base_case = FieldAssignment::is_neq(cs, &i, &zero); // base case - let u_single_next_base = if self.is_primary { + let u_range_next_base = if self.is_primary { u_dummy } else { u_single.clone() @@ -132,27 +128,40 @@ impl> AugmentedFCircuit { // (3) Generate Ui+1 ← NIFS.V(vk, U, u, T) let r = Self::get_challenge(cs, &u_range, commit_t.clone()); - let u_single_next_non_base = + let u_range_next_non_base = NifsCircuit::verify(cs, r, u_single.clone(), u_range.clone(), commit_t); - let u_single_next = RelaxedR1csInstanceAssignment::conditional_select( + let u_range_next = RelaxedR1csInstanceAssignment::conditional_select( cs, - &u_single_next_base, - &u_single_next_non_base, + &u_range_next_base, + &u_range_next_non_base, &base_case, ); let z_next = FC::invoke_cs(cs, z_i); - let u_next_x = u_single_next.hash( + // println!( + // "Hash(\n{:?}\n{:?}\n{:?}\n)", + // (&i + &FieldAssignment::constant(&C::Base::one())).value(cs), + // z_0.iter().map(|x| x.value(cs)).collect::>(), + // z_next.iter().map(|x| x.value(cs)).collect::>() + // ); + // println!( + // "U = (\n{:?}\n{:?}\n{:?}\n)", + // u_range_next.u.value(cs), + // u_range_next.x0.value(cs), + // u_range_next.x1.value(cs) + // ); + let u_next_x = u_range_next.hash( cs, &i + &FieldAssignment::constant(&C::Base::one()), z_0, z_next.clone(), ); - let x1 = FieldAssignment::inputize(cs, u_single.x1); - let u_next_x = FieldAssignment::inputize(cs, u_next_x); + let x0 = FieldAssignment::inputize(cs, u_single.x1); + let x1 = FieldAssignment::inputize(cs, u_next_x); + z_next } diff --git a/nova/src/hash.rs b/nova/src/hash.rs index 0fd15858..59e8b91b 100644 --- a/nova/src/hash.rs +++ b/nova/src/hash.rs @@ -7,7 +7,7 @@ use zkstd::common::{BNAffine, IntGroup, PrimeField, Ring}; /// Amount of rounds calculated for the 254 bit field. /// Doubled due to the usage of Feistel mode with zero key. -pub(crate) const MIMC_ROUNDS: usize = 2; +pub(crate) const MIMC_ROUNDS: usize = 0; pub(crate) struct Mimc { pub(crate) constants: [F; ROUND], diff --git a/nova/src/ivc.rs b/nova/src/ivc.rs index 3b3c162c..9963ae3e 100644 --- a/nova/src/ivc.rs +++ b/nova/src/ivc.rs @@ -4,9 +4,10 @@ use rand_core::OsRng; use std::marker::PhantomData; use crate::circuit::AugmentedFCircuit; -use crate::relaxed_r1cs::{R1csShape, RelaxedR1csInstance, RelaxedR1csWitness}; +use crate::relaxed_r1cs::{ + r1cs_instance_and_witness, R1csShape, RelaxedR1csInstance, RelaxedR1csWitness, +}; use zkstd::circuit::prelude::{CircuitDriver, R1cs}; -use zkstd::common::IntGroup; use zkstd::matrix::DenseVectors; pub struct Ivc @@ -50,27 +51,59 @@ where pp: &PublicParams, z0_primary: DenseVectors, z0_secondary: DenseVectors, - ) -> (Self, RecursiveProof) { + ) -> Self { + println!("START"); let mut cs_primary = R1cs::::default(); - let circuit_primary = AugmentedFCircuit::::default(); - let zi_primary = circuit_primary.generate(&mut cs_primary); // get zi_primary + let circuit_primary = AugmentedFCircuit:: { + is_primary: true, + i: 0, + z_0: z0_primary.clone(), + z_i: None, + u_single: None, + u_range: None, + commit_t: None, + f: Default::default(), + }; + let zi_primary = circuit_primary.generate(&mut cs_primary); - // get u_single_next/w_single_next primary + println!("Primary out"); + let (x, w) = r1cs_instance_and_witness(&cs_primary, &pp.r1cs_shape_primary); + let (u_single_next_primary, w_single_next_primary) = ( + RelaxedR1csInstance::new(DenseVectors::new(x)), + RelaxedR1csWitness::new(DenseVectors::new(w), pp.r1cs_shape_primary.m()), + ); let prover_primary = Prover::new(R1csShape::from(cs_primary.clone()), rng); let mut cs_secondary = R1cs::::default(); - let circuit_secondary = AugmentedFCircuit::::default(); + let circuit_secondary = AugmentedFCircuit:: { + is_primary: false, + i: 0, + z_0: z0_secondary.clone(), + z_i: None, + u_single: Some(u_single_next_primary.clone()), + u_range: None, + commit_t: None, + f: Default::default(), + }; let zi_secondary = circuit_secondary.generate(&mut cs_secondary); - // get u_single_next/w_single_next secondary + println!("Secondary out"); + let (x, w) = r1cs_instance_and_witness(&cs_secondary, &pp.r1cs_shape_secondary); + let (u_single_next_secondary, w_single_next_secondary) = ( + RelaxedR1csInstance::new(DenseVectors::new(x)), + RelaxedR1csWitness::new(DenseVectors::new(w), pp.r1cs_shape_secondary.m()), + ); let prover_secondary = Prover::new(R1csShape::from(cs_secondary.clone()), rng); - let u_dummy = RelaxedR1csInstance::::dummy(cs_primary.l() - 1); - let w_dummy = RelaxedR1csWitness::::dummy(cs_primary.m_l_1(), cs_primary.m()); + let u_dummy = RelaxedR1csInstance::::dummy(pp.r1cs_shape_secondary.l()); + let w_dummy = RelaxedR1csWitness::::dummy( + pp.r1cs_shape_secondary.m_l_1(), + pp.r1cs_shape_secondary.m(), + ); - let ivc = Self { + Self { i: 0, z0_primary, z0_secondary, @@ -88,31 +121,14 @@ where ), prover_primary, prover_secondary, - u_single_secondary: RelaxedR1csInstance::dummy(1), - w_single_secondary: RelaxedR1csWitness::dummy(1, 1), - u_range_primary: RelaxedR1csInstance::dummy(1), - w_range_primary: RelaxedR1csWitness::dummy(1, 1), - u_range_secondary: RelaxedR1csInstance::dummy(1), - w_range_secondary: RelaxedR1csWitness::dummy(1, 1), + u_single_secondary: u_single_next_secondary, + w_single_secondary: w_single_next_secondary, + u_range_primary: u_single_next_primary, + w_range_primary: w_single_next_primary, + u_range_secondary: u_dummy, + w_range_secondary: w_dummy, f: PhantomData::default(), - }; - let proof = RecursiveProof { - i: 0, - z0_primary: ivc.z0_primary.clone(), - z0_secondary: ivc.z0_secondary.clone(), - zi_primary: ivc.z0_primary.clone(), - zi_secondary: ivc.z0_secondary.clone(), - instances: ( - ( - ivc.u_single_secondary.clone(), - ivc.w_single_secondary.clone(), - ), - (ivc.u_range_primary.clone(), ivc.w_range_primary.clone()), - (ivc.u_range_secondary.clone(), ivc.w_range_secondary.clone()), - ), - marker: Default::default(), - }; - (ivc, proof) + } } pub fn prove_step( @@ -121,7 +137,25 @@ where ) -> RecursiveProof { if self.i == 0 { self.i = 1; - // return + return RecursiveProof { + i: self.i, + z0_primary: self.z0_primary.clone(), + z0_secondary: self.z0_secondary.clone(), + zi_primary: self.zi_primary.clone(), + zi_secondary: self.zi_secondary.clone(), + instances: ( + ( + self.u_single_secondary.clone(), + self.w_single_secondary.clone(), + ), + (self.u_range_primary.clone(), self.w_range_primary.clone()), + ( + self.u_range_secondary.clone(), + self.w_range_secondary.clone(), + ), + ), + marker: Default::default(), + }; } let z_next = FC1::invoke(&self.zi_primary); let (u_range_next_secondary, w_range_next_secondary, commit_t_secondary) = @@ -140,10 +174,8 @@ where z_i: Some(self.zi_primary.clone()), u_single: Some(self.u_single_secondary.clone()), u_range: Some(self.u_range_secondary.clone()), - u_range_next: None, commit_t: Some(commit_t_secondary), f: Default::default(), - x: E2::Base::zero(), }; circuit_primary.generate(&mut cs); // zi_primary @@ -166,10 +198,8 @@ where z_i: Some(self.zi_secondary.clone()), u_single: Some(self.u_range_primary.clone()), // u_single_next_primary u_range: Some(self.u_range_primary.clone()), - u_range_next: None, commit_t: Some(commit_t_primary), f: Default::default(), - x: E1::Base::zero(), }; circuit_secondary.generate(&mut cs); // zi_secondary @@ -188,7 +218,7 @@ where // self.zi_secondary = zi_secondary; RecursiveProof { - i: 0, + i: self.i, z0_primary: self.z0_primary.clone(), z0_secondary: self.z0_secondary.clone(), zi_primary: self.z0_primary.clone(), @@ -273,18 +303,17 @@ mod tests { ExampleFunction, >::setup(); - let z0_primary = DenseVectors::new(vec![Fr::from(3)]); - let z0_secondary = DenseVectors::new(vec![Fq::from(3)]); - let (mut ivc, proof_0) = Ivc::< - Bn254Driver, - GrumpkinDriver, - ExampleFunction, - ExampleFunction, - >::init(OsRng, &pp, z0_primary, z0_secondary); - - assert!(proof_0.verify(&pp)); + let z0_primary = DenseVectors::new(vec![Fr::from(0)]); + let z0_secondary = DenseVectors::new(vec![Fq::from(0)]); + let mut ivc = + Ivc::, ExampleFunction>::init( + OsRng, + &pp, + z0_primary, + z0_secondary, + ); - for i in 0..2 { + for i in 0..1 { let proof = ivc.prove_step(&pp); assert!(proof.verify(&pp)); } diff --git a/nova/src/proof.rs b/nova/src/proof.rs index eed1938b..842ac3c6 100644 --- a/nova/src/proof.rs +++ b/nova/src/proof.rs @@ -44,25 +44,38 @@ where (u_range_primary, w_range_primary), (u_range_secondary, w_range_secondary), ) = self.instances.clone(); + if u_single_secondary.x.len() != 2 || u_range_primary.x.len() != 2 || u_range_secondary.x.len() != 2 { + println!("Length doesn't match"); return false; } let (hash_primary, hash_secondary) = { ( u_range_secondary.hash::(self.i, &self.z0_primary, &self.zi_primary), - u_range_primary.hash::(self.i, &self.zi_secondary, &self.zi_secondary), + u_range_primary.hash::(self.i, &self.z0_secondary, &self.zi_secondary), ) }; if hash_primary != u_single_secondary.x[0] || hash_secondary != scalar_as_base::(u_single_secondary.x[1]) { + println!("Hash doesn't match"); return false; } + dbg!(pp + .r1cs_shape_primary + .is_sat(&u_range_primary, &w_range_primary)); + dbg!(pp + .r1cs_shape_secondary + .is_sat(&u_range_secondary, &w_range_secondary)); + dbg!(pp + .r1cs_shape_secondary + .is_sat(&u_single_secondary, &w_single_secondary)); + pp.r1cs_shape_primary .is_sat(&u_range_primary, &w_range_primary) && pp diff --git a/nova/src/relaxed_r1cs.rs b/nova/src/relaxed_r1cs.rs index 304fa557..996feca9 100644 --- a/nova/src/relaxed_r1cs.rs +++ b/nova/src/relaxed_r1cs.rs @@ -22,6 +22,7 @@ pub(crate) fn r1cs_instance_and_witness( cs: &R1cs, shape: &R1csShape, ) -> (Vec, Vec) { + println!("Cs.x = {:?}", cs.x()); assert_eq!(cs.m_l_1(), shape.m_l_1()); let w = cs.w(); let x = cs.x()[1..].to_vec(); diff --git a/nova/src/test.rs b/nova/src/test.rs index 1c7dd1af..89e8bd9b 100644 --- a/nova/src/test.rs +++ b/nova/src/test.rs @@ -13,6 +13,7 @@ pub(crate) struct ExampleFunction { impl FunctionCircuit for ExampleFunction { fn invoke(z: &DenseVectors) -> DenseVectors { + // z.clone() let next_z = z[0] * z[0] * z[0] + z[0] + F::from(5); DenseVectors::new(vec![next_z]) } @@ -26,5 +27,6 @@ impl FunctionCircuit for ExampleFunction { let z_i_cube = FieldAssignment::mul(cs, &z_i_square, &z_i[0]); vec![&(&z_i_cube + &z_i[0]) + &five] + // z_i } }