This commit is contained in:
Pascal Engélibert 2026-02-20 16:02:58 +01:00
commit 610cc4784a
5 changed files with 39 additions and 310 deletions

View file

@ -8,6 +8,8 @@
#![allow(clippy::tabs_in_doc_comments)]
//! Modular and polynomial arithmetic.
//!
//! See the examples in the repo.
pub mod matrix;
pub mod ntt;

View file

@ -1,232 +0,0 @@
crate::ring!(Z7681, u16, u32, i32, 7681);
/// Element of (Z/2Z)[x]/(x^N+1)
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct R7681<const N: usize>(pub [Z7681; N]);
impl<const N: usize> crate::poly::Poly<u16, N> for R7681<N> {
type Element = Z7681;
fn modulus() -> u16 {
7681
}
fn new(v: [Z7681; N]) -> Self {
Self(v)
}
}
impl<const N: usize> R7681<N> {
pub const fn one() -> Self {
let mut x = Self([Z7681(0); N]);
x.0[0].0 = 1;
x
}
pub fn is_one(&self) -> bool {
self.0[0].0 == 1 && self.0.iter().skip(1).all(|x| x.0 == 0)
}
pub const fn zetas() -> [u16; N] {
let mut zetas = [0; N];
let mut i: usize = 1;
let mut z = 62;
while i < N {
zetas[crate::poly::bitrev(i, N)] = z;
z = (z as u32 * 62 % 7681) as u16;
i += 1;
}
zetas
}
}
impl<const N: usize> std::ops::Add for R7681<N> {
type Output = Self;
fn add(mut self, rhs: Self) -> Self {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x += *y);
self
}
}
impl<const N: usize> std::ops::Add<&Self> for R7681<N> {
type Output = Self;
fn add(mut self, rhs: &Self) -> Self {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x += *y);
self
}
}
impl<const N: usize> std::ops::AddAssign for R7681<N> {
fn add_assign(&mut self, rhs: Self) {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x += *y);
}
}
impl<const N: usize> std::ops::AddAssign<&Self> for R7681<N> {
fn add_assign(&mut self, rhs: &Self) {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x += *y);
}
}
impl<const N: usize> std::ops::Sub for R7681<N> {
type Output = Self;
fn sub(mut self, rhs: Self) -> Self {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x -= *y);
self
}
}
impl<const N: usize> std::ops::Sub<&Self> for R7681<N> {
type Output = Self;
fn sub(mut self, rhs: &Self) -> Self {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x -= *y);
self
}
}
impl<const N: usize> std::ops::SubAssign for R7681<N> {
fn sub_assign(&mut self, rhs: Self) {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x -= *y);
}
}
impl<const N: usize> std::ops::SubAssign<&Self> for R7681<N> {
fn sub_assign(&mut self, rhs: &Self) {
self.0
.iter_mut()
.zip(rhs.0.iter())
.for_each(|(x, y)| *x -= *y);
}
}
impl<const N: usize> num_traits::Zero for R7681<N> {
fn zero() -> Self {
Self([Z7681(0); N])
}
fn is_zero(&self) -> bool {
self.0.iter().all(num_traits::Zero::is_zero)
}
}
/*impl num_traits::One for R7681<N> {
fn one() -> Self {
let mut x = Self([$Zq(0); $N]);
x.0[0].0 = 1;
x
}
fn is_one(&self) -> bool {
self.0[0].0 == 1 && self.0.iter().skip(1).all(|x| x.0 == 0)
}
}*/
impl<const N: usize> crate::ntt::Ntt for R7681<N> {
type Output = crate::ntt::NttDomain<R7681<N>>;
fn ntt(mut self) -> crate::ntt::NttDomain<R7681<N>> {
let mut m = 0;
let mut len = N / 2;
while len >= 1 {
for start in (0..N).step_by(2 * len) {
m += 1;
let z = Z7681(R7681::<N>::zetas()[m]);
for j in start..start + len {
let t = z * self.0[j + len];
self.0[j + len] = self.0[j] - t;
self.0[j] += t;
}
}
len /= 2;
}
crate::ntt::NttDomain(self)
}
}
impl<const N: usize> crate::ntt::NttInv for crate::ntt::NttDomain<R7681<N>> {
type Output = R7681<N>;
fn ntt_inv(mut self) -> R7681<N> {
let mut m = N;
let mut len = 1;
while len < N {
for start in (0..N).step_by(2 * len) {
m -= 1;
let z = Z7681(7681 - R7681::<N>::zetas()[m]);
for j in start..start + len {
let t = self.0.0[j];
self.0.0[j] += self.0.0[j + len];
self.0.0[j + len] = z * (t - self.0.0[j + len]);
}
}
len *= 2;
}
self.0.0.iter_mut().for_each(|wj| *wj *= Z7681(N as u16).inverse());
self.0
}
}
impl<const N: usize> std::ops::Mul for crate::ntt::NttDomain<R7681<N>> {
type Output = Self;
fn mul(mut self, rhs: Self) -> Self {
self.0
.0
.iter_mut()
.zip(rhs.0.0.iter())
.for_each(|(x, y)| *x *= *y);
self
}
}
impl<const N: usize> std::ops::Mul<&Self> for crate::ntt::NttDomain<R7681<N>> {
type Output = Self;
fn mul(mut self, rhs: &Self) -> Self {
self.0
.0
.iter_mut()
.zip(rhs.0.0.iter())
.for_each(|(x, y)| *x *= *y);
self
}
}
impl<const N: usize> std::ops::MulAssign for crate::ntt::NttDomain<R7681<N>> {
fn mul_assign(&mut self, rhs: Self) {
self.0
.0
.iter_mut()
.zip(rhs.0.0.iter())
.for_each(|(x, y)| *x *= *y);
}
}
impl<const N: usize> std::ops::MulAssign<&Self> for crate::ntt::NttDomain<R7681<N>> {
fn mul_assign(&mut self, rhs: &Self) {
self.0
.0
.iter_mut()
.zip(rhs.0.0.iter())
.for_each(|(x, y)| *x *= *y);
}
}
impl<const N: usize> num_traits::Inv for crate::ntt::NttDomain<R7681<N>> {
type Output = Self;
fn inv(mut self) -> Self {
self.0.0.iter_mut().for_each(|x| *x = x.inverse());
self
}
}