#[derive(Debug, PartialEq, Eq)]
pub enum LegendreSymbol {
Zero = 0,
QuadraticResidue = 1,
QuadraticNonResidue = -1,
}
impl LegendreSymbol {
pub fn is_zero(&self) -> bool {
*self == LegendreSymbol::Zero
}
pub fn is_qnr(&self) -> bool {
*self == LegendreSymbol::QuadraticNonResidue
}
pub fn is_qr(&self) -> bool {
*self == LegendreSymbol::QuadraticResidue
}
}
#[non_exhaustive]
pub enum SqrtPrecomputation<F: crate::Field> {
TonelliShanks {
two_adicity: u32,
quadratic_nonresidue_to_trace: F,
trace_of_modulus_minus_one_div_two: &'static [u64],
},
Case3Mod4 {
modulus_plus_one_div_four: &'static [u64],
},
}
impl<F: crate::Field> SqrtPrecomputation<F> {
pub fn sqrt(&self, elem: &F) -> Option<F> {
match self {
Self::TonelliShanks {
two_adicity,
quadratic_nonresidue_to_trace,
trace_of_modulus_minus_one_div_two,
} => {
if elem.is_zero() {
return Some(F::zero());
}
let mut z = *quadratic_nonresidue_to_trace;
let mut w = elem.pow(trace_of_modulus_minus_one_div_two);
let mut x = w * elem;
let mut b = x * &w;
let mut v = *two_adicity as usize;
while !b.is_one() {
let mut k = 0usize;
let mut b2k = b;
while !b2k.is_one() {
b2k.square_in_place();
k += 1;
}
if k == (*two_adicity as usize) {
return None;
}
let j = v - k;
w = z;
for _ in 1..j {
w.square_in_place();
}
z = w.square();
b *= &z;
x *= &w;
v = k;
}
if x.square() == *elem {
Some(x)
} else {
debug_assert!(!matches!(elem.legendre(), LegendreSymbol::QuadraticResidue));
None
}
},
Self::Case3Mod4 {
modulus_plus_one_div_four,
} => {
let result = elem.pow(modulus_plus_one_div_four.as_ref());
(result.square() == *elem).then_some(result)
},
}
}
}