use crate::arch::Chunk;
use crate::rand::RAND;
use crate::rsa2048::big;
use crate::rsa2048::big::BIG;
use crate::rsa2048::dbig::DBIG;
use crate::arch::DChunk;
pub const FFLEN:usize=2;
pub const FF_BITS: usize = big::BIGBITS * FFLEN;
pub const HFLEN: usize = FFLEN / 2;
pub const P_MBITS: usize = (big::MODBYTES as usize) * 8;
pub const P_OMASK: Chunk = (-1) << (P_MBITS % big::BASEBITS);
pub const P_FEXCESS: Chunk = 1 << (big::BASEBITS * big::NLEN - P_MBITS - 1);
pub const P_TBITS: usize = P_MBITS % big::BASEBITS;
pub struct FF {
v: Vec<BIG>,
length: usize,
}
impl FF {
pub fn excess(a: &BIG) -> Chunk {
return ((a.w[big::NLEN - 1] & P_OMASK) >> (P_TBITS)) + 1;
}
pub fn pexceed(a: &BIG, b: &BIG) -> bool {
let ea = FF::excess(a);
let eb = FF::excess(b);
if ((ea + 1) as DChunk) * ((eb + 1) as DChunk) > P_FEXCESS as DChunk {
return true;
}
return false;
}
pub fn sexceed(a: &BIG) -> bool {
let ea = FF::excess(a);
if ((ea + 1) as DChunk) * ((ea + 1) as DChunk) > P_FEXCESS as DChunk {
return true;
}
return false;
}
pub fn new_int(n: usize) -> FF {
let mut f = FF {
v: Vec::new(),
length: 0,
};
for _ in 0..n {
f.v.push(BIG::new());
}
f.length = n;
return f;
}
pub fn zero(&mut self) {
for i in 0..self.length {
self.v[i].zero();
}
}
pub fn getlen(&self) -> usize {
return self.length;
}
pub fn set(&mut self, m: isize) {
self.zero();
self.v[0].set(0, m as Chunk);
}
pub fn copy(&mut self, b: &FF) {
for i in 0..self.length {
self.v[i].copy(&b.v[i]);
}
}
pub fn dsucopy(&mut self, b: &FF) {
for i in 0..b.length {
self.v[b.length + i].copy(&b.v[i]);
self.v[i].zero();
}
}
pub fn dscopy(&mut self, b: &FF) {
for i in 0..b.length {
self.v[i].copy(&b.v[i]);
self.v[b.length + i].zero();
}
}
pub fn sducopy(&mut self, b: &FF) {
for i in 0..self.length {
self.v[i].copy(&b.v[self.length + i]);
}
}
pub fn one(&mut self) {
self.v[0].one();
for i in 1..self.length {
self.v[i].zero();
}
}
pub fn iszilch(&mut self) -> bool {
for i in 0..self.length {
if !self.v[i].iszilch() {
return false;
}
}
return true;
}
pub fn shrw(&mut self, n: usize) {
let mut t = BIG::new();
for i in 0..n {
t.copy(&self.v[i + n]);
self.v[i].copy(&t);
self.v[i + n].zero();
}
}
pub fn shlw(&mut self, n: usize) {
let mut t = BIG::new();
for i in 0..n {
t.copy(&self.v[i]);
self.v[n + i].copy(&t);
self.v[i].zero();
}
}
pub fn parity(&self) -> isize {
return self.v[0].parity();
}
pub fn lastbits(&mut self, m: usize) -> isize {
return self.v[0].lastbits(m);
}
pub fn comp(a: &FF, b: &FF) -> isize {
let mut i = a.length - 1;
loop {
let j = BIG::comp(&a.v[i], &b.v[i]);
if j != 0 {
return j;
}
if i == 0 {
break;
}
i -= 1;
}
return 0;
}
pub fn radd(&mut self, vp: usize, x: &FF, xp: usize, y: &FF, yp: usize, n: usize) {
for i in 0..n {
self.v[vp + i].copy(&x.v[xp + i]);
self.v[vp + i].add(&y.v[yp + i]);
}
}
pub fn rinc(&mut self, vp: usize, y: &FF, yp: usize, n: usize) {
for i in 0..n {
self.v[vp + i].add(&y.v[yp + i]);
}
}
pub fn rsinc(&mut self, n: usize) {
let mut t = BIG::new();
for i in 0..n {
t.copy(&self.v[i]);
self.v[n + i].add(&t);
}
}
pub fn rsub(&mut self, vp: usize, x: &FF, xp: usize, y: &FF, yp: usize, n: usize) {
for i in 0..n {
self.v[vp + i].copy(&x.v[xp + i]);
self.v[vp + i].sub(&y.v[yp + i]);
}
}
pub fn rdec(&mut self, vp: usize, y: &FF, yp: usize, n: usize) {
for i in 0..n {
self.v[vp + i].sub(&y.v[yp + i]);
}
}
pub fn add(&mut self, b: &FF) {
for i in 0..self.length {
self.v[i].add(&b.v[i]);
}
}
pub fn sub(&mut self, b: &FF) {
for i in 0..self.length {
self.v[i].sub(&b.v[i]);
}
}
pub fn revsub(&mut self, b: &FF) {
for i in 0..self.length {
self.v[i].rsub(&b.v[i]);
}
}
pub fn rnorm(&mut self, vp: usize, n: isize) {
let mut trunc = false;
let mut carry: Chunk;
let mut nn: usize = n as usize;
if n < 0 {
nn = (-n) as usize;
trunc = true;
}
for i in 0..nn - 1 {
carry = self.v[vp + i].norm();
self.v[vp + i].xortop(carry << P_TBITS);
self.v[vp + i + 1].w[0] += carry;
}
carry = self.v[vp + nn - 1].norm();
if trunc {
self.v[vp + nn - 1].xortop(carry << P_TBITS);
}
}
pub fn norm(&mut self) {
let n: isize = self.length as isize;
self.rnorm(0, n);
}
pub fn inc(&mut self, m: isize) {
self.v[0].inc(m);
self.norm();
}
pub fn dec(&mut self, m: isize) {
self.v[0].dec(m);
self.norm();
}
pub fn shl(&mut self) {
let mut delay_carry: isize = 0;
for i in 0..self.length - 1 {
let carry = self.v[i].fshl(1);
self.v[i].inc(delay_carry);
self.v[i].xortop((carry as Chunk) << P_TBITS);
delay_carry = carry;
}
self.v[self.length - 1].fshl(1);
self.v[self.length - 1].inc(delay_carry);
}
pub fn shr(&mut self) {
let mut i = self.length - 1;
while i > 0 {
let carry = self.v[i].fshr(1);
self.v[i - 1].xortop((carry as Chunk) << P_TBITS);
i -= 1;
}
self.v[0].fshr(1);
}
pub fn tostring(&mut self) -> String {
self.norm();
let mut s = String::new();
let mut i: usize = self.length - 1;
loop {
s = s + self.v[i].tostring().as_ref();
if i == 0 {
break;
}
i -= 1;
}
return s;
}
pub fn tobytes(&mut self, b: &mut [u8]) {
for i in 0..self.length {
self.v[i].tobytearray(b, (self.length - i - 1) * (big::MODBYTES as usize))
}
}
pub fn frombytes(x: &mut FF, b: &[u8]) {
for i in 0..x.length {
x.v[i] = BIG::frombytearray(b, (x.length - i - 1) * (big::MODBYTES as usize))
}
}
pub fn cswap(a: &mut FF, b: &mut FF, d: isize) {
for i in 0..a.length {
a.v[i].cswap(&mut b.v[i], d);
}
}
fn karmul(
&mut self,
vp: usize,
x: &FF,
xp: usize,
y: &FF,
yp: usize,
t: *mut FF,
tp: usize,
n: usize,
) {
if n == 1 {
let xx = BIG::new_copy(&x.v[xp]);
let yy = BIG::new_copy(&y.v[yp]);
let mut d = BIG::mul(&xx, &yy);
self.v[vp + 1] = d.split(8 * big::MODBYTES);
self.v[vp].dcopy(&d);
return;
}
let nd2 = n / 2;
self.radd(vp, x, xp, x, xp + nd2, nd2);
self.rnorm(vp, nd2 as isize);
self.radd(vp + nd2, y, yp, y, yp + nd2, nd2);
self.rnorm(vp + nd2, nd2 as isize);
unsafe {
(*t).karmul(tp, self, vp, self, vp + nd2, t, tp + n, nd2);
}
self.karmul(vp, x, xp, y, yp, t, tp + n, nd2);
self.karmul(vp + n, x, xp + nd2, y, yp + nd2, t, tp + n, nd2);
unsafe {
(*t).rdec(tp, self, vp, n);
(*t).rdec(tp, self, vp + n, n);
self.rinc(vp + nd2, &(*t), tp, n);
}
self.rnorm(vp, (2 * n) as isize);
}
fn karsqr(&mut self, vp: usize, x: &FF, xp: usize, t: *mut FF, tp: usize, n: usize) {
if n == 1 {
let xx = BIG::new_copy(&x.v[xp]);
let mut d = BIG::sqr(&xx);
self.v[vp + 1].copy(&d.split(8 * big::MODBYTES));
self.v[vp].dcopy(&d);
return;
}
let nd2 = n / 2;
self.karsqr(vp, x, xp, t, tp + n, nd2);
self.karsqr(vp + n, x, xp + nd2, t, tp + n, nd2);
unsafe {
(*t).karmul(tp, x, xp, x, xp + nd2, t, tp + n, nd2);
self.rinc(vp + nd2, &(*t), tp, n);
self.rinc(vp + nd2, &(*t), tp, n);
}
self.rnorm(vp + nd2, n as isize);
}
fn karmul_lower(
&mut self,
vp: usize,
x: &FF,
xp: usize,
y: &FF,
yp: usize,
t: *mut FF,
tp: usize,
n: usize,
) {
if n == 1 {
self.v[vp].copy(&BIG::smul(&x.v[xp], &y.v[yp]));
return;
}
let nd2 = n / 2;
self.karmul(vp, x, xp, y, yp, t, tp + n, nd2);
unsafe {
(*t).karmul_lower(tp, x, xp + nd2, y, yp, t, tp + n, nd2);
self.rinc(vp + nd2, &(*t), tp, nd2);
(*t).karmul_lower(tp, x, xp, y, yp + nd2, t, tp + n, nd2);
self.rinc(vp + nd2, &(*t), tp, nd2);
}
let sn: isize = nd2 as isize;
self.rnorm(vp + nd2, -sn);
}
fn karmul_upper(&mut self, x: &FF, y: &FF, t: *mut FF, n: usize) {
let nd2 = n / 2;
self.radd(n, x, 0, x, nd2, nd2);
self.radd(n + nd2, y, 0, y, nd2, nd2);
self.rnorm(n, nd2 as isize);
self.rnorm(n + nd2, nd2 as isize);
unsafe {
(*t).karmul(0, self, n + nd2, self, n, t, n, nd2);
}
self.karmul(n, x, nd2, y, nd2, t, n, nd2);
unsafe {
(*t).rdec(0, self, n, n);
self.rsinc(nd2);
self.rdec(nd2, &(*t), 0, nd2);
}
let sn: isize = n as isize;
self.rnorm(0, -sn);
unsafe {
(*t).rdec(0, self, 0, n);
self.rinc(nd2, &(*t), 0, n);
}
self.rnorm(nd2, sn);
}
pub fn mul(x: &FF, y: &FF) -> FF {
let n = x.length;
let mut z = FF::new_int(2 * n);
let mut t = FF::new_int(2 * n);
z.karmul(0, &x, 0, &y, 0, &mut t, 0, n);
return z;
}
pub fn lmul(&mut self, y: &FF) {
let n = self.length;
let mut t = FF::new_int(2 * n);
let mut x = FF::new_int(n);
x.copy(&self);
self.karmul_lower(0, &x, 0, &y, 0, &mut t, 0, n);
}
pub fn rmod(&mut self, m: &FF) {
let mut k = 1;
let n = m.length;
let mut c = FF::new_int(n);
c.copy(m);
self.norm();
if FF::comp(&self, &c) < 0 {
return;
}
c.shl();
while FF::comp(&self, &c) >= 0 {
c.shl();
k += 1;
}
while k > 0 {
c.shr();
if FF::comp(&self, &c) >= 0 {
self.sub(&c);
self.norm();
}
k -= 1;
}
}
pub fn sqr(x: &FF) -> FF {
let n = x.length;
let mut z = FF::new_int(2 * n);
let mut t = FF::new_int(2 * n);
z.karsqr(0, &x, 0, &mut t, 0, n);
return z;
}
pub fn reduce(&mut self, ms: &FF, md: &FF) -> FF {
let n = ms.length;
let mut t = FF::new_int(2 * n);
let mut r = FF::new_int(n);
let mut m = FF::new_int(n);
r.sducopy(&self);
m.karmul_lower(0, &self, 0, &md, 0, &mut t, 0, n);
self.karmul_upper(&ms, &m, &mut t, n);
m.sducopy(self);
r.add(&ms);
r.sub(&m);
r.norm();
return r;
}
pub fn dmod(&mut self, b: &FF) -> FF {
let n = b.length;
let mut m = FF::new_int(2 * n);
let mut x = FF::new_int(2 * n);
let mut r = FF::new_int(n);
x.copy(&self);
x.norm();
m.dsucopy(&b);
let mut k = big::BIGBITS * n;
while FF::comp(&x, &m) >= 0 {
x.sub(&m);
x.norm();
}
while k > 0 {
m.shr();
if FF::comp(&x, &m) >= 0 {
x.sub(&m);
x.norm();
}
k -= 1;
}
r.copy(&x);
r.rmod(b);
return r;
}
pub fn invmodp(&mut self, p: &FF) {
let n = p.length;
let mut u = FF::new_int(n);
let mut v = FF::new_int(n);
let mut x1 = FF::new_int(n);
let mut x2 = FF::new_int(n);
let mut t = FF::new_int(n);
let mut one = FF::new_int(n);
one.one();
u.copy(&self);
v.copy(&p);
x1.copy(&one);
x2.zero();
while FF::comp(&u, &one) != 0 && FF::comp(&v, &one) != 0 {
while u.parity() == 0 {
u.shr();
if x1.parity() != 0 {
x1.add(&p);
x1.norm();
}
x1.shr();
}
while v.parity() == 0 {
v.shr();
if x2.parity() != 0 {
x2.add(&p);
x2.norm();
}
x2.shr();
}
if FF::comp(&u, &v) >= 0 {
u.sub(&v);
u.norm();
if FF::comp(&x1, &x2) >= 0 {
x1.sub(&x2);
} else {
t.copy(&p);
t.sub(&x2);
x1.add(&t);
}
x1.norm();
} else {
v.sub(&u);
v.norm();
if FF::comp(&x2, &x1) >= 0 {
x2.sub(&x1);
} else {
t.copy(&p);
t.sub(&x1);
x2.add(&t);
}
x2.norm();
}
}
if FF::comp(&u, &one) == 0 {
self.copy(&x1);
} else {
self.copy(&x2);
}
}
pub fn nres(&mut self, m: &FF) {
let n = m.length;
if n == 1 {
let mut d = DBIG::new_scopy(&(self.v[0]));
d.shl(big::NLEN * (big::BASEBITS as usize));
self.v[0].copy(&d.dmod(&(m.v[0])));
} else {
let mut d = FF::new_int(2 * n);
d.dsucopy(&self);
self.copy(&d.dmod(m));
}
}
pub fn redc(&mut self, m: &FF, md: &FF) {
let n = m.length;
if n == 1 {
let mut d = DBIG::new_scopy(&(self.v[0]));
self.v[0].copy(&BIG::monty(
&(m.v[0]),
((1 as Chunk) << big::BASEBITS) - md.v[0].w[0],
&mut d,
));
} else {
let mut d = FF::new_int(2 * n);
self.rmod(m);
d.dscopy(&self);
self.copy(&d.reduce(&m, &md));
self.rmod(m);
}
}
pub fn mod2m(&mut self, m: usize) {
for i in m..self.length {
self.v[i].zero()
}
}
pub fn invmod2m(&self) -> FF {
let n = self.length;
let mut b = FF::new_int(n);
let mut c = FF::new_int(n);
let mut u = FF::new_int(n);
u.zero();
u.v[0].copy(&self.v[0]);
u.v[0].invmod2m();
let mut i = 1;
while i < n {
b.copy(&self);
b.mod2m(i);
let mut t = FF::mul(&u, &b);
t.shrw(i);
b.copy(&t);
c.copy(&self);
c.shrw(i);
c.mod2m(i);
c.lmul(&u);
c.mod2m(i);
b.add(&c);
b.norm();
b.lmul(&u);
b.mod2m(i);
c.one();
c.shlw(i);
b.revsub(&c);
b.norm();
b.shlw(i);
u.add(&b);
i <<= 1;
}
u.norm();
return u;
}
pub fn random(&mut self, rng: &mut RAND) {
let n = self.length;
for i in 0..n {
self.v[i].copy(&BIG::random(rng))
}
while self.v[n - 1].nbits() < (big::MODBYTES as usize) * 8 {
self.v[n - 1].copy(&BIG::random(rng));
}
}
pub fn randomnum(&mut self, p: &FF, rng: &mut RAND) {
let n = self.length;
let mut d = FF::new_int(2 * n);
for i in 0..2 * n {
d.v[i].copy(&BIG::random(rng));
}
self.copy(&d.dmod(p));
}
pub fn modmul(&mut self, y: &FF, p: &FF, nd: &FF) {
if FF::pexceed(&self.v[self.length - 1], &y.v[y.length - 1]) {
self.rmod(p)
}
let n = p.length;
if n == 1 {
let mut d = BIG::mul(&self.v[0], &y.v[0]);
self.v[0].copy(&BIG::monty(
&(p.v[0]),
((1 as Chunk) << big::BASEBITS) - nd.v[0].w[0],
&mut d,
));
} else {
let mut d = FF::mul(&self, y);
self.copy(&d.reduce(p, nd));
}
}
pub fn modsqr(&mut self, p: &FF, nd: &FF) {
if FF::sexceed(&self.v[self.length - 1]) {
self.rmod(p);
}
let n = p.length;
if n == 1 {
let mut d = BIG::sqr(&self.v[0]);
self.v[0].copy(&BIG::monty(
&(p.v[0]),
((1 as Chunk) << big::BASEBITS) - nd.v[0].w[0],
&mut d,
));
} else {
let mut d = FF::sqr(&self);
d.norm();
self.copy(&d.reduce(p, nd));
}
}
pub fn skpow(&mut self, e: &FF, p: &FF) {
let n = p.length;
let mut r0 = FF::new_int(n);
let mut r1 = FF::new_int(n);
let nd = p.invmod2m();
self.rmod(p);
r0.one();
r1.copy(&self);
r0.nres(p);
r1.nres(p);
let mut i = 8 * (big::MODBYTES as usize) * n - 1;
loop {
let b = (e.v[i / (big::BIGBITS as usize)]).bit(i % (big::BIGBITS as usize)) as isize;
self.copy(&r0);
self.modmul(&r1, p, &nd);
FF::cswap(&mut r0, &mut r1, b);
r0.modsqr(p, &nd);
r1.copy(&self);
FF::cswap(&mut r0, &mut r1, b);
if i == 0 {
break;
}
i -= 1;
}
self.copy(&r0);
self.redc(p, &nd);
}
pub fn skpows(&mut self, e: &BIG, p: &FF) {
let n = p.length;
let mut r0 = FF::new_int(n);
let mut r1 = FF::new_int(n);
let nd = p.invmod2m();
self.rmod(p);
r0.one();
r1.copy(&self);
r0.nres(p);
r1.nres(p);
let mut i = 8 * (big::MODBYTES as usize) - 1;
loop {
let b = e.bit(i);
self.copy(&r0);
self.modmul(&r1, p, &nd);
FF::cswap(&mut r0, &mut r1, b);
r0.modsqr(p, &nd);
r1.copy(&self);
FF::cswap(&mut r0, &mut r1, b);
if i == 0 {
break;
}
i -= 1;
}
self.copy(&r0);
self.redc(p, &nd);
}
pub fn power(&mut self, e: isize, p: &FF) {
let n = p.length;
let mut w = FF::new_int(n);
let nd = p.invmod2m();
let mut f = true;
let mut ee = e;
w.copy(&self);
w.nres(p);
if ee == 2 {
self.copy(&w);
self.modsqr(p, &nd);
} else {
loop {
if ee % 2 == 1 {
if f {
self.copy(&w);
} else {
self.modmul(&w, p, &nd)
}
f = false;
}
ee >>= 1;
if ee == 0 {
break;
}
w.modsqr(p, &nd);
}
}
self.redc(p, &nd);
}
pub fn pow(&mut self, e: &FF, p: &FF) {
let n = p.length;
let mut w = FF::new_int(n);
let nd = p.invmod2m();
w.copy(&self);
self.one();
self.nres(p);
w.nres(p);
let mut i = 8 * (big::MODBYTES as usize) * n - 1;
loop {
self.modsqr(p, &nd);
let b = (e.v[i / (big::BIGBITS as usize)]).bit(i % (big::BIGBITS as usize)) as isize;
if b == 1 {
self.modmul(&w, p, &nd)
}
if i == 0 {
break;
}
i -= 1;
}
self.redc(p, &nd);
}
pub fn pow2(&mut self, e: &BIG, y: &FF, f: &BIG, p: &FF) {
let n = p.length;
let mut xn = FF::new_int(n);
let mut yn = FF::new_int(n);
let mut xy = FF::new_int(n);
let nd = p.invmod2m();
xn.copy(&self);
yn.copy(y);
xn.nres(p);
yn.nres(p);
xy.copy(&xn);
xy.modmul(&yn, p, &nd);
self.one();
self.nres(p);
let mut i = 8 * (big::MODBYTES as usize) - 1;
loop {
let eb = e.bit(i);
let fb = f.bit(i);
self.modsqr(p, &nd);
if eb == 1 {
if fb == 1 {
self.modmul(&xy, p, &nd);
} else {
self.modmul(&xn, p, &nd)
}
} else {
if fb == 1 {
self.modmul(&yn, p, &nd)
}
}
if i == 0 {
break;
}
i -= 1;
}
self.redc(p, &nd);
}
pub fn igcd(x: isize, y: isize) -> isize {
if y == 0 {
return x;
}
let mut xx = x;
let mut yy = y;
loop {
let r = xx % yy;
if r == 0 {
break;
}
xx = yy;
yy = r;
}
return yy;
}
pub fn cfactor(&self, s: isize) -> bool {
let n = self.length;
let mut x = FF::new_int(n);
let mut y = FF::new_int(n);
y.set(s);
x.copy(&self);
x.norm();
x.sub(&y);
x.norm();
while !x.iszilch() && x.parity() == 0 {
x.shr()
}
while FF::comp(&x, &y) > 0 {
x.sub(&y);
x.norm();
while !x.iszilch() && x.parity() == 0 {
x.shr()
}
}
let g = x.v[0].get(0) as isize;
let r = FF::igcd(s, g);
if r > 1 {
return true;
}
return false;
}
pub fn prime(pp: &FF, rng: &mut RAND) -> bool {
let mut s = 0;
let n = pp.length;
let mut d = FF::new_int(n);
let mut x = FF::new_int(n);
let mut unity = FF::new_int(n);
let mut nm1 = FF::new_int(n);
let mut p = FF::new_int(n);
p.copy(pp);
let sf = 4849845;
p.norm();
if p.cfactor(sf) {
return false;
}
unity.one();
nm1.copy(&p);
nm1.sub(&unity);
nm1.norm();
d.copy(&nm1);
while d.parity() == 0 {
d.shr();
s += 1;
}
if s == 0 {
return false;
}
for _ in 0..10 {
x.randomnum(&p, rng);
x.pow(&d, &p);
if FF::comp(&x, &unity) == 0 || FF::comp(&x, &nm1) == 0 {
continue;
}
let mut looper = false;
for _ in 1..s {
x.power(2, &p);
if FF::comp(&x, &unity) == 0 {
return false;
}
if FF::comp(&x, &nm1) == 0 {
looper = true;
break;
}
}
if looper {
continue;
}
return false;
}
return true;
}
}