use air::Air;
use math::{fft, get_power_series, log2, StarkField};
use utils::collections::Vec;
pub struct StarkDomain<B: StarkField> {
trace_twiddles: Vec<B>,
ce_domain: Vec<B>,
ce_to_lde_blowup: usize,
ce_domain_mod_mask: usize,
domain_offset: B,
}
impl<B: StarkField> StarkDomain<B> {
pub fn new<A: Air<BaseField = B>>(air: &A) -> Self {
let trace_twiddles = fft::get_twiddles(air.trace_length());
let domain_gen = B::get_root_of_unity(log2(air.ce_domain_size()));
let ce_domain = get_power_series(domain_gen, air.ce_domain_size());
StarkDomain {
trace_twiddles,
ce_domain,
ce_to_lde_blowup: air.lde_domain_size() / air.ce_domain_size(),
ce_domain_mod_mask: air.ce_domain_size() - 1,
domain_offset: air.domain_offset(),
}
}
pub fn trace_length(&self) -> usize {
&self.trace_twiddles.len() * 2
}
pub fn trace_twiddles(&self) -> &[B] {
&self.trace_twiddles
}
pub fn trace_to_ce_blowup(&self) -> usize {
self.ce_domain_size() / self.trace_length()
}
pub fn trace_to_lde_blowup(&self) -> usize {
self.lde_domain_size() / self.trace_length()
}
#[inline(always)]
pub fn ce_domain_size(&self) -> usize {
self.ce_domain.len()
}
pub fn ce_domain_generator(&self) -> B {
B::get_root_of_unity(log2(self.ce_domain_size()))
}
pub fn ce_to_lde_blowup(&self) -> usize {
self.ce_to_lde_blowup
}
#[inline(always)]
pub fn get_ce_x_at(&self, step: usize) -> B {
self.ce_domain[step] * self.domain_offset
}
#[inline(always)]
pub fn get_ce_x_power_at(&self, step: usize, power: u64, offset_exp: B) -> B {
debug_assert_eq!(offset_exp, self.offset().exp(power.into()));
let index = step.wrapping_mul(power as usize) & self.ce_domain_mod_mask;
self.ce_domain[index] * offset_exp
}
pub fn lde_domain_size(&self) -> usize {
self.ce_domain_size() * self.ce_to_lde_blowup()
}
pub fn offset(&self) -> B {
self.domain_offset
}
}