use advanced_algorithms::number_theory::{miller_rabin, extended_euclidean, mersenne_twister};
fn main() {
println!("=== Number Theory & Cryptography Demo ===\n");
println!("=== Miller-Rabin Primality Test ===");
let test_numbers = vec![
(17, true),
(561, false), (1_000_000_007, true),
(1_000_000_009, true),
(1_000_000_000, false),
];
println!("Testing primality:");
for (n, expected) in test_numbers {
let is_prime = miller_rabin::is_prime(n, 20);
let symbol = if is_prime { "✓" } else { "✗" };
println!(" {} {} - {}", symbol, n, if is_prime { "prime" } else { "composite" });
assert_eq!(is_prime, expected);
}
println!("\nGenerating random primes:");
for bits in [16, 20, 24] {
let prime = miller_rabin::generate_prime(bits, 20);
let verified = miller_rabin::is_prime_deterministic(prime);
println!(" {}-bit prime: {} (verified: {})", bits, prime, verified);
}
println!("\n=== Simulated RSA Key Generation ===");
let p = miller_rabin::generate_prime(16, 20);
let q = miller_rabin::generate_prime(16, 20);
let n = p * q;
let phi = (p - 1) * (q - 1);
println!("Prime p: {}", p);
println!("Prime q: {}", q);
println!("Modulus n = p*q: {}", n);
println!("φ(n) = (p-1)(q-1): {}", phi);
let e = 65537i64;
match extended_euclidean::mod_inverse(e, phi as i64) {
Ok(d) => {
println!("\nPublic key: (e={}, n={})", e, n);
println!("Private key: (d={}, n={})", d, n);
let verify = (e * d) % phi as i64;
println!("Verification: e*d mod φ(n) = {} (should be 1)", verify);
}
Err(e) => println!("Error computing private key: {}", e),
}
println!("\n=== Extended Euclidean Algorithm ===");
let a = 240;
let b = 46;
let result = extended_euclidean::extended_gcd(a, b);
println!("GCD({}, {}):", a, b);
println!(" gcd = {}", result.gcd);
println!(" Bézout coefficients: x = {}, y = {}", result.x, result.y);
println!(" Verification: {}*{} + {}*{} = {}",
a, result.x, b, result.y, a * result.x + b * result.y);
println!("\nModular Inverses:");
let examples = vec![(3, 11), (7, 26), (17, 43)];
for (a, m) in examples {
match extended_euclidean::mod_inverse(a, m) {
Ok(inv) => {
println!(" {}^(-1) mod {} = {} (verify: {}*{} mod {} = {})",
a, m, inv, a, inv, m, (a * inv) % m);
}
Err(_) => {
println!(" {}^(-1) mod {} doesn't exist (not coprime)", a, m);
}
}
}
println!("\nSolving Linear Congruences:");
let solutions = extended_euclidean::solve_linear_congruence(3, 6, 9);
if !solutions.is_empty() {
println!(" 3x ≡ 6 (mod 9):");
println!(" Solutions: {:?}", solutions);
for &x in &solutions {
println!(" Verify: 3*{} mod 9 = {}", x, (3 * x) % 9);
}
}
println!("\nGCD and LCM:");
let numbers = vec![48, 18, 30];
let gcd_result = extended_euclidean::gcd_multiple(&numbers);
let lcm_result = extended_euclidean::lcm_multiple(&numbers);
println!(" Numbers: {:?}", numbers);
println!(" GCD: {}", gcd_result);
println!(" LCM: {}", lcm_result);
println!("\n=== Mersenne Twister PRNG ===");
let mut rng = mersenne_twister::MersenneTwister::new(12345);
println!("Random integers:");
for i in 0..5 {
println!(" {}: {}", i + 1, rng.next_u32());
}
println!("\nRandom floats [0, 1):");
for i in 0..5 {
println!(" {}: {:.6}", i + 1, rng.next_f64());
}
println!("\nRandom range [0, 100):");
for i in 0..5 {
println!(" {}: {}", i + 1, rng.next_range(100));
}
println!("\nGaussian (normal) distribution:");
let mut sum = 0.0;
let mut sum_sq = 0.0;
let n = 10000;
for _ in 0..n {
let x = rng.next_gaussian();
sum += x;
sum_sq += x * x;
}
let mean = sum / n as f64;
let variance = (sum_sq / n as f64) - (mean * mean);
let stddev = variance.sqrt();
println!(" Generated {} samples", n);
println!(" Mean: {:.4} (expected: 0.0)", mean);
println!(" Std dev: {:.4} (expected: 1.0)", stddev);
println!("\nReproducibility test:");
let mut rng1 = mersenne_twister::MersenneTwister::new(42);
let mut rng2 = mersenne_twister::MersenneTwister::new(42);
let same = (0..10).all(|_| rng1.next_u32() == rng2.next_u32());
println!(" Same seed produces same sequence: {}", same);
println!("\nUniformity test:");
let mut rng = mersenne_twister::MersenneTwister::new(999);
let mut buckets = vec![0; 10];
let total = 100000;
for _ in 0..total {
let val = rng.next_f64();
let bucket = (val * 10.0) as usize;
if bucket < 10 {
buckets[bucket] += 1;
}
}
println!(" Distribution across 10 buckets ({} samples):", total);
for (i, &count) in buckets.iter().enumerate() {
let expected = total / 10;
let deviation = ((count as f64 - expected as f64) / expected as f64 * 100.0).abs();
println!(" Bucket {}: {} ({:.1}% deviation from expected)",
i, count, deviation);
}
}