use lazy_static::lazy_static;
use num_bigint::{BigUint, ToBigUint};
lazy_static! {
pub static ref TWO: BigUint = 2u32.to_biguint().unwrap();
}
pub fn ifft(arr: Vec<BigUint>, xs: Vec<BigUint>, p: &BigUint) -> Vec<BigUint> {
if arr.len() == 1 {
return arr;
}
let n = arr.len() / 2;
let mut res0 = Vec::with_capacity(n);
let mut res1 = Vec::with_capacity(n);
let mut new_xs = Vec::with_capacity(n);
for i in (0..2 * n).step_by(2) {
let a = &arr[i];
let b = &arr[i + 1];
let x = &xs[i];
res0.push(div_mod(a + b, TWO.clone(), p));
let diff = if b > a { p - (b - a) } else { a - b };
res1.push(div_mod(diff, TWO.clone() * x, p));
new_xs.push(x.modpow(&TWO.clone(), p));
}
let merged_res0 = ifft(res0, new_xs.clone(), p);
let merged_res1 = ifft(res1, new_xs, p);
let mut merged = Vec::with_capacity(arr.len());
for i in 0..n {
merged.push(merged_res0[i].clone());
merged.push(merged_res1[i].clone());
}
merged
}
pub fn div_mod(a: BigUint, b: BigUint, p: &BigUint) -> BigUint {
a * b.modpow(&(p - TWO.clone()), p) % p
}