Path: blob/main/foundations/04-number-theory-rsa/rust/src/lib.rs
483 views
unlisted
//! # Module 04: Number Theory and RSA — Exercises1//!2//! ## Progression3//! 1. `extended_gcd` — Guided (recursive skeleton)4//! 2. `mod_inverse` — Scaffolded (use extended_gcd)5//! 3. `euler_totient` — Scaffolded (factorization hint)6//! 4. `rsa_keygen` — Scaffolded (from given primes)7//! 5. `rsa_encrypt_decrypt` — Independent89/// Compute the extended GCD: returns (gcd, x, y) such that a*x + b*y = gcd.10///11/// # Example12/// ```13/// # use number_theory_rsa::extended_gcd;14/// let (g, x, y) = extended_gcd(35, 15);15/// assert_eq!(g, 5);16/// assert_eq!(35_i64 * x + 15_i64 * y, 5);17/// ```18pub fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {19// Base case: if b == 0, return (a, 1, 0).20// Recursive case:21// let (g, x1, y1) = extended_gcd(b, a % b);22// return (g, y1, x1 - (a / b) * y1);23//24// TODO: implement the recursion (or convert to iterative).25if b == 0 {26return (a, 1, 0);27}28todo!("Recursive step of extended GCD")29}3031/// Compute the modular inverse of `a` mod `m`, if it exists.32///33/// Returns `Some(x)` where `a * x ≡ 1 (mod m)`, or `None` if gcd(a,m) != 1.34///35/// Hint: use `extended_gcd`. If gcd == 1, the inverse is `x mod m`.36pub fn mod_inverse(a: u64, m: u64) -> Option<u64> {37todo!("Use extended_gcd to find modular inverse")38}3940/// Compute Euler's totient φ(n).41///42/// φ(n) = n × ∏(1 - 1/p) for each distinct prime factor p of n.43///44/// For RSA: if n = p*q, then φ(n) = (p-1)(q-1).45///46/// Hint: factor n by trial division up to √n.47pub fn euler_totient(n: u64) -> u64 {48todo!("Compute Euler's totient via trial division")49}5051/// Generate RSA key components from two primes p and q.52///53/// Returns `(n, e, d)` where:54/// - `n = p * q`55/// - `e = 65537` (standard public exponent)56/// - `d = e^(-1) mod φ(n)`57///58/// Panics if e and φ(n) are not coprime.59pub fn rsa_keygen(p: u64, q: u64) -> (u64, u64, u64) {60todo!("Compute n, e=65537, d from primes p and q")61}6263/// RSA encryption or decryption: compute `msg^key mod n`.64///65/// This works for both encryption (msg^e mod n) and decryption (ciphertext^d mod n).66pub fn rsa_encrypt_decrypt(msg: u64, key: u64, n: u64) -> u64 {67todo!("Modular exponentiation for RSA")68}6970#[cfg(test)]71mod tests {72use super::*;7374#[test]75#[ignore]76fn test_extended_gcd_basic() {77let (g, x, y) = extended_gcd(35, 15);78assert_eq!(g, 5);79assert_eq!(35 * x + 15 * y, 5);80}8182#[test]83#[ignore]84fn test_extended_gcd_coprime() {85let (g, x, y) = extended_gcd(17, 13);86assert_eq!(g, 1);87assert_eq!(17 * x + 13 * y, 1);88}8990#[test]91#[ignore]92fn test_mod_inverse_exists() {93assert_eq!(mod_inverse(3, 7), Some(5)); // 3*5 = 15 ≡ 1 mod 794}9596#[test]97#[ignore]98fn test_mod_inverse_none() {99assert_eq!(mod_inverse(6, 9), None); // gcd(6,9) = 3100}101102#[test]103#[ignore]104fn test_euler_totient() {105assert_eq!(euler_totient(7), 6); // prime106assert_eq!(euler_totient(12), 4); // 12 = 2²×3, φ = 12(1-1/2)(1-1/3) = 4107assert_eq!(euler_totient(15), 8); // 15 = 3×5, φ = (3-1)(5-1) = 8108}109110#[test]111#[ignore]112fn test_rsa_roundtrip() {113let (n, e, d) = rsa_keygen(61, 53);114assert_eq!(n, 3233);115116let plaintext = 42_u64;117let ciphertext = rsa_encrypt_decrypt(plaintext, e, n);118let decrypted = rsa_encrypt_decrypt(ciphertext, d, n);119assert_eq!(decrypted, plaintext);120}121}122123124