diff --git a/Cargo.lock b/Cargo.lock index d68cbfbc..ee057df9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2293,6 +2293,7 @@ name = "ec-divisors" version = "0.1.0" dependencies = [ "dalek-ff-group", + "ff", "group", "hex", "pasta_curves", diff --git a/crypto/dalek-ff-group/src/field.rs b/crypto/dalek-ff-group/src/field.rs index b1af2711..bc3078c8 100644 --- a/crypto/dalek-ff-group/src/field.rs +++ b/crypto/dalek-ff-group/src/field.rs @@ -35,7 +35,7 @@ impl_modulus!( type ResidueType = Residue; /// A constant-time implementation of the Ed25519 field. -#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Zeroize)] pub struct FieldElement(ResidueType); // Square root of -1. diff --git a/crypto/dkg/Cargo.toml b/crypto/dkg/Cargo.toml index cde0d153..39ebb6dc 100644 --- a/crypto/dkg/Cargo.toml +++ b/crypto/dkg/Cargo.toml @@ -37,7 +37,6 @@ schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "^0.5 dleq = { path = "../dleq", version = "^0.4.1", default-features = false } # eVRF DKG dependencies -subtle = { version = "2", default-features = false, features = ["std"], optional = true } generic-array = { version = "1", default-features = false, features = ["alloc"], optional = true } blake2 = { version = "0.10", default-features = false, features = ["std"], optional = true } rand_chacha = { version = "0.3", default-features = false, features = ["std"], optional = true } @@ -82,7 +81,6 @@ borsh = ["dep:borsh"] evrf = [ "std", - "dep:subtle", "dep:generic-array", "dep:blake2", diff --git a/crypto/dkg/src/evrf/proof.rs b/crypto/dkg/src/evrf/proof.rs index ce9c57d1..8eb3ab00 100644 --- a/crypto/dkg/src/evrf/proof.rs +++ b/crypto/dkg/src/evrf/proof.rs @@ -1,6 +1,5 @@ use core::{marker::PhantomData, ops::Deref, fmt}; -use subtle::*; use zeroize::{Zeroize, Zeroizing}; use rand_core::{RngCore, CryptoRng, SeedableRng}; @@ -10,10 +9,7 @@ use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; use blake2::{Digest, Blake2s256}; use ciphersuite::{ - group::{ - ff::{Field, PrimeField, PrimeFieldBits}, - Group, GroupEncoding, - }, + group::{ff::Field, Group, GroupEncoding}, Ciphersuite, }; @@ -24,7 +20,7 @@ use generalized_bulletproofs::{ }; use generalized_bulletproofs_circuit_abstraction::*; -use ec_divisors::{DivisorCurve, new_divisor}; +use ec_divisors::{DivisorCurve, ScalarDecomposition}; use generalized_bulletproofs_ec_gadgets::*; /// A pair of curves to perform the eVRF with. @@ -309,147 +305,6 @@ impl Evrf { debug_assert!(challenged_generators.next().is_none()); } - /// Convert a scalar to a sequence of coefficients for the polynomial 2**i, where the sum of the - /// coefficients is F::NUM_BITS. - /// - /// Despite the name, the returned coefficients are not guaranteed to be bits (0 or 1). - /// - /// This scalar will presumably be used in a discrete log proof. That requires calculating a - /// divisor which is variable time to the amount of points interpolated. Since the amount of - /// points interpolated is equal to the sum of the coefficients in the polynomial, we need all - /// scalars to have a constant sum of their coefficients (instead of one variable to its bits). - /// - /// We achieve this by finding the highest non-0 coefficient, decrementing it, and increasing the - /// immediately less significant coefficient by 2. This increases the sum of the coefficients by - /// 1 (-1+2=1). - fn scalar_to_bits(scalar: &::F) -> Vec { - let num_bits = u64::from(<::EmbeddedCurve as Ciphersuite>::F::NUM_BITS); - - // Obtain the bits of the private key - let num_bits_usize = usize::try_from(num_bits).unwrap(); - let mut decomposition = vec![0; num_bits_usize]; - for (i, bit) in scalar.to_le_bits().into_iter().take(num_bits_usize).enumerate() { - let bit = u64::from(u8::from(bit)); - decomposition[i] = bit; - } - - // The following algorithm only works if the value of the scalar exceeds num_bits - // If it isn't, we increase it by the modulus such that it does exceed num_bits - { - let mut less_than_num_bits = Choice::from(0); - for i in 0 .. num_bits { - less_than_num_bits |= scalar.ct_eq(&::F::from(i)); - } - let mut decomposition_of_modulus = vec![0; num_bits_usize]; - // Decompose negative one - for (i, bit) in (-::F::ONE) - .to_le_bits() - .into_iter() - .take(num_bits_usize) - .enumerate() - { - let bit = u64::from(u8::from(bit)); - decomposition_of_modulus[i] = bit; - } - // Increment it by one - decomposition_of_modulus[0] += 1; - - // Add the decomposition onto the decomposition of the modulus - for i in 0 .. num_bits_usize { - let new_decomposition = <_>::conditional_select( - &decomposition[i], - &(decomposition[i] + decomposition_of_modulus[i]), - less_than_num_bits, - ); - decomposition[i] = new_decomposition; - } - } - - // Calculcate the sum of the coefficients - let mut sum_of_coefficients: u64 = 0; - for decomposition in &decomposition { - sum_of_coefficients += *decomposition; - } - - /* - Now, because we added a log2(k)-bit number to a k-bit number, we may have our sum of - coefficients be *too high*. We attempt to reduce the sum of the coefficients accordingly. - - This algorithm is guaranteed to complete as expected. Take the sequence `222`. `222` becomes - `032` becomes `013`. Even if the next coefficient in the sequence is `2`, the third - coefficient will be reduced once and the next coefficient (`2`, increased to `3`) will only - be eligible for reduction once. This demonstrates, even for a worst case of log2(k) `2`s - followed by `1`s (as possible if the modulus is a Mersenne prime), the log2(k) `2`s can be - reduced as necessary so long as there is a single coefficient after (requiring the entire - sequence be at least of length log2(k) + 1). For a 2-bit number, log2(k) + 1 == 2, so this - holds for any odd prime field. - - To fully type out the demonstration for the Mersenne prime 3, with scalar to encode 1 (the - highest value less than the number of bits): - - 10 - Little-endian bits of 1 - 21 - Little-endian bits of 1, plus the modulus - 02 - After one reduction, where the sum of the coefficients does in fact equal 2 (the target) - */ - { - let mut log2_num_bits = 0; - while (1 << log2_num_bits) < num_bits { - log2_num_bits += 1; - } - - for _ in 0 .. log2_num_bits { - // If the sum of coefficients is the amount of bits, we're done - let mut done = sum_of_coefficients.ct_eq(&num_bits); - - for i in 0 .. (num_bits_usize - 1) { - let should_act = (!done) & decomposition[i].ct_gt(&1); - // Subtract 2 from this coefficient - let amount_to_sub = <_>::conditional_select(&0, &2, should_act); - decomposition[i] -= amount_to_sub; - // Add 1 to the next coefficient - let amount_to_add = <_>::conditional_select(&0, &1, should_act); - decomposition[i + 1] += amount_to_add; - - // Also update the sum of coefficients - sum_of_coefficients -= <_>::conditional_select(&0, &1, should_act); - - // If we updated the coefficients this loop iter, we're done for this loop iter - done |= should_act; - } - } - } - - for _ in 0 .. num_bits { - // If the sum of coefficients is the amount of bits, we're done - let mut done = sum_of_coefficients.ct_eq(&num_bits); - - // Find the highest coefficient currently non-zero - for i in (1 .. decomposition.len()).rev() { - // If this is non-zero, we should decrement this coefficient if we haven't already - // decremented a coefficient this round - let is_non_zero = !(0.ct_eq(&decomposition[i])); - let should_act = (!done) & is_non_zero; - - // Update this coefficient and the prior coefficient - let amount_to_sub = <_>::conditional_select(&0, &1, should_act); - decomposition[i] -= amount_to_sub; - - let amount_to_add = <_>::conditional_select(&0, &2, should_act); - // i must be at least 1, so i - 1 will be at least 0 (meaning it's safe to index with) - decomposition[i - 1] += amount_to_add; - - // Also update the sum of coefficients - sum_of_coefficients += <_>::conditional_select(&0, &1, should_act); - - // If we updated the coefficients this loop iter, we're done for this loop iter - done |= should_act; - } - } - debug_assert!(bool::from(decomposition.iter().sum::().ct_eq(&num_bits))); - - decomposition - } - /// Prove a point on an elliptic curve had its discrete logarithm generated via an eVRF. pub(crate) fn prove( rng: &mut (impl RngCore + CryptoRng), @@ -471,11 +326,9 @@ impl Evrf { // A function to calculate a divisor and push it onto the tape // This defines a vec, divisor_points, outside of the fn to reuse its allocation - let mut divisor_points = - Vec::with_capacity((::F::NUM_BITS as usize) + 1); let mut divisor = |vector_commitment_tape: &mut Vec<_>, - dlog: &[u64], + dlog: &ScalarDecomposition<<::EmbeddedCurve as Ciphersuite>::F>, push_generator: bool, generator: <::EmbeddedCurve as Ciphersuite>::G, dh: <::EmbeddedCurve as Ciphersuite>::G| { @@ -484,24 +337,7 @@ impl Evrf { generator_tables.push(GeneratorTable::new(&curve_spec, x, y)); } - { - let mut generator = generator; - for coefficient in dlog { - let mut coefficient = *coefficient; - while coefficient != 0 { - coefficient -= 1; - divisor_points.push(generator); - } - generator = generator.double(); - } - debug_assert_eq!( - dlog.iter().sum::(), - u64::from(::F::NUM_BITS) - ); - } - divisor_points.push(-dh); - let mut divisor = new_divisor(&divisor_points).unwrap().normalize_x_coefficient(); - divisor_points.zeroize(); + let mut divisor = dlog.scalar_mul_divisor(generator).normalize_x_coefficient(); vector_commitment_tape.push(divisor.zero_coefficient); @@ -540,11 +376,12 @@ impl Evrf { let evrf_public_key; let mut actual_coefficients = Vec::with_capacity(coefficients); { - let mut dlog = Self::scalar_to_bits(evrf_private_key); + let dlog = + ScalarDecomposition::<::F>::new(**evrf_private_key); let points = Self::transcript_to_points(transcript, coefficients); // Start by pushing the discrete logarithm onto the tape - for coefficient in &dlog { + for coefficient in dlog.decomposition() { vector_commitment_tape.push(<_>::from(*coefficient)); } @@ -573,8 +410,6 @@ impl Evrf { actual_coefficients.push(res); } debug_assert_eq!(actual_coefficients.len(), coefficients); - - dlog.zeroize(); } // Now do the ECDHs for the encryption @@ -595,14 +430,15 @@ impl Evrf { break; } } - let mut dlog = Self::scalar_to_bits(&ecdh_private_key); + let dlog = + ScalarDecomposition::<::F>::new(ecdh_private_key); let ecdh_commitment = ::generator() * ecdh_private_key; ecdh_commitments.push(ecdh_commitment); ecdh_commitments_xy.last_mut().unwrap()[j] = <::G as DivisorCurve>::to_xy(ecdh_commitment).unwrap(); // Start by pushing the discrete logarithm onto the tape - for coefficient in &dlog { + for coefficient in dlog.decomposition() { vector_commitment_tape.push(<_>::from(*coefficient)); } @@ -625,7 +461,6 @@ impl Evrf { *res += dh_x; ecdh_private_key.zeroize(); - dlog.zeroize(); } encryption_masks.push(res); } diff --git a/crypto/evrf/divisors/Cargo.toml b/crypto/evrf/divisors/Cargo.toml index 037d8028..04e820b6 100644 --- a/crypto/evrf/divisors/Cargo.toml +++ b/crypto/evrf/divisors/Cargo.toml @@ -14,10 +14,11 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] rand_core = { version = "0.6", default-features = false } -zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "^1.5", default-features = false, features = ["std", "zeroize_derive"] } subtle = { version = "2", default-features = false, features = ["std"] } -group = "0.13" +ff = { version = "0.13", default-features = false, features = ["std", "bits"] } +group = { version = "0.13", default-features = false } hex = { version = "0.4", optional = true } dalek-ff-group = { path = "../../dalek-ff-group", features = ["std"], optional = true } diff --git a/crypto/evrf/divisors/src/lib.rs b/crypto/evrf/divisors/src/lib.rs index dc27c8d9..dbeb149f 100644 --- a/crypto/evrf/divisors/src/lib.rs +++ b/crypto/evrf/divisors/src/lib.rs @@ -3,15 +3,16 @@ #![deny(missing_docs)] #![allow(non_snake_case)] -use subtle::{Choice, ConstantTimeEq, ConditionallySelectable}; +use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConditionallySelectable}; +use zeroize::{Zeroize, ZeroizeOnDrop}; use group::{ - ff::{Field, PrimeField}, + ff::{Field, PrimeField, PrimeFieldBits}, Group, }; mod poly; -pub use poly::*; +pub use poly::Poly; #[cfg(test)] mod tests; @@ -19,7 +20,7 @@ mod tests; /// A curve usable with this library. pub trait DivisorCurve: Group + ConstantTimeEq + ConditionallySelectable { /// An element of the field this curve is defined over. - type FieldElement: PrimeField + ConditionallySelectable; + type FieldElement: Zeroize + PrimeField + ConditionallySelectable; /// The A in the curve equation y^2 = x^3 + A x + B. fn a() -> Self::FieldElement; @@ -257,6 +258,186 @@ pub fn new_divisor(points: &[C]) -> Option { + scalar: F, + decomposition: Vec, +} + +impl ScalarDecomposition { + /// Decompose a scalar. + pub fn new(scalar: F) -> Self { + /* + We need the sum of the coefficients to equal F::NUM_BITS. The scalar's bits will be less than + F::NUM_BITS. Accordingly, we need to increment the sum of the coefficients without + incrementing the scalar represented. We do this by finding the highest non-0 coefficient, + decrementing it, and increasing the immediately less significant coefficient by 2. This + increases the sum of the coefficients by 1 (-1+2=1). + */ + + let num_bits = u64::from(F::NUM_BITS); + + // Obtain the bits of the scalar + let num_bits_usize = usize::try_from(num_bits).unwrap(); + let mut decomposition = vec![0; num_bits_usize]; + for (i, bit) in scalar.to_le_bits().into_iter().take(num_bits_usize).enumerate() { + let bit = u64::from(u8::from(bit)); + decomposition[i] = bit; + } + + // The following algorithm only works if the value of the scalar exceeds num_bits + // If it isn't, we increase it by the modulus such that it does exceed num_bits + { + let mut less_than_num_bits = Choice::from(0); + for i in 0 .. num_bits { + less_than_num_bits |= scalar.ct_eq(&F::from(i)); + } + let mut decomposition_of_modulus = vec![0; num_bits_usize]; + // Decompose negative one + for (i, bit) in (-F::ONE).to_le_bits().into_iter().take(num_bits_usize).enumerate() { + let bit = u64::from(u8::from(bit)); + decomposition_of_modulus[i] = bit; + } + // Increment it by one + decomposition_of_modulus[0] += 1; + + // Add the decomposition onto the decomposition of the modulus + for i in 0 .. num_bits_usize { + let new_decomposition = <_>::conditional_select( + &decomposition[i], + &(decomposition[i] + decomposition_of_modulus[i]), + less_than_num_bits, + ); + decomposition[i] = new_decomposition; + } + } + + // Calculcate the sum of the coefficients + let mut sum_of_coefficients: u64 = 0; + for decomposition in &decomposition { + sum_of_coefficients += *decomposition; + } + + /* + Now, because we added a log2(k)-bit number to a k-bit number, we may have our sum of + coefficients be *too high*. We attempt to reduce the sum of the coefficients accordingly. + + This algorithm is guaranteed to complete as expected. Take the sequence `222`. `222` becomes + `032` becomes `013`. Even if the next coefficient in the sequence is `2`, the third + coefficient will be reduced once and the next coefficient (`2`, increased to `3`) will only + be eligible for reduction once. This demonstrates, even for a worst case of log2(k) `2`s + followed by `1`s (as possible if the modulus is a Mersenne prime), the log2(k) `2`s can be + reduced as necessary so long as there is a single coefficient after (requiring the entire + sequence be at least of length log2(k) + 1). For a 2-bit number, log2(k) + 1 == 2, so this + holds for any odd prime field. + + To fully type out the demonstration for the Mersenne prime 3, with scalar to encode 1 (the + highest value less than the number of bits): + + 10 - Little-endian bits of 1 + 21 - Little-endian bits of 1, plus the modulus + 02 - After one reduction, where the sum of the coefficients does in fact equal 2 (the target) + */ + { + let mut log2_num_bits = 0; + while (1 << log2_num_bits) < num_bits { + log2_num_bits += 1; + } + + for _ in 0 .. log2_num_bits { + // If the sum of coefficients is the amount of bits, we're done + let mut done = sum_of_coefficients.ct_eq(&num_bits); + + for i in 0 .. (num_bits_usize - 1) { + let should_act = (!done) & decomposition[i].ct_gt(&1); + // Subtract 2 from this coefficient + let amount_to_sub = <_>::conditional_select(&0, &2, should_act); + decomposition[i] -= amount_to_sub; + // Add 1 to the next coefficient + let amount_to_add = <_>::conditional_select(&0, &1, should_act); + decomposition[i + 1] += amount_to_add; + + // Also update the sum of coefficients + sum_of_coefficients -= <_>::conditional_select(&0, &1, should_act); + + // If we updated the coefficients this loop iter, we're done for this loop iter + done |= should_act; + } + } + } + + for _ in 0 .. num_bits { + // If the sum of coefficients is the amount of bits, we're done + let mut done = sum_of_coefficients.ct_eq(&num_bits); + + // Find the highest coefficient currently non-zero + for i in (1 .. decomposition.len()).rev() { + // If this is non-zero, we should decrement this coefficient if we haven't already + // decremented a coefficient this round + let is_non_zero = !(0.ct_eq(&decomposition[i])); + let should_act = (!done) & is_non_zero; + + // Update this coefficient and the prior coefficient + let amount_to_sub = <_>::conditional_select(&0, &1, should_act); + decomposition[i] -= amount_to_sub; + + let amount_to_add = <_>::conditional_select(&0, &2, should_act); + // i must be at least 1, so i - 1 will be at least 0 (meaning it's safe to index with) + decomposition[i - 1] += amount_to_add; + + // Also update the sum of coefficients + sum_of_coefficients += <_>::conditional_select(&0, &1, should_act); + + // If we updated the coefficients this loop iter, we're done for this loop iter + done |= should_act; + } + } + debug_assert!(bool::from(decomposition.iter().sum::().ct_eq(&num_bits))); + + ScalarDecomposition { scalar, decomposition } + } + + /// The decomposition of the scalar. + pub fn decomposition(&self) -> &[u64] { + &self.decomposition + } + + /// A divisor to prove a scalar multiplication. + /// + /// The divisor will interpolate $d_i$ instances of $2^i \cdot G$ with $-(s \cdot G)$. + /// + /// This function executes in constant time with regards to the scalar. + /// + /// This function MAY panic if this scalar is zero. + pub fn scalar_mul_divisor>( + &self, + mut generator: C, + ) -> Poly { + // The following for loop is constant time to the sum of `dlog`'s elements + let mut divisor_points = + Vec::with_capacity(usize::try_from(::NUM_BITS).unwrap()); + divisor_points.push(-generator * self.scalar); + for coefficient in &self.decomposition { + let mut coefficient = *coefficient; + while coefficient != 0 { + coefficient -= 1; + divisor_points.push(generator); + } + generator = generator.double(); + } + + let res = new_divisor(&divisor_points).unwrap(); + divisor_points.zeroize(); + res + } +} + #[cfg(any(test, feature = "pasta"))] mod pasta { use group::{ff::Field, Curve}; diff --git a/crypto/evrf/divisors/src/poly.rs b/crypto/evrf/divisors/src/poly.rs index 2c30cc5a..98654c1d 100644 --- a/crypto/evrf/divisors/src/poly.rs +++ b/crypto/evrf/divisors/src/poly.rs @@ -1,7 +1,7 @@ use core::ops::{Add, Neg, Sub, Mul, Rem}; use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConditionallySelectable}; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use group::ff::PrimeField; @@ -30,20 +30,20 @@ impl ConstantTimeGreater for CoefficientIndex { } } -/// A structure representing a Polynomial with x**i, y**i, and y**i * x**j terms. -#[derive(Clone, Debug, Zeroize)] -pub struct Poly + PrimeField> { - /// c[i] * y ** (i + 1) +/// A structure representing a Polynomial with x^i, y^i, and y^i * x^j terms. +#[derive(Clone, Debug, Zeroize, ZeroizeOnDrop)] +pub struct Poly + Zeroize + PrimeField> { + /// c\[i] * y^(i + 1) pub y_coefficients: Vec, - /// c[i][j] * y ** (i + 1) x ** (j + 1) + /// c\[i]\[j] * y^(i + 1) x^(j + 1) pub yx_coefficients: Vec>, - /// c[i] * x ** (i + 1) + /// c\[i] * x^(i + 1) pub x_coefficients: Vec, - /// Coefficient for x ** 0, y ** 0, and x ** 0 y ** 0 (the coefficient for 1) + /// Coefficient for x^0, y^0, and x^0 y^0 (the coefficient for 1) pub zero_coefficient: F, } -impl + PrimeField> PartialEq for Poly { +impl + Zeroize + PrimeField> PartialEq for Poly { fn eq(&self, b: &Poly) -> bool { { let mutual_y_coefficients = self.y_coefficients.len().min(b.y_coefficients.len()); @@ -103,9 +103,9 @@ impl + PrimeField> PartialEq for Poly { } } -impl + PrimeField> Poly { +impl + Zeroize + PrimeField> Poly { /// A polynomial for zero. - pub fn zero() -> Self { + pub(crate) fn zero() -> Self { Poly { y_coefficients: vec![], yx_coefficients: vec![], @@ -115,7 +115,7 @@ impl + PrimeField> Poly { } } -impl + PrimeField> Add<&Self> for Poly { +impl + Zeroize + PrimeField> Add<&Self> for Poly { type Output = Self; fn add(mut self, other: &Self) -> Self { @@ -153,7 +153,7 @@ impl + PrimeField> Add<&Self> for Poly { } } -impl + PrimeField> Neg for Poly { +impl + Zeroize + PrimeField> Neg for Poly { type Output = Self; fn neg(mut self) -> Self { @@ -174,7 +174,7 @@ impl + PrimeField> Neg for Poly { } } -impl + PrimeField> Sub for Poly { +impl + Zeroize + PrimeField> Sub for Poly { type Output = Self; fn sub(self, other: Self) -> Self { @@ -182,7 +182,7 @@ impl + PrimeField> Sub for Poly { } } -impl + PrimeField> Mul for Poly { +impl + Zeroize + PrimeField> Mul for Poly { type Output = Self; fn mul(mut self, scalar: F) -> Self { @@ -202,7 +202,7 @@ impl + PrimeField> Mul for Poly { } } -impl + PrimeField> Poly { +impl + Zeroize + PrimeField> Poly { #[must_use] fn shift_by_x(mut self, power_of_x: usize) -> Self { if power_of_x == 0 { @@ -256,14 +256,14 @@ impl + PrimeField> Poly { self.zero_coefficient = F::ZERO; // Move the x coefficients - self.yx_coefficients[power_of_y - 1] = self.x_coefficients; + std::mem::swap(&mut self.yx_coefficients[power_of_y - 1], &mut self.x_coefficients); self.x_coefficients = vec![]; self } } -impl + PrimeField> Mul<&Poly> for Poly { +impl + Zeroize + PrimeField> Mul<&Poly> for Poly { type Output = Self; fn mul(self, other: &Self) -> Self { @@ -290,7 +290,7 @@ impl + PrimeField> Mul<&Poly> for Poly { } } -impl + PrimeField> Poly { +impl + Zeroize + PrimeField> Poly { // The leading y coefficient and associated x coefficient. fn leading_coefficient(&self) -> (usize, usize) { if self.y_coefficients.len() > self.yx_coefficients.len() { @@ -355,7 +355,7 @@ impl + PrimeField> Poly { /// Perform multiplication mod `modulus`. #[must_use] - pub fn mul_mod(self, other: &Self, modulus: &Self) -> Self { + pub(crate) fn mul_mod(self, other: &Self, modulus: &Self) -> Self { (self * other) % modulus } @@ -366,10 +366,13 @@ impl + PrimeField> Poly { /// /// Panics upon division by a polynomial where all coefficients are zero. #[must_use] - pub fn div_rem(self, denominator: &Self) -> (Self, Self) { + pub(crate) fn div_rem(self, denominator: &Self) -> (Self, Self) { // These functions have undefined, unsafe behavior if this isn't a valid index #[allow(clippy::needless_lifetimes)] - fn ct_get<'a, F: From + PrimeField>(poly: &'a Poly, coeff: CoefficientIndex) -> &'a F { + fn ct_get<'a, F: From + Zeroize + PrimeField>( + poly: &'a Poly, + coeff: CoefficientIndex, + ) -> &'a F { let y_pow = isize::try_from(coeff.y_pow).unwrap(); let x_pow = isize::try_from(coeff.x_pow).unwrap(); @@ -415,14 +418,14 @@ impl + PrimeField> Poly { } #[allow(clippy::needless_lifetimes)] - fn ct_get_mut<'a, F: From + PrimeField>( + fn ct_get_mut<'a, F: From + Zeroize + PrimeField>( poly: &'a mut Poly, coeff: CoefficientIndex, ) -> &'a mut F { unsafe { (ct_get(poly, coeff) as *const F as *mut F).as_mut().unwrap() } } - fn structurally_eq + PrimeField>(a: &Poly, b: &Poly) -> bool { + fn structurally_eq + Zeroize + PrimeField>(a: &Poly, b: &Poly) -> bool { if a.y_coefficients.len() != b.y_coefficients.len() { return false; } @@ -440,7 +443,7 @@ impl + PrimeField> Poly { true } - fn conditional_select_poly + PrimeField>( + fn conditional_select_poly + Zeroize + PrimeField>( mut a: Poly, b: &Poly, choice: Choice, @@ -655,7 +658,7 @@ impl + PrimeField> Poly { } } -impl + PrimeField> Rem<&Self> for Poly { +impl + Zeroize + PrimeField> Rem<&Self> for Poly { type Output = Self; fn rem(self, modulus: &Self) -> Self { @@ -663,10 +666,10 @@ impl + PrimeField> Rem<&Self> for Poly { } } -impl + PrimeField> Poly { +impl + Zeroize + PrimeField> Poly { /// Evaluate this polynomial with the specified x/y values. /// - /// Panics on polynomials with terms whose powers exceed 2**64. + /// Panics on polynomials with terms whose powers exceed 2^64. #[must_use] pub fn eval(&self, x: F, y: F) -> F { let mut res = self.zero_coefficient; @@ -693,7 +696,7 @@ impl + PrimeField> Poly { res } - /// Differentiate a polynomial, reduced by a modulus with a leading y term y**2 x**0, by x and y. + /// Differentiate a polynomial, reduced by a modulus with a leading y term y^2 x^0, by x and y. /// /// This function has undefined behavior if unreduced. #[must_use]