ark_ff/fields/
sqrt.rs

1/// Indication of the field element's quadratic residuosity
2///
3/// # Examples
4/// ```
5/// # use ark_std::test_rng;
6/// # use ark_std::UniformRand;
7/// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp};
8/// let a: Fp = Fp::rand(&mut test_rng());
9/// let b = a.square();
10/// assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
11/// ```
12#[derive(Debug, PartialEq, Eq)]
13pub enum LegendreSymbol {
14    Zero = 0,
15    QuadraticResidue = 1,
16    QuadraticNonResidue = -1,
17}
18
19impl LegendreSymbol {
20    /// Returns true if `self.is_zero()`.
21    ///
22    /// # Examples
23    /// ```
24    /// # use ark_std::test_rng;
25    /// # use ark_std::UniformRand;
26    /// # use ark_test_curves::{LegendreSymbol, Field, bls12_381::Fq as Fp};
27    /// let a: Fp = Fp::rand(&mut test_rng());
28    /// let b: Fp = a.square();
29    /// assert!(!b.legendre().is_zero());
30    /// ```
31    pub fn is_zero(&self) -> bool {
32        *self == LegendreSymbol::Zero
33    }
34
35    /// Returns true if `self` is a quadratic non-residue.
36    ///
37    /// # Examples
38    /// ```
39    /// # use ark_test_curves::{Fp2Config, Field, LegendreSymbol, bls12_381::{Fq, Fq2Config}};
40    /// let a: Fq = Fq2Config::NONRESIDUE;
41    /// assert!(a.legendre().is_qnr());
42    /// ```
43    pub fn is_qnr(&self) -> bool {
44        *self == LegendreSymbol::QuadraticNonResidue
45    }
46
47    /// Returns true if `self` is a quadratic residue.
48    /// # Examples
49    /// ```
50    /// # use ark_std::test_rng;
51    /// # use ark_test_curves::bls12_381::Fq as Fp;
52    /// # use ark_std::UniformRand;
53    /// # use ark_ff::{LegendreSymbol, Field};
54    /// let a: Fp = Fp::rand(&mut test_rng());
55    /// let b: Fp = a.square();
56    /// assert!(b.legendre().is_qr());
57    /// ```
58    pub fn is_qr(&self) -> bool {
59        *self == LegendreSymbol::QuadraticResidue
60    }
61}
62
63/// Precomputation that makes computing square roots faster
64/// A particular variant should only be instantiated if the modulus satisfies
65/// the corresponding condition.
66#[non_exhaustive]
67pub enum SqrtPrecomputation<F: crate::Field> {
68    // Tonelli-Shanks algorithm works for all elements, no matter what the modulus is.
69    TonelliShanks {
70        two_adicity: u32,
71        quadratic_nonresidue_to_trace: F,
72        trace_of_modulus_minus_one_div_two: &'static [u64],
73    },
74    /// To be used when the modulus is 3 mod 4.
75    Case3Mod4 {
76        modulus_plus_one_div_four: &'static [u64],
77    },
78}
79
80impl<F: crate::Field> SqrtPrecomputation<F> {
81    pub fn sqrt(&self, elem: &F) -> Option<F> {
82        match self {
83            Self::TonelliShanks {
84                two_adicity,
85                quadratic_nonresidue_to_trace,
86                trace_of_modulus_minus_one_div_two,
87            } => {
88                // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
89                // Actually this is just normal Tonelli-Shanks; since `P::Generator`
90                // is a quadratic non-residue, `P::ROOT_OF_UNITY = P::GENERATOR ^ t`
91                // is also a quadratic non-residue (since `t` is odd).
92                if elem.is_zero() {
93                    return Some(F::zero());
94                }
95                // Try computing the square root (x at the end of the algorithm)
96                // Check at the end of the algorithm if x was a square root
97                // Begin Tonelli-Shanks
98                let mut z = *quadratic_nonresidue_to_trace;
99                let mut w = elem.pow(trace_of_modulus_minus_one_div_two);
100                let mut x = w * elem;
101                let mut b = x * &w;
102
103                let mut v = *two_adicity as usize;
104
105                while !b.is_one() {
106                    let mut k = 0usize;
107
108                    let mut b2k = b;
109                    while !b2k.is_one() {
110                        // invariant: b2k = b^(2^k) after entering this loop
111                        b2k.square_in_place();
112                        k += 1;
113                    }
114
115                    if k == (*two_adicity as usize) {
116                        // We are in the case where self^(T * 2^k) = x^(P::MODULUS - 1) = 1,
117                        // which means that no square root exists.
118                        return None;
119                    }
120                    let j = v - k;
121                    w = z;
122                    for _ in 1..j {
123                        w.square_in_place();
124                    }
125
126                    z = w.square();
127                    b *= &z;
128                    x *= &w;
129                    v = k;
130                }
131                // Is x the square root? If so, return it.
132                if x.square() == *elem {
133                    Some(x)
134                } else {
135                    // Consistency check that if no square root is found,
136                    // it is because none exists.
137                    debug_assert!(!matches!(elem.legendre(), LegendreSymbol::QuadraticResidue));
138                    None
139                }
140            },
141            Self::Case3Mod4 {
142                modulus_plus_one_div_four,
143            } => {
144                let result = elem.pow(modulus_plus_one_div_four.as_ref());
145                (result.square() == *elem).then_some(result)
146            },
147        }
148    }
149}