Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(443)

Unified Diff: runtime/lib/bigint.dart

Issue 567093002: Temporarily add a public modPow method to _Bigint class. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/lib/bigint.dart
===================================================================
--- runtime/lib/bigint.dart (revision 40252)
+++ runtime/lib/bigint.dart (working copy)
@@ -736,15 +736,39 @@
// Accumulate multiply.
// this[i..i+n-1]: bigint multiplicand.
- // x: digit multiplier.
+ // x: digit multiplier, 0 <= x < DIGIT_BASE (i.e. 32-bit multiplier).
// w[j..j+n-1]: bigint accumulator.
+ // Returns carry out.
+ // w[j..j+n-1] += this[i..i+n-1] * x.
+ // Returns carry out.
+ int _am(int i, int x, _Bigint w, int j, int n) {
+ if (x == 0) {
+ // No-op if x is 0.
+ return 0;
+ }
+ int c = 0;
+ int xl = x & DIGIT2_MASK;
+ int xh = x >> DIGIT2_BITS;
+ while (--n >= 0) {
+ int l = _digits[i] & DIGIT2_MASK;
+ int h = _digits[i++] >> DIGIT2_BITS;
+ int m = xh*l + h*xl;
+ l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + w._digits[j] + c;
+ c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h;
+ w._digits[j++] = l & DIGIT_MASK;
+ }
+ return c;
+ }
+
+ // Accumulate multiply with carry.
+ // this[i..i+n-1]: bigint multiplicand.
+ // x: digit multiplier, 0 <= x < 2*DIGIT_BASE (i.e. 33-bit multiplier).
+ // w[j..j+n-1]: bigint accumulator.
// c: int carry in.
// Returns carry out.
// w[j..j+n-1] += this[i..i+n-1] * x + c.
// Returns carry out.
- // TODO(regis): _sqrTo is the only caller passing an x possibly larger than
- // a digit (2*digit) and passing a non-zero carry in. Refactor?
- int _am(int i, int x, _Bigint w, int j, int c, int n) {
+ int _amc(int i, int x, _Bigint w, int j, int c, int n) {
if (x == 0 && c == 0) {
// No-op if both x and c are 0.
return 0;
@@ -772,8 +796,7 @@
r._digits[i] = 0;
}
for (i = 0; i < a._used; ++i) {
- // TODO(regis): Replace _am with addMulVVW.
- r._digits[i + _used] = _am(0, a._digits[i], r, i, 0, _used);
+ r._digits[i + _used] = _am(0, a._digits[i], r, i, _used);
}
r._clamp();
r._neg = r._used > 0 && _neg != a._neg; // Zero cannot be negative.
@@ -788,9 +811,9 @@
r._digits[i] = 0;
}
for (i = 0; i < _used - 1; ++i) {
- var c = _am(i, _digits[i], r, 2*i, 0, 1);
+ var c = _am(i, _digits[i], r, 2*i, 1);
var d = r._digits[i + _used];
- d += _am(i + 1, _digits[i] << 1, r, 2*i + 1, c, _used - i - 1);
+ d += _amc(i + 1, _digits[i] << 1, r, 2*i + 1, c, _used - i - 1);
if (d >= DIGIT_BASE) {
r._digits[i + _used] = d - DIGIT_BASE;
r._digits[i + _used + 1] = 1;
@@ -799,7 +822,7 @@
}
}
if (r._used > 0) {
- r._digits[r._used - 1] += _am(i, _digits[i], r, 2*i, 0, 1);
+ r._digits[r._used - 1] += _am(i, _digits[i], r, 2*i, 1);
}
r._neg = false;
r._clamp();
@@ -864,7 +887,7 @@
var qd = (r._digits[--i] == y0)
? DIGIT_MASK
: (r._digits[i]*d1 + (r._digits[i - 1] + e)*d2).floor();
- if ((r._digits[i] += y._am(0, qd, r, j, 0, y_used)) < qd) { // Try it out
+ if ((r._digits[i] += y._amc(0, qd, r, j, 0, y_used)) < qd) { // Try it out
y._dlShiftTo(j, t);
r._subTo(t, r);
while (r._digits[i] < --qd) {
@@ -940,10 +963,6 @@
return result._toValidInt();
}
- int pow(int exponent) {
- throw "Bigint.pow not implemented";
- }
-
// Overriden operators and methods.
// The following operators override operators of _IntegerImplementation for
@@ -1074,31 +1093,137 @@
return other._toBigint()._compareTo(this) == 0;
}
- // New method to support crypto.
+ // Return -1/this % DIGIT_BASE, useful for Montgomery reduction.
+ //
+ // xy == 1 (mod m)
+ // xy = 1+km
+ // xy(2-xy) = (1+km)(1-km)
+ // x(y(2-xy)) = 1-k^2 m^2
+ // x(y(2-xy)) == 1 (mod m^2)
+ // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+ // Should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+ int _invDigit() {
+ if (_used == 0) return 0;
+ var x = _digits[0];
+ if ((x & 1) == 0) return 0;
+ var y = x & 3; // y == 1/x mod 2^2
+ y = (y*(2 - (x & 0xf)*y)) & 0xf; // y == 1/x mod 2^4
+ y = (y*(2 - (x & 0xff)*y)) & 0xff; // y == 1/x mod 2^8
+ y = (y*(2 - (((x & 0xffff)*y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
+ // Last step - calculate inverse mod DIGIT_BASE directly;
+ // Assumes 16 < DIGIT_BITS <= 32 and assumes ability to handle 48-bit ints.
+ y = (y*(2 - x*y % DIGIT_BASE)) % DIGIT_BASE; // y == 1/x mod DIGIT_BASE
+ // We really want the negative inverse, and - DIGIT_BASE < y < DIGIT_BASE.
+ return (y > 0) ? DIGIT_BASE - y : -y;
+ }
- // Return this.pow(e) mod m, with 256 <= e < 1<<32.
+ // TODO(regis): Make this method private once the plumbing to invoke it from
+ // dart:math is in place.
+ // Return pow(this, e) % m.
int modPow(int e, int m) {
+ // TODO(regis): Where/how do we handle values of e smaller than 256?
+ // TODO(regis): Where/how do we handle even values of m?
assert(e >= 256 && !m.isEven());
- if (e >= (1 << 32)) {
- throw "Bigint.modPow with exponent larger than 32-bit not implemented";
+ if (e is! _Bigint) {
+ _Reduction z = new _Montgomery(m);
+ var r = new _Bigint();
+ var r2 = new _Bigint();
+ var g = z._convert(this);
+ int i = _nbits(e) - 1;
+ g._copyTo(r);
+ while (--i >= 0) {
+ z._sqrTo(r, r2);
+ if ((e & (1 << i)) > 0) {
+ z._mulTo(r2, g, r);
+ } else {
+ var t = r;
+ r = r2;
+ r2 = t;
+ }
+ }
+ return z._revert(r)._toValidInt();
}
+ var i = e.bitLength;
+ var k;
+ var r = new _Bigint()._setInt(1);
+ if (i <= 0) return r;
+ // TODO(regis): Are these values of k really optimal for our implementation?
+ else if (i < 18) k = 1;
+ else if (i < 48) k = 3;
+ else if (i < 144) k = 4;
+ else if (i < 768) k = 5;
+ else k = 6;
_Reduction z = new _Montgomery(m);
- var r = new _Bigint();
+ var n = 3;
+ var k1 = k - 1;
+ var km = (1 << k) - 1;
+ List g = new List(km + 1);
+ g[1] = z._convert(this);
+ if (k > 1) {
+ var g2 = new _Bigint();
+ z._sqrTo(g[1], g2);
+ while (n <= km) {
+ g[n] = new _Bigint();
+ z._mulTo(g2, g[n - 2], g[n]);
+ n += 2;
+ }
+ }
+ var j = e._used - 1;
+ var w;
+ var is1 = true;
var r2 = new _Bigint();
- var g = z.convert(this);
- int i = _nbits(e) - 1;
- g._copyTo(r);
- while (--i >= 0) {
- z.sqrTo(r, r2);
- if ((e & (1 << i)) > 0) {
- z.mulTo(r2, g, r);
+ var t;
+ i = _nbits(e._digits[j]) - 1;
+ while (j >= 0) {
+ if (i >= k1) {
+ w = (e._digits[j] >> (i - k1)) & km;
} else {
- var t = r;
+ w = (e._digits[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
+ if (j > 0) {
+ w |= e._digits[j - 1] >> (DIGIT_BITS + i - k1);
+ }
+ }
+ n = k;
+ while ((w & 1) == 0) {
+ w >>= 1;
+ --n;
+ }
+ if ((i -= n) < 0) {
+ i += DIGIT_BITS;
+ --j;
+ }
+ if (is1) { // r == 1, don't bother squaring or multiplying it.
+ g[w]._copyTo(r);
+ is1 = false;
+ }
+ else {
+ while (n > 1) {
+ z._sqrTo(r, r2);
+ z._sqrTo(r2, r);
+ n -= 2;
+ }
+ if (n > 0) {
+ z._sqrTo(r, r2);
+ } else {
+ t = r;
+ r = r2;
+ r2 = t;
+ }
+ z._mulTo(r2,g[w], r);
+ }
+
+ while (j >= 0 && (e._digits[j] & (1 << i)) == 0) {
+ z._sqrTo(r, r2);
+ t = r;
r = r2;
r2 = t;
+ if (--i < 0) {
+ i = DIGIT_BITS - 1;
+ --j;
+ }
}
}
- return z.revert(r)._toValidInt();
+ return z._revert(r)._toValidInt();
}
}
@@ -1168,8 +1293,8 @@
// Use _am to combine the multiply-shift-add into one call.
j = i + _m._used;
var digit = x._digits[j];
- digit += _m ._am(0, u0, x, i, 0, _m ._used);
- // propagate carry
+ digit += _m ._am(0, u0, x, i, _m._used);
+ // Propagate carry.
while (digit >= _Bigint.DIGIT_BASE) {
digit -= _Bigint.DIGIT_BASE;
x._digits[j++] = digit;
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698