From 810365e232cf03eb3467d8c69f169c46150257be Mon Sep 17 00:00:00 2001 From: cyphersnake Date: Wed, 8 Jan 2025 17:10:11 +0100 Subject: [PATCH] feat(ivc): impl cyclefold::ivc **Motivation** Close #368 Close #369 Close #370 Close #372 Close #373 Close #374 **Overview** Implementation of the cyclefold with test --- .../mod.rs | 566 +++++++++++++++++- .../public_params.rs | 284 +++++++-- src/ivc/cyclefold/sfc/mod.rs | 2 +- 3 files changed, 800 insertions(+), 52 deletions(-) diff --git a/src/ivc/cyclefold/incrementally_verifiable_computation/mod.rs b/src/ivc/cyclefold/incrementally_verifiable_computation/mod.rs index 0d269e64..0ff17f2e 100644 --- a/src/ivc/cyclefold/incrementally_verifiable_computation/mod.rs +++ b/src/ivc/cyclefold/incrementally_verifiable_computation/mod.rs @@ -1,34 +1,49 @@ -#![allow(unused_imports)] - use std::{marker::PhantomData, num::NonZeroUsize}; -use public_params::PublicParams; -use tracing::info_span; +use itertools::Itertools; +use tracing::{error, info_span, trace}; use super::{ ro, support_circuit::{self, SupportCircuit}, }; use crate::{ - halo2_proofs::halo2curves::{ - ff::{FromUniformBytes, PrimeFieldBits}, - group::prime::PrimeCurveAffine, - CurveAffine, + constants::MAX_BITS, + halo2_proofs::{ + halo2curves::{ + ff::{Field, FromUniformBytes, PrimeField, PrimeFieldBits}, + group::prime::PrimeCurveAffine, + CurveAffine, + }, + plonk::Error as Halo2PlonkError, }, ivc::{ cyclefold::sfc::{self, StepFoldingCircuit}, - StepCircuit, + step_circuit, StepCircuit, }, nifs::{ self, protogalaxy::{AccumulatorArgs, ProtoGalaxy}, - sangria::VanillaFS as SangriaFS, + sangria::VanillaFS, }, - plonk::PlonkTrace, + plonk::{eval, PlonkTrace}, + polynomial::lagrange, + poseidon::random_oracle::ROTrait, + prelude::CommitmentKey, table::CircuitRunner, + util, }; +type SangriaFS = VanillaFS; + +type SangriaRelaxedPlonkTrace = + nifs::sangria::RelaxedPlonkTrace; + +type SangriaFoldablePlonkInstance = + nifs::sangria::accumulator::FoldablePlonkInstance; + mod public_params; +pub use public_params::PublicParams; pub struct IVC where @@ -39,7 +54,14 @@ where CSup::Scalar: PrimeFieldBits + FromUniformBytes<64>, { step: NonZeroUsize, + + primary_acc: nifs::protogalaxy::Accumulator, primary_trace: PlonkTrace, + primary_z_current: [CMain::Scalar; ARITY], + primary_z_0: [CMain::Scalar; ARITY], + + support_acc: nifs::sangria::RelaxedPlonkTrace, + _p: PhantomData<(CMain, CSup, SC)>, } @@ -52,10 +74,522 @@ where CSup::Scalar: PrimeFieldBits + FromUniformBytes<64>, { pub fn new( - _pp: &PublicParams, - _sc: &SC, - _z_0: [CMain::ScalarExt; ARITY], - ) -> Self { - todo!("temporarily removed for the purposes of a simple merge into main") + pp: &mut PublicParams, + sc: &SC, + z_0: [CMain::ScalarExt; ARITY], + ) -> Result> { + let _span = info_span!("ivc_new", step = 0).entered(); + + let primary_initial_acc = ProtoGalaxy::::new_accumulator( + AccumulatorArgs::from(&pp.primary_S), + &pp.protogalaxy_prover_params(), + &mut ro(), + pp.primary_initial_trace.clone(), + ) + .map_err(Error::WhileProtoGalaxyAccCreation)?; + + // At zero step cyclefold ivc - output protogalaxy-accumulator is input + // protogalaxy-accumulator. Bug proof still should be valid. + let mut random_oracle = ro(); + let (_new_acc, self_proof) = ProtoGalaxy::prove( + &pp.primary_ck, + &pp.protogalaxy_prover_params(), + &mut random_oracle, + primary_initial_acc.clone(), + &[pp.primary_initial_trace.clone()], + )?; + + #[cfg(test)] + { + ProtoGalaxy::::is_sat(&pp.primary_ck, &pp.primary_S, &_new_acc) + .expect("initial primary accumulator not corrent"); + + assert_eq!( + ProtoGalaxy::verify( + &pp.protogalaxy_verifier_params(), + &mut ro(), + &mut ro(), + &primary_initial_acc.clone().into(), + &[pp.primary_initial_trace.u.clone()], + &self_proof, + ) + .expect("while verification after first prove"), + _new_acc.into() + ); + } + + let support_initial_acc = nifs::sangria::accumulator::RelaxedPlonkTrace::from_regular( + pp.support_initial_trace.clone(), + SupportCircuit::::MIN_K_TABLE_SIZE as usize, + ); + + // At zero step cyclefold ivc - output sangria-accumulator is input + // sangria-accumulator. Bug proofs still should be valid. + let SupportCircuitFoldResult { + new_accumulator: _new_new_accumulator, + incoming: support_incoming, + } = fold_support_circuit::( + &pp.support_ck, + &pp.sangria_prover_params(), + &support_initial_acc, + primary_initial_acc + .u + .W_commitments + .iter() + .copied() + .zip_eq(pp.primary_initial_trace.u.W_commitments.iter().copied()), + CMain::Base::ZERO, // for zero step + CMain::Base::ZERO, // for zero step + )?; + + let primary_sfc = StepFoldingCircuit::<'_, ARITY, CMain, CSup, SC> { + sc, + input: sfc::InputBuilder { + step: 0, + pp_digest: pp.pp_digest_coordinates(), + self_incoming: &pp.primary_initial_trace.u, + self_proof, + support_acc: &pp.support_initial_trace.u.clone().into(), + support_incoming: support_incoming.as_slice(), + self_acc: &primary_initial_acc.clone().into(), + z_i: z_0, + z_0, + } + .build(), + _p: PhantomData, + }; + + let primary_initial_instances = primary_sfc.initial_instances(); + + #[cfg(test)] + { + let _mock = info_span!("mock_debug").entered(); + crate::halo2_proofs::dev::MockProver::run( + pp.primary_k_table_size, + &primary_sfc, + primary_initial_instances.clone(), + ) + .unwrap() + .verify() + .unwrap(); + } + + let primary_cr = CircuitRunner::new( + pp.primary_k_table_size, + primary_sfc, + primary_initial_instances.clone(), + ); + let primary_witness = primary_cr + .try_collect_witness() + .map_err(|err| Error::WhileCollectPrimaryWitness { step: 0, err })?; + pp.primary_S = primary_cr + .try_collect_plonk_structure() + .map_err(|err| Error::WhileCollectPrimaryS { err })?; + + let primary_post_initial_trace = ProtoGalaxy::::generate_plonk_trace( + &pp.primary_ck, + &primary_initial_instances, + &primary_witness, + &pp.protogalaxy_prover_params(), + &mut ro(), + )?; + + Ok(Self { + step: NonZeroUsize::new(1).expect("safe: 1 != 0"), + // Because zero step using input values for output without any folding (only formal + // on-circuit) - we just take initial acc-s & z_0 + primary_z_current: z_0, + primary_z_0: z_0, + primary_trace: primary_post_initial_trace, + primary_acc: primary_initial_acc, + support_acc: support_initial_acc, + _p: PhantomData, + }) + } + + pub fn next( + self, + pp: &PublicParams, + sc: &SC, + ) -> Result> { + let _span = info_span!("ivc_next", step = self.step.get()).entered(); + + let Self { + step, + primary_acc, + primary_trace, + primary_z_current, + primary_z_0, + support_acc, + _p, + } = self; + + let mut random_oracle = ro(); + let (primary_next_acc, primary_proof) = ProtoGalaxy::prove( + &pp.primary_ck, + &pp.protogalaxy_prover_params(), + &mut random_oracle, + primary_acc.clone(), + &[primary_trace.clone()], + ) + .unwrap(); + + // Inside `prove` we use several challenges generated from `random oracle`. Since we + // delegate the `W_commitment` calculations to the `upport_circuit` we need `gamma` to + // repeat them. We take advantage of the fact that `gamma` is generated last and thus + // retrieve it + let gamma = random_oracle.squeeze::(MAX_BITS); + + // Within protogalaxy::prove there is a calculation of L0(gamma), L1(gamma), we repeat + // these calculations to reuse them in the support circuit + let [l0, l1] = lagrange::iter_eval_lagrange_poly_for_cyclic_group(gamma, 1) + .take(2) + .map(|v| util::fe_to_fe(&v).unwrap()) + .collect::>() + .try_into() + .unwrap(); + + let SupportCircuitFoldResult { + new_accumulator: support_next_acc, + incoming: support_incoming, + } = fold_support_circuit::( + &pp.support_ck, + &pp.sangria_prover_params(), + &support_acc, + primary_acc + .u + .W_commitments + .iter() + .copied() + .zip_eq(primary_trace.u.W_commitments.iter().copied()), + l0, + l1, + )?; + + let primary_z_next = sc.process_step(&primary_z_current, pp.primary_k_table_size)?; + + let primary_sfc = StepFoldingCircuit::<'_, ARITY, CMain, CSup, SC> { + sc, + input: sfc::InputBuilder { + step: step.get(), + pp_digest: pp.pp_digest_coordinates(), + z_i: primary_z_current, + z_0: primary_z_0, + self_incoming: &primary_trace.u, + self_proof: primary_proof, + support_acc: &support_acc.U, + support_incoming: support_incoming.as_slice(), + self_acc: &primary_acc.into(), + } + .build(), + _p: PhantomData, + }; + + let primary_instances = primary_sfc.instances( + &primary_next_acc.clone().into(), + &support_next_acc.U, + &primary_z_next, + ); + + #[cfg(test)] + { + let _mock = info_span!("mock_debug").entered(); + crate::halo2_proofs::dev::MockProver::run( + pp.primary_k_table_size, + &primary_sfc, + primary_instances.clone(), + ) + .unwrap() + .verify() + .unwrap(); + } + + let primary_witness = CircuitRunner::new( + pp.primary_k_table_size, + primary_sfc, + primary_instances.clone(), + ) + .try_collect_witness() + .map_err(|err| Error::WhileCollectPrimaryWitness { + step: step.get(), + err, + })?; + + let primary_next_trace = ProtoGalaxy::::generate_plonk_trace( + &pp.primary_ck, + &primary_instances, + &primary_witness, + &pp.protogalaxy_prover_params(), + &mut ro(), + )?; + + Ok(Self { + step: step.saturating_add(1), + primary_acc: primary_next_acc, + primary_trace: primary_next_trace, + primary_z_current: primary_z_next, + primary_z_0, + support_acc: support_next_acc, + _p, + }) + } + + pub fn verify(self, pp: &PublicParams) -> Result> { + let _span = info_span!("ivc_verify").entered(); + let Self { + step, + primary_acc, + primary_trace, + primary_z_current, + primary_z_0, + support_acc, + _p, + } = &self; + + let mut errors: Vec> = vec![]; + + if let Err(err) = VerifyError::is_mismatch_proto_galaxy_consistency_marker( + ro().absorb( + &sfc::InputBuilder { + step: step.get(), + pp_digest: pp.pp_digest_coordinates(), + self_acc: &primary_acc.clone().into(), + support_acc: &support_acc.U, + z_i: *primary_z_current, + z_0: *primary_z_0, + + // next fields not used in absorb + self_incoming: &primary_trace.u, + self_proof: nifs::protogalaxy::Proof::default(), + support_incoming: &[], + } + .build(), + ) + .inspect(|buf| trace!("buf before marker: {buf:?}")) + .output( + NonZeroUsize::new(::NUM_BITS as usize).unwrap(), + ), + primary_trace.u.instances[0][0], + ) { + errors.push(err); + } + + if let Err(err) = + ProtoGalaxy::::is_sat(&pp.primary_ck, &pp.primary_S, primary_acc) + { + errors.push(VerifyError::WhileProtoGalaxyIsSat(err)) + } + + if let Err(err) = SangriaFS::::is_sat(&pp.support_ck, &pp.support_S, support_acc, &[]) + { + errors.push(VerifyError::WhileSangriaIsSat(err)) + } + + if errors.is_empty() { + Ok(self) + } else { + Err(Error::Verify(errors.into_boxed_slice())) + } + } +} + +struct SupportCircuitFoldResult { + new_accumulator: SangriaRelaxedPlonkTrace, + incoming: Vec<( + SangriaFoldablePlonkInstance, + nifs::sangria::CrossTermCommits, + )>, +} + +fn fold_support_circuit( + support_ck: &CommitmentKey, + prover_params: &nifs::sangria::ProverParam, + accumulator: &SangriaRelaxedPlonkTrace, + W_commitments_pairs: impl Iterator, + l0: CMain::Base, + l1: CMain::Base, +) -> Result, nifs::sangria::Error> +where + CMain: CurveAffine::Scalar>, + CSup: CurveAffine::Scalar>, + CMain::Base: PrimeFieldBits + FromUniformBytes<64>, + CSup::Base: PrimeFieldBits + FromUniformBytes<64>, +{ + let _support = info_span!("support").entered(); + + let traces = W_commitments_pairs + .map(|(p0, p1)| support_circuit::InstanceInput:: { p0, p1, l0, l1 }.into_instance()) + .map(|instances| { + #[cfg(test)] + { + let _mock = info_span!("mock_debug").entered(); + crate::halo2_proofs::dev::MockProver::run( + SupportCircuit::::MIN_K_TABLE_SIZE, + &SupportCircuit::::default(), + instances.clone(), + ) + .unwrap() + .verify() + .unwrap(); + } + + let witness = CircuitRunner::::new( + SupportCircuit::::MIN_K_TABLE_SIZE, + SupportCircuit::::default(), + instances.clone(), + ) + .try_collect_witness()?; + + SangriaFS::::generate_plonk_trace( + support_ck, + &instances, + &witness, + prover_params, + &mut ro(), + ) + }) + .collect::, _>>()?; + + let mut new_accumulator = accumulator.clone(); + let mut paired_incoming = vec![]; + for trace in traces { + let (next_acc, proof) = SangriaFS::::prove( + support_ck, + prover_params, + &mut ro(), + new_accumulator, + &[trace.clone()], + )?; + + paired_incoming.push((trace.u, proof)); + + new_accumulator = next_acc; + } + + Ok(SupportCircuitFoldResult { + new_accumulator, + incoming: paired_incoming, + }) +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Error while verify: {0:?}")] + Verify(Box<[VerifyError]>), + + #[error("Sangria NIFS error: {0:?}")] + Sangria(#[from] nifs::sangria::Error), + + #[error("ProtoGalaxy NIFS error: {0:?}")] + ProtoGalaxy(#[from] nifs::protogalaxy::Error), + + #[error("While creating a new protogalaxy acc: {0:?}")] + WhileProtoGalaxyAccCreation(eval::Error), + + #[error("While collecting witness on the primary circuit at step {step}: {err:?}")] + WhileCollectPrimaryWitness { step: usize, err: Halo2PlonkError }, + + #[error("While collecting plonk structure on the primary circuit: {err:?}")] + WhileCollectPrimaryS { err: Halo2PlonkError }, + + #[error("While step circuit synthesis: {0:?}")] + WhileStepCircuitSynthesis(#[from] step_circuit::SynthesisError), +} + +#[derive(thiserror::Error, Debug)] +pub enum VerifyError { + #[error("Mismatch proto galaxy consistency marker: {expected:?} != {actual:?}")] + MismatchProtoGalaxyConsistencyMarker { + expected: CMain::ScalarExt, + actual: CMain::ScalarExt, + }, + #[error("While is sat protogalaxy acc: {0:?}")] + WhileProtoGalaxyIsSat(Vec>), + + #[error("While is sat protogalaxy acc: {0:?}")] + WhileSangriaIsSat(Vec), +} + +impl VerifyError { + fn is_mismatch_proto_galaxy_consistency_marker( + expected: CMain::ScalarExt, + actual: CMain::ScalarExt, + ) -> Result<(), Self> { + if expected != actual { + Err(Self::MismatchProtoGalaxyConsistencyMarker { expected, actual }) + } else { + Ok(()) + } + } +} + +#[cfg(test)] +mod tests { + use std::{array, path::Path}; + + use tracing::*; + use tracing_test::traced_test; + + use crate::{ + commitment::CommitmentKey, + halo2_proofs::arithmetic::Field, + ivc::step_circuit::trivial, + prelude::bn256::{C1Affine, C1Scalar, C2Affine}, + }; + + /// Arity : Input/output size per fold-step for primary step-circuit + /// For tivial case it can be any number + const ARITY: usize = 5; + + /// Key size for Primary Circuit + const PRIMARY_COMMITMENT_KEY_SIZE: usize = 23; + const SECONDARY_COMMITMENT_KEY_SIZE: usize = 23; + + const PRIMARY_CIRCUIT_TABLE_SIZE: u32 = 20; + + const FOLDER: &str = ".cache/examples"; + + #[traced_test] + #[test] + fn ivc() { + let sc = trivial::Circuit::::default(); + + let primary_commitment_key = unsafe { + CommitmentKey::::load_or_setup_cache( + Path::new(FOLDER), + "bn256", + PRIMARY_COMMITMENT_KEY_SIZE, + ) + .unwrap() + }; + + let secondary_commitment_key = unsafe { + CommitmentKey::::load_or_setup_cache( + Path::new(FOLDER), + "grumpkin", + SECONDARY_COMMITMENT_KEY_SIZE, + ) + .unwrap() + }; + + info!("ck generated"); + + let mut pp = super::PublicParams::new( + &sc, + primary_commitment_key, + secondary_commitment_key, + PRIMARY_CIRCUIT_TABLE_SIZE, + ) + .unwrap(); + info!("pp created"); + + super::IVC::new(&mut pp, &sc, array::from_fn(|_| C1Scalar::ZERO)) + .expect("while step=0") + .next(&pp, &sc) + .expect("while step=1") + .next(&pp, &sc) + .expect("while step=2") + .verify(&pp) + .expect("while verify"); } } diff --git a/src/ivc/cyclefold/incrementally_verifiable_computation/public_params.rs b/src/ivc/cyclefold/incrementally_verifiable_computation/public_params.rs index 32d98a3e..bb27d9ac 100644 --- a/src/ivc/cyclefold/incrementally_verifiable_computation/public_params.rs +++ b/src/ivc/cyclefold/incrementally_verifiable_computation/public_params.rs @@ -1,15 +1,18 @@ -use std::marker::PhantomData; +use std::{io, iter, marker::PhantomData}; -use halo2_proofs::halo2curves::ff::PrimeField; use serde::Serialize; +use tracing::info_span; use crate::{ constants::NUM_HASH_BITS, digest::{self, DigestToBits}, - halo2_proofs::halo2curves::{ - ff::{Field, FromUniformBytes, PrimeFieldBits}, - group::prime::PrimeCurveAffine, - CurveAffine, + halo2_proofs::{ + halo2curves::{ + ff::{Field, FromUniformBytes, PrimeField, PrimeFieldBits}, + group::prime::PrimeCurveAffine, + CurveAffine, + }, + plonk::Error as Halo2PlonkError, }, ivc::{ cyclefold::{ @@ -24,16 +27,18 @@ use crate::{ sangria::{FoldablePlonkTrace, VanillaFS}, }, plonk::{PlonkStructure, PlonkTrace}, + polynomial::Expression, poseidon::{PoseidonHash, ROTrait, Spec}, prelude::CommitmentKey, table::CircuitRunner, + util, }; -pub struct PublicParams +pub struct PublicParams where CMain: CurveAffine::Scalar>, CSup: CurveAffine::Scalar>, - SC: StepCircuit, + SC: StepCircuit, CMain::Scalar: PrimeFieldBits + FromUniformBytes<64>, CSup::Scalar: PrimeFieldBits + FromUniformBytes<64>, { @@ -44,9 +49,9 @@ where pub support_ck: CommitmentKey, pub support_S: PlonkStructure, - pub support_initial_trace: FoldablePlonkTrace, + pub support_initial_trace: FoldablePlonkTrace, - digest_bytes: Box<[u8]>, + hash_bytes: CMain, _p: PhantomData, } @@ -60,60 +65,269 @@ fn ro>() -> PoseidonHash { PoseidonHash::::new(Spec::::new(R_F, R_P)) } -impl PublicParams +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("While collect plonk structure: {0:?}")] + WhileCollectS(Halo2PlonkError), + + #[error("While collect witness: {0:?}")] + WhileCollectWitness(Halo2PlonkError), + + #[error("While nifs::protogalaxy: {0:?}")] + ProtoGalaxy(#[from] nifs::protogalaxy::Error), + + #[error("While nifs::sangria: {0:?}")] + Sangria(#[from] nifs::sangria::Error), + + #[error("While calculate digest: {0:?}")] + Digest(io::Error), +} + +impl PublicParams where CMain: CurveAffine::Scalar>, CSup: CurveAffine::Scalar>, - SC: StepCircuit, + SC: StepCircuit, CMain::Scalar: PrimeFieldBits + FromUniformBytes<64>, CSup::Scalar: PrimeFieldBits + FromUniformBytes<64>, { pub fn new( - _primary_sc: &SC, - _ck1: CommitmentKey, - _ck2: CommitmentKey, - _k_table_size: u32, - ) -> Self + primary_sc: &SC, + ck1: CommitmentKey, + ck2: CommitmentKey, + k_table_size: u32, + ) -> Result where CMain::ScalarExt: Serialize, CSup::ScalarExt: Serialize, { - todo!("temporarily removed for the purposes of a simple merge into main") - } + // Trace in C1::Base or C2::Scalar + let (support_S, support_initial_trace): ( + PlonkStructure, + FoldablePlonkTrace, + ) = { + let _support = info_span!("support").entered(); + // Since I want to scalar_multiply points for main::sfc, I take `CMain` as the main curve here + // CMain::Base or CSupport::Scalar (native for suppport_circuit) + // + // For step zero, cyclefold::sfc expects `C::identity` to be multiplied by zero + let support_circuit_instances: Vec> = support_circuit::InstanceInput { + p0: CMain::identity(), + l0: CMain::Base::ZERO, + p1: CMain::identity(), + l1: CMain::Base::ZERO, + } + .into_instance(); - pub fn cmain_pp_digest(&self) -> CMain { - digest::into_curve_from_bits(&self.digest_bytes, NUM_HASH_BITS) - } + #[cfg(test)] + { + let _mock = info_span!("mock-debug").entered(); + crate::halo2_proofs::dev::MockProver::run( + SupportCircuit::::MIN_K_TABLE_SIZE, + &SupportCircuit::::default(), + support_circuit_instances.clone(), + ) + .unwrap() + .verify() + .unwrap(); + } - pub fn csup_pp_digest(&self) -> CSup { - digest::into_curve_from_bits(&self.digest_bytes, NUM_HASH_BITS) - } + let support_cr = CircuitRunner::::new( + SupportCircuit::::MIN_K_TABLE_SIZE, + SupportCircuit::::default(), + support_circuit_instances.clone(), + ); + let S = support_cr + .try_collect_plonk_structure() + .map_err(Error::WhileCollectS)?; - pub fn cmain_pp_digest_coordinates(&self) -> (CMain::Base, CMain::Base) { - self.cmain_pp_digest() - .coordinates() - .map(|c| (*c.x(), *c.y())) - .unwrap() + // The trace is generated for `CSup`, since all result types use `C::ScalarExt` in our + // case it will be `CSup::ScalarExt` or `CMain::Base` + ( + S, + VanillaFS::::generate_plonk_trace( + &ck2, + &support_circuit_instances, + &support_cr + .try_collect_witness() + .map_err(Error::WhileCollectWitness)?, + &nifs::sangria::ProverParam { + S: support_cr + .try_collect_plonk_structure() + .map_err(Error::WhileCollectS)?, + pp_digest: (CSup::Base::ZERO, CSup::Base::ZERO), + }, + &mut ro(), + )?, + ) + }; + + let _primary = info_span!("primary").entered(); + + let (primary_S, primary_initial_trace) = { + let mock_S = { + let _s = info_span!("pre_run_mock").entered(); + + let num_io = iter::once(1) + .chain(primary_sc.instances().iter().map(|col| col.len())) + .collect::>(); + + let mock_sfc = StepFoldingCircuit:: { + sc: primary_sc, + input: sfc::Input::::new_initial::( + &PlonkStructure { + k: k_table_size as usize, + num_io, + // because with zero gates - calc count is zero - sfc panic + gates: vec![Expression::Constant(CMain::ScalarExt::ZERO)], + num_challenges: 3, + ..Default::default() + }, + &support_S, + &support_initial_trace.u, + ), + _p: PhantomData, + }; + + let mock_instances = mock_sfc.initial_instances(); + + #[cfg(test)] + { + let _mock = info_span!("mock-debug").entered(); + crate::halo2_proofs::dev::MockProver::run( + k_table_size, + &mock_sfc, + mock_instances.clone(), + ) + .unwrap() + .verify() + .unwrap(); + } + + CircuitRunner::new(k_table_size, mock_sfc, mock_instances) + .try_collect_plonk_structure() + .map_err(Error::WhileCollectS)? + }; + + let sfc = StepFoldingCircuit:: { + sc: primary_sc, + input: sfc::Input::::new_initial::( + &mock_S, + &support_S, + &support_initial_trace.u, + ), + _p: PhantomData, + }; + + let primary_instances = sfc.initial_instances(); + + #[cfg(test)] + { + let _mock = info_span!("mock-debug").entered(); + crate::halo2_proofs::dev::MockProver::run( + k_table_size, + &sfc, + primary_instances.clone(), + ) + .unwrap() + .verify() + .unwrap(); + } + + let primary_cr = CircuitRunner::new(k_table_size, sfc, primary_instances.clone()); + + ( + primary_cr + .try_collect_plonk_structure() + .map_err(Error::WhileCollectS)?, + ProtoGalaxy::::generate_plonk_trace( + &ck1, + &primary_instances, + &primary_cr + .try_collect_witness() + .map_err(Error::WhileCollectWitness)?, + &nifs::protogalaxy::ProverParam { + S: primary_cr + .try_collect_plonk_structure() + .map_err(Error::WhileCollectS)?, + pp_digest: (CMain::Base::ZERO, CMain::Base::ZERO), + }, + &mut ro(), + )?, + ) + }; + + let hash_bytes = { + let _digest = info_span!("digest").entered(); + use serde::Serialize; + + #[derive(Serialize)] + struct Meaningful<'link, CMainScalar: PrimeField, CSupScalar: PrimeField> + where + CMainScalar: Serialize, + CSupScalar: Serialize, + { + primary_S: &'link PlonkStructure, + primary_k_table_size: &'link u32, + support_S: &'link PlonkStructure, + } + + let bytes = digest::DefaultHasher::digest_to_bits(&Meaningful { + primary_S: &primary_S, + primary_k_table_size: &k_table_size, + support_S: &support_S, + }) + .map_err(Error::Digest)?; + + digest::into_curve_from_bits::(&bytes, NUM_HASH_BITS) + }; + + Ok(Self { + primary_ck: ck1, + support_ck: ck2, + primary_k_table_size: k_table_size, + + primary_initial_trace, + support_initial_trace, + + primary_S, + support_S, + + hash_bytes, + + _p: PhantomData, + }) } - pub fn csup_pp_digest_coordinates(&self) -> (CSup::Base, CSup::Base) { - self.csup_pp_digest() + pub fn pp_digest_coordinates(&self) -> (F, F) { + self.hash_bytes .coordinates() - .map(|c| (*c.x(), *c.y())) + .map(|c| { + ( + util::fe_to_fe(c.x()).unwrap(), + util::fe_to_fe(c.y()).unwrap(), + ) + }) .unwrap() } pub fn protogalaxy_prover_params(&self) -> nifs::protogalaxy::ProverParam { nifs::protogalaxy::ProverParam { S: self.primary_S.clone(), - pp_digest: self.cmain_pp_digest_coordinates(), + pp_digest: self.pp_digest_coordinates(), + } + } + + pub fn protogalaxy_verifier_params(&self) -> nifs::protogalaxy::VerifierParam { + nifs::protogalaxy::VerifierParam { + pp_digest: self.pp_digest_coordinates(), } } pub fn sangria_prover_params(&self) -> nifs::sangria::ProverParam { nifs::sangria::ProverParam { S: self.support_S.clone(), - pp_digest: self.csup_pp_digest_coordinates(), + pp_digest: self.pp_digest_coordinates(), } } } diff --git a/src/ivc/cyclefold/sfc/mod.rs b/src/ivc/cyclefold/sfc/mod.rs index 7e324738..d0346e4b 100644 --- a/src/ivc/cyclefold/sfc/mod.rs +++ b/src/ivc/cyclefold/sfc/mod.rs @@ -25,7 +25,7 @@ use crate::{ }; mod input; -pub use input::Input; +pub use input::{Input, InputBuilder}; pub mod sangria_adapter;