Skip to content

Commit 4a686f6

Browse files
author
Nym Seddon
committed
Add invmod algorithm
Add invmod algorithm using Extended Euclidean Algorithm Based on implementation from wolfSSL
1 parent d782512 commit 4a686f6

File tree

3 files changed

+277
-1
lines changed

3 files changed

+277
-1
lines changed

src/algorithms.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,10 @@ fn biguint_shr2(n: Cow<'_, BigUint>, digits: usize, shift: u8) -> BigUint {
900900
biguint_from_vec(data)
901901
}
902902

903+
pub(crate) fn invmod(base: &BigInt, modulus: &BigInt) -> BigInt {
904+
base.invmod(modulus)
905+
}
906+
903907
pub(crate) fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
904908
debug_assert!(a.last() != Some(&0));
905909
debug_assert!(b.last() != Some(&0));
@@ -914,7 +918,8 @@ pub(crate) fn cmp_slice(a: &[BigDigit], b: &[BigDigit]) -> Ordering {
914918
mod algorithm_tests {
915919
use crate::big_digit::BigDigit;
916920
use crate::{BigInt, BigUint};
917-
use num_traits::Num;
921+
use num_integer::Integer;
922+
use num_traits::{Num, One};
918923

919924
#[test]
920925
fn test_sub_sign() {
@@ -933,4 +938,48 @@ mod algorithm_tests {
933938
assert_eq!(sub_sign_i(&a.data[..], &b.data[..]), &a_i - &b_i);
934939
assert_eq!(sub_sign_i(&b.data[..], &a.data[..]), &b_i - &a_i);
935940
}
941+
942+
#[test]
943+
fn test_invmod() {
944+
use super::invmod;
945+
946+
let one = BigInt::one();
947+
948+
let test_modulus = |k| {
949+
for i in [
950+
/*11_u128,*/ 43_u128,
951+
67_u128,
952+
419_u128,
953+
2652528598121910586363_u128,
954+
]
955+
.iter()
956+
{
957+
let e = BigInt::from_bytes_le(super::Plus, i.to_le_bytes().as_ref());
958+
959+
let mut inv_e = invmod(&e, &k);
960+
inv_e *= &e;
961+
inv_e = inv_e.mod_floor(&k);
962+
963+
assert_eq!(inv_e, one);
964+
}
965+
966+
// test 1 / (k + 1) % k
967+
let mut e = k.clone();
968+
e += 1;
969+
let mut inv_e = invmod(&e, &k);
970+
inv_e *= &e;
971+
inv_e = inv_e.mod_floor(&k);
972+
973+
assert_eq!(inv_e, one);
974+
};
975+
976+
// Test even modulus
977+
// TODO: for some reason 11 has no inverse mod 265252859812191058636308480000000
978+
let mut k = BigInt::from_str_radix("265252859812191058636308480000000", 10).unwrap();
979+
test_modulus(k.clone());
980+
981+
// Test odd modulus
982+
k += 1_u32;
983+
test_modulus(k);
984+
}
936985
}

src/bigint.rs

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,6 +3231,223 @@ impl BigInt {
32313231
BigInt::from_biguint(sign, mag)
32323232
}
32333233

3234+
/// Returns `(1 / self) % modulus` using Extended Euclidean Algorithm
3235+
///
3236+
/// Panics if self and modulus are both even, either is zero, |self| == modulus, or no inverse is found
3237+
///
3238+
/// From wolfSSL implementation: fp_invmod, fp_invmod_slow
3239+
/// https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/tfm.c
3240+
pub fn invmod(&self, modulus: &Self) -> Self {
3241+
if modulus.is_even() {
3242+
return self.invmod_slow(modulus);
3243+
}
3244+
3245+
if self.is_zero() || modulus.is_zero() {
3246+
panic!("base and/or modulus cannot be zero");
3247+
}
3248+
3249+
if self.abs() == *modulus {
3250+
panic!("cannot invert |a| == modulus");
3251+
}
3252+
3253+
let x = modulus;
3254+
let y = if self > modulus {
3255+
self.mod_floor(modulus)
3256+
} else {
3257+
self.clone()
3258+
};
3259+
3260+
/* 3. u=x, v=y, B=0, D=1 */
3261+
3262+
/* x == modulus, y == value to invert */
3263+
let mut u = x.clone();
3264+
/* we need y = |a| */
3265+
let mut v = y.abs();
3266+
3267+
let mut bb = Self::zero();
3268+
let mut bd = Self::one();
3269+
3270+
// here an infinite loop takes the place of `goto top`
3271+
// where a condition calls for `goto top`, simply continue
3272+
//
3273+
// NOTE: need to be cautious to always break/return, else infinite loop
3274+
loop {
3275+
/* 4. while u is even do */
3276+
while u.is_even() {
3277+
/* 4.1 u = u / 2 */
3278+
u /= 2_u32;
3279+
3280+
/* 4.2 if B is odd then */
3281+
if bb.is_odd() {
3282+
/* B = (B-x)/2 */
3283+
bb -= x;
3284+
}
3285+
3286+
/* B = B/2 */
3287+
bb /= 2_u32;
3288+
}
3289+
3290+
/* 5. while v is even do */
3291+
while v.is_even() {
3292+
/* 5.1 v = v/2 */
3293+
v /= 2_u32;
3294+
3295+
/* 5.2 if D is odd then */
3296+
if bd.is_odd() {
3297+
/* D = (D-x)/2 */
3298+
bd -= x;
3299+
}
3300+
3301+
/* D = D/2 */
3302+
bd /= 2_u32;
3303+
}
3304+
3305+
/* 6. if u >= v then */
3306+
if u >= v {
3307+
/* u = u - v, B = B - D */
3308+
u -= &v;
3309+
bb -= &bd;
3310+
} else {
3311+
/* v = v - u, D = D - B */
3312+
v -= &u;
3313+
bd -= &bb;
3314+
}
3315+
3316+
/* if u != 0, goto step 4 */
3317+
if !u.is_zero() {
3318+
continue;
3319+
}
3320+
3321+
/* now a = B, b = D, gcd == g*v */
3322+
if !v.is_one() {
3323+
// if v != 1, there is no inverse
3324+
panic!("no inverse, GCD != 1");
3325+
}
3326+
3327+
/* while D is too low */
3328+
while bd.sign() == Minus {
3329+
bd += modulus;
3330+
}
3331+
3332+
/* while D is too big */
3333+
let mod_mag = modulus.magnitude();
3334+
while bd.magnitude() >= mod_mag {
3335+
bd -= modulus;
3336+
}
3337+
3338+
if self.sign() == Minus {
3339+
bd = bd.neg();
3340+
}
3341+
3342+
/* D is now the inverse */
3343+
break;
3344+
}
3345+
3346+
bd
3347+
}
3348+
3349+
fn invmod_slow(&self, modulus: &Self) -> Self {
3350+
if self.is_even() && modulus.is_even() {
3351+
panic!("base and modulus are both even");
3352+
}
3353+
3354+
if self.is_zero() || modulus.is_zero() {
3355+
panic!("base and/or modulus cannot be zero");
3356+
}
3357+
3358+
let x = self.mod_floor(modulus);
3359+
let y = modulus;
3360+
3361+
/* 3. u=x, v=y, A=1, B=0, C=0, D-1 */
3362+
let mut u = x.clone();
3363+
let mut v = y.clone();
3364+
let mut ba = Self::one();
3365+
let mut bb = Self::zero();
3366+
let mut bc = Self::zero();
3367+
let mut bd = Self::one();
3368+
3369+
// here an infinite loop takes the place of `goto top`
3370+
// where a condition calls for `goto top`, simply continue
3371+
//
3372+
// NOTE: need to be cautious to always break/return, else infinite loop
3373+
loop {
3374+
/* 4. while u is even do */
3375+
while u.is_even() {
3376+
/* 4.1 u = u / 2 */
3377+
u /= 2_u32;
3378+
3379+
/* 4.2 if A or B is odd then */
3380+
if ba.is_odd() || bb.is_odd() {
3381+
/* A = (A+y)/2, B = (B-x)/2*/
3382+
// div 2 happens unconditionally below
3383+
ba += y;
3384+
bb -= &x;
3385+
}
3386+
3387+
ba /= 2_u32;
3388+
bb /= 2_u32;
3389+
}
3390+
3391+
/* 5. while v is even do */
3392+
while v.is_even() {
3393+
/* 5.1 v = v / 2 */
3394+
v /= 2_u32;
3395+
3396+
/* 5.2 if C or D is odd then */
3397+
if bc.is_odd() || bd.is_odd() {
3398+
/* C = (C+y)/2, D = (D-x)/2 */
3399+
// div 2 happens unconditionally below
3400+
bc += y;
3401+
bd -= &x;
3402+
}
3403+
3404+
/* C = C/2, D = D/2 */
3405+
bc /= 2_u32;
3406+
bd /= 2_u32;
3407+
}
3408+
3409+
/* 6. if u >= v then */
3410+
if u >= v {
3411+
/* u = u - v, A = A - C, B = B - D */
3412+
u -= &v;
3413+
ba -= &bc;
3414+
bb -= &bd;
3415+
} else {
3416+
/* v = v - u, C = C - A, D = D - B */
3417+
v -= &u;
3418+
bc -= &ba;
3419+
bd -= &bb;
3420+
}
3421+
3422+
/* if u != 0, goto step 4 */
3423+
if !u.is_zero() {
3424+
continue;
3425+
}
3426+
3427+
/* now a = C, b = D, gcd == g*v */
3428+
if !v.is_one() {
3429+
// if v != 1, there is no inverse
3430+
panic!("no inverse, GCD != 1");
3431+
}
3432+
3433+
/* while C is too low */
3434+
while bc.sign() == Minus {
3435+
bc += y;
3436+
}
3437+
3438+
/* while C is too big */
3439+
let mod_mag = y.magnitude();
3440+
while bc.magnitude() > mod_mag {
3441+
bc -= y;
3442+
}
3443+
3444+
/* C is now the inverse */
3445+
break;
3446+
}
3447+
3448+
bc
3449+
}
3450+
32343451
/// Returns the truncated principal square root of `self` --
32353452
/// see [Roots::sqrt](https://docs.rs/num-integer/0.1/num_integer/trait.Roots.html#method.sqrt).
32363453
pub fn sqrt(&self) -> Self {

src/biguint.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod algorithms;
3232
#[path = "monty.rs"]
3333
mod monty;
3434

35+
use self::algorithms::invmod;
3536
use self::algorithms::{__add2, __sub2rev, add2, sub2, sub2rev};
3637
use self::algorithms::{biguint_shl, biguint_shr};
3738
use self::algorithms::{cmp_slice, fls, ilog2};
@@ -2674,6 +2675,15 @@ impl BigUint {
26742675
}
26752676
}
26762677

2678+
/// Return `(1 / self) % modulus` using Extended Euclidean Algorithm.
2679+
///
2680+
/// Panics if self and the modulus are both even, either is zero, |self| == modulus, or no inverse is found
2681+
pub fn invmod(&self, modulus: &Self) -> Self {
2682+
invmod(&self.clone().into(), &modulus.clone().into())
2683+
.into_parts()
2684+
.1
2685+
}
2686+
26772687
/// Returns the truncated principal square root of `self` --
26782688
/// see [Roots::sqrt](https://docs.rs/num-integer/0.1/num_integer/trait.Roots.html#method.sqrt)
26792689
pub fn sqrt(&self) -> Self {

0 commit comments

Comments
 (0)