extern crate alloc;
use crate::{
circle::cosets::Coset,
field::{element::FieldElement, fields::mersenne31::field::Mersenne31Field},
};
use alloc::vec::Vec;
#[derive(PartialEq)]
pub enum TwiddlesConfig {
Evaluation,
Interpolation,
}
#[cfg(feature = "alloc")]
pub fn get_twiddles(
domain: Coset,
config: TwiddlesConfig,
) -> Vec<Vec<FieldElement<Mersenne31Field>>> {
let half_domain_points = Coset::get_coset_points(&Coset::half_coset(domain.clone()));
let mut twiddles: Vec<Vec<FieldElement<Mersenne31Field>>> = Vec::new();
twiddles.push(half_domain_points.iter().map(|p| p.y).collect());
if domain.log_2_size >= 2 {
twiddles.push(
half_domain_points
.iter()
.take(half_domain_points.len() / 2)
.map(|p| p.x)
.collect(),
);
for _ in 0..(domain.log_2_size - 2) {
let prev = twiddles.last().unwrap();
let cur = prev
.iter()
.take(prev.len() / 2)
.map(|x| x.square().double() - FieldElement::<Mersenne31Field>::one())
.collect();
twiddles.push(cur);
}
}
if config == TwiddlesConfig::Interpolation {
twiddles.iter_mut().for_each(|x| {
FieldElement::<Mersenne31Field>::inplace_batch_inverse(x).unwrap();
});
} else {
twiddles.reverse();
}
twiddles
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn evaluation_twiddles_vectors_length_is_correct() {
let domain = Coset::new_standard(20);
let config = TwiddlesConfig::Evaluation;
let twiddles = get_twiddles(domain, config);
for i in 0..twiddles.len() - 1 {
assert_eq!(2 * twiddles[i].len(), twiddles[i + 1].len())
}
}
#[test]
fn interpolation_twiddles_vectors_length_is_correct() {
let domain = Coset::new_standard(20);
let config = TwiddlesConfig::Interpolation;
let twiddles = get_twiddles(domain, config);
for i in 0..twiddles.len() - 1 {
assert_eq!(twiddles[i].len(), 2 * twiddles[i + 1].len())
}
}
}