1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
//! This crate provides efficient Modular arithmetic operations for various integer types,
//! including primitive integers and `num-bigint`. The latter option is enabled optionally.
//!
//! To achieve fast modular arithmetics, convert integers to any [ModularInteger] implementation
//! use static `new()` or associated [ModularInteger::new()]. [MontgomeryInt] and [MontgomeryBigint]
//! are two builtin implementation based on the Montgomery form. The former one is for stack
//! allocated integer (like primitive types) and the latter one is for heap allocated integers (like `num-bigint::BigUint`)
//!
//! Example code:
//! ```rust
//! use num_modular::{ModularCoreOps, ModularInteger, MontgomeryInt};
//!
//! // directly using methods in ModularCoreOps
//! let (x, y, m) = (12u8, 13u8, 5u8);
//! assert_eq!(x.mulm(y, &m), x * y % m);
//!
//! // convert integers into ModularInteger
//! let mx = MontgomeryInt::new(x, m);
//! let my = mx.new(y); // faster than static new()
//! assert_eq!((mx * my).residue(), x * y % m);
//! ```
//!
// XXX: consider implementing lookup table based modulo?
// REF: https://eprint.iacr.org/2014/040.pdf
#![no_std]
#[cfg(any(feature = "std", test))]
extern crate std;
use core::ops::{Add, Mul, Neg, Sub};
/// This trait describes core modular arithmetic operations
pub trait ModularCoreOps<Rhs = Self, Modulus = Self> {
type Output;
/// Return (self + rhs) % m
fn addm(self, rhs: Rhs, m: Modulus) -> Self::Output;
/// Return (self + rhs) % m
fn subm(self, rhs: Rhs, m: Modulus) -> Self::Output;
/// Return (self * rhs) % m
fn mulm(self, rhs: Rhs, m: Modulus) -> Self::Output;
/// Return (-self) % m and make sure the result is normalized in range [0,m)
fn negm(self, m: Modulus) -> Self::Output;
}
/// This trait describes modular arithmetic operations
pub trait ModularOps<Rhs = Self, Modulus = Self>: ModularCoreOps<Rhs, Modulus> {
/// Return (self ^ exp) % m
fn powm(self, exp: Rhs, m: Modulus) -> Self::Output;
/// Calculate modular inverse (x such that self*x = 1 mod m).
///
/// This operation is only available for integer that is coprime to `m`
fn invm(self, m: Modulus) -> Option<Self::Output>
where
Self: Sized;
/// Calculate Jacobi Symbol (a|n), where a is self
///
/// # Panics
/// if n is negative or even
fn jacobi(self, n: Modulus) -> i8;
/// Calculate Kronecker Symbol (a|n), where a is self
fn kronecker(self, n: Modulus) -> i8;
/// Calculate Legendre Symbol (a|n), where a is self.
///
/// Note that this function doesn't perform primality check, since
/// is costly. So if n is not a prime, the result is not reasonable.
///
/// # Panics
/// if n is not prime
fn legendre(self, n: Modulus) -> i8;
// TODO: Modular sqrt aka Quadratic residue, follow the behavior of FLINT `n_sqrtmod`
// fn sqrtm(self, m: Modulus);
// TODO: Discrete log aka index, follow the behavior of FLINT `n_discrete_log_bsgs`
// fn logm(self, base: Modulus, m: Modulus);
}
/// Represents an number defined in a modulo ring ℤ/nℤ
///
/// The operators should panic if the modulus of two number
/// are not the same.
pub trait ModularInteger:
Sized
+ PartialEq
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Neg<Output = Self>
+ Mul<Self, Output = Self>
{
/// The underlying representation type of the integer
type Base;
/// Return the modulus of the ring
fn modulus(&self) -> &Self::Base;
/// Return the normalized residue of this integer in the ring
fn residue(&self) -> Self::Base;
/// Convert an normal integer into the same ring.
///
/// This method should be perferred over the static
/// constructor to prevent unnecessary overhead of pre-computation.
fn new(&self, n: Self::Base) -> Self;
}
mod barret;
mod double;
mod monty;
mod prim;
pub use double::{umax, udouble};
pub use monty::{Montgomery, MontgomeryInt};
#[cfg(std)]
pub use monty::MontgomeryBigint;
#[cfg(feature = "num-bigint")]
mod bigint;
// tests for ModularOps goes here
#[cfg(test)] mod tests;