From a3358fe45b87bf1956fac73af657fee72be694bc Mon Sep 17 00:00:00 2001 From: cyphersnake <57308842+cyphersnake@users.noreply.github.com> Date: Thu, 11 Jan 2024 12:26:15 +0100 Subject: [PATCH] test(ivc): impl `fold_challenges_test` (#99) docs(ivc): `fold_challenges` --- src/ivc/fold_relaxed_plonk_instance_chip.rs | 185 +++++++++++++++++++- 1 file changed, 180 insertions(+), 5 deletions(-) diff --git a/src/ivc/fold_relaxed_plonk_instance_chip.rs b/src/ivc/fold_relaxed_plonk_instance_chip.rs index ac322f53..b4f3000d 100644 --- a/src/ivc/fold_relaxed_plonk_instance_chip.rs +++ b/src/ivc/fold_relaxed_plonk_instance_chip.rs @@ -447,12 +447,24 @@ where Ok([new_folded_X0, new_folded_X1]) } - // TODO #32 rustdoc + /// Fold [`RelaxedPlonkInstance::challenges`] & [`PlonkInstance::challenges`] + /// + /// # Description + /// + /// This function is responsible for combining the current `folded_challenges` accumulator with + /// `input_challenges`. This is achieved through a [`FoldRelaxedPlonkInstanceChip::fold_via_biguint`] + /// fn call. + /// + /// ```markdown + /// new_folded_challenges[i] = fold_via_biguin(folded_challenges[i], input_challenges[i], m, r) + /// ``` + /// + /// Please check [`FoldRelaxedPlonkInstanceChip::fold_via_biguint`] for more details fn fold_challenges( - bn_chip: &BigUintMulModChip, region: &mut RegionCtx, - folded_challenges: Vec>>, + bn_chip: &BigUintMulModChip, input_challenges: Vec>>, + folded_challenges: Vec>>, r_as_bn: &[AssignedValue], m_bn: &[AssignedValue], limb_width: NonZeroUsize, @@ -556,10 +568,10 @@ where )?; let new_folded_challanges = Self::fold_challenges( - &bn_chip, region, - folded_challenges, + &bn_chip, input_challenges, + folded_challenges, &r.as_bn_limbs, &m_bn, self.limb_width, @@ -1342,6 +1354,169 @@ mod tests { } } + #[test_log::test] + fn fold_challenges_test() { + const NUM_CHALLENGES: usize = 5; + let Fixture { + mut td, + config, + mut rnd, + r, + .. + } = Fixture::default(); + + let mut layouter = SingleChipLayouter::new(&mut td, vec![]).unwrap(); + + let mut relaxed_plonk = RelaxedPlonkInstance::::new(0, NUM_CHALLENGES, 0); + + let bn_chip = BigUintMulModChip::::new( + config + .into_smaller_size::<{ big_uint_mul_mod_chip::MAIN_GATE_T }>() + .unwrap(), + LIMB_WIDTH, + LIMB_LIMIT, + ); + + for _round in 0..=NUM_OF_FOLD_ROUNDS { + let input_challenges = iter::repeat_with(|| ScalarExt::random(&mut rnd)) + .take(NUM_CHALLENGES) + .collect::>(); + + // Run twice for setup & real run + let on_circuit_challanges_cell = layouter.assign_region( + || "fold challenges test", + |region| { + let mut ctx = RegionCtx::new(region, 0); + + let mut advice_columns_assigner = config.advice_cycle_assigner(); + + macro_rules! assign_scalar_as_bn { + ($region:expr, $input:expr, $annotation_prefix:expr) => {{ + BigUint::from_f( + &util::fe_to_fe_safe::<_, Base>($input).unwrap(), + LIMB_WIDTH, + LIMB_LIMIT, + ) + .unwrap() + .limbs() + .iter() + .enumerate() + .map(|(limb_index, limb)| { + let limb = util::fe_to_fe_safe(limb) + .ok_or(Error::WhileScalarToBase { + variable_name: $annotation_prefix, + variable_str: format!("{limb:?}"), + }) + .unwrap(); + + advice_columns_assigner.assign_next_advice( + $region, + || format!("{}, limb {limb_index}", $annotation_prefix), + limb, + ) + }) + .collect::, _>>() + }}; + } + + let assigned_r = advice_columns_assigner + .assign_next_advice(&mut ctx, || "r", util::fe_to_fe(&r).unwrap()) + .unwrap(); + + let assigned_fold_challenges = relaxed_plonk + .challenges + .iter() + .map(|instance| assign_scalar_as_bn!(&mut ctx, instance, "folded instance")) + .collect::, _>>() + .unwrap(); + + let assigned_input_instance = input_challenges + .iter() + .map(|instance| assign_scalar_as_bn!(&mut ctx, instance, "input instance")) + .collect::, _>>()?; + + let mut fixed_columns_assigner = config.fixed_cycle_assigner(); + + let m_bn = BigUint::::from_biguint( + &num_bigint::BigUint::from_str_radix( + ::MODULUS.trim_start_matches("0x"), + 16, + ) + .unwrap(), + LIMB_WIDTH, + LIMB_LIMIT, + ) + .unwrap() + .limbs() + .iter() + .enumerate() + .map(|(limb_index, limb)| { + fixed_columns_assigner.assign_next_fixed( + &mut ctx, + || format!("m_bn [{limb_index}"), + *limb, + ) + }) + .collect::, _>>()?; + + ctx.next(); + + let r_as_bn = bn_chip + .from_assigned_cell_to_limbs(&mut ctx, &assigned_r) + .unwrap(); + + Ok(FoldRelaxedPlonkInstanceChip::::fold_challenges( + &mut ctx, + &bn_chip, + assigned_input_instance, + assigned_fold_challenges, + &r_as_bn, + &m_bn, + LIMB_WIDTH, + ) + .unwrap()) + }, + ); + + relaxed_plonk = relaxed_plonk.fold( + &PlonkInstance { + W_commitments: vec![], + instance: vec![], + challenges: input_challenges.to_vec(), + }, + &[], + &r, + ); + + let off_circuit_challenges = relaxed_plonk + .challenges + .iter() + .map(|instance| { + BigUint::from_f( + &util::fe_to_fe_safe::(instance).unwrap(), + LIMB_WIDTH, + LIMB_LIMIT, + ) + .unwrap() + .limbs() + .to_vec() + }) + .collect::>(); + + let on_circuit_challenges = on_circuit_challanges_cell + .unwrap() + .into_iter() + .map(|c| { + c.into_iter() + .map(|cell| *cell.value().unwrap().unwrap()) + .collect::>() + }) + .collect::>>(); + + assert_eq!(off_circuit_challenges, on_circuit_challenges); + } + } + #[test_log::test] fn fold() { debug!("start");