v0.1.0
This commit is contained in:
parent
f34f931030
commit
610cc4784a
5 changed files with 39 additions and 310 deletions
92
Cargo.lock
generated
92
Cargo.lock
generated
|
|
@ -10,46 +10,15 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -63,15 +32,14 @@ dependencies = [
|
|||
"num-traits",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"rayon",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.175"
|
||||
version = "0.2.182"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
|
|
@ -93,18 +61,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
|
@ -139,31 +107,11 @@ dependencies = [
|
|||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -172,9 +120,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
|
|
@ -184,18 +132,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.26"
|
||||
version = "0.8.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
|
||||
checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.26"
|
||||
version = "0.8.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
|
||||
checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -204,6 +152,6 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||
|
|
|
|||
11
Cargo.toml
11
Cargo.toml
|
|
@ -1,7 +1,15 @@
|
|||
[package]
|
||||
name = "gwrizienn"
|
||||
version = "0.1.0"
|
||||
authors = ["tuxmain <tuxmain@zettascript.org>"]
|
||||
edition = "2024"
|
||||
license = "AGPL-3.0-only"
|
||||
description = "Easy and fast modular arithmetic, polynomial quotient rings"
|
||||
categories = ["mathematics", "no-std"]
|
||||
keywords = ["arithmetic", "polynomial", "ntt", "lattice-crypto"]
|
||||
homepage = "https://git.zoai.re/tuxmain/gwrizienn"
|
||||
repository = "https://git.zoai.re/tuxmain/gwrizienn"
|
||||
documentation = "https://docs.rs/gwrizienn"
|
||||
|
||||
[dependencies]
|
||||
num-traits = "0.2"
|
||||
|
|
@ -9,9 +17,6 @@ rand = { version = "0.8", optional = true }
|
|||
rand_core = { version = "0.6", optional = true }
|
||||
zeroize = { version = "1", optional = true, default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
rayon = "1.8"
|
||||
|
||||
[features]
|
||||
default = ["rand", "zeroize"]
|
||||
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
Modular arithmetic, polynomial quotient rings in Rust.
|
||||
|
||||
Early development, really.
|
||||
|
||||
Goals:
|
||||
* Easy to use, obvious when you look at the documentation and type system
|
||||
* Fast, most possible work is done at compile time
|
||||
|
|
@ -13,12 +11,20 @@ Non-goals:
|
|||
* Generic (it's generic but only for primitive types)
|
||||
* Complete (it's simple because it's not a complete implementation of modern algebra)
|
||||
* Dynamic (vector dimensions and moduli are strongly typed)
|
||||
* Footgun-free (if you give incoherent arguments to the macros, it may produce unsafe code)
|
||||
|
||||
Supported:
|
||||
* ring Zq
|
||||
* ring Zq/(x^N+1) with additive operations
|
||||
* ring Zq/(x^N+1) with multiplicative operations if q=p or q=2p with p prime and 2N divides p-1
|
||||
* vectors and matrices of the above rings
|
||||
* lift between different rings (see example ntwe) (lifting may lack some features or be unsafe)
|
||||
|
||||
**Warning**: There are some TODOs in the code. The code has not been audited nor proven. Please don't use it in production yet.
|
||||
|
||||
## Why
|
||||
|
||||
When implementing Dilithium and other similar lattice-based schemes, I found no crate that was both easy and fast, so I made one with the exact set of features I needed.
|
||||
|
||||
## Name
|
||||
|
||||
|
|
@ -28,7 +34,7 @@ Pronounce _grizienn_. It's Breton for "root", because we use roots of unity to c
|
|||
|
||||
[Support me via LiberaPay](https://liberapay.com/tuxmain/donate)
|
||||
|
||||
GNU AGPL v3, CopyLeft 2025 Pascal Engélibert [(why copyleft?)](https://txmn.tk/blog/why-copyleft/)
|
||||
GNU AGPL v3, CopyLeft 2025-2026 Pascal Engélibert [(why copyleft?)](https://txmn.tk/blog/why-copyleft/)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
232
src/r7681.rs
232
src/r7681.rs
|
|
@ -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
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue