//! Helper methods for implementing the `ff` traits. use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use crate::PrimeField; /// Constant-time implementation of Tonelli–Shanks' square-root algorithm for /// `p mod 16 = 1`. /// /// `tm1d2` should be set to `(t - 1) // 2`, where `t = (modulus - 1) >> F::S`. /// /// ## Implementing [`Field::sqrt`] /// /// This function can be used to implement [`Field::sqrt`] for fields that both implement /// [`PrimeField`] and satisfy `p mod 16 = 1`. /// /// [`Field::sqrt`]: crate::Field::sqrt pub fn sqrt_tonelli_shanks>(f: &F, tm1d2: S) -> CtOption { // This is a constant-time version of https://eprint.iacr.org/2012/685.pdf (page 12, // algorithm 5). Steps 2-5 of the algorithm are omitted because they are only needed // to detect non-square input; it is more efficient to do that by checking at the end // whether the square of the result is the input. // 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 b2k = b.square(); let mut j_less_than_v: Choice = 1.into(); // This loop has three phases based on the value of k for algorithm 5: // - for j <= k, we square b2k in order to calculate b^{2^k}. // - for k < j <= v, we square z in order to calculate ω. // - for j > v, we do nothing. for j in 2..max_v { let b2k_is_one = b2k.ct_eq(&F::ONE); let squared = F::conditional_select(&b2k, &z, b2k_is_one).square(); b2k = F::conditional_select(&squared, &b2k, b2k_is_one); let new_z = F::conditional_select(&z, &squared, b2k_is_one); j_less_than_v &= !j.ct_eq(&v); k = u32::conditional_select(&j, &k, b2k_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. ) } /// 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 this method, $G_S$ is currently [`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. /// /// ## Implementing [`Field::sqrt_ratio`] /// /// This function can be used to implement [`Field::sqrt_ratio`] for fields that also /// implement [`PrimeField`]. If doing so, the default implementation of [`Field::sqrt`] /// *MUST* be overridden, or else both functions will recurse in a cycle until a stack /// overflow occurs. /// /// [`Field::sqrt_ratio`]: crate::Field::sqrt_ratio /// [`Field::sqrt`]: crate::Field::sqrt pub fn sqrt_ratio_generic(num: &F, div: &F) -> (Choice, F) { // 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(F::ZERO) * num; let b = a * F::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(), ) }