From 5f2f74377d94c0463de9d56a0f233b7227a73e85 Mon Sep 17 00:00:00 2001 From: Kirill Karbushev Date: Mon, 11 Dec 2023 16:39:57 +0900 Subject: [PATCH] adjust nova types, make instance allocations on provided CS --- nova/src/circuit/augmented.rs | 44 ++++++++++++++--------------- nova/src/circuit/nifs.rs | 14 ++++----- nova/src/circuit/transcript.rs | 39 ++++++++++++------------- nova/src/driver.rs | 15 ++++++++++ nova/src/function.rs | 13 +++++---- nova/src/gadget/mimc.rs | 2 +- nova/src/gadget/relaxed_instance.rs | 38 ++++++++++++++----------- nova/src/hash.rs | 28 +++++++++--------- nova/src/ivc.rs | 4 +-- nova/src/relaxed_r1cs.rs | 8 +++--- nova/src/relaxed_r1cs/instance.rs | 6 ++-- nova/src/test.rs | 21 +++++++------- 12 files changed, 127 insertions(+), 105 deletions(-) diff --git a/nova/src/circuit/augmented.rs b/nova/src/circuit/augmented.rs index aec22d41..62b4eab1 100644 --- a/nova/src/circuit/augmented.rs +++ b/nova/src/circuit/augmented.rs @@ -12,19 +12,19 @@ use zkstd::matrix::DenseVectors; use zkstd::r1cs::R1cs; #[derive(Debug, Clone)] -pub struct AugmentedFCircuit> { +pub struct AugmentedFCircuit> { pub i: usize, - pub z_0: DenseVectors, - pub z_i: DenseVectors, + pub z_0: DenseVectors, + pub z_i: DenseVectors, pub u_single: RelaxedR1csInstance, pub u_range: RelaxedR1csInstance, pub u_range_next: RelaxedR1csInstance, pub commit_t: C::Affine, pub f: PhantomData, - pub x: C::Scalar, + pub x: C::Base, } -impl> Default for AugmentedFCircuit { +impl> Default for AugmentedFCircuit { fn default() -> Self { Self { i: 0, @@ -44,10 +44,10 @@ impl> Default for AugmentedFCircuit> AugmentedFCircuit { - pub(crate) fn generate(&self, cs: &mut R1cs) { +impl> AugmentedFCircuit { + pub(crate) fn generate>(&self, cs: &mut R1cs) { // allocate inputs - let i = FieldAssignment::witness(cs, C::Scalar::from(self.i as u64)); + let i = FieldAssignment::witness(cs, C::Base::from(self.i as u64)); let z_0 = self .z_0 .iter() @@ -59,7 +59,7 @@ impl> AugmentedFCircuit { .map(|x| FieldAssignment::witness(cs, x)) .collect::>(); - let u_dummy_native = RelaxedR1csInstance::dummy(1); + let u_dummy_native = RelaxedR1csInstance::::dummy(1); let u_dummy = RelaxedR1csInstanceAssignment::witness(cs, &u_dummy_native); let u_i = RelaxedR1csInstanceAssignment::witness(cs, &self.u_single); let u_range = RelaxedR1csInstanceAssignment::witness(cs, &self.u_range); @@ -73,7 +73,7 @@ impl> AugmentedFCircuit { let x = FieldAssignment::instance(cs, self.x); let z_next = FC::invoke_cs(cs, z_i.clone()); - let zero = FieldAssignment::constant(&C::Scalar::zero()); + let zero = FieldAssignment::constant(&C::Base::zero()); let bin_true = BinaryAssignment::witness(cs, 1); let base_case = FieldAssignment::is_eq(cs, &i, &zero); @@ -105,7 +105,7 @@ impl> AugmentedFCircuit { FieldAssignment::conditional_enforce_equal( cs, &u_i.u, - &FieldAssignment::constant(&C::Scalar::one()), + &FieldAssignment::constant(&C::Base::one()), ¬_base_case, ); @@ -117,7 +117,7 @@ impl> AugmentedFCircuit { // 4. (base case) u_{i+1}.X == H(1, z_0, F(z_0)=F(z_i)=z_i1, U_i) (with U_i being dummy) let u_next_x_basecase = u_range.hash( cs, - FieldAssignment::constant(&C::Scalar::one()), + FieldAssignment::constant(&C::Base::one()), z_0.clone(), z_next.clone(), ); @@ -125,7 +125,7 @@ impl> AugmentedFCircuit { // 4. (non-base case). u_{i+1}.x = H(i+1, z_0, z_i+1, U_{i+1}) let u_next_x = u_range_next.hash( cs, - &i + &FieldAssignment::constant(&C::Scalar::one()), + &i + &FieldAssignment::constant(&C::Base::one()), z_0, z_next, ); @@ -136,12 +136,12 @@ impl> AugmentedFCircuit { FieldAssignment::conditional_enforce_equal(cs, &u_next_x, &x, ¬_base_case); } - pub(crate) fn get_challenge( - cs: &mut R1cs, + pub(crate) fn get_challenge>( + cs: &mut R1cs, u_range: &RelaxedR1csInstanceAssignment, - commit_t: PointAssignment, - ) -> FieldAssignment { - let mut transcript = MimcROCircuit::::default(); + commit_t: PointAssignment, + ) -> FieldAssignment { + let mut transcript = MimcROCircuit::::default(); transcript.append_point(commit_t); u_range.absorb_by_transcript(&mut transcript); transcript.squeeze(cs) @@ -151,16 +151,16 @@ impl> AugmentedFCircuit { #[cfg(test)] mod tests { use super::*; - use crate::driver::GrumpkinDriver; + use crate::driver::{Bn254Driver, GrumpkinDriver}; use crate::relaxed_r1cs::RelaxedR1csWitness; use crate::test::ExampleFunction; use crate::RelaxedR1cs; + use bn_254::Fr; #[test] fn augmented_circuit_dummies() { - let mut cs = R1cs::::default(); - let augmented_circuit = - AugmentedFCircuit::>::default(); + let mut cs = R1cs::::default(); + let augmented_circuit = AugmentedFCircuit::>::default(); augmented_circuit.generate(&mut cs); assert!(cs.is_sat()); diff --git a/nova/src/circuit/nifs.rs b/nova/src/circuit/nifs.rs index a42b352b..1b377965 100644 --- a/nova/src/circuit/nifs.rs +++ b/nova/src/circuit/nifs.rs @@ -8,9 +8,9 @@ pub(crate) struct NifsCircuit { } impl NifsCircuit { - pub(crate) fn verify( - cs: &mut R1cs, - r: FieldAssignment, + pub(crate) fn verify>( + cs: &mut R1cs, + r: FieldAssignment, instance1: RelaxedR1csInstanceAssignment, instance2: RelaxedR1csInstanceAssignment, instance3: RelaxedR1csInstanceAssignment, @@ -26,7 +26,7 @@ impl NifsCircuit { let r_x2 = FieldAssignment::mul(cs, &r, &x2); x1 + &r_x2 }) - .collect::>>(); + .collect::>>(); let second_check = x.iter() .zip(instance3.x) @@ -41,7 +41,7 @@ impl NifsCircuit { #[cfg(test)] mod tests { use super::*; - use crate::driver::GrumpkinDriver; + use crate::driver::{Bn254Driver, GrumpkinDriver}; use crate::hash::{MimcRO, MIMC_ROUNDS}; use crate::prover::tests::example_prover; use crate::RelaxedR1cs; @@ -51,13 +51,13 @@ mod tests { #[test] fn nifs_circuit() { let prover = example_prover(); - let r1cs = example_r1cs(1); + let r1cs = example_r1cs::(1); let running_r1cs = RelaxedR1cs::new(r1cs); let r1cs_to_fold = RelaxedR1cs::new(example_r1cs(2)); let (instance, witness, commit_t) = prover.prove(&r1cs_to_fold, &running_r1cs); - let mut transcript = MimcRO::::default(); + let mut transcript = MimcRO::::default(); transcript.append_point(commit_t); running_r1cs.absorb_by_transcript(&mut transcript); let t = prover.compute_cross_term(&r1cs_to_fold, &running_r1cs); diff --git a/nova/src/circuit/transcript.rs b/nova/src/circuit/transcript.rs index de17b670..9f124f01 100644 --- a/nova/src/circuit/transcript.rs +++ b/nova/src/circuit/transcript.rs @@ -1,49 +1,49 @@ use crate::gadget::MimcAssignment; use zkstd::circuit::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; -use zkstd::common::{IntGroup, PrimeField}; +use zkstd::common::IntGroup; -pub(crate) struct MimcROCircuit { - hasher: MimcAssignment, - state: Vec>, - key: FieldAssignment, +pub(crate) struct MimcROCircuit { + hasher: MimcAssignment, + state: Vec>, + key: FieldAssignment, } -impl Default for MimcROCircuit { +impl Default for MimcROCircuit { fn default() -> Self { Self { hasher: MimcAssignment::default(), state: Vec::default(), - key: FieldAssignment::constant(&F::zero()), + key: FieldAssignment::constant(&C::Base::zero()), } } } -impl MimcROCircuit { - pub(crate) fn append(&mut self, absorb: FieldAssignment) { +impl MimcROCircuit { + pub(crate) fn append(&mut self, absorb: FieldAssignment) { self.state.push(absorb) } - pub(crate) fn hash_vec>( + pub(crate) fn hash_vec>( &mut self, - cs: &mut R1cs, - values: Vec>, - ) -> FieldAssignment { + cs: &mut R1cs, + values: Vec>, + ) -> FieldAssignment { for x in values { self.state.push(x); } self.squeeze(cs) } - pub(crate) fn append_point(&mut self, point: PointAssignment) { + pub(crate) fn append_point(&mut self, point: PointAssignment) { self.append(point.get_x()); self.append(point.get_y()); self.append(point.get_z()); } - pub(crate) fn squeeze>( + pub(crate) fn squeeze>( &self, - cs: &mut R1cs, - ) -> FieldAssignment { + cs: &mut R1cs, + ) -> FieldAssignment { self.state.iter().fold(self.key.clone(), |acc, scalar| { let h = self.hasher.hash(cs, scalar.clone(), acc.clone()); &(&acc + scalar) + &h @@ -57,7 +57,8 @@ mod tests { use crate::hash::{MimcRO, MIMC_ROUNDS}; use crate::driver::{Bn254Driver, GrumpkinDriver}; - use bn_254::{Fq, Fr, G1Affine}; + use bn_254::Fr; + use grumpkin::Affine; use rand_core::OsRng; use zkstd::circuit::prelude::{FieldAssignment, PointAssignment, R1cs}; use zkstd::common::Group; @@ -67,7 +68,7 @@ mod tests { let mut mimc = MimcRO::::default(); let mut mimc_circuit = MimcROCircuit::::default(); // Base = Fr, Scalar = Fq let mut cs: R1cs = R1cs::default(); // Base = Fq, Scalar = Fr - let point = G1Affine::random(OsRng); // Base = Fq, Scalar = Fr + let point = Affine::random(OsRng); // Base = Fr, Scalar = Fq let scalar = Fr::random(OsRng); let point_assignment = PointAssignment::instance(&mut cs, point); diff --git a/nova/src/driver.rs b/nova/src/driver.rs index 90d3eda6..c5863ff1 100644 --- a/nova/src/driver.rs +++ b/nova/src/driver.rs @@ -1,6 +1,7 @@ use bn_254::{params::PARAM_B3 as BN254_PARAM_B3, Fq, Fr, G1Affine}; use grumpkin::{params::PARAM_B3 as GRUMPKIN_PARAM_B3, Affine}; use zkstd::circuit::CircuitDriver; +use zkstd::common::{IntGroup, PrimeField, Ring}; #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct GrumpkinDriver; @@ -34,6 +35,20 @@ impl CircuitDriver for Bn254Driver { } } +/// interpret scalar as base +pub fn scalar_as_base(input: C::Scalar) -> C::Base { + let input_bits = input.to_bits(); + let mut mult = C::Base::one(); + let mut val = C::Base::zero(); + for bit in input_bits.iter().rev() { + if *bit == 1 { + val += mult; + } + mult = mult + mult; + } + val +} + #[cfg(test)] mod grumpkin_gadget_tests { use super::{Fq as Scalar, Fr as Base, GrumpkinDriver}; diff --git a/nova/src/function.rs b/nova/src/function.rs index e757e725..d0741309 100644 --- a/nova/src/function.rs +++ b/nova/src/function.rs @@ -1,13 +1,14 @@ use std::fmt::Debug; use zkstd::circuit::prelude::{CircuitDriver, FieldAssignment}; +use zkstd::common::PrimeField; use zkstd::matrix::DenseVectors; use zkstd::r1cs::R1cs; -pub trait FunctionCircuit: Clone + Debug + Default { - fn invoke(z_i: &DenseVectors) -> DenseVectors; +pub trait FunctionCircuit: Clone + Debug + Default { + fn invoke(z_i: &DenseVectors) -> DenseVectors; - fn invoke_cs( - cs: &mut R1cs, - z_i: Vec>, - ) -> Vec>; + fn invoke_cs>( + cs: &mut R1cs, + z_i: Vec>, + ) -> Vec>; } diff --git a/nova/src/gadget/mimc.rs b/nova/src/gadget/mimc.rs index 7d76f82e..3846411d 100644 --- a/nova/src/gadget/mimc.rs +++ b/nova/src/gadget/mimc.rs @@ -16,7 +16,7 @@ impl Default for MimcAssignment { } impl MimcAssignment { - pub(crate) fn hash>( + pub(crate) fn hash>( &self, cs: &mut R1cs, mut xl: FieldAssignment, diff --git a/nova/src/gadget/relaxed_instance.rs b/nova/src/gadget/relaxed_instance.rs index c9fc7073..2b8acddb 100644 --- a/nova/src/gadget/relaxed_instance.rs +++ b/nova/src/gadget/relaxed_instance.rs @@ -1,21 +1,22 @@ use crate::relaxed_r1cs::RelaxedR1csInstance; use crate::circuit::MimcROCircuit; +use crate::driver::scalar_as_base; use crate::hash::MIMC_ROUNDS; use zkstd::circuit::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; use zkstd::common::CurveGroup; #[derive(Clone)] pub(crate) struct RelaxedR1csInstanceAssignment { - pub(crate) commit_w: PointAssignment, - pub(crate) commit_e: PointAssignment, - pub(crate) u: FieldAssignment, - pub(crate) x: Vec>, + pub(crate) commit_w: PointAssignment, + pub(crate) commit_e: PointAssignment, + pub(crate) u: FieldAssignment, + pub(crate) x: Vec>, } impl RelaxedR1csInstanceAssignment { - pub(crate) fn witness( - cs: &mut R1cs, + pub(crate) fn witness>( + cs: &mut R1cs, relaxed_r1cs_instance: &RelaxedR1csInstance, ) -> Self { let RelaxedR1csInstance { @@ -27,8 +28,8 @@ impl RelaxedR1csInstanceAssignment { let commit_w = PointAssignment::witness( cs, - commit_w.get_x().into(), - commit_w.get_y().into(), + commit_w.get_x(), + commit_w.get_y(), commit_w.is_identity(), ); let commit_e = PointAssignment::witness( @@ -37,8 +38,11 @@ impl RelaxedR1csInstanceAssignment { commit_e.get_y().into(), commit_e.is_identity(), ); - let u = FieldAssignment::witness(cs, *u); - let x = x.iter().map(|x| FieldAssignment::witness(cs, x)).collect(); + let u = FieldAssignment::witness(cs, scalar_as_base::(*u)); + let x = x + .iter() + .map(|x| FieldAssignment::witness(cs, scalar_as_base::(x))) + .collect(); Self { commit_w, @@ -50,7 +54,7 @@ impl RelaxedR1csInstanceAssignment { pub(crate) fn absorb_by_transcript( &self, - transcript: &mut MimcROCircuit, + transcript: &mut MimcROCircuit, ) { transcript.append_point(self.commit_w.clone()); transcript.append_point(self.commit_e.clone()); @@ -60,13 +64,13 @@ impl RelaxedR1csInstanceAssignment { } } - pub(crate) fn hash( + pub(crate) fn hash>( &self, - cs: &mut R1cs, - i: FieldAssignment, - z_0: Vec>, - z_i: Vec>, - ) -> FieldAssignment { + cs: &mut R1cs, + i: FieldAssignment, + z_0: Vec>, + z_i: Vec>, + ) -> FieldAssignment { MimcROCircuit::::default().hash_vec( cs, vec![ diff --git a/nova/src/hash.rs b/nova/src/hash.rs index ad9fdda8..1d8af057 100644 --- a/nova/src/hash.rs +++ b/nova/src/hash.rs @@ -2,7 +2,7 @@ mod helper; use helper::BlakeHelper; use zkstd::circuit::CircuitDriver; -use zkstd::common::{BNAffine, CurveGroup, IntGroup, PrimeField, Ring}; +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. @@ -41,45 +41,45 @@ impl Mimc { } } -pub(crate) struct MimcRO { - hasher: Mimc, - state: Vec, - key: F, +pub(crate) struct MimcRO { + hasher: Mimc, + state: Vec, + key: C::Base, } -impl Default for MimcRO { +impl Default for MimcRO { fn default() -> Self { Self { hasher: Mimc::default(), state: Vec::default(), - key: F::zero(), + key: C::Base::zero(), } } } -impl MimcRO { - pub(crate) fn append(&mut self, absorb: F) { +impl MimcRO { + pub(crate) fn append(&mut self, absorb: C::Base) { self.state.push(absorb) } - pub(crate) fn append_point(&mut self, point: impl BNAffine) { + pub(crate) fn append_point(&mut self, point: impl BNAffine) { self.append(point.get_x()); self.append(point.get_y()); self.append(if point.is_identity() { - F::zero() + C::Base::zero() } else { - F::one() + C::Base::one() }); } - pub(crate) fn hash_vec(&mut self, values: Vec) -> F { + pub(crate) fn hash_vec(&mut self, values: Vec) -> C::Base { for x in values { self.state.push(x); } self.squeeze() } - pub(crate) fn squeeze(&self) -> F { + pub(crate) fn squeeze(&self) -> C::Base { self.state.iter().fold(self.key, |acc, scalar| { let h = self.hasher.hash(*scalar, acc); acc + scalar + h diff --git a/nova/src/ivc.rs b/nova/src/ivc.rs index 28e01724..64c81302 100644 --- a/nova/src/ivc.rs +++ b/nova/src/ivc.rs @@ -9,7 +9,7 @@ use zkstd::circuit::prelude::{CircuitDriver, R1cs}; use zkstd::common::{Group, RngCore}; use zkstd::matrix::DenseVectors; -pub struct Ivc> { +pub struct Ivc> { i: usize, z0: DenseVectors, zi: DenseVectors, @@ -26,7 +26,7 @@ pub struct Ivc> { f: PhantomData, } -impl> Ivc { +impl> Ivc { pub fn new(rng: impl RngCore, z0: DenseVectors) -> Self { let mut r1cs = R1cs::default(); diff --git a/nova/src/relaxed_r1cs.rs b/nova/src/relaxed_r1cs.rs index a7792581..89139548 100644 --- a/nova/src/relaxed_r1cs.rs +++ b/nova/src/relaxed_r1cs.rs @@ -12,9 +12,9 @@ pub struct RelaxedR1cs { // 1. Structure S // a, b and c matrices and matrix size m: usize, - a: SparseMatrix, - b: SparseMatrix, - c: SparseMatrix, + a: SparseMatrix, + b: SparseMatrix, + c: SparseMatrix, // 2. Instance // r1cs instance includes public inputs, outputs and scalar @@ -139,7 +139,7 @@ impl RelaxedR1cs { pub(crate) fn absorb_by_transcript( &self, - transcript: &mut MimcRO, + transcript: &mut MimcRO, ) { self.instance.absorb_by_transcript(transcript); } diff --git a/nova/src/relaxed_r1cs/instance.rs b/nova/src/relaxed_r1cs/instance.rs index 9f9f0eaf..cb2e3c78 100644 --- a/nova/src/relaxed_r1cs/instance.rs +++ b/nova/src/relaxed_r1cs/instance.rs @@ -60,7 +60,7 @@ impl RelaxedR1csInstance { pub(crate) fn absorb_by_transcript( &self, - transcript: &mut MimcRO, + transcript: &mut MimcRO, ) { transcript.append_point(self.commit_w); transcript.append_point(self.commit_e); @@ -75,10 +75,10 @@ impl RelaxedR1csInstance { i: usize, z_0: &DenseVectors, z_i: &DenseVectors, - ) -> C::Scalar { + ) -> C::Base { let commit_e = self.commit_e.to_extended(); let commit_w = self.commit_w.to_extended(); - MimcRO::::default().hash_vec( + MimcRO::::default().hash_vec( vec![ vec![C::Base::from(i as u64)], z_0.get(), diff --git a/nova/src/test.rs b/nova/src/test.rs index a43c30a9..1c7dd1af 100644 --- a/nova/src/test.rs +++ b/nova/src/test.rs @@ -2,25 +2,26 @@ use crate::function::FunctionCircuit; use core::marker::PhantomData; use zkstd::circuit::prelude::{CircuitDriver, FieldAssignment}; +use zkstd::common::PrimeField; use zkstd::matrix::DenseVectors; use zkstd::r1cs::R1cs; #[derive(Debug, Clone, Default)] -pub(crate) struct ExampleFunction { - mark: PhantomData, +pub(crate) struct ExampleFunction { + mark: PhantomData, } -impl FunctionCircuit for ExampleFunction { - fn invoke(z: &DenseVectors) -> DenseVectors { - let next_z = z[0] * z[0] * z[0] + z[0] + C::Scalar::from(5); +impl FunctionCircuit for ExampleFunction { + fn invoke(z: &DenseVectors) -> DenseVectors { + let next_z = z[0] * z[0] * z[0] + z[0] + F::from(5); DenseVectors::new(vec![next_z]) } - fn invoke_cs( - cs: &mut R1cs, - z_i: Vec>, - ) -> Vec> { - let five = FieldAssignment::constant(&C::Scalar::from(5)); + fn invoke_cs>( + cs: &mut R1cs, + z_i: Vec>, + ) -> Vec> { + let five = FieldAssignment::constant(&F::from(5)); let z_i_square = FieldAssignment::mul(cs, &z_i[0], &z_i[0]); let z_i_cube = FieldAssignment::mul(cs, &z_i_square, &z_i[0]);