1use super::Uint;
2use crate::CtChoice;
34impl<const LIMBS: usize> Uint<LIMBS> {
5/// Computes 1/`self` mod `2^k`.
6 /// This method is constant-time w.r.t. `self` but not `k`.
7 ///
8 /// Conditions: `self` < 2^k and `self` must be odd
9pub const fn inv_mod2k_vartime(&self, k: usize) -> Self {
10// Using the Algorithm 3 from "A Secure Algorithm for Inversion Modulo 2k"
11 // by Sadiel de la Fe and Carles Ferrer.
12 // See <https://www.mdpi.com/2410-387X/2/3/23>.
1314 // Note that we are not using Alrgorithm 4, since we have a different approach
15 // of enforcing constant-timeness w.r.t. `self`.
1617let mut x = Self::ZERO; // keeps `x` during iterations
18let mut b = Self::ONE; // keeps `b_i` during iterations
19let mut i = 0;
2021while i < k {
22// X_i = b_i mod 2
23let x_i = b.limbs[0].0 & 1;
24let x_i_choice = CtChoice::from_lsb(x_i);
25// b_{i+1} = (b_i - a * X_i) / 2
26b = Self::ct_select(&b, &b.wrapping_sub(self), x_i_choice).shr_vartime(1);
27// Store the X_i bit in the result (x = x | (1 << X_i))
28x = x.bitor(&Uint::from_word(x_i).shl_vartime(i));
2930 i += 1;
31 }
3233 x
34 }
3536/// Computes 1/`self` mod `2^k`.
37 ///
38 /// Conditions: `self` < 2^k and `self` must be odd
39pub const fn inv_mod2k(&self, k: usize) -> Self {
40// This is the same algorithm as in `inv_mod2k_vartime()`,
41 // but made constant-time w.r.t `k` as well.
4243let mut x = Self::ZERO; // keeps `x` during iterations
44let mut b = Self::ONE; // keeps `b_i` during iterations
45let mut i = 0;
4647while i < Self::BITS {
48// Only iterations for i = 0..k need to change `x`,
49 // the rest are dummy ones performed for the sake of constant-timeness.
50let within_range = CtChoice::from_usize_lt(i, k);
5152// X_i = b_i mod 2
53let x_i = b.limbs[0].0 & 1;
54let x_i_choice = CtChoice::from_lsb(x_i);
55// b_{i+1} = (b_i - a * X_i) / 2
56b = Self::ct_select(&b, &b.wrapping_sub(self), x_i_choice).shr_vartime(1);
5758// Store the X_i bit in the result (x = x | (1 << X_i))
59 // Don't change the result in dummy iterations.
60let x_i_choice = x_i_choice.and(within_range);
61 x = x.set_bit(i, x_i_choice);
6263 i += 1;
64 }
6566 x
67 }
6869/// Computes the multiplicative inverse of `self` mod `modulus`, where `modulus` is odd.
70 /// In other words `self^-1 mod modulus`.
71 /// `bits` and `modulus_bits` are the bounds on the bit size
72 /// of `self` and `modulus`, respectively
73 /// (the inversion speed will be proportional to `bits + modulus_bits`).
74 /// The second element of the tuple is the truthy value if an inverse exists,
75 /// otherwise it is a falsy value.
76 ///
77 /// **Note:** variable time in `bits` and `modulus_bits`.
78 ///
79 /// The algorithm is the same as in GMP 6.2.1's `mpn_sec_invert`.
80pub const fn inv_odd_mod_bounded(
81&self,
82 modulus: &Self,
83 bits: usize,
84 modulus_bits: usize,
85 ) -> (Self, CtChoice) {
86debug_assert!(modulus.ct_is_odd().is_true_vartime());
8788let mut a = *self;
8990let mut u = Uint::ONE;
91let mut v = Uint::ZERO;
9293let mut b = *modulus;
9495// `bit_size` can be anything >= `self.bits()` + `modulus.bits()`, setting to the minimum.
96let bit_size = bits + modulus_bits;
9798let mut m1hp = *modulus;
99let (m1hp_new, carry) = m1hp.shr_1();
100debug_assert!(carry.is_true_vartime());
101 m1hp = m1hp_new.wrapping_add(&Uint::ONE);
102103let mut i = 0;
104while i < bit_size {
105debug_assert!(b.ct_is_odd().is_true_vartime());
106107let self_odd = a.ct_is_odd();
108109// Set `self -= b` if `self` is odd.
110let (new_a, swap) = a.conditional_wrapping_sub(&b, self_odd);
111// Set `b += self` if `swap` is true.
112b = Uint::ct_select(&b, &b.wrapping_add(&new_a), swap);
113// Negate `self` if `swap` is true.
114a = new_a.conditional_wrapping_neg(swap);
115116let (new_u, new_v) = Uint::ct_swap(&u, &v, swap);
117let (new_u, cy) = new_u.conditional_wrapping_sub(&new_v, self_odd);
118let (new_u, cyy) = new_u.conditional_wrapping_add(modulus, cy);
119debug_assert!(cy.is_true_vartime() == cyy.is_true_vartime());
120121let (new_a, overflow) = a.shr_1();
122debug_assert!(!overflow.is_true_vartime());
123let (new_u, cy) = new_u.shr_1();
124let (new_u, cy) = new_u.conditional_wrapping_add(&m1hp, cy);
125debug_assert!(!cy.is_true_vartime());
126127 a = new_a;
128 u = new_u;
129 v = new_v;
130131 i += 1;
132 }
133134debug_assert!(!a.ct_is_nonzero().is_true_vartime());
135136 (v, Uint::ct_eq(&b, &Uint::ONE))
137 }
138139/// Computes the multiplicative inverse of `self` mod `modulus`, where `modulus` is odd.
140 /// Returns `(inverse, CtChoice::TRUE)` if an inverse exists,
141 /// otherwise `(undefined, CtChoice::FALSE)`.
142pub const fn inv_odd_mod(&self, modulus: &Self) -> (Self, CtChoice) {
143self.inv_odd_mod_bounded(modulus, Uint::<LIMBS>::BITS, Uint::<LIMBS>::BITS)
144 }
145146/// Computes the multiplicative inverse of `self` mod `modulus`.
147 /// Returns `(inverse, CtChoice::TRUE)` if an inverse exists,
148 /// otherwise `(undefined, CtChoice::FALSE)`.
149pub const fn inv_mod(&self, modulus: &Self) -> (Self, CtChoice) {
150// Decompose `modulus = s * 2^k` where `s` is odd
151let k = modulus.trailing_zeros();
152let s = modulus.shr(k);
153154// Decompose `self` into RNS with moduli `2^k` and `s` and calculate the inverses.
155 // Using the fact that `(z^{-1} mod (m1 * m2)) mod m1 == z^{-1} mod m1`
156let (a, a_is_some) = self.inv_odd_mod(&s);
157let b = self.inv_mod2k(k);
158// inverse modulo 2^k exists either if `k` is 0 or if `self` is odd.
159let b_is_some = CtChoice::from_usize_being_nonzero(k)
160 .not()
161 .or(self.ct_is_odd());
162163// Restore from RNS:
164 // self^{-1} = a mod s = b mod 2^k
165 // => self^{-1} = a + s * ((b - a) * s^(-1) mod 2^k)
166 // (essentially one step of the Garner's algorithm for recovery from RNS).
167168let m_odd_inv = s.inv_mod2k(k); // `s` is odd, so this always exists
169170 // This part is mod 2^k
171let mask = Uint::ONE.shl(k).wrapping_sub(&Uint::ONE);
172let t = (b.wrapping_sub(&a).wrapping_mul(&m_odd_inv)).bitand(&mask);
173174// Will not overflow since `a <= s - 1`, `t <= 2^k - 1`,
175 // so `a + s * t <= s * 2^k - 1 == modulus - 1`.
176let result = a.wrapping_add(&s.wrapping_mul(&t));
177 (result, a_is_some.and(b_is_some))
178 }
179}
180181#[cfg(test)]
182mod tests {
183use crate::{U1024, U256, U64};
184185#[test]
186fn inv_mod2k() {
187let v =
188 U256::from_be_hex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f");
189let e =
190 U256::from_be_hex("3642e6faeaac7c6663b93d3d6a0d489e434ddc0123db5fa627c7f6e22ddacacf");
191let a = v.inv_mod2k(256);
192assert_eq!(e, a);
193194let v =
195 U256::from_be_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
196let e =
197 U256::from_be_hex("261776f29b6b106c7680cf3ed83054a1af5ae537cb4613dbb4f20099aa774ec1");
198let a = v.inv_mod2k(256);
199assert_eq!(e, a);
200 }
201202#[test]
203fn test_invert_odd() {
204let a = U1024::from_be_hex(concat![
205"000225E99153B467A5B451979A3F451DAEF3BF8D6C6521D2FA24BBB17F29544E",
206"347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8",
207"BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8",
208"382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985"
209]);
210let m = U1024::from_be_hex(concat![
211"D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
212"37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
213"D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
214"558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767"
215]);
216let expected = U1024::from_be_hex(concat![
217"B03623284B0EBABCABD5C5881893320281460C0A8E7BF4BFDCFFCBCCBF436A55",
218"D364235C8171E46C7D21AAD0680676E57274A8FDA6D12768EF961CACDD2DAE57",
219"88D93DA5EB8EDC391EE3726CDCF4613C539F7D23E8702200CB31B5ED5B06E5CA",
220"3E520968399B4017BF98A864FABA2B647EFC4998B56774D4F2CB026BC024A336"
221]);
222223let (res, is_some) = a.inv_odd_mod(&m);
224assert!(is_some.is_true_vartime());
225assert_eq!(res, expected);
226227// Even though it is less efficient, it still works
228let (res, is_some) = a.inv_mod(&m);
229assert!(is_some.is_true_vartime());
230assert_eq!(res, expected);
231 }
232233#[test]
234fn test_invert_even() {
235let a = U1024::from_be_hex(concat![
236"000225E99153B467A5B451979A3F451DAEF3BF8D6C6521D2FA24BBB17F29544E",
237"347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8",
238"BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8",
239"382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985"
240]);
241let m = U1024::from_be_hex(concat![
242"D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
243"37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
244"D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
245"558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156000"
246]);
247let expected = U1024::from_be_hex(concat![
248"1EBF391306817E1BC610E213F4453AD70911CCBD59A901B2A468A4FC1D64F357",
249"DBFC6381EC5635CAA664DF280028AF4651482C77A143DF38D6BFD4D64B6C0225",
250"FC0E199B15A64966FB26D88A86AD144271F6BDCD3D63193AB2B3CC53B99F21A3",
251"5B9BFAE5D43C6BC6E7A9856C71C7318C76530E9E5AE35882D5ABB02F1696874D",
252 ]);
253254let (res, is_some) = a.inv_mod(&m);
255assert!(is_some.is_true_vartime());
256assert_eq!(res, expected);
257 }
258259#[test]
260fn test_invert_bounded() {
261let a = U1024::from_be_hex(concat![
262"0000000000000000000000000000000000000000000000000000000000000000",
263"347A412B065B75A351EA9719E2430D2477B11CC9CF9C1AD6EDEE26CB15F463F8",
264"BCC72EF87EA30288E95A48AA792226CEC959DCB0672D8F9D80A54CBBEA85CAD8",
265"382EC224DEB2F5784E62D0CC2F81C2E6AD14EBABE646D6764B30C32B87688985"
266]);
267let m = U1024::from_be_hex(concat![
268"0000000000000000000000000000000000000000000000000000000000000000",
269"0000000000000000000000000000000000000000000000000000000000000000",
270"D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
271"558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767"
272]);
273274let (res, is_some) = a.inv_odd_mod_bounded(&m, 768, 512);
275276let expected = U1024::from_be_hex(concat![
277"0000000000000000000000000000000000000000000000000000000000000000",
278"0000000000000000000000000000000000000000000000000000000000000000",
279"0DCC94E2FE509E6EBBA0825645A38E73EF85D5927C79C1AD8FFE7C8DF9A822FA",
280"09EB396A21B1EF05CBE51E1A8EF284EF01EBDD36A9A4EA17039D8EEFDD934768"
281]);
282assert!(is_some.is_true_vartime());
283assert_eq!(res, expected);
284 }
285286#[test]
287fn test_invert_small() {
288let a = U64::from(3u64);
289let m = U64::from(13u64);
290291let (res, is_some) = a.inv_odd_mod(&m);
292293assert!(is_some.is_true_vartime());
294assert_eq!(U64::from(9u64), res);
295 }
296297#[test]
298fn test_no_inverse_small() {
299let a = U64::from(14u64);
300let m = U64::from(49u64);
301302let (_res, is_some) = a.inv_odd_mod(&m);
303304assert!(!is_some.is_true_vartime());
305 }
306}