use 16-bit n and add comments

This commit is contained in:
theBreadCompany 2024-12-04 13:56:14 +01:00
parent b8775f3675
commit 450131c6fa
2 changed files with 48 additions and 26 deletions

View file

@ -1,7 +1,11 @@
mod pollard_rho; mod pollard_rho;
fn main() { fn main() {
let n = rand::random::<u8>(); let mut n = 0;
while n % 2 == 0 { n = rand::random::<u16>(); }
let n_primediv = pollard_rho::pollard_rho(n.into()); let n_primediv = pollard_rho::pollard_rho(n.into());
eprintln!("Generated random number {}, got prime divisor {}", n, n_primediv); eprintln!(
"Generated random number {}, got prime divisor {}",
n, n_primediv
);
} }

View file

@ -1,53 +1,71 @@
use gcd::Gcd; use gcd::Gcd;
/** /**
* Calculate the primedivisor for some number `n` * Calculate the prime divisor for some number `n`
*
* Uses cycle finding
*/ */
pub fn pollard_rho(n: u16) -> u16 { pub fn pollard_rho(n: u32) -> u32 {
if n == 1 { return 1; } // 1 only has 1 as prime divisor if n == 1 {
if n % 2 == 0 { return 2; } // even numbers have at least 2 as prime divisor return 1;
if is_prime(n) { return n; } } // 1 only has 1 as prime divisor
if n % 2 == 0 {
return 2;
} // even numbers have at least 2 as prime divisor
if is_prime(n) {
return n;
} // need to detect to be able to decide if we have bad random numbers or the
let mut x = rand::random::<u16>() % 2; let mut x = rand::random::<u32>() % n; // cycle finding: tortoise
let mut y = x; let mut y = x; // cycle finding: hare
let c = rand::random::<u16>() % 2; let c = rand::random::<u32>() % n; // random number to add to the cycle finding moves
let mut div = 1; let mut div = 1; // divisor - 1 applies to all numbers and is our failed and start value
while div == 1 { while div == 1 {
// tortoise move
x = (mod_pow(x, 2, n) + c + n) % n; x = (mod_pow(x, 2, n) + c + n) % n;
// hare move
y = (mod_pow(y, 2, n) + c + n) % n; y = (mod_pow(y, 2, n) + c + n) % n;
y = (mod_pow(y, 2, n) + c + n) % n; y = (mod_pow(y, 2, n) + c + n) % n;
div = u16::try_from((i16::try_from(x).unwrap()-i16::try_from(y).unwrap()).abs()).unwrap().gcd(n); // divisor is the greatest common divisor between |x-y| and n
eprintln!("Got div {}", div); div = u32::try_from((i32::try_from(x).unwrap() - i32::try_from(y).unwrap()).abs())
if div == n { return pollard_rho(n); } .unwrap()
.gcd(n);
// bad random numbers, try again
if div == n {
return pollard_rho(n);
}
} }
return div; div
} }
/** /**
* Discrete/Modular exponentiation * Discrete/Modular exponentiation
* *
* Highly memory efficient because the full result is never stored, but shortened by defined modulo instead. * Highly memory efficient because the full result is never stored, but shortened by defined modulo instead.
* We can use that because the prime divisor required for our algorithm is guarenteed to be smaller * We can use that because the prime divisor required for our algorithm is guarenteed to be smaller
* than n. * than n.
* *
* Counterpart function to the discrete logarithm. * Counterpart function to the discrete logarithm.
*/ */
fn mod_pow(base: u16, exp: u16, r#mod: u16) -> u16 { fn mod_pow(base: u32, exp: u32, r#mod: u32) -> u32 {
let mut result = 1; let mut result = 1;
for _ in 0..exp - 1 {
for _ in 0..exp-1 {
result = (result * base) % r#mod; result = (result * base) % r#mod;
} }
result result
} }
fn is_prime(n: u16) -> bool { /**
for i in (3..=(n as f32).sqrt() as u16).step_by(2) { * very primitive prime checker
if n % i == 0 { return false; } */
fn is_prime(n: u32) -> bool {
for i in (3..=(n as f32).sqrt() as u32).step_by(2) {
if n % i == 0 {
return false;
}
} }
true true
} }