From 40968c80c5c7ba86848f1cda37671a070eaf6ae0 Mon Sep 17 00:00:00 2001 From: Adrian Hamelink Date: Wed, 24 Jan 2024 00:14:12 +0100 Subject: [PATCH] fiddling --- src/parafold/circuit.rs | 141 -------------- src/parafold/cycle_fold/circuit.rs | 6 +- src/parafold/cycle_fold/mod.rs | 23 +-- src/parafold/cycle_fold/prover.rs | 2 +- src/parafold/mod.rs | 2 - src/parafold/nifs_primary/mod.rs | 5 +- src/parafold/nifs_primary/prover.rs | 261 ++++++++++++-------------- src/parafold/nivc/circuit.rs | 64 +++---- src/parafold/nivc/circuit_alloc.rs | 4 +- src/parafold/nivc/hash.rs | 26 +++ src/parafold/nivc/mod.rs | 11 +- src/parafold/nivc/prover.rs | 39 ++-- src/parafold/prover.rs | 280 +++++++++++----------------- 13 files changed, 329 insertions(+), 535 deletions(-) delete mode 100644 src/parafold/circuit.rs create mode 100644 src/parafold/nivc/hash.rs diff --git a/src/parafold/circuit.rs b/src/parafold/circuit.rs deleted file mode 100644 index f36c1e028..000000000 --- a/src/parafold/circuit.rs +++ /dev/null @@ -1,141 +0,0 @@ -use bellpepper_core::num::AllocatedNum; -use bellpepper_core::{ConstraintSystem, SynthesisError}; - -use crate::parafold::nivc::circuit::NIVCHasher; -use crate::parafold::nivc::NIVCUpdateProof; -use crate::parafold::nivc::{AllocatedNIVCState, AllocatedNIVCStateProof}; -use crate::parafold::transcript::circuit::AllocatedTranscript; -use crate::traits::circuit_supernova::StepCircuit; -use crate::traits::{Engine, ROConstantsCircuit}; - -pub fn step< - C: StepCircuit, - E1: Engine, - E2: Engine, - CS: ConstraintSystem, ->( - cs: &mut CS, - pp: E1::Scalar, - ro_consts: ROConstantsCircuit, - circuit: C, - proof: NIVCUpdateProof, -) -> Result<(), SynthesisError> { - let arity = circuit.arity(); - let pp = AllocatedNum::alloc_infallible(cs.namespace(|| "alloc pp"), || pp); - let hasher = NIVCHasher::new(ro_consts.clone(), pp, arity); - let mut transcript = AllocatedTranscript::new(ro_consts); - let proof = AllocatedNIVCStateProof::alloc_infallible(cs.namespace(|| "alloc proof"), || proof); - let _state = AllocatedNIVCState::new_step( - cs.namespace(|| ""), - &hasher, - proof, - circuit, - &mut transcript, - )?; - Ok(()) - // state. -} - -// /// Given the state transition over the io -// /// `self_state = (vk_self, vk_nivc, self_acc, nivc_acc, nivc_io)` -// /// self_io = {self_state_curr, self_state_next} -// pub struct StateTransitionCircuit { -// /// Random-oracle constants -// ro_consts: ROConstantsCircuit, -// -// /// Hash of public parameters for IVC -// pp: AllocatedNum, -// -// state: AllocatedRecursionState, -// -// transcript: AllocatedTranscript, -// } -// -// impl StateTransitionCircuit { -// pub fn new( -// mut cs: CS, -// pk: &ProvingKey, -// self_acc_prev: RelaxedR1CSInstance, -// nivc_acc_curr: impl IntoIterator>>, -// nivc_state: NIVCState, -// ) -> Result -// where -// CS: ConstraintSystem, -// { -// let ro_consts = ROConstantsCircuit::::default(); -// -// let pp_self = AllocatedNum::alloc_infallible(cs.namespace(|| "alloc pp_self"), || pk.pp); -// let pp_nivc = pk -// .nivc -// .iter() -// .enumerate() -// .map(|(i, pk_nivc)| { -// AllocatedNum::alloc_infallible(cs.namespace(|| format!("alloc pp_nivc[{i}]")), || { -// pk_nivc.pp -// }) -// }) -// .collect::>(); -// -// let self_acc_prev = AllocatedRelaxedR1CSInstance::alloc_infallible( -// cs.namespace(|| "alloc self_acc_prev"), -// || self_acc_prev, -// ); -// -// let nivc_acc_curr = nivc_acc_curr -// .into_iter() -// .enumerate() -// .map(|(i, nivc_acc)| { -// AllocatedRelaxedR1CSInstance::alloc_infallible( -// cs.namespace(|| format!("alloc nivc_acc_prev[{i}]")), -// || nivc_acc.unwrap_or(RelaxedR1CSInstance::default(&pk.nivc[i].shape)), -// ) -// }) -// .collect::>(); -// -// let nivc_state = -// AllocatedNIVCIO::alloc_infallible(cs.namespace(|| "alloc nivc_state"), || nivc_state); -// -// Ok(Self { -// ro_consts, -// pp_self, -// pp_nivc, -// self_acc: self_acc_prev, -// nivc_acc: nivc_acc_curr, -// nivc_state, -// scalar_mul_instances: vec![], -// transcript: AllocatedTranscript::new()?, -// }) -// } -// -// // pub(crate) fn finalize(&self, mut cs: CS) -> Result<(), SynthesisError> -// // where -// // CS: ConstraintSystem, -// // { -// // let self_io_hash_next: AllocatedNum = Self::io_hash( -// // cs.namespace(|| "self_io_hash_next"), -// // &self.ro_consts, -// // &self.pp_self, -// // &self.pp_nivc, -// // &self.self_acc, // self_acc_curr -// // &self.nivc_acc, // self_acc_next -// // &self.nivc_state, -// // )?; -// // -// // self_io_hash_next.inputize(cs.namespace(|| "inputize self_io_hash_curr")) -// // } -// -// // fn io_hash( -// // /*mut*/ _cs: CS, -// // _ro_consts: &ROConstantsCircuit, -// // _pp_self: &AllocatedNum, -// // _pp_nivc: &[AllocatedNum], -// // _self_acc: &AllocatedRelaxedR1CSInstance, -// // _nivc_acc: &[AllocatedRelaxedR1CSInstance], -// // _nivc_state: &AllocatedNIVCIO, -// // ) -> Result, SynthesisError> -// // where -// // CS: ConstraintSystem, -// // { -// // todo!() -// // } -// } diff --git a/src/parafold/cycle_fold/circuit.rs b/src/parafold/cycle_fold/circuit.rs index 6eacabe3f..881cf770a 100644 --- a/src/parafold/cycle_fold/circuit.rs +++ b/src/parafold/cycle_fold/circuit.rs @@ -9,7 +9,11 @@ use crate::parafold::nifs_secondary::AllocatedSecondaryRelaxedR1CSInstance; use crate::parafold::transcript::circuit::AllocatedTranscript; use crate::traits::Engine; -impl> AllocatedScalarMulAccumulator { +impl AllocatedScalarMulAccumulator +where + E1: Engine, + E2: Engine, +{ /// Compute the result `C <- A + x * B` by folding a proof over the secondary curve. pub fn scalar_mul( &mut self, diff --git a/src/parafold/cycle_fold/mod.rs b/src/parafold/cycle_fold/mod.rs index 39748a8f4..114b835fb 100644 --- a/src/parafold/cycle_fold/mod.rs +++ b/src/parafold/cycle_fold/mod.rs @@ -10,10 +10,10 @@ use crate::parafold::nifs_secondary::{ AllocatedSecondaryFoldProof, AllocatedSecondaryMergeProof, AllocatedSecondaryRelaxedR1CSInstance, }; use crate::parafold::nifs_secondary::{SecondaryFoldProof, SecondaryMergeProof}; -use crate::parafold::transcript::prover::TranscriptRepresentable; use crate::traits::commitment::CommitmentTrait; use crate::traits::Engine; use crate::Commitment; +use crate::parafold::transcript; pub mod circuit; mod circuit_alloc; @@ -70,7 +70,7 @@ pub struct AllocatedHashedCommitment { hash: BigNat, } -impl crate::parafold::transcript::circuit::TranscriptRepresentable +impl transcript::circuit::TranscriptRepresentable for AllocatedHashedCommitment { fn to_field_vec(&self) -> Vec> { @@ -101,12 +101,17 @@ impl HashedCommitment { } } -impl TranscriptRepresentable for HashedCommitment { +impl transcript::prover::TranscriptRepresentable for HashedCommitment { fn to_field_vec(&self) -> Vec { self.hash_limbs.clone() } } +#[derive(Debug, Clone, PartialEq)] +pub struct ScalarMulAccumulatorInstance { + acc: SecondaryRelaxedR1CSInstance, +} + /// Circuit representation of a RelaxedR1CS accumulator of the non-native scalar multiplication circuit. /// /// # Future work @@ -127,12 +132,7 @@ impl TranscriptRepresentable for HashedCommitment { /// of deferred instances. #[derive(Debug, Clone)] pub struct AllocatedScalarMulAccumulator { - pub acc: AllocatedSecondaryRelaxedR1CSInstance, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct ScalarMulAccumulatorInstance { - acc: SecondaryRelaxedR1CSInstance, + acc: AllocatedSecondaryRelaxedR1CSInstance, } /// A proof for a non-native group operation C = A + x * B, where x is a native scalar @@ -145,10 +145,11 @@ pub struct ScalarMulFoldProof { #[derive(Debug, Clone)] pub struct AllocatedScalarMulFoldProof { - pub output: AllocatedHashedCommitment, - pub proof: AllocatedSecondaryFoldProof, + output: AllocatedHashedCommitment, + proof: AllocatedSecondaryFoldProof, } +/// #[derive(Debug, Clone)] pub struct ScalarMulMergeProof { proof: SecondaryMergeProof, diff --git a/src/parafold/cycle_fold/prover.rs b/src/parafold/cycle_fold/prover.rs index 4b9ee3139..51e642660 100644 --- a/src/parafold/cycle_fold/prover.rs +++ b/src/parafold/cycle_fold/prover.rs @@ -34,7 +34,7 @@ impl ScalarMulAccumulator { /// Compute pub fn merge>( self, - _other: Self, + _other: &Self, _transcript: &mut Transcript, ) -> (Self, ScalarMulMergeProof) { // self and other will not need to be added to the transcript since they are obtained from an accumulator diff --git a/src/parafold/mod.rs b/src/parafold/mod.rs index f6472b620..5611e6917 100644 --- a/src/parafold/mod.rs +++ b/src/parafold/mod.rs @@ -1,6 +1,4 @@ #[allow(dead_code)] -mod circuit; -#[allow(dead_code)] mod cycle_fold; #[allow(dead_code)] mod ecc; diff --git a/src/parafold/nifs_primary/mod.rs b/src/parafold/nifs_primary/mod.rs index ebc7aec59..69a37b067 100644 --- a/src/parafold/nifs_primary/mod.rs +++ b/src/parafold/nifs_primary/mod.rs @@ -26,6 +26,7 @@ pub struct AllocatedRelaxedR1CSInstance { E: AllocatedHashedCommitment, } + /// A proof for folding a statement X of a circuit C into a Relaxed-R1CS circuit for the same circuit C #[derive(Debug, Clone, Default)] pub struct FoldProof { @@ -35,8 +36,7 @@ pub struct FoldProof { E_sm_proof: ScalarMulFoldProof, } -/// An allocated Nova folding proof, for either folding an [R1CSInstance] or a [RelaxedR1CSInstance] into -/// another [RelaxedR1CSInstance] +/// Allocated [FoldProof] #[derive(Debug, Clone)] pub struct AllocatedFoldProof { pub W: AllocatedHashedCommitment, @@ -54,6 +54,7 @@ pub struct MergeProof { E2_sm_proof: ScalarMulFoldProof, } +/// Allocated [MergeProof] #[derive(Debug, Clone)] pub struct AllocatedMergeProof { T: AllocatedHashedCommitment, diff --git a/src/parafold/nifs_primary/prover.rs b/src/parafold/nifs_primary/prover.rs index 2f7cefc17..266436aeb 100644 --- a/src/parafold/nifs_primary/prover.rs +++ b/src/parafold/nifs_primary/prover.rs @@ -32,8 +32,10 @@ impl RelaxedR1CS { &self.instance } - /// Fold the proof for the previous state transition, producing an accumulator for the current state, - /// and a proof to be consumed by the verifier. + /// Given the public IO `X_new` for a circuit with R1CS representation `shape`, + /// along with a satisfying witness vector `W_new`, and assuming `self` is a valid accumulator for the same circuit, + /// this function will fold the statement into `self` and return a [FoldProof] that will allow the verifier to perform + /// the same transformation over the corresponding [RelaxedR1CSInstance] of the input `self`. /// /// # Warning /// We assume the R1CS IO `X_new` has already been absorbed in some form into the transcript in order to avoid @@ -58,75 +60,30 @@ impl RelaxedR1CS { transcript.absorb(&T_comm); let r = transcript.squeeze(); - let Self { - instance: instance_curr, - W: W_curr, - E: E_curr, - } = self; - - let (instance_next, W_sm_proof, E_sm_proof) = { - // Unpack accumulator - let RelaxedR1CSInstance { - u: u_curr, - X: X_curr, - W: W_comm_curr, - E: E_comm_curr, - } = instance_curr; - - // For relaxed instances, u_new = 1 - let u_next = *u_curr + r; - let X_next = zip_eq(X_curr, X_new) - .map(|(x_curr, x_new)| *x_curr + r * x_new) - .collect::>(); - // Compute scalar multiplications and resulting instances to be proved with the CycleFold circuit - // W_comm_next = W_comm_curr + r * W_comm_new - let (W_comm_next, W_sm_proof) = acc_sm.scalar_mul(&W_comm_curr, &W_comm_new, &r, transcript); - // E_comm_next = E_comm_curr + r * T - let (E_comm_next, E_sm_proof) = acc_sm.scalar_mul(&E_comm_curr, &T_comm, &r, transcript); - - let instance_next = RelaxedR1CSInstance { - u: u_next, - X: X_next, - W: W_comm_next, - E: E_comm_next, - }; - (instance_next, W_sm_proof, E_sm_proof) - }; - - let W_next = zip_with!( - (W_curr.into_par_iter(), W_new.par_iter()), - |w_curr, w_new| *w_curr + r * w_new - ) - .collect::>(); - let E_next = zip_with!( - (E_curr.into_par_iter(), T.par_iter()), - |e_curr, e_new| *e_curr + r * e_new - ) - .collect::>(); - - let fold_proof = FoldProof { - W: W_comm_new, - T: T_comm, - W_sm_proof, - E_sm_proof, - }; - - *self = Self { - instance: instance_next, - W: W_next, - E: E_next, - }; - + self + .W + .par_iter_mut() + .zip_eq(W_new.par_iter()) + .for_each(|(w, w_new)| *w += r * w_new); + + self + .E + .par_iter_mut() + .zip_eq(T.par_iter()) + .for_each(|(e, t)| *e += r * t); + + let fold_proof = self + .instance + .fold_aux(acc_sm, X_new, W_comm_new, T_comm, r, transcript); fold_proof } - /// Fold the proof for the previous state transition, producing an accumulator for the current state, - /// and a proof to be consumed by the verifier. + /// Given two lists of [RelaxedR1CS] accumulators, pub fn merge_many( ck: &CommitmentKey, shapes: &[R1CSShape], mut accs_L: Vec, - accs_R: Vec, + accs_R: &[Self], acc_sm: &mut ScalarMulAccumulator, transcript: &mut Transcript, ) -> (Vec, Vec>) @@ -153,92 +110,41 @@ impl RelaxedR1CS { } let r = transcript.squeeze(); - let (accs_next, merge_proofs): (Vec<_>, Vec<_>) = zip_with!( + zip_with!( ( accs_L.into_iter(), - accs_R.into_iter(), + accs_R.iter(), Ts.iter(), T_comms.into_iter() ), |acc_L, acc_R, T, T_comm| { - let Self { - instance: instance_L, - W: W_L, - E: E_L, - } = acc_L; - let Self { - instance: instance_R, - W: W_R, - E: E_R, - } = acc_R; - - let W_next = zip_with!((W_L.into_par_iter(), W_R.par_iter()), |w_L, w_R| w_L - + r * w_R) - .collect::>(); - let E_next = zip_with!( - (E_L.into_par_iter(), T.par_iter(), E_R.par_iter()), - |e_L, t, e_R| { - let e_tmp = *t + r * e_R; - e_L + r * e_tmp - } + let W = zip_with!( + (acc_L.W.into_par_iter(), acc_R.W.par_iter()), + |w_L, w_R| w_L + r * w_R ) - .collect::>(); - - let (instance_next, W_sm_proof, E1_sm_proof, E2_sm_proof) = { - // Unpack accumulator - let RelaxedR1CSInstance { - u: u_L, - X: X_L, - W: W_L, - E: E_L, - } = instance_L; - - // Unpack fresh proof - let RelaxedR1CSInstance { - u: u_R, - X: X_R, - W: W_R, - E: E_R, - } = instance_R; - - let u_next = u_L + r * u_R; - let X_next = zip_eq(X_L.into_iter(), X_R.iter()) - .map(|(x_L, x_R)| x_L + r * x_R) - .collect::>(); - // Compute scalar multiplications and resulting instances to be proved with the CycleFold circuit - // W_next = W_L + r * W_R - let (W_next, W_sm_proof) = acc_sm.scalar_mul::(&W_L, &W_R, &r, transcript); - let (E1_next, E1_sm_proof) = acc_sm.scalar_mul::(&T_comm, &E_R, &r, transcript); - // E_next = E_curr + r * E1_next = E_curr + r * T + r^2 * E_new - let (E_next, E2_sm_proof) = acc_sm.scalar_mul::(&E_L, &E1_next, &r, transcript); - - let instance_next = RelaxedR1CSInstance { - u: u_next, - X: X_next, - W: W_next, - E: E_next, - }; - (instance_next, W_sm_proof, E1_sm_proof, E2_sm_proof) - }; - - let acc_next = Self { - instance: instance_next, - W: W_next, - E: E_next, - }; - - let merge_proof = MergeProof { - T: T_comm, - W_sm_proof, - E1_sm_proof, - E2_sm_proof, - }; - (acc_next, merge_proof) + .collect(); + + let E = zip_with!( + (acc_L.E.into_par_iter(), T.par_iter(), acc_R.E.par_iter()), + |e_L, t, e_R| e_L + r * (*t + r * e_R) + ) + .collect(); + + let (instance, merge_proof) = RelaxedR1CSInstance::merge_aux( + acc_L.instance, + &acc_R.instance, + acc_sm, + T_comm, + r, + transcript, + ); + + let acc = Self { instance, W, E }; + + (acc, merge_proof) } ) - .unzip(); - - (accs_next, merge_proofs) + .unzip() } fn compute_fold_proof( @@ -253,3 +159,76 @@ impl RelaxedR1CS { todo!() } } + +impl RelaxedR1CSInstance { + pub fn fold_aux( + &mut self, + acc_sm: &mut ScalarMulAccumulator, + X_new: Vec, + W_new: HashedCommitment, + T: HashedCommitment, + r: E1::Scalar, + transcript: &mut Transcript, + ) -> FoldProof + where + E2: Engine, + { + // For non-relaxed instances, u_new = 1 + self.u += r; + self + .X + .iter_mut() + .zip_eq(X_new) + .for_each(|(x, x_new)| *x += r * x_new); + + // Compute scalar multiplications and resulting instances to be proved with the CycleFold circuit + // W_comm_next = W_comm_curr + r * W_comm_new + let (W, W_sm_proof) = acc_sm.scalar_mul(&self.W, &W_new, &r, transcript); + self.W = W; + + // E_comm_next = E_comm_curr + r * T + let (E, E_sm_proof) = acc_sm.scalar_mul(&self.E, &T, &r, transcript); + self.E = E; + + FoldProof { + W: W_new, + T, + W_sm_proof, + E_sm_proof, + } + } + + pub fn merge_aux( + acc_L: Self, + acc_R: &Self, + acc_sm: &mut ScalarMulAccumulator, + T: HashedCommitment, + r: E1::Scalar, + transcript: &mut Transcript, + ) -> (Self, MergeProof) + where + E2: Engine, + { + let u = acc_L.u + r * &acc_R.u; + let X = zip_eq(acc_L.X.into_iter(), acc_R.X.iter()) + .map(|(x_L, x_R)| x_L + r * x_R) + .collect(); + + // Compute scalar multiplications and resulting instances to be proved with the CycleFold circuit + // W_next = W_L + r * W_R + let (W, W_sm_proof) = acc_sm.scalar_mul::(&acc_L.W, &acc_R.W, &r, transcript); + + let (E1_next, E1_sm_proof) = acc_sm.scalar_mul::(&T, &acc_R.E, &r, transcript); + // E_next = E_L + r * E1_next = E_L + r * T + r^2 * E_R + let (E, E2_sm_proof) = acc_sm.scalar_mul::(&acc_L.E, &E1_next, &r, transcript); + let instance = Self { u, X, W, E }; + + let merge_proof = MergeProof { + T, + W_sm_proof, + E1_sm_proof, + E2_sm_proof, + }; + (instance, merge_proof) + } +} diff --git a/src/parafold/nivc/circuit.rs b/src/parafold/nivc/circuit.rs index 3dbc8ee40..da8839b65 100644 --- a/src/parafold/nivc/circuit.rs +++ b/src/parafold/nivc/circuit.rs @@ -7,12 +7,14 @@ use itertools::zip_eq; use crate::gadgets::utils::{alloc_num_equals, alloc_zero}; use crate::parafold::cycle_fold::AllocatedScalarMulAccumulator; use crate::parafold::nifs_primary::AllocatedRelaxedR1CSInstance; +use crate::parafold::nivc::hash::{AllocatedNIVCHasher, NIVCHasher}; use crate::parafold::nivc::{ - AllocatedNIVCIO, AllocatedNIVCMergeProof, AllocatedNIVCState, AllocatedNIVCStateProof, + AllocatedNIVCIO, AllocatedNIVCMergeProof, AllocatedNIVCState, AllocatedNIVCUpdateProof, + NIVCMergeProof, NIVCStateInstance, NIVCUpdateProof, }; use crate::parafold::transcript::circuit::AllocatedTranscript; use crate::traits::circuit_supernova::EnforcingStepCircuit; -use crate::traits::{Engine, ROConstantsCircuit}; +use crate::traits::Engine; impl AllocatedNIVCState where @@ -23,7 +25,7 @@ where fn hash( &self, mut cs: CS, - _hasher: &NIVCHasher, + _hasher: &AllocatedNIVCHasher, ) -> Result, SynthesisError> where CS: ConstraintSystem, @@ -43,7 +45,7 @@ where fn from_proof( mut cs: CS, hasher: &NIVCHasher, - proof: AllocatedNIVCStateProof, + proof: AllocatedNIVCUpdateProof, transcript: &mut AllocatedTranscript, ) -> Result< ( @@ -61,7 +63,7 @@ where // at index `index_prev`, where the inputs were `h_L, h_R`. // `fold_proof` proves this computation, but also includes auxiliary proof data to update the accumulators // in `state_prev`. - let AllocatedNIVCStateProof { + let AllocatedNIVCUpdateProof { state: state_prev, index: index_prev, fold_proof, @@ -128,17 +130,23 @@ where pub fn new_step( mut cs: CS, hasher: &NIVCHasher, - proof: AllocatedNIVCStateProof, + proof: NIVCUpdateProof, step_circuit: SF, - transcript: &mut AllocatedTranscript, - ) -> Result + ) -> Result, SynthesisError> where CS: ConstraintSystem, SF: EnforcingStepCircuit, { + let mut transcript = AllocatedTranscript::new(); + let proof = + AllocatedNIVCUpdateProof::alloc_infallible(cs.namespace(|| "alloc proof"), || proof); // Fold proof for previous state - let (io_prev, accs_next, acc_sm_next, hash_prev) = - Self::from_proof(cs.namespace(|| "verify self"), hasher, proof, transcript)?; + let (io_prev, accs_next, acc_sm_next, hash_prev) = Self::from_proof( + cs.namespace(|| "verify self"), + hasher, + proof, + &mut transcript, + )?; let AllocatedNIVCIO { pc_in: pc_init, @@ -178,19 +186,21 @@ where // To ensure both step and merge circuits have the same IO, we inputize the previous output twice hash_next.inputize(cs.namespace(|| "inputize hash_next"))?; - Ok(nivc_next) + nivc_next.to_native() } /// Circuit pub fn new_merge( mut cs: CS, hasher: &NIVCHasher, - proof: AllocatedNIVCMergeProof, - transcript: &mut AllocatedTranscript, - ) -> Result + proof: NIVCMergeProof, + ) -> Result, SynthesisError> where CS: ConstraintSystem, { + let mut transcript = AllocatedTranscript::new(); + + let proof = AllocatedNIVCMergeProof::alloc_infallible(cs.namespace(|| "alloc proof"), || proof); let AllocatedNIVCMergeProof { proof_L, proof_R, @@ -203,13 +213,13 @@ where cs.namespace(|| "verify proof_L"), hasher, proof_L, - transcript, + &mut transcript, )?; let (io_R_prev, accs_R_next, acc_sm_R_next, hash_R_prev) = Self::from_proof( cs.namespace(|| "verify proof_R"), hasher, proof_R, - transcript, + &mut transcript, )?; let mut acc_sm_next = AllocatedScalarMulAccumulator::merge( @@ -217,7 +227,7 @@ where acc_sm_L_next, acc_sm_R_next, sm_merge_proof, - transcript, + &mut transcript, )?; // merge the accumulators from both states. @@ -227,7 +237,7 @@ where accs_R_next, &mut acc_sm_next, nivc_merge_proofs, - transcript, + &mut transcript, )?; let io_next = io_L_prev.merge(cs.namespace(|| "merge io"), io_R_prev)?; @@ -242,7 +252,7 @@ where hash_next.inputize(cs.namespace(|| "inputize hash_next"))?; - Ok(nivc_next) + nivc_next.to_native() } } @@ -304,19 +314,3 @@ impl AllocatedNIVCIO { }); } } - -pub struct NIVCHasher { - ro_consts: ROConstantsCircuit, - pp: AllocatedNum, - arity: usize, -} - -impl NIVCHasher { - pub fn new(ro_consts: ROConstantsCircuit, pp: AllocatedNum, arity: usize) -> Self { - Self { - ro_consts, - pp, - arity, - } - } -} diff --git a/src/parafold/nivc/circuit_alloc.rs b/src/parafold/nivc/circuit_alloc.rs index 2b58b9a74..1a61375b4 100644 --- a/src/parafold/nivc/circuit_alloc.rs +++ b/src/parafold/nivc/circuit_alloc.rs @@ -4,7 +4,7 @@ use ff::PrimeField; use crate::parafold::cycle_fold::AllocatedScalarMulAccumulator; use crate::parafold::nifs_primary::{AllocatedFoldProof, AllocatedRelaxedR1CSInstance}; -use crate::parafold::nivc::{AllocatedNIVCIO, AllocatedNIVCState, AllocatedNIVCStateProof}; +use crate::parafold::nivc::{AllocatedNIVCIO, AllocatedNIVCState, AllocatedNIVCUpdateProof}; use crate::parafold::nivc::{NIVCStateInstance, NIVCUpdateProof, NIVCIO}; use crate::traits::Engine; @@ -140,7 +140,7 @@ where } } -impl AllocatedNIVCStateProof +impl AllocatedNIVCUpdateProof where E1: Engine, E2: Engine, diff --git a/src/parafold/nivc/hash.rs b/src/parafold/nivc/hash.rs new file mode 100644 index 000000000..1951c84e1 --- /dev/null +++ b/src/parafold/nivc/hash.rs @@ -0,0 +1,26 @@ +use crate::traits::{Engine, ROConstants, ROConstantsCircuit}; +use bellpepper_core::num::AllocatedNum; + +pub struct NIVCHasher { + ro_consts: ROConstants, + pp: E::Scalar, + arity: usize, +} + +pub struct AllocatedNIVCHasher { + ro_consts: ROConstantsCircuit, + pp: AllocatedNum, + arity: usize, +} + +impl NIVCHasher { + pub fn new(ro_consts: ROConstantsCircuit, pp: AllocatedNum, arity: usize) -> Self { + Self { + ro_consts, + pp, + arity, + } + } +} + +impl AllocatedNIVCHasher {} diff --git a/src/parafold/nivc/mod.rs b/src/parafold/nivc/mod.rs index 17591347d..deffd5a47 100644 --- a/src/parafold/nivc/mod.rs +++ b/src/parafold/nivc/mod.rs @@ -12,6 +12,7 @@ use ff::PrimeField; pub mod circuit; mod circuit_alloc; +pub mod hash; pub mod prover; #[derive(Debug, Clone, PartialEq)] @@ -61,7 +62,7 @@ pub struct NIVCUpdateProof { /// A proved NIVC step for a particular step function. Can be folded into an existing [`AllocatedNIVCState']. #[derive(Debug, Clone)] -pub struct AllocatedNIVCStateProof { +pub struct AllocatedNIVCUpdateProof { /// Output of the previous step state: AllocatedNIVCState, /// Index of the circuits that produced `state` @@ -72,8 +73,8 @@ pub struct AllocatedNIVCStateProof { #[derive(Debug, Clone)] pub struct NIVCMergeProof { - nivc_update_proof_L: NIVCUpdateProof, - nivc_update_proof_R: NIVCUpdateProof, + proof_L: NIVCUpdateProof, + proof_R: NIVCUpdateProof, sm_merge_proof: ScalarMulMergeProof, nivc_merge_proof: Vec>, } @@ -81,8 +82,8 @@ pub struct NIVCMergeProof { /// A proved NIVC step for a particular step function. Can be folded into an existing [`AllocatedNIVCState']. #[derive(Debug, Clone)] pub struct AllocatedNIVCMergeProof { - proof_L: AllocatedNIVCStateProof, - proof_R: AllocatedNIVCStateProof, + proof_L: AllocatedNIVCUpdateProof, + proof_R: AllocatedNIVCUpdateProof, /// Proof for merging the scalar multiplication accumulators from two different states. sm_merge_proof: AllocatedScalarMulMergeProof, /// Proofs for merging each accumulator in [AllocatedNIVCState.accs] from two different states diff --git a/src/parafold/nivc/prover.rs b/src/parafold/nivc/prover.rs index a0e360162..ac0455b2e 100644 --- a/src/parafold/nivc/prover.rs +++ b/src/parafold/nivc/prover.rs @@ -2,11 +2,12 @@ use ff::PrimeField; use crate::parafold::cycle_fold::prover::ScalarMulAccumulator; use crate::parafold::nifs_primary::prover::RelaxedR1CS; +use crate::parafold::nivc::hash::{AllocatedNIVCHasher, NIVCHasher}; use crate::parafold::nivc::{NIVCMergeProof, NIVCStateInstance, NIVCUpdateProof, NIVCIO}; use crate::parafold::prover::CommitmentKey; use crate::parafold::transcript::prover::Transcript; use crate::r1cs::R1CSShape; -use crate::traits::{Engine, ROConstants}; +use crate::traits::Engine; #[derive(Debug)] pub struct NIVCState { @@ -16,9 +17,10 @@ pub struct NIVCState { #[derive(Debug)] pub struct NIVCUpdateWitness { - state: NIVCStateInstance, - index: usize, - W: Vec, + // + pub(crate) state: NIVCStateInstance, + pub(crate) index: usize, + pub(crate) W: Vec, } impl NIVCState @@ -30,11 +32,11 @@ where &mut self, ck: &CommitmentKey, shapes: &[R1CSShape], - hasher: &NIVCHasher, + hasher: &AllocatedNIVCHasher, witness_prev: &NIVCUpdateWitness, transcript: &mut Transcript, ) -> NIVCUpdateProof { - let Self { accs, acc_sm, .. } = self; + let Self { accs, acc_sm } = self; let NIVCUpdateWitness { state: instance_prev, @@ -48,10 +50,8 @@ where let shape_prev = &shapes[index_prev]; // Add the R1CS IO to the transcript + transcript.absorb(&hash_prev); let X_prev = vec![hash_prev]; - for x_prev in &X_prev { - transcript.absorb(x_prev); - } // Fold the proof for the previous iteration into the correct accumulator let nifs_fold_proof = accs[index_prev].fold(ck, shape_prev, X_prev, W_prev, acc_sm, transcript); @@ -68,25 +68,20 @@ where pub fn merge( ck: &CommitmentKey, shapes: &[R1CSShape], - hasher: &NIVCHasher, mut self_L: Self, - mut self_R: Self, // reference? - witness_L: &NIVCUpdateWitness, - witness_R: &NIVCUpdateWitness, + self_R: &Self, + proof_L: NIVCUpdateProof, + proof_R: NIVCUpdateProof, transcript: &mut Transcript, ) -> (Self, NIVCMergeProof) { - let proof_L = self_L.update(ck, shapes, hasher, witness_L, transcript); - let proof_R = self_R.update(ck, shapes, hasher, witness_R, transcript); let Self { accs: accs_L, acc_sm: acc_sm_L, - .. } = self_L; let Self { accs: accs_R, acc_sm: acc_sm_R, - .. } = self_R; let (mut acc_sm, sm_merge_proof) = ScalarMulAccumulator::merge(acc_sm_L, acc_sm_R, transcript); @@ -95,8 +90,8 @@ where RelaxedR1CS::merge_many(ck, shapes, accs_L, accs_R, &mut acc_sm, transcript); let merge_proof = NIVCMergeProof { - nivc_update_proof_L: proof_L, - nivc_update_proof_R: proof_R, + proof_L, + proof_R, sm_merge_proof, nivc_merge_proof, }; @@ -113,12 +108,6 @@ impl NIVCStateInstance { } } -pub struct NIVCHasher { - ro_consts: ROConstants, - pp: E::Scalar, - arity: usize, -} - impl NIVCIO { pub fn default(arity: usize) -> Self { Self { diff --git a/src/parafold/prover.rs b/src/parafold/prover.rs index ed24e9a50..35bffe4e7 100644 --- a/src/parafold/prover.rs +++ b/src/parafold/prover.rs @@ -1,11 +1,19 @@ +use bellpepper_core::ConstraintSystem; + +use crate::bellpepper::solver::SatisfyingAssignment; use crate::parafold::cycle_fold::HashedCommitment; +use crate::parafold::nivc::hash::NIVCHasher; use crate::parafold::nivc::prover::{NIVCState, NIVCUpdateWitness}; +use crate::parafold::nivc::{AllocatedNIVCState, NIVCUpdateProof}; +use crate::parafold::transcript::prover::Transcript; +use crate::r1cs::R1CSShape; +use crate::traits::circuit_supernova::StepCircuit; use crate::traits::commitment::CommitmentEngineTrait; use crate::Engine; pub struct CommitmentKey { - // ro for secondary circuit to compute the hash of the point - // ro_secondary + // TODO: ro for secondary circuit to compute the hash of the point + // this should only be a 2-to-1 hash since we are hashing the coordinates ck: crate::CommitmentKey, } @@ -16,174 +24,108 @@ impl CommitmentKey { } } -// pub struct ProvingKey { -// -// } -// -// -// impl RecursiveSNARK { -// -// pub fn new(pk: &ProvingKey, ) -> Self { -// -// } -// } +pub struct ProvingKey { + // public params + ck: CommitmentKey, + nivc_hasher: NIVCHasher, + shapes: Vec>, +} pub struct RecursiveSNARK { - witness_prev: NIVCUpdateWitness, - state_curr: NIVCState, + // state + state: NIVCState, + proof: NIVCUpdateProof, +} + +impl RecursiveSNARK +where + E1: Engine, + E2: Engine, +{ + // pub fn new(pc_init: usize, shapes: &[R1CSShape]) -> Self { + // let num_circuits = shapes.len(); + // let arity = assert!(pc_init < num_circuits); + // } + + pub fn prove_step>( + mut self, + pk: &ProvingKey, + step_circuit: C, + ) -> Self { + let Self { mut state, proof } = self; + let circuit_index = step_circuit.circuit_index(); + let mut cs = SatisfyingAssignment::::new(); + let state_instance = + AllocatedNIVCState::new_step(&mut cs, &pk.nivc_hasher, proof, step_circuit).unwrap(); + let W = cs.aux_assignment(); + // assert state_instance == state.instance + let witness = NIVCUpdateWitness { + state: state_instance, + index: circuit_index, + W: W.to_vec(), + }; + + let mut transcript = Transcript::new(); + + let proof = state.update( + &pk.ck, + &pk.shapes, + &pk.nivc_hasher, + &witness, + &mut transcript, + ); + + Self { state, proof } + } + // pub fn merge>( + // pk: &ProvingKey, + // self_L: Self, + // self_R: &Self, + // ) -> Self { + // let Self { + // state: state_L, + // proof: proof_L, + // } = self_L; + // let Self { + // state: state_R, + // proof: proof_R, + // } = self_R; + // + // let mut transcript = Transcript::new(); + // + // let (state, proof) = NIVCState::merge( + // &pk.ck, + // &pk.shapes, + // state_L, + // state_R, + // proof_L, + // proof_R.clone(), + // &mut transcript, + // ); + // + // let circuit_index = pk.shapes.len(); + // let mut cs = SatisfyingAssignment::::new(); + // let state_instance = AllocatedNIVCState::new_merge(&mut cs, &pk.nivc_hasher, proof).unwrap(); + // let W = cs.aux_assignment(); + // // assert state_instance == state.instance + // let witness = NIVCUpdateWitness { + // state: state_instance, + // index: circuit_index, + // W: W.to_vec(), + // }; + // + // let mut transcript = Transcript::new(); + // + // let proof = state.update( + // &pk.ck, + // &pk.shapes, + // &pk.nivc_hasher, + // &witness, + // &mut transcript, + // ); + // + // Self { state, proof } + // } } -// -// pub struct RecursionState { -// hash_inputs: Vec, -// self_acc_prev: RelaxedR1CS, -// nivc_state: NIVCState, -// } -// -// pub struct Prover { -// state: RecursionState, -// } -// -// impl RecursionState { -// pub fn new(_pk: &ProvingKey) -> Self { -// todo!() -// } -// -// fn fold_proofs(self, pk: &ProvingKey, nivc_witnesses: &[NIVCWitness]) -> Self { -// let mut transcript = E::TE::new(b"fold"); -// let self_io_hash_curr = self.io_hash(); -// -// // Destructure current state -// let Self { -// self_acc_prev, -// nivc_acc_curr, -// nivc_state: nivc_state_curr, -// self_proof_curr, -// } = self; -// -// // sanity check -// assert_eq!(self_proof_curr.instance.X.len(), 2); -// assert_eq!(self_proof_curr.instance.X[1], self_io_hash_curr); -// -// let mut cs = SatisfyingAssignment::::with_capacity(pk.shape.num_io + 1, pk.shape.num_vars); -// -// let circuit = StateTransitionCircuit::new( -// cs.namespace(|| "circuit init"), -// pk, -// self_acc_prev.instance.clone(), -// nivc_acc_curr -// .iter() -// .map(|acc| acc.as_ref().map(|acc| acc.instance.clone())), -// nivc_state_curr.clone(), -// ); -// -// // Fold the proof of the current state into the accumulator for `Self` -// // Generate a proof adding the witness of the current accumulator -// let (self_acc_curr, self_fold_proof_curr, self_fold_scalar_mul_instances) = -// RelaxedR1CSAccumulator::nifs_fold( -// &pk.ck, -// &pk.shape, -// self_acc_prev, -// &self_proof_curr, -// &mut transcript, -// ); -// let circuit = circuit -// .fold_self(cs.namespace(|| "circuit fold self"), self_fold_proof_curr) -// .unwrap(); -// -// // Fold a list of `m` proofs into the current NIVC accumulator. -// // Generate the outputs of each NIVC circuit, and a folding proof -// let (nivc_acc_next, nivc_state_next, nivc_folding_proofs) = -// Self::fold_many_nivc(pk, nivc_acc_curr, nivc_state_curr, nivc_witnesses); -// -// let circuit = circuit -// .fold_many_nivc(cs.namespace(|| "circuit fold nivc"), nivc_folding_proofs) -// .unwrap(); -// -// circuit -// .finalize(cs.namespace(|| "circuit finalize")) -// .unwrap(); -// -// let self_proof_next: R1CSProof = Self::prove_transition(pk, cs); -// -// Self { -// self_acc_prev: self_acc_curr, -// nivc_acc_curr: nivc_acc_next, -// nivc_state: nivc_state_next, -// self_proof_curr: self_proof_next, -// } -// } -// -// /// Compute a collision-resistant hash of the circuit's state. -// fn io_hash(&self) -> E::Scalar { -// todo!() -// } -// -// /// Given a list NIVC accumulators `accs_init` that resulted in the computation of `state_init`, -// /// and a list of NIVC proofs of `m` sequential iterations, this function folds all the proofs into an `accs_init`, -// /// and returns proofs of this folding. -// fn fold_many_nivc( -// pk: &ProvingKey, -// accs_init: Vec>>, -// nivc_state_init: NIVCIO, -// nivc_witnesses: &[NIVCWitness], -// ) -> ( -// Vec>>, -// NIVCIO, -// Vec>, -// ) { -// let num_iters = nivc_witnesses.len(); -// -// let mut fold_proofs = Vec::with_capacity(num_iters); -// -// let (accs_next, nivc_state_next) = nivc_witnesses.iter().fold( -// (accs_init, nivc_state_init), -// |(accs_curr, nivc_state_curr), witness| { -// let NIVCWitness { io, proof } = witness; -// -// // assert_eq!(nivc_state_curr, input); -// -// let pc = nivc_state_curr.pc; -// -// let (accs_next, proof) = RelaxedR1CSAccumulator::nifs_fold_many( -// &pk.ck, -// &pk.ro_consts, -// &pk.nivc[pc].shape, -// &pk.nivc[pc].pp, -// accs_curr, -// pc, -// proof, -// ); -// -// let nifs_state_next = output.clone(); -// -// fold_proofs.push(NIVCProof { -// input, -// output, -// proof, -// }); -// -// (accs_next, nifs_state_next) -// }, -// ); -// (accs_next, nivc_state_next, fold_proofs) -// } -// -// // /// Create a proof for the circuit verifying the current state transition. -// // fn prove_transition + NovaWitness>( -// // pk: &ProvingKey, -// // cs: CS, -// // ) -> R1CSProof { -// // let (instance, witness) = cs -// // .r1cs_instance_and_witness(&pk.shape, &pk.ck) -// // .map_err(|_e| NovaError::UnSat) -// // .expect("Nova error unsat"); -// // let instance = R1CSInstance { -// // W: instance.comm_W, -// // X: instance.X, -// // }; -// // let witness = R1CSWitness { W: witness.W }; -// // -// // R1CSProof { instance, witness } -// // } -// } +pub struct CompressedSNARK {}