use super::element::Zp;
mod algorithms;
mod arithmetic;
mod display;
#[cfg(test)]
mod tests;
#[derive(Clone, PartialEq, Eq)]
pub struct PolyZp {
coeffs: Vec<u64>,
modulus: u64,
}
impl PolyZp {
#[inline]
pub fn from_coeffs(mut coeffs: Vec<u64>, modulus: u64) -> Self {
for c in coeffs.iter_mut() {
*c %= modulus;
}
while coeffs.last() == Some(&0) {
coeffs.pop();
}
Self { coeffs, modulus }
}
pub fn from_signed_coeffs(coeffs: &[i64], modulus: u64) -> Self {
let m = modulus as i64;
let normalized: Vec<u64> = coeffs.iter().map(|&c| (((c % m) + m) % m) as u64).collect();
Self::from_coeffs(normalized, modulus)
}
#[inline]
pub fn zero(modulus: u64) -> Self {
Self {
coeffs: Vec::new(),
modulus,
}
}
#[inline]
pub fn constant(c: u64, modulus: u64) -> Self {
if c.is_multiple_of(modulus) {
Self::zero(modulus)
} else {
Self {
coeffs: vec![c % modulus],
modulus,
}
}
}
#[inline]
pub fn x(modulus: u64) -> Self {
Self {
coeffs: vec![0, 1],
modulus,
}
}
#[inline]
pub fn x_minus_a(a: u64, modulus: u64) -> Self {
let neg_a = if a.is_multiple_of(modulus) {
0
} else {
modulus - (a % modulus)
};
Self {
coeffs: vec![neg_a, 1],
modulus,
}
}
#[inline]
pub fn is_zero(&self) -> bool {
self.coeffs.is_empty()
}
#[inline]
pub fn is_constant(&self) -> bool {
self.coeffs.len() <= 1
}
#[inline]
pub fn degree(&self) -> Option<usize> {
if self.coeffs.is_empty() {
None
} else {
Some(self.coeffs.len() - 1)
}
}
#[inline]
pub fn leading_coeff(&self) -> Option<Zp> {
self.coeffs.last().map(|&c| Zp::new(c, self.modulus))
}
#[inline]
pub fn coeff(&self, i: usize) -> Zp {
let value = self.coeffs.get(i).copied().unwrap_or(0);
Zp::new(value, self.modulus)
}
#[inline]
pub fn modulus(&self) -> u64 {
self.modulus
}
#[inline]
pub fn coefficients(&self) -> &[u64] {
&self.coeffs
}
}