crypto_bigint/int/
inv_mod.rs1use subtle::CtOption;
4
5use crate::modular::SafeGcdInverter;
6use crate::{ConstantTimeSelect, Int, InvMod, NonZero, Odd, PrecomputeInverter, Uint};
7
8impl<const LIMBS: usize, const UNSAT_LIMBS: usize> Int<LIMBS>
9where
10 Odd<Uint<LIMBS>>: PrecomputeInverter<Inverter = SafeGcdInverter<LIMBS, UNSAT_LIMBS>>,
11{
12 pub fn inv_odd_mod(&self, modulus: &Odd<Uint<LIMBS>>) -> CtOption<Uint<LIMBS>> {
14 let (abs, sgn) = self.abs_sign();
15 let abs_inv = abs.inv_odd_mod(modulus).into();
16
17 CtOption::ct_select(
20 &abs_inv,
21 &abs_inv.map(|abs_inv| modulus.wrapping_sub(&abs_inv)),
22 sgn.into(),
23 )
24 }
25}
26
27impl<const LIMBS: usize> InvMod<NonZero<Uint<LIMBS>>> for Int<LIMBS>
28where
29 Uint<LIMBS>: InvMod<Output = Uint<LIMBS>>,
30{
31 type Output = Uint<LIMBS>;
32
33 fn inv_mod(&self, modulus: &NonZero<Uint<LIMBS>>) -> CtOption<Self::Output> {
34 let (abs, sgn) = self.abs_sign();
35 let abs_inv = abs.inv_mod(modulus);
36
37 CtOption::ct_select(
40 &abs_inv,
41 &abs_inv.map(|abs_inv| modulus.wrapping_sub(&abs_inv)),
42 sgn.into(),
43 )
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use crate::{InvMod, I1024, U1024};
50
51 #[test]
52 fn test_invert_odd() {
53 let a = I1024::from_be_hex(concat![
54 "FFFDDA166EAC4B985A4BAE6865C0BAE2510C4072939ADE2D05DB444E80D6ABB1",
55 "CB85BED4F9A48A5CAE1568E61DBCF2DB884EE3363063E5291211D934EA0B9C07",
56 "4338D107815CFD7716A5B75586DDD93136A6234F98D270627F5AB344157A3527",
57 "C7D13DDB214D0A87B19D2F33D07E3D1952EB145419B92989B4CF3CD47897767B"
58 ]);
59 let m = U1024::from_be_hex(concat![
60 "D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
61 "37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
62 "D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
63 "558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767"
64 ])
65 .to_odd()
66 .unwrap();
67 let expected = U1024::from_be_hex(concat![
68 "24D3C45CFFAF0D5C7620A469C3DC2F3313DDE78A0987F0CEF7EABFF4A5407219",
69 "645BBF1E19580A3619798AAA545597FCA2496DAA2DF4685D313F98F52DD151C3",
70 "48BF956F72C8BDA32FC3F3E5F955226B8D9138C6E64AA568075BA2AEDBE58ED2",
71 "173B01FCA9E1905F9C74589FB3C36D55A4CBCB7FA86CC803BE979091D3F0C431"
72 ]);
73
74 let res = a.inv_odd_mod(&m).unwrap();
75 assert_eq!(res, expected);
76
77 let res = a.inv_mod(&m.to_nz().unwrap()).unwrap();
79 assert_eq!(res, expected);
80 }
81
82 #[test]
83 fn test_invert_even() {
84 let a = I1024::from_be_hex(concat![
85 "FFFDDA166EAC4B985A4BAE6865C0BAE2510C4072939ADE2D05DB444E80D6ABB1",
86 "CB85BED4F9A48A5CAE1568E61DBCF2DB884EE3363063E5291211D934EA0B9C07",
87 "4338D107815CFD7716A5B75586DDD93136A6234F98D270627F5AB344157A3527",
88 "C7D13DDB214D0A87B19D2F33D07E3D1952EB145419B92989B4CF3CD47897767B",
89 ]);
90 let m = U1024::from_be_hex(concat![
91 "D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
92 "37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
93 "D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
94 "558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156000"
95 ])
96 .to_nz()
97 .unwrap();
98 let expected = U1024::from_be_hex(concat![
99 "B64AAE72443C49FD5BE587DDE82A265E8C1226D73E5AE3DC3081E6C5471EE917",
100 "5BC37EF8AE73B8D7F0365652BC335F9BC375EA303381B08D4A15E0CBBF92FDF4",
101 "D58AB97A48B1507553808DC84F9C6F656F39F81D9157AE2E1FD98C487D4D52F8",
102 "F9F1107F0F4064B074637B983CB6672DAD75067A02F0E455DBB6E2CE7D7ED8B3",
103 ]);
104
105 let res = a.inv_mod(&m).unwrap();
106 assert_eq!(res, expected);
107 }
108}