| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| use crate::{AlgorithmError, AlgorithmResult}; |
| use std::f64::consts::PI; |
|
|
| |
| pub struct ModularExponentiation { |
| |
| pub a: u64, |
|
|
| |
| pub n: u64, |
|
|
| |
| pub x: u64, |
| } |
|
|
| impl ModularExponentiation { |
| |
| pub fn new(a: u64, n: u64) -> AlgorithmResult<Self> { |
| if n == 0 { |
| return Err(AlgorithmError::InvalidParameters("N must be nonzero".to_string())); |
| } |
| if a >= n { |
| return Err(AlgorithmError::InvalidParameters( |
| "Base must be less than N".to_string(), |
| )); |
| } |
|
|
| Ok(ModularExponentiation { a, n, x: 0 }) |
| } |
|
|
| |
| pub fn compute(&self, x: u64) -> u64 { |
| modpow(self.a, x, self.n) |
| } |
|
|
| |
| pub fn circuit_depth(&self) -> usize { |
| |
| let bits = (self.n as f64).log2().ceil() as usize; |
| 3 * bits * bits |
| } |
| } |
|
|
| |
| fn modpow(mut a: u64, mut b: u64, m: u64) -> u64 { |
| let mut result = 1u64; |
| a %= m; |
|
|
| while b > 0 { |
| if b & 1 == 1 { |
| result = ((result as u128 * a as u128) % m as u128) as u64; |
| } |
| b >>= 1; |
| a = ((a as u128 * a as u128) % m as u128) as u64; |
| } |
|
|
| result |
| } |
|
|
| |
| fn gcd(mut a: u64, mut b: u64) -> u64 { |
| while b != 0 { |
| let temp = b; |
| b = a % b; |
| a = temp; |
| } |
| a |
| } |
|
|
| |
| #[derive(Debug, Clone)] |
| pub struct PeriodFinding { |
| |
| pub a: u64, |
|
|
| |
| pub n: u64, |
|
|
| |
| pub period: Option<u64>, |
| } |
|
|
| impl PeriodFinding { |
| |
| pub fn new(a: u64, n: u64) -> AlgorithmResult<Self> { |
| if gcd(a, n) != 1 { |
| return Err(AlgorithmError::InvalidParameters( |
| "a and N must be coprime".to_string(), |
| )); |
| } |
|
|
| Ok(PeriodFinding { |
| a, |
| n, |
| period: None, |
| }) |
| } |
|
|
| |
| pub fn find_period_classical(&mut self) -> AlgorithmResult<u64> { |
| for r in 1..=self.n { |
| if modpow(self.a, r, self.n) == 1 { |
| self.period = Some(r); |
| return Ok(r); |
| } |
| } |
|
|
| Err(AlgorithmError::MathematicalError( |
| "No period found (a and N may not be coprime)".to_string(), |
| )) |
| } |
|
|
| |
| pub fn estimated_period(&self) -> u64 { |
| |
| self.n |
| } |
| } |
|
|
| |
| #[derive(Debug, Clone)] |
| pub struct ContinuedFractions { |
| |
| pub numerator: u64, |
|
|
| |
| pub denominator: u64, |
| } |
|
|
| impl ContinuedFractions { |
| |
| |
| pub fn from_phase(phase: f64, max_denominator: u64) -> AlgorithmResult<Self> { |
| |
| |
| let fraction = phase / (2.0 * PI); |
|
|
| |
| let (num, den) = approximate_fraction(fraction, max_denominator); |
|
|
| Ok(ContinuedFractions { |
| numerator: num, |
| denominator: den, |
| }) |
| } |
|
|
| |
| pub fn order(&self) -> u64 { |
| self.denominator |
| } |
| } |
|
|
| |
| fn approximate_fraction(x: f64, max_denom: u64) -> (u64, u64) { |
| let mut num = 0i64; |
| let mut den = 1i64; |
| let mut prev_num = 1i64; |
| let mut prev_den = 0i64; |
|
|
| let mut remaining = x; |
|
|
| for _ in 0..20 { |
| let a = remaining.floor() as i64; |
| let temp_num = a * num + prev_num; |
| let temp_den = a * den + prev_den; |
|
|
| if temp_den.abs() as u64 > max_denom { |
| break; |
| } |
|
|
| prev_num = num; |
| prev_den = den; |
| num = temp_num; |
| den = temp_den; |
|
|
| remaining -= a as f64; |
| if remaining.abs() < 1e-10 { |
| break; |
| } |
| remaining = 1.0 / remaining; |
| } |
|
|
| (num.abs() as u64, den.abs() as u64) |
| } |
|
|
| |
| #[derive(Debug, Clone)] |
| pub struct ShorFactoring { |
| |
| pub n: u64, |
|
|
| |
| pub factors: Vec<u64>, |
| } |
|
|
| impl ShorFactoring { |
| |
| pub fn new(n: u64) -> AlgorithmResult<Self> { |
| if n < 2 { |
| return Err(AlgorithmError::InvalidParameters("N must be >= 2".to_string())); |
| } |
|
|
| Ok(ShorFactoring { |
| n, |
| factors: Vec::new(), |
| }) |
| } |
|
|
| |
| pub fn check_even(&mut self) -> Option<u64> { |
| if self.n % 2 == 0 { |
| self.factors.push(2); |
| return Some(self.n / 2); |
| } |
| None |
| } |
|
|
| |
| pub fn check_perfect_power(&self) -> Option<u64> { |
| for k in 2..64 { |
| let root = (self.n as f64).powf(1.0 / k as f64) as u64; |
| for candidate in root.saturating_sub(2)..=root + 2 { |
| if candidate > 1 { |
| if let Some(power) = candidate.checked_pow(k as u32) { |
| if power == self.n { |
| return Some(candidate); |
| } |
| } |
| } |
| } |
| } |
| None |
| } |
|
|
| |
| pub fn factor(&mut self) -> AlgorithmResult<Vec<u64>> { |
| |
| if let Some(factor) = self.check_even() { |
| if factor > 1 { |
| self.factors.push(factor); |
| return Ok(self.factors.clone()); |
| } |
| } |
|
|
| if let Some(base) = self.check_perfect_power() { |
| self.factors.push(base); |
| return Ok(self.factors.clone()); |
| } |
|
|
| |
| let a = 2; |
|
|
| |
| let mut pf = PeriodFinding::new(a, self.n)?; |
| let r = pf.find_period_classical()?; |
|
|
| |
| if r % 2 != 0 { |
| return Err(AlgorithmError::MathematicalError( |
| "Period r is odd".to_string(), |
| )); |
| } |
|
|
| |
| let x = modpow(a, r / 2, self.n); |
|
|
| if x == 0 || x == self.n - 1 { |
| return Err(AlgorithmError::MathematicalError( |
| "Shor's algorithm failed".to_string(), |
| )); |
| } |
|
|
| |
| |
| let f1 = gcd(x.wrapping_sub(1), self.n); |
| let f2 = gcd(x.wrapping_add(1), self.n); |
|
|
| if f1 > 1 && f1 < self.n { |
| self.factors.push(f1); |
| } |
| if f2 > 1 && f2 < self.n { |
| self.factors.push(f2); |
| } |
|
|
| if self.factors.is_empty() { |
| return Err(AlgorithmError::MathematicalError( |
| "No non-trivial factors found".to_string(), |
| )); |
| } |
|
|
| Ok(self.factors.clone()) |
| } |
|
|
| |
| pub fn circuit_size_estimate(&self) -> usize { |
| let bits = (self.n as f64).log2().ceil() as usize; |
| |
| 6 * bits * bits |
| } |
|
|
| |
| pub fn success_probability() -> f64 { |
| 4.0 / (std::f64::consts::PI * std::f64::consts::PI) |
| } |
| } |
|
|
| #[cfg(test)] |
| mod tests { |
| use super::*; |
|
|
| #[test] |
| fn test_modpow() { |
| assert_eq!(modpow(2, 4, 15), 1); |
| assert_eq!(modpow(7, 4, 15), 1); |
| assert_eq!(modpow(2, 10, 1000), 24); |
| } |
|
|
| #[test] |
| fn test_gcd() { |
| assert_eq!(gcd(12, 8), 4); |
| assert_eq!(gcd(15, 10), 5); |
| assert_eq!(gcd(13, 7), 1); |
| } |
|
|
| #[test] |
| fn test_modular_exponentiation() { |
| let exp = ModularExponentiation::new(2, 15).unwrap(); |
| assert_eq!(exp.compute(4), 1); |
| } |
|
|
| #[test] |
| fn test_period_finding() { |
| let mut pf = PeriodFinding::new(2, 15).unwrap(); |
| let period = pf.find_period_classical().unwrap(); |
| assert_eq!(period, 4); |
| } |
|
|
| #[test] |
| fn test_period_finding_7_mod_15() { |
| let mut pf = PeriodFinding::new(7, 15).unwrap(); |
| let period = pf.find_period_classical().unwrap(); |
| assert_eq!(period, 4); |
| } |
|
|
| #[test] |
| fn test_continued_fractions() { |
| let cf = ContinuedFractions::from_phase(PI / 2.0, 100).unwrap(); |
| assert!(cf.denominator > 0); |
| } |
|
|
| #[test] |
| fn test_shor_factoring_15() { |
| let mut shor = ShorFactoring::new(15).unwrap(); |
| |
| |
| match shor.factor() { |
| Ok(factors) => { |
| |
| for factor in &factors { |
| assert!(15 % factor == 0, "Factor {} doesn't divide 15", factor); |
| } |
| } |
| Err(_) => { |
| |
| |
| } |
| } |
| } |
|
|
| #[test] |
| fn test_shor_check_even() { |
| let mut shor = ShorFactoring::new(6).unwrap(); |
| assert_eq!(shor.check_even(), Some(3)); |
| } |
|
|
| #[test] |
| fn test_shor_success_probability() { |
| let prob = ShorFactoring::success_probability(); |
| assert!(prob > 0.4 && prob < 0.5); |
| } |
|
|
| #[test] |
| fn test_circuit_size_estimate() { |
| let shor = ShorFactoring::new(15).unwrap(); |
| let size = shor.circuit_size_estimate(); |
| assert!(size > 0); |
| } |
| } |
|
|
| |
|
|