From e95ffebc8599deb41789a38b1a4fb0ce1150c41f Mon Sep 17 00:00:00 2001 From: "sm.wu" Date: Wed, 2 Oct 2024 20:29:10 +0800 Subject: [PATCH] all test passed --- ceno_zkvm/src/chip_handler/general.rs | 6 +- ceno_zkvm/src/chip_handler/memory.rs | 11 +- ceno_zkvm/src/chip_handler/register.rs | 6 +- ceno_zkvm/src/gadgets/is_lt.rs | 1 - ceno_zkvm/src/instructions/riscv/arith.rs | 10 +- ceno_zkvm/src/instructions/riscv/divu.rs | 11 +- ceno_zkvm/src/lib.rs | 2 - ceno_zkvm/src/scheme/mock_prover.rs | 4 +- ceno_zkvm/src/uint.rs | 49 ++-- ceno_zkvm/src/uint/arithmetic.rs | 25 +- ceno_zkvm/src/uint/constants.rs | 10 +- ceno_zkvm/src/uint/util.rs | 327 +--------------------- 12 files changed, 77 insertions(+), 385 deletions(-) diff --git a/ceno_zkvm/src/chip_handler/general.rs b/ceno_zkvm/src/chip_handler/general.rs index 37bf4de6d..bf3116caa 100644 --- a/ceno_zkvm/src/chip_handler/general.rs +++ b/ceno_zkvm/src/chip_handler/general.rs @@ -180,7 +180,6 @@ impl<'a, E: ExtensionField> CircuitBuilder<'a, E> { 16 => self.assert_u16(name_fn, expr), 8 => self.assert_byte(name_fn, expr), 5 => self.assert_u5(name_fn, expr), - 1 => self.assert_bit(name_fn, expr), c => panic!("Unsupported bit range {c}"), } } @@ -316,18 +315,19 @@ impl<'a, E: ExtensionField> CircuitBuilder<'a, E> { } /// less_than - pub(crate) fn less_than( + pub(crate) fn less_than( &mut self, name_fn: N, lhs: Expression, rhs: Expression, assert_less_than: Option, + max_num_u16_limbs: usize, ) -> Result where NR: Into + Display + Clone, N: FnOnce() -> NR, { - IsLtConfig::construct_circuit(self, name_fn, lhs, rhs, assert_less_than, MAX_U16_LIMB) + IsLtConfig::construct_circuit(self, name_fn, lhs, rhs, assert_less_than, max_num_u16_limbs) } pub(crate) fn is_equal( diff --git a/ceno_zkvm/src/chip_handler/memory.rs b/ceno_zkvm/src/chip_handler/memory.rs index 9293929b6..2900d48ff 100644 --- a/ceno_zkvm/src/chip_handler/memory.rs +++ b/ceno_zkvm/src/chip_handler/memory.rs @@ -50,7 +50,13 @@ impl<'a, E: ExtensionField, NR: Into, N: FnOnce() -> NR> MemoryChipOpera cb.write_record(|| "write_record", write_record)?; // assert prev_ts < current_ts - let lt_cfg = cb.less_than::<_, _, UINT_LIMBS>(|| "prev_ts < ts", prev_ts, ts.clone(), Some(true))?; + let lt_cfg = cb.less_than( + || "prev_ts < ts", + prev_ts, + ts.clone(), + Some(true), + UINT_LIMBS, + )?; let next_ts = ts + 1.into(); @@ -96,11 +102,12 @@ impl<'a, E: ExtensionField, NR: Into, N: FnOnce() -> NR> MemoryChipOpera cb.read_record(|| "read_record", read_record)?; cb.write_record(|| "write_record", write_record)?; - let lt_cfg = cb.less_than::<_, _, UINT_LIMBS>( + let lt_cfg = cb.less_than( || "prev_ts < ts", prev_ts, ts.clone(), Some(true), + UINT_LIMBS, )?; let next_ts = ts + 1.into(); diff --git a/ceno_zkvm/src/chip_handler/register.rs b/ceno_zkvm/src/chip_handler/register.rs index ac7d4497d..474ce32bd 100644 --- a/ceno_zkvm/src/chip_handler/register.rs +++ b/ceno_zkvm/src/chip_handler/register.rs @@ -51,11 +51,12 @@ impl<'a, E: ExtensionField, NR: Into, N: FnOnce() -> NR> RegisterChipOpe cb.write_record(|| "write_record", write_record)?; // assert prev_ts < current_ts - let lt_cfg = cb.less_than::<_, _, UINT_LIMBS>( + let lt_cfg = cb.less_than( || "prev_ts < ts", prev_ts, ts.clone(), Some(true), + UINT_LIMBS, )?; let next_ts = ts + 1.into(); @@ -101,11 +102,12 @@ impl<'a, E: ExtensionField, NR: Into, N: FnOnce() -> NR> RegisterChipOpe cb.read_record(|| "read_record", read_record)?; cb.write_record(|| "write_record", write_record)?; - let lt_cfg = cb.less_than::<_, _, UINT_LIMBS>( + let lt_cfg = cb.less_than( || "prev_ts < ts", prev_ts, ts.clone(), Some(true), + UINT_LIMBS, )?; let next_ts = ts + 1.into(); diff --git a/ceno_zkvm/src/gadgets/is_lt.rs b/ceno_zkvm/src/gadgets/is_lt.rs index c27c8de07..65eb12d4b 100644 --- a/ceno_zkvm/src/gadgets/is_lt.rs +++ b/ceno_zkvm/src/gadgets/is_lt.rs @@ -95,7 +95,6 @@ impl IsLtConfig { } pub fn cal_diff(is_lt: bool, max_num_u16_limbs: usize, lhs: u64, rhs: u64) -> u64 { - println!("max_num_u16_limbs {max_num_u16_limbs}"); let diff = if is_lt { 1u64 << (u16::BITS as usize * max_num_u16_limbs) } else { diff --git a/ceno_zkvm/src/instructions/riscv/arith.rs b/ceno_zkvm/src/instructions/riscv/arith.rs index a4ecb4cae..f8a24ebf5 100644 --- a/ceno_zkvm/src/instructions/riscv/arith.rs +++ b/ceno_zkvm/src/instructions/riscv/arith.rs @@ -440,6 +440,10 @@ mod test { .unwrap() .unwrap(); + let a = Value::<'_, u32>::new_unchecked(u32::MAX); + let b = Value::<'_, u32>::new_unchecked(u32::MAX); + let (c_limb, _, _) = a.mul(&b, &mut LkMultiplicity::default(), true); + // values assignment let (raw_witin, _) = MulInstruction::assign_instances( &config, @@ -448,9 +452,9 @@ mod test { 3, MOCK_PC_MUL, MOCK_PROGRAM[2], - 4294901760, - 4294901760, - Change::new(0, 0), + a.as_u64() as u32, + b.as_u64() as u32, + Change::new(0, Value::::from_limb_unchecked(c_limb).as_u64() as u32), 0, )], ) diff --git a/ceno_zkvm/src/instructions/riscv/divu.rs b/ceno_zkvm/src/instructions/riscv/divu.rs index ece8b1bc3..3d2289457 100644 --- a/ceno_zkvm/src/instructions/riscv/divu.rs +++ b/ceno_zkvm/src/instructions/riscv/divu.rs @@ -124,15 +124,19 @@ impl Instruction for ArithInstruction divisor", 10, 11, 0); verify("remainder", 11, 2, 5); verify("u32::MAX", u32::MAX, u32::MAX, 1); + verify("div u32::MAX", 3, u32::MAX, 0); verify("u32::MAX div by 2", u32::MAX, 2, u32::MAX / 2); verify("div by zero", 10, 0, u32::MAX); verify("mul carry", 1202729773, 171818539, 7); diff --git a/ceno_zkvm/src/lib.rs b/ceno_zkvm/src/lib.rs index 048310dc3..5af066611 100644 --- a/ceno_zkvm/src/lib.rs +++ b/ceno_zkvm/src/lib.rs @@ -1,8 +1,6 @@ #![feature(box_patterns)] #![feature(stmt_expr_attributes)] #![feature(variant_count)] -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] pub mod error; pub mod instructions; diff --git a/ceno_zkvm/src/scheme/mock_prover.rs b/ceno_zkvm/src/scheme/mock_prover.rs index 425b91ad0..23a7eed46 100644 --- a/ceno_zkvm/src/scheme/mock_prover.rs +++ b/ceno_zkvm/src/scheme/mock_prover.rs @@ -768,7 +768,7 @@ mod tests { fn construct_circuit(cb: &mut CircuitBuilder) -> Result { let a = cb.create_witin(|| "a")?; let b = cb.create_witin(|| "b")?; - let lt_wtns = cb.less_than::<_, _, 1>(|| "lt", a.expr(), b.expr(), Some(true))?; + let lt_wtns = cb.less_than(|| "lt", a.expr(), b.expr(), Some(true), 1)?; Ok(Self { a, b, lt_wtns }) } @@ -888,7 +888,7 @@ mod tests { fn construct_circuit(cb: &mut CircuitBuilder) -> Result { let a = cb.create_witin(|| "a")?; let b = cb.create_witin(|| "b")?; - let lt_wtns = cb.less_than::<_, _, 1>(|| "lt", a.expr(), b.expr(), None)?; + let lt_wtns = cb.less_than(|| "lt", a.expr(), b.expr(), None, 1)?; Ok(Self { a, b, lt_wtns }) } diff --git a/ceno_zkvm/src/uint.rs b/ceno_zkvm/src/uint.rs index 23325a2f6..aa82bb5c2 100644 --- a/ceno_zkvm/src/uint.rs +++ b/ceno_zkvm/src/uint.rs @@ -26,6 +26,7 @@ use std::{ pub use strum::IntoEnumIterator; use strum_macros::EnumIter; use sumcheck::util::ceil_log2; +use util::max_degree_2_carry_value; #[derive(Clone, EnumIter, Debug)] pub enum UintLimb { @@ -562,10 +563,11 @@ pub struct Value<'a, T: Into + From + Copy + Default> { // TODO generalize to support non 16 bit limbs // TODO optimize api with fixed size array impl<'a, T: Into + From + Copy + Default> Value<'a, T> { - const LIMBS: usize = { - let u16_bytes = (u16::BITS / 8) as usize; - mem::size_of::() / u16_bytes - }; + const M: usize = { mem::size_of::() * 8 }; + + const C: usize = 16; + + const LIMBS: usize = (Self::M + 15) / 16; pub fn new(val: T, lkm: &mut LkMultiplicity) -> Self { let uint = Value:: { @@ -699,30 +701,31 @@ impl<'a, T: Into + From + Copy + Default> Value<'a, T> { let mut c_limbs = vec![0u16; num_limbs]; let mut carries = vec![0u64; num_limbs]; // TODO FIXME: support full size multiplication - let tx = vec![0u64; num_limbs]; + let mut tmp = vec![0u64; num_limbs]; a_limbs.iter().enumerate().for_each(|(i, &a_limb)| { b_limbs.iter().enumerate().for_each(|(j, &b_limb)| { let idx = i + j; if idx < num_limbs { - let (c, overflow_mul) = a_limb.overflowing_mul(b_limb); - let (ret, overflow_add) = c_limbs[idx].overflowing_add(c); - - c_limbs[idx] = ret; - carries[idx] += overflow_add as u64; - if overflow_mul { - carries[idx] += ((a_limb as u32 * b_limb as u32) / (1 << 16)) as u64; - } + tmp[idx] += a_limb as u64 * b_limb as u64; } }) }); - // complete the computation by adding prev_carry - (1..num_limbs).for_each(|i| { - if carries[i - 1] > 0 { - let (ret, overflow) = c_limbs[i].overflowing_add(carries[i - 1]); - c_limbs[i] = ret; - carries[i] += overflow as u64; - } - }); + + tmp.iter() + .into_iter() + .zip(c_limbs.iter_mut()) + .enumerate() + .for_each(|(i, (tmp, limb))| { + // tmp + prev_carry - carry * Self::LIMB_BASE_MUL + let mut tmp = *tmp; + if i > 0 { + tmp = tmp + carries[i - 1]; + } + // update carry + carries[i] = tmp >> Self::C; + // update limb + *limb = (tmp - (carries[i] << Self::C)) as u16; + }); if !with_overflow { // If the outcome overflows, `with_overflow` can't be false @@ -733,10 +736,8 @@ impl<'a, T: Into + From + Copy + Default> Value<'a, T> { // range check c_limbs.iter().for_each(|c| lkm.assert_ux::<16>(*c as u64)); // calculate max possible carry value - let max_carry_value: u64 = u16::MAX as u64 * u16::MAX as u64 // 2^C * 2^C - * (2 * Self::LIMBS - 1) as u64; // max number of limbs for degree 2 mul - (c_limbs, carries, max_carry_value) + (c_limbs, carries, max_degree_2_carry_value(Self::M, Self::C)) } } diff --git a/ceno_zkvm/src/uint/arithmetic.rs b/ceno_zkvm/src/uint/arithmetic.rs index 3ac10cbe5..993bdca75 100644 --- a/ceno_zkvm/src/uint/arithmetic.rs +++ b/ceno_zkvm/src/uint/arithmetic.rs @@ -114,12 +114,7 @@ impl UIntLimbs { let Some(carries) = &c.carries else { return Err(ZKVMError::CircuitError); }; - println!( - "MAX_DEGREE_2_MUL_CARRY_BITS {:?} Self::MAX_DEGREE_2_MUL_CARRY_BITS_POW2 {:?} Self::MAX_DEGREE_2_MUL_CARRY_U16_LIMB {:?}", - Self::MAX_DEGREE_2_MUL_CARRY_BITS, - Self::MAX_DEGREE_2_MUL_CARRY_VALUE, - Self::MAX_DEGREE_2_MUL_CARRY_U16_LIMB - ); + c.carries_auxiliray_lt_config = Some( carries .iter() @@ -1090,6 +1085,9 @@ mod tests { #[test] fn test_mul_overflow() { + let a = Value::<'_, u32>::new_unchecked(u32::MAX); + let b = Value::<'_, u32>::new_unchecked(u32::MAX); + let (c_limb, c_carry, _) = a.mul(&b, &mut LkMultiplicity::default(), true); let witness_values: Vec> = vec![ // alloc a = 2^16 + (2^16 -1) * 2^16 vec![u16::MAX as u64, u16::MAX as u64], @@ -1097,29 +1095,22 @@ mod tests { vec![u16::MAX as u64, u16::MAX as u64], // mul_c = a * b, // alloc c [1, 0xfffe, 0xffff, 0] with lo part only - vec![1, 0xfffe], + c_limb.iter().map(|v| *v as u64).collect_vec(), // c carry - vec![0x1fffd, 0], + c_carry.iter().map(|v| *v as u64).collect_vec(), // each carry alloc with diff - calculate_carry_diff::<32, 16>(vec![0x1fffd, 0]), + calculate_carry_diff::<32, 16>(c_carry.to_vec()), ] .concat() .into_arc_mle(); - let a = Value::<'_, u32>::new_unchecked(u32::MAX); - let b = Value::<'_, u32>::new_unchecked(u32::MAX); - let (limb, carry, max_carry_value) = a.mul(&b, &mut LkMultiplicity::default(), false); - println!( - "limb {:?} carry {:?} max_carry_value {max_carry_value}", - limb, carry - ); let mut cs = ConstraintSystem::new(|| "test_mul_add"); let mut cb = CircuitBuilder::::new(&mut cs); let mut uint_a = UIntLimbs::<32, 16, E>::new(|| "uint_a", &mut cb).unwrap(); let mut uint_b = UIntLimbs::<32, 16, E>::new(|| "uint_b", &mut cb).unwrap(); let _ = uint_a - .mul(|| "mul_add", &mut cb, &mut uint_b, false) + .mul(|| "mul_add", &mut cb, &mut uint_b, true) .unwrap(); MockProver::assert_satisfied(&cb, &witness_values, None); diff --git a/ceno_zkvm/src/uint/constants.rs b/ceno_zkvm/src/uint/constants.rs index 4a4fd9005..30317526a 100644 --- a/ceno_zkvm/src/uint/constants.rs +++ b/ceno_zkvm/src/uint/constants.rs @@ -1,6 +1,6 @@ use crate::utils::const_min; -use super::UIntLimbs; +use super::{util::max_degree_2_carry_value, UIntLimbs}; pub const RANGE_CHIP_BIT_WIDTH: usize = 16; pub const BYTE_BIT_WIDTH: usize = 8; @@ -29,13 +29,7 @@ impl UIntLimbs { pub const N_RANGE_CELLS: usize = Self::NUM_CELLS * Self::N_RANGE_CELLS_PER_CELL; /// Max carry value during degree 2 limb multiplication - pub const MAX_DEGREE_2_MUL_CARRY_VALUE: u64 = { - assert!(M <= u64::BITS as usize); - let max_carry_value: u128 = ((1 << C) - 1) as u128 * ((1 << C) - 1 ) as u128 // 2^C * 2^C - * (2 * Self::NUM_CELLS - 1) as u128; // max number of limbs for degree 2 mul - assert!(max_carry_value <= u64::MAX as u128); - max_carry_value as u64 - }; + pub const MAX_DEGREE_2_MUL_CARRY_VALUE: u64 = max_degree_2_carry_value(Self::M, Self::C); /// Min bits to cover MAX_DEGREE_2_MUL_CARRY_VALUE pub const MAX_DEGREE_2_MUL_CARRY_BITS: usize = { diff --git a/ceno_zkvm/src/uint/util.rs b/ceno_zkvm/src/uint/util.rs index 7db0f50f1..81bbb6aae 100644 --- a/ceno_zkvm/src/uint/util.rs +++ b/ceno_zkvm/src/uint/util.rs @@ -1,318 +1,9 @@ -// /// Given some data represented by n small cells of size s -// /// this function represents the same data in m big cells of size b -// /// where b >= s -// /// e.g. -// /// information = 1100 -// /// represented with 2 small cells of size 2 each -// /// small -> 11 | 00 -// /// we can pack this into a single big cell of size 4 -// /// big -> 1100 -// pub fn convert_decomp( -// circuit_builder: &mut CircuitBuilder, -// small_wits_in: &[WitIn], -// small_wits_in_bit_width: usize, -// big_witin_bit_width: usize, -// is_little_endian: bool, -// ) -> Result, UtilError> { -// assert!(E::BaseField::NUM_BITS >= big_witin_bit_width as u32); - -// if small_wits_in_bit_width > big_witin_bit_width { -// return Err(UtilError::UIntError( -// "cannot pack bigger width cells into smaller width cells".to_string(), -// )); -// } - -// if small_wits_in_bit_width == big_witin_bit_width { -// return Ok(small_wits_in.to_vec()); -// } - -// // ensure the small cell values are in little endian form -// let small_cells = if !is_little_endian { -// small_wits_in.to_vec().into_iter().rev().collect() -// } else { -// small_wits_in.to_vec() -// }; - -// // compute the number of small cells that can fit into each big cell -// let small_cell_count_per_big_cell = big_witin_bit_width / small_wits_in_bit_width; - -// let mut new_cell_ids = vec![]; - -// // iteratively take and pack n small cells into 1 big cell -// for values in small_cells.chunks(small_cell_count_per_big_cell) { -// let big_cell = circuit_builder.create_cell(); -// for (small_chunk_index, small_bit_cell) in values.iter().enumerate() { -// let shift_size = small_chunk_index * small_wits_in_bit_width; -// circuit_builder.add( -// big_cell, -// *small_bit_cell, -// E::BaseField::from(1 << shift_size), -// ); -// } -// new_cell_ids.push(big_cell); -// } - -// Ok(new_cell_ids) -// } - -// /// Pads a `Vec` with new cells to reach some given size n -// pub fn pad_cells( -// circuit_builder: &mut CircuitBuilder, -// cells: &mut Vec, -// size: usize, -// ) { -// if cells.len() < size { -// cells.extend(circuit_builder.create_cells(size - cells.len())) -// } -// } - -// /// Compile time evaluated minimum function -// /// returns min(a, b) -// pub const fn const_min(a: usize, b: usize) -> usize { -// if a <= b { a } else { b } -// } - -// /// Assumes each limb < max_value -// /// adds 1 to the big value, while preserving the above constraint -// pub fn add_one_to_big_num(limb_modulo: F, limbs: &[F]) -> Vec { -// let mut should_add_one = true; -// let mut result = vec![]; - -// for limb in limbs { -// let mut new_limb_value = limb.clone(); -// if should_add_one { -// new_limb_value += F::ONE; -// if new_limb_value == limb_modulo { -// new_limb_value = F::ZERO; -// } else { -// should_add_one = false; -// } -// } -// result.push(new_limb_value); -// } - -// result -// } - -// #[cfg(test)] -// mod tests { -// use crate::uint::util::{add_one_to_big_num, const_min, convert_decomp, pad_cells}; -// use gkr::structs::{Circuit, CircuitWitness}; -// use goldilocks::{Goldilocks, GoldilocksExt2}; -// use itertools::Itertools; -// use simple_frontend::structs::CircuitBuilder; - -// #[test] -// #[should_panic] -// fn test_pack_big_cells_into_small_cells() { -// let mut circuit_builder = CircuitBuilder::::new(); -// let (_, big_values) = circuit_builder.create_witness_in(5); -// let big_bit_width = 5; -// let small_bit_width = 2; -// let cell_packing_result = convert_decomp( -// &mut circuit_builder, -// &big_values, -// big_bit_width, -// small_bit_width, -// true, -// ) -// .unwrap(); -// } - -// #[test] -// fn test_pack_same_size_cells() { -// let mut circuit_builder = CircuitBuilder::::new(); -// let (_, initial_values) = circuit_builder.create_witness_in(5); -// let small_bit_width = 2; -// let big_bit_width = 2; -// let new_values = convert_decomp( -// &mut circuit_builder, -// &initial_values, -// small_bit_width, -// big_bit_width, -// true, -// ) -// .unwrap(); -// assert_eq!(initial_values, new_values); -// } - -// #[test] -// fn test_pack_small_cells_into_big_cells() { -// let mut circuit_builder = CircuitBuilder::::new(); -// let (_, small_values) = circuit_builder.create_witness_in(9); -// let small_bit_width = 2; -// let big_bit_width = 6; -// let big_values = convert_decomp( -// &mut circuit_builder, -// &small_values, -// small_bit_width, -// big_bit_width, -// true, -// ) -// .unwrap(); -// assert_eq!(big_values.len(), 3); -// circuit_builder.create_witness_out_from_cells(&big_values); - -// // verify construction against concrete witness values -// circuit_builder.configure(); -// let circuit = Circuit::new(&circuit_builder); - -// // input -// // we start with cells of bit width 2 (9 of them) -// // 11 00 10 11 01 10 01 01 11 (bit representation) -// // 3 0 2 3 1 2 1 1 3 (field representation) -// // -// // expected output -// // repacking into cells of bit width 6 -// // we can only fit three 2-bit cells into a 6 bit cell -// // 100011 100111 110101 (bit representation) -// // 35 39 53 (field representation) - -// let witness_values = vec![3, 0, 2, 3, 1, 2, 1, 1, 3] -// .into_iter() -// .map(|v| Goldilocks::from(v)) -// .collect::>(); -// let circuit_witness = { -// let mut circuit_witness = CircuitWitness::new(&circuit, vec![]); -// circuit_witness.add_instance(&circuit, vec![witness_values]); -// circuit_witness -// }; - -// circuit_witness.check_correctness(&circuit); - -// let output = circuit_witness.output_layer_witness_ref().instances[0].to_vec(); - -// assert_eq!( -// &output[..3], -// vec![35, 39, 53] -// .into_iter() -// .map(|v| Goldilocks::from(v)) -// .collect::>() -// ); - -// // padding to power of 2 -// assert_eq!( -// &output[3..], -// vec![0] -// .into_iter() -// .map(|v| Goldilocks::from(v)) -// .collect_vec() -// ); -// } - -// #[test] -// fn test_pad_cells() { -// let mut circuit_builder = CircuitBuilder::::new(); -// let (_, mut small_values) = circuit_builder.create_witness_in(3); -// // assert before padding -// assert_eq!(small_values, vec![0, 1, 2]); -// // pad -// pad_cells(&mut circuit_builder, &mut small_values, 5); -// // assert after padding -// assert_eq!(small_values, vec![0, 1, 2, 3, 4]); -// } - -// #[test] -// fn test_min_function() { -// assert_eq!(const_min(2, 3), 2); -// assert_eq!(const_min(3, 3), 3); -// assert_eq!(const_min(5, 3), 3); -// } - -// #[test] -// fn test_add_one_big_num() { -// let limb_modulo = Goldilocks::from(2); - -// // 000 -// let initial_limbs = vec![Goldilocks::from(0); 3]; - -// // 100 -// let updated_limbs = add_one_to_big_num(limb_modulo, &initial_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(1), -// Goldilocks::from(0), -// Goldilocks::from(0) -// ] -// ); - -// // 010 -// let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(0), -// Goldilocks::from(1), -// Goldilocks::from(0) -// ] -// ); - -// // 110 -// let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(1), -// Goldilocks::from(1), -// Goldilocks::from(0) -// ] -// ); - -// // 001 -// let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(0), -// Goldilocks::from(0), -// Goldilocks::from(1) -// ] -// ); - -// // 101 -// let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(1), -// Goldilocks::from(0), -// Goldilocks::from(1) -// ] -// ); - -// // 011 -// let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(0), -// Goldilocks::from(1), -// Goldilocks::from(1) -// ] -// ); - -// // 111 -// let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(1), -// Goldilocks::from(1), -// Goldilocks::from(1) -// ] -// ); - -// // restart cycle -// // 000 -// let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); -// assert_eq!( -// updated_limbs, -// vec![ -// Goldilocks::from(0), -// Goldilocks::from(0), -// Goldilocks::from(0) -// ] -// ); -// } -// } +pub(crate) const fn max_degree_2_carry_value(m: usize, c: usize) -> u64 { + assert!(m <= u64::BITS as usize); + let num_cells = (m + c - 1) / c; + let max_carry_value: u128 = ((1 << c) - 1) as u128 * ((1 << c) - 1 ) as u128 // 2^C * 2^C + * (2 * num_cells - 1) as u128 + / (1 << c) as u128; // max number of limbs for degree 2 mul + assert!(max_carry_value <= u64::MAX as u128); + max_carry_value as u64 +}