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

Side by Side Diff: runtime/lib/bigint.dart

Issue 811763004: Modify Bigint _mulAdd, _sqrAdd, _estQuotientDigit, and Montgomery _mulMod (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 12 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 | runtime/vm/intrinsifier_arm.cc » ('j') | runtime/vm/object.cc » ('J')
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 814 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 r._neg = r_neg; 825 r._neg = r_neg;
826 return r; 826 return r;
827 } 827 }
828 828
829 // Multiply and accumulate. 829 // Multiply and accumulate.
830 // Input: 830 // Input:
831 // x_digits[xi]: multiplier digit x. 831 // x_digits[xi]: multiplier digit x.
832 // m_digits[i..i+n-1]: multiplicand digits. 832 // m_digits[i..i+n-1]: multiplicand digits.
833 // a_digits[j..j+n-1]: accumulator digits. 833 // a_digits[j..j+n-1]: accumulator digits.
834 // Operation: 834 // Operation:
835 // a_digits[j..j+n] += x*m_digits[i..i+n-1]. 835 // a_digits[j..j+n] += x_digits[xi]*m_digits[i..i+n-1].
836 static void _mulAdd(Uint32List x_digits, int xi, 836 // return 1.
837 Uint32List m_digits, int i, 837 // Note: intrinsics on 64-bit platform may process a digit pair:
838 Uint32List a_digits, int j, int n) { 838 // a_digits[j..j+n] += x_digits[xi..xi+1]*m_digits[i..i+n-1].
839 // return 2.
840 static int _mulAdd(Uint32List x_digits, int xi,
841 Uint32List m_digits, int i,
842 Uint32List a_digits, int j, int n) {
839 int x = x_digits[xi]; 843 int x = x_digits[xi];
840 if (x == 0) { 844 if (x == 0) {
841 // No-op if x is 0. 845 // No-op if x is 0.
842 return; 846 return 1;
843 } 847 }
844 int c = 0; 848 int c = 0;
845 int xl = x & DIGIT2_MASK; 849 int xl = x & DIGIT2_MASK;
846 int xh = x >> DIGIT2_BITS; 850 int xh = x >> DIGIT2_BITS;
847 while (--n >= 0) { 851 while (--n >= 0) {
848 int l = m_digits[i] & DIGIT2_MASK; 852 int l = m_digits[i] & DIGIT2_MASK;
849 int h = m_digits[i++] >> DIGIT2_BITS; 853 int h = m_digits[i++] >> DIGIT2_BITS;
850 int m = xh*l + h*xl; 854 int m = xh*l + h*xl;
851 l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + a_digits[j] + c; 855 l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + a_digits[j] + c;
852 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h; 856 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h;
853 a_digits[j++] = l & DIGIT_MASK; 857 a_digits[j++] = l & DIGIT_MASK;
854 } 858 }
855 while (c != 0) { 859 while (c != 0) {
856 int l = a_digits[j] + c; 860 int l = a_digits[j] + c;
857 c = l >> DIGIT_BITS; 861 c = l >> DIGIT_BITS;
858 a_digits[j++] = l & DIGIT_MASK; 862 a_digits[j++] = l & DIGIT_MASK;
859 } 863 }
864 return 1;
860 } 865 }
861 866
862 // Square and accumulate. 867 // Square and accumulate.
863 // Input: 868 // Input:
864 // x_digits[i..used-1]: digits of operand being squared. 869 // x_digits[i..used-1]: digits of operand being squared.
865 // a_digits[2*i..i+used-1]: accumulator digits. 870 // a_digits[2*i..i+used-1]: accumulator digits.
866 // Operation: 871 // Operation:
867 // a_digits[2*i..i+used-1] += x_digits[i]*x_digits[i] + 872 // a_digits[2*i..i+used-1] += x_digits[i]*x_digits[i] +
868 // 2*x_digits[i]*x_digits[i+1..used-1]. 873 // 2*x_digits[i]*x_digits[i+1..used-1].
869 static void _sqrAdd(Uint32List x_digits, int i, 874 // return 1.
870 Uint32List a_digits, int used) { 875 // Note: intrinsics on 64-bit platform may process a digit pair:
876 // a_digits[2*i..i+used-1] += x_digits[i..i+1]*x_digits[i..i+1] +
877 // 2*x_digits[i..i+1]*x_digits[i+2..used-1].
878 // return 2.
879 static int _sqrAdd(Uint32List x_digits, int i,
880 Uint32List a_digits, int used) {
871 int x = x_digits[i]; 881 int x = x_digits[i];
872 if (x == 0) return; 882 if (x == 0) return 1;
873 int j = 2*i; 883 int j = 2*i;
874 int c = 0; 884 int c = 0;
875 int xl = x & DIGIT2_MASK; 885 int xl = x & DIGIT2_MASK;
876 int xh = x >> DIGIT2_BITS; 886 int xh = x >> DIGIT2_BITS;
877 int m = 2*xh*xl; 887 int m = 2*xh*xl;
878 int l = xl*xl + ((m & DIGIT2_MASK) << DIGIT2_BITS) + a_digits[j]; 888 int l = xl*xl + ((m & DIGIT2_MASK) << DIGIT2_BITS) + a_digits[j];
879 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*xh; 889 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*xh;
880 a_digits[j] = l & DIGIT_MASK; 890 a_digits[j] = l & DIGIT_MASK;
881 x <<= 1; 891 x <<= 1;
882 xl = x & DIGIT2_MASK; 892 xl = x & DIGIT2_MASK;
883 xh = x >> DIGIT2_BITS; 893 xh = x >> DIGIT2_BITS;
884 int n = used - i - 1; 894 int n = used - i - 1;
885 int k = i + 1; 895 int k = i + 1;
886 j++; 896 j++;
887 while (--n >= 0) { 897 while (--n >= 0) {
888 int l = x_digits[k] & DIGIT2_MASK; 898 int l = x_digits[k] & DIGIT2_MASK;
889 int h = x_digits[k++] >> DIGIT2_BITS; 899 int h = x_digits[k++] >> DIGIT2_BITS;
890 int m = xh*l + h*xl; 900 int m = xh*l + h*xl;
891 l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + a_digits[j] + c; 901 l = xl*l + ((m & DIGIT2_MASK) << DIGIT2_BITS) + a_digits[j] + c;
892 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h; 902 c = (l >> DIGIT_BITS) + (m >> DIGIT2_BITS) + xh*h;
893 a_digits[j++] = l & DIGIT_MASK; 903 a_digits[j++] = l & DIGIT_MASK;
894 } 904 }
895 c += a_digits[i + used]; 905 c += a_digits[i + used];
896 if (c >= DIGIT_BASE) { 906 if (c >= DIGIT_BASE) {
897 a_digits[i + used] = c - DIGIT_BASE; 907 a_digits[i + used] = c - DIGIT_BASE;
898 a_digits[i + used + 1] = 1; 908 a_digits[i + used + 1] = 1;
899 } else { 909 } else {
900 a_digits[i + used] = c; 910 a_digits[i + used] = c;
901 } 911 }
912 return 1;
902 } 913 }
903 914
904 // r = this * a. 915 // r = this * a.
905 void _mulTo(_Bigint a, _Bigint r) { 916 void _mulTo(_Bigint a, _Bigint r) {
906 // TODO(regis): Use karatsuba multiplication when appropriate. 917 // TODO(regis): Use karatsuba multiplication when appropriate.
907 var used = _used; 918 var used = _used;
908 var a_used = a._used; 919 var a_used = a._used;
909 if (used == 0 || a_used == 0) { 920 if (used == 0 || a_used == 0) {
910 r._used = 0; 921 r._used = 0;
911 r._neg = false; 922 r._neg = false;
912 return; 923 return;
913 } 924 }
914 var r_used = used + a_used; 925 var r_used = used + a_used;
915 r._ensureLength(r_used); 926 r._ensureLength(r_used);
916 var digits = _digits; 927 var digits = _digits;
917 var a_digits = a._digits; 928 var a_digits = a._digits;
918 var r_digits = r._digits; 929 var r_digits = r._digits;
919 r._used = r_used; 930 r._used = r_used;
920 var i = r_used + 1; // Set leading zero for 64-bit processing. 931 var i = r_used + 1; // Set leading zero for 64-bit processing.
921 while (--i >= 0) { 932 while (--i >= 0) {
922 r_digits[i] = 0; 933 r_digits[i] = 0;
923 } 934 }
924 for (i = 0; i < a_used; ++i) { 935 i = 0;
925 _mulAdd(a_digits, i, digits, 0, r_digits, i, used); 936 while (i < a_used) {
937 i += _mulAdd(a_digits, i, digits, 0, r_digits, i, used);
926 } 938 }
927 r._clamp(); 939 r._clamp();
928 r._neg = r._used > 0 && _neg != a._neg; // Zero cannot be negative. 940 r._neg = r._used > 0 && _neg != a._neg; // Zero cannot be negative.
929 } 941 }
930 942
931 // r = this^2, r != this. 943 // r = this^2, r != this.
932 void _sqrTo(_Bigint r) { 944 void _sqrTo(_Bigint r) {
933 var used = _used; 945 var used = _used;
934 if (used == 0) { 946 if (used == 0) {
935 r._used = 0; 947 r._used = 0;
936 r._neg = false; 948 r._neg = false;
937 return; 949 return;
938 } 950 }
939 var r_used = 2 * used; 951 var r_used = 2 * used;
940 r._ensureLength(r_used); 952 r._ensureLength(r_used);
941 var digits = _digits; 953 var digits = _digits;
942 var r_digits = r._digits; 954 var r_digits = r._digits;
943 var i = r_used + 1; // Set leading zero for 64-bit processing. 955 var i = r_used + 1; // Set leading zero for 64-bit processing.
944 while (--i >= 0) { 956 while (--i >= 0) {
945 r_digits[i] = 0; 957 r_digits[i] = 0;
946 } 958 }
947 for (i = 0; i < used - 1; ++i) { 959 i = 0;
948 _sqrAdd(digits, i, r_digits, used); 960 while (i < used - 1) {
961 i += _sqrAdd(digits, i, r_digits, used);
949 } 962 }
950 if (r_used > 0) { 963 if (r_used > 0) {
951 _mulAdd(digits, i, digits, i, r_digits, 2*i, 1); 964 _mulAdd(digits, i, digits, i, r_digits, 2*i, 1);
952 } 965 }
953 r._used = r_used; 966 r._used = r_used;
954 r._neg = false; 967 r._neg = false;
955 r._clamp(); 968 r._clamp();
956 } 969 }
957 970
958 // Indices of the arguments of _estQuotientDigit. 971 // Indices of the arguments of _estQuotientDigit.
959 static const int _YT = 0; // Index of top digit of divisor y in args array. 972 // For 64-bit processing by intrinsics on 64-bit platforms, the top digit pair
960 static const int _QD = 1; // Index of estimated quotient digit in args array. 973 // of divisor y is provided in the args array, and a 64-bit estimated quotient
974 // is returned. However, on 32-bit platforms, the low 32-bit digit is ignored
975 // and only one 32-bit digit is returned as the estimated quotient.
976 static const int _YT_LO = 0; // Low digit of top digit pair of y, for 64-bit.
977 static const int _YT = 1; // Top digit of divisor y.
978 static const int _QD = 2; // Estimated quotient.
979 static const int _QD_HI = 3; // High digit of estimated quotient, for 64-bit.
961 980
962 // Estimate args[_QD] = digits[i]:digits[i-1] ~/ args[_YT]. 981 // Operation:
963 static void _estQuotientDigit(Uint32List args, Uint32List digits, int i) { 982 // Estimate args[_QD] = digits[i-1..i] ~/ args[_YT]
983 // return 1
984 // Note: intrinsics on 64-bit platform may process a digit pair:
985 // Estimate args[_QD.._QD_HI] = digits[i-3..i] ~/ args[_YT_LO.._YT]
986 // return 2
987 static int _estQuotientDigit(Uint32List args, Uint32List digits, int i) {
964 if (digits[i] == args[_YT]) { 988 if (digits[i] == args[_YT]) {
965 args[_QD] = DIGIT_MASK; 989 args[_QD] = DIGIT_MASK;
966 } else { 990 } else {
967 // Chop off one bit, since a Mint cannot hold 2 DIGITs. 991 // Chop off one bit, since a Mint cannot hold 2 DIGITs.
968 var qd = ((digits[i] << (DIGIT_BITS - 1)) | (digits[i - 1] >> 1)) 992 var qd = ((digits[i] << (DIGIT_BITS - 1)) | (digits[i - 1] >> 1))
969 ~/ (args[_YT] >> 1); 993 ~/ (args[_YT] >> 1);
970 if (qd > DIGIT_MASK) { 994 if (qd > DIGIT_MASK) {
971 args[_QD] = DIGIT_MASK; 995 args[_QD] = DIGIT_MASK;
972 } else { 996 } else {
973 args[_QD] = qd; 997 args[_QD] = qd;
974 } 998 }
975 } 999 }
1000 return 1;
976 } 1001 }
977 1002
978 1003
979 // Truncating division and remainder. 1004 // Truncating division and remainder.
980 // If q != null, q = trunc(this / a). 1005 // If q != null, q = trunc(this / a).
981 // If r != null, r = this - a * trunc(this / a). 1006 // If r != null, r = this - a * trunc(this / a).
982 void _divRemTo(_Bigint a, _Bigint q, _Bigint r) { 1007 void _divRemTo(_Bigint a, _Bigint q, _Bigint r) {
983 if (a._used == 0) return; 1008 if (a._used == 0) return;
984 if (_used < a._used) { 1009 if (_used < a._used) {
985 if (q != null) { 1010 if (q != null) {
986 // Set q to 0. 1011 // Set q to 0.
987 q._neg = false; 1012 q._neg = false;
988 q._used = 0; 1013 q._used = 0;
989 } 1014 }
990 if (r != null) { 1015 if (r != null) {
991 _copyTo(r); 1016 _copyTo(r);
992 } 1017 }
993 return; 1018 return;
994 } 1019 }
995 if (r == null) { 1020 if (r == null) {
996 r = new _Bigint(); 1021 r = new _Bigint();
997 } 1022 }
998 var y = new _Bigint(); // Normalized modulus. 1023 var y = new _Bigint(); // Normalized modulus.
999 var nsh = DIGIT_BITS - _nbits(a._digits[a._used - 1]); 1024 var nsh = DIGIT_BITS - _nbits(a._digits[a._used - 1]);
1025 // For 64-bit processing, make sure y has an even number of digits.
1026 if ((a._used & 1) == 1) {
1027 nsh += DIGIT_BITS;
1028 }
1000 if (nsh > 0) { 1029 if (nsh > 0) {
1001 a._lShiftTo(nsh, y); 1030 a._lShiftTo(nsh, y);
1002 _lShiftTo(nsh, r); 1031 _lShiftTo(nsh, r);
1003 } 1032 }
1004 else { 1033 else {
1005 a._copyTo(y); 1034 a._copyTo(y);
1006 _copyTo(r); 1035 _copyTo(r);
1007 } 1036 }
1008 // We consider this and a positive. Ignore the copied sign. 1037 // We consider this and a positive. Ignore the copied sign.
1009 y._neg = false; 1038 y._neg = false;
1010 r._neg = false; 1039 r._neg = false;
1011 var y_used = y._used; 1040 var y_used = y._used;
1012 var y_digits = y._digits; 1041 var y_digits = y._digits;
1013 var yt = y_digits[y_used - 1]; 1042 Uint32List args = new Uint32List(4);
1014 if (yt == 0) return; 1043 args[_YT_LO] = y_digits[y_used - 2];
1044 args[_YT] = y_digits[y_used - 1];
1015 var i = r._used; 1045 var i = r._used;
1016 var j = i - y_used; 1046 var j = i - y_used;
1017 _Bigint t = (q == null) ? new _Bigint() : q; 1047 _Bigint t = (q == null) ? new _Bigint() : q;
1018 y._dlShiftTo(j, t); 1048 y._dlShiftTo(j, t);
1019 var r_digits = r._digits; 1049 var r_digits = r._digits;
1020 if (r._compareTo(t) >= 0) { 1050 if (r._compareTo(t) >= 0) {
1021 r_digits[r._used++] = 1; 1051 r_digits[r._used++] = 1;
1022 r_digits[r._used] = 0; // Set leading zero for 64-bit processing. 1052 r_digits[r._used] = 0; // Set leading zero for 64-bit processing.
1023 r._subTo(t, r); 1053 r._subTo(t, r);
1024 } 1054 }
1025 ONE._dlShiftTo(y_used, t); 1055 ONE._dlShiftTo(y_used, t);
1026 t._subTo(y, y); // Negate y so we can replace sub with _mulAdd later. 1056 t._subTo(y, y); // Negate y so we can replace sub with _mulAdd later.
1027 while (y._used < y_used) { 1057 while (y._used < y_used) {
1028 y_digits[y._used++] = 0; 1058 y_digits[y._used++] = 0;
1029 } 1059 }
1030 y_digits[y._used] = 0; // Set leading zero for 64-bit processing. 1060 y_digits[y._used] = 0; // Set leading zero for 64-bit processing.
1031 Uint32List args = new Uint32List(2);
1032 args[_YT] = yt;
1033 while (--j >= 0) { 1061 while (--j >= 0) {
1034 _estQuotientDigit(args, r_digits, --i); 1062 var d0 = _estQuotientDigit(args, r_digits, --i);
1035 _mulAdd(args, _QD, y_digits, 0, r_digits, j, y_used); 1063 var d1 = _mulAdd(args, _QD, y_digits, 0, r_digits, j, y_used);
1036 if (r_digits[i] < args[_QD]) { 1064 // _estQuotientDigit and _mulAdd must agree on the number of digits to
1037 y._dlShiftTo(j, t); 1065 // process.
1038 r._subTo(t, r); 1066 assert(d0 == d1);
1039 while (r_digits[i] < --args[_QD]) { 1067 if (d0 == 1) {
1068 if (r_digits[i] < args[_QD]) {
1069 y._dlShiftTo(j, t);
1040 r._subTo(t, r); 1070 r._subTo(t, r);
1071 while (r_digits[i] < --args[_QD]) {
1072 r._subTo(t, r);
1073 }
1074 }
1075 } else {
1076 // TODO(regis): Is this necessary, since intrinsified estimation is more
1077 // accurate?
1078 if ((r_digits[i] < args[_QD_HI]) ||
1079 ((r_digits[i] == args[_QD_HI]) && (r_digits[i-1] < args[_QD]))) {
1080 y._dlShiftTo(j, t);
1081 r._subTo(t, r);
1082 assert(args[_QD] > 0);
1083 while (r_digits[i] < --args[_QD]) {
1084 r._subTo(t, r);
1085 }
1041 } 1086 }
1042 } 1087 }
1043 } 1088 }
1044 if (q != null) { 1089 if (q != null) {
1045 r._drShiftTo(y_used, q); 1090 r._drShiftTo(y_used, q);
1046 if (_neg != a._neg && q._used > 0) { 1091 if (_neg != a._neg && q._used > 0) {
1047 q._neg = !q._neg; 1092 q._neg = !q._neg;
1048 } 1093 }
1049 } 1094 }
1050 r._used = y_used; 1095 r._used = y_used;
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
1267 other._toBigint()._divRemTo(this, null, result); 1312 other._toBigint()._divRemTo(this, null, result);
1268 return result._toValidInt(); 1313 return result._toValidInt();
1269 } 1314 }
1270 bool _greaterThanFromInteger(int other) { 1315 bool _greaterThanFromInteger(int other) {
1271 return other._toBigint()._compareTo(this) > 0; 1316 return other._toBigint()._compareTo(this) > 0;
1272 } 1317 }
1273 bool _equalToInteger(int other) { 1318 bool _equalToInteger(int other) {
1274 return other._toBigint()._compareTo(this) == 0; 1319 return other._toBigint()._compareTo(this) == 0;
1275 } 1320 }
1276 1321
1277 // Return -1/this % DIGIT_BASE, useful for Montgomery reduction.
1278 //
1279 // xy == 1 (mod m)
1280 // xy = 1+km
1281 // xy(2-xy) = (1+km)(1-km)
1282 // x(y(2-xy)) = 1-k^2 m^2
1283 // x(y(2-xy)) == 1 (mod m^2)
1284 // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
1285 // Should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
1286 int _invDigit() {
1287 if (_used == 0) return 0;
1288 var x = _digits[0];
1289 if ((x & 1) == 0) return 0;
1290 var y = x & 3; // y == 1/x mod 2^2
1291 y = (y*(2 - (x & 0xf)*y)) & 0xf; // y == 1/x mod 2^4
1292 y = (y*(2 - (x & 0xff)*y)) & 0xff; // y == 1/x mod 2^8
1293 y = (y*(2 - (((x & 0xffff)*y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
1294 // Last step - calculate inverse mod DIGIT_BASE directly;
1295 // Assumes 16 < DIGIT_BITS <= 32 and assumes ability to handle 48-bit ints.
1296 y = (y*(2 - x*y % DIGIT_BASE)) % DIGIT_BASE; // y == 1/x mod DIGIT_BASE
1297 // We really want the negative inverse, and - DIGIT_BASE < y < DIGIT_BASE.
1298 return (y > 0) ? DIGIT_BASE - y : -y;
1299 }
1300
1301 // TODO(regis): Make this method private once the plumbing to invoke it from 1322 // TODO(regis): Make this method private once the plumbing to invoke it from
1302 // dart:math is in place. Move the argument checking to dart:math. 1323 // dart:math is in place. Move the argument checking to dart:math.
1303 // Return pow(this, e) % m. 1324 // Return pow(this, e) % m.
1304 int modPow(int e, int m) { 1325 int modPow(int e, int m) {
1305 if (e is! int) throw new ArgumentError(e); 1326 if (e is! int) throw new ArgumentError(e);
1306 if (m is! int) throw new ArgumentError(m); 1327 if (m is! int) throw new ArgumentError(m);
1307 int i = e.bitLength; 1328 int i = e.bitLength;
1308 if (i <= 0) return 1; 1329 if (i <= 0) return 1;
1309 if ((e is! _Bigint) || m.isEven) { 1330 if ((e is! _Bigint) || m.isEven) {
1310 _Reduction z = (i < 8 || m.isEven) ? new _Classic(m) : new _Montgomery(m); 1331 _Reduction z = (i < 8 || m.isEven) ? new _Classic(m) : new _Montgomery(m);
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1414 _Bigint _convert(_Bigint x); 1435 _Bigint _convert(_Bigint x);
1415 _Bigint _revert(_Bigint x); 1436 _Bigint _revert(_Bigint x);
1416 void _mulTo(_Bigint x, _Bigint y, _Bigint r); 1437 void _mulTo(_Bigint x, _Bigint y, _Bigint r);
1417 void _sqrTo(_Bigint x, _Bigint r); 1438 void _sqrTo(_Bigint x, _Bigint r);
1418 } 1439 }
1419 1440
1420 // Montgomery reduction on _Bigint. 1441 // Montgomery reduction on _Bigint.
1421 class _Montgomery implements _Reduction { 1442 class _Montgomery implements _Reduction {
1422 _Bigint _m; 1443 _Bigint _m;
1423 int _mused2; 1444 int _mused2;
1424 Uint32List _rho_mu; 1445 Uint32List _args;
1425 static const int _RHO = 0; // Index of rho in _rho_mu array. 1446 int _digits_per_step; // Number of digits processed in one step. 1 or 2.
1426 static const int _MU = 1; // Index of mu in _rho_mu array. 1447 static const int _X = 0; // Index of x.
1448 static const int _X_HI = 1; // Index of high 32-bits of x (64-bit only).
1449 static const int _RHO = 2; // Index of rho.
1450 static const int _RHO_HI = 3; // Index of high 32-bits of rho (64-bit only).
1451 static const int _MU = 4; // Index of mu.
1452 static const int _MU_HI = 5; // Index of high 32-bits of mu (64-bit only).
1427 1453
1428 _Montgomery(m) { 1454 _Montgomery(m) {
1429 _m = m._toBigint(); 1455 _m = m._toBigint();
1430 _mused2 = 2*_m._used; 1456 _mused2 = 2*_m._used;
1431 _rho_mu = new Uint32List(2); 1457 _args = new Uint32List(6);
1432 _rho_mu[_RHO] = _m._invDigit(); 1458 _args[_X] = _m._digits[0];
1459 _args[_X_HI] = _m._digits[1];
1460 _digits_per_step = _invDigit(_args);
1433 } 1461 }
1434 1462
1435 // args[_MU] = args[_RHO]*digits[i] mod DIGIT_BASE. 1463 // Return -1/this % DIGIT_BASE, useful for Montgomery reduction.
1436 static void _mulMod(Uint32List args, Uint32List digits, int i) { 1464 //
1465 // xy == 1 (mod m)
1466 // xy = 1+km
1467 // xy(2-xy) = (1+km)(1-km)
1468 // x(y(2-xy)) = 1-k^2 m^2
1469 // x(y(2-xy)) == 1 (mod m^2)
1470 // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
1471 // Should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
1472 //
1473 // TODO(regis): Intrinsify this method and provide a 64-bit inverse digit pair
1474 // on 64-bit platforms.
1475 //
1476 // Operation:
1477 // args[_RHO] = 1/args[_X] mod DIGIT_BASE.
1478 // return 1.
1479 // Note: intrinsics on 64-bit platform process a digit pair:
1480 // args[_RHO.._RHO_HI] = 1/args[_X.._X_HI] mod DIGIT_BASE^2.
1481 // return 2.
1482 static int _invDigit(Uint32List args) {
1483 var x = args[_X];
1484 var y = x & 3; // y == 1/x mod 2^2
1485 y = (y*(2 - (x & 0xf)*y)) & 0xf; // y == 1/x mod 2^4
1486 y = (y*(2 - (x & 0xff)*y)) & 0xff; // y == 1/x mod 2^8
1487 y = (y*(2 - (((x & 0xffff)*y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
1488 // Last step - calculate inverse mod DIGIT_BASE directly;
1489 // Assumes 16 < DIGIT_BITS <= 32 and assumes ability to handle 48-bit ints.
1490 y = (y*(2 - x*y % _Bigint.DIGIT_BASE)) % _Bigint.DIGIT_BASE;
1491 // y == 1/x mod DIGIT_BASE
1492 // We really want the negative inverse, and - DIGIT_BASE < y < DIGIT_BASE.
1493 args[_RHO] = (y > 0) ? _Bigint.DIGIT_BASE - y : -y;
1494 return 1;
1495 }
1496
1497 // Operation:
1498 // args[_MU] = args[_RHO]*digits[i] mod DIGIT_BASE.
1499 // return 1.
1500 // Note: intrinsics on 64-bit platform may process a digit pair:
1501 // args[_MU.._MU_HI] = args[_RHO.._RHO_HI]*digits[i..i+1] mod DIGIT_BASE^2.
1502 // return 2.
1503 static int _mulMod(Uint32List args, Uint32List digits, int i) {
1437 const int MU_MASK = (1 << (_Bigint.DIGIT_BITS - _Bigint.DIGIT2_BITS)) - 1; 1504 const int MU_MASK = (1 << (_Bigint.DIGIT_BITS - _Bigint.DIGIT2_BITS)) - 1;
1438 var rhol = args[_RHO] & _Bigint.DIGIT2_MASK; 1505 var rhol = args[_RHO] & _Bigint.DIGIT2_MASK;
1439 var rhoh = args[_RHO] >> _Bigint.DIGIT2_BITS; 1506 var rhoh = args[_RHO] >> _Bigint.DIGIT2_BITS;
1440 var dh = digits[i] >> _Bigint.DIGIT2_BITS; 1507 var dh = digits[i] >> _Bigint.DIGIT2_BITS;
1441 var dl = digits[i] & _Bigint.DIGIT2_MASK; 1508 var dl = digits[i] & _Bigint.DIGIT2_MASK;
1442 args[_MU] = 1509 args[_MU] =
1443 (dl*rhol + (((dl*rhoh + dh*rhol) & MU_MASK) << _Bigint.DIGIT2_BITS)) 1510 (dl*rhol + (((dl*rhoh + dh*rhol) & MU_MASK) << _Bigint.DIGIT2_BITS))
1444 & _Bigint.DIGIT_MASK; 1511 & _Bigint.DIGIT_MASK;
1512 return 1;
1445 } 1513 }
1446 1514
1447 // Return x*R mod _m 1515 // Return x*R mod _m
1448 _Bigint _convert(_Bigint x) { 1516 _Bigint _convert(_Bigint x) {
1449 var r = new _Bigint(); 1517 var r = new _Bigint();
1450 x.abs()._dlShiftTo(_m._used, r); 1518 x.abs()._dlShiftTo(_m._used, r);
1451 r._divRemTo(_m, null, r); 1519 r._divRemTo(_m, null, r);
1452 if (x._neg && !r._neg && r._used > 0) { 1520 if (x._neg && !r._neg && r._used > 0) {
1453 _m._subTo(r, r); 1521 _m._subTo(r, r);
1454 } 1522 }
(...skipping 11 matching lines...) Expand all
1466 // x = x/R mod _m 1534 // x = x/R mod _m
1467 void _reduce(_Bigint x) { 1535 void _reduce(_Bigint x) {
1468 x._ensureLength(_mused2 + 1); 1536 x._ensureLength(_mused2 + 1);
1469 var x_digits = x._digits; 1537 var x_digits = x._digits;
1470 while (x._used <= _mused2) { // Pad x so _mulAdd has enough room later. 1538 while (x._used <= _mused2) { // Pad x so _mulAdd has enough room later.
1471 x_digits[x._used++] = 0; 1539 x_digits[x._used++] = 0;
1472 } 1540 }
1473 x_digits[x._used] = 0; // Set leading zero for 64-bit processing. 1541 x_digits[x._used] = 0; // Set leading zero for 64-bit processing.
1474 var m_used = _m._used; 1542 var m_used = _m._used;
1475 var m_digits = _m._digits; 1543 var m_digits = _m._digits;
1476 for (var i = 0; i < m_used; i++) { 1544 var i = 0;
1477 _mulMod(_rho_mu, x_digits, i); 1545 while (i < m_used) {
1478 _Bigint._mulAdd(_rho_mu, _MU, m_digits, 0, x_digits, i, m_used); 1546 var d = _mulMod(_args, x_digits, i);
1547 assert(d == _digits_per_step);
1548 d = _Bigint._mulAdd(_args, _MU, m_digits, 0, x_digits, i, m_used);
1549 assert(d == _digits_per_step);
1550 i += d;
1479 } 1551 }
1480 x._clamp(); 1552 x._clamp();
1481 x._drShiftTo(m_used, x); 1553 x._drShiftTo(m_used, x);
1482 if (x._compareTo(_m) >= 0) { 1554 if (x._compareTo(_m) >= 0) {
1483 x._subTo(_m, x); 1555 x._subTo(_m, x);
1484 } 1556 }
1485 } 1557 }
1486 1558
1487 // r = x^2/R mod _m ; x != r 1559 // r = x^2/R mod _m ; x != r
1488 void _sqrTo(_Bigint x, _Bigint r) { 1560 void _sqrTo(_Bigint x, _Bigint r) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1528 void _sqrTo(_Bigint x, _Bigint r) { 1600 void _sqrTo(_Bigint x, _Bigint r) {
1529 x._sqrTo(r); 1601 x._sqrTo(r);
1530 _reduce(r); 1602 _reduce(r);
1531 } 1603 }
1532 1604
1533 void _mulTo(_Bigint x, _Bigint y, _Bigint r) { 1605 void _mulTo(_Bigint x, _Bigint y, _Bigint r) {
1534 x._mulTo(y, r); 1606 x._mulTo(y, r);
1535 _reduce(r); 1607 _reduce(r);
1536 } 1608 }
1537 } 1609 }
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intrinsifier_arm.cc » ('j') | runtime/vm/object.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698