use std::ops::{BitAnd, BitOr};
use either::Either;
use num_integer::{Integer, Roots};
use num_traits::Pow;
pub trait BitTest {
fn bits(&self) -> usize;
fn bit(&self, position: usize) -> bool;
fn trailing_zeros(&self) -> usize;
}
#[derive(Debug, Clone, Copy)]
pub enum Primality {
Yes,
No,
Probable(f32),
}
impl Primality {
pub fn probably(self) -> bool {
match self {
Primality::No => false,
_ => true,
}
}
}
impl BitAnd<Primality> for Primality {
type Output = Primality;
fn bitand(self, rhs: Primality) -> Self::Output {
match self {
Primality::No => Primality::No,
Primality::Yes => rhs,
Primality::Probable(p) => match rhs {
Primality::No => Primality::No,
Primality::Yes => Primality::Probable(p),
Primality::Probable(p2) => Primality::Probable(p * p2),
},
}
}
}
impl BitOr<Primality> for Primality {
type Output = Primality;
fn bitor(self, rhs: Primality) -> Self::Output {
match self {
Primality::No => rhs,
Primality::Yes => Primality::Yes,
Primality::Probable(p) => match rhs {
Primality::No => Primality::Probable(p),
Primality::Yes => Primality::Yes,
Primality::Probable(p2) => Primality::Probable(1. - (1. - p) * (1. - p2)),
},
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PrimalityTestConfig {
pub sprp_trials: usize,
pub sprp_random_trials: usize,
pub slprp_test: bool,
pub eslprp_test: bool,
}
impl PrimalityTestConfig {
pub fn default() -> Self {
Self {
sprp_trials: 2,
sprp_random_trials: 2,
slprp_test: false,
eslprp_test: false,
}
}
pub fn strict() -> Self {
Self::bpsw() }
pub fn bpsw() -> Self {
Self {
sprp_trials: 1,
sprp_random_trials: 0,
slprp_test: true,
eslprp_test: false,
}
}
fn psw() {
todo!() }
}
#[derive(Debug, Clone, Copy)]
pub struct FactorizationConfig {
pub primality_config: PrimalityTestConfig,
pub td_limit: Option<u64>,
pub rho_trials: usize,
brent_trials: usize,
pm1_trials: usize,
pp1_trials: usize,
}
impl FactorizationConfig {
pub fn default() -> Self {
const THRESHOLD_DEFAULT_TD: u64 = 1 << 14;
Self {
primality_config: PrimalityTestConfig::default(),
td_limit: Some(THRESHOLD_DEFAULT_TD),
rho_trials: 4,
brent_trials: 0,
pm1_trials: 0,
pp1_trials: 0,
}
}
pub fn strict() -> Self {
let mut config = Self::default();
config.primality_config = PrimalityTestConfig::strict();
config
}
}
pub trait ExactRoots: Roots + Pow<u32, Output = Self> + Clone {
fn nth_root_exact(&self, n: u32) -> Option<Self> {
let r = self.nth_root(n);
if &r.clone().pow(n) == self {
Some(r)
} else {
None
}
}
fn sqrt_exact(&self) -> Option<Self> {
self.nth_root_exact(2)
}
fn cbrt_exact(&self) -> Option<Self> {
self.nth_root_exact(3)
}
fn is_nth_power(&self, n: u32) -> bool {
self.nth_root_exact(n).is_some()
}
fn is_square(&self) -> bool {
self.sqrt_exact().is_some()
}
fn is_cubic(&self) -> bool {
self.cbrt_exact().is_some()
}
}
pub trait PrimeBuffer<'a> {
type PrimeIter: Iterator<Item = &'a u64>;
fn iter(&'a self) -> Self::PrimeIter;
fn reserve(&mut self, limit: u64);
fn bound(&self) -> u64;
fn contains(&self, num: u64) -> bool;
fn clear(&mut self);
}
pub trait PrimalityUtils: Integer + Clone {
fn is_prp(&self, base: Self) -> bool;
fn is_sprp(&self, base: Self) -> bool;
fn test_sprp(&self, base: Self) -> Either<bool, Self>;
fn is_lprp(&self, p: Option<usize>, q: Option<isize>) -> bool;
fn is_slprp(&self, p: Option<usize>, q: Option<isize>) -> bool;
fn is_eslprp(&self, p: Option<usize>) -> bool;
}
pub trait RandPrime<T> {
fn gen_prime(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> T;
fn gen_safe_prime(&mut self, bit_size: usize) -> T;
}