use crate::field::{EPSILON, Goldilocks, P};
const HALF_P: u64 = (P - 1) / 2;
pub fn legendre(a: Goldilocks) -> Goldilocks {
a.exp(HALF_P)
}
pub fn sqrt(n: Goldilocks) -> Option<Goldilocks> {
if n.is_zero() {
return Some(Goldilocks::ZERO);
}
let leg = legendre(n);
if leg == Goldilocks::NEG_ONE {
return None;
}
let s: u64 = EPSILON;
let mut big_m: u32 = 32; let mut c = Goldilocks::new(7).exp(s); let mut t = n.exp(s); let mut r = n.exp(s.div_ceil(2));
loop {
if t == Goldilocks::ONE {
if r.as_u64() > HALF_P {
r = -r;
}
return Some(r);
}
let mut i: u32 = 1;
let mut tmp = t.square();
while tmp != Goldilocks::ONE {
tmp = tmp.square();
i += 1;
}
let mut b = c;
for _ in 0..(big_m - i - 1) {
b = b.square();
}
big_m = i;
c = b.square();
t *= c;
r *= b;
}
}