├── .gitignore ├── FGInt.pas ├── README.md ├── compile └── test.pp /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /FGInt.pas: -------------------------------------------------------------------------------- 1 | {License, info, etc 2 | ------------------ 3 | This implementation is made by me, Walied Othman, to contact me 4 | mail to rainwolf@submanifold.be or triade@submanifold.be , 5 | always mention wether it 's about the FGInt or about the 6xs, 6 | preferably in the subject line. 7 | This source code is free, but only to other free software, 8 | it's a two-way street, if you use this code in an application from which 9 | you won't make any money of (e.g. software for the good of mankind) 10 | then go right ahead, I won't stop you, I do demand acknowledgement for 11 | my work. However, if you're using this code in a commercial application, 12 | an application from which you'll make money, then yes, I charge a 13 | license-fee, as described in the license agreement for commercial use, see 14 | the textfile in this zip-file. 15 | If you 're going to use these implementations, let me know, so I ca, put a link 16 | on my page if desired, I 'm always curious as to see where the spawn of my 17 | mind ends up in. If any algorithm is patented in your country, you should 18 | acquire a license before using this software. Modified versions of this 19 | software must contain an acknowledgement of the original author (=me). 20 | 21 | This implementation is available at 22 | http://www.submanifold.be 23 | 24 | copyright 2000, Walied Othman 25 | This header may not be removed.} 26 | 27 | Unit FGInt; 28 | 29 | {$H+}{$LongStrings ON} 30 | 31 | Interface 32 | 33 | Uses SysUtils, Math; 34 | 35 | Type 36 | TCompare = (Lt, St, Eq, Er); 37 | TSign = (negative, positive); 38 | TFGInt = Record 39 | Sign : TSign; 40 | Number : Array Of LongWord; 41 | End; 42 | 43 | Procedure FGIntDestroy(Var FGInt : TFGInt); 44 | Procedure FGIntCopy(Const FGInt1 : TFGInt; Var FGInt2 : TFGInt); 45 | Function FGIntCompareAbs(Const FGInt1, FGInt2 : TFGInt) : TCompare; 46 | Procedure FGIntAbs(Var FGInt : TFGInt); 47 | Procedure FGIntShiftLeft(Var FGInt : TFGInt); 48 | Procedure FGIntShiftLeftBy32(Var FGInt : TFGInt); 49 | Procedure FGIntShiftRight(Var FGInt : TFGInt); 50 | Procedure FGIntShiftRightBy32(Var FGInt : TFGInt); 51 | Procedure FGIntShiftLeftBy32Times(Var FGInt : TFGInt; times : LongWord); 52 | Procedure FGIntShiftRightBy32Times(Var FGInt : TFGInt; times : LongWord); 53 | Procedure FGIntShiftLeftBy(Var FGInt : TFGInt; by : LongWord); 54 | Procedure FGIntShiftRightBy(Var FGInt : TFGInt; by : LongWord); 55 | Procedure FGIntToBase2String(Const FGInt : TFGInt; Var S : String); 56 | Procedure Base2StringToFGInt(S : String; Var FGInt : TFGInt); 57 | Procedure Base10StringToFGInt(Base10 : String; Var FGInt : TFGInt); 58 | Procedure FGIntToBase10String(Const FGInt : TFGInt; Var Base10 : String); 59 | Procedure FGIntToBase256String(Const FGInt : TFGInt; Var str256 : String); 60 | Procedure Base256StringToFGInt(str256 : String; Var FGInt : TFGInt); 61 | Procedure ConvertBase256StringToHexString(Str256 : String; Var HexStr : String); 62 | Procedure ConvertHexStringToBase256String(HexStr : String; Var Str256 : String); 63 | Procedure PGPMPIToFGInt(PGPMPI : String; Var FGInt : TFGInt); 64 | Procedure FGIntToPGPMPI(FGInt : TFGInt; Var PGPMPI : String); 65 | 66 | Procedure FGIntDivByIntBis(Var FGInt : TFGInt; by : LongWord; Var modres : LongWord); 67 | Procedure FGIntAdd(Const FGInt1, FGInt2 : TFGInt; Var Sum : TFGInt); 68 | Procedure FGIntChangeSign(Var FGInt : TFGInt); 69 | Procedure FGIntSub(Const FGInt1 : TFGInt; Var FGInt2, dif : TFGInt); 70 | Procedure FGIntAddBis(Var FGInt1 : TFGInt; Const FGInt2 : TFGInt); 71 | Procedure FGIntSubBis(Var FGInt1 : TFGInt; Const FGInt2 : TFGInt); 72 | Procedure FGIntPencilPaperMultiply(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt); 73 | Procedure FGIntKaratsubaMultiply(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt); 74 | // Procedure FGIntKaratsubaMultiply(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt; Const karatsubaThreshold : LongWord); 75 | Procedure FGIntMul(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt); 76 | Procedure FGIntPencilPaperSquare(Const FGInt : TFGInt; Var Square : TFGInt); 77 | // Procedure FGIntKaratsubaSquare(Const FGInt : TFGInt; Var Square : TFGInt; Const karatsubaThreshold : LongWord); 78 | Procedure FGIntKaratsubaSquare(Const FGInt : TFGInt; Var Square : TFGInt); 79 | Procedure FGIntSquare(Const FGInt : TFGInt; Var Square : TFGInt); 80 | Procedure FGIntMulByInt(Const FGInt : TFGInt; Var res : TFGInt; by : LongWord); 81 | Procedure FGIntMulByIntbis(Var FGInt : TFGInt; by : LongWord); 82 | Procedure FGIntDivByInt(Const FGInt : TFGInt; Var res : TFGInt; by : LongWord; Var modres : LongWord); 83 | // Procedure FGIntDivByIntBis(Var FGInt : TFGInt; by : LongWord; Var modres : LongWord); 84 | Procedure FGIntExp(Const FGInt, exp : TFGInt; Var res : TFGInt); 85 | Procedure FGIntFac(Const FGInt : TFGInt; Var res : TFGInt); 86 | Procedure FGIntDivMod(Var FGInt1, FGInt2, QFGInt, MFGInt : TFGInt); 87 | Procedure FGIntDiv(Var FGInt1, FGInt2, QFGInt : TFGInt); 88 | Procedure FGIntMulByIntSubBis(Var FGInt1 : TFGInt; Const FGInt2 : TFGInt; divInt : LongWord); 89 | Procedure FGIntMod(Var FGInt1, FGInt2, MFGInt : TFGInt); 90 | Procedure FGIntSquareMod(Var FGInt, Modb, FGIntSM : TFGInt); 91 | Procedure FGIntAddMod(Var FGInt1, FGInt2, base, FGIntres : TFGInt); 92 | Procedure FGIntMulMod(Var FGInt1, FGInt2, base, FGIntres : TFGInt); 93 | 94 | Procedure FGIntModBis(Const FGInt : TFGInt; Var FGIntOut : TFGInt; b, head : LongWord); 95 | Procedure FGIntMulModBis(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt; b, head : LongWord); 96 | Procedure FGIntMontgomeryModExp(Var FGInt, exp, modb, res : TFGInt); 97 | Procedure FGIntModExp(Var FGInt, exp, modb, res : TFGInt); 98 | 99 | Procedure FGIntGCD(Const FGInt1, FGInt2 : TFGInt; Var GCD : TFGInt); 100 | Procedure FGIntLCM(Const FGInt1, FGInt2 : TFGInt; Var LCM : TFGInt); 101 | Procedure FGIntRandom1(Var Seed, RandomFGInt : TFGInt); 102 | Procedure FGIntRabinMiller(Var FGIntp : TFGInt; nrtest : Longword; Var ok : boolean); 103 | Procedure FGIntBezoutBachet(Var FGInt1, FGInt2, a, b : TFGInt); 104 | Procedure FGIntModInv(Const FGInt1, base : TFGInt; Var Inverse : TFGInt); 105 | Procedure FGIntPrimetest(Var FGIntp : TFGInt; nrRMtests : integer; Var ok : boolean); 106 | Procedure FGIntLegendreSymbol(Var a, p : TFGInt; Var L : integer); 107 | Procedure FGIntSquareRootModP(Square, Prime : TFGInt; Var SquareRoot : TFGInt); 108 | 109 | 110 | Procedure newtonInitialValue(Const FGInt : TFGInt; Const kZero: LongWord; Var resFGInt : TFGInt); 111 | Procedure newtonInversion(Const fGInt : TFGInt; Const precision : LongWord; Var resFGInt : TFGInt); 112 | Procedure FGIntBarretDivMod(Var FGInt1, FGInt2, QFGInt, MFGInt : TFGInt); 113 | Procedure FGIntBarretMod(Var FGInt1, FGInt2, MFGInt : TFGInt); 114 | Procedure FGIntBarrettModWithInvertedDivisorAndPrecision(Const GInt, divisorFGInt, invertedDivisor : TFGInt; precision : LongWord; Var modFGInt : TFGInt); 115 | // Procedure FGIntBarrettModWithInvertedDivisorAndPrecisionBis(Const fGInt, divisorFGInt, invertedDivisor : TFGInt; precision : LongWord; Var modFGInt : TFGInt); 116 | Procedure FGIntBarretModExp(Var FGInt, exp, modFGInt, res : TFGInt); 117 | 118 | 119 | 120 | Implementation 121 | 122 | Var 123 | primes : Array[1..1228] Of integer = 124 | (3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 125 | 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 126 | 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 127 | 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 128 | 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 129 | 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 130 | 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 131 | 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 132 | 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 133 | 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 134 | 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 135 | 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 136 | 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 137 | 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 138 | 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 139 | 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 140 | 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 141 | 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 142 | 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 143 | 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 144 | 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 145 | 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 146 | 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 147 | 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 148 | 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 149 | 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 150 | 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 151 | 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 152 | 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 153 | 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 154 | 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 155 | 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 156 | 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 157 | 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 158 | 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 159 | 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 160 | 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 161 | 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 162 | 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 163 | 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 164 | 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 165 | 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 166 | 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 167 | 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 168 | 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 169 | 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 170 | 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 171 | 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 172 | 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 173 | 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 174 | 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 175 | 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 176 | 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 177 | 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 178 | 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 179 | 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 180 | 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 181 | 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 182 | 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 183 | 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 184 | 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 185 | 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 186 | 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973); 187 | chr64 : Array[1..64] Of char = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 188 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 189 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 190 | 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'); 191 | karatsubaThreshold : Longword = 90; 192 | karatsubaSquaringThreshold : Longword = 175; 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | // Destroy a FGInt to free memory 205 | 206 | Procedure FGIntDestroy(Var FGInt : TFGInt); 207 | Begin 208 | FGInt.Number := Nil; 209 | End; 210 | 211 | 212 | // Returns the FGInt in absolute value 213 | 214 | Procedure FGIntAbs(Var FGInt : TFGInt); 215 | Begin 216 | FGInt.Sign := positive; 217 | End; 218 | 219 | 220 | // Copy a FGInt1 into FGInt2 221 | 222 | Procedure FGIntCopy(Const FGInt1 : TFGInt; Var FGInt2 : TFGInt); 223 | Begin 224 | FGInt2.Sign := FGInt1.Sign; 225 | FGInt2.Number := Nil; 226 | FGInt2.Number := Copy(FGInt1.Number, 0, FGInt1.Number[0] + 1); 227 | End; 228 | 229 | 230 | // Compare 2 FGInts in absolute value, returns 231 | // Lt if FGInt1 > FGInt2, St if FGInt1 < FGInt2, Eq if FGInt1 = FGInt2, 232 | // Er otherwise 233 | 234 | Function FGIntCompareAbs(Const FGInt1, FGInt2 : TFGInt) : TCompare; 235 | Var 236 | size1, size2, i : LongWord; 237 | Begin 238 | FGIntCompareAbs := Er; 239 | size1 := FGInt1.Number[0]; 240 | size2 := FGInt2.Number[0]; 241 | If size1 > size2 Then FGIntCompareAbs := Lt Else 242 | If size1 < size2 Then FGIntCompareAbs := St Else 243 | Begin 244 | i := size2; 245 | While (FGInt1.Number[i] = FGInt2.Number[i]) And (i > 1) Do i := i - 1; 246 | If FGInt1.Number[i] = FGInt2.Number[i] Then FGIntCompareAbs := Eq Else 247 | If FGInt1.Number[i] < FGInt2.Number[i] Then FGIntCompareAbs := St Else 248 | If FGInt1.Number[i] > FGInt2.Number[i] Then FGIntCompareAbs := Lt; 249 | End; 250 | End; 251 | 252 | 253 | // Shift the FGInt to the left in base 2 notation, ie FGInt = FGInt * 2 254 | 255 | Procedure FGIntShiftLeft(Var FGInt : TFGInt); 256 | Var 257 | i, size : LongWord; 258 | m, l: uint64; 259 | Begin 260 | size := FGInt.Number[0]; 261 | l := 0; 262 | For i := 1 To Size Do 263 | Begin 264 | m := FGInt.Number[i]; 265 | FGInt.Number[i] := ((m Shl 1) Or l) And 4294967295; 266 | l := m shr 31; 267 | End; 268 | If l <> 0 Then 269 | Begin 270 | setlength(FGInt.Number, size + 2); 271 | FGInt.Number[size + 1] := l; 272 | FGInt.Number[0] := size + 1; 273 | End; 274 | End; 275 | 276 | 277 | // FGInt = FGInt * 4294967296 278 | 279 | Procedure FGIntShiftLeftBy32(Var FGInt : TFGInt); 280 | Var 281 | f1, f2 : LongWord; 282 | i, size : longint; 283 | Begin 284 | if ((FGInt.Number[0] = 1) and (FGInt.Number[1] = 0)) then Exit; 285 | size := FGInt.Number[0]; 286 | SetLength(FGInt.Number, size + 2); 287 | f1 := 0; 288 | For i := 1 To (size + 1) Do 289 | Begin 290 | f2 := FGInt.Number[i]; 291 | FGInt.Number[i] := f1; 292 | f1 := f2; 293 | End; 294 | FGInt.Number[0] := size + 1; 295 | End; 296 | 297 | 298 | // Shift the FGInt to the right in base 2 notation, ie FGInt = FGInt div 2 299 | 300 | Procedure FGIntShiftRight(Var FGInt : TFGInt); 301 | Var 302 | l, m, i, size : LongWord; 303 | Begin 304 | size := FGInt.Number[0]; 305 | l := 0; 306 | For i := size Downto 1 Do 307 | Begin 308 | m := FGInt.Number[i] And 1; 309 | FGInt.Number[i] := (FGInt.Number[i] Shr 1) Or l; 310 | l := m Shl 31; 311 | End; 312 | If (FGInt.Number[size] = 0) And (size > 1) Then 313 | Begin 314 | setlength(FGInt.Number, size); 315 | FGInt.Number[0] := size - 1; 316 | End; 317 | End; 318 | 319 | 320 | // FGInt = FGInt / 4294967296 321 | 322 | Procedure FGIntShiftRightBy32(Var FGInt : TFGInt); 323 | Var 324 | size, i : LongWord; 325 | Begin 326 | size := FGInt.Number[0]; 327 | If size > 1 Then 328 | Begin 329 | For i := 1 To size - 1 Do 330 | Begin 331 | FGInt.Number[i] := FGInt.Number[i + 1]; 332 | End; 333 | SetLength(FGInt.Number, Size); 334 | FGInt.Number[0] := size - 1; 335 | End 336 | Else 337 | FGInt.Number[1] := 0; 338 | End; 339 | 340 | 341 | Procedure FGIntShiftLeftBy32Times(Var FGInt : TFGInt; times : LongWord); 342 | Var 343 | i, size : longint; 344 | Begin 345 | if times = 0 then Exit; 346 | if not ((FGInt.Number[0] = 1) and (FGInt.Number[1] = 0)) then 347 | begin 348 | size := FGInt.Number[0]; 349 | SetLength(FGInt.Number, size + 1 + times); 350 | For i := size Downto 1 Do 351 | Begin 352 | FGInt.Number[i + times] := FGInt.Number[i]; 353 | End; 354 | For i := 1 To times Do 355 | Begin 356 | FGInt.Number[i] := 0; 357 | End; 358 | FGInt.Number[0] := size + times; 359 | end; 360 | End; 361 | 362 | Procedure FGIntShiftRightBy32Times(Var FGInt : TFGInt; times : LongWord); 363 | Var 364 | i, size : longint; 365 | Begin 366 | if times = 0 then Exit; 367 | size := FGInt.Number[0]; 368 | if times >= size then 369 | begin 370 | SetLength(FGInt.Number, 2); 371 | FGInt.Number[0] := 1; 372 | FGInt.Number[1] := 0; 373 | end 374 | else if not ((FGInt.Number[0] = 1) and (FGInt.Number[1] = 0)) then 375 | begin 376 | For i := 1 to (size - times) Do 377 | Begin 378 | FGInt.Number[i] := FGInt.Number[i + times]; 379 | End; 380 | FGInt.Number[0] := size - times; 381 | SetLength(FGInt.Number, size + 1 - times); 382 | end; 383 | End; 384 | 385 | 386 | Procedure FGIntShiftLeftBy(Var FGInt : TFGInt; by : LongWord); 387 | Var 388 | i, size, m32Shift : LongWord; 389 | Begin 390 | if by = 0 then Exit; 391 | 392 | m32Shift := by mod 32; 393 | size := FGInt.Number[0]; 394 | if (not ((size = 1) and (FGInt.Number[1] = 0))) and (m32Shift <> 0) then 395 | begin 396 | if ((FGInt.Number[size] shr (32 - m32Shift)) > 0) then 397 | begin 398 | SetLength(FGInt.Number, size + 2); 399 | FGInt.Number[0] := size + 1; 400 | FGInt.Number[size + 1] := 0; 401 | size := size + 1; 402 | end; 403 | For i := size - 1 Downto 1 Do 404 | Begin 405 | FGInt.Number[i + 1] := (FGInt.Number[i + 1] shl m32Shift) or (FGInt.Number[i] shr (32 - m32Shift)); 406 | End; 407 | FGInt.Number[1] := (FGInt.Number[1] shl m32Shift); 408 | end; 409 | if (by div 32) > 0 then 410 | FGIntShiftLeftBy32Times(FGInt, by div 32); 411 | End; 412 | 413 | Procedure FGIntShiftRightBy(Var FGInt : TFGInt; by : LongWord); 414 | Var 415 | i, size, shift : LongWord; 416 | Begin 417 | if by = 0 then Exit; 418 | if (by div 32) > 0 then 419 | FGIntShiftRightBy32Times(FGInt, by div 32); 420 | shift := by mod 32; 421 | size := FGInt.Number[0]; 422 | if (not ((FGInt.Number[0] = 1) and (FGInt.Number[1] = 0))) and (shift > 0) then 423 | begin 424 | For i := 1 to size - 1 Do 425 | Begin 426 | FGInt.Number[i] := (FGInt.Number[i] shr shift) or (FGInt.Number[i + 1] shl (32 - shift)); 427 | End; 428 | FGInt.Number[size] := (FGInt.Number[size] shr shift); 429 | if FGInt.Number[size] = 0 then 430 | begin 431 | SetLength(FGInt.Number, size); 432 | FGInt.Number[0] := size - 1; 433 | end; 434 | end; 435 | 436 | End; 437 | 438 | 439 | 440 | 441 | 442 | 443 | // Convert a FGInt to a binary string (base 2) & visa versa 444 | 445 | Procedure FGIntToBase2String(Const FGInt : TFGInt; Var S : String); 446 | Var 447 | i : LongWord; 448 | j : integer; 449 | Begin 450 | S := ''; 451 | For i := 1 To FGInt.Number[0] Do 452 | Begin 453 | For j := 0 To 31 Do 454 | If (1 And (FGInt.Number[i] Shr j)) = 1 Then 455 | S := '1' + S 456 | Else 457 | S := '0' + S; 458 | End; 459 | While (length(S) > 1) And (S[1] = '0') Do 460 | delete(S, 1, 1); 461 | If S = '' Then S := '0'; 462 | End; 463 | 464 | 465 | Procedure Base2StringToFGInt(S : String; Var FGInt : TFGInt); 466 | Var 467 | i, j, size : LongWord; 468 | Begin 469 | While (S[1] = '0') And (length(S) > 1) Do 470 | delete(S, 1, 1); 471 | size := length(S) Div 32; 472 | If (length(S) Mod 32) <> 0 Then size := size + 1; 473 | SetLength(FGInt.Number, (size + 1)); 474 | FGInt.Number[0] := size; 475 | j := 1; 476 | FGInt.Number[j] := 0; 477 | i := 0; 478 | While length(S) > 0 Do 479 | Begin 480 | If S[length(S)] = '1' Then 481 | FGInt.Number[j] := FGInt.Number[j] Or (1 Shl i); 482 | i := i + 1; 483 | If i = 32 Then 484 | Begin 485 | i := 0; 486 | j := j + 1; 487 | If j <= size Then FGInt.Number[j] := 0; 488 | End; 489 | delete(S, length(S), 1); 490 | End; 491 | FGInt.Sign := positive; 492 | End; 493 | 494 | 495 | 496 | // Convert a base 10 string to a FGInt 497 | 498 | Procedure Base10StringToFGInt(Base10 : String; Var FGInt : TFGInt); 499 | Var 500 | i, size : LongWord; 501 | j : word; 502 | S, x : String; 503 | sign : TSign; 504 | 505 | Procedure FGIntDivByIntBis1(Var GInt : TFGInt; by : LongWord; Var modres : word); 506 | Var 507 | i, size, rest, temp : LongWord; 508 | Begin 509 | size := GInt.Number[0]; 510 | temp := 0; 511 | For i := size Downto 1 Do 512 | Begin 513 | temp := temp * 10000; 514 | rest := temp + GInt.Number[i]; 515 | GInt.Number[i] := rest Div by; 516 | temp := rest Mod by; 517 | End; 518 | modres := temp; 519 | While (GInt.Number[size] = 0) And (size > 1) Do 520 | size := size - 1; 521 | If size <> GInt.Number[0] Then 522 | Begin 523 | SetLength(GInt.Number, size + 1); 524 | GInt.Number[0] := size; 525 | End; 526 | End; 527 | 528 | Begin 529 | While (Not (Base10[1] In ['-', '0'..'9'])) And (length(Base10) > 1) Do 530 | delete(Base10, 1, 1); 531 | If copy(Base10, 1, 1) = '-' Then 532 | Begin 533 | Sign := negative; 534 | delete(Base10, 1, 1); 535 | End 536 | Else 537 | Sign := positive; 538 | While (length(Base10) > 1) And (copy(Base10, 1, 1) = '0') Do 539 | delete(Base10, 1, 1); 540 | size := length(Base10) Div 4; 541 | If (length(Base10) Mod 4) <> 0 Then size := size + 1; 542 | SetLength(FGInt.Number, size + 1); 543 | FGInt.Number[0] := size; 544 | For i := 1 To (size - 1) Do 545 | Begin 546 | x := copy(Base10, length(Base10) - 3, 4); 547 | FGInt.Number[i] := StrToInt(x); 548 | delete(Base10, length(Base10) - 3, 4); 549 | End; 550 | FGInt.Number[size] := StrToInt(Base10); 551 | 552 | S := ''; 553 | While (FGInt.Number[0] <> 1) Or (FGInt.Number[1] <> 0) Do 554 | Begin 555 | FGIntDivByIntBis1(FGInt, 2, j); 556 | S := inttostr(j) + S; 557 | End; 558 | If S = '' Then S := '0'; 559 | FGIntDestroy(FGInt); 560 | Base2StringToFGInt(S, FGInt); 561 | FGInt.Sign := sign; 562 | End; 563 | 564 | 565 | // Convert a FGInt to a base 10 string 566 | 567 | Procedure FGIntToBase10String(Const FGInt : TFGInt; Var Base10 : String); 568 | Var 569 | S : String; 570 | j : LongWord; 571 | temp : TFGInt; 572 | Begin 573 | FGIntCopy(FGInt, temp); 574 | Base10 := ''; 575 | While not ((temp.Number[0] = 1) and (temp.Number[1] = 0)) Do 576 | Begin 577 | FGIntDivByIntBis(temp, 10000, j); 578 | S := IntToStr(j); 579 | While Length(S) < 4 Do 580 | begin 581 | S := '0' + S; 582 | end; 583 | Base10 := S + Base10; 584 | End; 585 | Base10 := '0' + Base10; 586 | While (length(Base10) > 1) And (Base10[1] = '0') Do 587 | delete(Base10, 1, 1); 588 | If FGInt.Sign = negative Then Base10 := '-' + Base10; 589 | End; 590 | 591 | 592 | 593 | // Convert a FGInt to an base 256 string & visa versa 594 | 595 | Procedure FGIntToBase256String(Const FGInt : TFGInt; Var str256 : String); 596 | Var 597 | i, j : LongWord; 598 | b : byte; 599 | Begin 600 | str256 := ''; 601 | For i := 1 To FGInt.Number[0] Do 602 | Begin 603 | for j := 0 to 3 do 604 | begin 605 | b := (FGInt.Number[i] shr (j * 8)) and 255; 606 | str256 := chr(b) + str256; 607 | end; 608 | End; 609 | End; 610 | 611 | 612 | Procedure Base256StringToFGInt(str256 : String; Var FGInt : TFGInt); 613 | Var 614 | temp : String; 615 | i, l, j : LongWord; 616 | Begin 617 | temp := str256; 618 | while (length(temp) > 4) and (temp[1] = chr(0)) do delete(temp, 1, 1); 619 | while length(temp) mod 4 <> 0 do temp := chr(0) + temp; 620 | l := length(temp) div 4; 621 | FGInt.sign := positive; 622 | setLength(FGInt.Number, l + 1); 623 | FGInt.Number[0] := l; 624 | For i := 1 To l Do 625 | begin 626 | j := 4 * (i - 1); 627 | FGInt.Number[l - i + 1] := ord(temp[j + 1]); 628 | FGInt.Number[l - i + 1] := (FGInt.Number[l - i + 1] shl 8) or ord(temp[j + 2]); 629 | FGInt.Number[l - i + 1] := (FGInt.Number[l - i + 1] shl 8) or ord(temp[j + 3]); 630 | FGInt.Number[l - i + 1] := (FGInt.Number[l - i + 1] shl 8) or ord(temp[j + 4]); 631 | end; 632 | End; 633 | 634 | 635 | // Convert base 256 strings to base 16 (HexaDecimal) strings and visa versa 636 | 637 | Procedure ConvertBase256StringToHexString(Str256 : String; Var HexStr : String); 638 | Var 639 | i : longint; 640 | b : byte; 641 | Begin 642 | HexStr := ''; 643 | For i := 1 To length(str256) Do 644 | Begin 645 | b := ord(str256[i]); 646 | If (b Shr 4) < 10 Then HexStr := HexStr + chr(48 + (b Shr 4)) 647 | Else HexStr := HexStr + chr(55 + (b Shr 4)); 648 | If (b And 15) < 10 Then HexStr := HexStr + chr(48 + (b And 15)) 649 | Else HexStr := HexStr + chr(55 + (b And 15)); 650 | End; 651 | End; 652 | 653 | 654 | Procedure ConvertHexStringToBase256String(HexStr : String; Var Str256 : String); 655 | Var 656 | i : longint; 657 | b, h1, h2 : byte; 658 | temp : string; 659 | Begin 660 | Str256 := ''; 661 | If (length(Hexstr) mod 2) = 1 Then temp := '0' + HexStr Else temp := HexStr; 662 | For i := 1 To (length(temp) Div 2) Do 663 | Begin 664 | h2 := ord(temp[2 * i]); 665 | h1 := ord(temp[2 * i - 1]); 666 | If h1 < 58 Then 667 | b := ((h1 - 48) Shl 4) 668 | Else 669 | b := ((h1 - 55) Shl 4); 670 | If h2 < 58 Then 671 | b := (b Or (h2 - 48)) 672 | Else 673 | b := (b Or ((h2 - 55) and 15)); 674 | Str256 := Str256 + chr(b); 675 | End; 676 | End; 677 | 678 | 679 | // Convert an MPI (Multiple Precision Integer, PGP style) to an FGInt & 680 | // visa versa 681 | 682 | Procedure PGPMPIToFGInt(PGPMPI : String; Var FGInt : TFGInt); 683 | Var 684 | temp : String; 685 | Begin 686 | temp := PGPMPI; 687 | delete(temp, 1, 2); 688 | Base256StringToFGInt(temp, FGInt); 689 | End; 690 | 691 | 692 | Procedure FGIntToPGPMPI(FGInt : TFGInt; Var PGPMPI : String); 693 | Var 694 | len, i : word; 695 | c : char; 696 | b : byte; 697 | Begin 698 | FGIntToBase256String(FGInt, PGPMPI); 699 | len := length(PGPMPI) * 8; 700 | c := PGPMPI[1]; 701 | For i := 7 Downto 0 Do If (ord(c) Shr i) = 0 Then len := len - 1 Else break; 702 | b := len Mod 256; 703 | PGPMPI := chr(b) + PGPMPI; 704 | b := len Div 256; 705 | PGPMPI := chr(b) + PGPMPI; 706 | End; 707 | 708 | // divide a FGInt by an integer, FGInt = FGInt * by + modres 709 | 710 | Procedure FGIntDivByIntBis(Var FGInt : TFGInt; by : LongWord; Var modres : LongWord); 711 | Var 712 | i, size : LongWord; 713 | temp, rest : uint64; 714 | Begin 715 | size := FGInt.Number[0]; 716 | temp := 0; 717 | For i := size Downto 1 Do 718 | Begin 719 | temp := temp Shl 32; 720 | rest := temp Or FGInt.Number[i]; 721 | FGInt.Number[i] := rest Div by; 722 | temp := rest Mod by; 723 | End; 724 | modres := temp; 725 | While (FGInt.Number[size] = 0) And (size > 1) Do 726 | size := size - 1; 727 | If size <> FGInt.Number[0] Then 728 | Begin 729 | SetLength(FGInt.Number, size + 1); 730 | FGInt.Number[0] := size; 731 | End; 732 | End; 733 | 734 | 735 | 736 | // Add 2 FGInts, FGInt1 + FGInt2 = Sum 737 | 738 | Procedure FGIntAdd(Const FGInt1, FGInt2 : TFGInt; Var Sum : TFGInt); 739 | Var 740 | i, size1, size2, size, rest : LongWord; 741 | Trest : int64; 742 | Begin 743 | size1 := FGInt1.Number[0]; 744 | size2 := FGInt2.Number[0]; 745 | If size1 < size2 Then 746 | FGIntAdd(FGInt2, FGInt1, Sum) 747 | Else 748 | Begin 749 | If FGInt1.Sign = FGInt2.Sign Then 750 | Begin 751 | Sum.Sign := FGInt1.Sign; 752 | setlength(Sum.Number, (size1 + 2)); 753 | rest := 0; 754 | For i := 1 To size2 Do 755 | Begin 756 | Trest := FGInt1.Number[i]; 757 | Trest := Trest + FGInt2.Number[i]; 758 | Trest := Trest + rest; 759 | Sum.Number[i] := Trest And 4294967295; 760 | rest := Trest Shr 32; 761 | End; 762 | For i := (size2 + 1) To size1 Do 763 | Begin 764 | Trest := FGInt1.Number[i] + rest; 765 | Sum.Number[i] := Trest And 4294967295; 766 | rest := Trest Shr 32; 767 | End; 768 | size := size1 + 1; 769 | Sum.Number[0] := size; 770 | Sum.Number[size] := rest; 771 | While (Sum.Number[size] = 0) And (size > 1) Do 772 | size := size - 1; 773 | If Sum.Number[0] <> size Then SetLength(Sum.Number, size + 1); 774 | Sum.Number[0] := size; 775 | End 776 | Else 777 | Begin 778 | If FGIntCompareAbs(FGInt2, FGInt1) = Lt Then 779 | FGIntAdd(FGInt2, FGInt1, Sum) 780 | Else 781 | Begin 782 | SetLength(Sum.Number, (size1 + 1)); 783 | rest := 0; 784 | For i := 1 To size2 Do 785 | Begin 786 | Trest := 4294967296; 787 | TRest := Trest + FGInt1.Number[i]; 788 | TRest := Trest - FGInt2.Number[i]; 789 | TRest := Trest - rest; 790 | Sum.Number[i] := Trest And 4294967295; 791 | If (Trest > 4294967295) Then 792 | rest := 0 793 | Else 794 | rest := 1; 795 | End; 796 | For i := (size2 + 1) To size1 Do 797 | Begin 798 | Trest := 4294967296; 799 | TRest := Trest + FGInt1.Number[i]; 800 | TRest := Trest - rest; 801 | Sum.Number[i] := Trest And 4294967295; 802 | If (Trest > 4294967295) Then 803 | rest := 0 804 | Else 805 | rest := 1; 806 | End; 807 | size := size1; 808 | While (Sum.Number[size] = 0) And (size > 1) Do 809 | size := size - 1; 810 | If size <> size1 Then SetLength(Sum.Number, size + 1); 811 | Sum.Number[0] := size; 812 | Sum.Sign := FGInt1.Sign; 813 | End; 814 | End; 815 | End; 816 | End; 817 | 818 | 819 | 820 | Procedure FGIntChangeSign(Var FGInt : TFGInt); 821 | Begin 822 | If FGInt.Sign = negative Then FGInt.Sign := positive Else FGInt.Sign := negative; 823 | End; 824 | 825 | 826 | // Substract 2 FGInts, FGInt1 - FGInt2 = dif 827 | 828 | Procedure FGIntSub(Const FGInt1 : TFGInt; Var FGInt2, dif : TFGInt); 829 | Begin 830 | FGIntChangeSign(FGInt2); 831 | FGIntAdd(FGInt1, FGInt2, dif); 832 | FGIntChangeSign(FGInt2); 833 | End; 834 | 835 | 836 | Procedure FGIntAddBis(Var FGInt1 : TFGInt; Const FGInt2 : TFGInt); 837 | Var 838 | i, size1, size2, rest, minLength, maxLength : LongWord; 839 | Trest : int64; 840 | tmpFGInt1, tmpFGInt2 : TFGInt; 841 | Begin 842 | size1 := FGInt1.Number[0]; 843 | size2 := FGInt2.Number[0]; 844 | if size1 < size2 then 845 | begin 846 | minLength := size1; 847 | maxLength := size2; 848 | FGIntCopy(FGInt2, tmpFGInt1); 849 | tmpFGInt2 := FGInt1; 850 | end else 851 | begin 852 | minLength := size2; 853 | maxLength := size1; 854 | tmpFGInt2 := FGInt2; 855 | tmpFGInt1 := FGInt1; 856 | end; 857 | rest := 0; 858 | // if size1 < size2 then writeln('uh-ohhhh add '+IntToStr(size1) + ' ' + inttostr(size2) + ' hahaha fys: ' + inttostr(FGInt1.Number[1])); 859 | For i := 1 To minLength Do 860 | Begin 861 | Trest := tmpFGInt1.Number[i]; 862 | Trest := Trest + tmpFGInt2.Number[i] + rest; 863 | rest := Trest Shr 32; 864 | tmpFGInt1.Number[i] := Trest And 4294967295; 865 | End; 866 | For i := minLength + 1 To maxLength Do 867 | Begin 868 | if rest = 0 then break; 869 | Trest := tmpFGInt1.Number[i]; 870 | Trest := Trest + rest; 871 | rest := Trest Shr 32; 872 | tmpFGInt1.Number[i] := Trest And 4294967295; 873 | End; 874 | If rest <> 0 Then 875 | Begin 876 | SetLength(tmpFGInt1.Number, maxLength + 2); 877 | tmpFGInt1.Number[0] := maxLength + 1; 878 | tmpFGInt1.Number[maxLength + 1] := rest; 879 | End; 880 | If size1 < maxLength then 881 | begin 882 | FGIntDestroy(FGInt1); 883 | end; 884 | FGInt1 := tmpFGInt1; 885 | End; 886 | 887 | 888 | // FGInt1 = FGInt1 - FGInt2, use only when 0 < FGInt2 < FGInt1 889 | 890 | Procedure FGIntSubBis(Var FGInt1 : TFGInt; Const FGInt2 : TFGInt); 891 | Var 892 | i, size1, size2, rest : LongWord; 893 | Trest : int64; 894 | Begin 895 | size1 := FGInt1.Number[0]; 896 | size2 := FGInt2.Number[0]; 897 | // if size1 < size2 then writeln('uh-ohhhh '+IntToStr(size1) + ' ' + inttostr(size2) + ' hahaha fys: ' + inttostr(FGInt1.Number[1])); 898 | rest := 0; 899 | For i := 1 To size2 Do 900 | Begin 901 | Trest := (4294967296 Or FGInt1.Number[i]) - FGInt2.Number[i] - rest; 902 | If (Trest > 4294967295) Then 903 | rest := 0 904 | Else 905 | rest := 1; 906 | FGInt1.Number[i] := Trest And 4294967295; 907 | End; 908 | For i := size2 + 1 To size1 Do 909 | Begin 910 | Trest := (4294967296 Or FGInt1.Number[i]) - rest; 911 | If (Trest > 4294967295) Then 912 | rest := 0 913 | Else 914 | rest := 1; 915 | FGInt1.Number[i] := Trest And 4294967295; 916 | End; 917 | i := size1; 918 | While (FGInt1.Number[i] = 0) And (i > 1) Do 919 | i := i - 1; 920 | If i <> size1 Then 921 | Begin 922 | SetLength(FGInt1.Number, i + 1); 923 | FGInt1.Number[0] := i; 924 | End; 925 | End; 926 | 927 | 928 | 929 | // Multiply 2 FGInts with the pencil-and-paper method 930 | 931 | Procedure FGIntPencilPaperMultiply(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt); 932 | Var 933 | i, j, size, size1, size2, rest : LongWord; 934 | Trest : uint64; 935 | Begin 936 | size1 := FGInt1.Number[0]; 937 | size2 := FGInt2.Number[0]; 938 | size := size1 + size2; 939 | SetLength(Prod.Number, (size + 1)); 940 | For i := 1 To size Do 941 | Prod.Number[i] := 0; 942 | 943 | For i := 1 To size2 Do 944 | Begin 945 | rest := 0; 946 | For j := 1 To size1 Do 947 | Begin 948 | Trest := FGInt1.Number[j]; 949 | Trest := Trest * FGInt2.Number[i]; 950 | Trest := Trest + Prod.Number[j + i - 1]; 951 | Trest := Trest + rest; 952 | Prod.Number[j + i - 1] := Trest; 953 | rest := Trest Shr 32; 954 | End; 955 | Prod.Number[i + size1] := rest; 956 | End; 957 | 958 | Prod.Number[0] := size; 959 | While (Prod.Number[size] = 0) And (size > 1) Do 960 | size := size - 1; 961 | If size <> Prod.Number[0] Then 962 | Begin 963 | SetLength(Prod.Number, size + 1); 964 | Prod.Number[0] := size; 965 | End; 966 | If FGInt1.Sign = FGInt2.Sign Then 967 | Prod.Sign := Positive 968 | Else 969 | prod.Sign := negative; 970 | End; 971 | 972 | 973 | // Procedure FGIntKaratsubaMultiply(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt; Const karatsubaThreshold : LongWord); 974 | 975 | Procedure FGIntKaratsubaMultiply(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt); 976 | Var 977 | halfLength, size1, size2, max : LongWord; 978 | f1a, f1b, f2a, f2b, faa, fbb, fab, f1ab, f2ab, zero : TFGInt; 979 | Begin 980 | size1 := FGInt1.Number[0]; 981 | size2 := FGInt2.Number[0]; 982 | if (size1 < size2) Then max := size2 Else max := size1; 983 | if (max < karatsubaThreshold) Then 984 | Begin 985 | FGIntPencilPaperMultiply(FGInt1, FGInt2, Prod); 986 | Exit; 987 | End; 988 | 989 | if (size1 < max) Then 990 | Begin 991 | // FGIntKaratsubaMultiply(FGInt2, FGInt1, Prod, karatsubaThreshold); 992 | FGIntKaratsubaMultiply(FGInt2, FGInt1, Prod); 993 | Exit; 994 | End; 995 | 996 | halfLength := (max Div 2) + (max mod 2); 997 | f1b.Sign := FGInt1.Sign; 998 | f1a.Sign := FGInt1.Sign; 999 | f1b.Number := copy(FGInt1.Number, 0, halfLength + 1); 1000 | f1b.Number[0] := halfLength; 1001 | f1a.Number := copy(FGInt1.Number, halfLength, size1 - halfLength + 1); 1002 | f1a.Number[0] := size1 - halfLength; 1003 | 1004 | Base2StringToFGInt('0', zero); 1005 | 1006 | if (size2 <= halfLength) then 1007 | Begin 1008 | FGIntCopy(zero, f2a); 1009 | FGIntCopy(FGInt2, f2b); 1010 | End else 1011 | Begin 1012 | f2b.Sign := FGInt2.Sign; 1013 | f2a.Sign := FGInt2.Sign; 1014 | f2b.Number := copy(FGInt2.Number, 0, halfLength + 1); 1015 | f2b.Number[0] := halfLength; 1016 | f2a.Number := copy(FGInt2.Number, halfLength, size2 - halfLength + 1); 1017 | f2a.Number[0] := size2 - halfLength; 1018 | end; 1019 | 1020 | if ((FGIntCompareAbs(f1a, zero) <> Eq) and (FGIntCompareAbs(f2a, zero) <> Eq)) then 1021 | begin 1022 | FGIntKaratsubaMultiply(f1a, f2a, faa); 1023 | // FGIntKaratsubaMultiply(f1a, f2a, faa, karatsubaThreshold); 1024 | end 1025 | else 1026 | begin 1027 | FGIntCopy(zero, faa); 1028 | end; 1029 | 1030 | if ((FGIntCompareAbs(f1b, zero) <> Eq) and (FGIntCompareAbs(f2b, zero) <> Eq)) then 1031 | begin 1032 | // FGIntKaratsubaMultiply(f1b, f2b, fbb, karatsubaThreshold); 1033 | FGIntKaratsubaMultiply(f1b, f2b, fbb); 1034 | end 1035 | else 1036 | begin 1037 | FGIntCopy(zero, fbb); 1038 | end; 1039 | 1040 | 1041 | FGIntAdd(f1a, f1b, f1ab); 1042 | FGIntAdd(f2a, f2b, f2ab); 1043 | FGIntDestroy(f1a); 1044 | FGIntDestroy(f1b); 1045 | FGIntDestroy(f2a); 1046 | FGIntDestroy(f2b); 1047 | 1048 | if ((FGIntCompareAbs(f1ab, zero) <> Eq) and (FGIntCompareAbs(f2ab, zero) <> Eq)) then 1049 | begin 1050 | // FGIntKaratsubaMultiply(f1ab, f2ab, fab, karatsubaThreshold); 1051 | FGIntKaratsubaMultiply(f1ab, f2ab, fab); 1052 | end 1053 | else 1054 | begin 1055 | FGIntCopy(zero, fab); 1056 | end; 1057 | 1058 | 1059 | FGIntDestroy(zero); 1060 | FGIntDestroy(f1ab); 1061 | FGIntDestroy(f2ab); 1062 | FGIntSubBis(fab, faa); 1063 | FGIntSubBis(fab, fbb); 1064 | 1065 | 1066 | Prod := faa; 1067 | FGIntShiftLeftBy32Times(Prod, halfLength * 2); 1068 | FGIntShiftLeftBy32Times(fab, halfLength); 1069 | FGIntAddBis(prod, fab); 1070 | FGIntAddBis(prod, fbb); 1071 | 1072 | if fGInt1.sign = fGInt2.sign then Prod.sign := positive else Prod.sign := negative; 1073 | 1074 | FGIntDestroy(fab); 1075 | FGIntDestroy(fbb); 1076 | End; 1077 | 1078 | 1079 | 1080 | // Multiply 2 FGInts, FGInt1 * FGInt2 = Prod 1081 | 1082 | Procedure FGIntMul(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt); 1083 | Var 1084 | size1, size2 : LongWord; 1085 | Begin 1086 | size1 := FGInt1.Number[0]; 1087 | size2 := FGInt2.Number[0]; 1088 | if (size1 > karatsubaThreshold) or (size2 > karatsubaThreshold) then 1089 | FGIntKaratsubaMultiply(FGInt1, FGInt2, Prod) 1090 | else 1091 | FGIntPencilPaperMultiply(FGInt1, FGInt2, Prod); 1092 | End; 1093 | 1094 | 1095 | 1096 | // Square a FGInt, FGInt² = Square 1097 | 1098 | Procedure FGIntPencilPaperSquare(Const FGInt : TFGInt; Var Square : TFGInt); 1099 | Var 1100 | size, size1, i, j, k : LongWord; 1101 | Trest, overflow, rest, tmpInt : uint64; 1102 | Begin 1103 | size1 := FGInt.Number[0]; 1104 | size := 2 * size1; 1105 | SetLength(Square.Number, (size + 1)); 1106 | Square.Number[0] := size; 1107 | For i := 1 To size Do 1108 | Square.Number[i] := 0; 1109 | For i := 1 To size1 Do 1110 | Begin 1111 | tmpInt := FGInt.Number[i]; 1112 | Trest := tmpInt * tmpInt; 1113 | Trest := Trest + Square.Number[2 * i - 1]; 1114 | Square.Number[2 * i - 1] := Trest And 4294967295; 1115 | rest := Trest Shr 32; 1116 | For j := i + 1 To size1 Do 1117 | Begin 1118 | Trest := FGInt.Number[j]; 1119 | Trest := Trest * tmpInt; 1120 | if (Trest shr 63) = 1 then overflow := 1 else overflow := 0; 1121 | Trest := (Trest Shl 1) + Square.Number[i + j - 1] + rest; 1122 | Square.Number[i + j - 1] := Trest And 4294967295; 1123 | rest := (Trest Shr 32) or (overflow shl 32); 1124 | End; 1125 | k := 0; 1126 | while rest <> 0 do 1127 | begin 1128 | Trest := square.Number[i + size1 + k]; 1129 | Trest := Trest + rest; 1130 | square.Number[i + size1 + k] := Trest And 4294967295; 1131 | rest := Trest shr 32; 1132 | k := k + 1; 1133 | end; 1134 | End; 1135 | Square.Sign := positive; 1136 | While (Square.Number[size] = 0) And (size > 1) Do 1137 | size := size - 1; 1138 | If size <> (2 * size1) Then 1139 | Begin 1140 | SetLength(Square.Number, size + 1); 1141 | Square.Number[0] := size; 1142 | End; 1143 | End; 1144 | 1145 | 1146 | Procedure FGIntKaratsubaSquare(Const FGInt : TFGInt; Var Square : TFGInt); 1147 | // Procedure FGIntKaratsubaSquare(Const FGInt : TFGInt; Var Square : TFGInt; Const karatsubaThreshold : LongWord); 1148 | Var 1149 | fa, fb, faa, fbb, fab, zero : TFGInt; 1150 | halfLength, size, i : LongWord; 1151 | Begin 1152 | size := FGInt.Number[0]; 1153 | if (size < karatsubaSquaringThreshold) Then 1154 | Begin 1155 | FGIntPencilPaperSquare(FGInt, Square); 1156 | Exit; 1157 | End; 1158 | 1159 | halfLength := (size Div 2) + (size mod 2); 1160 | fa.Sign := positive; 1161 | fb.Sign := positive; 1162 | fb.Number := copy(FGInt.Number, 0, halfLength + 1); 1163 | fb.Number[0] := halfLength; 1164 | fa.Number := copy(FGInt.Number, halfLength, size - halfLength + 1); 1165 | fa.Number[0] := size - halfLength; 1166 | Base2StringToFGInt('0', zero); 1167 | 1168 | i := halfLength; 1169 | while (fa.Number[i] = 0) and (i > 1) do i := i - 1; 1170 | if i <> halfLength then 1171 | begin 1172 | setlength(fa.Number, i + 1); 1173 | fa.Number[0] := i; 1174 | end; 1175 | 1176 | 1177 | 1178 | if (FGIntCompareAbs(fa, zero) <> Eq) then 1179 | begin 1180 | FGIntKaratsubaSquare(fa, faa); 1181 | // FGIntKaratsubaSquare(fa, faa, karatsubaThreshold); 1182 | end 1183 | else 1184 | begin 1185 | FGIntCopy(zero, faa); 1186 | end; 1187 | 1188 | if (FGIntCompareAbs(fb, zero) <> Eq) then 1189 | begin 1190 | FGIntKaratsubaSquare(fb, fbb); 1191 | // FGIntKaratsubaSquare(fb, fbb, karatsubaThreshold); 1192 | end 1193 | else 1194 | begin 1195 | FGIntCopy(zero, fbb); 1196 | end; 1197 | 1198 | 1199 | FGIntAddBis(fa, fb); 1200 | if (FGIntCompareAbs(fa, zero) <> Eq) then 1201 | begin 1202 | FGIntKaratsubaSquare(fa, fab); 1203 | // FGIntKaratsubaSquare(fa, fab, karatsubaThreshold); 1204 | end 1205 | else 1206 | begin 1207 | FGIntCopy(zero, fab); 1208 | end; 1209 | 1210 | 1211 | FGIntSubBis(fab, faa); 1212 | FGIntSubBis(fab, fbb); 1213 | Square := faa; 1214 | FGIntShiftLeftBy32Times(square, halfLength * 2); 1215 | FGIntShiftLeftBy32Times(fab, halfLength); 1216 | FGIntAddBis(square, fab); 1217 | FGIntAddBis(square, fbb); 1218 | 1219 | FGIntDestroy(fa); 1220 | FGIntDestroy(fb); 1221 | FGIntDestroy(faa); 1222 | FGIntDestroy(fbb); 1223 | FGIntDestroy(zero); 1224 | FGIntDestroy(fab); 1225 | End; 1226 | 1227 | 1228 | 1229 | Procedure FGIntSquare(Const FGInt : TFGInt; Var Square : TFGInt); 1230 | Var 1231 | size : LongWord; 1232 | Begin 1233 | size := FGInt.Number[0]; 1234 | if (size > karatsubaSquaringThreshold) then 1235 | FGIntKaratsubaSquare(FGInt, square) 1236 | else 1237 | FGIntPencilPaperSquare(FGInt, square); 1238 | End; 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | // multiply a FGInt by an integer, FGInt * by = res, by < 2147483648 1257 | 1258 | Procedure FGIntMulByInt(Const FGInt : TFGInt; Var res : TFGInt; by : LongWord); 1259 | Var 1260 | i, size, rest : LongWord; 1261 | Trest : uint64; 1262 | Begin 1263 | size := FGInt.Number[0]; 1264 | setlength(res.Number, (size + 2)); 1265 | rest := 0; 1266 | For i := 1 To size Do 1267 | Begin 1268 | Trest := FGInt.Number[i]; 1269 | TRest := Trest * by; 1270 | TRest := Trest + rest; 1271 | res.Number[i] := Trest And 4294967295; 1272 | rest := Trest Shr 32; 1273 | End; 1274 | If rest <> 0 Then 1275 | Begin 1276 | size := size + 1; 1277 | Res.Number[size] := rest; 1278 | End 1279 | Else 1280 | SetLength(Res.Number, size + 1); 1281 | Res.Number[0] := size; 1282 | Res.Sign := FGInt.Sign; 1283 | End; 1284 | 1285 | 1286 | // multiply a FGInt by an integer, FGInt * by = res, by < 1000000000 1287 | 1288 | Procedure FGIntMulByIntbis(Var FGInt : TFGInt; by : LongWord); 1289 | Var 1290 | i, size, rest : LongWord; 1291 | Trest : uint64; 1292 | Begin 1293 | size := FGInt.Number[0]; 1294 | Setlength(FGInt.Number, size + 2); 1295 | rest := 0; 1296 | For i := 1 To size Do 1297 | Begin 1298 | Trest := FGInt.Number[i]; 1299 | TRest := Trest * by; 1300 | TRest := Trest + rest; 1301 | FGInt.Number[i] := Trest And 4294967295; 1302 | rest := Trest Shr 32; 1303 | End; 1304 | If rest <> 0 Then 1305 | Begin 1306 | size := size + 1; 1307 | FGInt.Number[size] := rest; 1308 | End 1309 | Else 1310 | SetLength(FGInt.Number, size + 1); 1311 | FGInt.Number[0] := size; 1312 | End; 1313 | 1314 | 1315 | // divide a FGInt by an integer, FGInt = res * by + modres 1316 | 1317 | Procedure FGIntDivByInt(Const FGInt : TFGInt; Var res : TFGInt; by : LongWord; Var modres : LongWord); 1318 | Var 1319 | i, size : LongWord; 1320 | rest : uint64; 1321 | Begin 1322 | size := FGInt.Number[0]; 1323 | setlength(res.Number, (size + 1)); 1324 | modres := 0; 1325 | For i := size Downto 1 Do 1326 | Begin 1327 | rest := modres; 1328 | rest := rest Shl 32; 1329 | rest := rest Or FGInt.Number[i]; 1330 | res.Number[i] := rest Div by; 1331 | modres := rest Mod by; 1332 | End; 1333 | While (res.Number[size] = 0) And (size > 1) Do 1334 | size := size - 1; 1335 | If size <> FGInt.Number[0] Then SetLength(res.Number, size + 1); 1336 | res.Number[0] := size; 1337 | Res.Sign := FGInt.Sign; 1338 | If FGInt.sign = negative Then modres := by - modres; 1339 | End; 1340 | 1341 | 1342 | 1343 | // Reduce a FGInt modulo by (=an integer), FGInt mod by = modres 1344 | 1345 | Procedure FGIntModByInt(Const FGInt : TFGInt; by : LongWord; Var modres : LongWord); 1346 | Var 1347 | i, size : LongWord; 1348 | temp, rest : uint64; 1349 | Begin 1350 | size := FGInt.Number[0]; 1351 | temp := 0; 1352 | For i := size Downto 1 Do 1353 | Begin 1354 | temp := temp Shl 32; 1355 | rest := temp Or FGInt.Number[i]; 1356 | temp := rest Mod by; 1357 | End; 1358 | modres := temp; 1359 | If FGInt.sign = negative Then modres := by - modres; 1360 | End; 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | // Exponentiate a FGInt, FGInt^exp = res 1372 | 1373 | Procedure FGIntExp(Const FGInt, exp : TFGInt; Var res : TFGInt); 1374 | Var 1375 | temp2, temp3 : TFGInt; 1376 | S : String; 1377 | i : LongWord; 1378 | Begin 1379 | FGIntToBase2String(exp, S); 1380 | If S[length(S)] = '0' Then Base10StringToFGInt('1', res) Else FGIntCopy(FGInt, res); 1381 | FGIntCopy(FGInt, temp2); 1382 | If length(S) > 1 Then 1383 | For i := (length(S) - 1) Downto 1 Do 1384 | Begin 1385 | FGIntSquare(temp2, temp3); 1386 | FGIntCopy(temp3, temp2); 1387 | If S[i] = '1' Then 1388 | Begin 1389 | FGIntMul(res, temp2, temp3); 1390 | FGIntCopy(temp3, res); 1391 | End; 1392 | End; 1393 | End; 1394 | 1395 | 1396 | // Compute FGInt! = FGInt * (FGInt - 1) * (FGInt - 2) * ... * 3 * 2 * 1 1397 | 1398 | Procedure FGIntFac(Const FGInt : TFGInt; Var res : TFGInt); 1399 | Var 1400 | one, temp, temp1 : TFGInt; 1401 | Begin 1402 | FGIntCopy(FGInt, temp); 1403 | Base10StringToFGInt('1', res); 1404 | Base10StringToFGInt('1', one); 1405 | 1406 | While Not (FGIntCompareAbs(temp, one) = Eq) Do 1407 | Begin 1408 | FGIntMul(temp, res, temp1); 1409 | FGIntCopy(temp1, res); 1410 | FGIntSubBis(temp, one); 1411 | End; 1412 | 1413 | FGIntDestroy(one); 1414 | FGIntDestroy(temp); 1415 | End; 1416 | 1417 | 1418 | 1419 | // Divide 2 FGInts, FGInt1 = FGInt2 * QFGInt + MFGInt, MFGInt is always positive 1420 | 1421 | Procedure FGIntDivMod(Var FGInt1, FGInt2, QFGInt, MFGInt : TFGInt); 1422 | Var 1423 | one, zero, temp1 : TFGInt; 1424 | s1, s2 : TSign; 1425 | j, s, t : LongWord; 1426 | i, k : uint64; 1427 | Begin 1428 | s1 := FGInt1.Sign; 1429 | s2 := FGInt2.Sign; 1430 | FGIntAbs(FGInt1); 1431 | FGIntAbs(FGInt2); 1432 | FGIntCopy(FGInt1, MFGInt); 1433 | FGIntCopy(FGInt2, temp1); 1434 | 1435 | If FGIntCompareAbs(FGInt1, FGInt2) <> St Then 1436 | Begin 1437 | s := FGInt1.Number[0] - FGInt2.Number[0]; 1438 | SetLength(QFGInt.Number, (s + 2)); 1439 | QFGInt.Number[0] := s + 1; 1440 | FGIntShiftLeftBy32Times(temp1, s); 1441 | For t := 1 To s Do 1442 | Begin 1443 | QFGInt.Number[t] := 0; 1444 | End; 1445 | j := s + 1; 1446 | QFGInt.Number[j] := 0; 1447 | While FGIntCompareAbs(MFGInt, FGInt2) <> St Do 1448 | Begin 1449 | While FGIntCompareAbs(MFGInt, temp1) <> St Do 1450 | Begin 1451 | If MFGInt.Number[0] > temp1.Number[0] Then 1452 | Begin 1453 | i := MFGInt.Number[MFGInt.Number[0]]; 1454 | i := i Shl 32; 1455 | i := i + MFGInt.Number[MFGInt.Number[0] - 1]; 1456 | i := i Div (temp1.Number[temp1.Number[0]] + 1); 1457 | End 1458 | Else 1459 | // i := MFGInt.Number[MFGInt.Number[0]] Div (temp1.Number[temp1.Number[0]] + 1); 1460 | Begin 1461 | If (MFGInt.Number[0] > 1) And (FGInt2.Number[0] > 1) Then 1462 | Begin 1463 | i := MFGInt.Number[MFGInt.Number[0]]; 1464 | i := i Shl 32; 1465 | i := i + MFGInt.Number[MFGInt.Number[0] - 1]; 1466 | k := temp1.Number[temp1.Number[0]]; 1467 | k := k shl 32; 1468 | k := k + temp1.Number[temp1.Number[0] - 1] + 1; 1469 | i := i Div k; 1470 | End 1471 | Else 1472 | i := MFGInt.Number[MFGInt.Number[0]] Div (temp1.Number[temp1.Number[0]] + 1); 1473 | End; 1474 | If (i <> 0) Then 1475 | Begin 1476 | FGIntMulByIntSubBis(MFGInt, temp1, i); 1477 | QFGInt.Number[j] := QFGInt.Number[j] + i; 1478 | End 1479 | Else 1480 | Begin 1481 | QFGInt.Number[j] := QFGInt.Number[j] + 1; 1482 | FGIntSubBis(MFGInt, temp1); 1483 | End; 1484 | End; 1485 | If MFGInt.Number[0] <= temp1.Number[0] Then 1486 | If FGIntCompareAbs(temp1, FGInt2) <> Eq Then 1487 | Begin 1488 | FGIntShiftRightBy32(temp1); 1489 | j := j - 1; 1490 | End; 1491 | End; 1492 | End 1493 | Else 1494 | Base10StringToFGInt('0', QFGInt); 1495 | s := QFGInt.Number[0]; 1496 | While (s > 1) And (QFGInt.Number[s] = 0) Do 1497 | s := s - 1; 1498 | If s < QFGInt.Number[0] Then 1499 | Begin 1500 | setlength(QFGInt.Number, s + 1); 1501 | QFGInt.Number[0] := s; 1502 | End; 1503 | QFGInt.Sign := positive; 1504 | 1505 | FGIntDestroy(temp1); 1506 | Base10StringToFGInt('0', zero); 1507 | Base10StringToFGInt('1', one); 1508 | If s1 = negative Then 1509 | Begin 1510 | If FGIntCompareAbs(MFGInt, zero) <> Eq Then 1511 | Begin 1512 | FGIntadd(QFGInt, one, temp1); 1513 | FGIntDestroy(QFGInt); 1514 | FGIntCopy(temp1, QFGInt); 1515 | FGIntDestroy(temp1); 1516 | FGIntsub(FGInt2, MFGInt, temp1); 1517 | FGIntDestroy(MFGInt); 1518 | FGIntCopy(temp1, MFGInt); 1519 | FGIntDestroy(temp1); 1520 | End; 1521 | If s2 = positive Then QFGInt.Sign := negative; 1522 | End 1523 | Else 1524 | QFGInt.Sign := s2; 1525 | FGIntDestroy(one); 1526 | FGIntDestroy(zero); 1527 | 1528 | FGInt1.Sign := s1; 1529 | FGInt2.Sign := s2; 1530 | End; 1531 | 1532 | 1533 | // Same as above but doesn 't compute MFGInt 1534 | 1535 | Procedure FGIntDiv(Var FGInt1, FGInt2, QFGInt : TFGInt); 1536 | Var 1537 | one, zero, temp1, MFGInt : TFGInt; 1538 | s1, s2 : TSign; 1539 | j, s, t : LongWord; 1540 | i, k : int64; 1541 | Begin 1542 | s1 := FGInt1.Sign; 1543 | s2 := FGInt2.Sign; 1544 | FGIntAbs(FGInt1); 1545 | FGIntAbs(FGInt2); 1546 | FGIntCopy(FGInt1, MFGInt); 1547 | FGIntCopy(FGInt2, temp1); 1548 | 1549 | If FGIntCompareAbs(FGInt1, FGInt2) <> St Then 1550 | Begin 1551 | s := FGInt1.Number[0] - FGInt2.Number[0]; 1552 | SetLength(QFGInt.Number, (s + 2)); 1553 | QFGInt.Number[0] := s + 1; 1554 | FGIntShiftLeftBy32Times(temp1, s); 1555 | For t := 1 To s Do 1556 | Begin 1557 | QFGInt.Number[t] := 0; 1558 | End; 1559 | j := s + 1; 1560 | QFGInt.Number[j] := 0; 1561 | While FGIntCompareAbs(MFGInt, FGInt2) <> St Do 1562 | Begin 1563 | While FGIntCompareAbs(MFGInt, temp1) <> St Do 1564 | Begin 1565 | If MFGInt.Number[0] > temp1.Number[0] Then 1566 | Begin 1567 | i := MFGInt.Number[MFGInt.Number[0]]; 1568 | i := i Shl 32; 1569 | i := i + MFGInt.Number[MFGInt.Number[0] - 1]; 1570 | i := i Div (temp1.Number[temp1.Number[0]] + 1); 1571 | End 1572 | Else 1573 | // i := MFGInt.Number[MFGInt.Number[0]] Div (temp1.Number[temp1.Number[0]] + 1); 1574 | Begin 1575 | If (MFGInt.Number[0] > 1) And (FGInt2.Number[0] > 1) Then 1576 | Begin 1577 | i := MFGInt.Number[MFGInt.Number[0]]; 1578 | i := i Shl 32; 1579 | i := i + MFGInt.Number[MFGInt.Number[0] - 1]; 1580 | k := temp1.Number[temp1.Number[0]]; 1581 | k := k shl 32; 1582 | k := k + temp1.Number[temp1.Number[0] - 1] + 1; 1583 | i := i Div k; 1584 | End 1585 | Else 1586 | i := MFGInt.Number[MFGInt.Number[0]] Div (temp1.Number[temp1.Number[0]] + 1); 1587 | End; 1588 | If (i <> 0) Then 1589 | Begin 1590 | FGIntMulByIntSubBis(MFGInt, temp1, i); 1591 | QFGInt.Number[j] := QFGInt.Number[j] + i; 1592 | End 1593 | Else 1594 | Begin 1595 | QFGInt.Number[j] := QFGInt.Number[j] + 1; 1596 | FGIntSubBis(MFGInt, temp1); 1597 | End; 1598 | End; 1599 | If MFGInt.Number[0] <= temp1.Number[0] Then 1600 | If FGIntCompareAbs(temp1, FGInt2) <> Eq Then 1601 | Begin 1602 | FGIntShiftRightBy32(temp1); 1603 | j := j - 1; 1604 | End; 1605 | End; 1606 | End 1607 | Else 1608 | Base10StringToFGInt('0', QFGInt); 1609 | s := QFGInt.Number[0]; 1610 | While (s > 1) And (QFGInt.Number[s] = 0) Do 1611 | s := s - 1; 1612 | If s < QFGInt.Number[0] Then 1613 | Begin 1614 | setlength(QFGInt.Number, s + 1); 1615 | QFGInt.Number[0] := s; 1616 | End; 1617 | QFGInt.Sign := positive; 1618 | 1619 | FGIntDestroy(temp1); 1620 | Base10StringToFGInt('0', zero); 1621 | Base10StringToFGInt('1', one); 1622 | If s1 = negative Then 1623 | Begin 1624 | If FGIntCompareAbs(MFGInt, zero) <> Eq Then 1625 | Begin 1626 | FGIntadd(QFGInt, one, temp1); 1627 | FGIntDestroy(QFGInt); 1628 | FGIntCopy(temp1, QFGInt); 1629 | FGIntDestroy(temp1); 1630 | FGIntsub(FGInt2, MFGInt, temp1); 1631 | FGIntDestroy(MFGInt); 1632 | FGIntCopy(temp1, MFGInt); 1633 | FGIntDestroy(temp1); 1634 | End; 1635 | If s2 = positive Then QFGInt.Sign := negative; 1636 | End 1637 | Else 1638 | QFGInt.Sign := s2; 1639 | FGIntDestroy(one); 1640 | FGIntDestroy(zero); 1641 | FGIntDestroy(MFGInt); 1642 | 1643 | FGInt1.Sign := s1; 1644 | FGInt2.Sign := s2; 1645 | End; 1646 | 1647 | 1648 | 1649 | // FGInt1 = FGInt1 - divInt * FGInt2, use only when 0 < FGInt2 < FGInt1 1650 | 1651 | Procedure FGIntMulByIntSubBis(Var FGInt1 : TFGInt; Const FGInt2 : TFGInt; divInt : LongWord); 1652 | Var 1653 | i, size1, size2, rest : LongWord; 1654 | mTmpRest, Trest, mRest : uint64; 1655 | Begin 1656 | size1 := FGInt1.Number[0]; 1657 | size2 := FGInt2.Number[0]; 1658 | rest := 0; 1659 | mRest := 0; 1660 | For i := 1 To size2 Do 1661 | Begin 1662 | mTmpRest := FGInt2.Number[i]; 1663 | mTmpRest := mTmpRest * divInt; 1664 | mTmpRest := mTmpRest + mRest; 1665 | Trest := (4294967296 Or FGInt1.Number[i]) - (mTmpRest And 4294967295) - rest; 1666 | If (Trest > 4294967295) Then 1667 | rest := 0 1668 | Else 1669 | rest := 1; 1670 | mRest := mTmpRest shr 32; 1671 | FGInt1.Number[i] := Trest And 4294967295; 1672 | End; 1673 | For i := size2 + 1 To size1 Do 1674 | Begin 1675 | Trest := (4294967296 Or FGInt1.Number[i]) - mRest - rest; 1676 | If (Trest > 4294967295) Then 1677 | rest := 0 1678 | Else 1679 | rest := 1; 1680 | mRest := mRest shr 32; 1681 | FGInt1.Number[i] := Trest And 4294967295; 1682 | End; 1683 | i := size1; 1684 | While (FGInt1.Number[i] = 0) And (i > 1) Do 1685 | i := i - 1; 1686 | If i <> size1 Then 1687 | Begin 1688 | SetLength(FGInt1.Number, i + 1); 1689 | FGInt1.Number[0] := i; 1690 | End; 1691 | End; 1692 | 1693 | 1694 | 1695 | Procedure FGIntMod(Var FGInt1, FGInt2, MFGInt : TFGInt); 1696 | Var 1697 | zero, temp1 : TFGInt; 1698 | s1, s2 : TSign; 1699 | s : LongWord; 1700 | i, j : uint64; 1701 | Begin 1702 | s1 := FGInt1.Sign; 1703 | s2 := FGInt2.Sign; 1704 | FGIntAbs(FGInt1); 1705 | FGIntAbs(FGInt2); 1706 | FGIntCopy(FGInt1, MFGInt); 1707 | FGIntCopy(FGInt2, temp1); 1708 | 1709 | If FGIntCompareAbs(FGInt1, FGInt2) <> St Then 1710 | Begin 1711 | s := FGInt1.Number[0] - FGInt2.Number[0]; 1712 | // For t := 1 To s Do 1713 | FGIntShiftLeftBy32Times(temp1,s); 1714 | While FGIntCompareAbs(MFGInt, FGInt2) <> St Do 1715 | Begin 1716 | While FGIntCompareAbs(MFGInt, temp1) <> St Do 1717 | Begin 1718 | If MFGInt.Number[0] > temp1.Number[0] Then 1719 | Begin 1720 | i := MFGInt.Number[MFGInt.Number[0]]; 1721 | i := i Shl 32; 1722 | i := i + MFGInt.Number[MFGInt.Number[0] - 1]; 1723 | i := i Div (temp1.Number[temp1.Number[0]] + 1); 1724 | End 1725 | Else 1726 | // i := MFGInt.Number[MFGInt.Number[0]] Div (temp1.Number[temp1.Number[0]] + 1); 1727 | Begin 1728 | If (MFGInt.Number[0] > 1) And (FGInt2.Number[0] > 1) Then 1729 | Begin 1730 | i := MFGInt.Number[MFGInt.Number[0]]; 1731 | i := i Shl 32; 1732 | i := i + MFGInt.Number[MFGInt.Number[0] - 1]; 1733 | j := temp1.Number[temp1.Number[0]]; 1734 | j := j shl 32; 1735 | j := j + temp1.Number[temp1.Number[0] - 1] + 1; 1736 | i := i Div j; 1737 | End 1738 | Else 1739 | i := MFGInt.Number[MFGInt.Number[0]] Div (temp1.Number[temp1.Number[0]] + 1); 1740 | End; 1741 | If (i <> 0) Then 1742 | Begin 1743 | FGIntMulByIntSubBis(MFGInt, temp1, i); 1744 | End 1745 | Else 1746 | FGIntSubBis(MFGInt, temp1); 1747 | End; 1748 | If MFGInt.Number[0] <= temp1.Number[0] Then 1749 | If FGIntCompareAbs(temp1, FGInt2) <> Eq Then FGIntShiftRightBy32(temp1); 1750 | End; 1751 | End; 1752 | 1753 | FGIntDestroy(temp1); 1754 | Base10StringToFGInt('0', zero); 1755 | If s1 = negative Then 1756 | Begin 1757 | If FGIntCompareAbs(MFGInt, zero) <> Eq Then 1758 | Begin 1759 | FGIntSub(FGInt2, MFGInt, temp1); 1760 | FGIntDestroy(MFGInt); 1761 | FGIntCopy(temp1, MFGInt); 1762 | FGIntDestroy(temp1); 1763 | End; 1764 | End; 1765 | FGIntDestroy(zero); 1766 | 1767 | FGInt1.Sign := s1; 1768 | FGInt2.Sign := s2; 1769 | End; 1770 | 1771 | 1772 | // Square a FGInt modulo Modb, FGInt^2 mod Modb = FGIntSM 1773 | 1774 | Procedure FGIntSquareMod(Var FGInt, Modb, FGIntSM : TFGInt); 1775 | Var 1776 | temp : TFGInt; 1777 | Begin 1778 | FGIntSquare(FGInt, temp); 1779 | FGIntMod(temp, Modb, FGIntSM); 1780 | FGIntDestroy(temp); 1781 | End; 1782 | 1783 | 1784 | // Add 2 FGInts modulo base, (FGInt1 + FGInt2) mod base = FGIntres 1785 | 1786 | Procedure FGIntAddMod(Var FGInt1, FGInt2, base, FGIntres : TFGInt); 1787 | Var 1788 | temp : TFGInt; 1789 | Begin 1790 | FGIntadd(FGInt1, FGInt2, temp); 1791 | FGIntMod(temp, base, FGIntres); 1792 | FGIntDestroy(temp); 1793 | End; 1794 | 1795 | 1796 | // Multiply 2 FGInts modulo base, (FGInt1 * FGInt2) mod base = FGIntres 1797 | 1798 | Procedure FGIntMulMod(Var FGInt1, FGInt2, base, FGIntres : TFGInt); 1799 | Var 1800 | temp : TFGInt; 1801 | Begin 1802 | FGIntMul(FGInt1, FGInt2, temp); 1803 | FGIntMod(temp, base, FGIntres); 1804 | FGIntDestroy(temp); 1805 | End; 1806 | 1807 | 1808 | // Procedures for Montgomery Exponentiation 1809 | 1810 | Procedure FGIntModBis(Const FGInt : TFGInt; Var FGIntOut : TFGInt; b, head : LongWord); 1811 | Var 1812 | i : LongWord; 1813 | Begin 1814 | If b <= FGInt.Number[0] Then 1815 | Begin 1816 | SetLength(FGIntOut.Number, (b + 1)); 1817 | For i := 0 To b Do 1818 | FGIntOut.Number[i] := FGInt.Number[i]; 1819 | FGIntOut.Number[b] := FGIntOut.Number[b] And head; 1820 | i := b; 1821 | While (FGIntOut.Number[i] = 0) And (i > 1) Do 1822 | i := i - 1; 1823 | If i < b Then SetLength(FGIntOut.Number, i + 1); 1824 | FGIntOut.Number[0] := i; 1825 | FGIntOut.Sign := positive; 1826 | End 1827 | Else 1828 | FGIntCopy(FGInt, FGIntOut); 1829 | End; 1830 | 1831 | 1832 | Procedure FGIntMulModBis(Const FGInt1, FGInt2 : TFGInt; Var Prod : TFGInt; b, head : LongWord); 1833 | Var 1834 | i, j, size, size1, size2, t, rest : LongWord; 1835 | Trest : uint64; 1836 | Begin 1837 | size1 := FGInt1.Number[0]; 1838 | size2 := FGInt2.Number[0]; 1839 | size := min(b, size1 + size2); 1840 | SetLength(Prod.Number, (size + 1)); 1841 | For i := 1 To size Do 1842 | Prod.Number[i] := 0; 1843 | 1844 | For i := 1 To size2 Do 1845 | Begin 1846 | rest := 0; 1847 | t := min(size1, b - i + 1); 1848 | For j := 1 To t Do 1849 | Begin 1850 | Trest := FGInt1.Number[j]; 1851 | Trest := Trest * FGInt2.Number[i]; 1852 | Trest := Trest + Prod.Number[j + i - 1]; 1853 | Trest := Trest + rest; 1854 | Prod.Number[j + i - 1] := Trest And 4294967295; 1855 | rest := Trest Shr 32; 1856 | End; 1857 | If (i + size1) <= b Then Prod.Number[i + size1] := rest; 1858 | End; 1859 | 1860 | Prod.Number[0] := size; 1861 | If size = b Then Prod.Number[b] := Prod.Number[b] And head; 1862 | While (Prod.Number[size] = 0) And (size > 1) Do 1863 | size := size - 1; 1864 | If size < Prod.Number[0] Then 1865 | Begin 1866 | SetLength(Prod.Number, size + 1); 1867 | Prod.Number[0] := size; 1868 | End; 1869 | If FGInt1.Sign = FGInt2.Sign Then 1870 | Prod.Sign := Positive 1871 | Else 1872 | prod.Sign := negative; 1873 | End; 1874 | 1875 | 1876 | Procedure FGIntMontgomeryMod(Const GInt, base, baseInv : TFGInt; Var MGInt : TFGInt; b : Longword; head : LongWord); 1877 | Var 1878 | m, temp, temp1 : TFGInt; 1879 | r : LongWord; 1880 | Begin 1881 | FGIntModBis(GInt, temp, b, head); 1882 | FGIntMulModBis(temp, baseInv, m, b, head); 1883 | FGIntMul(m, base, temp1); 1884 | FGIntDestroy(temp); 1885 | FGIntAdd(temp1, GInt, temp); 1886 | FGIntDestroy(temp1); 1887 | MGInt.Number := copy(temp.Number, b - 1, temp.Number[0] - b + 2); 1888 | MGInt.Sign := positive; 1889 | MGInt.Number[0] := temp.Number[0] - b + 1; 1890 | FGIntDestroy(temp); 1891 | If (head Shr 31) = 0 Then FGIntDivByIntBis(MGInt, head + 1, r) 1892 | Else FGIntShiftRightBy32(MGInt); 1893 | If FGIntCompareAbs(MGInt, base) <> St Then FGIntSubBis(MGInt, base); 1894 | FGIntDestroy(temp); 1895 | FGIntDestroy(m); 1896 | End; 1897 | 1898 | 1899 | Procedure FGIntMontgomeryModExp(Var FGInt, exp, modb, res : TFGInt); 1900 | Var 1901 | temp2, temp3, baseInv, r, zero : TFGInt; 1902 | i, j, t, b, head : LongWord; 1903 | S: String; 1904 | Begin 1905 | Base2StringToFGInt('0', zero); 1906 | FGIntMod(FGInt, modb, res); 1907 | If FGIntCompareAbs(res, zero)=Eq then 1908 | Begin 1909 | FGIntDestroy(zero); 1910 | Exit; 1911 | End else FGIntDestroy(res); 1912 | FGIntDestroy(zero); 1913 | 1914 | FGIntToBase2String(exp, S); 1915 | t := modb.Number[0]; 1916 | b := t; 1917 | 1918 | If (modb.Number[t] Shr 31) = 1 Then t := t + 1; 1919 | SetLength(r.Number, (t + 1)); 1920 | r.Number[0] := t; 1921 | r.Sign := positive; 1922 | For i := 1 To t Do 1923 | r.Number[i] := 0; 1924 | If t = modb.Number[0] Then 1925 | Begin 1926 | head := 4294967295; 1927 | For j := 30 Downto 0 Do 1928 | Begin 1929 | head := head Shr 1; 1930 | If (modb.Number[t] Shr j) = 1 Then 1931 | Begin 1932 | r.Number[t] := 1 Shl (j + 1); 1933 | break; 1934 | End; 1935 | End; 1936 | End 1937 | Else 1938 | Begin 1939 | r.Number[t] := 1; 1940 | head := 4294967295; 1941 | End; 1942 | 1943 | FGIntModInv(modb, r, temp2); 1944 | If temp2.Sign = negative Then 1945 | FGIntCopy(temp2, BaseInv) 1946 | Else 1947 | Begin 1948 | FGIntCopy(r, BaseInv); 1949 | FGIntSubBis(BaseInv, temp2); 1950 | End; 1951 | // FGIntBezoutBachet(r, modb, temp2, BaseInv); 1952 | FGIntAbs(BaseInv); 1953 | FGIntDestroy(temp2); 1954 | FGIntMod(r, modb, res); 1955 | FGIntMulMod(FGInt, res, modb, temp2); 1956 | FGIntDestroy(r); 1957 | 1958 | For i := length(S) Downto 1 Do 1959 | Begin 1960 | If S[i] = '1' Then 1961 | Begin 1962 | FGIntmul(res, temp2, temp3); 1963 | FGIntDestroy(res); 1964 | FGIntMontgomeryMod(temp3, modb, baseinv, res, b, head); 1965 | FGIntDestroy(temp3); 1966 | End; 1967 | FGIntSquare(temp2, temp3); 1968 | FGIntDestroy(temp2); 1969 | FGIntMontgomeryMod(temp3, modb, baseinv, temp2, b, head); 1970 | FGIntDestroy(temp3); 1971 | End; 1972 | FGIntDestroy(temp2); 1973 | FGIntMontgomeryMod(res, modb, baseinv, temp3, b, head); 1974 | FGIntCopy(temp3, res); 1975 | FGIntDestroy(temp3); 1976 | FGIntDestroy(baseinv); 1977 | End; 1978 | 1979 | 1980 | 1981 | 1982 | // Exponentiate 2 FGInts modulo base, (FGInt1 ^ FGInt2) mod modb = res 1983 | 1984 | Procedure FGIntModExp(Var FGInt, exp, modb, res : TFGInt); 1985 | Var 1986 | temp2, temp3 : TFGInt; 1987 | i : LongWord; 1988 | S : String; 1989 | Begin 1990 | If (Modb.Number[1] Mod 2) = 1 Then 1991 | Begin 1992 | FGIntMontgomeryModExp(FGInt, exp, modb, res); 1993 | exit; 1994 | End; 1995 | FGIntToBase2String(exp, S); 1996 | Base10StringToFGInt('1', res); 1997 | FGIntcopy(FGInt, temp2); 1998 | 1999 | For i := length(S) Downto 1 Do 2000 | Begin 2001 | If S[i] = '1' Then 2002 | Begin 2003 | FGIntmulMod(res, temp2, modb, temp3); 2004 | FGIntCopy(temp3, res); 2005 | End; 2006 | FGIntSquareMod(temp2, Modb, temp3); 2007 | FGIntCopy(temp3, temp2); 2008 | End; 2009 | FGIntDestroy(temp2); 2010 | End; 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | // Compute the Greatest Common Divisor of 2 FGInts 2018 | 2019 | Procedure FGIntGCD(Const FGInt1, FGInt2 : TFGInt; Var GCD : TFGInt); 2020 | Var 2021 | k : TCompare; 2022 | zero, temp1, temp2, temp3 : TFGInt; 2023 | Begin 2024 | k := FGIntCompareAbs(FGInt1, FGInt2); 2025 | If (k = Eq) Then FGIntCopy(FGInt1, GCD) Else 2026 | If (k = St) Then FGIntGCD(FGInt2, FGInt1, GCD) Else 2027 | Begin 2028 | Base10StringToFGInt('0', zero); 2029 | FGIntCopy(FGInt1, temp1); 2030 | FGIntCopy(FGInt2, temp2); 2031 | While (temp2.Number[0] <> 1) Or (temp2.Number[1] <> 0) Do 2032 | Begin 2033 | FGIntMod(temp1, temp2, temp3); 2034 | FGIntCopy(temp2, temp1); 2035 | FGIntCopy(temp3, temp2); 2036 | FGIntDestroy(temp3); 2037 | End; 2038 | FGIntCopy(temp1, GCD); 2039 | FGIntDestroy(temp2); 2040 | FGIntDestroy(zero); 2041 | End; 2042 | End; 2043 | 2044 | 2045 | // Compute the Least Common Multiple of 2 FGInts 2046 | 2047 | Procedure FGIntLCM(Const FGInt1, FGInt2 : TFGInt; Var LCM : TFGInt); 2048 | Var 2049 | temp1, temp2 : TFGInt; 2050 | Begin 2051 | FGIntGCD(FGInt1, FGInt2, temp1); 2052 | FGIntmul(FGInt1, FGInt2, temp2); 2053 | FGIntdiv(temp2, temp1, LCM); 2054 | FGIntDestroy(temp1); 2055 | FGIntDestroy(temp2); 2056 | End; 2057 | 2058 | 2059 | // Trialdivision of a FGInt upto 9999 and stopping when a divisor is found, returning ok=false 2060 | 2061 | Procedure FGIntTrialDiv9999(Const FGInt : TFGInt; Var ok : boolean); 2062 | Var 2063 | j : LongWord; 2064 | i : integer; 2065 | Begin 2066 | If ((FGInt.Number[1] Mod 2) = 0) Then ok := false 2067 | Else 2068 | Begin 2069 | i := 0; 2070 | ok := true; 2071 | While ok And (i < 1228) Do 2072 | Begin 2073 | i := i + 1; 2074 | FGIntmodbyint(FGInt, primes[i], j); 2075 | If j = 0 Then ok := false; 2076 | End; 2077 | End; 2078 | End; 2079 | 2080 | 2081 | // A prng 2082 | 2083 | Procedure FGIntRandom1(Var Seed, RandomFGInt : TFGInt); 2084 | Var 2085 | temp, base : TFGInt; 2086 | Begin 2087 | Base10StringToFGInt('281474976710656', base); 2088 | Base10StringToFGInt('44485709377909', temp); 2089 | FGIntMulMod(seed, temp, base, RandomFGInt); 2090 | FGIntDestroy(temp); 2091 | FGIntDestroy(base); 2092 | End; 2093 | 2094 | 2095 | // Perform a Rabin Miller Primality Test nrtest times on FGIntp, returns ok=true when FGIntp passes the test 2096 | 2097 | Procedure FGIntRabinMiller(Var FGIntp : TFGInt; nrtest : Longword; Var ok : boolean); 2098 | Var 2099 | j, b, i : LongWord; 2100 | m, z, temp1, temp2, temp3, zero, one, two, pmin1 : TFGInt; 2101 | ok1, ok2 : boolean; 2102 | Begin 2103 | randomize; 2104 | Base10StringToFGInt('0', zero); 2105 | Base10StringToFGInt('1', one); 2106 | Base10StringToFGInt('2', two); 2107 | FGIntsub(FGIntp, one, temp1); 2108 | FGIntsub(FGIntp, one, pmin1); 2109 | 2110 | b := 0; 2111 | While (temp1.Number[1] Mod 2) = 0 Do 2112 | Begin 2113 | b := b + 1; 2114 | FGIntShiftRight(temp1); 2115 | End; 2116 | m := temp1; 2117 | 2118 | i := 0; 2119 | ok := true; 2120 | Randomize; 2121 | While (i < nrtest) And ok Do 2122 | Begin 2123 | j := 0; 2124 | i := i + 1; 2125 | Base10StringToFGInt(inttostr(Primes[Random(1227) + 1]), temp2); 2126 | FGIntMontGomeryModExp(temp2, m, FGIntp, z); 2127 | FGIntDestroy(temp2); 2128 | ok1 := (FGIntCompareAbs(z, one) = Eq); 2129 | ok2 := (FGIntCompareAbs(z, pmin1) = Eq); 2130 | If Not (ok1 Or ok2) Then 2131 | Begin 2132 | 2133 | While (ok And (j < b)) Do 2134 | Begin 2135 | If (j > 0) And ok1 Then ok := false 2136 | Else 2137 | Begin 2138 | j := j + 1; 2139 | If (j < b) And (Not ok2) Then 2140 | Begin 2141 | FGIntSquaremod(z, FGIntp, temp3); 2142 | FGIntCopy(temp3, z); 2143 | ok1 := (FGIntCompareAbs(z, one) = Eq); 2144 | ok2 := (FGIntCompareAbs(z, pmin1) = Eq); 2145 | If ok2 Then j := b; 2146 | End 2147 | Else If (Not ok2) And (j >= b) Then ok := false; 2148 | End; 2149 | End; 2150 | 2151 | End 2152 | End; 2153 | 2154 | FGIntDestroy(zero); 2155 | FGIntDestroy(one); 2156 | FGIntDestroy(two); 2157 | FGIntDestroy(m); 2158 | FGIntDestroy(z); 2159 | FGIntDestroy(pmin1); 2160 | End; 2161 | 2162 | 2163 | // Compute the coefficients from the Bezout Bachet theorem, FGInt1 * a + FGInt2 * b = GCD(FGInt1, FGInt2) 2164 | 2165 | Procedure FGIntBezoutBachet(Var FGInt1, FGInt2, a, b : TFGInt); 2166 | Var 2167 | zero, r1, r2, r3, ta, gcd, temp, temp1, temp2 : TFGInt; 2168 | Begin 2169 | If FGIntCompareAbs(FGInt1, FGInt2) <> St Then 2170 | Begin 2171 | FGIntcopy(FGInt1, r1); 2172 | FGIntcopy(FGInt2, r2); 2173 | Base10StringToFGInt('0', zero); 2174 | Base10StringToFGInt('1', a); 2175 | Base10StringToFGInt('0', ta); 2176 | 2177 | Repeat 2178 | FGIntdivmod(r1, r2, temp, r3); 2179 | FGIntDestroy(r1); 2180 | r1 := r2; 2181 | r2 := r3; 2182 | 2183 | FGIntmul(ta, temp, temp1); 2184 | FGIntsub(a, temp1, temp2); 2185 | FGIntCopy(ta, a); 2186 | FGIntCopy(temp2, ta); 2187 | FGIntDestroy(temp1); 2188 | 2189 | FGIntDestroy(temp); 2190 | Until FGIntCompareAbs(r3, zero) = Eq; 2191 | 2192 | FGIntGCD(FGInt1, FGInt2, gcd); 2193 | FGIntmul(a, FGInt1, temp1); 2194 | FGIntsub(gcd, temp1, temp2); 2195 | FGIntDestroy(temp1); 2196 | FGIntdiv(temp2, FGInt2, b); 2197 | FGIntDestroy(temp2); 2198 | 2199 | FGIntDestroy(ta); 2200 | FGIntDestroy(r1); 2201 | FGIntDestroy(r2); 2202 | FGIntDestroy(gcd); 2203 | End 2204 | Else FGIntBezoutBachet(FGInt2, FGInt1, b, a); 2205 | End; 2206 | 2207 | 2208 | // Find the (multiplicative) Modular inverse of a FGInt in a finite ring 2209 | // of additive order base 2210 | 2211 | Procedure FGIntModInv(Const FGInt1, base : TFGInt; Var Inverse : TFGInt); 2212 | Var 2213 | zero, one, r1, r2, r3, tb, gcd, temp, temp1, temp2 : TFGInt; 2214 | Begin 2215 | Base10StringToFGInt('1', one); 2216 | FGIntGCD(FGInt1, base, gcd); 2217 | If FGIntCompareAbs(one, gcd) = Eq Then 2218 | Begin 2219 | FGIntcopy(base, r1); 2220 | FGIntcopy(FGInt1, r2); 2221 | Base10StringToFGInt('0', zero); 2222 | Base10StringToFGInt('0', inverse); 2223 | Base10StringToFGInt('1', tb); 2224 | 2225 | Repeat 2226 | FGIntDestroy(r3); 2227 | FGIntdivmod(r1, r2, temp, r3); 2228 | FGIntCopy(r2, r1); 2229 | FGIntCopy(r3, r2); 2230 | 2231 | FGIntmul(tb, temp, temp1); 2232 | FGIntsub(inverse, temp1, temp2); 2233 | FGIntDestroy(inverse); 2234 | FGIntDestroy(temp1); 2235 | FGIntCopy(tb, inverse); 2236 | FGIntCopy(temp2, tb); 2237 | 2238 | FGIntDestroy(temp); 2239 | Until FGIntCompareAbs(r3, zero) = Eq; 2240 | 2241 | If inverse.Sign = negative Then 2242 | Begin 2243 | FGIntadd(base, inverse, temp); 2244 | FGIntCopy(temp, inverse); 2245 | End; 2246 | 2247 | FGIntDestroy(tb); 2248 | FGIntDestroy(r1); 2249 | FGIntDestroy(r2); 2250 | End; 2251 | FGIntDestroy(gcd); 2252 | FGIntDestroy(one); 2253 | End; 2254 | 2255 | 2256 | // Perform a (combined) primality test on FGIntp consisting of a trialdivision upto 8192, 2257 | // if the FGInt passes perform nrRMtests Rabin Miller primality tests, returns ok when a 2258 | // FGInt is probably prime 2259 | 2260 | Procedure FGIntPrimetest(Var FGIntp : TFGInt; nrRMtests : integer; Var ok : boolean); 2261 | Begin 2262 | FGIntTrialdiv9999(FGIntp, ok); 2263 | If ok Then FGIntRabinMiller(FGIntp, nrRMtests, ok); 2264 | End; 2265 | 2266 | 2267 | // Computes the Legendre symbol for a any number and 2268 | // p a prime, returns 0 if p divides a, 1 if a is a 2269 | // quadratic residu mod p, -1 if a is a quadratic 2270 | // nonresidu mod p 2271 | 2272 | Procedure FGIntLegendreSymbol(Var a, p : TFGInt; Var L : integer); 2273 | Var 2274 | temp1, temp2, temp3, temp4, temp5, zero, one : TFGInt; 2275 | i : LongWord; 2276 | ok1, ok2 : boolean; 2277 | Begin 2278 | Base10StringToFGInt('0', zero); 2279 | Base10StringToFGInt('1', one); 2280 | FGIntMod(a, p, temp1); 2281 | If FGIntCompareAbs(zero, temp1) = Eq Then 2282 | Begin 2283 | FGIntDestroy(temp1); 2284 | L := 0; 2285 | End 2286 | Else 2287 | Begin 2288 | FGIntDestroy(temp1); 2289 | FGIntCopy(p, temp1); 2290 | FGIntCopy(a, temp2); 2291 | L := 1; 2292 | While FGIntCompareAbs(temp2, one) <> Eq Do 2293 | Begin 2294 | If (temp2.Number[1] Mod 2) = 0 Then 2295 | Begin 2296 | FGIntSquare(temp1, temp3); 2297 | FGIntSub(temp3, one, temp4); 2298 | FGIntDestroy(temp3); 2299 | FGIntDivByInt(temp4, temp3, 8, i); 2300 | If (temp3.Number[1] Mod 2) = 0 Then ok1 := false Else ok1 := true; 2301 | FGIntDestroy(temp3); 2302 | FGIntDestroy(temp4); 2303 | If ok1 = true Then L := L * (-1); 2304 | FGIntDivByIntBis(temp2, 2, i); 2305 | End 2306 | Else 2307 | Begin 2308 | FGIntSub(temp1, one, temp3); 2309 | FGIntSub(temp2, one, temp4); 2310 | FGIntMul(temp3, temp4, temp5); 2311 | FGIntDestroy(temp3); 2312 | FGIntDestroy(temp4); 2313 | FGIntDivByInt(temp5, temp3, 4, i); 2314 | If (temp3.Number[1] Mod 2) = 0 Then ok2 := false Else ok2 := true; 2315 | FGIntDestroy(temp5); 2316 | FGIntDestroy(temp3); 2317 | If ok2 = true Then L := L * (-1); 2318 | FGIntMod(temp1, temp2, temp3); 2319 | FGIntCopy(temp2, temp1); 2320 | FGIntCopy(temp3, temp2); 2321 | End; 2322 | End; 2323 | FGIntDestroy(temp1); 2324 | FGIntDestroy(temp2); 2325 | End; 2326 | FGIntDestroy(zero); 2327 | FGIntDestroy(one); 2328 | End; 2329 | 2330 | 2331 | // Compute a square root modulo a prime number 2332 | // SquareRoot^2 mod Prime = Square 2333 | 2334 | Procedure FGIntSquareRootModP(Square, Prime : TFGInt; Var SquareRoot : TFGInt); 2335 | Var 2336 | one, n, b, s, r, temp, temp1, temp2, temp3 : TFGInt; 2337 | a, i, j : longint; 2338 | L : Integer; 2339 | Begin 2340 | Base2StringToFGInt('1', one); 2341 | Base2StringToFGInt('10', n); 2342 | a := 0; 2343 | FGIntLegendreSymbol(n, Prime, L); 2344 | While L <> -1 Do 2345 | Begin 2346 | FGIntAddBis(n, one); 2347 | FGIntLegendreSymbol(n, Prime, L); 2348 | End; 2349 | FGIntCopy(Prime, s); 2350 | s.Number[1] := s.Number[1] - 1; 2351 | While (s.Number[1] Mod 2) = 0 Do 2352 | Begin 2353 | FGIntShiftRight(s); 2354 | a := a + 1; 2355 | End; 2356 | FGIntMontgomeryModExp(n, s, Prime, b); 2357 | FGIntAdd(s, one, temp); 2358 | FGIntShiftRight(temp); 2359 | FGIntMontgomeryModExp(Square, temp, Prime, r); 2360 | FGIntDestroy(temp); 2361 | FGIntModInv(Square, Prime, temp1); 2362 | 2363 | For i := 0 To (a - 2) Do 2364 | Begin 2365 | FGIntSquareMod(r, Prime, temp2); 2366 | FGIntMulMod(temp1, temp2, Prime, temp); 2367 | FGIntDestroy(temp2); 2368 | For j := 1 To (a - i - 2) Do 2369 | Begin 2370 | FGIntSquareMod(temp, Prime, temp2); 2371 | FGIntDestroy(temp); 2372 | FGIntCopy(temp2, temp); 2373 | FGIntDestroy(temp2); 2374 | End; 2375 | If FGIntCompareAbs(temp, one) <> Eq Then 2376 | Begin 2377 | FGIntMulMod(r, b, Prime, temp3); 2378 | FGIntDestroy(r); 2379 | FGIntCopy(temp3, r); 2380 | FGIntDestroy(temp3); 2381 | End; 2382 | FGIntDestroy(temp); 2383 | FGIntDestroy(temp2); 2384 | If i = (a - 2) Then break; 2385 | FGIntSquareMod(b, Prime, temp3); 2386 | FGIntDestroy(b); 2387 | FGIntCopy(temp3, b); 2388 | FGIntDestroy(temp3); 2389 | End; 2390 | 2391 | FGIntCopy(r, SquareRoot); 2392 | FGIntDestroy(r); 2393 | FGIntDestroy(s); 2394 | FGIntDestroy(b); 2395 | FGIntDestroy(temp1); 2396 | FGIntDestroy(one); 2397 | FGIntDestroy(n); 2398 | End; 2399 | 2400 | 2401 | 2402 | 2403 | 2404 | 2405 | // compute the initial bits for newton inversion with kZero fraction digits 2406 | 2407 | Procedure newtonInitialValue(Const FGInt : TFGInt; Const kZero: LongWord; Var resFGInt : TFGInt); 2408 | Var 2409 | tmpFGInt, bFGInt : TFGInt; 2410 | isTwo, i, j, l : LongWord; 2411 | k, divisorLength, tmpFGIntHead1, tmpFGIntHead2, bFGIntLength, divInt : uint64; 2412 | Begin 2413 | isTwo := 0; 2414 | divisorLength := FGInt.Number[0]; 2415 | 2416 | k := divisorLength; 2417 | for i := 1 to divisorLength do 2418 | begin 2419 | if FGInt.Number[i] <> 0 then 2420 | for l := 0 to 31 do 2421 | if (FGInt.Number[i] and (1 shl l)) <> 0 then isTwo := isTwo + 1; 2422 | end; 2423 | 2424 | if (isTwo <> 1) then 2425 | Begin 2426 | j := kZero div 32; 2427 | if kZero mod 32 <> 0 then j := j + 1; 2428 | k := divisorLength + j; 2429 | 2430 | bFGInt.sign := positive; 2431 | setlength(bFGInt.Number, k + 2); 2432 | For i := 1 to k do 2433 | bFGInt.Number[i] := 0; 2434 | bFGInt.Number[k+1] := 1; 2435 | bFGInt.Number[0] := k + 1; 2436 | 2437 | if bFGInt.Number[0] + 1 > divisorLength then j := bFGInt.Number[0] - divisorLength + 1 else j := 0; 2438 | FGIntCopy(fGInt, tmpFGInt); 2439 | if (j > 0) then 2440 | FGIntShiftLeftBy32Times(tmpFGInt, j - 1); 2441 | 2442 | resFGInt.sign := positive; 2443 | setlength(resFGInt.Number, j + 1); 2444 | For i := 1 to j do 2445 | resFGInt.Number[i] := 0; 2446 | resFGInt.Number[0] := j; 2447 | 2448 | tmpFGIntHead1 := tmpFGInt.Number[tmpFGInt.Number[0]]; 2449 | tmpFGIntHead1 := tmpFGIntHead1 + 1; 2450 | if tmpFGInt.Number[0] > 1 then 2451 | begin 2452 | tmpFGIntHead2 := tmpFGInt.Number[tmpFGInt.Number[0]]; 2453 | tmpFGIntHead2 := (tmpFGIntHead2 shl 32) + tmpFGInt.Number[tmpFGInt.Number[0] - 1] + 1; 2454 | end else 2455 | begin 2456 | tmpFGIntHead2 := 0; 2457 | end; 2458 | bFGIntLength := bFGInt.Number[0]; 2459 | 2460 | while FGIntCompareAbs(bFGInt, fGInt) <> St do 2461 | begin 2462 | while FGIntCompareAbs(bFGInt, tmpFGInt) <> St do 2463 | begin 2464 | if bFGIntLength > tmpFGInt.Number[0] then 2465 | begin 2466 | divInt := bFGInt.Number[bFGInt.Number[0]]; 2467 | divInt := ((divInt shl 32) + bFGInt.Number[bFGInt.Number[0] - 1]) div tmpFGIntHead1; 2468 | end else 2469 | begin 2470 | if (bFGIntLength > 1) and (tmpFGIntHead2 <> 0) then 2471 | begin 2472 | divInt := bFGInt.Number[bFGInt.Number[0]]; 2473 | divInt := ((divInt shl 32) + bFGInt.Number[bFGInt.Number[0] - 1] ) div tmpFGIntHead2; 2474 | end else 2475 | begin 2476 | divInt := bFGInt.Number[bFGInt.Number[0]]; 2477 | divInt := divInt div tmpFGIntHead1; 2478 | end 2479 | end; 2480 | if divInt <> 0 then 2481 | begin 2482 | FGIntMulByIntSubBis(bFGInt, tmpFGInt, divInt); 2483 | resFGInt.Number[j] := resFGInt.Number[j] + divInt; 2484 | end else 2485 | begin 2486 | FGIntSubBis(bFGInt, tmpFGInt); 2487 | resFGInt.Number[j] := resFGInt.Number[j] + 1; 2488 | end; 2489 | bFGIntLength := bFGInt.Number[0]; 2490 | end; 2491 | if (bFGIntLength <= tmpFGInt.Number[0]) and (tmpFGInt.Number[0] > divisorLength) then 2492 | begin 2493 | FGIntShiftRightBy32(tmpFGInt); 2494 | j := j - 1; 2495 | end; 2496 | end; 2497 | 2498 | 2499 | 2500 | while (resFGInt.Number[0] > 1) and (resFGInt.Number[resFGInt.Number[0]] = 0) do 2501 | begin 2502 | setLength(resFGInt.Number, resFGInt.Number[0]); 2503 | resFGInt.Number[0] := resFGInt.Number[0] - 1; 2504 | end; 2505 | j := kZero + 1; 2506 | i := 32 * (resFGInt.Number[0] - 1); 2507 | while (resFGInt.Number[resFGInt.Number[0]] shr i) <> 0 do 2508 | i := i + 1; 2509 | 2510 | // writeln(' - divInt - ' + inttostr(divInt)); 2511 | 2512 | if (i > j) then 2513 | FGIntShiftRightBy(resFGInt, i - j) 2514 | else 2515 | FGIntShiftLeftBy(resFGInt, j - i); 2516 | 2517 | FGIntDestroy(bFGInt); 2518 | FGIntDestroy(tmpFGInt); 2519 | 2520 | end else 2521 | Begin 2522 | Base2StringToFGInt('10', resFGInt); 2523 | FGIntShiftLeftBy(resFGInt, kZero); 2524 | End; 2525 | End; 2526 | 2527 | 2528 | // newtonInversion returns the 1/fGInt with precision fraction digits 2529 | 2530 | Procedure newtonInversion(Const fGInt : TFGInt; Const precision : LongWord; Var resFGInt : TFGInt); 2531 | Var 2532 | z, zSquare, vFGInt, t_FGInt, uFGInt : TFGInt; 2533 | h, j, k, baseCaseLength, vLength, uRadix, 2534 | zRadix, zSquareRadix, tRadix, vIndex : uint64; 2535 | kValues : Array of LongWord; 2536 | i : LongWord; 2537 | Begin 2538 | baseCaseLength := 128; 2539 | k := precision; 2540 | 2541 | FGIntCopy(fGInt, vFGInt); 2542 | vLength := vFGInt.Number[0]; 2543 | i := 0; 2544 | while (vFGInt.Number[vLength] < (2147483648 shr i)) do i := i + 1; 2545 | FGIntShiftLeftBy(vFGInt, i); 2546 | 2547 | j := k; 2548 | i := 0; 2549 | setlength(kValues, 0); 2550 | while (k > baseCaseLength) do 2551 | begin 2552 | k := (j div 2) + (j mod 2); 2553 | j := k; 2554 | setlength(kValues, length(kValues) + 1); 2555 | kValues[i] := k; 2556 | i := i + 1; 2557 | end; 2558 | newtonInitialValue(vFGInt, k, z); 2559 | zRadix := k; 2560 | vIndex := vLength; 2561 | tRadix := 0; 2562 | setLength(t_FGInt.Number, 0); 2563 | 2564 | for i := length(kValues) - 1 Downto 0 do 2565 | begin 2566 | k := kValues[i]; 2567 | FGIntSquare(z, zSquare); 2568 | zSquareRadix := 2 * zRadix; 2569 | 2570 | //////////////////// ToDo: optimize!!!!!!!!!!!!!!!!!!!!!!!!! 2571 | // h := (2*k + 3 - tRadix) div 32; 2572 | // if (2*k + 3 - tRadix) mod 32 <> 0 then h := h + 1; 2573 | 2574 | while tRadix < (2 * k + 3) do 2575 | begin 2576 | if (vIndex > 0) then 2577 | begin 2578 | if length(t_FGInt.Number) = 0 then Base2StringToFGInt('0', t_FGInt) else FGIntShiftLeftBy32(t_FGInt); 2579 | t_FGInt.Number[1] := vFGInt.Number[vIndex]; 2580 | end else 2581 | begin 2582 | FGIntShiftLeftBy32(t_FGInt); 2583 | end; 2584 | vIndex := vIndex - 1; 2585 | tRadix := tRadix + 32; 2586 | end; 2587 | t_FGInt.Number[0] := tRadix div 32; 2588 | h := tRadix - 2*k - 3; 2589 | FGIntMul(t_FGInt, zSquare, uFGInt); 2590 | FGIntDestroy(zSquare); 2591 | uRadix := tRadix + zSquareRadix; 2592 | if (uRadix > 2*k + 1 + h) then 2593 | begin 2594 | FGIntShiftRightBy(uFGInt, uRadix - (2*k + 1 + h)); 2595 | uRadix := 2*k + 1 + h; 2596 | end; 2597 | FGIntShiftLeft(z); 2598 | 2599 | 2600 | if (uRadix > zRadix) then 2601 | begin 2602 | FGIntShiftLeftBy(z, uRadix - zRadix); 2603 | zRadix := uRadix; 2604 | end; 2605 | FGIntSubBis(z, uFGInt); 2606 | FGIntDestroy(uFGInt); 2607 | end; 2608 | 2609 | if (zRadix > precision) then FGIntShiftRightBy(z, zRadix - precision); 2610 | FGIntAbs(z); 2611 | 2612 | kValues := nil; 2613 | FGIntDestroy(t_FGInt); 2614 | FGIntDestroy(vFGInt); 2615 | resFGInt := z; 2616 | End; 2617 | 2618 | 2619 | 2620 | Procedure FGIntBarretDivMod(Var FGInt1, FGInt2, QFGInt, MFGInt : TFGInt); 2621 | Var 2622 | fGInt1Copy, divisorCopy, tmpFGInt, one, invertedDivisor : TFGInt; 2623 | i, m, n : Longword; 2624 | mnCorrect : boolean; 2625 | fGIntSign, divisorSign : TSign; 2626 | begin 2627 | m := (fGInt1.Number[0] - 1) * 32; 2628 | n := (fGInt2.Number[0] - 1) * 32; 2629 | mnCorrect := false; 2630 | fGIntSign := fGInt1.sign; 2631 | divisorSign := fGInt2.sign; 2632 | 2633 | if FGIntCompareAbs(fGInt1, fGInt2) <> St then 2634 | begin 2635 | FGIntAbs(fGInt1); 2636 | FGIntAbs(fGInt2); 2637 | for i := 0 to 31 do 2638 | if (fGInt1.Number[fGInt1.Number[0]] shr i) = 0 then break else m := m + 1; 2639 | for i := 0 to 31 do 2640 | if (fGInt2.Number[fGInt2.Number[0]] shr i) = 0 then break else n := n + 1; 2641 | 2642 | if (m > 2 * n) then 2643 | begin 2644 | mnCorrect := True; 2645 | FGIntCopy(fGInt1, fGInt1Copy); 2646 | FGIntCopy(fGInt2, divisorCopy); 2647 | end; 2648 | 2649 | while (m > 2*n) do 2650 | begin 2651 | if (m >= 2*n + 32) then 2652 | begin 2653 | FGIntShiftLeftBy32(fGInt1); 2654 | FGIntShiftLeftBy32(fGInt2); 2655 | m := m + 32; 2656 | n := n + 32; 2657 | end else 2658 | begin 2659 | FGIntShiftLeft(fGInt1); 2660 | FGIntShiftLeft(fGInt2); 2661 | m := m + 1; 2662 | n := n + 1; 2663 | end; 2664 | end; 2665 | newtonInversion(fGInt2, m - n, invertedDivisor); 2666 | FGIntCopy(fGInt1, tmpFGInt); 2667 | 2668 | i := n - 1; 2669 | if i > 0 then FGIntShiftRightBy(tmpFGInt, i); 2670 | 2671 | FGIntMul(tmpFGInt, invertedDivisor, QFGInt); 2672 | FGIntDestroy(tmpFGInt); 2673 | 2674 | i := m - n + 1; 2675 | if (i > 0) then FGIntShiftRightBy(QFGInt, i); 2676 | 2677 | if (mnCorrect) then 2678 | begin 2679 | fGInt1 := fGInt1Copy; 2680 | fGInt2 := divisorCopy; 2681 | end; 2682 | 2683 | FGIntMul(fGInt2, QFGInt, tmpFGInt); 2684 | FGIntSub(fGInt1, tmpFGInt, MFGInt); 2685 | FGIntDestroy(tmpFGInt); 2686 | 2687 | Base2StringToFGInt('1', one); 2688 | 2689 | while not ((MFGInt.sign = positive) and (FGIntCompareAbs(MFGInt, fGInt2) = St)) do 2690 | begin 2691 | if (MFGInt.sign = negative) then 2692 | begin 2693 | FGIntAdd(MFGInt, fGInt2, tmpFGInt); 2694 | FGIntDestroy(MFGInt); 2695 | MFGInt := tmpFGInt; 2696 | FGIntSubBis(QFGInt, one); 2697 | end else 2698 | begin 2699 | FGIntSubBis(MFGInt, fGInt2); 2700 | FGIntAddBis(QFGInt, one); 2701 | end; 2702 | end; 2703 | 2704 | if (fGInt1.Sign = negative) then 2705 | begin 2706 | FGIntSub(fGInt2, MFGInt, tmpFGInt); 2707 | FGIntDestroy(MFGInt); 2708 | MFGInt := tmpFGInt; 2709 | FGIntAddBis(QFGInt, one); 2710 | end; 2711 | if fGIntSign = divisorSign then QFGInt.sign := positive else QFGInt.sign := negative; 2712 | 2713 | FGIntDestroy(invertedDivisor); 2714 | FGIntDestroy(one); 2715 | end else 2716 | begin 2717 | if (fGInt1.sign = positive) then 2718 | begin 2719 | Base2StringToFGInt('0', QFGInt); 2720 | FGIntCopy(fGInt1, MFGInt); 2721 | end else 2722 | begin 2723 | if (fGInt2.sign = positive) then 2724 | begin 2725 | Base2StringToFGInt('1', QFGInt); 2726 | QFGInt.sign := negative; 2727 | end else 2728 | Base2StringToFGInt('1', QFGInt); 2729 | 2730 | FGIntCopy(fGInt2, MFGInt); 2731 | FGIntAbs(MFGInt); 2732 | FGIntSubBis(MFGInt, fGInt1); 2733 | end; 2734 | end; 2735 | end; 2736 | 2737 | 2738 | 2739 | 2740 | Procedure FGIntBarretMod(Var FGInt1, FGInt2, MFGInt : TFGInt); 2741 | Var 2742 | fGInt1Copy, divisorCopy, tmpFGInt, one, invertedDivisor, QFGInt : TFGInt; 2743 | i, m, n : Longword; 2744 | mnCorrect : boolean; 2745 | begin 2746 | m := (fGInt1.Number[0] - 1) * 32; 2747 | n := (fGInt2.Number[0] - 1) * 32; 2748 | mnCorrect := false; 2749 | 2750 | if FGIntCompareAbs(fGInt1, fGInt2) <> St then 2751 | begin 2752 | FGIntAbs(fGInt1); 2753 | FGIntAbs(fGInt2); 2754 | for i := 0 to 31 do 2755 | if (fGInt1.Number[fGInt1.Number[0]] shr i) = 0 then break else m := m + 1; 2756 | for i := 0 to 31 do 2757 | if (fGInt2.Number[fGInt2.Number[0]] shr i) = 0 then break else n := n + 1; 2758 | 2759 | if (m > 2 * n) then 2760 | begin 2761 | mnCorrect := True; 2762 | FGIntCopy(fGInt1, fGInt1Copy); 2763 | FGIntCopy(fGInt2, divisorCopy); 2764 | end; 2765 | 2766 | while (m > 2*n) do 2767 | begin 2768 | if (m >= 2*n + 32) then 2769 | begin 2770 | FGIntShiftLeftBy32(fGInt1); 2771 | FGIntShiftLeftBy32(fGInt2); 2772 | m := m + 32; 2773 | n := n + 32; 2774 | end else 2775 | begin 2776 | FGIntShiftLeft(fGInt1); 2777 | FGIntShiftLeft(fGInt2); 2778 | m := m + 1; 2779 | n := n + 1; 2780 | end; 2781 | end; 2782 | newtonInversion(fGInt2, m - n, invertedDivisor); 2783 | FGIntCopy(fGInt1, tmpFGInt); 2784 | 2785 | i := n - 1; 2786 | if i > 0 then FGIntShiftRightBy(tmpFGInt, i); 2787 | 2788 | FGIntMul(tmpFGInt, invertedDivisor, QFGInt); 2789 | FGIntDestroy(tmpFGInt); 2790 | 2791 | i := m - n + 1; 2792 | if (i > 0) then FGIntShiftRightBy(QFGInt, i); 2793 | 2794 | if (mnCorrect) then 2795 | begin 2796 | fGInt1 := fGInt1Copy; 2797 | fGInt2 := divisorCopy; 2798 | end; 2799 | 2800 | FGIntMul(fGInt2, QFGInt, tmpFGInt); 2801 | FGIntSub(fGInt1, tmpFGInt, MFGInt); 2802 | FGIntDestroy(tmpFGInt); 2803 | 2804 | Base2StringToFGInt('1', one); 2805 | 2806 | while not ((MFGInt.sign = positive) and (FGIntCompareAbs(MFGInt, fGInt2) = St)) do 2807 | begin 2808 | if (MFGInt.sign = negative) then 2809 | begin 2810 | FGIntAdd(MFGInt, fGInt2, tmpFGInt); 2811 | FGIntDestroy(MFGInt); 2812 | MFGInt := tmpFGInt; 2813 | end else 2814 | begin 2815 | FGIntSubBis(MFGInt, fGInt2); 2816 | end; 2817 | end; 2818 | 2819 | if (fGInt1.Sign = negative) then 2820 | begin 2821 | FGIntSub(fGInt2, MFGInt, tmpFGInt); 2822 | FGIntDestroy(MFGInt); 2823 | MFGInt := tmpFGInt; 2824 | end; 2825 | 2826 | FGIntDestroy(QFGInt); 2827 | FGIntDestroy(invertedDivisor); 2828 | FGIntDestroy(one); 2829 | end else 2830 | begin 2831 | if (fGInt1.sign = positive) then 2832 | begin 2833 | FGIntCopy(fGInt1, MFGInt); 2834 | end else 2835 | begin 2836 | FGIntCopy(fGInt2, MFGInt); 2837 | FGIntAbs(MFGInt); 2838 | FGIntSubBis(MFGInt, fGInt1); 2839 | end; 2840 | end; 2841 | end; 2842 | 2843 | 2844 | 2845 | 2846 | 2847 | 2848 | 2849 | // barrettMod expects fGInt to contain not more than double the amount of significant bits of divisorFGInt, 2850 | // invertedDivisor has double the amount of significant bits of divisorFGInt as fraction bits. 2851 | // barrettMod expects all arguments to be positive. 2852 | 2853 | 2854 | Procedure FGIntBarrettModWithInvertedDivisorAndPrecision(Const GInt, divisorFGInt, invertedDivisor : TFGInt; precision : LongWord; Var modFGInt : TFGInt); 2855 | Var 2856 | QFGInt, tmpFGInt : TFGInt; 2857 | i, j : LongWord; 2858 | // str : string; 2859 | begin 2860 | if FGIntCompareAbs(GInt, divisorFGInt) <> St then 2861 | begin 2862 | i := precision - 1; 2863 | j := (i div 32); 2864 | tmpFGInt.sign := GInt.sign; 2865 | if (j > 0) and (j < GInt.Number[0]) then tmpFGInt.Number := copy(GInt.Number, j, GInt.Number[0] - j + 1); 2866 | tmpFGInt.Number[0] := GInt.Number[0] - j; 2867 | j := i mod 32; 2868 | if (j > 0) then FGIntShiftRightBy(tmpFGInt, j); 2869 | FGIntMul(tmpFGInt, invertedDivisor, QFGInt); 2870 | FGIntDestroy(tmpFGInt); 2871 | i := precision + 1; 2872 | if (i > 0) then FGIntShiftRightBy(QFGInt, i); 2873 | 2874 | FGIntMul(divisorFGInt, QFGInt, tmpFGInt); 2875 | FGIntDestroy(QFGInt); 2876 | FGIntSub(GInt, tmpFGInt, modFGInt); 2877 | FGIntDestroy(tmpFGInt); 2878 | 2879 | while not ((modFGInt.sign = positive) and (FGIntCompareAbs(modFGInt, divisorFGInt) = St)) do 2880 | begin 2881 | if (modFGInt.sign = negative) then 2882 | begin 2883 | FGIntAdd(modFGInt, divisorFGInt, tmpFGInt); 2884 | FGIntDestroy(modFGInt); 2885 | modFGInt := tmpFGInt; 2886 | end else 2887 | begin 2888 | FGIntSubBis(modFGInt, divisorFGInt); 2889 | end; 2890 | end; 2891 | end else 2892 | FGIntCopy(GInt, modFGInt); 2893 | end; 2894 | 2895 | 2896 | 2897 | 2898 | 2899 | // raise fGInt to the power fGIntN mod modFGInt, and return (fGInt ^ fGIntN) % modFGInt 2900 | 2901 | Procedure FGIntBarretModExp(Var FGInt, exp, modFGInt, res : TFGInt); 2902 | Var 2903 | tmpFGInt1, invertedDivisor, tmpFGInt : TFGInt; 2904 | i, j, precision, tmp : Longword; 2905 | // str : string; 2906 | Begin 2907 | precision := (modFGInt.Number[0] - 1) * 32; 2908 | for i := 0 to 31 do 2909 | if (modFGInt.Number[modFGInt.Number[0]] shr i) = 0 then break else precision := precision + 1; 2910 | 2911 | newtonInversion(modFGInt, precision, invertedDivisor); 2912 | FGIntCopy(FGInt, tmpFGInt1); 2913 | 2914 | Base2StringToFGInt('1', res); 2915 | 2916 | For i := 1 to exp.Number[0] - 1 do 2917 | begin 2918 | tmp := exp.Number[i]; 2919 | for j := 0 to 31 do 2920 | begin 2921 | if ((tmp shr j) and 1) = 1 then 2922 | begin 2923 | FGIntMul(res, tmpFGInt1, tmpFGInt); 2924 | FGIntDestroy(res); 2925 | FGIntBarrettModWithInvertedDivisorAndPrecision(tmpFGInt, modFGInt, invertedDivisor, precision, res); 2926 | FGIntDestroy(tmpFGInt); 2927 | end; 2928 | FGIntSquare(tmpFGInt1, tmpFGInt); 2929 | FGIntDestroy(tmpFGInt1); 2930 | FGIntBarrettModWithInvertedDivisorAndPrecision(tmpFGInt, modFGInt, invertedDivisor, precision, tmpFGInt1); 2931 | FGIntDestroy(tmpFGInt); 2932 | end; 2933 | end; 2934 | tmp := exp.Number[exp.Number[0]]; 2935 | for j := 0 to 31 do 2936 | begin 2937 | if ((tmp shr j) and 1) = 1 then 2938 | begin 2939 | FGIntMul(res, tmpFGInt1, tmpFGInt); 2940 | FGIntDestroy(res); 2941 | FGIntBarrettModWithInvertedDivisorAndPrecision(tmpFGInt, modFGInt, invertedDivisor, precision, res); 2942 | FGIntDestroy(tmpFGInt) 2943 | end; 2944 | FGIntSquare(tmpFGInt1, tmpFGInt); 2945 | FGIntDestroy(tmpFGInt1); 2946 | FGIntBarrettModWithInvertedDivisorAndPrecision(tmpFGInt, modFGInt, invertedDivisor, precision, tmpFGInt1); 2947 | FGIntDestroy(tmpFGInt); 2948 | end; 2949 | 2950 | FGIntDestroy(invertedDivisor); 2951 | FGIntDestroy(tmpFGInt1); 2952 | 2953 | End; 2954 | 2955 | 2956 | End. 2957 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FGInt 2 | ===== 3 | stands for Fast Gigantic Integers. 4 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | fpc test 3 | rm *.o *.ppu 4 | ./test 5 | rm test 6 | -------------------------------------------------------------------------------- /test.pp: -------------------------------------------------------------------------------- 1 | Program test101; 2 | 3 | {$H+}{$LongStrings ON} 4 | 5 | 6 | Uses SysUtils,DateUtils, FGInt; 7 | 8 | Var 9 | f1,f2,f3,f4,f5,f6,f7,f8,f9: TFGInt; 10 | t1,t2 : TDateTime; 11 | S, strIn, strOut, resultStr : String; 12 | i, j, treshold, time : longword; 13 | 14 | 15 | Begin 16 | writeln; 17 | 18 | writeln('- String conversion tests:'); 19 | 20 | strIn := '1234567890987654321'; 21 | Base10StringToFGInt(strIn, f1); 22 | FGIntToBase10String(f1, strOut); 23 | If strIn = strOut then resultStr := 'success' else resultStr := '! failed !'; 24 | Writeln(' Base10 conversion test: ' + resultStr); 25 | FGIntDestroy(f1); 26 | 27 | strIn := '11110000111100001010'; 28 | Base2StringToFGInt(strIn, f1); 29 | FGIntToBase2String(f1, strOut); 30 | If strIn = strOut then resultStr := 'success' else resultStr := '! failed !'; 31 | Writeln(' Base2 conversion test: ' + resultStr); 32 | FGIntDestroy(f1); 33 | 34 | strIn := '!R@C%YN)N^Q%Y{#$"NCRPDF$V%(qb[3Q5GW#|QCR$){W'; 35 | Base256StringToFGInt(strIn, f1); 36 | FGIntToBase256String(f1, strOut); 37 | If strIn = strOut then resultStr := 'success' else resultStr := '! failed !'; 38 | Writeln(' Base256 (byte string) conversion test: ' + resultStr); 39 | FGIntDestroy(f1); 40 | 41 | 42 | writeln('- Arithmetic tests:'); 43 | 44 | strIn := '12345678909876543210'; 45 | Base10StringToFGInt(strIn, f1); 46 | strIn := '100000000000000000001'; 47 | Base10StringToFGInt(strIn, f2); 48 | FGIntAdd(f1, f2, f3); 49 | FGIntSub(f3, f1, f4); 50 | If FGIntCompareAbs(f2, f4) = Eq then resultStr := 'success' else resultStr := '! failed !'; 51 | Writeln(' Addition/subtraction test: ' + resultStr); 52 | FGIntDestroy(f1); 53 | FGIntDestroy(f2); 54 | FGIntDestroy(f3); 55 | FGIntDestroy(f4); 56 | 57 | strIn := '1234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909'; 58 | Base10StringToFGInt(strIn, f1); 59 | strIn := '1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000000000000000'; 60 | Base10StringToFGInt(strIn, f2); 61 | FGIntPencilPaperMultiply(f1, f2, f3); 62 | FGIntKaratsubaMultiply(f1, f2, f4); 63 | If FGIntCompareAbs(f3, f4) = Eq then resultStr := 'success' else resultStr := '! failed !'; 64 | Writeln(' Multiplication test: ' + resultStr); 65 | FGIntDestroy(f1); 66 | FGIntDestroy(f2); 67 | FGIntDestroy(f3); 68 | FGIntDestroy(f4); 69 | 70 | strIn := '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'; 71 | Base2StringToFGInt(strIn, f1); 72 | FGIntPencilPaperSquare(f1, f2); 73 | // FGIntKaratsubaSquare(f1, f3); 74 | FGIntMul(f1, f1, f3); 75 | If FGIntCompareAbs(f2, f3) = Eq then resultStr := 'success' else resultStr := '! failed !'; 76 | Writeln(' Squaring test: ' + resultStr); 77 | FGIntDestroy(f1); 78 | FGIntDestroy(f2); 79 | FGIntDestroy(f3); 80 | 81 | // strIn := '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'; 82 | // Base2StringToFGInt(strIn, f1); 83 | // FGIntPencilPaperSquare(f1, f2); 84 | // FGIntToBase10String(f2, resultStr); 85 | // Writeln(' Squaring: ' + resultStr); 86 | // FGIntMul(f1, f1, f3); 87 | // FGIntToBase10String(f3, resultStr); 88 | // Writeln(' multipli: ' + resultStr); 89 | // If FGIntCompareAbs(f2, f3) = Eq then resultStr := 'success' else resultStr := '! failed !'; 90 | // Writeln(' Squaring test: ' + resultStr); 91 | // FGIntDestroy(f1); 92 | // FGIntDestroy(f2); 93 | // FGIntDestroy(f3); 94 | 95 | strIn := '1234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909'; 96 | Base10StringToFGInt(strIn, f1); 97 | strIn := '1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000003'; 98 | Base10StringToFGInt(strIn, f2); 99 | FGIntMul(f1, f2, f3); 100 | FGIntDivMod(f3, f2, f4, f5); 101 | If FGIntCompareAbs(f4, f1) = Eq then resultStr := 'success' else resultStr := '! failed !'; 102 | Writeln(' Division test: ' + resultStr); 103 | FGIntDestroy(f1); 104 | FGIntDestroy(f2); 105 | FGIntDestroy(f3); 106 | FGIntDestroy(f4); 107 | FGIntDestroy(f5); 108 | 109 | strIn := '123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789098765432101'; 110 | Base10StringToFGInt(strIn, f1); 111 | strIn := '1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000003'; 112 | Base10StringToFGInt(strIn, f2); 113 | FGIntDivMod(f1, f2, f3, f4); 114 | FGIntBarretDivMod(f1, f2, f5, f6); 115 | If FGIntCompareAbs(f3, f5) = Eq then resultStr := 'success' else resultStr := '! failed !'; 116 | Writeln(' Barret Division test: ' + resultStr); 117 | If FGIntCompareAbs(f4, f6) = Eq then resultStr := 'success' else resultStr := '! failed !'; 118 | Writeln(' Barret Remainder test: ' + resultStr); 119 | // FGIntToBase10String(f5, resultStr); 120 | // Writeln(' barret mod quotient test: ' + resultStr); 121 | // FGIntToBase10String(f3, resultStr); 122 | // Writeln(' Division mod quotient test: ' + resultStr); 123 | // FGIntToBase10String(f6, resultStr); 124 | // Writeln(' barret mod remainder test: ' + resultStr); 125 | // FGIntToBase10String(f4, resultStr); 126 | // Writeln(' Division mod remainder test: ' + resultStr); 127 | FGIntDestroy(f1); 128 | FGIntDestroy(f2); 129 | FGIntDestroy(f3); 130 | FGIntDestroy(f4); 131 | FGIntDestroy(f5); 132 | FGIntDestroy(f6); 133 | 134 | 135 | strIn := '123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789'; 136 | Base10StringToFGInt(strIn, f1); 137 | strIn := '1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000003'; 138 | Base10StringToFGInt(strIn, f2); 139 | strIn := '10000000000000555555555555555555555555000000000000000000000000000011000000000000008888888888888888880000000000000000000003'; 140 | Base10StringToFGInt(strIn, f3); 141 | FGIntModExp(f1, f3, f2, f4); 142 | FGIntBarretModExp(f1, f3, f2, f5); 143 | If FGIntCompareAbs(f4, f5) = Eq then resultStr := 'success' else resultStr := '! failed !'; 144 | Writeln(' Modular Exponentiation test: ' + resultStr); 145 | FGIntDestroy(f1); 146 | FGIntDestroy(f2); 147 | FGIntDestroy(f3); 148 | FGIntDestroy(f4); 149 | FGIntDestroy(f5); 150 | 151 | 152 | // exit; 153 | 154 | 155 | // strIn := '123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789123456789098765432101234567890987654321012345678909876543210123456789098765432101234567890987654321012345678909876543210123456789123456789098765432101234567890987654321'; 156 | // Base10StringToFGInt(strIn, f1); 157 | // strIn := ' 135066410865995223349603216278805969938881475605667027524485143851526510604859533833940287150571909441798207282164471551373680419703964191743046496589274256239341020864383202110372958725762358509643110564073501508187510676594629205563685529475213500852879416377328533906109750544334999811150056977236890927563'; 158 | // Base10StringToFGInt(strIn, f2); 159 | // strIn := '1000000000000055555555555555555555555500000000000000000000000000001100000000000000888888888888888888000000000000000000000310000000000000555555555555555555555555000000000000000000000000000011000000000000008888888888888888880000000000000000000003100000000000005555555555555555555555550000000000000000000000000'; 160 | // Base10StringToFGInt(strIn, f3); 161 | 162 | // t1 := Now; 163 | // for i := 1 to 50 Do 164 | // Begin 165 | // FGIntBarretModExp(f1, f3, f2, f5); 166 | // end; 167 | // t2 := Now; 168 | // // FGIntToBase10String(f3,S); 169 | // Writeln(' barret took '+inttostr(MilliSecondsBetween(t1,t2))+' milliseconds'); 170 | 171 | // t1 := Now; 172 | // for i := 1 to 50 Do 173 | // Begin 174 | // FGIntModExp(f1, f3, f2, f4); 175 | // end; 176 | // t2 := Now; 177 | // // FGIntToBase10String(f3,S); 178 | // Writeln(' montgomery took '+inttostr(MilliSecondsBetween(t1,t2))+' milliseconds'); 179 | 180 | 181 | // readln; 182 | 183 | End. 184 | --------------------------------------------------------------------------------