diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 9c8fa07..f2fce95 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "TPNSM" +name = "crypto_test" version = "0.1.0" edition = "2021" @@ -7,4 +7,5 @@ edition = "2021" [dependencies] num = "0.4" -rayon = "1.5.3" \ No newline at end of file +rayon = "1.5" +rand = "0.8" \ No newline at end of file diff --git a/rust/algo.md b/rust/algo.md index b79d918..6466e89 100644 --- a/rust/algo.md +++ b/rust/algo.md @@ -1,2 +1,22 @@ -Elliptic_curve_primality -![image](./pictures/ecp.png) \ No newline at end of file +# Primality tests + +
+Elliptic curve + + +![image](./pictures/ecp.png) +
+ +
+Miller–Rabin + + +![image](./pictures/mrp.png) +
+ + +Baillie–PSW + +AKS + +Adleman–Pomerance–Rumely \ No newline at end of file diff --git a/rust/pictures/mrp.png b/rust/pictures/mrp.png new file mode 100644 index 0000000..27689a2 Binary files /dev/null and b/rust/pictures/mrp.png differ diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 94a8f2f..edcf95f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,2 +1,2 @@ pub mod prime; -pub mod utils; \ No newline at end of file +pub mod utils; diff --git a/rust/src/main.rs b/rust/src/main.rs index 8a2b537..e7a11a9 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,15 +1,3 @@ -use TPNSM::prime::{prime_classical, prime_dumb_rayon}; - fn main() { println!("Hello, world!"); - - let max = 1000000; - find_prime(prime_classical(max)); - //find_prime(prime_dumb_rayon(max)); } - -fn find_prime(primes: Vec) { - //println!("{:?}", primes); - println!("{:?}", primes.last()); - println!("{}", primes.len()); -} \ No newline at end of file diff --git a/rust/src/prime.rs b/rust/src/prime.rs index a3afcc2..a9bb46a 100644 --- a/rust/src/prime.rs +++ b/rust/src/prime.rs @@ -1,17 +1,60 @@ +use crate::utils::fast_exp; use num::integer::sqrt; +use rand::{thread_rng, Rng}; use rayon::prelude::*; +pub fn miller_rabbin_gen(max: u32, acr: u32) -> Vec { + let method = |n| miller_rabbin_test(n, acr); + prime_gen(max, method) +} + +pub fn miller_rabbin_test(n: u32, acr: u32) -> bool { + if n % 2 == 0 { + false + } else { + let (k, q) = find_2_k_q(n - 1); + let mut random = thread_rng(); + + 'l: for _ in 0..acr { + let a = random.gen_range(1..n - 1); + let mut x = fast_exp(a, q, n); + + if x != 1 && x != n - 1 { + for _ in 0..k - 1 { + x = fast_exp(x, 2, n); + if x == n - 1 { + continue 'l; + } + } + return false; + } + } + true + } +} + +fn find_2_k_q(mut n: u32) -> (u32, u32) { + let mut k = 0; + while n % 2 == 0 { + n /= 2; + k += 1; + } + (k, n) +} + fn prime_gen(max: u32, method: F) -> Vec - where F: Fn(u32) -> bool { +where + F: Fn(u32) -> bool, +{ let mut primes = vec![2_u32]; - let mut i = 1; + let mut i = 3; while i < max { - i += 2; let prime = method(i); if prime { primes.push(i); } + i += 2; } primes } @@ -19,7 +62,7 @@ fn prime_gen(max: u32, method: F) -> Vec pub fn prime_classical(max: u32) -> Vec { let mut primes = vec![2_u32]; let mut i = 1; - 'l: while i < max { + 'l: while i + 2 < max { i += 2; for p in &primes { if i % p == 0 { @@ -35,16 +78,53 @@ pub fn prime_classical(max: u32) -> Vec { pub fn prime_dumb_rayon(max: u32) -> Vec { let mut primes = vec![2_u32]; - let mut i = 1; + let mut i = 3; while i < max { - i += 2; - let found = primes.par_iter() - .filter(|x| { **x <= sqrt(i) }) - .any(|x| { i % *x == 0 }); + let found = primes + .par_iter() + .filter(|x| **x <= sqrt(i)) + .any(|x| i % *x == 0); if !found { primes.push(i); } + i += 2; } primes -} \ No newline at end of file +} +#[cfg(test)] +mod tests { + use super::*; + const PRIME_TEST: [(u32, u32); 6] = [ + (10, 7), + (100, 97), + (500, 499), + (1000, 997), + (8300, 8297), + (10000, 9973), + ]; + + #[test] + fn test_prime_classical() { + for (max, prem) in PRIME_TEST { + assert_eq!(prime_classical(max).last(), Some(&prem)); + } + } + + #[test] + fn test_prime_dumb_rayon() { + for (max, prem) in PRIME_TEST { + assert_eq!(prime_dumb_rayon(max).last(), Some(&prem)); + } + } + + #[test] + fn test_miller_rabbin() { + for (max, prem) in PRIME_TEST { + assert_eq!(miller_rabbin_gen(max, 10).last(), Some(&prem)); + } + + assert!(!miller_rabbin_test(2147483649, 10)); + assert!(miller_rabbin_test(2147483647, 10)); + } +} diff --git a/rust/src/utils.rs b/rust/src/utils.rs index be52dae..bb5828d 100644 --- a/rust/src/utils.rs +++ b/rust/src/utils.rs @@ -48,7 +48,6 @@ pub fn congruent(a: i32, b: i32, n: i32) -> bool { (a - b) % n == 0 } - pub fn gcd_euclid(mut a: u32, mut b: u32) -> u32 { let mut r = a % b; while r != 0 { @@ -79,6 +78,23 @@ pub fn modular_inverse(a: u32, n: u32) -> Option { Some(t as u32) } +pub fn fast_exp(mut b: u32, mut e: u32, m: u32) -> u32 { + if m == 1 { + return 0; + } + let mut result = 1; + + b %= m; + while e > 0 { + if e % 2 == 1 { + result = (result as u64 * b as u64 % m as u64) as u32; + } + e >>= 1; + b = (b as u64 * b as u64 % m as u64) as u32; + } + result +} + #[cfg(test)] mod tests { use super::*; @@ -124,4 +140,12 @@ mod tests { assert_eq!(modular_inverse(10, 19), Some(2)); assert_eq!(modular_inverse(4, 6), None); } -} \ No newline at end of file + + #[test] + fn test_fast_exp() { + assert_eq!(fast_exp(5, 3, 13), 8); + assert_eq!(fast_exp(11, 13, 19), 11); + assert_eq!(fast_exp(1234, 754, 452), 392); + assert_eq!(fast_exp(76158, 24586, 5364), 576); + } +}