modulo_n_tools/
lib.rs

1#![no_std]
2//! modulo_tools
3//! ```
4//! use modulo_n_tools::*;
5//! use modulo_n_tools::montgomery::*;
6//! let a = add_mod(&3, &4, &5);
7//! assert_eq!(a, 2);
8//! let b = mul_mod(&3, &a, &5);
9//! assert_eq!(b, 1);
10//! let c = pow_mod(2, 6, &7);
11//! assert_eq!(c, 1);
12//! let m = Montgomery64::new(57);
13//! let d = m.powmod(5, 42);
14//! assert_eq!(d, 7);
15//! ```
16use core::ops::{Add, AddAssign, BitAnd, Mul, Neg, Rem, ShrAssign, Sub, SubAssign};
17pub mod montgomery;
18
19fn reduce<T>(mut a: T, modulo: &T) -> T
20where
21    T: Ord + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
22    for<'x> &'x T: Neg<Output = T>,
23{
24    if &a >= modulo {
25        a -= modulo;
26    } else if a <= -modulo {
27        a += modulo
28    }
29    a
30}
31
32/// $`a + b \bmod n`$
33///
34/// Input: $`-\text{modulo} \leq a,\, b \leq \text{modulo}`$  
35/// Output: $`-\text{modulo} \leq x \leq \text{modulo}`$
36/// ```
37/// use modulo_n_tools::add_mod;
38/// assert_eq!(add_mod(&3, &4, &5), 2);
39/// assert_eq!(add_mod(&2, &5, &6), 1);
40/// assert_eq!(add_mod(&-3, &-2, &4), -1);
41/// assert_eq!(add_mod(&2, &3, &5), 0);
42/// ```
43pub fn add_mod<T>(a: &T, b: &T, modulo: &T) -> T
44where
45    T: Ord + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
46    for<'x> &'x T: Add<Output = T> + Neg<Output = T>,
47{
48    let c = a + b;
49    reduce(c, modulo)
50}
51
52/// $`a - b \bmod n`$
53///
54/// Input: $`-\text{modulo} \leq a,\, b \leq \text{modulo}`$  
55/// Output: $`-\text{modulo} \leq x \leq \text{modulo}`$
56/// ```
57/// use modulo_n_tools::sub_mod;
58/// assert_eq!(sub_mod(&3, &4, &5), -1);
59/// assert_eq!(sub_mod(&2, &-5, &6), 1);
60/// assert_eq!(sub_mod(&-2, &-3, &4), 1);
61/// assert_eq!(sub_mod(&2, &2, &5), 0);
62/// ```
63pub fn sub_mod<T>(a: &T, b: &T, modulo: &T) -> T
64where
65    T: Ord + for<'x> AddAssign<&'x T> + for<'x> SubAssign<&'x T>,
66    for<'x> &'x T: Sub<Output = T> + Neg<Output = T>,
67{
68    let c = a - b;
69    reduce(c, modulo)
70}
71
72/// $`ab \bmod n`$
73///
74/// Input: $`-\text{modulo} \leq a,\, b \leq \text{modulo}`$  
75/// Output: $`-\text{modulo} \leq x \leq \text{modulo}`$
76/// ```
77/// use modulo_n_tools::mul_mod;
78/// assert_eq!(mul_mod(&3, &4, &5), 2);
79/// assert_eq!(mul_mod(&2, &5, &6), 4);
80/// assert_eq!(mul_mod(&-2, &-3, &4), 2);
81/// assert_eq!(mul_mod(&2, &3, &6), 0);
82/// ```
83pub fn mul_mod<T>(a: &T, b: &T, modulo: &T) -> T
84where
85    for<'x> &'x T: Mul<Output = T> + Rem<Output = T>,
86{
87    &(a * b) % modulo
88}
89
90/// $`a^b \bmod n`$
91///
92/// Input: $`-\text{modulo} \leq a \leq \text{modulo}`$,
93/// b is non-negative integer.  
94/// Output: $`-\text{modulo} \leq x \leq \text{modulo}`$
95/// ```
96/// use modulo_n_tools::pow_mod;
97/// assert_eq!(pow_mod(3, 4, &5), 1);
98/// assert_eq!(pow_mod(2, 5, &6), 2);
99/// assert_eq!(pow_mod(-2, 3, &4), 0);
100/// assert_eq!(pow_mod(2, 3, &7), 1);
101/// ```
102pub fn pow_mod<T, U>(a: T, mut b: U, modulo: &T) -> T
103where
104    T: From<u8>,
105    for<'x> &'x T: Mul<Output = T> + Rem<Output = T>,
106    U: Ord + ShrAssign<u8> + From<u8>,
107    for<'x> &'x U: BitAnd<Output = U>,
108{
109    let c0 = U::from(0);
110    let c1 = U::from(1);
111    let mut x = a;
112    let mut y = T::from(1);
113    while b > c0 {
114        if &b & &c1 != c0 {
115            y = mul_mod(&x, &y, modulo);
116        }
117        x = mul_mod(&x, &x, modulo);
118        b >>= 1;
119    }
120    y
121}
122
123/// $`a\cdot b^p \bmod n`$
124///
125/// Input: $`-\text{modulo} \leq b \leq \text{modulo}`$,
126/// c is non-negative integer.  
127/// Output: $`-\text{modulo} \leq x \leq \text{modulo}`$
128/// ```
129/// use modulo_n_tools::mul_pow_mod;
130/// assert_eq!(mul_pow_mod(1, 3, 4, &5), 1);
131/// assert_eq!(mul_pow_mod(1, 2, 5, &6), 2);
132/// assert_eq!(mul_pow_mod(1, -2, 3, &4), 0);
133/// assert_eq!(mul_pow_mod(1, 2, 3, &7), 1);
134/// ```
135pub fn mul_pow_mod<T, U>(a: T, base: T, mut power: U, modulo: &T) -> T
136where
137    for<'x> &'x T: Mul<Output = T> + Rem<Output = T>,
138    U: Ord + ShrAssign<u8> + From<u8>,
139    for<'x> &'x U: BitAnd<Output = U>,
140{
141    let c0 = U::from(0);
142    let c1 = U::from(1);
143    let mut x = base;
144    let mut y = a;
145    while power > c0 {
146        if &power & &c1 != c0 {
147            y = mul_mod(&x, &y, modulo);
148        }
149        x = mul_mod(&x, &x, modulo);
150        power >>= 1;
151    }
152    y
153}