Implement invmod manually

This commit is contained in:
2022-10-15 09:41:10 -04:00
parent 3176f23662
commit 86c28caf12

View File

@@ -70,25 +70,53 @@ pub fn rsa_gen_keys() -> Result<(RsaPublicKey, RsaPrivateKey), ErrorStack> {
}
pub fn invmod(a: &BigNum, n: &BigNum) -> Result<BigNum, ErrorStack> {
//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<BigNum, ErrorStack> {