Montgomery class
Montgomery reduction on BigInteger
class Montgomery {
BigInteger m;
var mp;
var mpl;
var mph;
var um;
var mt2;
/**
* Montgomery reduction
*/
Montgomery(this.m) {
this.mp = m.invDigit();
this.mpl = this.mp&0x7fff;
this.mph = this.mp>>15;
this.um = (1<<(BigInteger.BI_DB-15))-1;
this.mt2 = 2*m.t;
}
/**
* xR mod m
*/
BigInteger convert(BigInteger x) {
var r = BigInteger.nbi();
x.abs().dlShiftTo(this.m.t,r);
r.divRemTo(this.m,null,r);
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
return r;
}
/**
* x/R mod m
*/
BigInteger revert(BigInteger x) {
var r = BigInteger.nbi();
x.copyTo(r);
this.reduce(r);
return r;
}
/**
* x = x/R mod m (HAC 14.32)
*/
void reduce(x) {
var x_array = x.array;
while(x.t <= this.mt2) { // pad x so am has enough room later
x_array[x.t++] = 0;
}
for(var i = 0; i < this.m.t; ++i) {
// faster way of calculating u0 = x[i]*mp mod DV
var j = x_array[i]&0x7fff;
var u0 = (j*this.mpl+(((j*this.mph+(x_array[i]>>15)*this.mpl)&this.um)<<15))&BigInteger.BI_DM;
// use am to combine the multiply-shift-add into one call
j = i+this.m.t;
x_array[j] += this.m.am(0,u0,x,i,0,this.m.t);
// propagate carry
while(x_array[j] >= BigInteger.BI_DV) {
x_array[j] -= BigInteger.BI_DV;
x_array[++j]++;
}
}
x.clamp();
x.drShiftTo(this.m.t,x);
if(x.compareTo(this.m) >= 0) {
x.subTo(this.m,x);
}
}
/**
* r = "x^2/R mod m"; x != r
*/
sqrTo(x,r) {
x.squareTo(r);
this.reduce(r);
}
/**
* r = "xy/R mod m"; x,y != r
*/
mulTo(x,y,r) {
x.multiplyTo(y,r);
this.reduce(r);
}
}
Constructors
new Montgomery(BigInteger m) #
Montgomery reduction
Montgomery(this.m) {
this.mp = m.invDigit();
this.mpl = this.mp&0x7fff;
this.mph = this.mp>>15;
this.um = (1<<(BigInteger.BI_DB-15))-1;
this.mt2 = 2*m.t;
}
Methods
BigInteger convert(BigInteger x) #
xR mod m
BigInteger convert(BigInteger x) {
var r = BigInteger.nbi();
x.abs().dlShiftTo(this.m.t,r);
r.divRemTo(this.m,null,r);
if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
return r;
}
mulTo(x, y, r) #
r = "xy/R mod m"; x,y != r
mulTo(x,y,r) {
x.multiplyTo(y,r);
this.reduce(r);
}
void reduce(x) #
x = x/R mod m (HAC 14.32)
void reduce(x) {
var x_array = x.array;
while(x.t <= this.mt2) { // pad x so am has enough room later
x_array[x.t++] = 0;
}
for(var i = 0; i < this.m.t; ++i) {
// faster way of calculating u0 = x[i]*mp mod DV
var j = x_array[i]&0x7fff;
var u0 = (j*this.mpl+(((j*this.mph+(x_array[i]>>15)*this.mpl)&this.um)<<15))&BigInteger.BI_DM;
// use am to combine the multiply-shift-add into one call
j = i+this.m.t;
x_array[j] += this.m.am(0,u0,x,i,0,this.m.t);
// propagate carry
while(x_array[j] >= BigInteger.BI_DV) {
x_array[j] -= BigInteger.BI_DV;
x_array[++j]++;
}
}
x.clamp();
x.drShiftTo(this.m.t,x);
if(x.compareTo(this.m) >= 0) {
x.subTo(this.m,x);
}
}
BigInteger revert(BigInteger x) #
x/R mod m
BigInteger revert(BigInteger x) {
var r = BigInteger.nbi();
x.copyTo(r);
this.reduce(r);
return r;
}
sqrTo(x, r) #
r = "x^2/R mod m"; x != r
sqrTo(x,r) {
x.squareTo(r);
this.reduce(r);
}