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); }