diff --git a/src/fields/nonnative/.github/workflows/ci.yml b/src/fields/nonnative/.github/workflows/ci.yml index 4d06528b..55bc3f7d 100644 --- a/src/fields/nonnative/.github/workflows/ci.yml +++ b/src/fields/nonnative/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: name: Test runs-on: ubuntu-latest env: - RUSTFLAGS: -Dwarnings + RUSTFLAGS: -Dwarnings --cfg ci strategy: matrix: rust: diff --git a/src/fields/nonnative/benches/bench.rs b/src/fields/nonnative/benches/bench.rs index ec320ba4..4e19e5d1 100644 --- a/src/fields/nonnative/benches/bench.rs +++ b/src/fields/nonnative/benches/bench.rs @@ -15,7 +15,7 @@ fn allocation( let before = cs.num_constraints(); // there will be a check that ensures it has the reasonable number of bits - NonNativeFieldVar::::new_witness( + let _ = NonNativeFieldVar::::new_witness( ark_relations::ns!(cs, "alloc a"), || Ok(a_native), ) @@ -110,7 +110,7 @@ fn inverse( .unwrap(); let before = cs.num_constraints(); - num.inverse().unwrap(); + let _ = num.inverse().unwrap(); let after = cs.num_constraints(); return after - before; diff --git a/src/fields/nonnative/tests/tests.rs b/src/fields/nonnative/tests/tests.rs index 4715af78..250db1a0 100644 --- a/src/fields/nonnative/tests/tests.rs +++ b/src/fields/nonnative/tests/tests.rs @@ -11,8 +11,15 @@ use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::FieldVar, R1CSVar}; use ark_relations::r1cs::{ConstraintSystem, ConstraintSystemRef}; use rand::RngCore; +#[cfg(not(ci))] const NUM_REPETITIONS: usize = 100; +#[cfg(ci)] +const NUM_REPETITIONS: usize = 1; + +#[cfg(not(ci))] const TEST_COUNT: usize = 100; +#[cfg(ci)] +const TEST_COUNT: usize = 1; fn allocation_test( cs: ConstraintSystemRef, @@ -680,6 +687,7 @@ nonnative_test!( ::Fq, ::Fr ); +#[cfg(not(ci))] nonnative_test!( MNT6BigMNT4Small, ::Fr, diff --git a/src/lib.rs b/src/lib.rs index 0778f03d..81c9e6d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,17 @@ -//! This library provides the non-native field gadget for the Zexe constraint-writing platform. -//! The non-native field gadget can be used as a standard FieldVar, given a reasonable non-native gadget parameters. +//! This library provides the non-native field gadget for the `arkworks` constraint-writing platform. +//! The non-native field gadget can be used as a standard `FieldVar`, given +//! reasonable non-native gadget parameters. //! //! This file contains the implementation of three structs: //! -//! - NonNativeFieldParams specifies the constraint prime field (called BaseField), the simulated prime field (called TargetField), and internal parameters searched by the Python script (see README). -//! - NonNativeFieldVar implements the FieldVar for simulating the TargetField within the BaseField. -//! - NonNativeFieldMulResultVar is an intermediate representations of the result of multiplication, which is hidden from the FieldVar interface and is left for advanced users who want better performance. +//! - `NonNativeFieldParams` specifies the constraint prime field (called `BaseField`), +//! the simulated prime field (called `TargetField`), and internal parameters +//! searched by the Python script (see `README.md`). +//! - `NonNativeFieldVar` implements the `FieldVar` for simulating `TargetField` +//! arithmetic within `BaseField`. +//! - `NonNativeFieldMulResultVar` is an intermediate representations of the +//! result of multiplication, which is hidden from the `FieldVar` interface +//! and is left for advanced users who want better performance. //! //! The Python script mentioned above can be found in the subdirectory `scripts`. @@ -18,7 +24,13 @@ rust_2018_idioms, missing_docs )] -#![allow(clippy::redundant_closure_call)] +#![allow( + clippy::redundant_closure_call, + clippy::enum_glob_use, + clippy::missing_errors_doc, + clippy::cast_possible_truncation, + clippy::unseparated_literal_suffix +)] #![forbid(unsafe_code)] #[macro_use] @@ -48,15 +60,15 @@ use ark_std::{borrow::Borrow, cmp::max, fmt::Debug, marker::PhantomData, vec, ve /// example parameters of non-native field gadget /// /// Sample parameters for non-native field gadgets -/// - BaseField: the constraint field -/// - TargetField: the field being simulated -/// - num_limbs: how many limbs are used (searched using the Python script) -/// - bits_per_top_limb: the size of the most significant limb (searched using the Python script) -/// - bits_per_non_top_limb: the size of limbs other than the most significant one (searched using the Python script) +/// - `BaseField`: the constraint field +/// - `TargetField`: the field being simulated +/// - `num_limbs`: how many limbs are used (searched using the Python script) +/// - `bits_per_top_limb`: the size of the most significant limb (searched using the Python script) +/// - `bits_per_non_top_limb`: the size of limbs other than the most significant one (searched using the Python script) /// /// Some requirements for the parameters: -/// - bits_per_top_limb <= bits_per_non_top_limb, since the current implementation does not handle the other case, and the other case would not be significantly more efficient. -/// - BaseField's prime length - 1 > 2 * (bits_per_non_top_limb + 5), which ensures that the reducer is able to reduce the representations using the `sum of residues` method. +/// - `bits_per_top_limb <= bits_per_non_top_limb`, since the current implementation does not handle the other case, and the other case would not be significantly more efficient. +/// - `BaseField's prime length - 1` > `2 * (bits_per_non_top_limb + 5)`, which ensures that the reducer is able to reduce the representations using the `sum of residues` method. pub mod params; /// a submodule for reducing the representations #[doc(hidden)] @@ -93,10 +105,10 @@ macro_rules! overhead { }}; } -/// Parameters for a specific NonNativeFieldGadget instantiation +/// Parameters for a specific `NonNativeFieldVar` instantiation #[derive(Clone, Debug)] pub struct NonNativeFieldParams { - /// The number of limbs (BaseField elements) used to represent a TargetField element. Highest limb first. + /// The number of limbs (`BaseField` elements) used to represent a `TargetField` element. Highest limb first. /// Searched by the Python script pub num_limbs: usize, @@ -109,8 +121,9 @@ pub struct NonNativeFieldParams { pub bits_per_non_top_limb: usize, } -/// The allocated version of NonNativeFieldVar (introduced below) +/// The allocated version of `NonNativeFieldVar` (introduced below) #[derive(Debug)] +#[must_use] pub struct AllocatedNonNativeFieldVar { /// Reference to the constraint system pub cs: ConstraintSystemRef, @@ -120,12 +133,13 @@ pub struct AllocatedNonNativeFieldVar, } -/// A gadget for representing non-native (TargetField) field elements over the constraint field (BaseField). +/// A gadget for representing non-native (`TargetField`) field elements over the constraint field (`BaseField`). #[derive(Clone, Debug)] +#[must_use] pub enum NonNativeFieldVar { /// Constant Constant(TargetField), @@ -231,7 +245,7 @@ impl cur.double_in_place(); } - result += &(val * &power); + result += &(val * power); power *= &base; } @@ -270,7 +284,7 @@ impl let other_limbs = Self::get_limbs_representations(other, Some(&self.cs))?; for (this_limb, other_limb) in self.limbs.iter().zip(other_limbs.iter()) { - limbs.push(this_limb.add_constant(other_limb.clone())); + limbs.push(this_limb.add_constant(*other_limb)); } let mut res = Self { @@ -347,7 +361,7 @@ impl self.value() .unwrap() .inverse() - .unwrap_or(TargetField::zero()) + .unwrap_or_else(TargetField::zero) }) })?; @@ -361,15 +375,14 @@ impl Ok(inverse) } - /// Convert a TargetField element into limbs (not constraints) + /// Convert a `TargetField` element into limbs (not constraints) /// This is an internal function that would be reused by a number of other functions #[tracing::instrument(target = "r1cs")] pub fn get_limbs_representations( elem: &TargetField, cs: Option<&ConstraintSystemRef>, ) -> Result, SynthesisError> { - let cur: ::BigInt = elem.into_repr().clone(); - Self::get_limbs_representations_from_big_int(&cur, cs) + Self::get_limbs_representations_from_big_int(&elem.into_repr(), cs) } /// Obtain the limbs directly from a big int @@ -378,7 +391,7 @@ impl cs: Option<&ConstraintSystemRef>, ) -> Result, SynthesisError> { let mut limbs: Vec = Vec::new(); - let mut cur = elem.clone(); + let mut cur = *elem; let params = match cs { Some(cs) => get_params::(cs), @@ -415,7 +428,7 @@ impl } /// for advanced use, multiply and output the intermediate representations (without reduction) - /// This intermediate representations can be added with each other, and they can later be reduced back to the NonNativeFieldGadget. + /// This intermediate representations can be added with each other, and they can later be reduced back to the `NonNativeFieldVar`. pub fn mul_without_reduce( &self, other: &Self, @@ -449,7 +462,7 @@ impl } let mut prod_limbs: Vec> = Vec::new(); - for z_i in z.iter() { + for z_i in &z { prod_limbs.push(AllocatedFp::new_witness( ark_relations::ns!(self.cs, "limb product"), || Ok(z_i), @@ -459,18 +472,18 @@ impl let x_vars: Vec> = self_reduced .limbs .iter() - .map(|f| LinearCombination::from((BaseField::one(), f.variable.clone()))) + .map(|f| LinearCombination::from((BaseField::one(), f.variable))) .collect(); let y_vars: Vec> = other_reduced .limbs .iter() - .map(|f| LinearCombination::from((BaseField::one(), f.variable.clone()))) + .map(|f| LinearCombination::from((BaseField::one(), f.variable))) .collect(); let z_vars: Vec> = prod_limbs .iter() - .map(|f| LinearCombination::from((BaseField::one(), f.variable.clone()))) + .map(|f| LinearCombination::from((BaseField::one(), f.variable))) .collect(); for c in 0..(2 * num_limbs - 1) { @@ -486,17 +499,17 @@ impl x_vars .iter() .enumerate() - .map(|(i, x_var)| x_var * c_pows[i].clone()) + .map(|(i, x_var)| x_var * c_pows[i]) .fold(lc!(), |new_lc, term| new_lc + term), y_vars .iter() .enumerate() - .map(|(i, y_var)| y_var * c_pows[i].clone()) + .map(|(i, y_var)| y_var * c_pows[i]) .fold(lc!(), |new_lc, term| new_lc + term), z_vars .iter() .enumerate() - .map(|(i, z_var)| z_var * c_pows[i].clone()) + .map(|(i, z_var)| z_var * c_pows[i]) .fold(lc!(), |new_lc, term| new_lc + term), )?; } @@ -518,8 +531,8 @@ impl Ok(AllocatedNonNativeFieldMulResultVar { cs: self.cs.clone(), limbs: prod_limbs_unbalanced_cut, - prod_of_num_of_additions: (x_num_of_additions + &BaseField::one()) - * &(y_num_of_additions + &BaseField::one()), + prod_of_num_of_additions: (x_num_of_additions + BaseField::one()) + * (y_num_of_additions + BaseField::one()), target_phantom: PhantomData, }) } @@ -558,7 +571,7 @@ impl ToBitsGadget let mut bits = Vec::>::new(); for (i, limb) in self_normal.limbs.iter().enumerate() { - let mut limb_bits = Reducer::::limb_to_bits(&limb, { + let limb_bits = Reducer::::limb_to_bits(&limb, { if i == 0 { params.bits_per_top_limb } else { @@ -566,7 +579,7 @@ impl ToBitsGadget } })?; - bits.extend_from_slice(&mut limb_bits); + bits.extend_from_slice(&limb_bits); } bits.reverse(); @@ -585,7 +598,7 @@ impl ToBytesGadget let mut bytes = Vec::>::new(); bits.chunks(8).for_each(|bits_per_byte| { - let mut bits_per_byte: Vec> = bits_per_byte.clone().to_vec(); + let mut bits_per_byte: Vec> = bits_per_byte.to_vec(); if bits_per_byte.len() == 8 { bits_per_byte.resize_with(8, || Boolean::::constant(false)); } @@ -618,8 +631,8 @@ impl CondSelectGadget cs: true_value.cs.clone(), limbs: limbs_sel, num_of_additions_over_normal_form: max( - true_value.num_of_additions_over_normal_form.clone(), - false_value.num_of_additions_over_normal_form.clone(), + true_value.num_of_additions_over_normal_form, + false_value.num_of_additions_over_normal_form, ), is_in_the_normal_form: true_value.is_in_the_normal_form && false_value.is_in_the_normal_form, @@ -641,7 +654,8 @@ impl TwoBitLookupGadget(&cs); @@ -659,12 +673,12 @@ impl TwoBitLookupGadget::two_bit_lookup( bits, limbs_constant, @@ -672,7 +686,7 @@ impl TwoBitLookupGadget { - cs: cs.clone(), + cs, limbs, num_of_additions_over_normal_form: BaseField::zero(), is_in_the_normal_form: true, @@ -698,7 +712,8 @@ impl ThreeBitCondNegLookupGadget debug_assert!(bits.len() == 3); debug_assert!(constants.len() == 4); - if !bits.cs().is_none() { + let is_variable = !bits.cs().is_none(); + if is_variable { let params = get_params::(&bits.cs()); let mut limbs_constants = Vec::new(); @@ -714,12 +729,12 @@ impl ThreeBitCondNegLookupGadget )?; for (i, representation) in representations.iter().enumerate() { - limbs_constants[i].push((*representation).clone()); + limbs_constants[i].push(*representation); } } let mut limbs = Vec::new(); - for limbs_constant in limbs_constants.iter() { + for limbs_constant in &limbs_constants { limbs.push(AllocatedFp::::three_bit_cond_neg_lookup( bits, b0b1, @@ -728,7 +743,7 @@ impl ThreeBitCondNegLookupGadget } Ok(AllocatedNonNativeFieldVar:: { - cs: bits.cs().clone(), + cs: bits.cs(), limbs, num_of_additions_over_normal_form: BaseField::zero(), is_in_the_normal_form: true, @@ -766,7 +781,7 @@ impl AllocVar::new_variable( ark_relations::ns!(cs, "alloc"), || Ok(limb), @@ -792,7 +807,7 @@ impl AllocVar ToConstraintFieldGadget { fn to_constraint_field(&self) -> Result>, SynthesisError> { - let mut res = Vec::>::new(); - for limb in self.limbs.iter() { - res.push(FpVar::::from(limb.clone())); - } - Ok(res) + Ok(self.limbs.iter().cloned().map(FpVar::from).collect()) } } @@ -848,7 +859,7 @@ impl FieldVar Result { match self { Self::Constant(c) => Ok(Self::Constant({ - let mut tmp = (*c).clone(); + let mut tmp = *c; tmp.frobenius_map(power); tmp })), @@ -857,43 +868,6 @@ impl FieldVar PartialEq - for NonNativeFieldVar -{ - fn eq(&self, other: &Self) -> bool { - let self_value = self.value().unwrap_or_default(); - let other_value = other.value().unwrap_or_default(); - - self_value.eq(&other_value) - } -} - -impl Eq - for NonNativeFieldVar -{ -} - -impl PartialOrd - for NonNativeFieldVar -{ - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord - for NonNativeFieldVar -{ - #[inline] - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - let self_native = self.value().unwrap_or_default(); - let other_native = other.value().unwrap_or_default(); - - self_native.cmp(&other_native) - } -} - /****************************************************************************/ /****************************************************************************/ @@ -1045,7 +1019,7 @@ impl CondSelectGadget Self::Var(v) => v.clone(), }; let false_value = match false_value { - Self::Constant(f) => AllocatedNonNativeFieldVar::new_constant(cs.clone(), f)?, + Self::Constant(f) => AllocatedNonNativeFieldVar::new_constant(cs, f)?, Self::Var(v) => v.clone(), }; cond.select(&true_value, &false_value).map(Self::Var) @@ -1068,13 +1042,15 @@ impl TwoBitLookupGadget Result { debug_assert_eq!(b.len(), 2); debug_assert_eq!(c.len(), 4); - if !b.cs().is_none() { - AllocatedNonNativeFieldVar::two_bit_lookup(b, c).map(Self::Var) - } else { + if b.cs().is_none() { + // We're in the constant case + let lsb = b[0].value()? as usize; let msb = b[1].value()? as usize; let index = lsb + (msb << 1); Ok(Self::Constant(c[index])) + } else { + AllocatedNonNativeFieldVar::two_bit_lookup(b, c).map(Self::Var) } } } @@ -1093,9 +1069,9 @@ impl ThreeBitCondNegLookupGadget debug_assert_eq!(b.len(), 3); debug_assert_eq!(c.len(), 4); - if !b.cs().or(b0b1.cs()).is_none() { - AllocatedNonNativeFieldVar::three_bit_cond_neg_lookup(b, b0b1, c).map(Self::Var) - } else { + if b.cs().or(b0b1.cs()).is_none() { + // We're in the constant case + let lsb = b[0].value()? as usize; let msb = b[1].value()? as usize; let index = lsb + (msb << 1); @@ -1108,6 +1084,8 @@ impl ThreeBitCondNegLookupGadget intermediate }; Ok(Self::Constant(y)) + } else { + AllocatedNonNativeFieldVar::three_bit_cond_neg_lookup(b, b0b1, c).map(Self::Var) } } } @@ -1133,28 +1111,25 @@ impl ToConstraintFieldGadget Result>, SynthesisError> { match self { - Self::Constant(c) => { - let mut res = Vec::new(); - let limbs = - AllocatedNonNativeFieldVar::::get_limbs_representations(c, None)?; - for limb in limbs { - res.push(FpVar::constant(limb)); - } - Ok(res) - } + Self::Constant(c) => Ok(AllocatedNonNativeFieldVar::get_limbs_representations( + c, None, + )? + .into_iter() + .map(FpVar::constant) + .collect()), Self::Var(v) => v.to_constraint_field(), } } } impl NonNativeFieldVar { - /// The mul_without_reduce for NonNativeFieldVar + /// The `mul_without_reduce` for `NonNativeFieldVar` pub fn mul_without_reduce( &self, other: &Self, ) -> Result, SynthesisError> { match self { - Self::Constant(c) => Ok(NonNativeFieldMulResultVar::Constant(c.clone())), + Self::Constant(c) => Ok(NonNativeFieldMulResultVar::Constant(*c)), Self::Var(v) => { let other_v = match other { Self::Constant(other_c) => { @@ -1170,8 +1145,9 @@ impl NonNativeFieldVar { /// A reference to the constraint system pub cs: ConstraintSystemRef, @@ -1183,12 +1159,15 @@ pub struct AllocatedNonNativeFieldMulResultVar, } -#[derive(Debug)] /// An intermediate representation especially for the result of a multiplication, containing more limbs. /// It is intended for advanced usage to improve the efficiency. /// -/// That is, instead of calling `mul`, one can call `mul_without_reduce` to obtain this intermediate representation, which can still be added. -/// Then, one can call `reduce` to reduce it back to NonNativeFieldGadget. This may help cut the number of reduce operations. +/// That is, instead of calling `mul`, one can call `mul_without_reduce` to +/// obtain this intermediate representation, which can still be added. +/// Then, one can call `reduce` to reduce it back to `NonNativeFieldVar`. +/// This may help cut the number of reduce operations. +#[derive(Debug)] +#[must_use] pub enum NonNativeFieldMulResultVar { /// as a constant Constant(TargetField), @@ -1209,12 +1188,9 @@ impl let log_top_limb = overhead!(self.prod_of_num_of_additions); let log_sub_top_limb = overhead!(self.prod_of_num_of_additions.double()); - let log_other_limbs_upper_bound = overhead!(self.prod_of_num_of_additions.mul( - &BaseField::from_repr(::BigInt::from( - (params.num_limbs) as u64 - )) - .unwrap() - )); + let log_other_limbs_upper_bound = overhead!(self + .prod_of_num_of_additions + .mul(&BaseField::from_repr(BaseField::BigInt::from(params.num_limbs as u64)).unwrap())); let bits_per_unreduced_top_limb = max( 2 * (bits_per_top_limb + 1) + log_top_limb + bits_per_non_top_limb + 1, @@ -1267,15 +1243,8 @@ impl let num_limbs = params.num_limbs; - let mut sum = Vec::::with_capacity(num_limbs); - for _ in 0..num_limbs { - sum.push(BaseField::zero()); - } - - let mut sum_lc = Vec::>::with_capacity(num_limbs); - for _ in 0..num_limbs { - sum_lc.push(LinearCombination::zero()); - } + let mut sum = vec![BaseField::zero(); num_limbs]; + let mut sum_lc = vec![LinearCombination::zero(); num_limbs]; let bits = self.to_bits()?; @@ -1296,7 +1265,7 @@ impl if val { sum[j].add_assign(limb); } - sum_lc[j] = &sum_lc[j] + &(bits_cond.lc() * limb.clone()); + sum_lc[j] = &sum_lc[j] + &(bits_cond.lc() * *limb); } } @@ -1310,10 +1279,10 @@ impl } let mut sum_gadget = Vec::>::new(); - for i in 0..num_limbs { + for limb in sum.iter().take(num_limbs) { sum_gadget.push(AllocatedFp::::new_witness( ark_relations::ns!(cs, "alloc_sum"), - || Ok(sum[i].clone()), + || Ok(limb), )?); } @@ -1366,7 +1335,7 @@ impl for (i, limb) in self.limbs.iter().rev().enumerate() { if i < other_limbs.len() { - new_limbs.push(limb.add_constant(other_limbs[i].clone())); + new_limbs.push(limb.add_constant(other_limbs[i])); } else { new_limbs.push((*limb).clone()); } @@ -1377,7 +1346,7 @@ impl Ok(Self { cs: self.cs.clone(), limbs: new_limbs, - prod_of_num_of_additions: self.prod_of_num_of_additions + &BaseField::one(), + prod_of_num_of_additions: self.prod_of_num_of_additions + BaseField::one(), target_phantom: PhantomData, }) } @@ -1386,17 +1355,17 @@ impl impl NonNativeFieldMulResultVar { - /// Create a zero NonNativeFieldMulResultVar (used for additions) + /// Create a zero `NonNativeFieldMulResultVar` (used for additions) pub fn zero() -> Self { Self::Constant(TargetField::zero()) } - /// Create an NonNativeFieldMulResultVar from a constant + /// Create an `NonNativeFieldMulResultVar` from a constant pub fn constant(v: TargetField) -> Self { Self::Constant(v) } - /// Reduce the NonNativeFieldMulResultVar back to NonNativeFieldVar + /// Reduce the `NonNativeFieldMulResultVar` back to NonNativeFieldVar #[tracing::instrument(target = "r1cs")] pub fn reduce(&self) -> Result, SynthesisError> { match self { diff --git a/src/params.rs b/src/params.rs index 04f8d7a1..63e2afdd 100644 --- a/src/params.rs +++ b/src/params.rs @@ -79,7 +79,8 @@ impl HitRate { } } -/// Obtain the parameters from a ConstraintSystem's cache or generate a new one +/// Obtain the parameters from a `ConstraintSystem`'s cache or generate a new one +#[must_use] pub fn get_params( cs: &ConstraintSystemRef, ) -> NonNativeFieldParams { @@ -90,42 +91,38 @@ pub fn get_params( let mut big_map = cs_sys.cache_map.borrow_mut(); let small_map = big_map.get(&TypeId::of::()); - if small_map.is_some() { - match small_map.unwrap().downcast_ref::() { - Some(map) => { - let params = - map.get(&(BaseField::size_in_bits(), TargetField::size_in_bits())); - if let Some(params) = params { - let params = params.clone(); - HitRate::update(&mut *big_map, true); - params - } else { - let params = gen_params::(); - - let mut small_map = (*map).clone(); - small_map.insert( - (BaseField::size_in_bits(), TargetField::size_in_bits()), - params.clone(), - ); - big_map.insert(TypeId::of::(), Box::new(small_map)); - - HitRate::update(&mut *big_map, false); - params - } - } - None => { + if let Some(small_map) = small_map { + if let Some(map) = small_map.downcast_ref::() { + let params = map.get(&(BaseField::size_in_bits(), TargetField::size_in_bits())); + if let Some(params) = params { + let params = params.clone(); + HitRate::update(&mut *big_map, true); + params + } else { let params = gen_params::(); - let mut small_map = ParamsMap::new(); + let mut small_map = (*map).clone(); small_map.insert( (BaseField::size_in_bits(), TargetField::size_in_bits()), params.clone(), ); - big_map.insert(TypeId::of::(), Box::new(small_map)); + HitRate::update(&mut *big_map, false); params } + } else { + let params = gen_params::(); + + let mut small_map = ParamsMap::new(); + small_map.insert( + (BaseField::size_in_bits(), TargetField::size_in_bits()), + params.clone(), + ); + + big_map.insert(TypeId::of::(), Box::new(small_map)); + HitRate::update(&mut *big_map, false); + params } } else { let params = gen_params::(); @@ -145,6 +142,7 @@ pub fn get_params( } /// Generate the new params +#[must_use] pub fn gen_params() -> NonNativeFieldParams { let mut problem = ParamsSearching::new(BaseField::size_in_bits(), TargetField::size_in_bits()); problem.solve(); @@ -178,6 +176,7 @@ pub struct ParamsSearching { impl ParamsSearching { /// Create the search problem + #[must_use] pub fn new(base_field_prime_length: usize, target_field_prime_bit_length: usize) -> Self { Self { base_field_prime_length, @@ -239,36 +238,35 @@ impl ParamsSearching { / (self.num_of_limbs - 1); // top limb must be smaller; otherwise, the top limb is too long - if !(top_limb_size <= non_top_limb_size) { + if top_limb_size > non_top_limb_size { break; } // post-add reduce must succeed; otherwise, the top limb is too long - if !(2 * (top_limb_size + 5) < base_field_prime_length) { + if 2 * (top_limb_size + 5) >= base_field_prime_length { break; } - if !(2 * (non_top_limb_size + 5) < base_field_prime_length) { + if 2 * (non_top_limb_size + 5) >= base_field_prime_length { continue; } // computation on the top limb works - if 2 * (top_limb_size + 1) + log_top_limb + non_top_limb_size + 1 - >= 2 * (non_top_limb_size + 1) + log_sub_top_limb + 1 + if 2 * (top_limb_size + 1) + log_top_limb + non_top_limb_size + >= 2 * (non_top_limb_size + 1) + log_sub_top_limb { - if !(2 * (top_limb_size + 1) + log_top_limb + non_top_limb_size - < base_field_prime_length - 1) + if 2 * (top_limb_size + 1) + log_top_limb + non_top_limb_size + >= base_field_prime_length - 1 { continue; } - } else if !(2 * (non_top_limb_size + 1) + log_sub_top_limb - < base_field_prime_length - 1) + } else if 2 * (non_top_limb_size + 1) + log_sub_top_limb + >= base_field_prime_length - 1 { continue; } // computation on the non-top limb works - if !(2 * non_top_limb_size + log_other_limbs_upper_bound - <= base_field_prime_length - 1) + if 2 * non_top_limb_size + log_other_limbs_upper_bound > base_field_prime_length - 1 { continue; } @@ -281,7 +279,7 @@ impl ParamsSearching { * (2 * (non_top_limb_size + 1) + log_other_limbs_upper_bound) - target_field_prime_bit_length; - if flag == false || this_cost < cost { + if !flag || this_cost < cost { flag = true; cost = this_cost; current_top_limb_size = Some(top_limb_size); @@ -289,7 +287,7 @@ impl ParamsSearching { } } - if flag == false { + if !flag { self.num_of_limbs += 1; self.num_of_additions_after_mul = 1; continue; diff --git a/src/reduce.rs b/src/reduce.rs index d5fab203..642f00e1 100644 --- a/src/reduce.rs +++ b/src/reduce.rs @@ -10,7 +10,7 @@ use ark_r1cs_std::{ }; use ark_relations::{ lc, - r1cs::{LinearCombination, SynthesisError}, + r1cs::{LinearCombination, Result as R1CSResult}, }; use ark_std::{ cmp::{max, min}, @@ -33,7 +33,7 @@ impl Reducer) -> bool { let params = get_params::(&elem.cs); - let log = overhead!(elem.num_of_additions_over_normal_form + &BaseField::one()) + 1; + let log = overhead!(elem.num_of_additions_over_normal_form + BaseField::one()) + 1; BaseField::size_in_bits() > params.bits_per_non_top_limb + log + 1 } @@ -45,9 +45,8 @@ impl Reducer bool { let params = get_params::(&elem.cs); - let prod_of_num_of_additions = (elem.num_of_additions_over_normal_form.clone() - + &BaseField::one()) - * &(other.num_of_additions_over_normal_form.clone() + &BaseField::one()); + let prod_of_num_of_additions = (elem.num_of_additions_over_normal_form + BaseField::one()) + * (other.num_of_additions_over_normal_form + BaseField::one()); let bits_per_top_limb = params.bits_per_top_limb; let bits_per_non_top_limb = params.bits_per_non_top_limb; @@ -72,12 +71,13 @@ impl Reducer, num_bits: usize, - ) -> Result>, SynthesisError> { + ) -> R1CSResult>> { let cs = limb.cs.clone(); let num_bits = min(BaseField::size_in_bits() - 1, num_bits); @@ -92,7 +92,7 @@ impl Reducer Reducer, - ) -> Result<(), SynthesisError> { + ) -> R1CSResult<()> { let cs = elem.cs.clone(); let params = get_params::(&cs); // almost only used for mandatory reduce, since the values are not pushed first (pushing first provides better efficiency) let mut limb_bits = Vec::new(); - let surfeit = overhead!(elem.num_of_additions_over_normal_form + &BaseField::one()) + 1; + let surfeit = overhead!(elem.num_of_additions_over_normal_form + BaseField::one()) + 1; for (i, limb) in elem.limbs.iter().enumerate() { if i == 0 { // the top limb @@ -219,7 +219,7 @@ impl Reducer Reducer, - ) -> Result< - ( - Vec>, - Vec, - Vec>, - ), - SynthesisError, - > { + ) -> R1CSResult<( + Vec>, + Vec, + Vec>, + )> { let cs = elem.cs.clone(); let params = get_params::(&cs); - let surfeit = overhead!(elem.num_of_additions_over_normal_form + &BaseField::one()) + 1; + let surfeit = overhead!(elem.num_of_additions_over_normal_form + BaseField::one()) + 1; let surfeit_plus_one = surfeit + 1; // one more bit is added as a result of pushing let mut limbs_value = Vec::::new(); @@ -272,13 +269,13 @@ impl Reducer::zero(); let mut coeff = BaseField::one(); - let surfeit_cur = if i != 0 { surfeit_plus_one } else { surfeit }; + let surfeit_cur = if i == 0 { surfeit } else { surfeit_plus_one }; let limbs_bits = Self::limb_to_bits(&limb_added, params.bits_per_non_top_limb + surfeit_cur)?; @@ -370,11 +367,11 @@ impl Reducer, - ) -> Result<(Vec, Vec>), SynthesisError> { + ) -> R1CSResult<(Vec, Vec>)> { let cs = elem.cs.clone(); let params = get_params::(&cs); - let surfeit = overhead!(elem.num_of_additions_over_normal_form + &BaseField::one()) + 1; + let surfeit = overhead!(elem.num_of_additions_over_normal_form + BaseField::one()) + 1; let surfeit_plus_one = surfeit + 1; // one more bit is added as a result of pushing let mut limbs_value = Vec::::new(); @@ -460,8 +457,8 @@ impl Reducer, - ) -> Result<(), SynthesisError> { - let surfeit = overhead!(elem.num_of_additions_over_normal_form + &BaseField::one()) + 1; + ) -> R1CSResult<()> { + let surfeit = overhead!(elem.num_of_additions_over_normal_form + BaseField::one()) + 1; let cs = elem.cs.clone(); let params = get_params::(&cs); @@ -472,11 +469,10 @@ impl Reducer::get_limbs_representations( &cur, @@ -502,7 +498,7 @@ impl Reducer Reducer, - ) -> Result<(), SynthesisError> { + ) -> R1CSResult<()> { if Self::can_safely_push(elem) { Ok(()) } else { @@ -543,7 +539,7 @@ impl Reducer, elem_other: &mut AllocatedNonNativeFieldVar, - ) -> Result<(), SynthesisError> { + ) -> R1CSResult<()> { let params = get_params::(&elem.cs); if (2 * params.bits_per_top_limb + params.bits_per_non_top_limb + 1 @@ -570,7 +566,7 @@ impl Reducer, - ) -> Result<(), SynthesisError> { + ) -> R1CSResult<()> { let cs = elem.cs.clone(); let params = get_params::(&cs); @@ -595,7 +591,7 @@ impl Reducer::new_constant(cs.clone(), limb)?); } let p_gadget = AllocatedNonNativeFieldVar:: { @@ -617,8 +613,8 @@ impl Reducer Reducer::BigInt::from(256)).unwrap(); for byte in bytes.iter().rev() { - let bytes_basefield = - BaseField::from_repr(::BigInt::from(*byte as u64)) - .unwrap(); - val = val + &(cur * &bytes_basefield); + let bytes_basefield = BaseField::from(*byte); + val += cur * bytes_basefield; cur *= &basefield_256; } @@ -665,13 +659,13 @@ impl Reducer { cs: elem.cs.clone(), limbs: kp_gadget_limbs, - num_of_additions_over_normal_form: elem.num_of_additions_over_normal_form.clone(), + num_of_additions_over_normal_form: elem.num_of_additions_over_normal_form, is_in_the_normal_form: false, target_phantom: PhantomData, };