blob: 07226edf03ac7d8ef6179b66c787891a0a689522 [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.
*/
/* AMCL BIG number class */
var BIG,
DBIG;
BIG = function(ctx) {
"use strict";
/**
* General purpose Constructor
*
* @constructor
* @this {BIG}
*/
var BIG = function(x) {
this.w = new Array(BIG.NLEN);
switch (typeof(x)) {
case "object":
this.copy(x);
break;
case "number":
this.zero();
this.w[0] = x;
break;
default:
this.zero();
}
};
BIG.CHUNK = 32;
BIG.MODBYTES = ctx.config["@NB"];
BIG.BASEBITS = ctx.config["@BASE"];
BIG.NLEN = (1 + (Math.floor((8 * BIG.MODBYTES - 1) / BIG.BASEBITS)));
BIG.DNLEN = 2 * BIG.NLEN;
BIG.BMASK = (1 << BIG.BASEBITS) - 1;
BIG.BIGBITS = (8 * BIG.MODBYTES);
BIG.NEXCESS = (1 << (BIG.CHUNK - BIG.BASEBITS - 1));
BIG.MODINV = (Math.pow(2, -BIG.BASEBITS));
BIG.prototype = {
/**
* set to zero
*
* @this {BIG}
* @return BIG number
*/
zero: function() {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] = 0;
}
return this;
},
/**
* set to one
*
* @this {BIG}
* @return BIG number
*/
one: function() {
var i;
this.w[0] = 1;
for (i = 1; i < BIG.NLEN; i++) {
this.w[i] = 0;
}
return this;
},
get: function(i) {
return this.w[i];
},
set: function(i, x) {
this.w[i] = x;
},
/**
* test for zero
*
* @this {BIG}
* @return True if zero
*/
iszilch: function() {
var i;
for (i = 0; i < BIG.NLEN; i++) {
if (this.w[i] !== 0) {
return false;
}
}
return true;
},
/**
* test for unity
*
* @this {BIG}
* @return True if one
*/
isunity: function() {
var i;
for (i = 1; i < BIG.NLEN; i++) {
if (this.w[i] !== 0) {
return false;
}
}
if (this.w[0] != 1) {
return false;
}
return true;
},
/**
* Conditional swap of two BIGs depending on d using XOR - no branches
*
* @this {BIG}
* @parameter b BIG number
* @parameter d BIG number
*/
cswap: function(b, d) {
var c = d,
t, i;
c = ~(c - 1);
for (i = 0; i < BIG.NLEN; i++) {
t = c & (this.w[i] ^ b.w[i]);
this.w[i] ^= t;
b.w[i] ^= t;
}
},
/**
* Conditional move of BIG depending on d using XOR - no branches
*
* @this {BIG}
* @parameter b BIG number
* @parameter d BIG number
*/
cmove: function(b, d) {
var c = d,
i;
c = ~(c - 1);
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] ^= (this.w[i] ^ b.w[i]) & c;
}
},
/**
* Copy from another BIG
*
* @this {BIG}
* @parameter y BIG number
* @return The BIG object
*/
copy: function(y) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] = y.w[i];
}
return this;
},
/**
* copy from bottom half of ctx.DBIG
*
* @this {BIG}
* @parameter y BIG number
* @return The new BIG object
*/
hcopy: function(y) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] = y.w[i];
}
return this;
},
/**
* copy from ROM
*
* @this {BIG}
* @parameter y BIG number in ROM
* @return The BIG object
*/
rcopy: function(y) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] = y[i];
}
return this;
},
xortop: function(x) {
this.w[BIG.NLEN - 1] ^= x;
},
ortop: function(x) {
this.w[BIG.NLEN - 1] |= x;
},
/**
* normalise BIG - force all digits < 2^BASEBITS
*
* @this {BIG}
* @return BIG number
*/
norm: function() {
var carry = 0,
d, i;
for (i = 0; i < BIG.NLEN - 1; i++) {
d = this.w[i] + carry;
this.w[i] = d & BIG.BMASK;
carry = d >> BIG.BASEBITS;
}
this.w[BIG.NLEN - 1] = (this.w[BIG.NLEN - 1] + carry);
return (this.w[BIG.NLEN - 1] >> ((8 * BIG.MODBYTES) % BIG.BASEBITS));
},
/**
* Quick Fast shifts a BIG right by a small number of bits - input must be normalised, output will be normalised
*
* @this {BIG}
* @parameter k Number of bits to shift
* @return r The shifted out part
*/
fshr: function(k) {
var r, i;
r = this.w[0] & ((1 << k) - 1); /* shifted out part */
for (i = 0; i < BIG.NLEN - 1; i++) {
this.w[i] = (this.w[i] >> k) | ((this.w[i + 1] << (BIG.BASEBITS - k)) & BIG.BMASK);
}
this.w[BIG.NLEN - 1] = this.w[BIG.NLEN - 1] >> k;
return r;
},
/**
* General shift right by k bits
*
* @this {BIG}
* @parameter k Number of bits to shift
* @return BIG number
*/
shr: function(k) {
var n = k % BIG.BASEBITS,
m = Math.floor(k / BIG.BASEBITS),
i;
for (i = 0; i < BIG.NLEN - m - 1; i++) {
this.w[i] = (this.w[m + i] >> n) | ((this.w[m + i + 1] << (BIG.BASEBITS - n)) & BIG.BMASK);
}
this.w[BIG.NLEN - m - 1] = this.w[BIG.NLEN - 1] >> n;
for (i = BIG.NLEN - m; i < BIG.NLEN; i++) {
this.w[i] = 0;
}
return this;
},
/**
* Fast shifts a BIG left by a small number of bits - input must be normalised, output will be normalised
*
* @this {BIG}
* @parameter k Number of bits to shift
* @return r The shifted out part
*/
fshl: function(k) {
var i;
this.w[BIG.NLEN - 1] = ((this.w[BIG.NLEN - 1] << k)) | (this.w[BIG.NLEN - 2] >> (BIG.BASEBITS - k));
for (i = BIG.NLEN - 2; i > 0; i--) {
this.w[i] = ((this.w[i] << k) & BIG.BMASK) | (this.w[i - 1] >> (BIG.BASEBITS - k));
}
this.w[0] = (this.w[0] << k) & BIG.BMASK;
return (this.w[BIG.NLEN - 1] >> ((8 * BIG.MODBYTES) % BIG.BASEBITS)); /* return excess - only used in FF.java */
},
/**
* General shift left by k bits
*
* @this {BIG}
* @parameter k Number of bits to shift
* @return BIG number
*/
shl: function(k) {
var n = k % BIG.BASEBITS,
m = Math.floor(k / BIG.BASEBITS),
i;
this.w[BIG.NLEN - 1] = (this.w[BIG.NLEN - 1 - m] << n);
if (BIG.NLEN > m + 2) {
this.w[BIG.NLEN - 1] |= (this.w[BIG.NLEN - m - 2] >> (BIG.BASEBITS - n));
}
for (i = BIG.NLEN - 2; i > m; i--) {
this.w[i] = ((this.w[i - m] << n) & BIG.BMASK) | (this.w[i - m - 1] >> (BIG.BASEBITS - n));
}
this.w[m] = (this.w[0] << n) & BIG.BMASK;
for (i = 0; i < m; i++) {
this.w[i] = 0;
}
return this;
},
/**
* length in bits
*
* @this {BIG}
* @return The number of bigs in BIG object
*/
nbits: function() {
var k = BIG.NLEN - 1,
bts, c;
var t=new BIG(0); t.copy(this);
t.norm();
while (k >= 0 && t.w[k] === 0) {
k--;
}
if (k < 0) {
return 0;
}
bts = BIG.BASEBITS * k;
c = t.w[k];
while (c !== 0) {
c = Math.floor(c / 2);
bts++;
}
return bts;
},
/**
* Convert to string
*
* @this {BIG}
* @return string representation of a BIG number
*/
toString: function() {
var s = "",
len = this.nbits(),
b, i;
if (len % 4 === 0) {
len = Math.floor(len / 4);
} else {
len = Math.floor(len / 4);
len++;
}
if (len < BIG.MODBYTES * 2) {
len = BIG.MODBYTES * 2;
}
for (i = len - 1; i >= 0; i--) {
b = new BIG(0);
b.copy(this);
b.shr(i * 4);
s += (b.w[0] & 15).toString(16);
}
return s;
},
/**
* Sum two BIG mumbers
*
* @this {BIG}
* @parameter y BIG object
* @return this+=y
*/
add: function(y) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] += y.w[i];
}
return this;
},
/**
* OR two BIG mumbers
*
* @this {BIG}
* @parameter y BIG object
* @return this|=y
*/
or: function(y) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] |= y.w[i];
}
return this;
},
/**
* Sum two BIG mumbers
*
* @this {BIG}
* @parameter x BIG object
* @return this+x
*/
plus: function(x) {
var s = new BIG(0),
i;
for (i = 0; i < BIG.NLEN; i++) {
s.w[i] = this.w[i] + x.w[i];
}
return s;
},
/**
* Sum BIG and integer
*
* @this {BIG}
* @parameter i Integer to add
* @return this+=i
*/
inc: function(i) {
this.norm();
this.w[0] += i;
return this;
},
/**
* Subtract BIG from one another
*
* @this {BIG}
* @parameter y BIG object
* @return this-=y
*/
sub: function(y) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] -= y.w[i];
}
return this;
},
/**
* Reverse subtract BIG from one another
*
* @this {BIG}
* @parameter x BIG object
* @return this=x-this
*/
rsub: function(x) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] = x.w[i] - this.w[i];
}
return this;
},
/**
* Subtract integer from BIG
*
* @this {BIG}
* @parameter i Integer to subtract
* @return this-=i
*/
dec: function(i) {
this.norm();
this.w[0] -= i;
return this;
},
/**
* Subtract BIG
*
* @this {BIG}
* @parameter x BIG object
* @return New BIG object
*/
minus: function(x) {
var d = new BIG(0),
i;
for (i = 0; i < BIG.NLEN; i++) {
d.w[i] = this.w[i] - x.w[i];
}
return d;
},
/**
* Multiply by small integer
*
* @this {BIG}
* @parameter c small integer
* @return this*c
*/
imul: function(c) {
var i;
for (i = 0; i < BIG.NLEN; i++) {
this.w[i] *= c;
}
return this;
},
/**
* convert this BIG to byte array
*
* @this {BIG}
*/
tobytearray: function(b, n) {
var c = new BIG(0),
i;
c.copy(this);
c.norm();
for (i = BIG.MODBYTES - 1; i >= 0; i--) {
b[i + n] = c.w[0] & 0xff;
c.fshr(8);
}
return this;
},
/**
* convert this to byte array
*
* @this {BIG}
*/
toBytes: function(b) {
this.tobytearray(b, 0);
},
/**
* this[i]+=x*y+c, and return high part
*
* @this {BIG}
*/
muladd: function(x, y, c, i) {
var prod = x * y + c + this.w[i];
this.w[i] = prod & BIG.BMASK;
return ((prod - this.w[i]) * BIG.MODINV);
},
/**
* multiply by larger int
*
* @this {BIG}
* @parameter c large integer
* @return carry value
*/
pmul: function(c) {
var carry = 0,
ak, i;
for (i = 0; i < BIG.NLEN; i++) {
ak = this.w[i];
this.w[i] = 0;
carry = this.muladd(ak, c, carry, i);
}
return carry;
},
/**
* multiply by still larger int - results requires a DBIG
*
* @this {BIG}
* @parameter c large integer
* @return DBIG object
*/
pxmul: function(c) {
var m = new ctx.DBIG(0),
carry = 0,
j;
for (j = 0; j < BIG.NLEN; j++) {
carry = m.muladd(this.w[j], c, carry, j);
}
m.w[BIG.NLEN] = carry;
return m;
},
/**
* divide by 3
*
* @this {BIG}
* @return carry value
*/
div3: function() {
var carry = 0,
ak, base, i;
this.norm();
base = (1 << BIG.BASEBITS);
for (i = BIG.NLEN - 1; i >= 0; i--) {
ak = (carry * base + this.w[i]);
this.w[i] = Math.floor(ak / 3);
carry = ak % 3;
}
return carry;
},
/**
* set x = x mod 2^m
*
* @this {BIG}
* @parameter m Exponent
* @return BIG object
*/
mod2m: function(m) {
var i, wd, bt, msk;
wd = Math.floor(m / BIG.BASEBITS);
bt = m % BIG.BASEBITS;
msk = (1 << bt) - 1;
this.w[wd] &= msk;
for (i = wd + 1; i < BIG.NLEN; i++) {
this.w[i] = 0;
}
},
/**
* a=1/a mod 2^256. This is very fast!
*
* @this {BIG}
* @return BIG object
*/
invmod2m: function() {
var U = new BIG(0),
b = new BIG(0),
c = new BIG(0),
i, t1, t2;
U.inc(BIG.invmod256(this.lastbits(8)));
for (i = 8; i < BIG.BIGBITS; i <<= 1) {
U.norm();
b.copy(this);
b.mod2m(i);
t1 = BIG.smul(U, b);
t1.shr(i);
c.copy(this);
c.shr(i);
c.mod2m(i);
t2 = BIG.smul(U, c);
t2.mod2m(i);
t1.add(t2);
t1.norm();
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);
}
U.mod2m(BIG.BIGBITS);
this.copy(U);
this.norm();
},
/**
* reduce this mod m
*
* @this {BIG}
* @return BIG object
*/
mod: function(m1) {
var k = 0,
r = new BIG(0);
var m=new BIG(0); m.copy(m1);
this.norm();
if (BIG.comp(this, m) < 0) {
return;
}
do {
m.fshl(1);
k++;
} while (BIG.comp(this, m) >= 0);
while (k > 0) {
m.fshr(1);
r.copy(this);
r.sub(m);
r.norm();
this.cmove(r, (1 - ((r.w[BIG.NLEN - 1] >> (BIG.CHUNK - 1)) & 1)));
k--;
}
},
/**
* this/=m1
*
* @this {BIG}
* @paramter m1 divisor
* @return BIG number
*/
div: function(m1) {
var k = 0,
d = 0,
e = new BIG(1),
b = new BIG(0),
r = new BIG(0);
var m=new BIG(0); m.copy(m1);
this.norm();
b.copy(this);
this.zero();
while (BIG.comp(b, m) >= 0) {
e.fshl(1);
m.fshl(1);
k++;
}
while (k > 0) {
m.fshr(1);
e.fshr(1);
r.copy(b);
r.sub(m);
r.norm();
d = (1 - ((r.w[BIG.NLEN - 1] >> (BIG.CHUNK - 1)) & 1));
b.cmove(r, d);
r.copy(this);
r.add(e);
r.norm();
this.cmove(r, d);
k--;
}
},
/**
* return parity of this
*
* @this {BIG}
* @return BIG object
*/
parity: function() {
return this.w[0] % 2;
},
/**
* return n-th bit of this
*
* @this {BIG}
* @parameter nth bit to return
* @return bit value
*/
bit: function(n) {
if ((this.w[Math.floor(n / BIG.BASEBITS)] & (1 << (n % BIG.BASEBITS))) > 0) {
return 1;
} else {
return 0;
}
},
/**
* return last n bits of this
*
* @this {BIG}
* @parameter n bits to return
* @return bit values
*/
lastbits: function(n) {
var msk = (1 << n) - 1;
this.norm();
return (this.w[0]) & msk;
},
isok: function() {
var ok = true,
i;
for (i = 0; i < BIG.NLEN; i++) {
if ((this.w[i] >> BIG.BASEBITS) != 0) {
ok = false;
}
}
return ok;
},
/**
* Jacobi Symbol (this/p)
*
* @this {BIG}
* @parameter p BIG number
* @return 0, 1 or -1
*/
jacobi: function(p) {
var m = 0,
t = new BIG(0),
x = new BIG(0),
n = new BIG(0),
zilch = new BIG(0),
one = new BIG(1),
n8, k;
if (p.parity() === 0 || BIG.comp(this, zilch) === 0 || BIG.comp(p, one) <= 0) {
return 0;
}
this.norm();
x.copy(this);
n.copy(p);
x.mod(p);
while (BIG.comp(n, one) > 0) {
if (BIG.comp(x, zilch) === 0) {
return 0;
}
n8 = n.lastbits(3);
k = 0;
while (x.parity() === 0) {
k++;
x.shr(1);
}
if (k % 2 == 1) {
m += (n8 * n8 - 1) / 8;
}
m += (n8 - 1) * (x.lastbits(2) - 1) / 4;
t.copy(n);
t.mod(x);
n.copy(x);
x.copy(t);
m %= 2;
}
if (m === 0) {
return 1;
} else {
return -1;
}
},
/**
* this=1/this mod p. Binary method
*
* @this {BIG}
* @parameter p The BIG Modulus
* @return BIG object
*/
invmodp: function(p) {
var u = new BIG(0),
v = new BIG(0),
x1 = new BIG(1),
x2 = new BIG(0),
t = new BIG(0),
one = new BIG(1);
this.mod(p);
u.copy(this);
v.copy(p);
while (BIG.comp(u, one) !== 0 && BIG.comp(v, one) !== 0) {
while (u.parity() === 0) {
u.fshr(1);
if (x1.parity() !== 0) {
x1.add(p);
x1.norm();
}
x1.fshr(1);
}
while (v.parity() === 0) {
v.fshr(1);
if (x2.parity() !== 0) {
x2.add(p);
x2.norm();
}
x2.fshr(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) {
this.copy(x1);
} else {
this.copy(x2);
}
},
/**
* Exponentation modulo m
*
* @this {BIG}
* @parameter e1 BIG number
* @parameter m The BIG Modulus
* @return this^e mod m
*/
powmod: function(e1, m) {
var a = new BIG(1),
z = new BIG(0),
s = new BIG(0),
bt;
var e=new BIG(0); e.copy(e1);
this.norm();
e.norm();
z.copy(e);
s.copy(this);
for (;;) {
bt = z.parity();
z.fshr(1);
if (bt == 1) {
a = BIG.modmul(a, s, m);
}
if (z.iszilch()) {
break;
}
s = BIG.modsqr(s, m);
}
return a;
}
};
BIG.ssn = function(r,a,m) {
var n=BIG.NLEN-1;
m.w[0]=(m.w[0]>>1)|((m.w[1]<<(BIG.BASEBITS-1))&BIG.BMASK);
r.w[0]=a.w[0]-m.w[0];
var carry=r.w[0]>>BIG.BASEBITS;
r.w[0]&=BIG.BMASK;
for (var i=1;i<n;i++) {
m.w[i]=(m.w[i]>>1)|((m.w[i+1]<<(BIG.BASEBITS-1))&BIG.BMASK);
r.w[i]=a.w[i]-m.w[i]+carry;
carry=r.w[i]>>BIG.BASEBITS;
r.w[i]&=BIG.BMASK;
}
m.w[n]>>=1;
r.w[n]=a.w[n]-m.w[n]+carry;
return ((r.w[n]>>(BIG.CHUNK-1))&1);
};
/**
* convert from byte array to BIG
*
* @this {BIG}
* @parameter b Bytearray
* @return BIG object
*/
BIG.frombytearray = function(b, n) {
var m = new BIG(0),
i;
for (i = 0; i < BIG.MODBYTES; i++) {
m.fshl(8);
m.w[0] += b[i + n] & 0xff;
}
return m;
};
BIG.fromBytes = function(b) {
return BIG.frombytearray(b, 0);
};
/**
* return a*b where product fits a BIG
*
* @this {BIG}
* @parameter a BIG number
* @parameter b BIG number
* @return a*b
*/
BIG.smul = function(a, b) {
var c = new BIG(0),
carry, i, j;
for (i = 0; i < BIG.NLEN; i++) {
carry = 0;
for (j = 0; j < BIG.NLEN; j++) {
if (i + j < BIG.NLEN) {
carry = c.muladd(a.w[i], b.w[j], carry, i + j);
}
}
}
return c;
};
/**
* Compare a and b
*
* @this {BIG}
* @parameter a BIG number (normalised)
* @parameter b BIG number (normalised
* @return 0 if a==b, -1 if a<b, +1 if a>b
*/
BIG.comp = function(a, b) {
var i;
for (i = BIG.NLEN - 1; i >= 0; i--) {
if (a.w[i] == b.w[i]) {
continue;
}
if (a.w[i] > b.w[i]) {
return 1;
} else {
return -1;
}
}
return 0;
};
/**
* Get 8*MODBYTES size random number
*
* @this {BIG}
* @parameter rng Cryptographically Secure Random Number Generator
* @return BIG number
*/
BIG.random = function(rng) {
var m = new BIG(0),
j = 0,
r = 0,
i, b;
/* generate random BIG */
for (i = 0; i < 8 * BIG.MODBYTES; i++) {
if (j === 0) {
r = rng.getByte();
} else {
r >>= 1;
}
b = r & 1;
m.shl(1);
m.w[0] += b; // m.inc(b);
j++;
j &= 7;
}
return m;
};
/**
* Create random BIG in portable way, one bit at a time
*
* @this {BIG}
* @parameter rng Cryptographically Secure Random Number Generator
* @parameter q The BIG Modulus
* @return BIG number
*/
BIG.randomnum = function(q, rng) {
var d = new ctx.DBIG(0),
j = 0,
r = 0,
i, b, m;
for (i = 0; i < 2 * q.nbits(); i++) {
if (j === 0) {
r = rng.getByte();
} else {
r >>= 1;
}
b = r & 1;
d.shl(1);
d.w[0] += b;
j++;
j &= 7;
}
m = d.mod(q);
return m;
};
/**
* Multiple two BIG numbers
*
* @this {BIG}
* @parameter a BIG number
* @parameter b BIG number
* @return a*b as a DBIG number
*/
BIG.mul = function(a, b) {
var c = new ctx.DBIG(0),
d = new Array(BIG.NLEN), //[],
n, s, t, i, k, co;
for (i = 0; i < BIG.NLEN; i++) {
d[i] = a.w[i] * b.w[i];
}
s = d[0];
t = s;
c.w[0] = t;
for (k = 1; k < BIG.NLEN; k++) {
s += d[k];
t = s;
for (i = k; i >= 1 + Math.floor(k / 2); i--) {
t += (a.w[i] - a.w[k - i]) * (b.w[k - i] - b.w[i]);
}
c.w[k] = t;
}
for (k = BIG.NLEN; k < 2 * BIG.NLEN - 1; k++) {
s -= d[k - BIG.NLEN];
t = s;
for (i = BIG.NLEN - 1; i >= 1 + Math.floor(k / 2); i--) {
t += (a.w[i] - a.w[k - i]) * (b.w[k - i] - b.w[i]);
}
c.w[k] = t;
}
co = 0;
for (i = 0; i < BIG.DNLEN - 1; i++) {
n = c.w[i] + co;
c.w[i] = n & BIG.BMASK;
co = (n - c.w[i]) * BIG.MODINV;
}
c.w[BIG.DNLEN - 1] = co;
return c;
};
/**
* Square two BIG numbers
*
* @this {BIG}
* @parameter a BIG number
* @return a*2 as a DBIG number
*/
BIG.sqr = function(a) {
var c = new ctx.DBIG(0),
n, t, j, i, co;
c.w[0] = a.w[0] * a.w[0];
for (j = 1; j < BIG.NLEN - 1;) {
t = a.w[j] * a.w[0];
for (i = 1; i < (j + 1) >> 1; i++) {
t += a.w[j - i] * a.w[i];
}
t += t;
c.w[j] = t;
j++;
t = a.w[j] * a.w[0];
for (i = 1; i < (j + 1) >> 1; i++) {
t += a.w[j - i] * a.w[i];
}
t += t;
t += a.w[j >> 1] * a.w[j >> 1];
c.w[j] = t;
j++;
}
for (j = BIG.NLEN - 1 + BIG.NLEN % 2; j < BIG.DNLEN - 3;) {
t = a.w[BIG.NLEN - 1] * a.w[j - BIG.NLEN + 1];
for (i = j - BIG.NLEN + 2; i < (j + 1) >> 1; i++) {
t += a.w[j - i] * a.w[i];
}
t += t;
c.w[j] = t;
j++;
t = a.w[BIG.NLEN - 1] * a.w[j - BIG.NLEN + 1];
for (i = j - BIG.NLEN + 2; i < (j + 1) >> 1; i++) {
t += a.w[j - i] * a.w[i];
}
t += t;
t += a.w[j >> 1] * a.w[j >> 1];
c.w[j] = t;
j++;
}
t = a.w[BIG.NLEN - 2] * a.w[BIG.NLEN - 1];
t += t;
c.w[BIG.DNLEN - 3] = t;
t = a.w[BIG.NLEN - 1] * a.w[BIG.NLEN - 1];
c.w[BIG.DNLEN - 2] = t;
co = 0;
for (i = 0; i < BIG.DNLEN - 1; i++) {
n = c.w[i] + co;
c.w[i] = n & BIG.BMASK;
co = (n - c.w[i]) * BIG.MODINV;
}
c.w[BIG.DNLEN - 1] = co;
return c;
};
BIG.monty = function(m, nd, d) {
var b = new BIG(0),
v = new Array(BIG.NLEN),
dd = new Array(BIG.NLEN),
s, c, t, i, k;
t = d.w[0];
v[0] = ((t & BIG.BMASK) * nd) & BIG.BMASK;
t += v[0] * m.w[0];
c = d.w[1] + (t * BIG.MODINV);
s = 0;
for (k = 1; k < BIG.NLEN; k++) {
t = c + s + v[0] * m.w[k];
for (i = k - 1; i > Math.floor(k / 2); i--) {
t += (v[k - i] - v[i]) * (m.w[i] - m.w[k - i]);
}
v[k] = ((t & BIG.BMASK) * nd) & BIG.BMASK;
t += v[k] * m.w[0];
c = (t * BIG.MODINV) + d.w[k + 1];
dd[k] = v[k] * m.w[k];
s += dd[k];
}
for (k = BIG.NLEN; k < 2 * BIG.NLEN - 1; k++) {
t = c + s;
for (i = BIG.NLEN - 1; i >= 1 + Math.floor(k / 2); i--) {
t += (v[k - i] - v[i]) * (m.w[i] - m.w[k - i]);
}
b.w[k - BIG.NLEN] = t & BIG.BMASK;
c = ((t - b.w[k - BIG.NLEN]) * BIG.MODINV) + d.w[k + 1];
s -= dd[k - BIG.NLEN + 1];
}
b.w[BIG.NLEN - 1] = c & BIG.BMASK;
return b;
};
/**
* Multiple two BIG numbers modulo m
*
* @this {BIG}
* @parameter a1 BIG number
* @parameter b1 BIG number
* @parameter m The BIG Modulus
* @return a1*b1 mod m as a BIG number
*/
BIG.modmul = function(a1, b1, m) {
var d;
var a=new BIG(0); a.copy(a1);
var b=new BIG(0); b.copy(b1);
a.mod(m);
b.mod(m);
d = BIG.mul(a, b);
return d.mod(m);
};
/**
* Square a BIG number modulo m
*
* @this {BIG}
* @parameter a1 BIG number
* @parameter m The BIG Modulus
* @return a*2 mod m as a BIG number
*/
BIG.modsqr = function(a1, m) {
var d;
var a=new BIG(0); a.copy(a1);
a.mod(m);
d = BIG.sqr(a);
return d.mod(m);
};
/**
* Inversion
*
* @this {BIG}
* @parameter a1 BIG number
* @parameter m The BIG Modulus
* @return -a1 mod m
*/
BIG.modneg = function(a1, m) {
var a=new BIG(0); a.copy(a1);
a.mod(m);
return m.minus(a);
};
/**
* Arazi and Qi inversion mod 256
*
* @this {BIG}
* @parameter a BIG number
* @return BIG number
*/
BIG.invmod256 = function(a) {
var U, t1, t2, b, c;
t1 = 0;
c = (a >> 1) & 1;
t1 += c;
t1 &= 1;
t1 = 2 - t1;
t1 <<= 1;
U = t1 + 1;
// i=2
b = a & 3;
t1 = U * b;
t1 >>= 2;
c = (a >> 2) & 3;
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 BIG;
};
/* AMCL double length DBIG number class */
DBIG = function(ctx) {
"use strict";
/**
* General purpose Constructor
*
* @constructor
* @this {DBIG}
*/
var DBIG = function(x) {
this.w = new Array(BIG.DNLEN);
this.zero();
this.w[0] = x;
};
DBIG.prototype = {
/**
* set to zero
*
* @this {DBIG}
* @return BIG number
*/
zero: function() {
for (var i = 0; i < ctx.BIG.DNLEN; i++) {
this.w[i] = 0;
}
return this;
},
/**
* set to b
*
* @this {DBIG}
* @parameter b DBIG number
* @return DBIG number
*/
copy: function(b) {
for (var i = 0; i < ctx.BIG.DNLEN; i++) {
this.w[i] = b.w[i];
}
return this;
},
/**
* copy from ctx.BIG
*
* @this {DBIG}
* @parameter b BIG number
* @return DBIG number
*/
hcopy: function(b) {
var i;
for (i = 0; i < ctx.BIG.NLEN; i++) {
this.w[i] = b.w[i];
}
for (i = ctx.BIG.NLEN; i < ctx.BIG.DNLEN; i++) {
this.w[i] = 0;
}
return this;
},
ucopy: function(b) {
var i;
for (i = 0; i < ctx.BIG.NLEN; i++) {
this.w[i] = 0;
}
for (i = ctx.BIG.NLEN; i < ctx.BIG.DNLEN; i++) {
this.w[i] = b.w[i - ctx.BIG.NLEN];
}
return this;
},
/**
* normalise DBIG - force all digits < 2^BASEBITS
*
* @this {DBIG}
* @return DBIG number
*/
norm: function() {
var carry = 0,
d, i;
for (i = 0; i < ctx.BIG.DNLEN - 1; i++) {
d = this.w[i] + carry;
this.w[i] = d & ctx.BIG.BMASK;
carry = d >> ctx.BIG.BASEBITS;
}
this.w[ctx.BIG.DNLEN - 1] = (this.w[ctx.BIG.DNLEN - 1] + carry);
return this;
},
/**
* this[i]+=x*y+c, and return high part
*
* @this {DBIG}
*/
muladd: function(x, y, c, i) {
var prod = x * y + c + this.w[i];
this.w[i] = prod & ctx.BIG.BMASK;
return ((prod - this.w[i]) * ctx.BIG.MODINV);
},
/**
* General shift right by k bits
*
* @this {DBIG}
* @parameter k Number of bits to shift
* @return BIG number
*/
shr: function(k) {
var n = k % ctx.BIG.BASEBITS,
m = Math.floor(k / ctx.BIG.BASEBITS),
i;
for (i = 0; i < ctx.BIG.DNLEN - m - 1; i++) {
this.w[i] = (this.w[m + i] >> n) | ((this.w[m + i + 1] << (ctx.BIG.BASEBITS - n)) & ctx.BIG.BMASK);
}
this.w[ctx.BIG.DNLEN - m - 1] = this.w[ctx.BIG.DNLEN - 1] >> n;
for (i = ctx.BIG.DNLEN - m; i < ctx.BIG.DNLEN; i++) {
this.w[i] = 0;
}
return this;
},
/**
* General shift left by k bits
*
* @this {BIG}
* @parameter k Number of bits to shift
* @return BIG number
*/
shl: function(k) {
var n = k % ctx.BIG.BASEBITS,
m = Math.floor(k / ctx.BIG.BASEBITS),
i;
this.w[ctx.BIG.DNLEN - 1] = ((this.w[ctx.BIG.DNLEN - 1 - m] << n)) | (this.w[ctx.BIG.DNLEN - m - 2] >> (ctx.BIG.BASEBITS - n));
for (i = ctx.BIG.DNLEN - 2; i > m; i--) {
this.w[i] = ((this.w[i - m] << n) & ctx.BIG.BMASK) | (this.w[i - m - 1] >> (ctx.BIG.BASEBITS - n));
}
this.w[m] = (this.w[0] << n) & ctx.BIG.BMASK;
for (i = 0; i < m; i++) {
this.w[i] = 0;
}
return this;
},
/**
* Conditional move of BIG depending on d using XOR - no branches
*
* @this {DBIG}
* @parameter b DBIG number
* @parameter d DBIG number
*/
cmove: function(b, d) {
var c = d,
i;
c = ~(c - 1);
for (i = 0; i < ctx.BIG.DNLEN; i++) {
this.w[i] ^= (this.w[i] ^ b.w[i]) & c;
}
},
/**
* Sum two DBIG mumbers
*
* @this {DBIG}
* @parameter x DBIG object
* @return this+=x
*/
add: function(x) {
for (var i = 0; i < ctx.BIG.DNLEN; i++) {
this.w[i] += x.w[i];
}
},
/**
* Subtract DBIG from one another
*
* @this {DBIG}
* @parameter x BIG object
* @return this-=x
*/
sub: function(x) {
for (var i = 0; i < ctx.BIG.DNLEN; i++) {
this.w[i] -= x.w[i];
}
},
rsub: function(x) {
for (var i = 0; i < ctx.BIG.DNLEN; i++) {
this.w[i] = x.w[i] - this.w[i];
}
},
/**
* length in bits
*
* @this {DBIG}
* @return The number of bigs in DBIG object
*/
nbits: function() {
var k = ctx.BIG.DNLEN - 1,
bts, c;
var t=new DBIG(0); t.copy(this);
t.norm();
while (k >= 0 && t.w[k] === 0) {
k--;
}
if (k < 0) {
return 0;
}
bts = ctx.BIG.BASEBITS * k;
c = t.w[k];
while (c !== 0) {
c = Math.floor(c / 2);
bts++;
}
return bts;
},
/**
* Convert to string
*
* @this {DBIG}
* @return string representation of a BIG number
*/
toString: function() {
var s = "",
len = this.nbits(),
b, i;
if (len % 4 === 0) {
len = Math.floor(len / 4);
} else {
len = Math.floor(len / 4);
len++;
}
for (i = len - 1; i >= 0; i--) {
b = new DBIG(0);
b.copy(this);
b.shr(i * 4);
s += (b.w[0] & 15).toString(16);
}
return s;
},
/**
* reduces this DBIG mod a ctx.BIG, and returns the ctx.BIG
*
* @this {DBIG}
* @return BIG object
*/
mod: function(c) {
var k = 0,
m = new DBIG(0),
dr = new DBIG(0),
r = new ctx.BIG(0);
this.norm();
m.hcopy(c);
r.hcopy(this);
if (DBIG.comp(this, m) < 0) {
return r;
}
do {
m.shl(1);
k++;
} while (DBIG.comp(this, m) >= 0);
while (k > 0) {
m.shr(1);
dr.copy(this);
dr.sub(m);
dr.norm();
this.cmove(dr, (1 - ((dr.w[ctx.BIG.DNLEN - 1] >> (ctx.BIG.CHUNK - 1)) & 1)));
k--;
}
r.hcopy(this);
return r;
},
/**
* this/=c
*
* @this {DBIG}
* @paramter c divisor
* @return DBIG number
*/
div: function(c) {
var d = 0,
k = 0,
m = new DBIG(0),
dr = new DBIG(0),
r = new ctx.BIG(0),
a = new ctx.BIG(0),
e = new ctx.BIG(1);
m.hcopy(c);
this.norm();
while (DBIG.comp(this, m) >= 0) {
e.fshl(1);
m.shl(1);
k++;
}
while (k > 0) {
m.shr(1);
e.shr(1);
dr.copy(this);
dr.sub(m);
dr.norm();
d = (1 - ((dr.w[ctx.BIG.DNLEN - 1] >> (ctx.BIG.CHUNK - 1)) & 1));
this.cmove(dr, d);
r.copy(a);
r.add(e);
r.norm();
a.cmove(r, d);
k--;
}
return a;
},
/**
* split this DBIG at position n, return higher half, keep lower half
*
* @this {DBIG}
* @paramter n Position to splitdivisor
* @return lower half BIG number
*/
split: function(n) {
var t = new ctx.BIG(0),
m = n % ctx.BIG.BASEBITS,
carry = this.w[ctx.BIG.DNLEN - 1] << (ctx.BIG.BASEBITS - m),
nw, i;
for (i = ctx.BIG.DNLEN - 2; i >= ctx.BIG.NLEN - 1; i--) {
nw = (this.w[i] >> m) | carry;
carry = (this.w[i] << (ctx.BIG.BASEBITS - m)) & ctx.BIG.BMASK;
t.w[i - ctx.BIG.NLEN + 1] = nw;
}
this.w[ctx.BIG.NLEN - 1] &= ((1 << m) - 1);
return t;
}
};
/**
* Compare a and b
*
* @this {DBIG}
* @parameter a DBIG number (normalised)
* @parameter b DBIG number (normalised
* @return 0 if a==b, -1 if a<b, +1 if a>b
*/
DBIG.comp = function(a, b) {
var i;
for (i = ctx.BIG.DNLEN - 1; i >= 0; i--) {
if (a.w[i] == b.w[i]) {
continue;
}
if (a.w[i] > b.w[i]) {
return 1;
} else {
return -1;
}
}
return 0;
};
return DBIG;
};
if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
module.exports = {
BIG: BIG,
DBIG: DBIG
};
}