use num_bigint::BigUint;
use crate::{Field, TwoAdicField};
fn exp_biguint<F: Field>(base: F, exponent: &BigUint) -> F {
let mut product = F::ONE;
let mut current = base;
for j in 0..exponent.bits() {
if exponent.bit(j) {
product *= current;
}
current = current.square();
}
product
}
fn tonelli_shanks_inner<F: Field>(a: F, s: usize, q: &BigUint, mut c: F) -> Option<F> {
let u = exp_biguint(a, &((q - 1u32) >> 1));
let mut r = u * a;
let mut t = r * u;
let mut m = s;
while !t.is_one() {
let mut i = 0;
let mut t2i = t;
while !t2i.is_one() {
t2i = t2i.square();
i += 1;
if i == m {
return None;
}
}
let b = c.exp_power_of_2(m - i - 1);
m = i;
c = b.square();
t *= c;
r *= b;
}
Some(r)
}
pub fn tonelli_shanks<F: Field>(a: F) -> Option<F> {
if a.is_zero() {
return Some(F::ZERO);
}
let order_minus_one = F::order() - BigUint::from(1u8);
let s = order_minus_one
.trailing_zeros()
.expect("field order must be at least two") as usize;
let q = &order_minus_one >> s;
let c = exp_biguint(F::GENERATOR, &q);
tonelli_shanks_inner(a, s, &q, c)
}
pub fn tonelli_shanks_two_adic<F: TwoAdicField>(a: F) -> Option<F> {
if a.is_zero() {
return Some(F::ZERO);
}
let s = F::TWO_ADICITY;
let q = (F::order() - BigUint::from(1u8)) >> s;
let c = F::two_adic_generator(s);
tonelli_shanks_inner(a, s, &q, c)
}