use super::super::arch;
use super::big;
use super::big::BIG;
use super::super::arch::Chunk;
#[derive(Copy)]
pub struct DBIG {
pub w: [Chunk; big::DNLEN],
}
impl Clone for DBIG {
fn clone(&self) -> DBIG { *self }
}
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;
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;
}
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;
}
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
}
}
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
}
}
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;
}
}
pub fn add(&mut self, x: &DBIG) {
for i in 0..big::DNLEN {
self.w[i] += x.w[i];
}
}
pub fn sub(&mut self, x: &DBIG) {
for i in 0..big::DNLEN {
self.w[i] -= x.w[i];
}
}
pub fn rsub(&mut self, x: &DBIG) {
for i in 0..big::DNLEN {
self.w[i] = x.w[i] - self.w[i];
}
}
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;
}
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
}
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,
);
k -= 1;
}
let r = BIG::new_dcopy(self);
return r;
}
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);
k -= 1;
}
return a;
}
pub fn mod2m(&mut self, m: usize) {
let wd = m / big::BASEBITS;
let bt = m % big::BASEBITS;
let msk = (1 << bt) - 1;
self.w[wd] &= msk;
for i in wd + 1..big::DNLEN {
self.w[i] = 0
}
}
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;
}
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;
}
}