| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| if debug {println!("sf2= {}",self.tostring())} |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| use super::big; |
| use super::dbig::DBIG; |
| use super::big::BIG; |
| use super::super::arch::Chunk; |
| use rand::RAND; |
| |
| use super::super::arch::DChunk; |
| |
| /* Finite field support - for RSA, DH etc. */ |
| /* RSA/DH modulus length as multiple of BIGBITS */ |
| |
| pub use super::rom::FFLEN; |
| //use std::str::SplitWhitespace; |
| |
| pub const FF_BITS: usize = (big::BIGBITS * FFLEN); /* Finite Field Size in bits - must be 256.2^n */ |
| pub const HFLEN: usize = (FFLEN / 2); /* Useful for half-size RSA private key operations */ |
| |
| 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; |
| } |
| |
| /* Constructors */ |
| 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; |
| } |
| |
| /* set to integer */ |
| pub fn set(&mut self, m: isize) { |
| self.zero(); |
| self.v[0].set(0, m as Chunk); |
| } |
| |
| /* copy from FF b */ |
| pub fn copy(&mut self, b: &FF) { |
| for i in 0..self.length { |
| self.v[i].copy(&b.v[i]); |
| } |
| } |
| |
| /* x=y<<n */ |
| 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(); |
| } |
| } |
| |
| /* x=y */ |
| 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(); |
| } |
| } |
| |
| /* x=y>>n */ |
| 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(); |
| } |
| } |
| |
| /* test equals 0 */ |
| pub fn iszilch(&mut self) -> bool { |
| for i in 0..self.length { |
| if !self.v[i].iszilch() { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /* shift right by BIGBITS-bit words */ |
| 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(); |
| } |
| } |
| |
| /* shift left by BIGBITS-bit words */ |
| 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(); |
| } |
| } |
| |
| /* extract last bit */ |
| pub fn parity(&self) -> isize { |
| return self.v[0].parity(); |
| } |
| |
| pub fn lastbits(&mut self, m: usize) -> isize { |
| return self.v[0].lastbits(m); |
| } |
| |
| /* compare x and y - must be normalised, and of same length */ |
| 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; |
| } |
| |
| /* recursive add */ |
| 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]); |
| } |
| } |
| |
| /* recursive inc */ |
| 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); |
| } |
| } |
| |
| /* recursive sub */ |
| 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]); |
| } |
| } |
| |
| /* recursive dec */ |
| 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]); |
| } |
| } |
| |
| /* simple add */ |
| pub fn add(&mut self, b: &FF) { |
| for i in 0..self.length { |
| self.v[i].add(&b.v[i]); |
| } |
| } |
| |
| /* simple sub */ |
| pub fn sub(&mut self, b: &FF) { |
| for i in 0..self.length { |
| self.v[i].sub(&b.v[i]); |
| } |
| } |
| |
| /* reverse sub */ |
| pub fn revsub(&mut self, b: &FF) { |
| for i in 0..self.length { |
| self.v[i].rsub(&b.v[i]); |
| } |
| } |
| |
| /* normalise - but hold any overflow in top part unless n<0 */ |
| 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 { |
| /* -v n signals to do truncation */ |
| 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); |
| } |
| |
| /* increment/decrement by a small integer */ |
| 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(); |
| } |
| |
| /* shift left by one bit */ |
| 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); |
| } |
| |
| /* shift right by one bit */ |
| |
| 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); |
| } |
| |
| /* Convert to Hex String */ |
| 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; |
| } |
| |
| /* Convert FFs to/from byte arrays */ |
| 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)) |
| } |
| } |
| |
| /* in-place swapping using xor - side channel resistant - lengths must be the same */ |
| 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); |
| } |
| } |
| |
| /* z=x*y, t is workspace */ |
| 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); /* Important - required for 32-bit build */ |
| self.radd(vp + nd2, y, yp, y, yp + nd2, nd2); |
| self.rnorm(vp + nd2, nd2 as isize); /* Important - required for 32-bit build */ |
| 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); |
| } |
| |
| /* Calculates Least Significant bottom half of x*y */ |
| 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 { |
| /* only calculate bottom half of product */ |
| 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); /* truncate it */ |
| } |
| |
| /* Calculates Most Significant upper half of x*y, given lower part */ |
| 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); /* t = (a0+a1)(b0+b1) */ |
| } |
| self.karmul(n, x, nd2, y, nd2, t, n, nd2); /* z[n]= a1*b1 */ |
| /* z[0-nd2]=l(a0b0) z[nd2-n]= h(a0b0)+l(t)-l(a0b0)-l(a1b1) */ |
| unsafe { |
| (*t).rdec(0, self, n, n); /* t=t-a1b1 */ |
| |
| self.rsinc(nd2); /* z[nd2-n]+=l(a0b0) = h(a0b0)+l(t)-l(a1b1) */ |
| self.rdec(nd2, &(*t), 0, nd2); /* z[nd2-n]=h(a0b0)+l(t)-l(a1b1)-l(t-a1b1)=h(a0b0) */ |
| } |
| |
| let sn: isize = n as isize; |
| self.rnorm(0, -sn); /* a0b0 now in z - truncate it */ |
| unsafe { |
| (*t).rdec(0, self, 0, n); /* (a0+a1)(b0+b1) - a0b0 */ |
| self.rinc(nd2, &(*t), 0, n); |
| } |
| self.rnorm(nd2, sn); |
| } |
| |
| /* z=x*y. Assumes x and y are of same length. */ |
| 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; |
| } |
| |
| /* return low part of product this*y */ |
| 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); |
| } |
| |
| /* Set b=b mod c */ |
| 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; |
| } |
| } |
| |
| /* z=x^2 */ |
| 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; |
| } |
| |
| /* return This mod modulus, ms is modulus, md is Montgomery Constant */ |
| pub fn reduce(&mut self, ms: &FF, md: &FF) -> FF { |
| /* fast karatsuba Montgomery reduction */ |
| 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; |
| } |
| |
| /* Set r=this mod b */ |
| /* this is of length - 2*n */ |
| /* r,b is of length - n */ |
| 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; |
| } |
| |
| /* Set return=1/this mod p. Binary method - a<p on entry */ |
| |
| 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(); |
| |
| // reduce n in here as well! |
| 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); |
| } |
| } |
| |
| /* nresidue mod m */ |
| 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() |
| } |
| } |
| |
| /* U=1/a mod 2^m - Arazi & Qi */ |
| 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)) |
| } |
| /* make sure top bit is 1 */ |
| while self.v[n - 1].nbits() < (big::MODBYTES as usize) * 8 { |
| self.v[n - 1].copy(&BIG::random(rng)); |
| } |
| } |
| |
| /* generate random x less than p */ |
| 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)); |
| } |
| |
| /* this*=y mod 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)); |
| } |
| } |
| |
| /* this*=y mod p */ |
| 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)); |
| } |
| } |
| |
| /* this=this^e mod p using side-channel resistant Montgomery Ladder, for large e */ |
| 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); |
| } |
| |
| /* this =this^e mod p using side-channel resistant Montgomery Ladder, for short e */ |
| 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); |
| } |
| |
| /* raise to an integer power - right-to-left method */ |
| 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); |
| } |
| |
| /* this=this^e mod p, faster but not side channel resistant */ |
| 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); |
| } |
| |
| /* double exponentiation r=x^e.y^f mod p */ |
| 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 { |
| /* integer GCD, returns GCD of x and y */ |
| |
| 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; |
| } |
| |
| /* quick and dirty check for common factor with n */ |
| 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; |
| } |
| |
| /* Miller-Rabin test for primality. Slow. */ |
| 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; /* 3*5*.. *19 */ |
| 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; |
| } |
| } |