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

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 // New methods to support crypto.
srdjan 2014/09/15 18:10:52 Maybe remove this comment?
regis 2014/09/15 19:29:31 Done.
1078 1097
1079 // Return this.pow(e) mod m, with 256 <= e < 1<<32. 1098 // Return -1/this % DIGIT_BASE, useful for Montgomery reduction.
1099 //
1100 // xy == 1 (mod m)
1101 // xy = 1+km
1102 // xy(2-xy) = (1+km)(1-km)
1103 // x(y(2-xy)) = 1-k^2 m^2
1104 // x(y(2-xy)) == 1 (mod m^2)
1105 // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
1106 // Should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
1107 int _invDigit() {
1108 if (_used == 0) return 0;
1109 var x = _digits[0];
1110 if ((x & 1) == 0) return 0;
1111 var y = x & 3; // y == 1/x mod 2^2
1112 y = (y*(2 - (x & 0xf)*y)) & 0xf; // y == 1/x mod 2^4
1113 y = (y*(2 - (x & 0xff)*y)) & 0xff; // y == 1/x mod 2^8
1114 y = (y*(2 - (((x & 0xffff)*y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
1115 // Last step - calculate inverse mod DIGIT_BASE directly;
1116 // Assumes 16 < DIGIT_BITS <= 32 and assumes ability to handle 48-bit ints.
1117 y = (y*(2 - x*y % DIGIT_BASE)) % DIGIT_BASE; // y == 1/x mod DIGIT_BASE
1118 // We really want the negative inverse, and - DIGIT_BASE < y < DIGIT_BASE.
1119 return (y > 0) ? DIGIT_BASE - y : -y;
1120 }
1121
1122 // TODO(regis): Make this method private once the plumbing to invoke it from
1123 // dart:math is in place.
1124 // Return pow(this, e) % m.
1080 int modPow(int e, int m) { 1125 int modPow(int e, int m) {
srdjan 2014/09/15 18:10:52 Maybe in a later CL: You may also implement a modP
regis 2014/09/15 19:29:31 Will do.
1126 // TODO(regis): Where/how do we handle values of e smaller than 256?
1127 // TODO(regis): Where/how do we handle even values of m?
1081 assert(e >= 256 && !m.isEven()); 1128 assert(e >= 256 && !m.isEven());
1082 if (e >= (1 << 32)) { 1129 if (e is! _Bigint) {
1083 throw "Bigint.modPow with exponent larger than 32-bit not implemented"; 1130 _Reduction z = new _Montgomery(m);
1131 var r = new _Bigint();
1132 var r2 = new _Bigint();
1133 var g = z._convert(this);
1134 int i = _nbits(e) - 1;
1135 g._copyTo(r);
1136 while (--i >= 0) {
1137 z._sqrTo(r, r2);
1138 if ((e & (1 << i)) > 0) {
1139 z._mulTo(r2, g, r);
1140 } else {
1141 var t = r;
1142 r = r2;
1143 r2 = t;
1144 }
1145 }
1146 return z._revert(r)._toValidInt();
1084 } 1147 }
1148 var i = e.bitLength;
1149 var k;
1150 var r = new _Bigint()._setInt(1);
1151 if (i <= 0) return r;
1152 // TODO(regis): Are these values of k really optimal for our implementation?
1153 else if (i < 18) k = 1;
1154 else if (i < 48) k = 3;
1155 else if (i < 144) k = 4;
1156 else if (i < 768) k = 5;
1157 else k = 6;
1085 _Reduction z = new _Montgomery(m); 1158 _Reduction z = new _Montgomery(m);
1086 var r = new _Bigint(); 1159 var n = 3;
1160 var k1 = k - 1;
1161 var km = (1 << k) - 1;
1162 List g = new List(km + 1);
1163 g[1] = z._convert(this);
1164 if (k > 1) {
1165 var g2 = new _Bigint();
1166 z._sqrTo(g[1], g2);
1167 while (n <= km) {
1168 g[n] = new _Bigint();
1169 z._mulTo(g2, g[n - 2], g[n]);
1170 n += 2;
1171 }
1172 }
1173 var j = e._used - 1;
1174 var w;
1175 var is1 = true;
1087 var r2 = new _Bigint(); 1176 var r2 = new _Bigint();
1088 var g = z.convert(this); 1177 var t;
1089 int i = _nbits(e) - 1; 1178 i = _nbits(e._digits[j]) - 1;
1090 g._copyTo(r); 1179 while (j >= 0) {
1091 while (--i >= 0) { 1180 if (i >= k1) {
1092 z.sqrTo(r, r2); 1181 w = (e._digits[j] >> (i - k1)) & km;
1093 if ((e & (1 << i)) > 0) {
1094 z.mulTo(r2, g, r);
1095 } else { 1182 } else {
1096 var t = r; 1183 w = (e._digits[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
1184 if (j > 0) {
1185 w |= e._digits[j - 1] >> (DIGIT_BITS + i - k1);
1186 }
1187 }
1188 n = k;
1189 while ((w & 1) == 0) {
1190 w >>= 1;
1191 --n;
1192 }
1193 if ((i -= n) < 0) {
1194 i += DIGIT_BITS;
1195 --j;
1196 }
1197 if (is1) { // r == 1, don't bother squaring or multiplying it.
1198 g[w]._copyTo(r);
1199 is1 = false;
1200 }
1201 else {
1202 while (n > 1) {
1203 z._sqrTo(r, r2);
1204 z._sqrTo(r2, r);
1205 n -= 2;
1206 }
1207 if (n > 0) {
1208 z._sqrTo(r, r2);
1209 } else {
1210 t = r;
1211 r = r2;
1212 r2 = t;
1213 }
1214 z._mulTo(r2,g[w], r);
1215 }
1216
1217 while (j >= 0 && (e._digits[j] & (1 << i)) == 0) {
1218 z._sqrTo(r, r2);
1219 t = r;
1097 r = r2; 1220 r = r2;
1098 r2 = t; 1221 r2 = t;
1222 if (--i < 0) {
1223 i = DIGIT_BITS - 1;
1224 --j;
1225 }
1099 } 1226 }
1100 } 1227 }
1101 return z.revert(r)._toValidInt(); 1228 return z._revert(r)._toValidInt();
1102 } 1229 }
1103 } 1230 }
1104 1231
1105 // New classes to support crypto (modPow method). 1232 // New classes to support crypto (modPow method).
1106 1233
1107 class _Reduction { 1234 class _Reduction {
1108 const _Reduction(); 1235 const _Reduction();
1109 _Bigint _convert(_Bigint x) => x; 1236 _Bigint _convert(_Bigint x) => x;
1110 _Bigint _revert(_Bigint x) => x; 1237 _Bigint _revert(_Bigint x) => x;
1111 1238
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1161 x._digits[x._used++] = 0; 1288 x._digits[x._used++] = 0;
1162 } 1289 }
1163 for (var i = 0; i < _m._used; ++i) { 1290 for (var i = 0; i < _m._used; ++i) {
1164 // Faster way of calculating u0 = x[i]*mp mod DIGIT_BASE. 1291 // Faster way of calculating u0 = x[i]*mp mod DIGIT_BASE.
1165 var j = x._digits[i] & _Bigint.DIGIT2_MASK; 1292 var j = x._digits[i] & _Bigint.DIGIT2_MASK;
1166 var u0 = (j*_mpl + (((j*_mph + (x._digits[i] >> _Bigint.DIGIT2_BITS) 1293 var u0 = (j*_mpl + (((j*_mph + (x._digits[i] >> _Bigint.DIGIT2_BITS)
1167 *_mpl) & _um) << _Bigint.DIGIT2_BITS)) & _Bigint.DIGIT_MASK; 1294 *_mpl) & _um) << _Bigint.DIGIT2_BITS)) & _Bigint.DIGIT_MASK;
1168 // Use _am to combine the multiply-shift-add into one call. 1295 // Use _am to combine the multiply-shift-add into one call.
1169 j = i + _m._used; 1296 j = i + _m._used;
1170 var digit = x._digits[j]; 1297 var digit = x._digits[j];
1171 digit += _m ._am(0, u0, x, i, 0, _m ._used); 1298 digit += _m ._am(0, u0, x, i, _m._used);
1172 // propagate carry 1299 // Propagate carry.
1173 while (digit >= _Bigint.DIGIT_BASE) { 1300 while (digit >= _Bigint.DIGIT_BASE) {
1174 digit -= _Bigint.DIGIT_BASE; 1301 digit -= _Bigint.DIGIT_BASE;
1175 x._digits[j++] = digit; 1302 x._digits[j++] = digit;
1176 digit = x._digits[j]; 1303 digit = x._digits[j];
1177 digit++; 1304 digit++;
1178 } 1305 }
1179 x._digits[j] = digit; 1306 x._digits[j] = digit;
1180 } 1307 }
1181 x._clamp(); 1308 x._clamp();
1182 x._drShiftTo(_m ._used, x); 1309 x._drShiftTo(_m ._used, x);
1183 if (x._compareTo(_m ) >= 0) { 1310 if (x._compareTo(_m ) >= 0) {
1184 x._subTo(_m , x); 1311 x._subTo(_m , x);
1185 } 1312 }
1186 } 1313 }
1187 1314
1188 // r = x^2/R mod _m ; x != r 1315 // r = x^2/R mod _m ; x != r
1189 void _sqrTo(_Bigint x, _Bigint r) { 1316 void _sqrTo(_Bigint x, _Bigint r) {
1190 x._sqrTo(r); 1317 x._sqrTo(r);
1191 _reduce(r); 1318 _reduce(r);
1192 } 1319 }
1193 1320
1194 // r = x*y/R mod _m ; x, y != r 1321 // r = x*y/R mod _m ; x, y != r
1195 void _mulTo(_Bigint x, _Bigint y, _Bigint r) { 1322 void _mulTo(_Bigint x, _Bigint y, _Bigint r) {
1196 x._mulTo(y, r); 1323 x._mulTo(y, r);
1197 _reduce(r); 1324 _reduce(r);
1198 } 1325 }
1199 } 1326 }
1200 1327
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