/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-bigint-0.2.6/src/monty.rs
Line | Count | Source |
1 | | use integer::Integer; |
2 | | use traits::Zero; |
3 | | |
4 | | use biguint::BigUint; |
5 | | |
6 | | struct MontyReducer<'a> { |
7 | | n: &'a BigUint, |
8 | | n0inv: u32, |
9 | | } |
10 | | |
11 | | // Calculate the modular inverse of `num`, using Extended GCD. |
12 | | // |
13 | | // Reference: |
14 | | // Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 1.20 |
15 | 0 | fn inv_mod_u32(num: u32) -> u32 { |
16 | | // num needs to be relatively prime to 2**32 -- i.e. it must be odd. |
17 | 0 | assert!(num % 2 != 0); |
18 | | |
19 | 0 | let mut a: i64 = i64::from(num); |
20 | 0 | let mut b: i64 = i64::from(u32::max_value()) + 1; |
21 | | |
22 | | // ExtendedGcd |
23 | | // Input: positive integers a and b |
24 | | // Output: integers (g, u, v) such that g = gcd(a, b) = ua + vb |
25 | | // As we don't need v for modular inverse, we don't calculate it. |
26 | | |
27 | | // 1: (u, w) <- (1, 0) |
28 | 0 | let mut u = 1; |
29 | 0 | let mut w = 0; |
30 | | // 3: while b != 0 |
31 | 0 | while b != 0 { |
32 | 0 | // 4: (q, r) <- DivRem(a, b) |
33 | 0 | let q = a / b; |
34 | 0 | let r = a % b; |
35 | 0 | // 5: (a, b) <- (b, r) |
36 | 0 | a = b; |
37 | 0 | b = r; |
38 | 0 | // 6: (u, w) <- (w, u - qw) |
39 | 0 | let m = u - w * q; |
40 | 0 | u = w; |
41 | 0 | w = m; |
42 | 0 | } |
43 | | |
44 | 0 | assert!(a == 1); |
45 | | // Downcasting acts like a mod 2^32 too. |
46 | 0 | u as u32 |
47 | 0 | } Unexecuted instantiation: num_bigint::biguint::monty::inv_mod_u32 Unexecuted instantiation: num_bigint::biguint::monty::inv_mod_u32 |
48 | | |
49 | | impl<'a> MontyReducer<'a> { |
50 | 0 | fn new(n: &'a BigUint) -> Self { |
51 | 0 | let n0inv = inv_mod_u32(n.data[0]); |
52 | 0 | MontyReducer { n: n, n0inv: n0inv } |
53 | 0 | } Unexecuted instantiation: <num_bigint::biguint::monty::MontyReducer>::new Unexecuted instantiation: <num_bigint::biguint::monty::MontyReducer>::new |
54 | | } |
55 | | |
56 | | // Montgomery Reduction |
57 | | // |
58 | | // Reference: |
59 | | // Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 2.6 |
60 | 0 | fn monty_redc(a: BigUint, mr: &MontyReducer) -> BigUint { |
61 | 0 | let mut c = a.data; |
62 | 0 | let n = &mr.n.data; |
63 | 0 | let n_size = n.len(); |
64 | | |
65 | | // Allocate sufficient work space |
66 | 0 | c.resize(2 * n_size + 2, 0); |
67 | | |
68 | | // β is the size of a word, in this case 32 bits. So "a mod β" is |
69 | | // equivalent to masking a to 32 bits. |
70 | | // mu <- -N^(-1) mod β |
71 | 0 | let mu = 0u32.wrapping_sub(mr.n0inv); |
72 | | |
73 | | // 1: for i = 0 to (n-1) |
74 | 0 | for i in 0..n_size { |
75 | 0 | // 2: q_i <- mu*c_i mod β |
76 | 0 | let q_i = c[i].wrapping_mul(mu); |
77 | 0 |
|
78 | 0 | // 3: C <- C + q_i * N * β^i |
79 | 0 | super::algorithms::mac_digit(&mut c[i..], n, q_i); |
80 | 0 | } |
81 | | |
82 | | // 4: R <- C * β^(-n) |
83 | | // This is an n-word bitshift, equivalent to skipping n words. |
84 | 0 | let ret = BigUint::new(c[n_size..].to_vec()); |
85 | | |
86 | | // 5: if R >= β^n then return R-N else return R. |
87 | 0 | if ret < *mr.n { |
88 | 0 | ret |
89 | | } else { |
90 | 0 | ret - mr.n |
91 | | } |
92 | 0 | } Unexecuted instantiation: num_bigint::biguint::monty::monty_redc Unexecuted instantiation: num_bigint::biguint::monty::monty_redc |
93 | | |
94 | | // Montgomery Multiplication |
95 | 0 | fn monty_mult(a: BigUint, b: &BigUint, mr: &MontyReducer) -> BigUint { |
96 | 0 | monty_redc(a * b, mr) |
97 | 0 | } Unexecuted instantiation: num_bigint::biguint::monty::monty_mult Unexecuted instantiation: num_bigint::biguint::monty::monty_mult |
98 | | |
99 | | // Montgomery Squaring |
100 | 0 | fn monty_sqr(a: BigUint, mr: &MontyReducer) -> BigUint { |
101 | | // TODO: Replace with an optimised squaring function |
102 | 0 | monty_redc(&a * &a, mr) |
103 | 0 | } Unexecuted instantiation: num_bigint::biguint::monty::monty_sqr Unexecuted instantiation: num_bigint::biguint::monty::monty_sqr |
104 | | |
105 | 0 | pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { |
106 | 0 | let mr = MontyReducer::new(modulus); |
107 | | |
108 | | // Calculate the Montgomery parameter |
109 | 0 | let mut v = vec![0; modulus.data.len()]; |
110 | 0 | v.push(1); |
111 | 0 | let r = BigUint::new(v); |
112 | | |
113 | | // Map the base to the Montgomery domain |
114 | 0 | let mut apri = a * &r % modulus; |
115 | | |
116 | | // Binary exponentiation |
117 | 0 | let mut ans = &r % modulus; |
118 | 0 | let mut e = exp.clone(); |
119 | 0 | while !e.is_zero() { |
120 | 0 | if e.is_odd() { |
121 | 0 | ans = monty_mult(ans, &apri, &mr); |
122 | 0 | } |
123 | 0 | apri = monty_sqr(apri, &mr); |
124 | 0 | e >>= 1; |
125 | | } |
126 | | |
127 | | // Map the result back to the residues domain |
128 | 0 | monty_redc(ans, &mr) |
129 | 0 | } Unexecuted instantiation: num_bigint::biguint::monty::monty_modpow Unexecuted instantiation: num_bigint::biguint::monty::monty_modpow |