From 86c28caf12bcf286dee58c9c2f85dddeffe14654 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Sat, 15 Oct 2022 09:41:10 -0400 Subject: [PATCH] Implement invmod manually --- src/rsa.rs | 56 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/rsa.rs b/src/rsa.rs index b4e7c2a..0c7d2b1 100644 --- a/src/rsa.rs +++ b/src/rsa.rs @@ -70,25 +70,53 @@ pub fn rsa_gen_keys() -> Result<(RsaPublicKey, RsaPrivateKey), ErrorStack> { } pub fn invmod(a: &BigNum, n: &BigNum) -> Result { - //let zero = BigNum::from_u32(0)?; + fn extended_gcd(a: BigNum, b: BigNum) -> Result<(BigNum, BigNum, BigNum), ErrorStack> { + // credit: https://www.dcode.fr/extended-gcd + // r1 = b, r2 = a, u1 = 0, v1 = 1, u2 = 1, v2 = 0 + let mut r1 = b; + let mut r2 = a; + let mut u1 = BigNum::from_u32(0)?; + let mut v1 = BigNum::from_u32(1)?; + let mut u2 = BigNum::from_u32(1)?; + let mut v2 = BigNum::from_u32(0)?; - //let gcd_extended = |a: &mut BigNum, b: &mut BigNum| -> (BigNum, BigNum, BigNum) { - // if *a == zero { - // return ( - // BigNum::from_u32(0).unwrap(), - // BigNum::from_u32(1).unwrap(), - // b); - // } - // ( - // BigNum::from_u32(0).unwrap(), - // BigNum::from_u32(1).unwrap(), - // b) - //} + // while (r2! = 0) do + while r2.num_bits() != 0 { + // q = r1 รท r2 (integer division) + let q = &r1 / &r2; + + // r3 = r1, u3 = u1, v3 = v1, + let r3 = r1; + let u3 = u1; + let v3 = v1; + + // r1 = r2, u1 = u2, v1 = v2, + r1 = r2; + u1 = u2; + v1 = v2; + + // r2 = r3 - q * r2, u2 = u3 - q * u2, v2 = v3 - q * v2 + r2 = &r3 - &(&q * &r1); + u2 = &u3 - &(&q * &u1); + v2 = &v3 - &(&q * &v1); + } + + // return (r1, u1, v1) (r1 natural integer and u1, v1 rational integers) + Ok((r1, u1, v1)) + } + + // No, couldn't think of a worse way to do that. + let a_cloned = BigNum::from_hex_str(&a.to_hex_str()?)?; + let n_cloned = BigNum::from_hex_str(&n.to_hex_str()?)?; + + let (_, u1, _) = extended_gcd(a_cloned, n_cloned)?; + let r_manual = &(&(&u1 % n) + n) % n; let mut ctx = BigNumContext::new()?; let mut r = BigNum::new()?; r.mod_inverse(&a, &n, &mut ctx)?; - Ok(r) + assert_eq!(r_manual, r, "invmod implementation incorrect"); + Ok(r_manual) } pub fn rsa_encrypt(m: &BigNum, p: &RsaPublicKey) -> Result {