diff --git a/CHANGELOG.md b/CHANGELOG.md index f890811..a561cc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Migrated to `ff 0.13`, `group 0.13`. + +### Removed +- `pasta_curves::arithmetic::SqrtRatio` (use `ff::Field::{sqrt_ratio, sqrt_alt}` + instead). +- `pasta_curves::arithmetic::SqrtTables` (from public API, as it isn't suitable + for generic usage). ## [0.4.1] - 2022-10-13 ### Added diff --git a/Cargo.toml b/Cargo.toml index 5d40b4c..23f20ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,3 +72,6 @@ sqrt-table = ["alloc", "lazy_static"] repr-c = [] uninline-portable = [] serde = ["hex", "serde_crate"] + +[patch.crates-io] +ff = { git = "https://github.com/zkcrypto/ff.git", rev = "9a844a72d30ea9f859cd46dcc2237a1ae3277ddc" } diff --git a/src/arithmetic/fields.rs b/src/arithmetic/fields.rs index 3cf2e9e..db16715 100644 --- a/src/arithmetic/fields.rs +++ b/src/arithmetic/fields.rs @@ -4,99 +4,35 @@ use core::mem::size_of; use static_assertions::const_assert; -use subtle::{Choice, ConditionallySelectable, CtOption}; use super::Group; -use core::assert; - #[cfg(feature = "sqrt-table")] use alloc::{boxed::Box, vec::Vec}; #[cfg(feature = "sqrt-table")] use core::marker::PhantomData; +#[cfg(feature = "sqrt-table")] +use subtle::Choice; + const_assert!(size_of::() >= 4); -/// A trait that exposes additional operations related to calculating square roots of +/// An internal trait that exposes additional operations related to calculating square roots of /// prime-order finite fields. -pub trait SqrtRatio: ff::PrimeField { - /// The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd. - const T_MINUS1_OVER2: [u64; 4]; - - /// Raise this field element to the power [`Self::T_MINUS1_OVER2`]. +pub(crate) trait SqrtTableHelpers: ff::PrimeField { + /// Raise this field element to the power $(t-1)/2$. /// /// Field implementations may override this to use an efficient addition chain. - fn pow_by_t_minus1_over2(&self) -> Self { - ff::Field::pow_vartime(self, &Self::T_MINUS1_OVER2) - } + fn pow_by_t_minus1_over2(&self) -> Self; /// Gets the lower 32 bits of this field element when expressed /// canonically. fn get_lower_32(&self) -> u32; - - /// Computes: - /// - /// - $(\textsf{true}, \sqrt{\textsf{num}/\textsf{div}})$, if $\textsf{num}$ and - /// $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is a square in the - /// field; - /// - $(\textsf{true}, 0)$, if $\textsf{num}$ is zero; - /// - $(\textsf{false}, 0)$, if $\textsf{num}$ is nonzero and $\textsf{div}$ is zero; - /// - $(\textsf{false}, \sqrt{G_S \cdot \textsf{num}/\textsf{div}})$, if - /// $\textsf{num}$ and $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is - /// a nonsquare in the field; - /// - /// where $G_S$ is a non-square. - /// - /// For `pasta_curves`, $G_S$ is currently [`ff::PrimeField::root_of_unity`], a - /// generator of the order $2^S$ subgroup. Users of this crate should not rely on this - /// generator being fixed; it may be changed in future crate versions to simplify the - /// implementation of the SSWU hash-to-curve algorithm. - /// - /// The choice of root from sqrt is unspecified. - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - // General implementation: - // - // a = num * inv0(div) - // = { 0 if div is zero - // { num/div otherwise - // - // b = G_S * a - // = { 0 if div is zero - // { G_S*num/div otherwise - // - // Since G_S is non-square, a and b are either both zero (and both square), or - // only one of them is square. We can therefore choose the square root to return - // based on whether a is square, but for the boolean output we need to handle the - // num != 0 && div == 0 case specifically. - - let a = div.invert().unwrap_or_else(Self::zero) * num; - let b = a * Self::root_of_unity(); - let sqrt_a = a.sqrt(); - let sqrt_b = b.sqrt(); - - let num_is_zero = num.is_zero(); - let div_is_zero = div.is_zero(); - let is_square = sqrt_a.is_some(); - let is_nonsquare = sqrt_b.is_some(); - assert!(bool::from( - num_is_zero | div_is_zero | (is_square ^ is_nonsquare) - )); - - ( - is_square & !(!num_is_zero & div_is_zero), - CtOption::conditional_select(&sqrt_b, &sqrt_a, is_square).unwrap(), - ) - } - - /// Equivalent to `Self::sqrt_ratio(self, one())`. - fn sqrt_alt(&self) -> (Choice, Self) { - Self::sqrt_ratio(self, &Self::one()) - } } /// This trait is a common interface for dealing with elements of a finite /// field. -pub trait FieldExt: SqrtRatio + From + Ord + Group { +pub trait FieldExt: ff::PrimeField + From + Ord + Group { /// Modulus of the field written as a string for display purposes const MODULUS: &'static str; @@ -119,77 +55,11 @@ pub trait FieldExt: SqrtRatio + From + Ord + Group { /// byte representation of an integer. fn from_bytes_wide(bytes: &[u8; 64]) -> Self; - /// Exponentiates `self` by `by`, where `by` is a little-endian order - /// integer exponent. - fn pow(&self, by: &[u64; 4]) -> Self { - let mut res = Self::one(); - for e in by.iter().rev() { - for i in (0..64).rev() { - res = res.square(); - let mut tmp = res; - tmp *= self; - res.conditional_assign(&tmp, (((*e >> i) & 0x1) as u8).into()); - } - } - res - } - /// Gets the lower 128 bits of this field element when expressed /// canonically. fn get_lower_128(&self) -> u128; } -/// Tonelli–Shanks' square-root algorithm for `p mod 16 = 1`. -/// -/// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) -/// -/// `tm1d2` should be set to `(t - 1) // 2`, where `t = (modulus - 1) >> F::S`. -#[cfg(not(feature = "sqrt-table"))] -#[cfg_attr(docsrs, doc(cfg(not(feature = "sqrt-table"))))] -pub(crate) fn sqrt_tonelli_shanks>( - f: &F, - tm1d2: S, -) -> CtOption { - use subtle::ConstantTimeEq; - - // w = self^((t - 1) // 2) - let w = f.pow_vartime(tm1d2); - - let mut v = F::S; - let mut x = w * f; - let mut b = x * w; - - // Initialize z as the 2^S root of unity. - let mut z = F::root_of_unity(); - - for max_v in (1..=F::S).rev() { - let mut k = 1; - let mut tmp = b.square(); - let mut j_less_than_v: Choice = 1.into(); - - for j in 2..max_v { - let tmp_is_one = tmp.ct_eq(&F::one()); - let squared = F::conditional_select(&tmp, &z, tmp_is_one).square(); - tmp = F::conditional_select(&squared, &tmp, tmp_is_one); - let new_z = F::conditional_select(&z, &squared, tmp_is_one); - j_less_than_v &= !j.ct_eq(&v); - k = u32::conditional_select(&j, &k, tmp_is_one); - z = F::conditional_select(&z, &new_z, j_less_than_v); - } - - let result = x * z; - x = F::conditional_select(&result, &x, b.ct_eq(&F::one())); - z = z.square(); - b *= z; - v = k; - } - - CtOption::new( - x, - (x * x).ct_eq(f), // Only return Some if it's the square root. - ) -} - /// Parameters for a perfect hash function used in square root computation. #[cfg(feature = "sqrt-table")] #[cfg_attr(docsrs, doc(cfg(feature = "sqrt-table")))] @@ -201,7 +71,7 @@ struct SqrtHasher { } #[cfg(feature = "sqrt-table")] -impl SqrtHasher { +impl SqrtHasher { /// Returns a perfect hash of x for use with SqrtTables::inv. fn hash(&self, x: &F) -> usize { // This is just the simplest constant-time perfect hash construction that could @@ -216,7 +86,7 @@ impl SqrtHasher { #[cfg(feature = "sqrt-table")] #[cfg_attr(docsrs, doc(cfg(feature = "sqrt-table")))] #[derive(Debug)] -pub struct SqrtTables { +pub(crate) struct SqrtTables { hasher: SqrtHasher, inv: Vec, g0: Box<[F; 256]>, @@ -226,7 +96,7 @@ pub struct SqrtTables { } #[cfg(feature = "sqrt-table")] -impl SqrtTables { +impl SqrtTables { /// Build tables given parameters for the perfect hash. pub fn new(hash_xor: u32, hash_mod: usize) -> Self { use alloc::vec; diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 08687fd..c315111 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -11,7 +11,7 @@ use lazy_static::lazy_static; #[cfg(feature = "bits")] use ff::{FieldBits, PrimeFieldBits}; -use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtRatio}; +use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtTableHelpers}; #[cfg(feature = "sqrt-table")] use crate::arithmetic::SqrtTables; @@ -232,6 +232,7 @@ const DELTA: Fp = Fp::from_raw([ ]); /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. +#[cfg(any(test, not(feature = "sqrt-table")))] const T_MINUS1_OVER2: [u64; 4] = [ 0x04a6_7c8d_cc96_9876, 0x0000_0000_1123_4c7e, @@ -510,6 +511,21 @@ impl ff::Field for Fp { self.square() } + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + #[cfg(feature = "sqrt-table")] + { + FP_TABLES.sqrt_ratio(num, div) + } + + #[cfg(not(feature = "sqrt-table"))] + ff::helpers::sqrt_ratio_generic(num, div) + } + + #[cfg(feature = "sqrt-table")] + fn sqrt_alt(&self) -> (Choice, Self) { + FP_TABLES.sqrt_alt(self) + } + /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { #[cfg(feature = "sqrt-table")] @@ -519,7 +535,7 @@ impl ff::Field for Fp { } #[cfg(not(feature = "sqrt-table"))] - crate::arithmetic::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2) + ff::helpers::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2) } /// Computes the multiplicative inverse of this element, @@ -669,9 +685,7 @@ lazy_static! { static ref FP_TABLES: SqrtTables = SqrtTables::new(0x11BE, 1098); } -impl SqrtRatio for Fp { - const T_MINUS1_OVER2: [u64; 4] = T_MINUS1_OVER2; - +impl SqrtTableHelpers for Fp { fn pow_by_t_minus1_over2(&self) -> Self { let sqr = |x: Fp, i: u32| (0..i).fold(x, |x, _| x.square()); @@ -709,16 +723,6 @@ impl SqrtRatio for Fp { tmp.0[0] as u32 } - - #[cfg(feature = "sqrt-table")] - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - FP_TABLES.sqrt_ratio(num, div) - } - - #[cfg(feature = "sqrt-table")] - fn sqrt_alt(&self) -> (Choice, Self) { - FP_TABLES.sqrt_alt(self) - } } impl FieldExt for Fp { diff --git a/src/fields/fq.rs b/src/fields/fq.rs index f22f61b..3d3d8c7 100644 --- a/src/fields/fq.rs +++ b/src/fields/fq.rs @@ -11,7 +11,7 @@ use lazy_static::lazy_static; #[cfg(feature = "bits")] use ff::{FieldBits, PrimeFieldBits}; -use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtRatio}; +use crate::arithmetic::{adc, mac, sbb, FieldExt, Group, SqrtTableHelpers}; #[cfg(feature = "sqrt-table")] use crate::arithmetic::SqrtTables; @@ -232,6 +232,7 @@ const DELTA: Fq = Fq::from_raw([ ]); /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. +#[cfg(any(test, not(feature = "sqrt-table")))] const T_MINUS1_OVER2: [u64; 4] = [ 0x04ca_546e_c623_7590, 0x0000_0000_1123_4c7e, @@ -510,6 +511,21 @@ impl ff::Field for Fq { self.square() } + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + #[cfg(feature = "sqrt-table")] + { + FQ_TABLES.sqrt_ratio(num, div) + } + + #[cfg(not(feature = "sqrt-table"))] + ff::helpers::sqrt_ratio_generic(num, div) + } + + #[cfg(feature = "sqrt-table")] + fn sqrt_alt(&self) -> (Choice, Self) { + FQ_TABLES.sqrt_alt(self) + } + /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { #[cfg(feature = "sqrt-table")] @@ -519,7 +535,7 @@ impl ff::Field for Fq { } #[cfg(not(feature = "sqrt-table"))] - crate::arithmetic::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2) + ff::helpers::sqrt_tonelli_shanks(self, &T_MINUS1_OVER2) } /// Computes the multiplicative inverse of this element, @@ -668,9 +684,7 @@ lazy_static! { static ref FQ_TABLES: SqrtTables = SqrtTables::new(0x116A9E, 1206); } -impl SqrtRatio for Fq { - const T_MINUS1_OVER2: [u64; 4] = T_MINUS1_OVER2; - +impl SqrtTableHelpers for Fq { fn pow_by_t_minus1_over2(&self) -> Self { let sqr = |x: Fq, i: u32| (0..i).fold(x, |x, _| x.square()); @@ -708,16 +722,6 @@ impl SqrtRatio for Fq { tmp.0[0] as u32 } - - #[cfg(feature = "sqrt-table")] - fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { - FQ_TABLES.sqrt_ratio(num, div) - } - - #[cfg(feature = "sqrt-table")] - fn sqrt_alt(&self) -> (Choice, Self) { - FQ_TABLES.sqrt_alt(self) - } } impl FieldExt for Fq {