/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ff-0.13.1/src/helpers.rs
Line | Count | Source |
1 | | //! Helper methods for implementing the `ff` traits. |
2 | | |
3 | | use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; |
4 | | |
5 | | use crate::PrimeField; |
6 | | |
7 | | /// Constant-time implementation of Tonelli–Shanks' square-root algorithm for |
8 | | /// `p mod 16 = 1`. |
9 | | /// |
10 | | /// `tm1d2` should be set to `(t - 1) // 2`, where `t = (modulus - 1) >> F::S`. |
11 | | /// |
12 | | /// ## Implementing [`Field::sqrt`] |
13 | | /// |
14 | | /// This function can be used to implement [`Field::sqrt`] for fields that both implement |
15 | | /// [`PrimeField`] and satisfy `p mod 16 = 1`. |
16 | | /// |
17 | | /// [`Field::sqrt`]: crate::Field::sqrt |
18 | | pub fn sqrt_tonelli_shanks<F: PrimeField, S: AsRef<[u64]>>(f: &F, tm1d2: S) -> CtOption<F> { |
19 | | // This is a constant-time version of https://eprint.iacr.org/2012/685.pdf (page 12, |
20 | | // algorithm 5). Steps 2-5 of the algorithm are omitted because they are only needed |
21 | | // to detect non-square input; it is more efficient to do that by checking at the end |
22 | | // whether the square of the result is the input. |
23 | | |
24 | | // w = self^((t - 1) // 2) |
25 | | let w = f.pow_vartime(tm1d2); |
26 | | |
27 | | let mut v = F::S; |
28 | | let mut x = w * f; |
29 | | let mut b = x * w; |
30 | | |
31 | | // Initialize z as the 2^S root of unity. |
32 | | let mut z = F::ROOT_OF_UNITY; |
33 | | |
34 | | for max_v in (1..=F::S).rev() { |
35 | | let mut k = 1; |
36 | | let mut b2k = b.square(); |
37 | | let mut j_less_than_v: Choice = 1.into(); |
38 | | |
39 | | // This loop has three phases based on the value of k for algorithm 5: |
40 | | // - for j <= k, we square b2k in order to calculate b^{2^k}. |
41 | | // - for k < j <= v, we square z in order to calculate ω. |
42 | | // - for j > v, we do nothing. |
43 | | for j in 2..max_v { |
44 | | let b2k_is_one = b2k.ct_eq(&F::ONE); |
45 | | let squared = F::conditional_select(&b2k, &z, b2k_is_one).square(); |
46 | | b2k = F::conditional_select(&squared, &b2k, b2k_is_one); |
47 | | let new_z = F::conditional_select(&z, &squared, b2k_is_one); |
48 | | j_less_than_v &= !j.ct_eq(&v); |
49 | | k = u32::conditional_select(&j, &k, b2k_is_one); |
50 | | z = F::conditional_select(&z, &new_z, j_less_than_v); |
51 | | } |
52 | | |
53 | | let result = x * z; |
54 | | x = F::conditional_select(&result, &x, b.ct_eq(&F::ONE)); |
55 | | z = z.square(); |
56 | | b *= z; |
57 | | v = k; |
58 | | } |
59 | | |
60 | | CtOption::new( |
61 | | x, |
62 | | (x * x).ct_eq(f), // Only return Some if it's the square root. |
63 | | ) |
64 | | } |
65 | | |
66 | | /// Computes: |
67 | | /// |
68 | | /// - $(\textsf{true}, \sqrt{\textsf{num}/\textsf{div}})$, if $\textsf{num}$ and |
69 | | /// $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is a square in the |
70 | | /// field; |
71 | | /// - $(\textsf{true}, 0)$, if $\textsf{num}$ is zero; |
72 | | /// - $(\textsf{false}, 0)$, if $\textsf{num}$ is nonzero and $\textsf{div}$ is zero; |
73 | | /// - $(\textsf{false}, \sqrt{G_S \cdot \textsf{num}/\textsf{div}})$, if |
74 | | /// $\textsf{num}$ and $\textsf{div}$ are nonzero and $\textsf{num}/\textsf{div}$ is |
75 | | /// a nonsquare in the field; |
76 | | /// |
77 | | /// where $G_S$ is a non-square. |
78 | | /// |
79 | | /// For this method, $G_S$ is currently [`PrimeField::ROOT_OF_UNITY`], a generator of the |
80 | | /// order $2^S$ subgroup. Users of this crate should not rely on this generator being |
81 | | /// fixed; it may be changed in future crate versions to simplify the implementation of |
82 | | /// the SSWU hash-to-curve algorithm. |
83 | | /// |
84 | | /// The choice of root from sqrt is unspecified. |
85 | | /// |
86 | | /// ## Implementing [`Field::sqrt_ratio`] |
87 | | /// |
88 | | /// This function can be used to implement [`Field::sqrt_ratio`] for fields that also |
89 | | /// implement [`PrimeField`]. If doing so, the default implementation of [`Field::sqrt`] |
90 | | /// *MUST* be overridden, or else both functions will recurse in a cycle until a stack |
91 | | /// overflow occurs. |
92 | | /// |
93 | | /// [`Field::sqrt_ratio`]: crate::Field::sqrt_ratio |
94 | | /// [`Field::sqrt`]: crate::Field::sqrt |
95 | 0 | pub fn sqrt_ratio_generic<F: PrimeField>(num: &F, div: &F) -> (Choice, F) { |
96 | | // General implementation: |
97 | | // |
98 | | // a = num * inv0(div) |
99 | | // = { 0 if div is zero |
100 | | // { num/div otherwise |
101 | | // |
102 | | // b = G_S * a |
103 | | // = { 0 if div is zero |
104 | | // { G_S*num/div otherwise |
105 | | // |
106 | | // Since G_S is non-square, a and b are either both zero (and both square), or |
107 | | // only one of them is square. We can therefore choose the square root to return |
108 | | // based on whether a is square, but for the boolean output we need to handle the |
109 | | // num != 0 && div == 0 case specifically. |
110 | | |
111 | 0 | let a = div.invert().unwrap_or(F::ZERO) * num; |
112 | 0 | let b = a * F::ROOT_OF_UNITY; |
113 | 0 | let sqrt_a = a.sqrt(); |
114 | 0 | let sqrt_b = b.sqrt(); |
115 | | |
116 | 0 | let num_is_zero = num.is_zero(); |
117 | 0 | let div_is_zero = div.is_zero(); |
118 | 0 | let is_square = sqrt_a.is_some(); |
119 | 0 | let is_nonsquare = sqrt_b.is_some(); |
120 | 0 | assert!(bool::from( |
121 | 0 | num_is_zero | div_is_zero | (is_square ^ is_nonsquare) |
122 | 0 | )); |
123 | | |
124 | 0 | ( |
125 | 0 | is_square & (num_is_zero | !div_is_zero), |
126 | 0 | CtOption::conditional_select(&sqrt_b, &sqrt_a, is_square).unwrap(), |
127 | 0 | ) |
128 | 0 | } Unexecuted instantiation: ff::helpers::sqrt_ratio_generic::<p256::arithmetic::field::FieldElement> Unexecuted instantiation: ff::helpers::sqrt_ratio_generic::<p256::arithmetic::scalar::Scalar> |