diff --git a/ceno_recursion/src/zkvm_verifier/binding.rs b/ceno_recursion/src/zkvm_verifier/binding.rs index e2ed1f4c9..de0283c82 100644 --- a/ceno_recursion/src/zkvm_verifier/binding.rs +++ b/ceno_recursion/src/zkvm_verifier/binding.rs @@ -68,7 +68,7 @@ pub struct ZKVMProofInputVariable { pub raw_pi: Array>>, pub raw_pi_num_variables: Array>, pub pi_evals: Array>, - pub chip_proofs: Array>>, + pub chip_proofs: Array>, pub max_num_var: Var, pub max_width: Var, pub witin_commit: BasefoldCommitmentVariable, @@ -92,7 +92,7 @@ pub(crate) struct ZKVMProofInput { pub raw_pi: Vec>, // Evaluation of raw_pi. pub pi_evals: Vec, - pub chip_proofs: BTreeMap, + pub chip_proofs: BTreeMap, pub witin_commit: BasefoldCommitment, pub opening_proof: BasefoldProof, } @@ -135,22 +135,16 @@ impl ZKVMProofInput { chip_proofs: zkvm_proof .chip_proofs .into_iter() - .map(|(chip_idx, proofs)| { + .map(|(chip_idx, proof)| { let (num_witin, num_fixed) = *chip_witin_num_vars .get(&chip_idx) .expect("num_witin data should exist"); ( chip_idx, - proofs - .into_iter() - .map(|proof| { - ZKVMChipProofInput::from((chip_idx, proof, num_witin, num_fixed)) - }) - .collect::>() - .into(), + ZKVMChipProofInput::from((chip_idx, proof, num_witin, num_fixed)), ) }) - .collect::>(), + .collect::>(), witin_commit: zkvm_proof.witin_commit.into(), opening_proof: zkvm_proof.opening_proof.into(), } @@ -166,7 +160,7 @@ impl Hintable for ZKVMProofInput { let raw_pi_num_variables = Vec::::read(builder); let pi_evals = Vec::::read(builder); builder.cycle_tracker_start("read chip proofs"); - let chip_proofs = Vec::::read(builder); + let chip_proofs = Vec::::read(builder); builder.cycle_tracker_end("read chip proofs"); let max_num_var = usize::read(builder); let max_width = usize::read(builder); @@ -202,28 +196,24 @@ impl Hintable for ZKVMProofInput { .collect(); let witin_num_vars = self .chip_proofs - .iter() - .flat_map(|(_, proofs)| proofs.iter()) + .values() .filter(|proof| proof.num_witin > 0) .map(|proof| proof.num_vars) .collect::>(); let witin_max_widths = self .chip_proofs - .iter() - .flat_map(|(_, proofs)| proofs.iter()) + .values() .map(|proof| proof.wits_in_evals.len().max(1)) .collect::>(); let fixed_num_vars = self .chip_proofs - .iter() - .flat_map(|(_, proofs)| proofs.iter()) + .values() .filter(|proof| !proof.fixed_in_evals.is_empty()) .map(|proof| proof.num_vars) .collect::>(); let fixed_max_widths = self .chip_proofs - .iter() - .flat_map(|(_, proofs)| proofs.iter()) + .values() .filter(|proof| !proof.fixed_in_evals.is_empty()) .map(|proof| proof.fixed_in_evals.len()) .collect::>(); @@ -261,8 +251,8 @@ impl Hintable for ZKVMProofInput { stream.extend(raw_pi_num_variables.write()); stream.extend(self.pi_evals.write()); stream.extend(vec![vec![F::from_canonical_usize(self.chip_proofs.len())]]); - for proofs in self.chip_proofs.values() { - stream.extend(proofs.write()); + for proof in self.chip_proofs.values() { + stream.extend(proof.write()); } stream.extend(>::write(&max_num_var)); stream.extend(>::write(&max_width)); @@ -404,35 +394,6 @@ pub struct ZKVMChipProofInput { impl VecAutoHintable for ZKVMChipProofInput {} -/// wrapper struct to allow us implement VecAutoHintable -pub struct ZKVMChipProofs(Vec); - -impl From> for ZKVMChipProofs { - fn from(v: Vec) -> Self { - Self(v) - } -} - -impl VecAutoHintable for ZKVMChipProofs {} - -impl ZKVMChipProofs { - pub fn iter(&self) -> std::slice::Iter<'_, ZKVMChipProofInput> { - self.0.iter() - } -} - -impl Hintable for ZKVMChipProofs { - type HintVariable = Array>; - - fn read(builder: &mut Builder) -> Self::HintVariable { - Vec::::read(builder) - } - - fn write(&self) -> Vec::N>> { - self.0.write() - } -} - impl From<(usize, ZKVMChipProof, usize, usize)> for ZKVMChipProofInput { fn from(d: (usize, ZKVMChipProof, usize, usize)) -> Self { let idx = d.0; diff --git a/ceno_recursion/src/zkvm_verifier/verifier.rs b/ceno_recursion/src/zkvm_verifier/verifier.rs index bb1e360fb..cabd109b0 100644 --- a/ceno_recursion/src/zkvm_verifier/verifier.rs +++ b/ceno_recursion/src/zkvm_verifier/verifier.rs @@ -177,18 +177,14 @@ pub fn verify_zkvm_proof>( }); iter_zip!(builder, zkvm_proof_input.chip_proofs).for_each(|ptr_vec, builder| { - let chip_proofs = builder.iter_ptr_get(&zkvm_proof_input.chip_proofs, ptr_vec[0]); - let chip_idx = builder.get(&chip_proofs, 0).idx_felt; + let chip_proof = builder.iter_ptr_get(&zkvm_proof_input.chip_proofs, ptr_vec[0]); + let chip_idx = chip_proof.idx_felt; challenger.observe(builder, chip_idx); - iter_zip!(builder, chip_proofs).for_each(|ptr_vec, builder| { - let chip_proof = builder.iter_ptr_get(&chip_proofs, ptr_vec[0]); - - iter_zip!(builder, chip_proof.num_instances).for_each(|ptr_vec, builder| { - let num_instance = builder.iter_ptr_get(&chip_proof.num_instances, ptr_vec[0]); - let num_instance = builder.unsafe_cast_var_to_felt(num_instance); - challenger.observe(builder, num_instance); - }); + iter_zip!(builder, chip_proof.num_instances).for_each(|ptr_vec, builder| { + let num_instance = builder.iter_ptr_get(&chip_proof.num_instances, ptr_vec[0]); + let num_instance = builder.unsafe_cast_var_to_felt(num_instance); + challenger.observe(builder, num_instance); }); }); @@ -224,13 +220,7 @@ pub fn verify_zkvm_proof>( let dummy_table_item = alpha; let dummy_table_item_multiplicity: Var = builder.constant(C::N::ZERO); - let proofs_len: Usize = builder.eval(C::N::ZERO); - builder - .range(0, zkvm_proof_input.chip_proofs.len()) - .for_each(|idx_vec, builder| { - let chip_proofs_len = builder.get(&zkvm_proof_input.chip_proofs, idx_vec[0]).len(); - builder.assign(&proofs_len, proofs_len.clone() + chip_proofs_len); - }); + let proofs_len: Usize = builder.eval(zkvm_proof_input.chip_proofs.len().get_var()); // not each chip has witness or fixed opening // therefore we need to truncate these two opening arrays @@ -256,8 +246,8 @@ pub fn verify_zkvm_proof>( .range(0, chip_indices.len()) .for_each(|idx_vec, builder| { let i = idx_vec[0]; - let chip_proofs = builder.get(&zkvm_proof_input.chip_proofs, i); - let chip_idx = builder.get(&chip_proofs, 0).idx; + let chip_proof = builder.get(&zkvm_proof_input.chip_proofs, i); + let chip_idx = chip_proof.idx; builder.set(&chip_indices, i, chip_idx); }); @@ -270,145 +260,140 @@ pub fn verify_zkvm_proof>( let chip_id: Var = builder.get(&chip_indices, num_chips_verified.get_var()); builder.if_eq(chip_id, RVar::from(i)).then(|builder| { - let chip_proofs = + let chip_proof = builder.get(&zkvm_proof_input.chip_proofs, num_chips_verified.get_var()); + // fork transcript to support chip concurrently proved + let mut chip_challenger = clone_challenger_state(builder, &challenger); + challenger_add_forked_index(builder, &mut chip_challenger, &forked_sample_index); + builder.assert_usize_eq( + chip_proof.wits_in_evals.len(), + Usize::from(circuit_vk.get_cs().num_witin()), + ); + builder.assert_usize_eq( + chip_proof.fixed_in_evals.len(), + Usize::from(circuit_vk.get_cs().num_fixed()), + ); + builder.assert_usize_eq( + chip_proof.r_out_evals.len(), + Usize::from(circuit_vk.get_cs().num_reads()), + ); + builder.assert_usize_eq( + chip_proof.w_out_evals.len(), + Usize::from(circuit_vk.get_cs().num_writes()), + ); + builder.assert_usize_eq( + chip_proof.lk_out_evals.len(), + Usize::from(circuit_vk.get_cs().num_lks()), + ); - iter_zip!(builder, chip_proofs).for_each(|ptr_vec, builder| { - let chip_proof = builder.iter_ptr_get(&chip_proofs, ptr_vec[0]); - // fork transcript to support chip concurrently proved - let mut chip_challenger = clone_challenger_state(builder, &challenger); - challenger_add_forked_index(builder, &mut chip_challenger, &forked_sample_index); - builder.assert_usize_eq( - chip_proof.wits_in_evals.len(), - Usize::from(circuit_vk.get_cs().num_witin()), - ); - builder.assert_usize_eq( - chip_proof.fixed_in_evals.len(), - Usize::from(circuit_vk.get_cs().num_fixed()), - ); - builder.assert_usize_eq( - chip_proof.r_out_evals.len(), - Usize::from(circuit_vk.get_cs().num_reads()), - ); - builder.assert_usize_eq( - chip_proof.w_out_evals.len(), - Usize::from(circuit_vk.get_cs().num_writes()), - ); - builder.assert_usize_eq( - chip_proof.lk_out_evals.len(), - Usize::from(circuit_vk.get_cs().num_lks()), - ); + let chip_logup_sum: Ext = builder.constant(C::EF::ZERO); + iter_zip!(builder, chip_proof.lk_out_evals).for_each(|ptr_vec, builder| { + let evals = builder.iter_ptr_get(&chip_proof.lk_out_evals, ptr_vec[0]); + let p1 = builder.get(&evals, 0); + let p2 = builder.get(&evals, 1); + let q1 = builder.get(&evals, 2); + let q2 = builder.get(&evals, 3); - let chip_logup_sum: Ext = builder.constant(C::EF::ZERO); - iter_zip!(builder, chip_proof.lk_out_evals).for_each(|ptr_vec, builder| { - let evals = builder.iter_ptr_get(&chip_proof.lk_out_evals, ptr_vec[0]); - let p1 = builder.get(&evals, 0); - let p2 = builder.get(&evals, 1); - let q1 = builder.get(&evals, 2); - let q2 = builder.get(&evals, 3); + builder.assign(&chip_logup_sum, chip_logup_sum + p1 * q1.inverse()); + builder.assign(&chip_logup_sum, chip_logup_sum + p2 * q2.inverse()); + }); + chip_challenger.observe(builder, chip_proof.idx_felt); - builder.assign(&chip_logup_sum, chip_logup_sum + p1 * q1.inverse()); - builder.assign(&chip_logup_sum, chip_logup_sum + p2 * q2.inverse()); - }); - chip_challenger.observe(builder, chip_proof.idx_felt); - - if circuit_vk.get_cs().is_with_lk_table() { - builder.assign(&logup_sum, logup_sum - chip_logup_sum); - } else { - // getting the number of dummy padding item that we used in this opcode circuit - let num_lks: Var = - builder.eval(C::N::from_canonical_usize(chip_vk.get_cs().num_lks())); - - // each padding instance contribute to (2^rotation_vars) dummy lookup padding - let next_pow2_instance: Var = - pow_2(builder, chip_proof.log2_num_instances.get_var()); - let num_padded_instance: Var = - builder.eval(next_pow2_instance - chip_proof.sum_num_instances.clone()); - let rotation_var: Var = builder.constant(C::N::from_canonical_usize( - 1 << circuit_vk.get_cs().rotation_vars().unwrap_or(0), + if circuit_vk.get_cs().is_with_lk_table() { + builder.assign(&logup_sum, logup_sum - chip_logup_sum); + } else { + // getting the number of dummy padding item that we used in this opcode circuit + let num_lks: Var = + builder.eval(C::N::from_canonical_usize(chip_vk.get_cs().num_lks())); + + // each padding instance contribute to (2^rotation_vars) dummy lookup padding + let next_pow2_instance: Var = + pow_2(builder, chip_proof.log2_num_instances.get_var()); + let num_padded_instance: Var = + builder.eval(next_pow2_instance - chip_proof.sum_num_instances.clone()); + let rotation_var: Var = builder.constant(C::N::from_canonical_usize( + 1 << circuit_vk.get_cs().rotation_vars().unwrap_or(0), + )); + let rotation_subgroup_size: Var = + builder.constant(C::N::from_canonical_usize( + circuit_vk.get_cs().rotation_subgroup_size().unwrap_or(0), )); - let rotation_subgroup_size: Var = - builder.constant(C::N::from_canonical_usize( - circuit_vk.get_cs().rotation_subgroup_size().unwrap_or(0), - )); - builder.assign(&num_padded_instance, num_padded_instance * rotation_var); - - // each instance contribute to (2^rotation_vars - rotated) dummy lookup padding - let num_instance_non_selected: Var = builder.eval( - chip_proof.sum_num_instances.clone() - * (rotation_var - rotation_subgroup_size - C::N::ONE), - ); - let new_multiplicity: Var = - builder.eval(num_lks * (num_padded_instance + num_instance_non_selected)); - builder.assign( - &dummy_table_item_multiplicity, - dummy_table_item_multiplicity + new_multiplicity, - ); + builder.assign(&num_padded_instance, num_padded_instance * rotation_var); - builder.assign(&logup_sum, logup_sum + chip_logup_sum); - } - - builder.cycle_tracker_start("Verify chip proof"); - let (input_opening_point, chip_shard_ec_sum) = verify_chip_proof( - circuit_name, - builder, - &mut chip_challenger, - &chip_proof, - &zkvm_proof_input.pi_evals, - &zkvm_proof_input.raw_pi, - &zkvm_proof_input.raw_pi_num_variables, - &challenges, - chip_vk, - &unipoly_extrapolator, - &mut poly_evaluator, + // each instance contribute to (2^rotation_vars - rotated) dummy lookup padding + let num_instance_non_selected: Var = builder.eval( + chip_proof.sum_num_instances.clone() + * (rotation_var - rotation_subgroup_size - C::N::ONE), + ); + let new_multiplicity: Var = + builder.eval(num_lks * (num_padded_instance + num_instance_non_selected)); + builder.assign( + &dummy_table_item_multiplicity, + dummy_table_item_multiplicity + new_multiplicity, ); - builder.cycle_tracker_end("Verify chip proof"); - let point_clone: Array> = - builder.eval(input_opening_point.clone()); + builder.assign(&logup_sum, logup_sum + chip_logup_sum); + } - if circuit_vk.get_cs().num_witin() > 0 { - let witin_round: RoundOpeningVariable = builder.eval(RoundOpeningVariable { - num_var: input_opening_point.len().get_var(), - point_and_evals: PointAndEvalsVariable { - point: PointVariable { fs: point_clone }, - evals: chip_proof.wits_in_evals, - }, - }); - builder.set_value(&witin_openings, num_witin_openings.get_var(), witin_round); - builder.inc(&num_witin_openings); - } - if circuit_vk.get_cs().num_fixed() > 0 { - let fixed_round: RoundOpeningVariable = builder.eval(RoundOpeningVariable { - num_var: input_opening_point.len().get_var(), - point_and_evals: PointAndEvalsVariable { - point: PointVariable { - fs: input_opening_point, - }, - evals: chip_proof.fixed_in_evals, + builder.cycle_tracker_start("Verify chip proof"); + let (input_opening_point, chip_shard_ec_sum) = verify_chip_proof( + circuit_name, + builder, + &mut chip_challenger, + &chip_proof, + &zkvm_proof_input.pi_evals, + &zkvm_proof_input.raw_pi, + &zkvm_proof_input.raw_pi_num_variables, + &challenges, + chip_vk, + &unipoly_extrapolator, + &mut poly_evaluator, + ); + builder.cycle_tracker_end("Verify chip proof"); + + let point_clone: Array> = builder.eval(input_opening_point.clone()); + + if circuit_vk.get_cs().num_witin() > 0 { + let witin_round: RoundOpeningVariable = builder.eval(RoundOpeningVariable { + num_var: input_opening_point.len().get_var(), + point_and_evals: PointAndEvalsVariable { + point: PointVariable { fs: point_clone }, + evals: chip_proof.wits_in_evals, + }, + }); + builder.set_value(&witin_openings, num_witin_openings.get_var(), witin_round); + builder.inc(&num_witin_openings); + } + if circuit_vk.get_cs().num_fixed() > 0 { + let fixed_round: RoundOpeningVariable = builder.eval(RoundOpeningVariable { + num_var: input_opening_point.len().get_var(), + point_and_evals: PointAndEvalsVariable { + point: PointVariable { + fs: input_opening_point, }, - }); + evals: chip_proof.fixed_in_evals, + }, + }); - builder.set_value(&fixed_openings, num_fixed_openings.get_var(), fixed_round); - builder.inc(&num_fixed_openings); - } + builder.set_value(&fixed_openings, num_fixed_openings.get_var(), fixed_round); + builder.inc(&num_fixed_openings); + } - let r_out_evals_prod = nested_product(builder, &chip_proof.r_out_evals); - builder.assign(&prod_r, prod_r * r_out_evals_prod); + let r_out_evals_prod = nested_product(builder, &chip_proof.r_out_evals); + builder.assign(&prod_r, prod_r * r_out_evals_prod); - let w_out_evals_prod = nested_product(builder, &chip_proof.w_out_evals); - builder.assign(&prod_w, prod_w * w_out_evals_prod); + let w_out_evals_prod = nested_product(builder, &chip_proof.w_out_evals); + builder.assign(&prod_w, prod_w * w_out_evals_prod); - builder - .if_ne(chip_shard_ec_sum.is_infinity.clone(), Usize::from(1)) - .then(|builder| { - add_septic_points_in_place(builder, &shard_ec_sum, &chip_shard_ec_sum); - }); + builder + .if_ne(chip_shard_ec_sum.is_infinity.clone(), Usize::from(1)) + .then(|builder| { + add_septic_points_in_place(builder, &shard_ec_sum, &chip_shard_ec_sum); + }); - let chip_sample = chip_challenger.sample_ext(builder); - builder.set(&forked_samples, forked_sample_index.get_var(), chip_sample); - builder.inc(&forked_sample_index); - }); + let chip_sample = chip_challenger.sample_ext(builder); + builder.set(&forked_samples, forked_sample_index.get_var(), chip_sample); + builder.inc(&forked_sample_index); builder.inc(&num_chips_verified); }); } diff --git a/ceno_zkvm/src/e2e.rs b/ceno_zkvm/src/e2e.rs index 215cbf7b6..88eb4c0b6 100644 --- a/ceno_zkvm/src/e2e.rs +++ b/ceno_zkvm/src/e2e.rs @@ -56,7 +56,7 @@ use witness::next_pow2_instance_padding; // default value: 16GB VRAM, each cell 4 byte, log explosion 2 pub const DEFAULT_MAX_CELLS_PER_SHARDS: u64 = (1 << 30) * 16 / 4 / 2; pub const DEFAULT_MAX_CYCLE_PER_SHARDS: Cycle = 1 << 29; -pub const DEFAULT_CROSS_SHARD_ACCESS_LIMIT: usize = 1 << 20; +pub const DEFAULT_CROSS_SHARD_ACCESS_LIMIT: usize = u32::MAX as usize; // define a relative small number to make first shard handle much less instruction /// The polynomial commitment scheme kind #[derive( diff --git a/ceno_zkvm/src/scheme.rs b/ceno_zkvm/src/scheme.rs index fa9127f10..9a585ea19 100644 --- a/ceno_zkvm/src/scheme.rs +++ b/ceno_zkvm/src/scheme.rs @@ -8,7 +8,6 @@ use serde::{Deserialize, Serialize, de::DeserializeOwned}; use std::{ collections::{BTreeMap, HashMap}, fmt::{self, Debug}, - iter, ops::Div, sync::Arc, }; @@ -174,8 +173,8 @@ pub struct ZKVMProof> { pub raw_pi: Vec>, // the evaluation of raw_pi. pub pi_evals: Vec, - // each circuit may have multiple proof instances - pub chip_proofs: BTreeMap>>, + // each circuit has exactly one proof entry + pub chip_proofs: BTreeMap>, pub witin_commit: >::Commitment, pub opening_proof: PCS::Proof, } @@ -184,7 +183,7 @@ impl> ZKVMProof { pub fn new( raw_pi: Vec>, pi_evals: Vec, - chip_proofs: BTreeMap>>, + chip_proofs: BTreeMap>, witin_commit: >::Commitment, opening_proof: PCS::Proof, ) -> Self { @@ -230,13 +229,7 @@ impl> ZKVMProof { let halt_instance_count = self .chip_proofs .get(&halt_circuit_index) - .map_or(0, |proofs| { - proofs - .iter() - .flat_map(|proof| &proof.num_instances) - .copied() - .sum() - }); + .map_or(0, |proof| proof.num_instances.iter().copied().sum()); if halt_instance_count > 0 { assert_eq!( halt_instance_count, 1, @@ -265,9 +258,6 @@ impl + Serialize> fmt::Dis let tower_proof = self .chip_proofs .iter() - .flat_map(|(circuit_index, proofs)| { - iter::repeat_n(circuit_index, proofs.len()).zip(proofs) - }) .map(|(circuit_index, proof)| { let size = bincode::serialized_size(&proof.tower_proof); size.inspect(|size| { @@ -282,9 +272,6 @@ impl + Serialize> fmt::Dis let main_sumcheck = self .chip_proofs .iter() - .flat_map(|(circuit_index, proofs)| { - iter::repeat_n(circuit_index, proofs.len()).zip(proofs) - }) .map(|(circuit_index, proof)| { let size = bincode::serialized_size(&proof.main_sumcheck_proofs); size.inspect(|size| { diff --git a/ceno_zkvm/src/scheme/prover.rs b/ceno_zkvm/src/scheme/prover.rs index 99ad1ac39..023935171 100644 --- a/ceno_zkvm/src/scheme/prover.rs +++ b/ceno_zkvm/src/scheme/prover.rs @@ -241,6 +241,23 @@ impl< / (1024.0 * 1024.0) ); + for (trace_idx, rmm) in &wits_rmms { + let bytes = rmm.values.len() * std::mem::size_of::(); + let gib = bytes as f64 / (1024.0 * 1024.0 * 1024.0); + let circuit_name = name_and_instances + .get(*trace_idx) + .map(|(name, _)| name.as_str()) + .unwrap_or(""); + println!( + "[wits_rmms] trace_idx={} circuit={} num_instances={} elements={} size={:.6} GiB", + trace_idx, + circuit_name, + rmm.num_instances(), + rmm.values.len(), + gib + ); + } + // Build trace index map: maps circuit enum index -> trace index in pcs_data. // BTreeMap iterates in key order, so trace indices match insertion order. // GPU uses this for deferred witness extraction; CPU ignores it. @@ -715,7 +732,7 @@ impl< fn collect_chip_results( results: Vec>, ) -> ( - BTreeMap>>, + BTreeMap>, Vec>, Vec>>, HashMap, @@ -742,10 +759,12 @@ impl< assert!(result.proof.wits_in_evals.is_empty()); assert!(result.proof.fixed_in_evals.is_empty()); } - chip_proofs - .entry(result.circuit_idx) - .or_insert(vec![]) - .push(result.proof); + let prev = chip_proofs.insert(result.circuit_idx, result.proof); + assert!( + prev.is_none(), + "duplicate chip proof for circuit_idx={} is not supported", + result.circuit_idx + ); for (idx, eval) in result.pi_in_evals { pi_updates.insert(idx, eval); } diff --git a/ceno_zkvm/src/scheme/verifier.rs b/ceno_zkvm/src/scheme/verifier.rs index cfa4f0abf..fdae4b556 100644 --- a/ceno_zkvm/src/scheme/verifier.rs +++ b/ceno_zkvm/src/scheme/verifier.rs @@ -222,10 +222,10 @@ impl> ZKVMVerifier } // write (circuit_idx, num_instance) to transcript - for (circuit_idx, proofs) in vm_proof.chip_proofs.iter() { + for (circuit_idx, proof) in vm_proof.chip_proofs.iter() { transcript.append_field_element(&E::BaseField::from_canonical_u32(*circuit_idx as u32)); // length of proof.num_instances will be constrained in verify_chip_proof - for num_instance in proofs.iter().flat_map(|proof| &proof.num_instances) { + for num_instance in &proof.num_instances { transcript.append_field_element(&E::BaseField::from_canonical_usize(*num_instance)); } } @@ -259,8 +259,8 @@ impl> ZKVMVerifier let mut shard_ec_sum = SepticPoint::::default(); // check num proofs - let mut num_proofs = 0; - for (index, proofs) in &vm_proof.chip_proofs { + let num_proofs = vm_proof.chip_proofs.len(); + for index in vm_proof.chip_proofs.keys() { let circuit_name = &self.vk.circuit_index_to_name[index]; let circuit_vk = &self.vk.circuit_vks[circuit_name]; if shard_id > 0 && circuit_vk.get_cs().with_omc_init_only() { @@ -269,13 +269,6 @@ impl> ZKVMVerifier .into(), )); } - if shard_id == 0 && circuit_vk.get_cs().with_omc_init_only() && proofs.len() != 1 { - return Err(ZKVMError::InvalidProof( - format!("{shard_id}th shard first shard got > 1 omc dynamic table init",) - .into(), - )); - } - num_proofs += proofs.len(); } // fork transcript to support chip concurrently proved @@ -283,7 +276,6 @@ impl> ZKVMVerifier for ((index, proof), transcript) in vm_proof .chip_proofs .iter() - .flat_map(|(index, proofs)| iter::repeat_n(index, proofs.len()).zip(proofs)) .zip_eq(forked_transcripts.iter_mut()) { let num_instance: usize = proof.num_instances.iter().sum();