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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 // Copyright 2009 The Go Authors. All rights reserved. 5 // Copyright 2009 The Go Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style 6 // Use of this source code is governed by a BSD-style
7 // license that can be found in the LICENSE file. 7 // license that can be found in the LICENSE file.
8 8
9 /* 9 /*
10 * Copyright (c) 2003-2005 Tom Wu 10 * Copyright (c) 2003-2005 Tom Wu
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 r_neg = !r_neg; 729 r_neg = !r_neg;
730 a._absSubTo(this, r); 730 a._absSubTo(this, r);
731 } 731 }
732 } 732 }
733 r._neg = r_neg; 733 r._neg = r_neg;
734 return r; 734 return r;
735 } 735 }
736 736
737 // Accumulate multiply. 737 // Accumulate multiply.
738 // this[i..i+n-1]: bigint multiplicand. 738 // this[i..i+n-1]: bigint multiplicand.
739 // x: digit multiplier. 739 // x: digit multiplier, 0 <= x < DIGIT_BASE (i.e. 32-bit multiplier).
740 // w[j..j+n-1]: bigint accumulator.
741 // Returns carry out.
742 // w[j..j+n-1] += this[i..i+n-1] * x.
743 // Returns carry out.
744 int _am(int i, int x, _Bigint w, int j, int n) {
745 if (x == 0) {
746 // No-op if x is 0.
747 return 0;
748 }
749 int c = 0;
750 int xl = x & DIGIT2_MASK;
751 int xh = x >> DIGIT2_BITS;
752 while (--n >= 0) {
753 int l = _digits[i] & DIGIT2_MASK;
754 int h = _digits[i++] >> DIGIT2_BITS;
755 int m = xh*l + h*xl;
756 l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + w._digits[j] + c;
757 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h;
758 w._digits[j++] = l & DIGIT_MASK;
759 }
760 return c;
761 }
762
763 // Accumulate multiply with carry.
764 // this[i..i+n-1]: bigint multiplicand.
765 // x: digit multiplier, 0 <= x < 2*DIGIT_BASE (i.e. 33-bit multiplier).
740 // w[j..j+n-1]: bigint accumulator. 766 // w[j..j+n-1]: bigint accumulator.
741 // c: int carry in. 767 // c: int carry in.
742 // Returns carry out. 768 // Returns carry out.
743 // w[j..j+n-1] += this[i..i+n-1] * x + c. 769 // w[j..j+n-1] += this[i..i+n-1] * x + c.
744 // Returns carry out. 770 // Returns carry out.
745 // TODO(regis): _sqrTo is the only caller passing an x possibly larger than 771 int _amc(int i, int x, _Bigint w, int j, int c, int n) {
746 // a digit (2*digit) and passing a non-zero carry in. Refactor?
747 int _am(int i, int x, _Bigint w, int j, int c, int n) {
748 if (x == 0 && c == 0) { 772 if (x == 0 && c == 0) {
749 // No-op if both x and c are 0. 773 // No-op if both x and c are 0.
750 return 0; 774 return 0;
751 } 775 }
752 int xl = x & DIGIT2_MASK; 776 int xl = x & DIGIT2_MASK;
753 int xh = x >> DIGIT2_BITS; 777 int xh = x >> DIGIT2_BITS;
754 while (--n >= 0) { 778 while (--n >= 0) {
755 int l = _digits[i] & DIGIT2_MASK; 779 int l = _digits[i] & DIGIT2_MASK;
756 int h = _digits[i++] >> DIGIT2_BITS; 780 int h = _digits[i++] >> DIGIT2_BITS;
757 int m = xh*l + h*xl; 781 int m = xh*l + h*xl;
758 l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + w._digits[j] + c; 782 l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + w._digits[j] + c;
759 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h; 783 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h;
760 w._digits[j++] = l & DIGIT_MASK; 784 w._digits[j++] = l & DIGIT_MASK;
761 } 785 }
762 return c; 786 return c;
763 } 787 }
764 788
765 // r = this * a. 789 // r = this * a.
766 void _mulTo(_Bigint a, _Bigint r) { 790 void _mulTo(_Bigint a, _Bigint r) {
767 // TODO(regis): Use karatsuba multiplication when appropriate. 791 // TODO(regis): Use karatsuba multiplication when appropriate.
768 var i = _used; 792 var i = _used;
769 r._ensureLength(i + a._used); 793 r._ensureLength(i + a._used);
770 r._used = i + a._used; 794 r._used = i + a._used;
771 while (--i >= 0) { 795 while (--i >= 0) {
772 r._digits[i] = 0; 796 r._digits[i] = 0;
773 } 797 }
774 for (i = 0; i < a._used; ++i) { 798 for (i = 0; i < a._used; ++i) {
775 // TODO(regis): Replace _am with addMulVVW. 799 r._digits[i + _used] = _am(0, a._digits[i], r, i, _used);
776 r._digits[i + _used] = _am(0, a._digits[i], r, i, 0, _used);
777 } 800 }
778 r._clamp(); 801 r._clamp();
779 r._neg = r._used > 0 && _neg != a._neg; // Zero cannot be negative. 802 r._neg = r._used > 0 && _neg != a._neg; // Zero cannot be negative.
780 } 803 }
781 804
782 // r = this^2, r != this. 805 // r = this^2, r != this.
783 void _sqrTo(_Bigint r) { 806 void _sqrTo(_Bigint r) {
784 var i = 2 * _used; 807 var i = 2 * _used;
785 r._ensureLength(i); 808 r._ensureLength(i);
786 r._used = i; 809 r._used = i;
787 while (--i >= 0) { 810 while (--i >= 0) {
788 r._digits[i] = 0; 811 r._digits[i] = 0;
789 } 812 }
790 for (i = 0; i < _used - 1; ++i) { 813 for (i = 0; i < _used - 1; ++i) {
791 var c = _am(i, _digits[i], r, 2*i, 0, 1); 814 var c = _am(i, _digits[i], r, 2*i, 1);
792 var d = r._digits[i + _used]; 815 var d = r._digits[i + _used];
793 d += _am(i + 1, _digits[i] << 1, r, 2*i + 1, c, _used - i - 1); 816 d += _amc(i + 1, _digits[i] << 1, r, 2*i + 1, c, _used - i - 1);
794 if (d >= DIGIT_BASE) { 817 if (d >= DIGIT_BASE) {
795 r._digits[i + _used] = d - DIGIT_BASE; 818 r._digits[i + _used] = d - DIGIT_BASE;
796 r._digits[i + _used + 1] = 1; 819 r._digits[i + _used + 1] = 1;
797 } else { 820 } else {
798 r._digits[i + _used] = d; 821 r._digits[i + _used] = d;
799 } 822 }
800 } 823 }
801 if (r._used > 0) { 824 if (r._used > 0) {
802 r._digits[r._used - 1] += _am(i, _digits[i], r, 2*i, 0, 1); 825 r._digits[r._used - 1] += _am(i, _digits[i], r, 2*i, 1);
803 } 826 }
804 r._neg = false; 827 r._neg = false;
805 r._clamp(); 828 r._clamp();
806 } 829 }
807 830
808 // Truncating division and remainder. 831 // Truncating division and remainder.
809 // If q != null, q = trunc(this / a). 832 // If q != null, q = trunc(this / a).
810 // If r != null, r = this - a * trunc(this / a). 833 // If r != null, r = this - a * trunc(this / a).
811 void _divRemTo(_Bigint a, _Bigint q, _Bigint r) { 834 void _divRemTo(_Bigint a, _Bigint q, _Bigint r) {
812 if (a._used == 0) return; 835 if (a._used == 0) return;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 ONE._dlShiftTo(y_used, t); 880 ONE._dlShiftTo(y_used, t);
858 t._subTo(y, y); // "negative" y so we can replace sub with _am later 881 t._subTo(y, y); // "negative" y so we can replace sub with _am later
859 while (y._used < y_used) { 882 while (y._used < y_used) {
860 y._digits[y._used++] = 0; 883 y._digits[y._used++] = 0;
861 } 884 }
862 while (--j >= 0) { 885 while (--j >= 0) {
863 // Estimate quotient digit 886 // Estimate quotient digit
864 var qd = (r._digits[--i] == y0) 887 var qd = (r._digits[--i] == y0)
865 ? DIGIT_MASK 888 ? DIGIT_MASK
866 : (r._digits[i]*d1 + (r._digits[i - 1] + e)*d2).floor(); 889 : (r._digits[i]*d1 + (r._digits[i - 1] + e)*d2).floor();
867 if ((r._digits[i] += y._am(0, qd, r, j, 0, y_used)) < qd) { // Try it out 890 if ((r._digits[i] += y._amc(0, qd, r, j, 0, y_used)) < qd) { // Try it ou t
868 y._dlShiftTo(j, t); 891 y._dlShiftTo(j, t);
869 r._subTo(t, r); 892 r._subTo(t, r);
870 while (r._digits[i] < --qd) { 893 while (r._digits[i] < --qd) {
871 r._subTo(t, r); 894 r._subTo(t, r);
872 } 895 }
873 } 896 }
874 } 897 }
875 if (q != null) { 898 if (q != null) {
876 r._drShiftTo(y_used, q); 899 r._drShiftTo(y_used, q);
877 if (_neg != a._neg) { 900 if (_neg != a._neg) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
933 if (_used > 2 || (_used == 2 && _digits[1] > 0x10000000)) { 956 if (_used > 2 || (_used == 2 && _digits[1] > 0x10000000)) {
934 throw new OutOfMemoryError(); 957 throw new OutOfMemoryError();
935 } else { 958 } else {
936 shift = ((_used == 2) ? (_digits[1] << DIGIT_BITS) : 0) + _digits[0]; 959 shift = ((_used == 2) ? (_digits[1] << DIGIT_BITS) : 0) + _digits[0];
937 } 960 }
938 _Bigint result = new _Bigint(); 961 _Bigint result = new _Bigint();
939 other._toBigint()._lShiftTo(shift, result); 962 other._toBigint()._lShiftTo(shift, result);
940 return result._toValidInt(); 963 return result._toValidInt();
941 } 964 }
942 965
943 int pow(int exponent) {
944 throw "Bigint.pow not implemented";
945 }
946
947 // Overriden operators and methods. 966 // Overriden operators and methods.
948 967
949 // The following operators override operators of _IntegerImplementation for 968 // The following operators override operators of _IntegerImplementation for
950 // efficiency, but are not necessary for correctness. They shortcut native 969 // efficiency, but are not necessary for correctness. They shortcut native
951 // calls that would return null because the receiver is _Bigint. 970 // calls that would return null because the receiver is _Bigint.
952 num operator +(num other) { 971 num operator +(num other) {
953 return other._toBigintOrDouble()._addFromInteger(this); 972 return other._toBigintOrDouble()._addFromInteger(this);
954 } 973 }
955 num operator -(num other) { 974 num operator -(num other) {
956 return other._toBigintOrDouble()._subFromInteger(this); 975 return other._toBigintOrDouble()._subFromInteger(this);
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 other._toBigint()._divRemTo(this, null, result); 1086 other._toBigint()._divRemTo(this, null, result);
1068 return result._toValidInt(); 1087 return result._toValidInt();
1069 } 1088 }
1070 bool _greaterThanFromInteger(int other) { 1089 bool _greaterThanFromInteger(int other) {
1071 return other._toBigint()._compareTo(this) > 0; 1090 return other._toBigint()._compareTo(this) > 0;
1072 } 1091 }
1073 bool _equalToInteger(int other) { 1092 bool _equalToInteger(int other) {
1074 return other._toBigint()._compareTo(this) == 0; 1093 return other._toBigint()._compareTo(this) == 0;
1075 } 1094 }
1076 1095
1077 // New method to support crypto. 1096 // Return -1/this % DIGIT_BASE, useful for Montgomery reduction.
1097 //
1098 // xy == 1 (mod m)
1099 // xy = 1+km
1100 // xy(2-xy) = (1+km)(1-km)
1101 // x(y(2-xy)) = 1-k^2 m^2
1102 // x(y(2-xy)) == 1 (mod m^2)
1103 // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
1104 // Should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
1105 int _invDigit() {
1106 if (_used == 0) return 0;
1107 var x = _digits[0];
1108 if ((x & 1) == 0) return 0;
1109 var y = x & 3; // y == 1/x mod 2^2
1110 y = (y*(2 - (x & 0xf)*y)) & 0xf; // y == 1/x mod 2^4
1111 y = (y*(2 - (x & 0xff)*y)) & 0xff; // y == 1/x mod 2^8
1112 y = (y*(2 - (((x & 0xffff)*y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
1113 // Last step - calculate inverse mod DIGIT_BASE directly;
1114 // Assumes 16 < DIGIT_BITS <= 32 and assumes ability to handle 48-bit ints.
1115 y = (y*(2 - x*y % DIGIT_BASE)) % DIGIT_BASE; // y == 1/x mod DIGIT_BASE
1116 // We really want the negative inverse, and - DIGIT_BASE < y < DIGIT_BASE.
1117 return (y > 0) ? DIGIT_BASE - y : -y;
1118 }
1078 1119
1079 // Return this.pow(e) mod m, with 256 <= e < 1<<32. 1120 // TODO(regis): Make this method private once the plumbing to invoke it from
1121 // dart:math is in place.
1122 // Return pow(this, e) % m.
1080 int modPow(int e, int m) { 1123 int modPow(int e, int m) {
1124 // TODO(regis): Where/how do we handle values of e smaller than 256?
1125 // TODO(regis): Where/how do we handle even values of m?
1081 assert(e >= 256 && !m.isEven()); 1126 assert(e >= 256 && !m.isEven());
1082 if (e >= (1 << 32)) { 1127 if (e is! _Bigint) {
1083 throw "Bigint.modPow with exponent larger than 32-bit not implemented"; 1128 _Reduction z = new _Montgomery(m);
1129 var r = new _Bigint();
1130 var r2 = new _Bigint();
1131 var g = z._convert(this);
1132 int i = _nbits(e) - 1;
1133 g._copyTo(r);
1134 while (--i >= 0) {
1135 z._sqrTo(r, r2);
1136 if ((e & (1 << i)) > 0) {
1137 z._mulTo(r2, g, r);
1138 } else {
1139 var t = r;
1140 r = r2;
1141 r2 = t;
1142 }
1143 }
1144 return z._revert(r)._toValidInt();
1084 } 1145 }
1146 var i = e.bitLength;
1147 var k;
1148 var r = new _Bigint()._setInt(1);
1149 if (i <= 0) return r;
1150 // TODO(regis): Are these values of k really optimal for our implementation?
1151 else if (i < 18) k = 1;
1152 else if (i < 48) k = 3;
1153 else if (i < 144) k = 4;
1154 else if (i < 768) k = 5;
1155 else k = 6;
1085 _Reduction z = new _Montgomery(m); 1156 _Reduction z = new _Montgomery(m);
1086 var r = new _Bigint(); 1157 var n = 3;
1158 var k1 = k - 1;
1159 var km = (1 << k) - 1;
1160 List g = new List(km + 1);
1161 g[1] = z._convert(this);
1162 if (k > 1) {
1163 var g2 = new _Bigint();
1164 z._sqrTo(g[1], g2);
1165 while (n <= km) {
1166 g[n] = new _Bigint();
1167 z._mulTo(g2, g[n - 2], g[n]);
1168 n += 2;
1169 }
1170 }
1171 var j = e._used - 1;
1172 var w;
1173 var is1 = true;
1087 var r2 = new _Bigint(); 1174 var r2 = new _Bigint();
1088 var g = z.convert(this); 1175 var t;
1089 int i = _nbits(e) - 1; 1176 i = _nbits(e._digits[j]) - 1;
1090 g._copyTo(r); 1177 while (j >= 0) {
1091 while (--i >= 0) { 1178 if (i >= k1) {
1092 z.sqrTo(r, r2); 1179 w = (e._digits[j] >> (i - k1)) & km;
1093 if ((e & (1 << i)) > 0) {
1094 z.mulTo(r2, g, r);
1095 } else { 1180 } else {
1096 var t = r; 1181 w = (e._digits[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
1182 if (j > 0) {
1183 w |= e._digits[j - 1] >> (DIGIT_BITS + i - k1);
1184 }
1185 }
1186 n = k;
1187 while ((w & 1) == 0) {
1188 w >>= 1;
1189 --n;
1190 }
1191 if ((i -= n) < 0) {
1192 i += DIGIT_BITS;
1193 --j;
1194 }
1195 if (is1) { // r == 1, don't bother squaring or multiplying it.
1196 g[w]._copyTo(r);
1197 is1 = false;
1198 }
1199 else {
1200 while (n > 1) {
1201 z._sqrTo(r, r2);
1202 z._sqrTo(r2, r);
1203 n -= 2;
1204 }
1205 if (n > 0) {
1206 z._sqrTo(r, r2);
1207 } else {
1208 t = r;
1209 r = r2;
1210 r2 = t;
1211 }
1212 z._mulTo(r2,g[w], r);
1213 }
1214
1215 while (j >= 0 && (e._digits[j] & (1 << i)) == 0) {
1216 z._sqrTo(r, r2);
1217 t = r;
1097 r = r2; 1218 r = r2;
1098 r2 = t; 1219 r2 = t;
1220 if (--i < 0) {
1221 i = DIGIT_BITS - 1;
1222 --j;
1223 }
1099 } 1224 }
1100 } 1225 }
1101 return z.revert(r)._toValidInt(); 1226 return z._revert(r)._toValidInt();
1102 } 1227 }
1103 } 1228 }
1104 1229
1105 // New classes to support crypto (modPow method). 1230 // New classes to support crypto (modPow method).
1106 1231
1107 class _Reduction { 1232 class _Reduction {
1108 const _Reduction(); 1233 const _Reduction();
1109 _Bigint _convert(_Bigint x) => x; 1234 _Bigint _convert(_Bigint x) => x;
1110 _Bigint _revert(_Bigint x) => x; 1235 _Bigint _revert(_Bigint x) => x;
1111 1236
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1161 x._digits[x._used++] = 0; 1286 x._digits[x._used++] = 0;
1162 } 1287 }
1163 for (var i = 0; i < _m._used; ++i) { 1288 for (var i = 0; i < _m._used; ++i) {
1164 // Faster way of calculating u0 = x[i]*mp mod DIGIT_BASE. 1289 // Faster way of calculating u0 = x[i]*mp mod DIGIT_BASE.
1165 var j = x._digits[i] & _Bigint.DIGIT2_MASK; 1290 var j = x._digits[i] & _Bigint.DIGIT2_MASK;
1166 var u0 = (j*_mpl + (((j*_mph + (x._digits[i] >> _Bigint.DIGIT2_BITS) 1291 var u0 = (j*_mpl + (((j*_mph + (x._digits[i] >> _Bigint.DIGIT2_BITS)
1167 *_mpl) & _um) << _Bigint.DIGIT2_BITS)) & _Bigint.DIGIT_MASK; 1292 *_mpl) & _um) << _Bigint.DIGIT2_BITS)) & _Bigint.DIGIT_MASK;
1168 // Use _am to combine the multiply-shift-add into one call. 1293 // Use _am to combine the multiply-shift-add into one call.
1169 j = i + _m._used; 1294 j = i + _m._used;
1170 var digit = x._digits[j]; 1295 var digit = x._digits[j];
1171 digit += _m ._am(0, u0, x, i, 0, _m ._used); 1296 digit += _m ._am(0, u0, x, i, _m._used);
1172 // propagate carry 1297 // Propagate carry.
1173 while (digit >= _Bigint.DIGIT_BASE) { 1298 while (digit >= _Bigint.DIGIT_BASE) {
1174 digit -= _Bigint.DIGIT_BASE; 1299 digit -= _Bigint.DIGIT_BASE;
1175 x._digits[j++] = digit; 1300 x._digits[j++] = digit;
1176 digit = x._digits[j]; 1301 digit = x._digits[j];
1177 digit++; 1302 digit++;
1178 } 1303 }
1179 x._digits[j] = digit; 1304 x._digits[j] = digit;
1180 } 1305 }
1181 x._clamp(); 1306 x._clamp();
1182 x._drShiftTo(_m ._used, x); 1307 x._drShiftTo(_m ._used, x);
1183 if (x._compareTo(_m ) >= 0) { 1308 if (x._compareTo(_m ) >= 0) {
1184 x._subTo(_m , x); 1309 x._subTo(_m , x);
1185 } 1310 }
1186 } 1311 }
1187 1312
1188 // r = x^2/R mod _m ; x != r 1313 // r = x^2/R mod _m ; x != r
1189 void _sqrTo(_Bigint x, _Bigint r) { 1314 void _sqrTo(_Bigint x, _Bigint r) {
1190 x._sqrTo(r); 1315 x._sqrTo(r);
1191 _reduce(r); 1316 _reduce(r);
1192 } 1317 }
1193 1318
1194 // r = x*y/R mod _m ; x, y != r 1319 // r = x*y/R mod _m ; x, y != r
1195 void _mulTo(_Bigint x, _Bigint y, _Bigint r) { 1320 void _mulTo(_Bigint x, _Bigint y, _Bigint r) {
1196 x._mulTo(y, r); 1321 x._mulTo(y, r);
1197 _reduce(r); 1322 _reduce(r);
1198 } 1323 }
1199 } 1324 }
1200 1325
OLDNEW
« 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