129 lines
4.7 KiB
Rust
129 lines
4.7 KiB
Rust
//! 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: PrimeField, S: AsRef<[u64]>>(f: &F, tm1d2: S) -> CtOption<F> {
|
||
// 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<F: PrimeField>(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(),
|
||
)
|
||
}
|