SNAPKITTYWEST's picture
chore: push full sov-kernel-monster content from local build
9425aed verified
Raw
History Blame Contribute Delete
10.6 kB
//! Shor's Algorithm - Modular Arithmetic & Factoring
//!
//! Factorizes N via order-finding: find r where a^r ≡ 1 (mod N)
//! Then compute gcd(a^(r/2) ± 1, N) to factor.
//!
//! Pipeline:
//! 1. ModularExponentiation: quantum circuit for a^x mod N
//! 2. PeriodFinding: use phase estimation to find r
//! 3. ContinuedFractions: extract r from measured phase
//! 4. Factor via gcd
use crate::{AlgorithmError, AlgorithmResult};
use std::f64::consts::PI;
/// Modular exponentiation: compute a^x mod N
pub struct ModularExponentiation {
/// Base a
pub a: u64,
/// Modulus N
pub n: u64,
/// Exponent x
pub x: u64,
}
impl ModularExponentiation {
/// Create new modular exponentiation
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 })
}
/// Compute a^x mod n (classical)
pub fn compute(&self, x: u64) -> u64 {
modpow(self.a, x, self.n)
}
/// Get circuit depth for quantum implementation
pub fn circuit_depth(&self) -> usize {
// Rough estimate: 3L² for L = bit length of N
let bits = (self.n as f64).log2().ceil() as usize;
3 * bits * bits
}
}
/// Classical modular exponentiation a^b mod m
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
}
/// Greatest common divisor
fn gcd(mut a: u64, mut b: u64) -> u64 {
while b != 0 {
let temp = b;
b = a % b;
a = temp;
}
a
}
/// Period finding: find r where a^r ≡ 1 (mod N)
#[derive(Debug, Clone)]
pub struct PeriodFinding {
/// Base a
pub a: u64,
/// Modulus N
pub n: u64,
/// Found period r (if any)
pub period: Option<u64>,
}
impl PeriodFinding {
/// Create period finder
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,
})
}
/// Find period by brute force (classical, for small N)
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(),
))
}
/// Estimated period (Carmichael lambda function)
pub fn estimated_period(&self) -> u64 {
// Rough bound: r ≤ N
self.n
}
}
/// Continued fractions for phase estimation → order extraction
#[derive(Debug, Clone)]
pub struct ContinuedFractions {
/// Numerator
pub numerator: u64,
/// Denominator (estimated order)
pub denominator: u64,
}
impl ContinuedFractions {
/// Extract order from measured phase
/// Phase φ = 2π * (k/r) where r is the order
pub fn from_phase(phase: f64, max_denominator: u64) -> AlgorithmResult<Self> {
// Simplified: assume phase = 2π * k/r
// We want to find r (denominator)
let fraction = phase / (2.0 * PI);
// Simple rational approximation
let (num, den) = approximate_fraction(fraction, max_denominator);
Ok(ContinuedFractions {
numerator: num,
denominator: den,
})
}
/// Get estimated order
pub fn order(&self) -> u64 {
self.denominator
}
}
/// Rational approximation via continued fractions
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)
}
/// Shor's factoring algorithm
#[derive(Debug, Clone)]
pub struct ShorFactoring {
/// Number to factor
pub n: u64,
/// Found factors
pub factors: Vec<u64>,
}
impl ShorFactoring {
/// Create factoring instance
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(),
})
}
/// Check if N is even
pub fn check_even(&mut self) -> Option<u64> {
if self.n % 2 == 0 {
self.factors.push(2);
return Some(self.n / 2);
}
None
}
/// Check if N is a perfect power
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
}
/// Shor's algorithm (quantum-classical hybrid, simplified)
pub fn factor(&mut self) -> AlgorithmResult<Vec<u64>> {
// Check easy cases
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());
}
// Pick random a < N
let a = 2; // Simplified: use 2
// Find period r
let mut pf = PeriodFinding::new(a, self.n)?;
let r = pf.find_period_classical()?;
// r must be even
if r % 2 != 0 {
return Err(AlgorithmError::MathematicalError(
"Period r is odd".to_string(),
));
}
// Compute x = a^(r/2) mod N
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(),
));
}
// Factors: gcd(x-1, N) and gcd(x+1, N)
// Use wrapping arithmetic to avoid panics
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())
}
/// Get circuit size estimate
pub fn circuit_size_estimate(&self) -> usize {
let bits = (self.n as f64).log2().ceil() as usize;
// Rough: 6L² for L = bit length
6 * bits * bits
}
/// Success probability (at least 4/π²)
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); // 2^4 mod 15 = 16 mod 15 = 1
assert_eq!(modpow(7, 4, 15), 1); // 7^4 mod 15 = 2401 mod 15 = 1
assert_eq!(modpow(2, 10, 1000), 24); // 2^10 mod 1000 = 1024 mod 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); // 2^4 ≡ 1 (mod 15)
}
#[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); // 7^4 ≡ 1 (mod 15)
}
#[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();
// Just test that the algorithm structure works
// Result may vary depending on random a selection
match shor.factor() {
Ok(factors) => {
// If we get factors, they should be valid
for factor in &factors {
assert!(15 % factor == 0, "Factor {} doesn't divide 15", factor);
}
}
Err(_) => {
// Algorithm may fail to factor if a=2 doesn't work
// That's OK for this test
}
}
}
#[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); // 4/π² ≈ 0.405
}
#[test]
fn test_circuit_size_estimate() {
let shor = ShorFactoring::new(15).unwrap();
let size = shor.circuit_size_estimate();
assert!(size > 0);
}
}
// Made with Bob