zmodn-rs

A simple Rust library for integers modulo N
git clone https://git.tronto.net/zmodn-rs
Download | Log | Files | Refs | README

commit c07b47ee1a7aa3469753fa2ec49f3b499defac55
parent 51bb82df499e35cdc13d33dd24eca85d7abd0aaf
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Mon, 23 Jun 2025 11:21:11 +0200

Finalized

Diffstat:
AREADME.md | 3+++
Msrc/lib.rs | 83+++++++++++++++++++++++++++++++++++++++----------------------------------------
2 files changed, 44 insertions(+), 42 deletions(-)

diff --git a/README.md b/README.md @@ -0,0 +1,3 @@ +A small library for integers modulo n, similar to +[zmodn](https://git.tronto.net/zmodn/file/README.md.html) +but in Rust. diff --git a/src/lib.rs b/src/lib.rs @@ -1,20 +1,19 @@ -// TODO: make Zmod argument type generic -// TODO: re-implement ECM? - use std::fmt; use std::ops; +pub type BaseInt = i64; + // We assume canonical representative, can compare value for PartialEq #[derive(Copy, Clone, Debug, PartialEq)] -pub struct Zmod<const N: i64> { - value: i64 +pub struct Zmod<const N: BaseInt> { + value: BaseInt } -fn canonical_rep<const N: i64>(x: i64) -> i64 { +fn canonical_rep<const N: BaseInt>(x: BaseInt) -> BaseInt { return (x % N + N) % N; } -fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) { +fn extended_gcd(a: BaseInt, b: BaseInt) -> (BaseInt, BaseInt, BaseInt) { if b == 0 { return (a, 1, 0); } @@ -22,15 +21,15 @@ fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) { (g, y, x - y*(a/b)) } -impl<const N: i64> Zmod<N> { - pub fn from(x: i64) -> Zmod<N> { +impl<const N: BaseInt> Zmod<N> { + pub fn from(x: BaseInt) -> Zmod<N> { #[cfg(debug_assertions)] assert!(N > 1, "modulus must be greater than 1"); Zmod::<N> { value: canonical_rep::<N>(x) } } - fn inverse(self) -> Result<Zmod<N>, i64> { + fn inverse(self) -> Result<Zmod<N>, BaseInt> { let (g, a, _) = extended_gcd(self.value, N); if g == 1 { Ok(Zmod::<N>::from(a)) @@ -40,13 +39,13 @@ impl<const N: i64> Zmod<N> { } } -impl<const N: i64> fmt::Display for Zmod<N> { +impl<const N: BaseInt> fmt::Display for Zmod<N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({} mod {})", self.value, N) } } -impl<const N: i64> ops::Add for Zmod<N> { +impl<const N: BaseInt> ops::Add for Zmod<N> { type Output = Zmod<N>; fn add(self, z: Zmod<N>) -> Zmod<N> { @@ -54,15 +53,15 @@ impl<const N: i64> ops::Add for Zmod<N> { } } -impl<const N: i64> ops::Add<i64> for Zmod<N> { +impl<const N: BaseInt> ops::Add<BaseInt> for Zmod<N> { type Output = Zmod<N>; - fn add(self, z: i64) -> Zmod<N> { + fn add(self, z: BaseInt) -> Zmod<N> { Zmod::<N>::from(self.value + z) } } -impl<const N: i64> ops::Add<Zmod<N>> for i64 { +impl<const N: BaseInt> ops::Add<Zmod<N>> for BaseInt { type Output = Zmod::<N>; fn add(self, z: Zmod::<N>) -> Zmod<N> { @@ -70,19 +69,19 @@ impl<const N: i64> ops::Add<Zmod<N>> for i64 { } } -impl<const N: i64> ops::AddAssign for Zmod<N> { +impl<const N: BaseInt> ops::AddAssign for Zmod<N> { fn add_assign(&mut self, z: Zmod<N>) { self.value = canonical_rep::<N>(self.value + z.value); } } -impl<const N: i64> ops::AddAssign<i64> for Zmod<N> { - fn add_assign(&mut self, z: i64) { +impl<const N: BaseInt> ops::AddAssign<BaseInt> for Zmod<N> { + fn add_assign(&mut self, z: BaseInt) { self.value = canonical_rep::<N>(self.value + z); } } -impl<const N: i64> ops::Sub for Zmod<N> { +impl<const N: BaseInt> ops::Sub for Zmod<N> { type Output = Zmod<N>; fn sub(self, z: Zmod<N>) -> Zmod<N> { @@ -90,15 +89,15 @@ impl<const N: i64> ops::Sub for Zmod<N> { } } -impl<const N: i64> ops::Sub<i64> for Zmod<N> { +impl<const N: BaseInt> ops::Sub<BaseInt> for Zmod<N> { type Output = Zmod<N>; - fn sub(self, z: i64) -> Zmod<N> { + fn sub(self, z: BaseInt) -> Zmod<N> { Zmod::<N>::from(self.value - z) } } -impl<const N: i64> ops::Sub<Zmod<N>> for i64 { +impl<const N: BaseInt> ops::Sub<Zmod<N>> for BaseInt { type Output = Zmod<N>; fn sub(self, z: Zmod<N>) -> Zmod<N> { @@ -106,19 +105,19 @@ impl<const N: i64> ops::Sub<Zmod<N>> for i64 { } } -impl<const N: i64> ops::SubAssign for Zmod<N> { +impl<const N: BaseInt> ops::SubAssign for Zmod<N> { fn sub_assign(&mut self, z: Zmod<N>) { self.value = canonical_rep::<N>(self.value - z.value); } } -impl<const N: i64> ops::SubAssign<i64> for Zmod<N> { - fn sub_assign(&mut self, z: i64) { +impl<const N: BaseInt> ops::SubAssign<BaseInt> for Zmod<N> { + fn sub_assign(&mut self, z: BaseInt) { self.value = canonical_rep::<N>(self.value - z); } } -impl<const N: i64> ops::Neg for Zmod<N> { +impl<const N: BaseInt> ops::Neg for Zmod<N> { type Output = Zmod<N>; fn neg(self) -> Zmod<N> { @@ -126,7 +125,7 @@ impl<const N: i64> ops::Neg for Zmod<N> { } } -impl<const N: i64> ops::Mul for Zmod<N> { +impl<const N: BaseInt> ops::Mul for Zmod<N> { type Output = Zmod<N>; fn mul(self, z: Zmod<N>) -> Zmod<N> { @@ -134,15 +133,15 @@ impl<const N: i64> ops::Mul for Zmod<N> { } } -impl<const N: i64> ops::Mul<i64> for Zmod<N> { +impl<const N: BaseInt> ops::Mul<BaseInt> for Zmod<N> { type Output = Zmod<N>; - fn mul(self, z: i64) -> Zmod<N> { + fn mul(self, z: BaseInt) -> Zmod<N> { Zmod::<N>::from(self.value * z) } } -impl<const N: i64> ops::Mul<Zmod<N>> for i64 { +impl<const N: BaseInt> ops::Mul<Zmod<N>> for BaseInt { type Output = Zmod<N>; fn mul(self, z: Zmod<N>) -> Zmod<N> { @@ -150,38 +149,38 @@ impl<const N: i64> ops::Mul<Zmod<N>> for i64 { } } -impl<const N: i64> ops::MulAssign for Zmod<N> { +impl<const N: BaseInt> ops::MulAssign for Zmod<N> { fn mul_assign(&mut self, z: Zmod<N>) { self.value = canonical_rep::<N>(self.value * z.value); } } -impl<const N: i64> ops::MulAssign<i64> for Zmod<N> { - fn mul_assign(&mut self, z: i64) { +impl<const N: BaseInt> ops::MulAssign<BaseInt> for Zmod<N> { + fn mul_assign(&mut self, z: BaseInt) { self.value = canonical_rep::<N>(self.value * z); } } -impl<const N: i64> ops::Div for Zmod<N> { - type Output = Result<Zmod<N>, i64>; +impl<const N: BaseInt> ops::Div for Zmod<N> { + type Output = Result<Zmod<N>, BaseInt>; - fn div(self, z: Zmod<N>) -> Result<Zmod<N>, i64> { + fn div(self, z: Zmod<N>) -> Result<Zmod<N>, BaseInt> { Ok(self * z.inverse()?) } } -impl<const N: i64> ops::Div<i64> for Zmod<N> { - type Output = Result<Zmod<N>, i64>; +impl<const N: BaseInt> ops::Div<BaseInt> for Zmod<N> { + type Output = Result<Zmod<N>, BaseInt>; - fn div(self, z: i64) -> Result<Zmod<N>, i64> { + fn div(self, z: BaseInt) -> Result<Zmod<N>, BaseInt> { self / Zmod::<N>::from(z) } } -impl<const N: i64> ops::Div<Zmod<N>> for i64 { - type Output = Result<Zmod<N>, i64>; +impl<const N: BaseInt> ops::Div<Zmod<N>> for BaseInt { + type Output = Result<Zmod<N>, BaseInt>; - fn div(self, z: Zmod<N>) -> Result<Zmod<N>, i64> { + fn div(self, z: Zmod<N>) -> Result<Zmod<N>, BaseInt> { Zmod::<N>::from(self) / z } }