#[cfg(any(feature = "lucas", feature = "ssmr"))]
use crate::primes::PRIME_TABLE_128;
#[cfg(feature="qft")]
use crate::qft::qft;
use crate::check::mul_inv2;
pub const fn mul_inv2_128(n: u128) -> u128 {
let est : u128 = mul_inv2(n as u64) as u128;
2u128.wrapping_sub(est.wrapping_mul(n)).wrapping_mul(est)
}
#[inline(always)]
const fn split_to_u128(x: u128) -> (u128, u128) {
(x>>64, (x as u64) as u128)
}
pub const fn nqr_128(a: u128, n: u128) -> bool {
let mut sign: u32 = 0;
let (mut a64, mut n64) = if n >> 64 == 0 {
(a as u64, n as u64)
} else {
if n == 0 {
return false;
}
let zeros = a.trailing_zeros();
let a = a >> zeros;
sign ^= (n as u32).wrapping_add(2) >> 1 & zeros << 1;
sign ^= a as u32 & n as u32;
((n % a) as u64, a as u64)
};
while a64 != 0 {
let zeros = a64.trailing_zeros();
a64 >>= zeros;
sign ^= (n64 as u32).wrapping_add(2) >> 1 & zeros << 1;
sign ^= (a64 & n64) as u32;
(a64, n64) = (n64 % a64, a64)
}
n64 == 1 && sign & 2 != 0
}
#[cfg(not(feature="qft"))]
pub const fn param_search_128(n: u128) -> u128 {
let rem = n % 5;
if rem == 3 || rem == 2 {
return 3;
}
let rem = n % 12;
if rem == 5 || rem == 7{
return 4;
}
let rem = n % 21;
if rem == 2 || rem == 8 || rem == 11 || rem == 10 || rem == 13 || rem == 19 {
return 5;
}
let mut p = 6u128;
loop {
if nqr_128(p*p-4, n) {
break;
}
p +=1;
}
p
}
pub const fn u256prod(lhs: u128, rhs: u128) -> (u128, u128) {
let ((x1, x0), (y1, y0)) = (split_to_u128(lhs), split_to_u128(rhs));
let (c, z0) = split_to_u128(x0 * y0);
let (c, z1) = split_to_u128(x1 * y0 + c);
let z2 = x1 * y1 + c;
let (c, z1) = split_to_u128(x0 * y1 + z1);
(z2 + c, z0 | z1 << 64) }
pub const fn u256prod_hi(lhs: u128, rhs: u128) -> u128 {
let ((x1, x0), (y1, y0)) = (split_to_u128(lhs), split_to_u128(rhs));
let c = (x0 * y0) >> 64;
let (c, z1) = split_to_u128(x1 * y0 + c);
let z2 = x1 * y1 + c;
let c = (x0 * y1 + z1) >> 64;
z2 + c
}
pub const fn u256sqr(x: u128) -> (u128, u128) {
let (x1, x0) = split_to_u128(x);
let z2 = x1*x1;
let m = x1*x0;
let (c0, z0) = split_to_u128(x0*x0);
let (c1, z1) = split_to_u128(m+c0);
let z2 = z2+c1;
let (c1, z1) = split_to_u128(m+z1);
(z2.wrapping_add(c1), z0 | z1.wrapping_shl(64)) }
#[inline]
pub const fn one_mont_128(n: u128) -> u128 {
n.wrapping_neg() % n
}
pub const fn two_mont_128(one: u128, n: u128) -> u128 {
let two = 2*one;
if two >= n {
return two-n;
}
two
}
pub const fn mont_sub_128(x: u128, y: u128, n: u128) -> u128 {
if x >= y {
x-y
} else {
x.wrapping_sub(y).wrapping_add(n)
}
}
pub const fn to_mont_128(x: u128, n: u128) -> u128 {
const RADIX: u128 = 0x10000000000000000;
let mut dividend = x;
let mut divisor = n;
let s = divisor.leading_zeros();
dividend = dividend.wrapping_shl(s);
divisor = divisor.wrapping_shl(s);
let (d1, d0) = split_to_u128(divisor);
let (mut q1, mut rhat) = (dividend / d1, dividend % d1);
let mut prod = q1.wrapping_mul(d0);
let addend = RADIX.wrapping_mul(d1);
let mut prod2 = RADIX.wrapping_mul(rhat);
while q1 >= RADIX || prod > prod2 {
q1 = q1.wrapping_sub(1);
prod = prod.wrapping_sub(d0);
rhat = rhat.wrapping_add(d1);
prod2 = prod2.wrapping_add(addend);
if rhat >= RADIX {
break;
}
}
let r21 = dividend
.wrapping_mul(RADIX)
.wrapping_sub(q1.wrapping_mul(divisor));
let (mut q0, mut rhat) = (r21 / d1, r21 % d1);
let mut prod = q0.wrapping_mul(d0);
while q0 >= RADIX || prod > RADIX.wrapping_mul(rhat) {
q0 = q0.wrapping_sub(1);
rhat = rhat.wrapping_add(d1);
prod = prod.wrapping_sub(d0);
if rhat >= RADIX {
break;
}
}
let r = (r21
.wrapping_mul(RADIX)
.wrapping_sub(q0.wrapping_mul(divisor)))
.wrapping_shr(s);
r
}
pub const fn mont_prod_128(x: u128, y: u128, inv: u128, n: u128) -> u128 {
let (hi, lo) = u256prod(x, y);
let lo = lo.wrapping_mul(inv);
let carry = u256prod_hi(lo, n);
if hi < carry {
hi.wrapping_sub(carry).wrapping_add(n)
} else {
hi.wrapping_sub(carry)
}
}
pub const fn mont_sqr_128(x: u128, inv: u128, n: u128) -> u128 {
let (hi, lo) = u256sqr(x);
let lo = lo.wrapping_mul(inv);
let carry = u256prod_hi(lo, n);
if hi < carry {
hi.wrapping_sub(carry).wrapping_add(n)
} else {
hi.wrapping_sub(carry)
}
}
pub const fn mont_pow_128(mut base: u128, mut one: u128, mut p: u128, inv: u128, n: u128) -> u128 {
while p > 1 {
if p & 1 == 0 {
base = mont_sqr_128(base, inv,n);
p >>=1;
} else {
one = mont_prod_128(one, base, inv,n);
base = mont_sqr_128(base, inv,n);
p >>=1;
}
}
mont_prod_128(one,base, inv, n)
}
#[cfg(not(feature="qft"))]
pub const fn lucas_128(n: u128, one: u128, two: u128, inv: u128) -> bool {
let n_plus = n+1;
let s = n_plus.trailing_zeros();
let d = n_plus>>s;
let param = param_search_128(n);
let m_param = to_mont_128(param, n);
let m_2_inv = mont_prod_128(mont_sub_128(n, two, n), one, inv, n);
let mut w = mont_sub_128(mont_sqr_128(m_param, inv, n), two, n);
let mut v = m_param;
let b : u32 = 128-d.leading_zeros();
let mut i = 2;
while i < (b+1) {
let t = mont_sub_128(mont_prod_128(v, w, inv, n), m_param, n);
if (d>>(b-i)) & 1 == 1 {
v = t;
w = mont_sub_128(mont_sqr_128(w, inv, n), two, n);
} else {
w = t;
v = mont_sub_128(mont_sqr_128(v, inv, n), two, n);
}
i +=1;
}
if v == two || v == m_2_inv {
return true;
}
let mut counter = 1;
while counter < s {
if v == 0 {
return true;
}
v = mont_sub_128(mont_sqr_128(v, inv, n), two, n);
if v == two {
return false;
}
counter +=1;
}
false
}
pub const fn strong_fermat_128(
n: u128,
tz: u32,
base: u128,
one: u128,
oneinv: u128,
inv: u128,
) -> bool {
let d = n>>tz;
let mut result = mont_pow_128(base, one, d, inv, n);
if result == one || result == oneinv {
return true;
}
let mut count = 1;
while count < tz {
count +=1;
result = mont_sqr_128(result, inv, n);
if result == oneinv {
return true;
}
}
false
}
const fn core_primality_128(x: u128) -> bool {
let inv = mul_inv2_128(x);
let tzc = (x-1).trailing_zeros();
let one = one_mont_128(x);
let oneinv = x.wrapping_sub(one);
let two = two_mont_128(one, x);
if !strong_fermat_128(x, tzc, two, one, oneinv, inv) {
return false;
}
let sqrt = x.isqrt();
if sqrt*sqrt == x{
return false;
}
#[cfg(feature="qft")]
{
qft(x,one,two,oneinv,inv)
}
#[cfg(not(feature="qft"))]
{
lucas_128(x, one, two, inv)
}
}
#[no_mangle]
pub const extern "C" fn is_prime_wc_128(x: u128) -> bool {
if x < 0x10000000000000000{
return crate::check::is_prime_wc(x as u64);
}
core_primality_128(x)
}
#[no_mangle]
pub const extern "C" fn is_prime_128(x: u128) -> bool {
if x < 0x10000000000000000{
return crate::check::is_prime(x as u64);
}
if x & 1 == 0 {
return false;
}
#[cfg(any(feature = "lucas", feature = "ssmr"))]
{
let mut idx: usize = 0;
while idx < 256 {
let prod = x.wrapping_mul(PRIME_TABLE_128[idx]);
if prod <= PRIME_TABLE_128[idx+1]{
return prod==1;
}
idx +=2;
}
} core_primality_128(x)
}