Skip to content

Commit eb2c00a

Browse files
committed
Introduce int::inv_mod
1 parent 87b3841 commit eb2c00a

File tree

3 files changed

+121
-13
lines changed

3 files changed

+121
-13
lines changed

src/int.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod cmp;
2020
mod div;
2121
mod encoding;
2222
mod from;
23+
mod inv_mod;
2324
mod mul;
2425
mod neg;
2526
mod resize;

src/int/inv_mod.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! Operations related to computing the inverse of an [`Int`] modulo a [`Uint`].
2+
3+
use subtle::CtOption;
4+
5+
use crate::modular::SafeGcdInverter;
6+
use crate::{ConstantTimeSelect, Int, InvMod, NonZero, Odd, PrecomputeInverter, Uint};
7+
8+
impl<const LIMBS: usize, const UNSAT_LIMBS: usize> Int<LIMBS>
9+
where
10+
Odd<Uint<LIMBS>>: PrecomputeInverter<Inverter = SafeGcdInverter<LIMBS, UNSAT_LIMBS>>,
11+
{
12+
/// Computes the multiplicative inverse of `self` mod `modulus`, where `modulus` is odd.
13+
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+
// Note: when `self` is negative and modulus is non-zero, then
18+
// self^{-1} % modulus = modulus - |self|^{-1} % modulus
19+
CtOption::ct_select(
20+
&abs_inv,
21+
&abs_inv.map(|abs_inv| modulus.wrapping_sub(&abs_inv)),
22+
sgn.into(),
23+
)
24+
}
25+
}
26+
27+
impl<const LIMBS: usize, const UNSAT_LIMBS: usize> InvMod<NonZero<Uint<LIMBS>>, Uint<LIMBS>>
28+
for Int<LIMBS>
29+
where
30+
Odd<Uint<LIMBS>>: PrecomputeInverter<Inverter = SafeGcdInverter<LIMBS, UNSAT_LIMBS>>,
31+
{
32+
fn inv_mod(&self, modulus: &NonZero<Uint<LIMBS>>) -> CtOption<Uint<LIMBS>> {
33+
let (abs, sgn) = self.abs_sign();
34+
let abs_inv = abs.inv_mod(modulus).into();
35+
36+
// Note: when `self` is negative and modulus is non-zero, then
37+
// self^{-1} % modulus = modulus - |self|^{-1} % modulus
38+
CtOption::ct_select(
39+
&abs_inv,
40+
&abs_inv.map(|abs_inv| modulus.wrapping_sub(&abs_inv)),
41+
sgn.into(),
42+
)
43+
}
44+
}
45+
46+
#[cfg(test)]
47+
mod tests {
48+
use crate::{InvMod, I1024, U1024};
49+
50+
#[test]
51+
fn test_invert_odd() {
52+
let a = I1024::from_be_hex(concat![
53+
"FFFDDA166EAC4B985A4BAE6865C0BAE2510C4072939ADE2D05DB444E80D6ABB1",
54+
"CB85BED4F9A48A5CAE1568E61DBCF2DB884EE3363063E5291211D934EA0B9C07",
55+
"4338D107815CFD7716A5B75586DDD93136A6234F98D270627F5AB344157A3527",
56+
"C7D13DDB214D0A87B19D2F33D07E3D1952EB145419B92989B4CF3CD47897767B"
57+
]);
58+
let m = U1024::from_be_hex(concat![
59+
"D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
60+
"37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
61+
"D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
62+
"558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156767"
63+
])
64+
.to_odd()
65+
.unwrap();
66+
let expected = U1024::from_be_hex(concat![
67+
"24D3C45CFFAF0D5C7620A469C3DC2F3313DDE78A0987F0CEF7EABFF4A5407219",
68+
"645BBF1E19580A3619798AAA545597FCA2496DAA2DF4685D313F98F52DD151C3",
69+
"48BF956F72C8BDA32FC3F3E5F955226B8D9138C6E64AA568075BA2AEDBE58ED2",
70+
"173B01FCA9E1905F9C74589FB3C36D55A4CBCB7FA86CC803BE979091D3F0C431"
71+
]);
72+
73+
let res = a.inv_odd_mod(&m).unwrap();
74+
assert_eq!(res, expected);
75+
76+
// Even though it is less efficient, it still works
77+
let res = a.inv_mod(&m.to_nz().unwrap()).unwrap();
78+
assert_eq!(res, expected);
79+
}
80+
81+
#[test]
82+
fn test_invert_even() {
83+
let a = I1024::from_be_hex(concat![
84+
"FFFDDA166EAC4B985A4BAE6865C0BAE2510C4072939ADE2D05DB444E80D6ABB1",
85+
"CB85BED4F9A48A5CAE1568E61DBCF2DB884EE3363063E5291211D934EA0B9C07",
86+
"4338D107815CFD7716A5B75586DDD93136A6234F98D270627F5AB344157A3527",
87+
"C7D13DDB214D0A87B19D2F33D07E3D1952EB145419B92989B4CF3CD47897767B",
88+
]);
89+
let m = U1024::from_be_hex(concat![
90+
"D509E7854ABDC81921F669F1DC6F61359523F3949803E58ED4EA8BC16483DC6F",
91+
"37BFE27A9AC9EEA2969B357ABC5C0EE214BE16A7D4C58FC620D5B5A20AFF001A",
92+
"D198D3155E5799DC4EA76652D64983A7E130B5EACEBAC768D28D589C36EC749C",
93+
"558D0B64E37CD0775C0D0104AE7D98BA23C815185DD43CD8B16292FD94156000"
94+
])
95+
.to_nz()
96+
.unwrap();
97+
let expected = U1024::from_be_hex(concat![
98+
"B64AAE72443C49FD5BE587DDE82A265E8C1226D73E5AE3DC3081E6C5471EE917",
99+
"5BC37EF8AE73B8D7F0365652BC335F9BC375EA303381B08D4A15E0CBBF92FDF4",
100+
"D58AB97A48B1507553808DC84F9C6F656F39F81D9157AE2E1FD98C487D4D52F8",
101+
"F9F1107F0F4064B074637B983CB6672DAD75067A02F0E455DBB6E2CE7D7ED8B3",
102+
]);
103+
104+
let res = a.inv_mod(&m).unwrap();
105+
assert_eq!(res, expected);
106+
}
107+
}

src/traits.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
//! Traits provided by this crate
22
3-
mod sealed;
4-
5-
pub use num_traits::{
6-
ConstZero, WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
7-
};
8-
9-
pub(crate) use sealed::PrecomputeInverterWithAdjuster;
10-
11-
use crate::{Limb, NonZero, Odd, Reciprocal};
123
use core::fmt::{self, Debug};
134
use core::ops::{
145
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
156
Mul, MulAssign, Neg, Not, Rem, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
167
};
8+
9+
pub use num_traits::{
10+
ConstZero, WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
11+
};
12+
#[cfg(feature = "rand_core")]
13+
use rand_core::CryptoRngCore;
1714
use subtle::{
1815
Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
1916
CtOption,
2017
};
2118

22-
#[cfg(feature = "rand_core")]
23-
use rand_core::CryptoRngCore;
19+
pub(crate) use sealed::PrecomputeInverterWithAdjuster;
20+
21+
use crate::{Limb, NonZero, Odd, Reciprocal};
22+
23+
mod sealed;
2424

2525
/// Integers whose representation takes a bounded amount of space.
2626
pub trait Bounded {
@@ -443,9 +443,9 @@ pub trait MulMod<Rhs = Self> {
443443
}
444444

445445
/// Compute `1 / self mod p`.
446-
pub trait InvMod: Sized {
446+
pub trait InvMod<Rhs = Self, Output = Self>: Sized {
447447
/// Compute `1 / self mod p`.
448-
fn inv_mod(&self, p: &Self) -> CtOption<Self>;
448+
fn inv_mod(&self, p: &Rhs) -> CtOption<Output>;
449449
}
450450

451451
/// Checked addition.

0 commit comments

Comments
 (0)