pub trait CyclotomicMultSubgroup: crate::Field {
const INVERSE_IS_FAST: bool = false;
fn cyclotomic_square(&self) -> Self {
let mut result = *self;
*result.cyclotomic_square_in_place()
}
fn cyclotomic_square_in_place(&mut self) -> &mut Self {
self.square_in_place()
}
fn cyclotomic_inverse(&self) -> Option<Self> {
let mut result = *self;
result.cyclotomic_inverse_in_place().copied()
}
fn cyclotomic_inverse_in_place(&mut self) -> Option<&mut Self> {
self.inverse_in_place()
}
fn cyclotomic_exp(&self, e: impl AsRef<[u64]>) -> Self {
let mut result = *self;
result.cyclotomic_exp_in_place(e);
result
}
fn cyclotomic_exp_in_place(&mut self, e: impl AsRef<[u64]>) {
if self.is_zero() {
return;
}
if Self::INVERSE_IS_FAST {
let naf = crate::biginteger::arithmetic::find_naf(e.as_ref());
exp_loop(self, naf.into_iter().rev())
} else {
exp_loop(
self,
crate::bits::BitIteratorBE::without_leading_zeros(e.as_ref()).map(|e| e as i8),
)
};
}
}
fn exp_loop<F: CyclotomicMultSubgroup, I: Iterator<Item = i8>>(f: &mut F, e: I) {
let self_inverse = if F::INVERSE_IS_FAST {
f.cyclotomic_inverse().unwrap() } else {
F::one()
};
let mut res = F::one();
let mut found_nonzero = false;
for value in e {
if found_nonzero {
res.cyclotomic_square_in_place();
}
if value != 0 {
found_nonzero = true;
if value > 0 {
res *= &*f;
} else if F::INVERSE_IS_FAST {
res *= &self_inverse;
}
}
}
*f = res;
}