📄 bigint.js
字号:
//convert a bigInt into a string in a given base, from base 2 up to base 95.
//Base -1 prints the contents of the array representing the number.
function bigInt2str(x,base) {
var i,t,s="";
if (s6.length!=x.length)
s6=dup(x);
else
copy(s6,x);
if (base==-1) { //return the list of array contents
for (i=x.length-1;i>0;i--)
s+=x[i]+',';
s+=x[0];
}
else { //return it in the given base
while (!isZero(s6)) {
t=divInt(s6,base); //t=s6 % base; s6=floor(s6/base);
s=digitsStr.substring(t,t+1)+s;
}
}
if (s.length==0)
s="0";
return s;
}
//returns a duplicate of bigInt x
function dup(x) {
var i;
buff=new Array(x.length);
copy(buff,x);
return buff;
}
//do x=y on bigInts x and y. x must be an array at least as big as y (not counting the leading zeros in y).
function copy(x,y) {
var i;
var k=x.length<y.length ? x.length : y.length;
for (i=0;i<k;i++)
x[i]=y[i];
for (i=k;i<x.length;i++)
x[i]=0;
}
//do x=y on bigInt x and integer y.
function copyInt(x,n) {
var i,c;
for (c=n,i=0;i<x.length;i++) {
x[i]=c & mask;
c>>=bpe;
}
}
//do x=x+n where x is a bigInt and n is an integer.
//x must be large enough to hold the result.
function addInt(x,n) {
var i,k,c,b;
x[0]+=n;
k=x.length;
c=0;
for (i=0;i<k;i++) {
c+=x[i];
b=0;
if (c<0) {
b=-(c>>bpe);
c+=b*radix;
}
x[i]=c & mask;
c=(c>>bpe)-b;
if (!c) return; //stop carrying as soon as the carry is zero
}
}
//right shift bigInt x by n bits. n<bpe.
function rightShift(x,n) {
var i;
var k=Math.floor(n/bpe);
if (k) {
for (i=0;i<x.length-k;i++) //right shift x by k elements
x[i]=x[i+k];
for (;i<x.length;i++)
x[i]=0;
n%=bpe;
}
for (i=0;i<x.length-1;i++) {
x[i]=mask & ((x[i+1]<<(bpe-n)) | (x[i]>>n));
}
x[i]>>=n;
}
//do x=floor(|x|/2)*sgn(x) for bigInt x in 2's complement
function halve(x) {
var i;
for (i=0;i<x.length-1;i++) {
x[i]=mask & ((x[i+1]<<(bpe-1)) | (x[i]>>1));
}
x[i]=(x[i]>>1) | (x[i] & (radix>>1)); //most significant bit stays the same
}
//left shift bigInt x by n bits.
function leftShift(x,n) {
var i;
var k=Math.floor(n/bpe);
if (k) {
for (i=x.length; i>=k; i--) //left shift x by k elements
x[i]=x[i-k];
for (;i>=0;i--)
x[i]=0;
n%=bpe;
}
if (!n)
return;
for (i=x.length-1;i>0;i--) {
x[i]=mask & ((x[i]<<n) | (x[i-1]>>(bpe-n)));
}
x[i]=mask & (x[i]<<n);
}
//do x=x*n where x is a bigInt and n is an integer.
//x must be large enough to hold the result.
function multInt(x,n) {
var i,k,c,b;
if (!n)
return;
k=x.length;
c=0;
for (i=0;i<k;i++) {
c+=x[i]*n;
b=0;
if (c<0) {
b=-(c>>bpe);
c+=b*radix;
}
x[i]=c & mask;
c=(c>>bpe)-b;
}
}
//do x=floor(x/n) for bigInt x and integer n, and return the remainder
function divInt(x,n) {
var i,r=0,s;
for (i=x.length-1;i>=0;i--) {
s=r*radix+x[i];
x[i]=Math.floor(s/n);
r=s%n;
}
return r;
}
//do the linear combination x=a*x+b*y for bigInts x and y, and integers a and b.
//x must be large enough to hold the answer.
function linComb(x,y,a,b) {
var i,c,k,kk;
k=x.length<y.length ? x.length : y.length;
kk=x.length;
for (c=0,i=0;i<k;i++) {
c+=a*x[i]+b*y[i];
x[i]=c & mask;
c>>=bpe;
}
for (i=k;i<kk;i++) {
c+=a*x[i];
x[i]=c & mask;
c>>=bpe;
}
}
//do the linear combination x=a*x+b*(y<<(ys*bpe)) for bigInts x and y, and integers a, b and ys.
//x must be large enough to hold the answer.
function linCombShift(x,y,b,ys) {
var i,c,k,kk;
k=x.length<ys+y.length ? x.length : ys+y.length;
kk=x.length;
for (c=0,i=ys;i<k;i++) {
c+=x[i]+b*y[i-ys];
x[i]=c & mask;
c>>=bpe;
}
for (i=k;c && i<kk;i++) {
c+=x[i];
x[i]=c & mask;
c>>=bpe;
}
}
//do x=x+(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
//x must be large enough to hold the answer.
function addShift(x,y,ys) {
var i,c,k,kk;
k=x.length<ys+y.length ? x.length : ys+y.length;
kk=x.length;
for (c=0,i=ys;i<k;i++) {
c+=x[i]+y[i-ys];
x[i]=c & mask;
c>>=bpe;
}
for (i=k;c && i<kk;i++) {
c+=x[i];
x[i]=c & mask;
c>>=bpe;
}
}
//do x=x-(y<<(ys*bpe)) for bigInts x and y, and integers a,b and ys.
//x must be large enough to hold the answer.
function subShift(x,y,ys) {
var i,c,k,kk;
k=x.length<ys+y.length ? x.length : ys+y.length;
kk=x.length;
for (c=0,i=ys;i<k;i++) {
c+=x[i]-y[i-ys];
x[i]=c & mask;
c>>=bpe;
}
for (i=k;c && i<kk;i++) {
c+=x[i];
x[i]=c & mask;
c>>=bpe;
}
}
//do x=x-y for bigInts x and y.
//x must be large enough to hold the answer.
//negative answers will be 2s complement
function sub(x,y) {
var i,c,k,kk;
k=x.length<y.length ? x.length : y.length;
for (c=0,i=0;i<k;i++) {
c+=x[i]-y[i];
x[i]=c & mask;
c>>=bpe;
}
for (i=k;c && i<x.length;i++) {
c+=x[i];
x[i]=c & mask;
c>>=bpe;
}
}
//do x=x+y for bigInts x and y.
//x must be large enough to hold the answer.
function add(x,y) {
var i,c,k,kk;
k=x.length<y.length ? x.length : y.length;
for (c=0,i=0;i<k;i++) {
c+=x[i]+y[i];
x[i]=c & mask;
c>>=bpe;
}
for (i=k;c && i<x.length;i++) {
c+=x[i];
x[i]=c & mask;
c>>=bpe;
}
}
//do x=x*y for bigInts x and y.
//for greater speed, let y<x.
function mult(x,y) {
var i;
if (ss.length!=2*x.length)
ss=new Array(2*x.length);
copyInt(ss,0);
for (i=0;i<y.length;i++)
if (y[i])
linCombShift(ss,x,y[i],i); //ss=1*ss+y[i]*(x<<(i*bpe))
copy(x,ss);
}
//do x=x mod n for bigInts x and n.
function mod(x,n) {
if (s4.length!=x.length)
s4=dup(x);
else
copy(s4,x);
if (s5.length!=x.length)
s5=dup(x);
divide(s4,n,s5,x); //x = remainder of s4 / n
}
//do x=x*y mod n for bigInts x,y,n.
//for greater speed, let y<x.
function multMod(x,y,n) {
var i;
if (s0.length!=2*x.length)
s0=new Array(2*x.length);
copyInt(s0,0);
for (i=0;i<y.length;i++)
if (y[i])
linCombShift(s0,x,y[i],i); //s0=1*s0+y[i]*(x<<(i*bpe))
mod(s0,n);
copy(x,s0);
}
//do x=x*x mod n for bigInts x,n.
function squareMod(x,n) {
var i,j,d,c,kx,kn,k;
for (kx=x.length; kx>0 && !x[kx-1]; kx--); //ignore leading zeros in x
k=kx>n.length ? 2*kx : 2*n.length; //k=# elements in the product, which is twice the elements in the larger of x and n
if (s0.length!=k)
s0=new Array(k);
copyInt(s0,0);
for (i=0;i<kx;i++) {
c=s0[2*i]+x[i]*x[i];
s0[2*i]=c & mask;
c>>=bpe;
for (j=i+1;j<kx;j++) {
c=s0[i+j]+2*x[i]*x[j]+c;
s0[i+j]=(c & mask);
c>>=bpe;
}
s0[i+kx]=c;
}
mod(s0,n);
copy(x,s0);
}
//return x with exactly k leading zeros
function trim(x,k) {
var i,y;
for (i=x.length; i>0 && !x[i-1]; i--);
y=new Array(i+k);
copy(y,x);
return y;
}
//do x=x**y mod n, where x,y,n are bigInts (n is odd) and ** is exponentiation. 0**0=1.
function powMod(x,y,n) {
var k1,k2,kn,np;
//calculate np from n for the Montgomery multiplications
for (kn=n.length;kn>0 && !n[kn-1];kn--);
np=radix-inverseModInt(modInt(n,radix),radix);
if(s7.length!=n.length)
s7=dup(n);
copyInt(s7,0);
s7[kn]=1;
multMod(x ,s7,n); // x = x * 2**(kn*bp) mod n
if (s3.length!=x.length)
s3=dup(x);
else
copy(s3,x);
for (k1=y.length-1;k1>0 & !y[k1]; k1--); //k1=first nonzero element of y
if (y[k1]==0) { //anything to the 0th power is 1
copyInt(x,1);
return;
}
for (k2=1<<(bpe-1);k2 && !(y[k1] & k2); k2>>=1); //k2=position of first 1 bit in y[k1]
for (;;) {
if (!(k2>>=1)) { //look at next bit of y
k1--;
if (k1<0) {
mont(x,one,n,np);
return;
}
k2=1<<(bpe-1);
}
mont(x,x,n,np);
if (k2 & y[k1]) //if next bit is a 1
mont(x,s3,n,np);
}
}
//do x=x*y*Ri mod n for bigInts x,y,n,
// where Ri = 2**(-kn*bpe) mod n, and kn is the
// number of elements in the n array, not
// counting leading zeros.
//x must be large enough to hold the answer.
//It's OK if x and y are the same variable.
//must have:
// x,y < n
// n is odd
// np = -(n^(-1)) mod radix
function mont(x,y,n,np) {
var i,j,c,ui,t;
var kn=n.length;
var ky=y.length;
if (sa.length!=kn)
sa=new Array(kn);
for (;kn>0 && n[kn-1]==0;kn--); //ignore leading zeros of n
//this function sometimes gives wrong answers when the next line is uncommented
//for (;ky>0 && y[ky-1]==0;ky--); //ignore leading zeros of y
copyInt(sa,0);
//the following loop consumes 95% of the runtime for randTruePrime() and powMod() for large keys
for (i=0; i<kn; i++) {
t=sa[0]+x[i]*y[0];
ui=(t*np) & mask;
c=(t+ui*n[0]) >> bpe;
t=x[i];
//do sa=(sa+x[i]*y+ui*n)/b where b=2**bpe
for (j=1;j<ky;j++) {
c+=sa[j]+t*y[j]+ui*n[j];
sa[j-1]=c & mask;
c>>=bpe;
}
for (;j<kn;j++) {
c+=sa[j]+ui*n[j];
sa[j-1]=c & mask;
c>>=bpe;
}
sa[j-1]=c & mask;
}
if (!greater(n,sa))
sub(sa,n);
copy(x,sa);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -