blob: a16fbf2c85f7d76cc6aa8cc2df78a128a713764b [file] [log] [blame]
/*
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
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 std::fmt;
use std::cmp::Ordering;
use rom;
use rom::Chunk;
#[cfg(target_pointer_width = "32")]
use rom::DChunk;
#[derive(Copy, Clone)]
pub struct BIG {
pub w: [Chunk; rom::NLEN]
}
//mod dbig;
use dbig::DBIG;
use rand::RAND;
impl fmt::Display for BIG {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut big = self.clone();
write!(f, "BIG: [ {} ]", big.tostring())
}
}
impl fmt::Debug for BIG {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut big = self.clone();
write!(f, "BIG: [ {} ]", big.tostring())
}
}
impl PartialEq for BIG {
fn eq(&self, other: &BIG) -> bool {
return self.w == other.w;
}
}
impl Ord for BIG {
fn cmp(&self, other: &BIG) -> Ordering {
let r = BIG::comp(self, other);
if r > 0 {
return Ordering::Greater;
}
if r < 0 {
return Ordering::Less;
}
return Ordering::Equal;
}
}
impl Eq for BIG { }
impl PartialOrd for BIG {
fn partial_cmp(&self, other: &BIG) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl BIG {
pub fn new() -> BIG {
BIG {
w: [0; rom::NLEN]
}
}
pub fn new_int(x:isize) -> BIG {
let mut s= BIG::new();
s.w[0]=x as Chunk;
return s;
}
pub fn new_ints(a:&[Chunk]) -> BIG {
let mut s= BIG::new();
for i in 0..rom::NLEN {s.w[i]=a[i]}
return s;
}
pub fn new_copy(y:&BIG) -> BIG {
let mut s= BIG::new();
for i in 0..rom::NLEN {s.w[i]=y.w[i]}
return s;
}
pub fn new_big(y:&BIG) -> BIG {
let mut s= BIG::new();
for i in 0..rom::NLEN {s.w[i]=y.w[i]}
return s;
}
pub fn new_dcopy(y:&DBIG) -> BIG {
let mut s= BIG::new();
for i in 0..rom::NLEN {s.w[i]=y.w[i]}
return s;
}
pub fn get(&self,i:usize) -> Chunk {
return self.w[i];
}
pub fn set(&mut self,i:usize,x:Chunk) {
self.w[i]=x;
}
pub fn xortop(&mut self,x:Chunk) {
self.w[rom::NLEN-1]^=x;
}
pub fn ortop(&mut self,x:Chunk) {
self.w[rom::NLEN-1]|=x;
}
/* test for zero */
pub fn iszilch(&self) -> bool {
for i in 0 ..rom::NLEN {
if self.w[i]!=0 {return false}
}
return true;
}
/* set to zero */
pub fn zero(&mut self) {
for i in 0 ..rom::NLEN {
self.w[i]=0
}
}
/* Test for equal to one */
pub fn isunity(&self) -> bool {
for i in 1 ..rom::NLEN {
if self.w[i]!=0 {return false}
}
if self.w[0]!=1 {return false}
return true;
}
/* set to one */
pub fn one(&mut self) {
self.w[0]=1;
for i in 1 ..rom::NLEN {
self.w[i]=0;
}
}
/* Copy from another BIG */
pub fn copy(&mut self,x: &BIG) {
for i in 0 ..rom::NLEN {
self.w[i]=x.w[i]
}
}
pub fn dcopy(&mut self,x: &DBIG)
{
for i in 0 ..rom::NLEN {self.w[i] = x.w[i]}
}
/* calculate Field Excess */
pub fn excess(a:&BIG) -> Chunk {
return (a.w[rom::NLEN-1]&rom::OMASK)>>(rom::MODBITS%rom::BASEBITS)
}
pub fn ff_excess(a:&BIG) -> Chunk {
return (a.w[rom::NLEN-1]&rom::P_OMASK)>>(rom::P_MB)
}
#[cfg(target_pointer_width = "32")]
pub fn pexceed(a: &BIG,b: &BIG) -> bool {
let ea=BIG::excess(a);
let eb=BIG::excess(b);
if ((ea+1) as DChunk)*((eb+1) as DChunk) > rom::FEXCESS as DChunk {return true}
return false
}
#[cfg(target_pointer_width = "32")]
pub fn sexceed(a: &BIG) -> bool {
let ea=BIG::excess(a);
if ((ea+1) as DChunk)*((ea+1) as DChunk) > rom::FEXCESS as DChunk {return true}
return false
}
#[cfg(target_pointer_width = "32")]
pub fn ff_pexceed(a: &BIG,b: &BIG) -> bool {
let ea=BIG::ff_excess(a);
let eb=BIG::ff_excess(b);
if ((ea+1) as DChunk)*((eb+1) as DChunk) > rom::P_FEXCESS as DChunk {return true}
return false;
}
#[cfg(target_pointer_width = "32")]
pub fn ff_sexceed(a: &BIG) -> bool {
let ea=BIG::ff_excess(a);
if ((ea+1) as DChunk)*((ea+1) as DChunk) > rom::P_FEXCESS as DChunk {return true}
return false;
}
/* Get top and bottom half of =x*y+c+r */
#[cfg(target_pointer_width = "32")]
pub fn muladd(a: Chunk,b: Chunk,c: Chunk,r: Chunk) -> (Chunk,Chunk) {
let prod:DChunk = (a as DChunk)*(b as DChunk)+(c as DChunk)+(r as DChunk);
let bot=(prod&(rom::BMASK as DChunk)) as Chunk;
let top=(prod>>rom::BASEBITS) as Chunk;
return (top,bot);
}
#[cfg(target_pointer_width = "64")]
pub fn pexceed(a: &BIG,b: &BIG) -> bool {
let ea=BIG::excess(a);
let eb=BIG::excess(b);
if (ea+1) > rom::FEXCESS/(eb+1) {return true}
return false
}
#[cfg(target_pointer_width = "64")]
pub fn sexceed(a: &BIG) -> bool {
let ea=BIG::excess(a);
if (ea+1) > rom::FEXCESS/(ea+1) {return true}
return false
}
#[cfg(target_pointer_width = "64")]
pub fn ff_pexceed(a: &BIG,b: &BIG) -> bool {
let ea=BIG::ff_excess(a);
let eb=BIG::ff_excess(b);
if (ea+1) > rom::P_FEXCESS/(eb+1) {return true}
return false;
}
#[cfg(target_pointer_width = "64")]
pub fn ff_sexceed(a: &BIG) -> bool {
let ea=BIG::ff_excess(a);
if (ea+1) > rom::P_FEXCESS/(ea+1) {return true}
return false;
}
#[cfg(target_pointer_width = "64")]
pub fn muladd(a: Chunk,b: Chunk,c: Chunk,r: Chunk) -> (Chunk,Chunk) {
let x0=a&rom::HMASK;
let x1=a>>rom::HBITS;
let y0=b&rom::HMASK;
let y1=b>>rom::HBITS;
let mut bot=x0*y0;
let mut top=x1*y1;
let mid=x0*y1+x1*y0;
let u0=mid&rom::HMASK;
let u1=mid>>rom::HBITS;
bot+= u0 <<rom::HBITS;
bot+=c; bot+=r;
top+=u1;
let carry=bot>>rom::BASEBITS;
bot&=rom::BMASK;
top+=carry;
return (top,bot);
}
/*
alise BIG - force all digits < 2^rom::BASEBITS */
pub fn norm(&mut self) -> Chunk
{
let mut carry=0 as Chunk;
for i in 0 ..rom::NLEN-1 {
let d=self.w[i]+carry;
self.w[i]=d&rom::BMASK;
carry=d>>rom::BASEBITS;
}
self.w[rom::NLEN-1]+=carry;
return (self.w[rom::NLEN-1]>>((8*rom::MODBYTES)%rom::BASEBITS)) as Chunk;
}
/* Conditional swap of two bigs depending on d using XOR - no branches */
pub fn cswap(&mut self,b: &mut BIG,d: isize) {
let mut c= d as Chunk;
c=!(c-1);
for i in 0 ..rom::NLEN {
let t=c&(self.w[i]^b.w[i]);
self.w[i]^=t;
b.w[i]^=t;
}
}
pub fn cmove(&mut self,g:&BIG,d: isize) {
let b= -d as Chunk;
for i in 0 ..rom::NLEN {
self.w[i]^=(self.w[i]^g.w[i])&b;
}
}
/* Shift right by less than a word */
pub fn fshr(&mut self, k: usize) -> isize {
let n = k;
let w=self.w[0]&((1<<n)-1); /* shifted out part */
for i in 0 ..rom::NLEN-1 {
self.w[i]=(self.w[i]>>k)|((self.w[i+1]<<(rom::BASEBITS-n))&rom::BMASK);
}
self.w[rom::NLEN-1]=self.w[rom::NLEN-1]>>k;
return w as isize;
}
/* general shift right */
pub fn shr(&mut self,k:usize) {
let n=k%rom::BASEBITS;
let m=k/rom::BASEBITS;
for i in 0 ..rom::NLEN-m-1 {
self.w[i]=(self.w[m+i]>>n)|((self.w[m+i+1]<<(rom::BASEBITS-n))&rom::BMASK)
}
self.w[rom::NLEN-m-1]=self.w[rom::NLEN-1]>>n;
for i in rom::NLEN-m ..rom::NLEN
{self.w[i]=0}
}
/* Shift right by less than a word */
pub fn fshl(&mut self,k:usize) -> isize {
let n=k;
self.w[rom::NLEN-1]=((self.w[rom::NLEN-1]<<n))|(self.w[rom::NLEN-2]>>(rom::BASEBITS-n));
for i in (1 ..rom::NLEN-1).rev() {
self.w[i]=((self.w[i]<<k)&rom::BMASK)|(self.w[i-1]>>(rom::BASEBITS-n));
}
self.w[0]=(self.w[0]<<n)&rom::BMASK;
return (self.w[rom::NLEN-1]>>((8*rom::MODBYTES)%rom::BASEBITS)) as isize /* return excess - only used in ff.c */
}
/* general shift left */
pub fn shl(&mut self,k: usize) {
let n=k%rom::BASEBITS;
let m=k/rom::BASEBITS;
self.w[rom::NLEN-1]=self.w[rom::NLEN-1-m]<<n;
if rom::NLEN>=m+2 {self.w[rom::NLEN-1]|=self.w[rom::NLEN-m-2]>>(rom::BASEBITS-n)}
for i in (m+1 ..rom::NLEN-1).rev() {
self.w[i]=((self.w[i-m]<<n)&rom::BMASK)|(self.w[i-m-1]>>(rom::BASEBITS-n));
}
self.w[m]=(self.w[0]<<n)&rom::BMASK;
for i in 0 ..m {self.w[i]=0}
}
/* return number of bits */
pub fn nbits(&mut self) -> usize {
let mut k=rom::NLEN-1;
self.norm();
while (k as isize)>=0 && self.w[k]==0 {k=k.wrapping_sub(1)}
if (k as isize) <0 {return 0}
let mut bts=rom::BASEBITS*k;
let mut c=self.w[k];
while c!=0 {c/=2; bts+=1;}
return bts;
}
/* Convert to Hex String */
pub fn tostring(&mut self) -> String {
let mut s = String::new();
let mut len=self.nbits();
if len%4==0 {
len/=4;
} else {
len/=4;
len+=1;
}
let mb=(rom::MODBYTES*2) as usize;
if len<mb {len=mb}
for i in (0 ..len).rev() {
let mut b=BIG::new_copy(&self);
b.shr(i*4);
s=s + &format!("{:X}", b.w[0]&15);
}
return s;
}
pub fn fromstring(val: String) -> BIG {
let mut res = BIG::new();
let len = val.len();
let op = &val[0..1];
let n = u8::from_str_radix(op, 16).unwrap();
res.w[0] += n as Chunk;
for i in 1..len {
res.shl(4);
let op = &val[i..i+1];
let n = u8::from_str_radix(op, 16).unwrap();
res.w[0] += n as Chunk;
}
return res;
}
pub fn add(&mut self,r:&BIG) {
for i in 0 ..rom::NLEN {
self.w[i]+=r.w[i]
}
}
pub fn dbl(&mut self) {
for i in 0 ..rom::NLEN {
self.w[i]+=self.w[i]
}
}
/* return this+x */
pub fn plus(&self,x: &BIG) -> BIG {
let mut s=BIG::new();
for i in 0 ..rom::NLEN {
s.w[i]=self.w[i]+x.w[i];
}
return s;
}
pub fn inc(&mut self,x:isize) {
self.norm();
self.w[0]+=x as Chunk;
}
// pub fn incl(&mut self,x:Chunk) {
// self.norm();
// self.w[0]+=x;
// }
/* return self-x */
pub fn minus(&self,x:& BIG) -> BIG {
let mut d=BIG::new();
for i in 0 ..rom::NLEN {
d.w[i]=self.w[i]-x.w[i];
}
return d;
}
/* self-=x */
pub fn sub(&mut self,x:&BIG) {
for i in 0 ..rom::NLEN {
self.w[i]-=x.w[i];
}
}
/* reverse subtract this=x-this */
pub fn rsub(&mut self,x:&BIG) {
for i in 0 ..rom::NLEN {
self.w[i]=x.w[i]-self.w[i]
}
}
/* self-=x, where x is int */
pub fn dec(&mut self,x:isize) {
self.norm();
self.w[0]-= x as Chunk;
}
/* self*=x, where x is small int<NEXCESS */
pub fn imul(&mut self,c: isize) {
for i in 0 ..rom::NLEN {
self.w[i]*=c as Chunk;
}
}
/* convert this BIG to byte array */
pub fn tobytearray(&mut self,b: &mut [u8],n:usize) {
self.norm();
let mut c=BIG::new_copy(self);
for i in (0 ..(rom::MODBYTES as usize)).rev() {
b[i+n]=(c.w[0]&0xff) as u8;
c.fshr(8);
}
}
/* convert from byte array to BIG */
pub fn frombytearray(b: &[u8],n:usize) -> BIG {
let mut m=BIG::new();
for i in 0 ..(rom::MODBYTES as usize) {
m.fshl(8); m.w[0]+=(b[i+n]&0xff) as Chunk;
}
return m;
}
pub fn tobytes(&mut self,b: &mut [u8]) {
self.tobytearray(b,0)
}
pub fn frombytes(b: &[u8]) -> BIG {
return BIG::frombytearray(b,0)
}
pub fn to_hex(&mut self) -> String {
self.tostring()
}
pub fn from_hex(val: String) -> BIG {
BIG::fromstring(val)
}
/* self*=x, where x is >NEXCESS */
pub fn pmul(&mut self,c: isize) -> Chunk {
let mut carry=0 as Chunk;
self.norm();
for i in 0 ..rom::NLEN {
let ak=self.w[i];
let tuple=BIG::muladd(ak,c as Chunk,carry,0 as Chunk);
carry=tuple.0; self.w[i]=tuple.1;
}
return carry;
}
/* self*=c and catch overflow in DBIG */
pub fn pxmul(&mut self,c: isize) -> DBIG
{
let mut m=DBIG::new();
let mut carry=0 as Chunk;
for j in 0 ..rom::NLEN {
let tuple=BIG::muladd(self.w[j],c as Chunk,carry,m.w[j]);
carry=tuple.0; m.w[j]=tuple.1;
}
m.w[rom::NLEN]=carry;
return m;
}
/* divide by 3 */
pub fn div3(&mut self) -> Chunk
{
let mut carry=0 as Chunk;
self.norm();
let base=1<<rom::BASEBITS;
for i in (0 ..rom::NLEN).rev() {
let ak=carry*base+self.w[i];
self.w[i]=ak/3;
carry=ak%3;
}
return carry;
}
/* return a*b where result fits in a BIG */
pub fn smul(a: &BIG,b: &BIG) -> BIG {
let mut c=BIG::new();
for i in 0 ..rom::NLEN {
let mut carry=0 as Chunk;
for j in 0 ..rom::NLEN {
if i+j<rom::NLEN {
let tuple=BIG::muladd(a.w[i],b.w[j],carry,c.w[i+j]);
carry=tuple.0; c.w[i+j]=tuple.1;
}
}
}
return c;
}
/* Compare a and b, return 0 if a==b, -1 if a<b, +1 if a>b. Inputs must be normalised */
pub fn comp(a: &BIG,b: &BIG) -> isize {
for i in (0 ..rom::NLEN).rev() {
if a.w[i]==b.w[i] {continue}
if a.w[i]>b.w[i] {return 1}
else {return -1}
}
return 0;
}
/* set x = x mod 2^m */
pub fn mod2m(&mut self,m: usize)
{
let wd=m/rom::BASEBITS;
let bt=m%rom::BASEBITS;
let msk=(1<<bt)-1;
self.w[wd]&=msk;
for i in wd+1 ..rom::NLEN {self.w[i]=0}
}
/* Arazi and Qi inversion mod 256 */
pub fn invmod256(a: isize) -> isize {
let mut t1:isize=0;
let mut c=(a>>1)&1;
t1+=c;
t1&=1;
t1=2-t1;
t1<<=1;
let mut u=t1+1;
// i=2
let mut b=a&3;
t1=u*b; t1>>=2;
c=(a>>2)&3;
let mut t2=(u*c)&3;
t1+=t2;
t1*=u; t1&=3;
t1=4-t1;
t1<<=2;
u+=t1;
// i=4
b=a&15;
t1=u*b; t1>>=4;
c=(a>>4)&15;
t2=(u*c)&15;
t1+=t2;
t1*=u; t1&=15;
t1=16-t1;
t1<<=4;
u+=t1;
return u;
}
/* return parity */
pub fn parity(&self) -> isize {
return (self.w[0]%2) as isize;
}
/* return n-th bit */
pub fn bit(&self,n: usize) -> isize {
if (self.w[n/(rom::BASEBITS as usize)]&(1<<(n%rom::BASEBITS)))>0 {return 1;}
else {return 0;}
}
/* return n last bits */
pub fn lastbits(&mut self,n: usize) -> isize
{
let msk = ((1<<n)-1) as Chunk;
self.norm();
return (self.w[0]&msk) as isize;
}
/* a=1/a mod 2^256. This is very fast! */
pub fn invmod2m(&mut self) {
let mut u=BIG::new();
let mut b=BIG::new();
let mut c=BIG::new();
u.inc(BIG::invmod256(self.lastbits(8)));
let mut i=8;
while i<rom::BIGBITS {
b.copy(self);
b.mod2m(i);
let mut t1=BIG::smul(&u,&b);
t1.shr(i);
c.copy(self);
c.shr(i);
c.mod2m(i);
let mut t2=BIG::smul(&u,&c);
t2.mod2m(i);
t1.add(&t2);
b=BIG::smul(&t1,&u);
t1.copy(&b);
t1.mod2m(i);
t2.one(); t2.shl(i); t1.rsub(&t2); t1.norm();
t1.shl(i);
u.add(&t1);
i<<=1;
}
u.mod2m(rom::BIGBITS);
self.copy(&u);
self.norm();
}
/* reduce self mod m */
pub fn rmod(&mut self,n: &BIG) {
let mut k=0;
let mut m=BIG::new_copy(n);
let mut r=BIG::new();
self.norm();
if BIG::comp(self,&m)<0 {return}
loop {
m.fshl(1);
k += 1;
if BIG::comp(self,&m)<0 {break}
}
while k>0 {
m.fshr(1);
r.copy(self);
r.sub(&m);
r.norm();
self.cmove(&r,(1-((r.w[rom::NLEN-1]>>(rom::CHUNK-1))&1)) as isize);
/*
if BIG::comp(self,&m)>=0 {
self.sub(&m);
self.norm();
} */
k -= 1;
}
}
/* divide self by m */
pub fn div(&mut self,n: &BIG) {
let mut k=0;
self.norm();
let mut e=BIG::new_int(1);
let mut b=BIG::new_copy(self);
let mut m=BIG::new_copy(n);
let mut r=BIG::new();
self.zero();
while BIG::comp(&b,&m)>=0 {
e.fshl(1);
m.fshl(1);
k += 1;
}
while k>0 {
m.fshr(1);
e.fshr(1);
r.copy(&b);
r.sub(&m);
r.norm();
let d=(1-((r.w[rom::NLEN-1]>>(rom::CHUNK-1))&1)) as isize;
b.cmove(&r,d);
r.copy(self);
r.add(&e);
r.norm();
self.cmove(&r,d);
/*
if BIG::comp(&b,&m)>=0 {
self.add(&e);
self.norm();
b.sub(&m);
b.norm();
} */
k -= 1;
}
}
/* get 8*MODBYTES size random number */
pub fn random(rng: &mut RAND) -> BIG {
let mut m=BIG::new();
let mut j=0;
let mut r:u8=0;
/* generate random BIG */
for _ in 0..8*(rom::MODBYTES as usize) {
if j==0 {
r=rng.getbyte()
} else {r>>=1}
let b= (r as Chunk)&1;
m.shl(1); m.w[0]+=b;// m.inc(b)
j+=1; j&=7;
}
return m;
}
/* Create random BIG in portable way, one bit at a time */
pub fn randomnum(q: &BIG,rng: &mut RAND) -> BIG {
let mut d=DBIG::new();
let mut j=0;
let mut r:u8=0;
for _ in 0..2*(rom::MODBITS as usize) {
if j==0 {
r=rng.getbyte();
} else {r>>=1}
let b= (r as Chunk)&1;
d.shl(1); d.w[0]+=b; // m.inc(b);
j+=1; j&=7;
}
let m=d.dmod(q);
return m;
}
/* Jacobi Symbol (this/p). Returns 0, 1 or -1 */
pub fn jacobi(&mut self,p: &BIG) -> isize {
let mut m:usize=0;
let mut t=BIG::new();
let mut x=BIG::new();
let mut n=BIG::new();
let zilch=BIG::new();
let one=BIG::new_int(1);
if p.parity()==0 || BIG::comp(self,&zilch)==0 || BIG::comp(p,&one)<=0 {return 0}
self.norm();
x.copy(self);
n.copy(p);
x.rmod(p);
while BIG::comp(&n,&one)>0 {
if BIG::comp(&x,&zilch)==0 {return 0}
let n8=n.lastbits(3) as usize;
let mut k=0;
while x.parity()==0 {
k += 1;
x.shr(1);
}
if k%2==1 {m+=(n8*n8-1)/8}
m+=(n8-1)*((x.lastbits(2) as usize)-1)/4;
t.copy(&n);
t.rmod(&x);
n.copy(&x);
x.copy(&t);
m%=2;
}
if m==0 {return 1}
else {return -1}
}
/* self=1/self mod p. Binary method */
pub fn invmodp(&mut self,p: &BIG) {
self.rmod(p);
let mut u=BIG::new_copy(self);
let mut v=BIG::new_copy(p);
let mut x1=BIG::new_int(1);
let mut x2=BIG::new();
let mut t=BIG::new();
let one=BIG::new_int(1);
while (BIG::comp(&u,&one) != 0 ) && (BIG::comp(&v,&one) != 0 ) {
while u.parity()==0 {
u.shr(1);
if x1.parity() != 0 {
x1.add(p);
x1.norm();
}
x1.shr(1);
}
while v.parity()==0 {
v.shr(1);
if x2.parity() != 0 {
x2.add(p);
x2.norm();
}
x2.shr(1);
}
if BIG::comp(&u,&v)>=0 {
u.sub(&v);
u.norm();
if BIG::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 BIG::comp(&x2,&x1)>=0 {x2.sub(&x1)}
else
{
t.copy(p);
t.sub(&x1);
x2.add(&t);
}
x2.norm();
}
}
if BIG::comp(&u,&one)==0 {self.copy(&x1)}
else {self.copy(&x2)}
}
/* return a*b as DBIG */
#[cfg(target_pointer_width = "32")]
pub fn mul(a: &BIG,b: &BIG) -> DBIG {
let mut c=DBIG::new();
let rm=rom::BMASK as DChunk;
let rb=rom::BASEBITS;
// a.norm();
// b.norm();
let mut d: [DChunk; rom::DNLEN] = [0; rom::DNLEN];
for i in 0 ..rom::NLEN {
d[i]=(a.w[i] as DChunk)*(b.w[i] as DChunk);
}
let mut s=d[0];
let mut t=s; c.w[0]=(t&rm) as Chunk;
let mut co=t>>rb;
for k in 1 ..rom::NLEN {
s+=d[k]; t=co+s;
for i in 1+k/2..k+1
{t+=((a.w[i]-a.w[k-i]) as DChunk)*((b.w[k-i]-b.w[i]) as DChunk)}
c.w[k]=(t&rm) as Chunk; co=t>>rb;
}
for k in rom::NLEN ..2*rom::NLEN-1 {
s-=d[k-rom::NLEN]; t=co+s;
let mut i=1+k/2;
while i<rom::NLEN {
t+=((a.w[i]-a.w[k-i]) as DChunk)*((b.w[k-i]-b.w[i]) as DChunk);
i+=1;
}
c.w[k]=(t&rm) as Chunk; co=t>>rb;
}
c.w[2*rom::NLEN-1]=co as Chunk;
return c;
}
/* return a^2 as DBIG */
#[cfg(target_pointer_width = "32")]
pub fn sqr(a: &BIG) -> DBIG {
let mut c=DBIG::new();
let rm=rom::BMASK as DChunk;
let rb=rom::BASEBITS;
// a.norm();
let mut t=(a.w[0] as DChunk)*(a.w[0] as DChunk);
c.w[0]=(t&rm) as Chunk; let mut co=t>>rb;
t=(a.w[1] as DChunk)*(a.w[0] as DChunk); t+=t; t+=co;
c.w[1]=(t&rm) as Chunk; co=t>>rb;
let last=rom::NLEN-(rom::NLEN%2);
let mut j=2;
while j<last {
t=(a.w[j] as DChunk)*(a.w[0] as DChunk); for i in 1 ..(j+1)/2 {t+=(a.w[j-i] as DChunk)*(a.w[i] as DChunk)} ; t+=t; t+=co; t+=(a.w[j/2] as DChunk)*(a.w[j/2] as DChunk);
c.w[j]=(t&rm) as Chunk; co=t>>rb;
t=(a.w[j+1] as DChunk)*(a.w[0] as DChunk); for i in 1 ..(j+2)/2 {t+=(a.w[j+1-i] as DChunk)*(a.w[i] as DChunk)} ; t+=t; t+=co;
c.w[j+1]=(t&rm) as Chunk; co=t>>rb;
j+=2;
}
j=last;
if rom::NLEN%2==1 {
t=(a.w[j] as DChunk)*(a.w[0] as DChunk); for i in 1 ..(j+1)/2 {t+=(a.w[j-i] as DChunk)*(a.w[i] as DChunk)} ; t+=t; t+=co; t+=(a.w[j/2] as DChunk)*(a.w[j/2] as DChunk);
c.w[j]=(t&rm) as Chunk; co=t>>rb; j += 1;
t=(a.w[rom::NLEN-1] as DChunk)*(a.w[j-rom::NLEN+1] as DChunk); for i in j-rom::NLEN+2 ..(j+1)/2 {t+=(a.w[j-i] as DChunk)*(a.w[i] as DChunk)}; t+=t; t+=co;
c.w[j]=(t&rm) as Chunk; co=t>>rb; j += 1;
}
while j<rom::DNLEN-2 {
t=(a.w[rom::NLEN-1] as DChunk)*(a.w[j-rom::NLEN+1] as DChunk); for i in j-rom::NLEN+2 ..(j+1)/2 {t+=(a.w[j-i] as DChunk)*(a.w[i] as DChunk)} ; t+=t; t+=co; t+=(a.w[j/2] as DChunk)*(a.w[j/2] as DChunk);
c.w[j]=(t&rm) as Chunk; co=t>>rb;
t=(a.w[rom::NLEN-1] as DChunk)*(a.w[j-rom::NLEN+2] as DChunk); for i in j-rom::NLEN+3 ..(j+2)/2 {t+=(a.w[j+1-i] as DChunk)*(a.w[i] as DChunk)} ; t+=t; t+=co;
c.w[j+1]=(t&rm) as Chunk; co=t>>rb;
j+=2;
}
t=(a.w[rom::NLEN-1] as DChunk)*(a.w[rom::NLEN-1] as DChunk)+co;
c.w[rom::DNLEN-2]=(t&rm) as Chunk; co=t>>rb;
c.w[rom::DNLEN-1]=co as Chunk;
return c;
}
#[cfg(target_pointer_width = "32")]
fn monty(d: &mut DBIG) -> BIG {
let mut b=BIG::new();
let md=BIG::new_ints(&rom::MODULUS);
let rm=rom::BMASK as DChunk;
let rb=rom::BASEBITS;
let mut dd: [DChunk; rom::NLEN] = [0; rom::NLEN];
let mut v: [Chunk; rom::NLEN] = [0; rom::NLEN];
b.zero();
let mut t=d.w[0] as DChunk; v[0]=(((t&rm) as Chunk).wrapping_mul(rom::MCONST))&rom::BMASK; t+=(v[0] as DChunk)*(md.w[0] as DChunk); let mut c=(d.w[1] as DChunk)+(t>>rb); let mut s:DChunk=0;
for k in 1 ..rom::NLEN {
t=c+s+(v[0] as DChunk)*(md.w[k] as DChunk);
let mut i=1+k/2;
while i<k {
t+=((v[k-i]-v[i]) as DChunk)*((md.w[i]-md.w[k-i]) as DChunk);
i+=1;
}
v[k]=(((t&rm) as Chunk).wrapping_mul(rom::MCONST))&rom::BMASK; t+=(v[k] as DChunk)*(md.w[0] as DChunk); c=(d.w[k+1] as DChunk)+(t>>rb);
dd[k]=(v[k] as DChunk)*(md.w[k] as DChunk); s+=dd[k];
}
for k in rom::NLEN ..2*rom::NLEN-1
{
t=c+s;
let mut i=1+k/2;
while i<rom::NLEN {
t+=((v[k-i]-v[i]) as DChunk)*((md.w[i]-md.w[k-i]) as DChunk);
i+=1;
}
b.w[k-rom::NLEN]=(t&rm) as Chunk; c=(d.w[k+1] as DChunk)+(t>>rb); s-=dd[k-rom::NLEN+1];
}
b.w[rom::NLEN-1]=(c&rm) as Chunk;
b.norm();
return b;
}
/* return a*b as DBIG */
#[cfg(target_pointer_width = "64")]
pub fn mul(a: &BIG,b: &BIG) -> DBIG {
let mut c=DBIG::new();
let mut carry;
for i in 0 ..rom::NLEN {
carry=0;
for j in 0 ..rom::NLEN {
let tuple=BIG::muladd(a.w[i],b.w[j],carry,c.w[i+j]);
carry=tuple.0; c.w[i+j]=tuple.1;
}
c.w[rom::NLEN+i]=carry;
}
return c;
}
/* return a^2 as DBIG */
#[cfg(target_pointer_width = "64")]
pub fn sqr(a: &BIG) -> DBIG {
let mut c=DBIG::new();
let mut carry;
for i in 0 ..rom::NLEN {
carry=0;
for j in i+1 ..rom::NLEN {
let tuple=BIG::muladd(2*a.w[i],a.w[j],carry,c.w[i+j]);
carry=tuple.0; c.w[i+j]=tuple.1;
//carry,c.w[i+j]=muladd(2*a.w[i],a.w[j],carry,c.w[i+j])
//carry=c.muladd(2*a.w[i],a.w[j],carry,i+j)
}
c.w[rom::NLEN+i]=carry;
}
for i in 0 ..rom::NLEN {
let tuple=BIG::muladd(a.w[i],a.w[i],0,c.w[2*i]);
c.w[2*i]=tuple.1;
c.w[2*i+1]+=tuple.0;
//c.w[2*i+1]+=c.muladd(a.w[i],a.w[i],0,2*i)
}
c.norm();
return c;
}
#[cfg(target_pointer_width = "64")]
fn monty(d: &mut DBIG) -> BIG {
let mut b=BIG::new();
let md=BIG::new_ints(&rom::MODULUS);
let mut carry;
let mut m;
for i in 0 ..rom::NLEN {
if rom::MCONST==-1 {
m=(-d.w[i])&rom::BMASK;
} else {
if rom::MCONST==1 {
m=d.w[i];
} else {
m=(rom::MCONST.wrapping_mul(d.w[i]))&rom::BMASK;
}
}
carry=0;
for j in 0 ..rom::NLEN {
let tuple=BIG::muladd(m,md.w[j],carry,d.w[i+j]);
carry=tuple.0; d.w[i+j]=tuple.1;
}
d.w[rom::NLEN+i]+=carry;
}
for i in 0 ..rom::NLEN {
b.w[i]=d.w[rom::NLEN+i];
}
b.norm();
return b;
}
/* reduce a DBIG to a BIG using the appropriate form of the modulus */
/* dd */
pub fn modulo(d: &mut DBIG) -> BIG {
if rom::MODTYPE==rom::PSEUDO_MERSENNE {
let mut b=BIG::new();
let mut t=d.split(rom::MODBITS);
b.dcopy(&d);
let v=t.pmul(rom::MCONST as isize);
let tw=t.w[rom::NLEN-1];
t.w[rom::NLEN-1] &= rom::TMASK;
t.w[0]+=rom::MCONST*((tw>>rom::TBITS)+(v<<(rom::BASEBITS-rom::TBITS)));
b.add(&t);
b.norm();
return b;
}
if rom::MODTYPE==rom::MONTGOMERY_FRIENDLY
{
let mut b=BIG::new();
for i in 0 ..rom::NLEN {
let x=d.w[i];
let tuple=BIG::muladd(x,rom::MCONST-1,x,d.w[rom::NLEN+i-1]);
d.w[rom::NLEN+i]+=tuple.0; d.w[rom::NLEN+i-1]=tuple.1;
}
b.zero();
for i in 0 ..rom::NLEN {
b.w[i]=d.w[rom::NLEN+i];
}
b.norm();
return b;
}
if rom::MODTYPE==rom::GENERALISED_MERSENNE
{ // GoldiLocks Only
let mut b=BIG::new();
let t=d.split(rom::MODBITS);
let rm2=(rom::MODBITS/2) as usize;
b.dcopy(&d);
b.add(&t);
let mut dd=DBIG::new_scopy(&t);
dd.shl(rm2);
let mut tt=dd.split(rom::MODBITS);
let lo=BIG::new_dcopy(&dd);
b.add(&tt);
b.add(&lo);
b.norm();
tt.shl(rm2);
b.add(&tt);
let carry=b.w[rom::NLEN-1]>>rom::TBITS;
b.w[rom::NLEN-1]&=rom::TMASK;
b.w[0]+=carry;
b.w[(224/rom::BASEBITS) as usize]+=carry<<(224%rom::BASEBITS);
b.norm();
return b;
}
if rom::MODTYPE==rom::NOT_SPECIAL {
return BIG::monty(d);
}
return BIG::new();
}
/* return a*b mod m */
pub fn modmul(a: &mut BIG,b: &mut BIG,m: &BIG) -> BIG {
a.rmod(m);
b.rmod(m);
let mut d=BIG::mul(a,b);
return d.dmod(m);
}
/* return a^2 mod m */
pub fn modsqr(a: &mut BIG,m: &BIG) -> BIG {
a.rmod(m);
let mut d=BIG::sqr(a);
return d.dmod(m);
}
/* return -a mod m */
pub fn modneg(a: &mut BIG,m: &BIG) -> BIG {
a.rmod(m);
return m.minus(a);
}
/* return this^e mod m */
pub fn powmod(&mut self,e: &mut BIG,m: &BIG) -> BIG {
self.norm();
e.norm();
let mut a=BIG::new_int(1);
let mut z=BIG::new_copy(e);
let mut s=BIG::new_copy(self);
loop {
let bt=z.parity();
z.fshr(1);
if bt==1 {a=BIG::modmul(&mut a,&mut s,m)}
if z.iszilch() {break}
s=BIG::modsqr(&mut s,m);
}
return a;
}
}
/*
fn main() {
let fd: [i32; rom::NLEN as usize] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut x= BIG::new();
x.inc(3);
println!("{}", x.w[0]);
let mut y= BIG::new_int(7);
println!("{}", y.w[0]);
y=BIG::new_copy(&x);
println!("{}", y.w[0]);
x.add(&y);
x.add(&y);
println!("{}", x.w[0]);
let mut z= BIG::new_ints(&fd);
println!("{}", z.w[0]);
z.shr(3);
z.norm();
println!("{:X}", z.w[0]);
println!("{}",z.tostring());
let mut a = BIG::new_int(3);
let mut m = BIG::new_ints(&MODULUS);
println!("rom::MODULUS= {}",m.tostring());
let mut e = BIG::new_copy(&m);
e.dec(1); e.norm();
println!("Exponent= {}",e.tostring());
// for i in 0..20
// {
a=a.powmod(&mut e,&mut m);
// a.inc(2);
// }
println!("Result= {}",a.tostring());
}
*/