blob: 2c5b680f0f6c1a5fa720cfe63e7c96bf344b342f [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 arch;
use xxx::big;
use xxx::big::BIG;
use arch::Chunk;
//#[derive(Copy, Clone)]
pub struct DBIG {
pub w: [Chunk; big::DNLEN]
}
impl DBIG {
pub fn new() -> DBIG {
DBIG {
w: [0; big::DNLEN as usize]
}
}
pub fn new_copy(y:&DBIG) -> DBIG {
let mut s= DBIG::new();
for i in 0..big::DNLEN {s.w[i]=y.w[i]}
return s;
}
pub fn new_scopy(x:&BIG) -> DBIG {
let mut b= DBIG::new();
for i in 0 ..big::NLEN {
b.w[i]=x.w[i];
}
b.w[big::NLEN-1]=x.get(big::NLEN-1)&big::BMASK; /* top word normalized */
b.w[big::NLEN]=x.get(big::NLEN-1)>>big::BASEBITS;
for i in big::NLEN+1 ..big::DNLEN {b.w[i]=0}
return b;
}
/* split DBIG at position n, return higher half, keep lower half */
pub fn split(&mut self,n: usize) -> BIG
{
let mut t=BIG::new();
let m=n%big::BASEBITS;
let mut carry=self.w[big::DNLEN-1]<<(big::BASEBITS-m);
for i in (big::NLEN-1..big::DNLEN-1).rev() {
let nw=(self.w[i]>>m)|carry;
carry= (self.w[i]<<(big::BASEBITS-m))&big::BMASK;
t.set(i+1-big::NLEN,nw);
}
self.w[big::NLEN-1]&=((1 as Chunk)<<m)-1;
return t;
}
/* general shift left */
pub fn shl(&mut self,k: usize)
{
let n=k%big::BASEBITS;
let m=k/big::BASEBITS;
self.w[big::DNLEN-1]=((self.w[big::DNLEN-1-m]<<n))|(self.w[big::DNLEN-m-2]>>(big::BASEBITS-n));
for i in (m+1..big::DNLEN-1).rev() {
self.w[i]=((self.w[i-m]<<n)&big::BMASK)|(self.w[i-m-1]>>(big::BASEBITS-n));
}
self.w[m]=(self.w[0]<<n)&big::BMASK;
for i in 0 ..m {self.w[i]=0}
}
/* general shift right */
pub fn shr(&mut self,k: usize) {
let n=k%big::BASEBITS;
let m=k/big::BASEBITS;
for i in 0 ..big::DNLEN-m-1 {
self.w[i]=(self.w[m+i]>>n)|((self.w[m+i+1]<<(big::BASEBITS-n))&big::BMASK);
}
self.w[big::DNLEN-m-1]=self.w[big::DNLEN-1]>>n;
for i in big::DNLEN - m ..big::DNLEN {self.w[i]=0}
}
/* Copy from another DBIG */
pub fn copy(&mut self,x: &DBIG) {
for i in 0 ..big::DNLEN {
self.w[i]=x.w[i];
}
}
pub fn ucopy(&mut self,x: &BIG) {
for i in 0 ..big::NLEN {
self.w[i]=0;
}
for i in big::NLEN ..big::DNLEN {
self.w[i]=x.w[i-big::NLEN];
}
}
pub fn cmove(&mut self,g:&DBIG,d: isize) {
let b=-d as Chunk;
for i in 0 ..big::DNLEN {
self.w[i]^=(self.w[i]^g.w[i])&b;
}
}
/* self+=x */
pub fn add(&mut self,x:&DBIG) {
for i in 0 ..big::DNLEN {
self.w[i]+=x.w[i];
}
}
/* self-=x */
pub fn sub(&mut self,x:&DBIG) {
for i in 0 ..big::DNLEN {
self.w[i]-=x.w[i];
}
}
/* self=x-self */
pub fn rsub(&mut self,x:&DBIG) {
for i in 0 ..big::DNLEN {
self.w[i]=x.w[i]-self.w[i];
}
}
/* 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: &DBIG,b: &DBIG) -> isize {
for i in (0 ..big::DNLEN).rev() {
if a.w[i]==b.w[i] {continue}
if a.w[i]>b.w[i] {return 1}
else {return -1}
}
return 0;
}
/* normalise BIG - force all digits < 2^big::BASEBITS */
pub fn norm(&mut self) {
let mut carry=0 as Chunk;
for i in 0 ..big::DNLEN-1 {
let d=self.w[i]+carry;
self.w[i]=d&big::BMASK;
carry=d>>big::BASEBITS;
}
self.w[big::DNLEN-1]+=carry
}
/* reduces self DBIG mod a BIG, and returns the BIG */
pub fn dmod(&mut self,c: &BIG) -> BIG {
let mut k=0;
self.norm();
let mut m=DBIG::new_scopy(c);
let mut dr=DBIG::new();
if DBIG::comp(self,&m)<0 {
let r=BIG::new_dcopy(self);
return r;
}
loop {
m.shl(1);
k += 1;
if DBIG::comp(self,&m)<0 {break;}
}
while k>0 {
m.shr(1);
dr.copy(self);
dr.sub(&m);
dr.norm();
self.cmove(&dr,(1-((dr.w[big::DNLEN-1]>>(arch::CHUNK-1))&1)) as isize);
/*
if DBIG::comp(self,&m)>=0 {
self.sub(&m);
self.norm();
} */
k -= 1;
}
let r=BIG::new_dcopy(self);
return r;
}
/* return this/c */
pub fn div(&mut self,c: &BIG) -> BIG {
let mut k=0;
let mut m=DBIG::new_scopy(c);
let mut a=BIG::new();
let mut e=BIG::new_int(1);
let mut dr=DBIG::new();
let mut r=BIG::new();
self.norm();
while DBIG::comp(self,&m)>=0 {
e.fshl(1);
m.shl(1);
k+=1;
}
while k>0 {
m.shr(1);
e.shr(1);
dr.copy(self);
dr.sub(&m);
dr.norm();
let d=(1-((dr.w[big::DNLEN-1]>>(arch::CHUNK-1))&1)) as isize;
self.cmove(&dr,d);
r.copy(&a);
r.add(&e);
r.norm();
a.cmove(&r,d);
/*
if DBIG::comp(self,&m)>0 {
a.add(&e);
a.norm();
self.sub(&m);
self.norm();
} */
k-=1;
}
return a;
}
/* return number of bits */
pub fn nbits(&mut self) -> usize {
let mut k=big::DNLEN-1;
let mut s=DBIG::new_copy(&self);
s.norm();
while (k as isize)>=0 && s.w[k]==0 {k=k.wrapping_sub(1)}
if (k as isize) <0 {return 0}
let mut bts=(big::BASEBITS as usize)*k;
let mut c=s.w[k];
while c!=0 {c/=2; bts+=1;}
return bts;
}
/* Convert to Hex String */
pub fn to_string(&mut self) -> String {
let mut s = String::new();
let mut len=self.nbits();
if len%4==0 {
len/=4;
} else {
len/=4;
len+=1;
}
for i in (0 ..len).rev() {
let mut b=DBIG::new_copy(&self);
b.shr(i*4);
s=s + &format!("{:X}", b.w[0]&15);
}
return s;
}
}