| | | 1 | | using System; |
| | | 2 | | using System.Text; |
| | | 3 | | |
| | | 4 | | using Renci.SshNet.Security.Org.BouncyCastle.Utilities; |
| | | 5 | | |
| | | 6 | | namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC |
| | | 7 | | { |
| | | 8 | | internal class LongArray |
| | | 9 | | { |
| | | 10 | | //private static long DEInterleave_MASK = 0x5555555555555555L; |
| | | 11 | | |
| | | 12 | | /* |
| | | 13 | | * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits. |
| | | 14 | | * In a binary field, this operation is the same as squaring an 8 bit number. |
| | | 15 | | */ |
| | 1 | 16 | | private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[] |
| | 1 | 17 | | { |
| | 1 | 18 | | 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, |
| | 1 | 19 | | 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, |
| | 1 | 20 | | 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, |
| | 1 | 21 | | 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, |
| | 1 | 22 | | 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, |
| | 1 | 23 | | 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, |
| | 1 | 24 | | 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, |
| | 1 | 25 | | 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, |
| | 1 | 26 | | 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, |
| | 1 | 27 | | 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, |
| | 1 | 28 | | 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, |
| | 1 | 29 | | 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, |
| | 1 | 30 | | 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, |
| | 1 | 31 | | 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, |
| | 1 | 32 | | 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, |
| | 1 | 33 | | 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, |
| | 1 | 34 | | 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, |
| | 1 | 35 | | 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, |
| | 1 | 36 | | 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, |
| | 1 | 37 | | 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, |
| | 1 | 38 | | 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, |
| | 1 | 39 | | 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, |
| | 1 | 40 | | 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, |
| | 1 | 41 | | 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, |
| | 1 | 42 | | 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, |
| | 1 | 43 | | 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, |
| | 1 | 44 | | 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, |
| | 1 | 45 | | 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, |
| | 1 | 46 | | 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, |
| | 1 | 47 | | 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, |
| | 1 | 48 | | 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, |
| | 1 | 49 | | 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 |
| | 1 | 50 | | }; |
| | | 51 | | |
| | | 52 | | /* |
| | | 53 | | * This expands 7 bit indices into 21 bit contents (high bit 18), by inserting 0s between bits. |
| | | 54 | | */ |
| | 1 | 55 | | private static readonly int[] INTERLEAVE3_TABLE = new int[] |
| | 1 | 56 | | { |
| | 1 | 57 | | 0x00000, 0x00001, 0x00008, 0x00009, 0x00040, 0x00041, 0x00048, 0x00049, |
| | 1 | 58 | | 0x00200, 0x00201, 0x00208, 0x00209, 0x00240, 0x00241, 0x00248, 0x00249, |
| | 1 | 59 | | 0x01000, 0x01001, 0x01008, 0x01009, 0x01040, 0x01041, 0x01048, 0x01049, |
| | 1 | 60 | | 0x01200, 0x01201, 0x01208, 0x01209, 0x01240, 0x01241, 0x01248, 0x01249, |
| | 1 | 61 | | 0x08000, 0x08001, 0x08008, 0x08009, 0x08040, 0x08041, 0x08048, 0x08049, |
| | 1 | 62 | | 0x08200, 0x08201, 0x08208, 0x08209, 0x08240, 0x08241, 0x08248, 0x08249, |
| | 1 | 63 | | 0x09000, 0x09001, 0x09008, 0x09009, 0x09040, 0x09041, 0x09048, 0x09049, |
| | 1 | 64 | | 0x09200, 0x09201, 0x09208, 0x09209, 0x09240, 0x09241, 0x09248, 0x09249, |
| | 1 | 65 | | 0x40000, 0x40001, 0x40008, 0x40009, 0x40040, 0x40041, 0x40048, 0x40049, |
| | 1 | 66 | | 0x40200, 0x40201, 0x40208, 0x40209, 0x40240, 0x40241, 0x40248, 0x40249, |
| | 1 | 67 | | 0x41000, 0x41001, 0x41008, 0x41009, 0x41040, 0x41041, 0x41048, 0x41049, |
| | 1 | 68 | | 0x41200, 0x41201, 0x41208, 0x41209, 0x41240, 0x41241, 0x41248, 0x41249, |
| | 1 | 69 | | 0x48000, 0x48001, 0x48008, 0x48009, 0x48040, 0x48041, 0x48048, 0x48049, |
| | 1 | 70 | | 0x48200, 0x48201, 0x48208, 0x48209, 0x48240, 0x48241, 0x48248, 0x48249, |
| | 1 | 71 | | 0x49000, 0x49001, 0x49008, 0x49009, 0x49040, 0x49041, 0x49048, 0x49049, |
| | 1 | 72 | | 0x49200, 0x49201, 0x49208, 0x49209, 0x49240, 0x49241, 0x49248, 0x49249 |
| | 1 | 73 | | }; |
| | | 74 | | |
| | | 75 | | /* |
| | | 76 | | * This expands 8 bit indices into 32 bit contents (high bit 28), by inserting 0s between bits. |
| | | 77 | | */ |
| | 1 | 78 | | private static readonly int[] INTERLEAVE4_TABLE = new int[] |
| | 1 | 79 | | { |
| | 1 | 80 | | 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 0x00000101, 0x00000110, 0x00000111, |
| | 1 | 81 | | 0x00001000, 0x00001001, 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 0x00001111, |
| | 1 | 82 | | 0x00010000, 0x00010001, 0x00010010, 0x00010011, 0x00010100, 0x00010101, 0x00010110, 0x00010111, |
| | 1 | 83 | | 0x00011000, 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, 0x00011110, 0x00011111, |
| | 1 | 84 | | 0x00100000, 0x00100001, 0x00100010, 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111, |
| | 1 | 85 | | 0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, 0x00101101, 0x00101110, 0x00101111, |
| | 1 | 86 | | 0x00110000, 0x00110001, 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, 0x00110111, |
| | 1 | 87 | | 0x00111000, 0x00111001, 0x00111010, 0x00111011, 0x00111100, 0x00111101, 0x00111110, 0x00111111, |
| | 1 | 88 | | 0x01000000, 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, 0x01000110, 0x01000111, |
| | 1 | 89 | | 0x01001000, 0x01001001, 0x01001010, 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111, |
| | 1 | 90 | | 0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, 0x01010101, 0x01010110, 0x01010111, |
| | 1 | 91 | | 0x01011000, 0x01011001, 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, 0x01011111, |
| | 1 | 92 | | 0x01100000, 0x01100001, 0x01100010, 0x01100011, 0x01100100, 0x01100101, 0x01100110, 0x01100111, |
| | 1 | 93 | | 0x01101000, 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, 0x01101110, 0x01101111, |
| | 1 | 94 | | 0x01110000, 0x01110001, 0x01110010, 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111, |
| | 1 | 95 | | 0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, 0x01111101, 0x01111110, 0x01111111, |
| | 1 | 96 | | 0x10000000, 0x10000001, 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, 0x10000111, |
| | 1 | 97 | | 0x10001000, 0x10001001, 0x10001010, 0x10001011, 0x10001100, 0x10001101, 0x10001110, 0x10001111, |
| | 1 | 98 | | 0x10010000, 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, 0x10010110, 0x10010111, |
| | 1 | 99 | | 0x10011000, 0x10011001, 0x10011010, 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111, |
| | 1 | 100 | | 0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, 0x10100101, 0x10100110, 0x10100111, |
| | 1 | 101 | | 0x10101000, 0x10101001, 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, 0x10101111, |
| | 1 | 102 | | 0x10110000, 0x10110001, 0x10110010, 0x10110011, 0x10110100, 0x10110101, 0x10110110, 0x10110111, |
| | 1 | 103 | | 0x10111000, 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, 0x10111110, 0x10111111, |
| | 1 | 104 | | 0x11000000, 0x11000001, 0x11000010, 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111, |
| | 1 | 105 | | 0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, 0x11001101, 0x11001110, 0x11001111, |
| | 1 | 106 | | 0x11010000, 0x11010001, 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, 0x11010111, |
| | 1 | 107 | | 0x11011000, 0x11011001, 0x11011010, 0x11011011, 0x11011100, 0x11011101, 0x11011110, 0x11011111, |
| | 1 | 108 | | 0x11100000, 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, 0x11100110, 0x11100111, |
| | 1 | 109 | | 0x11101000, 0x11101001, 0x11101010, 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111, |
| | 1 | 110 | | 0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, 0x11110101, 0x11110110, 0x11110111, |
| | 1 | 111 | | 0x11111000, 0x11111001, 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, 0x11111111 |
| | 1 | 112 | | }; |
| | | 113 | | |
| | | 114 | | /* |
| | | 115 | | * This expands 7 bit indices into 35 bit contents (high bit 30), by inserting 0s between bits. |
| | | 116 | | */ |
| | 1 | 117 | | private static readonly int[] INTERLEAVE5_TABLE = new int[] { |
| | 1 | 118 | | 0x00000000, 0x00000001, 0x00000020, 0x00000021, 0x00000400, 0x00000401, 0x00000420, 0x00000421, |
| | 1 | 119 | | 0x00008000, 0x00008001, 0x00008020, 0x00008021, 0x00008400, 0x00008401, 0x00008420, 0x00008421, |
| | 1 | 120 | | 0x00100000, 0x00100001, 0x00100020, 0x00100021, 0x00100400, 0x00100401, 0x00100420, 0x00100421, |
| | 1 | 121 | | 0x00108000, 0x00108001, 0x00108020, 0x00108021, 0x00108400, 0x00108401, 0x00108420, 0x00108421, |
| | 1 | 122 | | 0x02000000, 0x02000001, 0x02000020, 0x02000021, 0x02000400, 0x02000401, 0x02000420, 0x02000421, |
| | 1 | 123 | | 0x02008000, 0x02008001, 0x02008020, 0x02008021, 0x02008400, 0x02008401, 0x02008420, 0x02008421, |
| | 1 | 124 | | 0x02100000, 0x02100001, 0x02100020, 0x02100021, 0x02100400, 0x02100401, 0x02100420, 0x02100421, |
| | 1 | 125 | | 0x02108000, 0x02108001, 0x02108020, 0x02108021, 0x02108400, 0x02108401, 0x02108420, 0x02108421, |
| | 1 | 126 | | 0x40000000, 0x40000001, 0x40000020, 0x40000021, 0x40000400, 0x40000401, 0x40000420, 0x40000421, |
| | 1 | 127 | | 0x40008000, 0x40008001, 0x40008020, 0x40008021, 0x40008400, 0x40008401, 0x40008420, 0x40008421, |
| | 1 | 128 | | 0x40100000, 0x40100001, 0x40100020, 0x40100021, 0x40100400, 0x40100401, 0x40100420, 0x40100421, |
| | 1 | 129 | | 0x40108000, 0x40108001, 0x40108020, 0x40108021, 0x40108400, 0x40108401, 0x40108420, 0x40108421, |
| | 1 | 130 | | 0x42000000, 0x42000001, 0x42000020, 0x42000021, 0x42000400, 0x42000401, 0x42000420, 0x42000421, |
| | 1 | 131 | | 0x42008000, 0x42008001, 0x42008020, 0x42008021, 0x42008400, 0x42008401, 0x42008420, 0x42008421, |
| | 1 | 132 | | 0x42100000, 0x42100001, 0x42100020, 0x42100021, 0x42100400, 0x42100401, 0x42100420, 0x42100421, |
| | 1 | 133 | | 0x42108000, 0x42108001, 0x42108020, 0x42108021, 0x42108400, 0x42108401, 0x42108420, 0x42108421 |
| | 1 | 134 | | }; |
| | | 135 | | |
| | | 136 | | /* |
| | | 137 | | * This expands 9 bit indices into 63 bit (long) contents (high bit 56), by inserting 0s between bits. |
| | | 138 | | */ |
| | 1 | 139 | | private static readonly long[] INTERLEAVE7_TABLE = new long[] |
| | 1 | 140 | | { |
| | 1 | 141 | | 0x0000000000000000L, 0x0000000000000001L, 0x0000000000000080L, 0x0000000000000081L, |
| | 1 | 142 | | 0x0000000000004000L, 0x0000000000004001L, 0x0000000000004080L, 0x0000000000004081L, |
| | 1 | 143 | | 0x0000000000200000L, 0x0000000000200001L, 0x0000000000200080L, 0x0000000000200081L, |
| | 1 | 144 | | 0x0000000000204000L, 0x0000000000204001L, 0x0000000000204080L, 0x0000000000204081L, |
| | 1 | 145 | | 0x0000000010000000L, 0x0000000010000001L, 0x0000000010000080L, 0x0000000010000081L, |
| | 1 | 146 | | 0x0000000010004000L, 0x0000000010004001L, 0x0000000010004080L, 0x0000000010004081L, |
| | 1 | 147 | | 0x0000000010200000L, 0x0000000010200001L, 0x0000000010200080L, 0x0000000010200081L, |
| | 1 | 148 | | 0x0000000010204000L, 0x0000000010204001L, 0x0000000010204080L, 0x0000000010204081L, |
| | 1 | 149 | | 0x0000000800000000L, 0x0000000800000001L, 0x0000000800000080L, 0x0000000800000081L, |
| | 1 | 150 | | 0x0000000800004000L, 0x0000000800004001L, 0x0000000800004080L, 0x0000000800004081L, |
| | 1 | 151 | | 0x0000000800200000L, 0x0000000800200001L, 0x0000000800200080L, 0x0000000800200081L, |
| | 1 | 152 | | 0x0000000800204000L, 0x0000000800204001L, 0x0000000800204080L, 0x0000000800204081L, |
| | 1 | 153 | | 0x0000000810000000L, 0x0000000810000001L, 0x0000000810000080L, 0x0000000810000081L, |
| | 1 | 154 | | 0x0000000810004000L, 0x0000000810004001L, 0x0000000810004080L, 0x0000000810004081L, |
| | 1 | 155 | | 0x0000000810200000L, 0x0000000810200001L, 0x0000000810200080L, 0x0000000810200081L, |
| | 1 | 156 | | 0x0000000810204000L, 0x0000000810204001L, 0x0000000810204080L, 0x0000000810204081L, |
| | 1 | 157 | | 0x0000040000000000L, 0x0000040000000001L, 0x0000040000000080L, 0x0000040000000081L, |
| | 1 | 158 | | 0x0000040000004000L, 0x0000040000004001L, 0x0000040000004080L, 0x0000040000004081L, |
| | 1 | 159 | | 0x0000040000200000L, 0x0000040000200001L, 0x0000040000200080L, 0x0000040000200081L, |
| | 1 | 160 | | 0x0000040000204000L, 0x0000040000204001L, 0x0000040000204080L, 0x0000040000204081L, |
| | 1 | 161 | | 0x0000040010000000L, 0x0000040010000001L, 0x0000040010000080L, 0x0000040010000081L, |
| | 1 | 162 | | 0x0000040010004000L, 0x0000040010004001L, 0x0000040010004080L, 0x0000040010004081L, |
| | 1 | 163 | | 0x0000040010200000L, 0x0000040010200001L, 0x0000040010200080L, 0x0000040010200081L, |
| | 1 | 164 | | 0x0000040010204000L, 0x0000040010204001L, 0x0000040010204080L, 0x0000040010204081L, |
| | 1 | 165 | | 0x0000040800000000L, 0x0000040800000001L, 0x0000040800000080L, 0x0000040800000081L, |
| | 1 | 166 | | 0x0000040800004000L, 0x0000040800004001L, 0x0000040800004080L, 0x0000040800004081L, |
| | 1 | 167 | | 0x0000040800200000L, 0x0000040800200001L, 0x0000040800200080L, 0x0000040800200081L, |
| | 1 | 168 | | 0x0000040800204000L, 0x0000040800204001L, 0x0000040800204080L, 0x0000040800204081L, |
| | 1 | 169 | | 0x0000040810000000L, 0x0000040810000001L, 0x0000040810000080L, 0x0000040810000081L, |
| | 1 | 170 | | 0x0000040810004000L, 0x0000040810004001L, 0x0000040810004080L, 0x0000040810004081L, |
| | 1 | 171 | | 0x0000040810200000L, 0x0000040810200001L, 0x0000040810200080L, 0x0000040810200081L, |
| | 1 | 172 | | 0x0000040810204000L, 0x0000040810204001L, 0x0000040810204080L, 0x0000040810204081L, |
| | 1 | 173 | | 0x0002000000000000L, 0x0002000000000001L, 0x0002000000000080L, 0x0002000000000081L, |
| | 1 | 174 | | 0x0002000000004000L, 0x0002000000004001L, 0x0002000000004080L, 0x0002000000004081L, |
| | 1 | 175 | | 0x0002000000200000L, 0x0002000000200001L, 0x0002000000200080L, 0x0002000000200081L, |
| | 1 | 176 | | 0x0002000000204000L, 0x0002000000204001L, 0x0002000000204080L, 0x0002000000204081L, |
| | 1 | 177 | | 0x0002000010000000L, 0x0002000010000001L, 0x0002000010000080L, 0x0002000010000081L, |
| | 1 | 178 | | 0x0002000010004000L, 0x0002000010004001L, 0x0002000010004080L, 0x0002000010004081L, |
| | 1 | 179 | | 0x0002000010200000L, 0x0002000010200001L, 0x0002000010200080L, 0x0002000010200081L, |
| | 1 | 180 | | 0x0002000010204000L, 0x0002000010204001L, 0x0002000010204080L, 0x0002000010204081L, |
| | 1 | 181 | | 0x0002000800000000L, 0x0002000800000001L, 0x0002000800000080L, 0x0002000800000081L, |
| | 1 | 182 | | 0x0002000800004000L, 0x0002000800004001L, 0x0002000800004080L, 0x0002000800004081L, |
| | 1 | 183 | | 0x0002000800200000L, 0x0002000800200001L, 0x0002000800200080L, 0x0002000800200081L, |
| | 1 | 184 | | 0x0002000800204000L, 0x0002000800204001L, 0x0002000800204080L, 0x0002000800204081L, |
| | 1 | 185 | | 0x0002000810000000L, 0x0002000810000001L, 0x0002000810000080L, 0x0002000810000081L, |
| | 1 | 186 | | 0x0002000810004000L, 0x0002000810004001L, 0x0002000810004080L, 0x0002000810004081L, |
| | 1 | 187 | | 0x0002000810200000L, 0x0002000810200001L, 0x0002000810200080L, 0x0002000810200081L, |
| | 1 | 188 | | 0x0002000810204000L, 0x0002000810204001L, 0x0002000810204080L, 0x0002000810204081L, |
| | 1 | 189 | | 0x0002040000000000L, 0x0002040000000001L, 0x0002040000000080L, 0x0002040000000081L, |
| | 1 | 190 | | 0x0002040000004000L, 0x0002040000004001L, 0x0002040000004080L, 0x0002040000004081L, |
| | 1 | 191 | | 0x0002040000200000L, 0x0002040000200001L, 0x0002040000200080L, 0x0002040000200081L, |
| | 1 | 192 | | 0x0002040000204000L, 0x0002040000204001L, 0x0002040000204080L, 0x0002040000204081L, |
| | 1 | 193 | | 0x0002040010000000L, 0x0002040010000001L, 0x0002040010000080L, 0x0002040010000081L, |
| | 1 | 194 | | 0x0002040010004000L, 0x0002040010004001L, 0x0002040010004080L, 0x0002040010004081L, |
| | 1 | 195 | | 0x0002040010200000L, 0x0002040010200001L, 0x0002040010200080L, 0x0002040010200081L, |
| | 1 | 196 | | 0x0002040010204000L, 0x0002040010204001L, 0x0002040010204080L, 0x0002040010204081L, |
| | 1 | 197 | | 0x0002040800000000L, 0x0002040800000001L, 0x0002040800000080L, 0x0002040800000081L, |
| | 1 | 198 | | 0x0002040800004000L, 0x0002040800004001L, 0x0002040800004080L, 0x0002040800004081L, |
| | 1 | 199 | | 0x0002040800200000L, 0x0002040800200001L, 0x0002040800200080L, 0x0002040800200081L, |
| | 1 | 200 | | 0x0002040800204000L, 0x0002040800204001L, 0x0002040800204080L, 0x0002040800204081L, |
| | 1 | 201 | | 0x0002040810000000L, 0x0002040810000001L, 0x0002040810000080L, 0x0002040810000081L, |
| | 1 | 202 | | 0x0002040810004000L, 0x0002040810004001L, 0x0002040810004080L, 0x0002040810004081L, |
| | 1 | 203 | | 0x0002040810200000L, 0x0002040810200001L, 0x0002040810200080L, 0x0002040810200081L, |
| | 1 | 204 | | 0x0002040810204000L, 0x0002040810204001L, 0x0002040810204080L, 0x0002040810204081L, |
| | 1 | 205 | | 0x0100000000000000L, 0x0100000000000001L, 0x0100000000000080L, 0x0100000000000081L, |
| | 1 | 206 | | 0x0100000000004000L, 0x0100000000004001L, 0x0100000000004080L, 0x0100000000004081L, |
| | 1 | 207 | | 0x0100000000200000L, 0x0100000000200001L, 0x0100000000200080L, 0x0100000000200081L, |
| | 1 | 208 | | 0x0100000000204000L, 0x0100000000204001L, 0x0100000000204080L, 0x0100000000204081L, |
| | 1 | 209 | | 0x0100000010000000L, 0x0100000010000001L, 0x0100000010000080L, 0x0100000010000081L, |
| | 1 | 210 | | 0x0100000010004000L, 0x0100000010004001L, 0x0100000010004080L, 0x0100000010004081L, |
| | 1 | 211 | | 0x0100000010200000L, 0x0100000010200001L, 0x0100000010200080L, 0x0100000010200081L, |
| | 1 | 212 | | 0x0100000010204000L, 0x0100000010204001L, 0x0100000010204080L, 0x0100000010204081L, |
| | 1 | 213 | | 0x0100000800000000L, 0x0100000800000001L, 0x0100000800000080L, 0x0100000800000081L, |
| | 1 | 214 | | 0x0100000800004000L, 0x0100000800004001L, 0x0100000800004080L, 0x0100000800004081L, |
| | 1 | 215 | | 0x0100000800200000L, 0x0100000800200001L, 0x0100000800200080L, 0x0100000800200081L, |
| | 1 | 216 | | 0x0100000800204000L, 0x0100000800204001L, 0x0100000800204080L, 0x0100000800204081L, |
| | 1 | 217 | | 0x0100000810000000L, 0x0100000810000001L, 0x0100000810000080L, 0x0100000810000081L, |
| | 1 | 218 | | 0x0100000810004000L, 0x0100000810004001L, 0x0100000810004080L, 0x0100000810004081L, |
| | 1 | 219 | | 0x0100000810200000L, 0x0100000810200001L, 0x0100000810200080L, 0x0100000810200081L, |
| | 1 | 220 | | 0x0100000810204000L, 0x0100000810204001L, 0x0100000810204080L, 0x0100000810204081L, |
| | 1 | 221 | | 0x0100040000000000L, 0x0100040000000001L, 0x0100040000000080L, 0x0100040000000081L, |
| | 1 | 222 | | 0x0100040000004000L, 0x0100040000004001L, 0x0100040000004080L, 0x0100040000004081L, |
| | 1 | 223 | | 0x0100040000200000L, 0x0100040000200001L, 0x0100040000200080L, 0x0100040000200081L, |
| | 1 | 224 | | 0x0100040000204000L, 0x0100040000204001L, 0x0100040000204080L, 0x0100040000204081L, |
| | 1 | 225 | | 0x0100040010000000L, 0x0100040010000001L, 0x0100040010000080L, 0x0100040010000081L, |
| | 1 | 226 | | 0x0100040010004000L, 0x0100040010004001L, 0x0100040010004080L, 0x0100040010004081L, |
| | 1 | 227 | | 0x0100040010200000L, 0x0100040010200001L, 0x0100040010200080L, 0x0100040010200081L, |
| | 1 | 228 | | 0x0100040010204000L, 0x0100040010204001L, 0x0100040010204080L, 0x0100040010204081L, |
| | 1 | 229 | | 0x0100040800000000L, 0x0100040800000001L, 0x0100040800000080L, 0x0100040800000081L, |
| | 1 | 230 | | 0x0100040800004000L, 0x0100040800004001L, 0x0100040800004080L, 0x0100040800004081L, |
| | 1 | 231 | | 0x0100040800200000L, 0x0100040800200001L, 0x0100040800200080L, 0x0100040800200081L, |
| | 1 | 232 | | 0x0100040800204000L, 0x0100040800204001L, 0x0100040800204080L, 0x0100040800204081L, |
| | 1 | 233 | | 0x0100040810000000L, 0x0100040810000001L, 0x0100040810000080L, 0x0100040810000081L, |
| | 1 | 234 | | 0x0100040810004000L, 0x0100040810004001L, 0x0100040810004080L, 0x0100040810004081L, |
| | 1 | 235 | | 0x0100040810200000L, 0x0100040810200001L, 0x0100040810200080L, 0x0100040810200081L, |
| | 1 | 236 | | 0x0100040810204000L, 0x0100040810204001L, 0x0100040810204080L, 0x0100040810204081L, |
| | 1 | 237 | | 0x0102000000000000L, 0x0102000000000001L, 0x0102000000000080L, 0x0102000000000081L, |
| | 1 | 238 | | 0x0102000000004000L, 0x0102000000004001L, 0x0102000000004080L, 0x0102000000004081L, |
| | 1 | 239 | | 0x0102000000200000L, 0x0102000000200001L, 0x0102000000200080L, 0x0102000000200081L, |
| | 1 | 240 | | 0x0102000000204000L, 0x0102000000204001L, 0x0102000000204080L, 0x0102000000204081L, |
| | 1 | 241 | | 0x0102000010000000L, 0x0102000010000001L, 0x0102000010000080L, 0x0102000010000081L, |
| | 1 | 242 | | 0x0102000010004000L, 0x0102000010004001L, 0x0102000010004080L, 0x0102000010004081L, |
| | 1 | 243 | | 0x0102000010200000L, 0x0102000010200001L, 0x0102000010200080L, 0x0102000010200081L, |
| | 1 | 244 | | 0x0102000010204000L, 0x0102000010204001L, 0x0102000010204080L, 0x0102000010204081L, |
| | 1 | 245 | | 0x0102000800000000L, 0x0102000800000001L, 0x0102000800000080L, 0x0102000800000081L, |
| | 1 | 246 | | 0x0102000800004000L, 0x0102000800004001L, 0x0102000800004080L, 0x0102000800004081L, |
| | 1 | 247 | | 0x0102000800200000L, 0x0102000800200001L, 0x0102000800200080L, 0x0102000800200081L, |
| | 1 | 248 | | 0x0102000800204000L, 0x0102000800204001L, 0x0102000800204080L, 0x0102000800204081L, |
| | 1 | 249 | | 0x0102000810000000L, 0x0102000810000001L, 0x0102000810000080L, 0x0102000810000081L, |
| | 1 | 250 | | 0x0102000810004000L, 0x0102000810004001L, 0x0102000810004080L, 0x0102000810004081L, |
| | 1 | 251 | | 0x0102000810200000L, 0x0102000810200001L, 0x0102000810200080L, 0x0102000810200081L, |
| | 1 | 252 | | 0x0102000810204000L, 0x0102000810204001L, 0x0102000810204080L, 0x0102000810204081L, |
| | 1 | 253 | | 0x0102040000000000L, 0x0102040000000001L, 0x0102040000000080L, 0x0102040000000081L, |
| | 1 | 254 | | 0x0102040000004000L, 0x0102040000004001L, 0x0102040000004080L, 0x0102040000004081L, |
| | 1 | 255 | | 0x0102040000200000L, 0x0102040000200001L, 0x0102040000200080L, 0x0102040000200081L, |
| | 1 | 256 | | 0x0102040000204000L, 0x0102040000204001L, 0x0102040000204080L, 0x0102040000204081L, |
| | 1 | 257 | | 0x0102040010000000L, 0x0102040010000001L, 0x0102040010000080L, 0x0102040010000081L, |
| | 1 | 258 | | 0x0102040010004000L, 0x0102040010004001L, 0x0102040010004080L, 0x0102040010004081L, |
| | 1 | 259 | | 0x0102040010200000L, 0x0102040010200001L, 0x0102040010200080L, 0x0102040010200081L, |
| | 1 | 260 | | 0x0102040010204000L, 0x0102040010204001L, 0x0102040010204080L, 0x0102040010204081L, |
| | 1 | 261 | | 0x0102040800000000L, 0x0102040800000001L, 0x0102040800000080L, 0x0102040800000081L, |
| | 1 | 262 | | 0x0102040800004000L, 0x0102040800004001L, 0x0102040800004080L, 0x0102040800004081L, |
| | 1 | 263 | | 0x0102040800200000L, 0x0102040800200001L, 0x0102040800200080L, 0x0102040800200081L, |
| | 1 | 264 | | 0x0102040800204000L, 0x0102040800204001L, 0x0102040800204080L, 0x0102040800204081L, |
| | 1 | 265 | | 0x0102040810000000L, 0x0102040810000001L, 0x0102040810000080L, 0x0102040810000081L, |
| | 1 | 266 | | 0x0102040810004000L, 0x0102040810004001L, 0x0102040810004080L, 0x0102040810004081L, |
| | 1 | 267 | | 0x0102040810200000L, 0x0102040810200001L, 0x0102040810200080L, 0x0102040810200081L, |
| | 1 | 268 | | 0x0102040810204000L, 0x0102040810204001L, 0x0102040810204080L, 0x0102040810204081L |
| | 1 | 269 | | }; |
| | | 270 | | |
| | | 271 | | // For toString(); must have length 64 |
| | | 272 | | private const string ZEROES = "0000000000000000000000000000000000000000000000000000000000000000"; |
| | | 273 | | |
| | 1 | 274 | | internal static readonly byte[] BitLengths = |
| | 1 | 275 | | { |
| | 1 | 276 | | 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, |
| | 1 | 277 | | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
| | 1 | 278 | | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| | 1 | 279 | | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| | 1 | 280 | | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| | 1 | 281 | | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| | 1 | 282 | | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| | 1 | 283 | | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
| | 1 | 284 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
| | 1 | 285 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
| | 1 | 286 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
| | 1 | 287 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
| | 1 | 288 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
| | 1 | 289 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
| | 1 | 290 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, |
| | 1 | 291 | | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 |
| | 1 | 292 | | }; |
| | | 293 | | |
| | | 294 | | // TODO make m fixed for the LongArray, and hence compute T once and for all |
| | | 295 | | |
| | | 296 | | private long[] m_ints; |
| | | 297 | | |
| | 0 | 298 | | public LongArray(int intLen) |
| | 0 | 299 | | { |
| | 0 | 300 | | m_ints = new long[intLen]; |
| | 0 | 301 | | } |
| | | 302 | | |
| | 0 | 303 | | public LongArray(long[] ints) |
| | 0 | 304 | | { |
| | 0 | 305 | | m_ints = ints; |
| | 0 | 306 | | } |
| | | 307 | | |
| | 0 | 308 | | public LongArray(long[] ints, int off, int len) |
| | 0 | 309 | | { |
| | 0 | 310 | | if (off == 0 && len == ints.Length) |
| | 0 | 311 | | { |
| | 0 | 312 | | m_ints = ints; |
| | 0 | 313 | | } |
| | | 314 | | else |
| | 0 | 315 | | { |
| | 0 | 316 | | m_ints = new long[len]; |
| | 0 | 317 | | Array.Copy(ints, off, m_ints, 0, len); |
| | 0 | 318 | | } |
| | 0 | 319 | | } |
| | | 320 | | |
| | 0 | 321 | | public LongArray(BigInteger bigInt) |
| | 0 | 322 | | { |
| | 0 | 323 | | if (bigInt == null || bigInt.SignValue < 0) |
| | 0 | 324 | | { |
| | 0 | 325 | | throw new ArgumentException("invalid F2m field value", "bigInt"); |
| | | 326 | | } |
| | | 327 | | |
| | 0 | 328 | | if (bigInt.SignValue == 0) |
| | 0 | 329 | | { |
| | 0 | 330 | | m_ints = new long[] { 0L }; |
| | 0 | 331 | | return; |
| | | 332 | | } |
| | | 333 | | |
| | 0 | 334 | | byte[] barr = bigInt.ToByteArray(); |
| | 0 | 335 | | int barrLen = barr.Length; |
| | 0 | 336 | | int barrStart = 0; |
| | 0 | 337 | | if (barr[0] == 0) |
| | 0 | 338 | | { |
| | | 339 | | // First byte is 0 to enforce highest (=sign) bit is zero. |
| | | 340 | | // In this case ignore barr[0]. |
| | 0 | 341 | | barrLen--; |
| | 0 | 342 | | barrStart = 1; |
| | 0 | 343 | | } |
| | 0 | 344 | | int intLen = (barrLen + 7) / 8; |
| | 0 | 345 | | m_ints = new long[intLen]; |
| | | 346 | | |
| | 0 | 347 | | int iarrJ = intLen - 1; |
| | 0 | 348 | | int rem = barrLen % 8 + barrStart; |
| | 0 | 349 | | long temp = 0; |
| | 0 | 350 | | int barrI = barrStart; |
| | 0 | 351 | | if (barrStart < rem) |
| | 0 | 352 | | { |
| | 0 | 353 | | for (; barrI < rem; barrI++) |
| | 0 | 354 | | { |
| | 0 | 355 | | temp <<= 8; |
| | 0 | 356 | | uint barrBarrI = barr[barrI]; |
| | 0 | 357 | | temp |= barrBarrI; |
| | 0 | 358 | | } |
| | 0 | 359 | | m_ints[iarrJ--] = temp; |
| | 0 | 360 | | } |
| | | 361 | | |
| | 0 | 362 | | for (; iarrJ >= 0; iarrJ--) |
| | 0 | 363 | | { |
| | 0 | 364 | | temp = 0; |
| | 0 | 365 | | for (int i = 0; i < 8; i++) |
| | 0 | 366 | | { |
| | 0 | 367 | | temp <<= 8; |
| | 0 | 368 | | uint barrBarrI = barr[barrI++]; |
| | 0 | 369 | | temp |= barrBarrI; |
| | 0 | 370 | | } |
| | 0 | 371 | | m_ints[iarrJ] = temp; |
| | 0 | 372 | | } |
| | 0 | 373 | | } |
| | | 374 | | |
| | | 375 | | internal void CopyTo(long[] z, int zOff) |
| | 0 | 376 | | { |
| | 0 | 377 | | Array.Copy(m_ints, 0, z, zOff, m_ints.Length); |
| | 0 | 378 | | } |
| | | 379 | | |
| | | 380 | | public bool IsOne() |
| | 0 | 381 | | { |
| | 0 | 382 | | long[] a = m_ints; |
| | 0 | 383 | | if (a[0] != 1L) |
| | 0 | 384 | | { |
| | 0 | 385 | | return false; |
| | | 386 | | } |
| | 0 | 387 | | for (int i = 1; i < a.Length; ++i) |
| | 0 | 388 | | { |
| | 0 | 389 | | if (a[i] != 0L) |
| | 0 | 390 | | { |
| | 0 | 391 | | return false; |
| | | 392 | | } |
| | 0 | 393 | | } |
| | 0 | 394 | | return true; |
| | 0 | 395 | | } |
| | | 396 | | |
| | | 397 | | public bool IsZero() |
| | 0 | 398 | | { |
| | 0 | 399 | | long[] a = m_ints; |
| | 0 | 400 | | for (int i = 0; i < a.Length; ++i) |
| | 0 | 401 | | { |
| | 0 | 402 | | if (a[i] != 0L) |
| | 0 | 403 | | { |
| | 0 | 404 | | return false; |
| | | 405 | | } |
| | 0 | 406 | | } |
| | 0 | 407 | | return true; |
| | 0 | 408 | | } |
| | | 409 | | |
| | | 410 | | public int GetUsedLength() |
| | 0 | 411 | | { |
| | 0 | 412 | | return GetUsedLengthFrom(m_ints.Length); |
| | 0 | 413 | | } |
| | | 414 | | |
| | | 415 | | public int GetUsedLengthFrom(int from) |
| | 0 | 416 | | { |
| | 0 | 417 | | long[] a = m_ints; |
| | 0 | 418 | | from = System.Math.Min(from, a.Length); |
| | | 419 | | |
| | 0 | 420 | | if (from < 1) |
| | 0 | 421 | | { |
| | 0 | 422 | | return 0; |
| | | 423 | | } |
| | | 424 | | |
| | | 425 | | // Check if first element will act as sentinel |
| | 0 | 426 | | if (a[0] != 0) |
| | 0 | 427 | | { |
| | 0 | 428 | | while (a[--from] == 0) |
| | 0 | 429 | | { |
| | 0 | 430 | | } |
| | 0 | 431 | | return from + 1; |
| | | 432 | | } |
| | | 433 | | |
| | | 434 | | do |
| | 0 | 435 | | { |
| | 0 | 436 | | if (a[--from] != 0) |
| | 0 | 437 | | { |
| | 0 | 438 | | return from + 1; |
| | | 439 | | } |
| | 0 | 440 | | } |
| | 0 | 441 | | while (from > 0); |
| | | 442 | | |
| | 0 | 443 | | return 0; |
| | 0 | 444 | | } |
| | | 445 | | |
| | | 446 | | public int Degree() |
| | 0 | 447 | | { |
| | 0 | 448 | | int i = m_ints.Length; |
| | | 449 | | long w; |
| | | 450 | | do |
| | 0 | 451 | | { |
| | 0 | 452 | | if (i == 0) |
| | 0 | 453 | | { |
| | 0 | 454 | | return 0; |
| | | 455 | | } |
| | 0 | 456 | | w = m_ints[--i]; |
| | 0 | 457 | | } |
| | 0 | 458 | | while (w == 0); |
| | | 459 | | |
| | 0 | 460 | | return (i << 6) + BitLength(w); |
| | 0 | 461 | | } |
| | | 462 | | |
| | | 463 | | private int DegreeFrom(int limit) |
| | 0 | 464 | | { |
| | 0 | 465 | | int i = (int)(((uint)limit + 62) >> 6); |
| | | 466 | | long w; |
| | | 467 | | do |
| | 0 | 468 | | { |
| | 0 | 469 | | if (i == 0) |
| | 0 | 470 | | { |
| | 0 | 471 | | return 0; |
| | | 472 | | } |
| | 0 | 473 | | w = m_ints[--i]; |
| | 0 | 474 | | } |
| | 0 | 475 | | while (w == 0); |
| | | 476 | | |
| | 0 | 477 | | return (i << 6) + BitLength(w); |
| | 0 | 478 | | } |
| | | 479 | | |
| | | 480 | | // private int lowestCoefficient() |
| | | 481 | | // { |
| | | 482 | | // for (int i = 0; i < m_ints.Length; ++i) |
| | | 483 | | // { |
| | | 484 | | // long mi = m_ints[i]; |
| | | 485 | | // if (mi != 0) |
| | | 486 | | // { |
| | | 487 | | // int j = 0; |
| | | 488 | | // while ((mi & 0xFFL) == 0) |
| | | 489 | | // { |
| | | 490 | | // j += 8; |
| | | 491 | | // mi >>>= 8; |
| | | 492 | | // } |
| | | 493 | | // while ((mi & 1L) == 0) |
| | | 494 | | // { |
| | | 495 | | // ++j; |
| | | 496 | | // mi >>>= 1; |
| | | 497 | | // } |
| | | 498 | | // return (i << 6) + j; |
| | | 499 | | // } |
| | | 500 | | // } |
| | | 501 | | // return -1; |
| | | 502 | | // } |
| | | 503 | | |
| | | 504 | | private static int BitLength(long w) |
| | 0 | 505 | | { |
| | 0 | 506 | | int u = (int)((ulong)w >> 32), b; |
| | 0 | 507 | | if (u == 0) |
| | 0 | 508 | | { |
| | 0 | 509 | | u = (int)w; |
| | 0 | 510 | | b = 0; |
| | 0 | 511 | | } |
| | | 512 | | else |
| | 0 | 513 | | { |
| | 0 | 514 | | b = 32; |
| | 0 | 515 | | } |
| | | 516 | | |
| | 0 | 517 | | int t = (int)((uint)u >> 16), k; |
| | 0 | 518 | | if (t == 0) |
| | 0 | 519 | | { |
| | 0 | 520 | | t = (int)((uint)u >> 8); |
| | 0 | 521 | | k = (t == 0) ? BitLengths[u] : 8 + BitLengths[t]; |
| | 0 | 522 | | } |
| | | 523 | | else |
| | 0 | 524 | | { |
| | 0 | 525 | | int v = (int)((uint)t >> 8); |
| | 0 | 526 | | k = (v == 0) ? 16 + BitLengths[t] : 24 + BitLengths[v]; |
| | 0 | 527 | | } |
| | | 528 | | |
| | 0 | 529 | | return b + k; |
| | 0 | 530 | | } |
| | | 531 | | |
| | | 532 | | private long[] ResizedInts(int newLen) |
| | 0 | 533 | | { |
| | 0 | 534 | | long[] newInts = new long[newLen]; |
| | 0 | 535 | | Array.Copy(m_ints, 0, newInts, 0, System.Math.Min(m_ints.Length, newLen)); |
| | 0 | 536 | | return newInts; |
| | 0 | 537 | | } |
| | | 538 | | |
| | | 539 | | public BigInteger ToBigInteger() |
| | 0 | 540 | | { |
| | 0 | 541 | | int usedLen = GetUsedLength(); |
| | 0 | 542 | | if (usedLen == 0) |
| | 0 | 543 | | { |
| | 0 | 544 | | return BigInteger.Zero; |
| | | 545 | | } |
| | | 546 | | |
| | 0 | 547 | | long highestInt = m_ints[usedLen - 1]; |
| | 0 | 548 | | byte[] temp = new byte[8]; |
| | 0 | 549 | | int barrI = 0; |
| | 0 | 550 | | bool trailingZeroBytesDone = false; |
| | 0 | 551 | | for (int j = 7; j >= 0; j--) |
| | 0 | 552 | | { |
| | 0 | 553 | | byte thisByte = (byte)((ulong)highestInt >> (8 * j)); |
| | 0 | 554 | | if (trailingZeroBytesDone || (thisByte != 0)) |
| | 0 | 555 | | { |
| | 0 | 556 | | trailingZeroBytesDone = true; |
| | 0 | 557 | | temp[barrI++] = thisByte; |
| | 0 | 558 | | } |
| | 0 | 559 | | } |
| | | 560 | | |
| | 0 | 561 | | int barrLen = 8 * (usedLen - 1) + barrI; |
| | 0 | 562 | | byte[] barr = new byte[barrLen]; |
| | 0 | 563 | | for (int j = 0; j < barrI; j++) |
| | 0 | 564 | | { |
| | 0 | 565 | | barr[j] = temp[j]; |
| | 0 | 566 | | } |
| | | 567 | | // Highest value int is done now |
| | | 568 | | |
| | 0 | 569 | | for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--) |
| | 0 | 570 | | { |
| | 0 | 571 | | long mi = m_ints[iarrJ]; |
| | 0 | 572 | | for (int j = 7; j >= 0; j--) |
| | 0 | 573 | | { |
| | 0 | 574 | | barr[barrI++] = (byte)((ulong)mi >> (8 * j)); |
| | 0 | 575 | | } |
| | 0 | 576 | | } |
| | 0 | 577 | | return new BigInteger(1, barr); |
| | 0 | 578 | | } |
| | | 579 | | |
| | | 580 | | // private static long shiftUp(long[] x, int xOff, int count) |
| | | 581 | | // { |
| | | 582 | | // long prev = 0; |
| | | 583 | | // for (int i = 0; i < count; ++i) |
| | | 584 | | // { |
| | | 585 | | // long next = x[xOff + i]; |
| | | 586 | | // x[xOff + i] = (next << 1) | prev; |
| | | 587 | | // prev = next >>> 63; |
| | | 588 | | // } |
| | | 589 | | // return prev; |
| | | 590 | | // } |
| | | 591 | | |
| | | 592 | | private static long ShiftUp(long[] x, int xOff, int count, int shift) |
| | 0 | 593 | | { |
| | 0 | 594 | | int shiftInv = 64 - shift; |
| | 0 | 595 | | long prev = 0; |
| | 0 | 596 | | for (int i = 0; i < count; ++i) |
| | 0 | 597 | | { |
| | 0 | 598 | | long next = x[xOff + i]; |
| | 0 | 599 | | x[xOff + i] = (next << shift) | prev; |
| | 0 | 600 | | prev = (long)((ulong)next >> shiftInv); |
| | 0 | 601 | | } |
| | 0 | 602 | | return prev; |
| | 0 | 603 | | } |
| | | 604 | | |
| | | 605 | | private static long ShiftUp(long[] x, int xOff, long[] z, int zOff, int count, int shift) |
| | 0 | 606 | | { |
| | 0 | 607 | | int shiftInv = 64 - shift; |
| | 0 | 608 | | long prev = 0; |
| | 0 | 609 | | for (int i = 0; i < count; ++i) |
| | 0 | 610 | | { |
| | 0 | 611 | | long next = x[xOff + i]; |
| | 0 | 612 | | z[zOff + i] = (next << shift) | prev; |
| | 0 | 613 | | prev = (long)((ulong)next >> shiftInv); |
| | 0 | 614 | | } |
| | 0 | 615 | | return prev; |
| | 0 | 616 | | } |
| | | 617 | | |
| | | 618 | | public LongArray AddOne() |
| | 0 | 619 | | { |
| | 0 | 620 | | if (m_ints.Length == 0) |
| | 0 | 621 | | { |
| | 0 | 622 | | return new LongArray(new long[]{ 1L }); |
| | | 623 | | } |
| | | 624 | | |
| | 0 | 625 | | int resultLen = System.Math.Max(1, GetUsedLength()); |
| | 0 | 626 | | long[] ints = ResizedInts(resultLen); |
| | 0 | 627 | | ints[0] ^= 1L; |
| | 0 | 628 | | return new LongArray(ints); |
| | 0 | 629 | | } |
| | | 630 | | |
| | | 631 | | // private void addShiftedByBits(LongArray other, int bits) |
| | | 632 | | // { |
| | | 633 | | // int words = bits >>> 6; |
| | | 634 | | // int shift = bits & 0x3F; |
| | | 635 | | // |
| | | 636 | | // if (shift == 0) |
| | | 637 | | // { |
| | | 638 | | // addShiftedByWords(other, words); |
| | | 639 | | // return; |
| | | 640 | | // } |
| | | 641 | | // |
| | | 642 | | // int otherUsedLen = other.GetUsedLength(); |
| | | 643 | | // if (otherUsedLen == 0) |
| | | 644 | | // { |
| | | 645 | | // return; |
| | | 646 | | // } |
| | | 647 | | // |
| | | 648 | | // int minLen = otherUsedLen + words + 1; |
| | | 649 | | // if (minLen > m_ints.Length) |
| | | 650 | | // { |
| | | 651 | | // m_ints = resizedInts(minLen); |
| | | 652 | | // } |
| | | 653 | | // |
| | | 654 | | // long carry = addShiftedByBits(m_ints, words, other.m_ints, 0, otherUsedLen, shift); |
| | | 655 | | // m_ints[otherUsedLen + words] ^= carry; |
| | | 656 | | // } |
| | | 657 | | |
| | | 658 | | private void AddShiftedByBitsSafe(LongArray other, int otherDegree, int bits) |
| | 0 | 659 | | { |
| | 0 | 660 | | int otherLen = (int)((uint)(otherDegree + 63) >> 6); |
| | | 661 | | |
| | 0 | 662 | | int words = (int)((uint)bits >> 6); |
| | 0 | 663 | | int shift = bits & 0x3F; |
| | | 664 | | |
| | 0 | 665 | | if (shift == 0) |
| | 0 | 666 | | { |
| | 0 | 667 | | Add(m_ints, words, other.m_ints, 0, otherLen); |
| | 0 | 668 | | return; |
| | | 669 | | } |
| | | 670 | | |
| | 0 | 671 | | long carry = AddShiftedUp(m_ints, words, other.m_ints, 0, otherLen, shift); |
| | 0 | 672 | | if (carry != 0L) |
| | 0 | 673 | | { |
| | 0 | 674 | | m_ints[otherLen + words] ^= carry; |
| | 0 | 675 | | } |
| | 0 | 676 | | } |
| | | 677 | | |
| | | 678 | | private static long AddShiftedUp(long[] x, int xOff, long[] y, int yOff, int count, int shift) |
| | 0 | 679 | | { |
| | 0 | 680 | | int shiftInv = 64 - shift; |
| | 0 | 681 | | long prev = 0; |
| | 0 | 682 | | for (int i = 0; i < count; ++i) |
| | 0 | 683 | | { |
| | 0 | 684 | | long next = y[yOff + i]; |
| | 0 | 685 | | x[xOff + i] ^= (next << shift) | prev; |
| | 0 | 686 | | prev = (long)((ulong)next >> shiftInv); |
| | 0 | 687 | | } |
| | 0 | 688 | | return prev; |
| | 0 | 689 | | } |
| | | 690 | | |
| | | 691 | | private static long AddShiftedDown(long[] x, int xOff, long[] y, int yOff, int count, int shift) |
| | 0 | 692 | | { |
| | 0 | 693 | | int shiftInv = 64 - shift; |
| | 0 | 694 | | long prev = 0; |
| | 0 | 695 | | int i = count; |
| | 0 | 696 | | while (--i >= 0) |
| | 0 | 697 | | { |
| | 0 | 698 | | long next = y[yOff + i]; |
| | 0 | 699 | | x[xOff + i] ^= (long)((ulong)next >> shift) | prev; |
| | 0 | 700 | | prev = next << shiftInv; |
| | 0 | 701 | | } |
| | 0 | 702 | | return prev; |
| | 0 | 703 | | } |
| | | 704 | | |
| | | 705 | | public void AddShiftedByWords(LongArray other, int words) |
| | 0 | 706 | | { |
| | 0 | 707 | | int otherUsedLen = other.GetUsedLength(); |
| | 0 | 708 | | if (otherUsedLen == 0) |
| | 0 | 709 | | { |
| | 0 | 710 | | return; |
| | | 711 | | } |
| | | 712 | | |
| | 0 | 713 | | int minLen = otherUsedLen + words; |
| | 0 | 714 | | if (minLen > m_ints.Length) |
| | 0 | 715 | | { |
| | 0 | 716 | | m_ints = ResizedInts(minLen); |
| | 0 | 717 | | } |
| | | 718 | | |
| | 0 | 719 | | Add(m_ints, words, other.m_ints, 0, otherUsedLen); |
| | 0 | 720 | | } |
| | | 721 | | |
| | | 722 | | private static void Add(long[] x, int xOff, long[] y, int yOff, int count) |
| | 0 | 723 | | { |
| | 0 | 724 | | for (int i = 0; i < count; ++i) |
| | 0 | 725 | | { |
| | 0 | 726 | | x[xOff + i] ^= y[yOff + i]; |
| | 0 | 727 | | } |
| | 0 | 728 | | } |
| | | 729 | | |
| | | 730 | | private static void Add(long[] x, int xOff, long[] y, int yOff, long[] z, int zOff, int count) |
| | 0 | 731 | | { |
| | 0 | 732 | | for (int i = 0; i < count; ++i) |
| | 0 | 733 | | { |
| | 0 | 734 | | z[zOff + i] = x[xOff + i] ^ y[yOff + i]; |
| | 0 | 735 | | } |
| | 0 | 736 | | } |
| | | 737 | | |
| | | 738 | | private static void AddBoth(long[] x, int xOff, long[] y1, int y1Off, long[] y2, int y2Off, int count) |
| | 0 | 739 | | { |
| | 0 | 740 | | for (int i = 0; i < count; ++i) |
| | 0 | 741 | | { |
| | 0 | 742 | | x[xOff + i] ^= y1[y1Off + i] ^ y2[y2Off + i]; |
| | 0 | 743 | | } |
| | 0 | 744 | | } |
| | | 745 | | |
| | | 746 | | private static void Distribute(long[] x, int src, int dst1, int dst2, int count) |
| | 0 | 747 | | { |
| | 0 | 748 | | for (int i = 0; i < count; ++i) |
| | 0 | 749 | | { |
| | 0 | 750 | | long v = x[src + i]; |
| | 0 | 751 | | x[dst1 + i] ^= v; |
| | 0 | 752 | | x[dst2 + i] ^= v; |
| | 0 | 753 | | } |
| | 0 | 754 | | } |
| | | 755 | | |
| | | 756 | | public int Length |
| | | 757 | | { |
| | 0 | 758 | | get { return m_ints.Length; } |
| | | 759 | | } |
| | | 760 | | |
| | | 761 | | private static void FlipWord(long[] buf, int off, int bit, long word) |
| | 0 | 762 | | { |
| | 0 | 763 | | int n = off + (int)((uint)bit >> 6); |
| | 0 | 764 | | int shift = bit & 0x3F; |
| | 0 | 765 | | if (shift == 0) |
| | 0 | 766 | | { |
| | 0 | 767 | | buf[n] ^= word; |
| | 0 | 768 | | } |
| | | 769 | | else |
| | 0 | 770 | | { |
| | 0 | 771 | | buf[n] ^= word << shift; |
| | 0 | 772 | | word = (long)((ulong)word >> (64 - shift)); |
| | 0 | 773 | | if (word != 0) |
| | 0 | 774 | | { |
| | 0 | 775 | | buf[++n] ^= word; |
| | 0 | 776 | | } |
| | 0 | 777 | | } |
| | 0 | 778 | | } |
| | | 779 | | |
| | | 780 | | // private static long getWord(long[] buf, int off, int len, int bit) |
| | | 781 | | // { |
| | | 782 | | // int n = off + (bit >>> 6); |
| | | 783 | | // int shift = bit & 0x3F; |
| | | 784 | | // if (shift == 0) |
| | | 785 | | // { |
| | | 786 | | // return buf[n]; |
| | | 787 | | // } |
| | | 788 | | // long result = buf[n] >>> shift; |
| | | 789 | | // if (++n < len) |
| | | 790 | | // { |
| | | 791 | | // result |= buf[n] << (64 - shift); |
| | | 792 | | // } |
| | | 793 | | // return result; |
| | | 794 | | // } |
| | | 795 | | |
| | | 796 | | public bool TestBitZero() |
| | 0 | 797 | | { |
| | 0 | 798 | | return m_ints.Length > 0 && (m_ints[0] & 1L) != 0; |
| | 0 | 799 | | } |
| | | 800 | | |
| | | 801 | | private static bool TestBit(long[] buf, int off, int n) |
| | 0 | 802 | | { |
| | | 803 | | // theInt = n / 64 |
| | 0 | 804 | | int theInt = (int)((uint)n >> 6); |
| | | 805 | | // theBit = n % 64 |
| | 0 | 806 | | int theBit = n & 0x3F; |
| | 0 | 807 | | long tester = 1L << theBit; |
| | 0 | 808 | | return (buf[off + theInt] & tester) != 0; |
| | 0 | 809 | | } |
| | | 810 | | |
| | | 811 | | private static void FlipBit(long[] buf, int off, int n) |
| | 0 | 812 | | { |
| | | 813 | | // theInt = n / 64 |
| | 0 | 814 | | int theInt = (int)((uint)n >> 6); |
| | | 815 | | // theBit = n % 64 |
| | 0 | 816 | | int theBit = n & 0x3F; |
| | 0 | 817 | | long flipper = 1L << theBit; |
| | 0 | 818 | | buf[off + theInt] ^= flipper; |
| | 0 | 819 | | } |
| | | 820 | | |
| | | 821 | | // private static void SetBit(long[] buf, int off, int n) |
| | | 822 | | // { |
| | | 823 | | // // theInt = n / 64 |
| | | 824 | | // int theInt = n >>> 6; |
| | | 825 | | // // theBit = n % 64 |
| | | 826 | | // int theBit = n & 0x3F; |
| | | 827 | | // long setter = 1L << theBit; |
| | | 828 | | // buf[off + theInt] |= setter; |
| | | 829 | | // } |
| | | 830 | | // |
| | | 831 | | // private static void ClearBit(long[] buf, int off, int n) |
| | | 832 | | // { |
| | | 833 | | // // theInt = n / 64 |
| | | 834 | | // int theInt = n >>> 6; |
| | | 835 | | // // theBit = n % 64 |
| | | 836 | | // int theBit = n & 0x3F; |
| | | 837 | | // long setter = 1L << theBit; |
| | | 838 | | // buf[off + theInt] &= ~setter; |
| | | 839 | | // } |
| | | 840 | | |
| | | 841 | | private static void MultiplyWord(long a, long[] b, int bLen, long[] c, int cOff) |
| | 0 | 842 | | { |
| | 0 | 843 | | if ((a & 1L) != 0L) |
| | 0 | 844 | | { |
| | 0 | 845 | | Add(c, cOff, b, 0, bLen); |
| | 0 | 846 | | } |
| | 0 | 847 | | int k = 1; |
| | 0 | 848 | | while ((a = (long)((ulong)a >> 1)) != 0L) |
| | 0 | 849 | | { |
| | 0 | 850 | | if ((a & 1L) != 0L) |
| | 0 | 851 | | { |
| | 0 | 852 | | long carry = AddShiftedUp(c, cOff, b, 0, bLen, k); |
| | 0 | 853 | | if (carry != 0L) |
| | 0 | 854 | | { |
| | 0 | 855 | | c[cOff + bLen] ^= carry; |
| | 0 | 856 | | } |
| | 0 | 857 | | } |
| | 0 | 858 | | ++k; |
| | 0 | 859 | | } |
| | 0 | 860 | | } |
| | | 861 | | |
| | | 862 | | public LongArray ModMultiplyLD(LongArray other, int m, int[] ks) |
| | 0 | 863 | | { |
| | | 864 | | /* |
| | | 865 | | * Find out the degree of each argument and handle the zero cases |
| | | 866 | | */ |
| | 0 | 867 | | int aDeg = Degree(); |
| | 0 | 868 | | if (aDeg == 0) |
| | 0 | 869 | | { |
| | 0 | 870 | | return this; |
| | | 871 | | } |
| | 0 | 872 | | int bDeg = other.Degree(); |
| | 0 | 873 | | if (bDeg == 0) |
| | 0 | 874 | | { |
| | 0 | 875 | | return other; |
| | | 876 | | } |
| | | 877 | | |
| | | 878 | | /* |
| | | 879 | | * Swap if necessary so that A is the smaller argument |
| | | 880 | | */ |
| | 0 | 881 | | LongArray A = this, B = other; |
| | 0 | 882 | | if (aDeg > bDeg) |
| | 0 | 883 | | { |
| | 0 | 884 | | A = other; B = this; |
| | 0 | 885 | | int tmp = aDeg; aDeg = bDeg; bDeg = tmp; |
| | 0 | 886 | | } |
| | | 887 | | |
| | | 888 | | /* |
| | | 889 | | * Establish the word lengths of the arguments and result |
| | | 890 | | */ |
| | 0 | 891 | | int aLen = (int)((uint)(aDeg + 63) >> 6); |
| | 0 | 892 | | int bLen = (int)((uint)(bDeg + 63) >> 6); |
| | 0 | 893 | | int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); |
| | | 894 | | |
| | 0 | 895 | | if (aLen == 1) |
| | 0 | 896 | | { |
| | 0 | 897 | | long a0 = A.m_ints[0]; |
| | 0 | 898 | | if (a0 == 1L) |
| | 0 | 899 | | { |
| | 0 | 900 | | return B; |
| | | 901 | | } |
| | | 902 | | |
| | | 903 | | /* |
| | | 904 | | * Fast path for small A, with performance dependent only on the number of set bits |
| | | 905 | | */ |
| | 0 | 906 | | long[] c0 = new long[cLen]; |
| | 0 | 907 | | MultiplyWord(a0, B.m_ints, bLen, c0, 0); |
| | | 908 | | |
| | | 909 | | /* |
| | | 910 | | * Reduce the raw answer against the reduction coefficients |
| | | 911 | | */ |
| | 0 | 912 | | return ReduceResult(c0, 0, cLen, m, ks); |
| | | 913 | | } |
| | | 914 | | |
| | | 915 | | /* |
| | | 916 | | * Determine if B will get bigger during shifting |
| | | 917 | | */ |
| | 0 | 918 | | int bMax = (int)((uint)(bDeg + 7 + 63) >> 6); |
| | | 919 | | |
| | | 920 | | /* |
| | | 921 | | * Lookup table for the offset of each B in the tables |
| | | 922 | | */ |
| | 0 | 923 | | int[] ti = new int[16]; |
| | | 924 | | |
| | | 925 | | /* |
| | | 926 | | * Precompute table of all 4-bit products of B |
| | | 927 | | */ |
| | 0 | 928 | | long[] T0 = new long[bMax << 4]; |
| | 0 | 929 | | int tOff = bMax; |
| | 0 | 930 | | ti[1] = tOff; |
| | 0 | 931 | | Array.Copy(B.m_ints, 0, T0, tOff, bLen); |
| | 0 | 932 | | for (int i = 2; i < 16; ++i) |
| | 0 | 933 | | { |
| | 0 | 934 | | ti[i] = (tOff += bMax); |
| | 0 | 935 | | if ((i & 1) == 0) |
| | 0 | 936 | | { |
| | 0 | 937 | | ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1); |
| | 0 | 938 | | } |
| | | 939 | | else |
| | 0 | 940 | | { |
| | 0 | 941 | | Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); |
| | 0 | 942 | | } |
| | 0 | 943 | | } |
| | | 944 | | |
| | | 945 | | /* |
| | | 946 | | * Second table with all 4-bit products of B shifted 4 bits |
| | | 947 | | */ |
| | 0 | 948 | | long[] T1 = new long[T0.Length]; |
| | 0 | 949 | | ShiftUp(T0, 0, T1, 0, T0.Length, 4); |
| | | 950 | | // shiftUp(T0, bMax, T1, bMax, tOff, 4); |
| | | 951 | | |
| | 0 | 952 | | long[] a = A.m_ints; |
| | 0 | 953 | | long[] c = new long[cLen]; |
| | | 954 | | |
| | 0 | 955 | | int MASK = 0xF; |
| | | 956 | | |
| | | 957 | | /* |
| | | 958 | | * Lopez-Dahab algorithm |
| | | 959 | | */ |
| | | 960 | | |
| | 0 | 961 | | for (int k = 56; k >= 0; k -= 8) |
| | 0 | 962 | | { |
| | 0 | 963 | | for (int j = 1; j < aLen; j += 2) |
| | 0 | 964 | | { |
| | 0 | 965 | | int aVal = (int)((ulong)a[j] >> k); |
| | 0 | 966 | | int u = aVal & MASK; |
| | 0 | 967 | | int v = (int)((uint)aVal >> 4) & MASK; |
| | 0 | 968 | | AddBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax); |
| | 0 | 969 | | } |
| | 0 | 970 | | ShiftUp(c, 0, cLen, 8); |
| | 0 | 971 | | } |
| | | 972 | | |
| | 0 | 973 | | for (int k = 56; k >= 0; k -= 8) |
| | 0 | 974 | | { |
| | 0 | 975 | | for (int j = 0; j < aLen; j += 2) |
| | 0 | 976 | | { |
| | 0 | 977 | | int aVal = (int)((ulong)a[j] >> k); |
| | 0 | 978 | | int u = aVal & MASK; |
| | 0 | 979 | | int v = (int)((uint)aVal >> 4) & MASK; |
| | 0 | 980 | | AddBoth(c, j, T0, ti[u], T1, ti[v], bMax); |
| | 0 | 981 | | } |
| | 0 | 982 | | if (k > 0) |
| | 0 | 983 | | { |
| | 0 | 984 | | ShiftUp(c, 0, cLen, 8); |
| | 0 | 985 | | } |
| | 0 | 986 | | } |
| | | 987 | | |
| | | 988 | | /* |
| | | 989 | | * Finally the raw answer is collected, reduce it against the reduction coefficients |
| | | 990 | | */ |
| | 0 | 991 | | return ReduceResult(c, 0, cLen, m, ks); |
| | 0 | 992 | | } |
| | | 993 | | |
| | | 994 | | public LongArray ModMultiply(LongArray other, int m, int[] ks) |
| | 0 | 995 | | { |
| | | 996 | | /* |
| | | 997 | | * Find out the degree of each argument and handle the zero cases |
| | | 998 | | */ |
| | 0 | 999 | | int aDeg = Degree(); |
| | 0 | 1000 | | if (aDeg == 0) |
| | 0 | 1001 | | { |
| | 0 | 1002 | | return this; |
| | | 1003 | | } |
| | 0 | 1004 | | int bDeg = other.Degree(); |
| | 0 | 1005 | | if (bDeg == 0) |
| | 0 | 1006 | | { |
| | 0 | 1007 | | return other; |
| | | 1008 | | } |
| | | 1009 | | |
| | | 1010 | | /* |
| | | 1011 | | * Swap if necessary so that A is the smaller argument |
| | | 1012 | | */ |
| | 0 | 1013 | | LongArray A = this, B = other; |
| | 0 | 1014 | | if (aDeg > bDeg) |
| | 0 | 1015 | | { |
| | 0 | 1016 | | A = other; B = this; |
| | 0 | 1017 | | int tmp = aDeg; aDeg = bDeg; bDeg = tmp; |
| | 0 | 1018 | | } |
| | | 1019 | | |
| | | 1020 | | /* |
| | | 1021 | | * Establish the word lengths of the arguments and result |
| | | 1022 | | */ |
| | 0 | 1023 | | int aLen = (int)((uint)(aDeg + 63) >> 6); |
| | 0 | 1024 | | int bLen = (int)((uint)(bDeg + 63) >> 6); |
| | 0 | 1025 | | int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); |
| | | 1026 | | |
| | 0 | 1027 | | if (aLen == 1) |
| | 0 | 1028 | | { |
| | 0 | 1029 | | long a0 = A.m_ints[0]; |
| | 0 | 1030 | | if (a0 == 1L) |
| | 0 | 1031 | | { |
| | 0 | 1032 | | return B; |
| | | 1033 | | } |
| | | 1034 | | |
| | | 1035 | | /* |
| | | 1036 | | * Fast path for small A, with performance dependent only on the number of set bits |
| | | 1037 | | */ |
| | 0 | 1038 | | long[] c0 = new long[cLen]; |
| | 0 | 1039 | | MultiplyWord(a0, B.m_ints, bLen, c0, 0); |
| | | 1040 | | |
| | | 1041 | | /* |
| | | 1042 | | * Reduce the raw answer against the reduction coefficients |
| | | 1043 | | */ |
| | 0 | 1044 | | return ReduceResult(c0, 0, cLen, m, ks); |
| | | 1045 | | } |
| | | 1046 | | |
| | | 1047 | | /* |
| | | 1048 | | * Determine if B will get bigger during shifting |
| | | 1049 | | */ |
| | 0 | 1050 | | int bMax = (int)((uint)(bDeg + 7 + 63) >> 6); |
| | | 1051 | | |
| | | 1052 | | /* |
| | | 1053 | | * Lookup table for the offset of each B in the tables |
| | | 1054 | | */ |
| | 0 | 1055 | | int[] ti = new int[16]; |
| | | 1056 | | |
| | | 1057 | | /* |
| | | 1058 | | * Precompute table of all 4-bit products of B |
| | | 1059 | | */ |
| | 0 | 1060 | | long[] T0 = new long[bMax << 4]; |
| | 0 | 1061 | | int tOff = bMax; |
| | 0 | 1062 | | ti[1] = tOff; |
| | 0 | 1063 | | Array.Copy(B.m_ints, 0, T0, tOff, bLen); |
| | 0 | 1064 | | for (int i = 2; i < 16; ++i) |
| | 0 | 1065 | | { |
| | 0 | 1066 | | ti[i] = (tOff += bMax); |
| | 0 | 1067 | | if ((i & 1) == 0) |
| | 0 | 1068 | | { |
| | 0 | 1069 | | ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1); |
| | 0 | 1070 | | } |
| | | 1071 | | else |
| | 0 | 1072 | | { |
| | 0 | 1073 | | Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); |
| | 0 | 1074 | | } |
| | 0 | 1075 | | } |
| | | 1076 | | |
| | | 1077 | | /* |
| | | 1078 | | * Second table with all 4-bit products of B shifted 4 bits |
| | | 1079 | | */ |
| | 0 | 1080 | | long[] T1 = new long[T0.Length]; |
| | 0 | 1081 | | ShiftUp(T0, 0, T1, 0, T0.Length, 4); |
| | | 1082 | | // ShiftUp(T0, bMax, T1, bMax, tOff, 4); |
| | | 1083 | | |
| | 0 | 1084 | | long[] a = A.m_ints; |
| | 0 | 1085 | | long[] c = new long[cLen << 3]; |
| | | 1086 | | |
| | 0 | 1087 | | int MASK = 0xF; |
| | | 1088 | | |
| | | 1089 | | /* |
| | | 1090 | | * Lopez-Dahab (Modified) algorithm |
| | | 1091 | | */ |
| | | 1092 | | |
| | 0 | 1093 | | for (int aPos = 0; aPos < aLen; ++aPos) |
| | 0 | 1094 | | { |
| | 0 | 1095 | | long aVal = a[aPos]; |
| | 0 | 1096 | | int cOff = aPos; |
| | | 1097 | | for (;;) |
| | 0 | 1098 | | { |
| | 0 | 1099 | | int u = (int)aVal & MASK; |
| | 0 | 1100 | | aVal = (long)((ulong)aVal >> 4); |
| | 0 | 1101 | | int v = (int)aVal & MASK; |
| | 0 | 1102 | | AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); |
| | 0 | 1103 | | aVal = (long)((ulong)aVal >> 4); |
| | 0 | 1104 | | if (aVal == 0L) |
| | 0 | 1105 | | { |
| | 0 | 1106 | | break; |
| | | 1107 | | } |
| | 0 | 1108 | | cOff += cLen; |
| | 0 | 1109 | | } |
| | 0 | 1110 | | } |
| | | 1111 | | |
| | 0 | 1112 | | { |
| | 0 | 1113 | | int cOff = c.Length; |
| | 0 | 1114 | | while ((cOff -= cLen) != 0) |
| | 0 | 1115 | | { |
| | 0 | 1116 | | AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); |
| | 0 | 1117 | | } |
| | 0 | 1118 | | } |
| | | 1119 | | |
| | | 1120 | | /* |
| | | 1121 | | * Finally the raw answer is collected, reduce it against the reduction coefficients |
| | | 1122 | | */ |
| | 0 | 1123 | | return ReduceResult(c, 0, cLen, m, ks); |
| | 0 | 1124 | | } |
| | | 1125 | | |
| | | 1126 | | public LongArray ModMultiplyAlt(LongArray other, int m, int[] ks) |
| | 0 | 1127 | | { |
| | | 1128 | | /* |
| | | 1129 | | * Find out the degree of each argument and handle the zero cases |
| | | 1130 | | */ |
| | 0 | 1131 | | int aDeg = Degree(); |
| | 0 | 1132 | | if (aDeg == 0) |
| | 0 | 1133 | | { |
| | 0 | 1134 | | return this; |
| | | 1135 | | } |
| | 0 | 1136 | | int bDeg = other.Degree(); |
| | 0 | 1137 | | if (bDeg == 0) |
| | 0 | 1138 | | { |
| | 0 | 1139 | | return other; |
| | | 1140 | | } |
| | | 1141 | | |
| | | 1142 | | /* |
| | | 1143 | | * Swap if necessary so that A is the smaller argument |
| | | 1144 | | */ |
| | 0 | 1145 | | LongArray A = this, B = other; |
| | 0 | 1146 | | if (aDeg > bDeg) |
| | 0 | 1147 | | { |
| | 0 | 1148 | | A = other; B = this; |
| | 0 | 1149 | | int tmp = aDeg; aDeg = bDeg; bDeg = tmp; |
| | 0 | 1150 | | } |
| | | 1151 | | |
| | | 1152 | | /* |
| | | 1153 | | * Establish the word lengths of the arguments and result |
| | | 1154 | | */ |
| | 0 | 1155 | | int aLen = (int)((uint)(aDeg + 63) >> 6); |
| | 0 | 1156 | | int bLen = (int)((uint)(bDeg + 63) >> 6); |
| | 0 | 1157 | | int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); |
| | | 1158 | | |
| | 0 | 1159 | | if (aLen == 1) |
| | 0 | 1160 | | { |
| | 0 | 1161 | | long a0 = A.m_ints[0]; |
| | 0 | 1162 | | if (a0 == 1L) |
| | 0 | 1163 | | { |
| | 0 | 1164 | | return B; |
| | | 1165 | | } |
| | | 1166 | | |
| | | 1167 | | /* |
| | | 1168 | | * Fast path for small A, with performance dependent only on the number of set bits |
| | | 1169 | | */ |
| | 0 | 1170 | | long[] c0 = new long[cLen]; |
| | 0 | 1171 | | MultiplyWord(a0, B.m_ints, bLen, c0, 0); |
| | | 1172 | | |
| | | 1173 | | /* |
| | | 1174 | | * Reduce the raw answer against the reduction coefficients |
| | | 1175 | | */ |
| | 0 | 1176 | | return ReduceResult(c0, 0, cLen, m, ks); |
| | | 1177 | | } |
| | | 1178 | | |
| | | 1179 | | // NOTE: This works, but is slower than width 4 processing |
| | | 1180 | | // if (aLen == 2) |
| | | 1181 | | // { |
| | | 1182 | | // /* |
| | | 1183 | | // * Use common-multiplicand optimization to save ~1/4 of the adds |
| | | 1184 | | // */ |
| | | 1185 | | // long a1 = A.m_ints[0], a2 = A.m_ints[1]; |
| | | 1186 | | // long aa = a1 & a2; a1 ^= aa; a2 ^= aa; |
| | | 1187 | | // |
| | | 1188 | | // long[] b = B.m_ints; |
| | | 1189 | | // long[] c = new long[cLen]; |
| | | 1190 | | // multiplyWord(aa, b, bLen, c, 1); |
| | | 1191 | | // add(c, 0, c, 1, cLen - 1); |
| | | 1192 | | // multiplyWord(a1, b, bLen, c, 0); |
| | | 1193 | | // multiplyWord(a2, b, bLen, c, 1); |
| | | 1194 | | // |
| | | 1195 | | // /* |
| | | 1196 | | // * Reduce the raw answer against the reduction coefficients |
| | | 1197 | | // */ |
| | | 1198 | | // return ReduceResult(c, 0, cLen, m, ks); |
| | | 1199 | | // } |
| | | 1200 | | |
| | | 1201 | | /* |
| | | 1202 | | * Determine the parameters of the Interleaved window algorithm: the 'width' in bits to |
| | | 1203 | | * process together, the number of evaluation 'positions' implied by that width, and the |
| | | 1204 | | * 'top' position at which the regular window algorithm stops. |
| | | 1205 | | */ |
| | | 1206 | | int width, positions, top, banks; |
| | | 1207 | | |
| | | 1208 | | // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto |
| | | 1209 | | // width = 1; positions = 64; top = 64; banks = 4; |
| | | 1210 | | // width = 2; positions = 32; top = 64; banks = 4; |
| | | 1211 | | // width = 3; positions = 21; top = 63; banks = 3; |
| | 0 | 1212 | | width = 4; positions = 16; top = 64; banks = 8; |
| | | 1213 | | // width = 5; positions = 13; top = 65; banks = 7; |
| | | 1214 | | // width = 7; positions = 9; top = 63; banks = 9; |
| | | 1215 | | // width = 8; positions = 8; top = 64; banks = 8; |
| | | 1216 | | |
| | | 1217 | | /* |
| | | 1218 | | * Determine if B will get bigger during shifting |
| | | 1219 | | */ |
| | 0 | 1220 | | int shifts = top < 64 ? positions : positions - 1; |
| | 0 | 1221 | | int bMax = (int)((uint)(bDeg + shifts + 63) >> 6); |
| | | 1222 | | |
| | 0 | 1223 | | int bTotal = bMax * banks, stride = width * banks; |
| | | 1224 | | |
| | | 1225 | | /* |
| | | 1226 | | * Create a single temporary buffer, with an offset table to find the positions of things in it |
| | | 1227 | | */ |
| | 0 | 1228 | | int[] ci = new int[1 << width]; |
| | 0 | 1229 | | int cTotal = aLen; |
| | 0 | 1230 | | { |
| | 0 | 1231 | | ci[0] = cTotal; |
| | 0 | 1232 | | cTotal += bTotal; |
| | 0 | 1233 | | ci[1] = cTotal; |
| | 0 | 1234 | | for (int i = 2; i < ci.Length; ++i) |
| | 0 | 1235 | | { |
| | 0 | 1236 | | cTotal += cLen; |
| | 0 | 1237 | | ci[i] = cTotal; |
| | 0 | 1238 | | } |
| | 0 | 1239 | | cTotal += cLen; |
| | 0 | 1240 | | } |
| | | 1241 | | // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen' |
| | 0 | 1242 | | ++cTotal; |
| | | 1243 | | |
| | 0 | 1244 | | long[] c = new long[cTotal]; |
| | | 1245 | | |
| | | 1246 | | // Prepare A in Interleaved form, according to the chosen width |
| | 0 | 1247 | | Interleave(A.m_ints, 0, c, 0, aLen, width); |
| | | 1248 | | |
| | | 1249 | | // Make a working copy of B, since we will be shifting it |
| | 0 | 1250 | | { |
| | 0 | 1251 | | int bOff = aLen; |
| | 0 | 1252 | | Array.Copy(B.m_ints, 0, c, bOff, bLen); |
| | 0 | 1253 | | for (int bank = 1; bank < banks; ++bank) |
| | 0 | 1254 | | { |
| | 0 | 1255 | | ShiftUp(c, aLen, c, bOff += bMax, bMax, bank); |
| | 0 | 1256 | | } |
| | 0 | 1257 | | } |
| | | 1258 | | |
| | | 1259 | | /* |
| | | 1260 | | * The main loop analyzes the Interleaved windows in A, and for each non-zero window |
| | | 1261 | | * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is |
| | | 1262 | | * breadth-first, checking the lowest window in each word, then looping again for the |
| | | 1263 | | * next higher window position. |
| | | 1264 | | */ |
| | 0 | 1265 | | int MASK = (1 << width) - 1; |
| | | 1266 | | |
| | 0 | 1267 | | int k = 0; |
| | | 1268 | | for (;;) |
| | 0 | 1269 | | { |
| | 0 | 1270 | | int aPos = 0; |
| | | 1271 | | do |
| | 0 | 1272 | | { |
| | 0 | 1273 | | long aVal = (long)((ulong)c[aPos] >> k); |
| | 0 | 1274 | | int bank = 0, bOff = aLen; |
| | | 1275 | | for (;;) |
| | 0 | 1276 | | { |
| | 0 | 1277 | | int index = (int)(aVal) & MASK; |
| | 0 | 1278 | | if (index != 0) |
| | 0 | 1279 | | { |
| | | 1280 | | /* |
| | | 1281 | | * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in |
| | | 1282 | | * Interleaved form, the bits represent the current B shifted by 0, 'positions', |
| | | 1283 | | * 'positions' * 2, ..., 'positions' * ('width' - 1) |
| | | 1284 | | */ |
| | 0 | 1285 | | Add(c, aPos + ci[index], c, bOff, bMax); |
| | 0 | 1286 | | } |
| | 0 | 1287 | | if (++bank == banks) |
| | 0 | 1288 | | { |
| | 0 | 1289 | | break; |
| | | 1290 | | } |
| | 0 | 1291 | | bOff += bMax; |
| | 0 | 1292 | | aVal = (long)((ulong)aVal >> width); |
| | 0 | 1293 | | } |
| | 0 | 1294 | | } |
| | 0 | 1295 | | while (++aPos < aLen); |
| | | 1296 | | |
| | 0 | 1297 | | if ((k += stride) >= top) |
| | 0 | 1298 | | { |
| | 0 | 1299 | | if (k >= 64) |
| | 0 | 1300 | | { |
| | 0 | 1301 | | break; |
| | | 1302 | | } |
| | | 1303 | | |
| | | 1304 | | /* |
| | | 1305 | | * Adjustment for window setups with top == 63, the final bit (if any) is processed |
| | | 1306 | | * as the top-bit of a window |
| | | 1307 | | */ |
| | 0 | 1308 | | k = 64 - width; |
| | 0 | 1309 | | MASK &= MASK << (top - k); |
| | 0 | 1310 | | } |
| | | 1311 | | |
| | | 1312 | | /* |
| | | 1313 | | * After each position has been checked for all words of A, B is shifted up 1 place |
| | | 1314 | | */ |
| | 0 | 1315 | | ShiftUp(c, aLen, bTotal, banks); |
| | 0 | 1316 | | } |
| | | 1317 | | |
| | 0 | 1318 | | int ciPos = ci.Length; |
| | 0 | 1319 | | while (--ciPos > 1) |
| | 0 | 1320 | | { |
| | 0 | 1321 | | if ((ciPos & 1L) == 0L) |
| | 0 | 1322 | | { |
| | | 1323 | | /* |
| | | 1324 | | * For even numbers, shift contents and add to the half-position |
| | | 1325 | | */ |
| | 0 | 1326 | | AddShiftedUp(c, ci[(uint)ciPos >> 1], c, ci[ciPos], cLen, positions); |
| | 0 | 1327 | | } |
| | | 1328 | | else |
| | 0 | 1329 | | { |
| | | 1330 | | /* |
| | | 1331 | | * For odd numbers, 'distribute' contents to the result and the next-lowest position |
| | | 1332 | | */ |
| | 0 | 1333 | | Distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen); |
| | 0 | 1334 | | } |
| | 0 | 1335 | | } |
| | | 1336 | | |
| | | 1337 | | /* |
| | | 1338 | | * Finally the raw answer is collected, reduce it against the reduction coefficients |
| | | 1339 | | */ |
| | 0 | 1340 | | return ReduceResult(c, ci[1], cLen, m, ks); |
| | 0 | 1341 | | } |
| | | 1342 | | |
| | | 1343 | | public LongArray ModReduce(int m, int[] ks) |
| | 0 | 1344 | | { |
| | 0 | 1345 | | long[] buf = Arrays.Clone(m_ints); |
| | 0 | 1346 | | int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks); |
| | 0 | 1347 | | return new LongArray(buf, 0, rLen); |
| | 0 | 1348 | | } |
| | | 1349 | | |
| | | 1350 | | public LongArray Multiply(LongArray other, int m, int[] ks) |
| | 0 | 1351 | | { |
| | | 1352 | | /* |
| | | 1353 | | * Find out the degree of each argument and handle the zero cases |
| | | 1354 | | */ |
| | 0 | 1355 | | int aDeg = Degree(); |
| | 0 | 1356 | | if (aDeg == 0) |
| | 0 | 1357 | | { |
| | 0 | 1358 | | return this; |
| | | 1359 | | } |
| | 0 | 1360 | | int bDeg = other.Degree(); |
| | 0 | 1361 | | if (bDeg == 0) |
| | 0 | 1362 | | { |
| | 0 | 1363 | | return other; |
| | | 1364 | | } |
| | | 1365 | | |
| | | 1366 | | /* |
| | | 1367 | | * Swap if necessary so that A is the smaller argument |
| | | 1368 | | */ |
| | 0 | 1369 | | LongArray A = this, B = other; |
| | 0 | 1370 | | if (aDeg > bDeg) |
| | 0 | 1371 | | { |
| | 0 | 1372 | | A = other; B = this; |
| | 0 | 1373 | | int tmp = aDeg; aDeg = bDeg; bDeg = tmp; |
| | 0 | 1374 | | } |
| | | 1375 | | |
| | | 1376 | | /* |
| | | 1377 | | * Establish the word lengths of the arguments and result |
| | | 1378 | | */ |
| | 0 | 1379 | | int aLen = (int)((uint)(aDeg + 63) >> 6); |
| | 0 | 1380 | | int bLen = (int)((uint)(bDeg + 63) >> 6); |
| | 0 | 1381 | | int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); |
| | | 1382 | | |
| | 0 | 1383 | | if (aLen == 1) |
| | 0 | 1384 | | { |
| | 0 | 1385 | | long a0 = A.m_ints[0]; |
| | 0 | 1386 | | if (a0 == 1L) |
| | 0 | 1387 | | { |
| | 0 | 1388 | | return B; |
| | | 1389 | | } |
| | | 1390 | | |
| | | 1391 | | /* |
| | | 1392 | | * Fast path for small A, with performance dependent only on the number of set bits |
| | | 1393 | | */ |
| | 0 | 1394 | | long[] c0 = new long[cLen]; |
| | 0 | 1395 | | MultiplyWord(a0, B.m_ints, bLen, c0, 0); |
| | | 1396 | | |
| | | 1397 | | /* |
| | | 1398 | | * Reduce the raw answer against the reduction coefficients |
| | | 1399 | | */ |
| | | 1400 | | //return ReduceResult(c0, 0, cLen, m, ks); |
| | 0 | 1401 | | return new LongArray(c0, 0, cLen); |
| | | 1402 | | } |
| | | 1403 | | |
| | | 1404 | | /* |
| | | 1405 | | * Determine if B will get bigger during shifting |
| | | 1406 | | */ |
| | 0 | 1407 | | int bMax = (int)((uint)(bDeg + 7 + 63) >> 6); |
| | | 1408 | | |
| | | 1409 | | /* |
| | | 1410 | | * Lookup table for the offset of each B in the tables |
| | | 1411 | | */ |
| | 0 | 1412 | | int[] ti = new int[16]; |
| | | 1413 | | |
| | | 1414 | | /* |
| | | 1415 | | * Precompute table of all 4-bit products of B |
| | | 1416 | | */ |
| | 0 | 1417 | | long[] T0 = new long[bMax << 4]; |
| | 0 | 1418 | | int tOff = bMax; |
| | 0 | 1419 | | ti[1] = tOff; |
| | 0 | 1420 | | Array.Copy(B.m_ints, 0, T0, tOff, bLen); |
| | 0 | 1421 | | for (int i = 2; i < 16; ++i) |
| | 0 | 1422 | | { |
| | 0 | 1423 | | ti[i] = (tOff += bMax); |
| | 0 | 1424 | | if ((i & 1) == 0) |
| | 0 | 1425 | | { |
| | 0 | 1426 | | ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1); |
| | 0 | 1427 | | } |
| | | 1428 | | else |
| | 0 | 1429 | | { |
| | 0 | 1430 | | Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); |
| | 0 | 1431 | | } |
| | 0 | 1432 | | } |
| | | 1433 | | |
| | | 1434 | | /* |
| | | 1435 | | * Second table with all 4-bit products of B shifted 4 bits |
| | | 1436 | | */ |
| | 0 | 1437 | | long[] T1 = new long[T0.Length]; |
| | 0 | 1438 | | ShiftUp(T0, 0, T1, 0, T0.Length, 4); |
| | | 1439 | | // ShiftUp(T0, bMax, T1, bMax, tOff, 4); |
| | | 1440 | | |
| | 0 | 1441 | | long[] a = A.m_ints; |
| | 0 | 1442 | | long[] c = new long[cLen << 3]; |
| | | 1443 | | |
| | 0 | 1444 | | int MASK = 0xF; |
| | | 1445 | | |
| | | 1446 | | /* |
| | | 1447 | | * Lopez-Dahab (Modified) algorithm |
| | | 1448 | | */ |
| | | 1449 | | |
| | 0 | 1450 | | for (int aPos = 0; aPos < aLen; ++aPos) |
| | 0 | 1451 | | { |
| | 0 | 1452 | | long aVal = a[aPos]; |
| | 0 | 1453 | | int cOff = aPos; |
| | | 1454 | | for (; ; ) |
| | 0 | 1455 | | { |
| | 0 | 1456 | | int u = (int)aVal & MASK; |
| | 0 | 1457 | | aVal = (long)((ulong)aVal >> 4); |
| | 0 | 1458 | | int v = (int)aVal & MASK; |
| | 0 | 1459 | | AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); |
| | 0 | 1460 | | aVal = (long)((ulong)aVal >> 4); |
| | 0 | 1461 | | if (aVal == 0L) |
| | 0 | 1462 | | { |
| | 0 | 1463 | | break; |
| | | 1464 | | } |
| | 0 | 1465 | | cOff += cLen; |
| | 0 | 1466 | | } |
| | 0 | 1467 | | } |
| | | 1468 | | |
| | 0 | 1469 | | { |
| | 0 | 1470 | | int cOff = c.Length; |
| | 0 | 1471 | | while ((cOff -= cLen) != 0) |
| | 0 | 1472 | | { |
| | 0 | 1473 | | AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); |
| | 0 | 1474 | | } |
| | 0 | 1475 | | } |
| | | 1476 | | |
| | | 1477 | | /* |
| | | 1478 | | * Finally the raw answer is collected, reduce it against the reduction coefficients |
| | | 1479 | | */ |
| | | 1480 | | //return ReduceResult(c, 0, cLen, m, ks); |
| | 0 | 1481 | | return new LongArray(c, 0, cLen); |
| | 0 | 1482 | | } |
| | | 1483 | | |
| | | 1484 | | public void Reduce(int m, int[] ks) |
| | 0 | 1485 | | { |
| | 0 | 1486 | | long[] buf = m_ints; |
| | 0 | 1487 | | int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks); |
| | 0 | 1488 | | if (rLen < buf.Length) |
| | 0 | 1489 | | { |
| | 0 | 1490 | | m_ints = new long[rLen]; |
| | 0 | 1491 | | Array.Copy(buf, 0, m_ints, 0, rLen); |
| | 0 | 1492 | | } |
| | 0 | 1493 | | } |
| | | 1494 | | |
| | | 1495 | | private static LongArray ReduceResult(long[] buf, int off, int len, int m, int[] ks) |
| | 0 | 1496 | | { |
| | 0 | 1497 | | int rLen = ReduceInPlace(buf, off, len, m, ks); |
| | 0 | 1498 | | return new LongArray(buf, off, rLen); |
| | 0 | 1499 | | } |
| | | 1500 | | |
| | | 1501 | | // private static void deInterleave(long[] x, int xOff, long[] z, int zOff, int count, int rounds) |
| | | 1502 | | // { |
| | | 1503 | | // for (int i = 0; i < count; ++i) |
| | | 1504 | | // { |
| | | 1505 | | // z[zOff + i] = deInterleave(x[zOff + i], rounds); |
| | | 1506 | | // } |
| | | 1507 | | // } |
| | | 1508 | | // |
| | | 1509 | | // private static long deInterleave(long x, int rounds) |
| | | 1510 | | // { |
| | | 1511 | | // while (--rounds >= 0) |
| | | 1512 | | // { |
| | | 1513 | | // x = deInterleave32(x & DEInterleave_MASK) | (deInterleave32((x >>> 1) & DEInterleave_MASK) << 32); |
| | | 1514 | | // } |
| | | 1515 | | // return x; |
| | | 1516 | | // } |
| | | 1517 | | // |
| | | 1518 | | // private static long deInterleave32(long x) |
| | | 1519 | | // { |
| | | 1520 | | // x = (x | (x >>> 1)) & 0x3333333333333333L; |
| | | 1521 | | // x = (x | (x >>> 2)) & 0x0F0F0F0F0F0F0F0FL; |
| | | 1522 | | // x = (x | (x >>> 4)) & 0x00FF00FF00FF00FFL; |
| | | 1523 | | // x = (x | (x >>> 8)) & 0x0000FFFF0000FFFFL; |
| | | 1524 | | // x = (x | (x >>> 16)) & 0x00000000FFFFFFFFL; |
| | | 1525 | | // return x; |
| | | 1526 | | // } |
| | | 1527 | | |
| | | 1528 | | private static int ReduceInPlace(long[] buf, int off, int len, int m, int[] ks) |
| | 0 | 1529 | | { |
| | 0 | 1530 | | int mLen = (m + 63) >> 6; |
| | 0 | 1531 | | if (len < mLen) |
| | 0 | 1532 | | { |
| | 0 | 1533 | | return len; |
| | | 1534 | | } |
| | | 1535 | | |
| | 0 | 1536 | | int numBits = System.Math.Min(len << 6, (m << 1) - 1); // TODO use actual degree? |
| | 0 | 1537 | | int excessBits = (len << 6) - numBits; |
| | 0 | 1538 | | while (excessBits >= 64) |
| | 0 | 1539 | | { |
| | 0 | 1540 | | --len; |
| | 0 | 1541 | | excessBits -= 64; |
| | 0 | 1542 | | } |
| | | 1543 | | |
| | 0 | 1544 | | int kLen = ks.Length, kMax = ks[kLen - 1], kNext = kLen > 1 ? ks[kLen - 2] : 0; |
| | 0 | 1545 | | int wordWiseLimit = System.Math.Max(m, kMax + 64); |
| | 0 | 1546 | | int vectorableWords = (excessBits + System.Math.Min(numBits - wordWiseLimit, m - kNext)) >> 6; |
| | 0 | 1547 | | if (vectorableWords > 1) |
| | 0 | 1548 | | { |
| | 0 | 1549 | | int vectorWiseWords = len - vectorableWords; |
| | 0 | 1550 | | ReduceVectorWise(buf, off, len, vectorWiseWords, m, ks); |
| | 0 | 1551 | | while (len > vectorWiseWords) |
| | 0 | 1552 | | { |
| | 0 | 1553 | | buf[off + --len] = 0L; |
| | 0 | 1554 | | } |
| | 0 | 1555 | | numBits = vectorWiseWords << 6; |
| | 0 | 1556 | | } |
| | | 1557 | | |
| | 0 | 1558 | | if (numBits > wordWiseLimit) |
| | 0 | 1559 | | { |
| | 0 | 1560 | | ReduceWordWise(buf, off, len, wordWiseLimit, m, ks); |
| | 0 | 1561 | | numBits = wordWiseLimit; |
| | 0 | 1562 | | } |
| | | 1563 | | |
| | 0 | 1564 | | if (numBits > m) |
| | 0 | 1565 | | { |
| | 0 | 1566 | | ReduceBitWise(buf, off, numBits, m, ks); |
| | 0 | 1567 | | } |
| | | 1568 | | |
| | 0 | 1569 | | return mLen; |
| | 0 | 1570 | | } |
| | | 1571 | | |
| | | 1572 | | private static void ReduceBitWise(long[] buf, int off, int BitLength, int m, int[] ks) |
| | 0 | 1573 | | { |
| | 0 | 1574 | | while (--BitLength >= m) |
| | 0 | 1575 | | { |
| | 0 | 1576 | | if (TestBit(buf, off, BitLength)) |
| | 0 | 1577 | | { |
| | 0 | 1578 | | ReduceBit(buf, off, BitLength, m, ks); |
| | 0 | 1579 | | } |
| | 0 | 1580 | | } |
| | 0 | 1581 | | } |
| | | 1582 | | |
| | | 1583 | | private static void ReduceBit(long[] buf, int off, int bit, int m, int[] ks) |
| | 0 | 1584 | | { |
| | 0 | 1585 | | FlipBit(buf, off, bit); |
| | 0 | 1586 | | int n = bit - m; |
| | 0 | 1587 | | int j = ks.Length; |
| | 0 | 1588 | | while (--j >= 0) |
| | 0 | 1589 | | { |
| | 0 | 1590 | | FlipBit(buf, off, ks[j] + n); |
| | 0 | 1591 | | } |
| | 0 | 1592 | | FlipBit(buf, off, n); |
| | 0 | 1593 | | } |
| | | 1594 | | |
| | | 1595 | | private static void ReduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks) |
| | 0 | 1596 | | { |
| | 0 | 1597 | | int toPos = (int)((uint)toBit >> 6); |
| | | 1598 | | |
| | 0 | 1599 | | while (--len > toPos) |
| | 0 | 1600 | | { |
| | 0 | 1601 | | long word = buf[off + len]; |
| | 0 | 1602 | | if (word != 0) |
| | 0 | 1603 | | { |
| | 0 | 1604 | | buf[off + len] = 0; |
| | 0 | 1605 | | ReduceWord(buf, off, (len << 6), word, m, ks); |
| | 0 | 1606 | | } |
| | 0 | 1607 | | } |
| | | 1608 | | |
| | 0 | 1609 | | { |
| | 0 | 1610 | | int partial = toBit & 0x3F; |
| | 0 | 1611 | | long word = (long)((ulong)buf[off + toPos] >> partial); |
| | 0 | 1612 | | if (word != 0) |
| | 0 | 1613 | | { |
| | 0 | 1614 | | buf[off + toPos] ^= word << partial; |
| | 0 | 1615 | | ReduceWord(buf, off, toBit, word, m, ks); |
| | 0 | 1616 | | } |
| | 0 | 1617 | | } |
| | 0 | 1618 | | } |
| | | 1619 | | |
| | | 1620 | | private static void ReduceWord(long[] buf, int off, int bit, long word, int m, int[] ks) |
| | 0 | 1621 | | { |
| | 0 | 1622 | | int offset = bit - m; |
| | 0 | 1623 | | int j = ks.Length; |
| | 0 | 1624 | | while (--j >= 0) |
| | 0 | 1625 | | { |
| | 0 | 1626 | | FlipWord(buf, off, offset + ks[j], word); |
| | 0 | 1627 | | } |
| | 0 | 1628 | | FlipWord(buf, off, offset, word); |
| | 0 | 1629 | | } |
| | | 1630 | | |
| | | 1631 | | private static void ReduceVectorWise(long[] buf, int off, int len, int words, int m, int[] ks) |
| | 0 | 1632 | | { |
| | | 1633 | | /* |
| | | 1634 | | * NOTE: It's important we go from highest coefficient to lowest, because for the highest |
| | | 1635 | | * one (only) we allow the ranges to partially overlap, and therefore any changes must take |
| | | 1636 | | * effect for the subsequent lower coefficients. |
| | | 1637 | | */ |
| | 0 | 1638 | | int baseBit = (words << 6) - m; |
| | 0 | 1639 | | int j = ks.Length; |
| | 0 | 1640 | | while (--j >= 0) |
| | 0 | 1641 | | { |
| | 0 | 1642 | | FlipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]); |
| | 0 | 1643 | | } |
| | 0 | 1644 | | FlipVector(buf, off, buf, off + words, len - words, baseBit); |
| | 0 | 1645 | | } |
| | | 1646 | | |
| | | 1647 | | private static void FlipVector(long[] x, int xOff, long[] y, int yOff, int yLen, int bits) |
| | 0 | 1648 | | { |
| | 0 | 1649 | | xOff += (int)((uint)bits >> 6); |
| | 0 | 1650 | | bits &= 0x3F; |
| | | 1651 | | |
| | 0 | 1652 | | if (bits == 0) |
| | 0 | 1653 | | { |
| | 0 | 1654 | | Add(x, xOff, y, yOff, yLen); |
| | 0 | 1655 | | } |
| | | 1656 | | else |
| | 0 | 1657 | | { |
| | 0 | 1658 | | long carry = AddShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits); |
| | 0 | 1659 | | x[xOff] ^= carry; |
| | 0 | 1660 | | } |
| | 0 | 1661 | | } |
| | | 1662 | | |
| | | 1663 | | public LongArray ModSquare(int m, int[] ks) |
| | 0 | 1664 | | { |
| | 0 | 1665 | | int len = GetUsedLength(); |
| | 0 | 1666 | | if (len == 0) |
| | 0 | 1667 | | { |
| | 0 | 1668 | | return this; |
| | | 1669 | | } |
| | | 1670 | | |
| | 0 | 1671 | | int _2len = len << 1; |
| | 0 | 1672 | | long[] r = new long[_2len]; |
| | | 1673 | | |
| | 0 | 1674 | | int pos = 0; |
| | 0 | 1675 | | while (pos < _2len) |
| | 0 | 1676 | | { |
| | 0 | 1677 | | long mi = m_ints[(uint)pos >> 1]; |
| | 0 | 1678 | | r[pos++] = Interleave2_32to64((int)mi); |
| | 0 | 1679 | | r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32)); |
| | 0 | 1680 | | } |
| | | 1681 | | |
| | 0 | 1682 | | return new LongArray(r, 0, ReduceInPlace(r, 0, r.Length, m, ks)); |
| | 0 | 1683 | | } |
| | | 1684 | | |
| | | 1685 | | public LongArray ModSquareN(int n, int m, int[] ks) |
| | 0 | 1686 | | { |
| | 0 | 1687 | | int len = GetUsedLength(); |
| | 0 | 1688 | | if (len == 0) |
| | 0 | 1689 | | { |
| | 0 | 1690 | | return this; |
| | | 1691 | | } |
| | | 1692 | | |
| | 0 | 1693 | | int mLen = (m + 63) >> 6; |
| | 0 | 1694 | | long[] r = new long[mLen << 1]; |
| | 0 | 1695 | | Array.Copy(m_ints, 0, r, 0, len); |
| | | 1696 | | |
| | 0 | 1697 | | while (--n >= 0) |
| | 0 | 1698 | | { |
| | 0 | 1699 | | SquareInPlace(r, len, m, ks); |
| | 0 | 1700 | | len = ReduceInPlace(r, 0, r.Length, m, ks); |
| | 0 | 1701 | | } |
| | | 1702 | | |
| | 0 | 1703 | | return new LongArray(r, 0, len); |
| | 0 | 1704 | | } |
| | | 1705 | | |
| | | 1706 | | public LongArray Square(int m, int[] ks) |
| | 0 | 1707 | | { |
| | 0 | 1708 | | int len = GetUsedLength(); |
| | 0 | 1709 | | if (len == 0) |
| | 0 | 1710 | | { |
| | 0 | 1711 | | return this; |
| | | 1712 | | } |
| | | 1713 | | |
| | 0 | 1714 | | int _2len = len << 1; |
| | 0 | 1715 | | long[] r = new long[_2len]; |
| | | 1716 | | |
| | 0 | 1717 | | int pos = 0; |
| | 0 | 1718 | | while (pos < _2len) |
| | 0 | 1719 | | { |
| | 0 | 1720 | | long mi = m_ints[(uint)pos >> 1]; |
| | 0 | 1721 | | r[pos++] = Interleave2_32to64((int)mi); |
| | 0 | 1722 | | r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32)); |
| | 0 | 1723 | | } |
| | | 1724 | | |
| | 0 | 1725 | | return new LongArray(r, 0, r.Length); |
| | 0 | 1726 | | } |
| | | 1727 | | |
| | | 1728 | | private static void SquareInPlace(long[] x, int xLen, int m, int[] ks) |
| | 0 | 1729 | | { |
| | 0 | 1730 | | int pos = xLen << 1; |
| | 0 | 1731 | | while (--xLen >= 0) |
| | 0 | 1732 | | { |
| | 0 | 1733 | | long xVal = x[xLen]; |
| | 0 | 1734 | | x[--pos] = Interleave2_32to64((int)((ulong)xVal >> 32)); |
| | 0 | 1735 | | x[--pos] = Interleave2_32to64((int)xVal); |
| | 0 | 1736 | | } |
| | 0 | 1737 | | } |
| | | 1738 | | |
| | | 1739 | | private static void Interleave(long[] x, int xOff, long[] z, int zOff, int count, int width) |
| | 0 | 1740 | | { |
| | 0 | 1741 | | switch (width) |
| | | 1742 | | { |
| | | 1743 | | case 3: |
| | 0 | 1744 | | Interleave3(x, xOff, z, zOff, count); |
| | 0 | 1745 | | break; |
| | | 1746 | | case 5: |
| | 0 | 1747 | | Interleave5(x, xOff, z, zOff, count); |
| | 0 | 1748 | | break; |
| | | 1749 | | case 7: |
| | 0 | 1750 | | Interleave7(x, xOff, z, zOff, count); |
| | 0 | 1751 | | break; |
| | | 1752 | | default: |
| | 0 | 1753 | | Interleave2_n(x, xOff, z, zOff, count, BitLengths[width] - 1); |
| | 0 | 1754 | | break; |
| | | 1755 | | } |
| | 0 | 1756 | | } |
| | | 1757 | | |
| | | 1758 | | private static void Interleave3(long[] x, int xOff, long[] z, int zOff, int count) |
| | 0 | 1759 | | { |
| | 0 | 1760 | | for (int i = 0; i < count; ++i) |
| | 0 | 1761 | | { |
| | 0 | 1762 | | z[zOff + i] = Interleave3(x[xOff + i]); |
| | 0 | 1763 | | } |
| | 0 | 1764 | | } |
| | | 1765 | | |
| | | 1766 | | private static long Interleave3(long x) |
| | 0 | 1767 | | { |
| | 0 | 1768 | | long z = x & (1L << 63); |
| | 0 | 1769 | | return z |
| | 0 | 1770 | | | Interleave3_21to63((int)x & 0x1FFFFF) |
| | 0 | 1771 | | | Interleave3_21to63((int)((ulong)x >> 21) & 0x1FFFFF) << 1 |
| | 0 | 1772 | | | Interleave3_21to63((int)((ulong)x >> 42) & 0x1FFFFF) << 2; |
| | | 1773 | | |
| | | 1774 | | // int zPos = 0, wPos = 0, xPos = 0; |
| | | 1775 | | // for (;;) |
| | | 1776 | | // { |
| | | 1777 | | // z |= ((x >>> xPos) & 1L) << zPos; |
| | | 1778 | | // if (++zPos == 63) |
| | | 1779 | | // { |
| | | 1780 | | // String sz2 = Long.toBinaryString(z); |
| | | 1781 | | // return z; |
| | | 1782 | | // } |
| | | 1783 | | // if ((xPos += 21) >= 63) |
| | | 1784 | | // { |
| | | 1785 | | // xPos = ++wPos; |
| | | 1786 | | // } |
| | | 1787 | | // } |
| | 0 | 1788 | | } |
| | | 1789 | | |
| | | 1790 | | private static long Interleave3_21to63(int x) |
| | 0 | 1791 | | { |
| | 0 | 1792 | | int r00 = INTERLEAVE3_TABLE[x & 0x7F]; |
| | 0 | 1793 | | int r21 = INTERLEAVE3_TABLE[((uint)x >> 7) & 0x7F]; |
| | 0 | 1794 | | int r42 = INTERLEAVE3_TABLE[(uint)x >> 14]; |
| | 0 | 1795 | | return (r42 & 0xFFFFFFFFL) << 42 | (r21 & 0xFFFFFFFFL) << 21 | (r00 & 0xFFFFFFFFL); |
| | 0 | 1796 | | } |
| | | 1797 | | |
| | | 1798 | | private static void Interleave5(long[] x, int xOff, long[] z, int zOff, int count) |
| | 0 | 1799 | | { |
| | 0 | 1800 | | for (int i = 0; i < count; ++i) |
| | 0 | 1801 | | { |
| | 0 | 1802 | | z[zOff + i] = Interleave5(x[xOff + i]); |
| | 0 | 1803 | | } |
| | 0 | 1804 | | } |
| | | 1805 | | |
| | | 1806 | | private static long Interleave5(long x) |
| | 0 | 1807 | | { |
| | 0 | 1808 | | return Interleave3_13to65((int)x & 0x1FFF) |
| | 0 | 1809 | | | Interleave3_13to65((int)((ulong)x >> 13) & 0x1FFF) << 1 |
| | 0 | 1810 | | | Interleave3_13to65((int)((ulong)x >> 26) & 0x1FFF) << 2 |
| | 0 | 1811 | | | Interleave3_13to65((int)((ulong)x >> 39) & 0x1FFF) << 3 |
| | 0 | 1812 | | | Interleave3_13to65((int)((ulong)x >> 52) & 0x1FFF) << 4; |
| | | 1813 | | |
| | | 1814 | | // long z = 0; |
| | | 1815 | | // int zPos = 0, wPos = 0, xPos = 0; |
| | | 1816 | | // for (;;) |
| | | 1817 | | // { |
| | | 1818 | | // z |= ((x >>> xPos) & 1L) << zPos; |
| | | 1819 | | // if (++zPos == 64) |
| | | 1820 | | // { |
| | | 1821 | | // return z; |
| | | 1822 | | // } |
| | | 1823 | | // if ((xPos += 13) >= 64) |
| | | 1824 | | // { |
| | | 1825 | | // xPos = ++wPos; |
| | | 1826 | | // } |
| | | 1827 | | // } |
| | 0 | 1828 | | } |
| | | 1829 | | |
| | | 1830 | | private static long Interleave3_13to65(int x) |
| | 0 | 1831 | | { |
| | 0 | 1832 | | int r00 = INTERLEAVE5_TABLE[x & 0x7F]; |
| | 0 | 1833 | | int r35 = INTERLEAVE5_TABLE[(uint)x >> 7]; |
| | 0 | 1834 | | return (r35 & 0xFFFFFFFFL) << 35 | (r00 & 0xFFFFFFFFL); |
| | 0 | 1835 | | } |
| | | 1836 | | |
| | | 1837 | | private static void Interleave7(long[] x, int xOff, long[] z, int zOff, int count) |
| | 0 | 1838 | | { |
| | 0 | 1839 | | for (int i = 0; i < count; ++i) |
| | 0 | 1840 | | { |
| | 0 | 1841 | | z[zOff + i] = Interleave7(x[xOff + i]); |
| | 0 | 1842 | | } |
| | 0 | 1843 | | } |
| | | 1844 | | |
| | | 1845 | | private static long Interleave7(long x) |
| | 0 | 1846 | | { |
| | 0 | 1847 | | long z = x & (1L << 63); |
| | 0 | 1848 | | return z |
| | 0 | 1849 | | | INTERLEAVE7_TABLE[(int)x & 0x1FF] |
| | 0 | 1850 | | | INTERLEAVE7_TABLE[(int)((ulong)x >> 9) & 0x1FF] << 1 |
| | 0 | 1851 | | | INTERLEAVE7_TABLE[(int)((ulong)x >> 18) & 0x1FF] << 2 |
| | 0 | 1852 | | | INTERLEAVE7_TABLE[(int)((ulong)x >> 27) & 0x1FF] << 3 |
| | 0 | 1853 | | | INTERLEAVE7_TABLE[(int)((ulong)x >> 36) & 0x1FF] << 4 |
| | 0 | 1854 | | | INTERLEAVE7_TABLE[(int)((ulong)x >> 45) & 0x1FF] << 5 |
| | 0 | 1855 | | | INTERLEAVE7_TABLE[(int)((ulong)x >> 54) & 0x1FF] << 6; |
| | | 1856 | | |
| | | 1857 | | // int zPos = 0, wPos = 0, xPos = 0; |
| | | 1858 | | // for (;;) |
| | | 1859 | | // { |
| | | 1860 | | // z |= ((x >>> xPos) & 1L) << zPos; |
| | | 1861 | | // if (++zPos == 63) |
| | | 1862 | | // { |
| | | 1863 | | // return z; |
| | | 1864 | | // } |
| | | 1865 | | // if ((xPos += 9) >= 63) |
| | | 1866 | | // { |
| | | 1867 | | // xPos = ++wPos; |
| | | 1868 | | // } |
| | | 1869 | | // } |
| | 0 | 1870 | | } |
| | | 1871 | | |
| | | 1872 | | private static void Interleave2_n(long[] x, int xOff, long[] z, int zOff, int count, int rounds) |
| | 0 | 1873 | | { |
| | 0 | 1874 | | for (int i = 0; i < count; ++i) |
| | 0 | 1875 | | { |
| | 0 | 1876 | | z[zOff + i] = Interleave2_n(x[xOff + i], rounds); |
| | 0 | 1877 | | } |
| | 0 | 1878 | | } |
| | | 1879 | | |
| | | 1880 | | private static long Interleave2_n(long x, int rounds) |
| | 0 | 1881 | | { |
| | 0 | 1882 | | while (rounds > 1) |
| | 0 | 1883 | | { |
| | 0 | 1884 | | rounds -= 2; |
| | 0 | 1885 | | x = Interleave4_16to64((int)x & 0xFFFF) |
| | 0 | 1886 | | | Interleave4_16to64((int)((ulong)x >> 16) & 0xFFFF) << 1 |
| | 0 | 1887 | | | Interleave4_16to64((int)((ulong)x >> 32) & 0xFFFF) << 2 |
| | 0 | 1888 | | | Interleave4_16to64((int)((ulong)x >> 48) & 0xFFFF) << 3; |
| | 0 | 1889 | | } |
| | 0 | 1890 | | if (rounds > 0) |
| | 0 | 1891 | | { |
| | 0 | 1892 | | x = Interleave2_32to64((int)x) | Interleave2_32to64((int)((ulong)x >> 32)) << 1; |
| | 0 | 1893 | | } |
| | 0 | 1894 | | return x; |
| | 0 | 1895 | | } |
| | | 1896 | | |
| | | 1897 | | private static long Interleave4_16to64(int x) |
| | 0 | 1898 | | { |
| | 0 | 1899 | | int r00 = INTERLEAVE4_TABLE[x & 0xFF]; |
| | 0 | 1900 | | int r32 = INTERLEAVE4_TABLE[(uint)x >> 8]; |
| | 0 | 1901 | | return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL); |
| | 0 | 1902 | | } |
| | | 1903 | | |
| | | 1904 | | private static long Interleave2_32to64(int x) |
| | 0 | 1905 | | { |
| | 0 | 1906 | | int r00 = INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[((uint)x >> 8) & 0xFF] << 16; |
| | 0 | 1907 | | int r32 = INTERLEAVE2_TABLE[((uint)x >> 16) & 0xFF] | INTERLEAVE2_TABLE[(uint)x >> 24] << 16; |
| | 0 | 1908 | | return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL); |
| | 0 | 1909 | | } |
| | | 1910 | | |
| | | 1911 | | // private static LongArray ExpItohTsujii2(LongArray B, int n, int m, int[] ks) |
| | | 1912 | | // { |
| | | 1913 | | // LongArray t1 = B, t3 = new LongArray(new long[]{ 1L }); |
| | | 1914 | | // int scale = 1; |
| | | 1915 | | // |
| | | 1916 | | // int numTerms = n; |
| | | 1917 | | // while (numTerms > 1) |
| | | 1918 | | // { |
| | | 1919 | | // if ((numTerms & 1) != 0) |
| | | 1920 | | // { |
| | | 1921 | | // t3 = t3.ModMultiply(t1, m, ks); |
| | | 1922 | | // t1 = t1.modSquareN(scale, m, ks); |
| | | 1923 | | // } |
| | | 1924 | | // |
| | | 1925 | | // LongArray t2 = t1.modSquareN(scale, m, ks); |
| | | 1926 | | // t1 = t1.ModMultiply(t2, m, ks); |
| | | 1927 | | // numTerms >>>= 1; scale <<= 1; |
| | | 1928 | | // } |
| | | 1929 | | // |
| | | 1930 | | // return t3.ModMultiply(t1, m, ks); |
| | | 1931 | | // } |
| | | 1932 | | // |
| | | 1933 | | // private static LongArray ExpItohTsujii23(LongArray B, int n, int m, int[] ks) |
| | | 1934 | | // { |
| | | 1935 | | // LongArray t1 = B, t3 = new LongArray(new long[]{ 1L }); |
| | | 1936 | | // int scale = 1; |
| | | 1937 | | // |
| | | 1938 | | // int numTerms = n; |
| | | 1939 | | // while (numTerms > 1) |
| | | 1940 | | // { |
| | | 1941 | | // bool m03 = numTerms % 3 == 0; |
| | | 1942 | | // bool m14 = !m03 && (numTerms & 1) != 0; |
| | | 1943 | | // |
| | | 1944 | | // if (m14) |
| | | 1945 | | // { |
| | | 1946 | | // t3 = t3.ModMultiply(t1, m, ks); |
| | | 1947 | | // t1 = t1.modSquareN(scale, m, ks); |
| | | 1948 | | // } |
| | | 1949 | | // |
| | | 1950 | | // LongArray t2 = t1.modSquareN(scale, m, ks); |
| | | 1951 | | // t1 = t1.ModMultiply(t2, m, ks); |
| | | 1952 | | // |
| | | 1953 | | // if (m03) |
| | | 1954 | | // { |
| | | 1955 | | // t2 = t2.modSquareN(scale, m, ks); |
| | | 1956 | | // t1 = t1.ModMultiply(t2, m, ks); |
| | | 1957 | | // numTerms /= 3; scale *= 3; |
| | | 1958 | | // } |
| | | 1959 | | // else |
| | | 1960 | | // { |
| | | 1961 | | // numTerms >>>= 1; scale <<= 1; |
| | | 1962 | | // } |
| | | 1963 | | // } |
| | | 1964 | | // |
| | | 1965 | | // return t3.ModMultiply(t1, m, ks); |
| | | 1966 | | // } |
| | | 1967 | | // |
| | | 1968 | | // private static LongArray ExpItohTsujii235(LongArray B, int n, int m, int[] ks) |
| | | 1969 | | // { |
| | | 1970 | | // LongArray t1 = B, t4 = new LongArray(new long[]{ 1L }); |
| | | 1971 | | // int scale = 1; |
| | | 1972 | | // |
| | | 1973 | | // int numTerms = n; |
| | | 1974 | | // while (numTerms > 1) |
| | | 1975 | | // { |
| | | 1976 | | // if (numTerms % 5 == 0) |
| | | 1977 | | // { |
| | | 1978 | | //// t1 = ExpItohTsujii23(t1, 5, m, ks); |
| | | 1979 | | // |
| | | 1980 | | // LongArray t3 = t1; |
| | | 1981 | | // t1 = t1.modSquareN(scale, m, ks); |
| | | 1982 | | // |
| | | 1983 | | // LongArray t2 = t1.modSquareN(scale, m, ks); |
| | | 1984 | | // t1 = t1.ModMultiply(t2, m, ks); |
| | | 1985 | | // t2 = t1.modSquareN(scale << 1, m, ks); |
| | | 1986 | | // t1 = t1.ModMultiply(t2, m, ks); |
| | | 1987 | | // |
| | | 1988 | | // t1 = t1.ModMultiply(t3, m, ks); |
| | | 1989 | | // |
| | | 1990 | | // numTerms /= 5; scale *= 5; |
| | | 1991 | | // continue; |
| | | 1992 | | // } |
| | | 1993 | | // |
| | | 1994 | | // bool m03 = numTerms % 3 == 0; |
| | | 1995 | | // bool m14 = !m03 && (numTerms & 1) != 0; |
| | | 1996 | | // |
| | | 1997 | | // if (m14) |
| | | 1998 | | // { |
| | | 1999 | | // t4 = t4.ModMultiply(t1, m, ks); |
| | | 2000 | | // t1 = t1.modSquareN(scale, m, ks); |
| | | 2001 | | // } |
| | | 2002 | | // |
| | | 2003 | | // LongArray t2 = t1.modSquareN(scale, m, ks); |
| | | 2004 | | // t1 = t1.ModMultiply(t2, m, ks); |
| | | 2005 | | // |
| | | 2006 | | // if (m03) |
| | | 2007 | | // { |
| | | 2008 | | // t2 = t2.modSquareN(scale, m, ks); |
| | | 2009 | | // t1 = t1.ModMultiply(t2, m, ks); |
| | | 2010 | | // numTerms /= 3; scale *= 3; |
| | | 2011 | | // } |
| | | 2012 | | // else |
| | | 2013 | | // { |
| | | 2014 | | // numTerms >>>= 1; scale <<= 1; |
| | | 2015 | | // } |
| | | 2016 | | // } |
| | | 2017 | | // |
| | | 2018 | | // return t4.ModMultiply(t1, m, ks); |
| | | 2019 | | // } |
| | | 2020 | | |
| | | 2021 | | public LongArray ModInverse(int m, int[] ks) |
| | 0 | 2022 | | { |
| | | 2023 | | /* |
| | | 2024 | | * Fermat's Little Theorem |
| | | 2025 | | */ |
| | | 2026 | | // LongArray A = this; |
| | | 2027 | | // LongArray B = A.modSquare(m, ks); |
| | | 2028 | | // LongArray R0 = B, R1 = B; |
| | | 2029 | | // for (int i = 2; i < m; ++i) |
| | | 2030 | | // { |
| | | 2031 | | // R1 = R1.modSquare(m, ks); |
| | | 2032 | | // R0 = R0.ModMultiply(R1, m, ks); |
| | | 2033 | | // } |
| | | 2034 | | // |
| | | 2035 | | // return R0; |
| | | 2036 | | |
| | | 2037 | | /* |
| | | 2038 | | * Itoh-Tsujii |
| | | 2039 | | */ |
| | | 2040 | | // LongArray B = modSquare(m, ks); |
| | | 2041 | | // switch (m) |
| | | 2042 | | // { |
| | | 2043 | | // case 409: |
| | | 2044 | | // return ExpItohTsujii23(B, m - 1, m, ks); |
| | | 2045 | | // case 571: |
| | | 2046 | | // return ExpItohTsujii235(B, m - 1, m, ks); |
| | | 2047 | | // case 163: |
| | | 2048 | | // case 233: |
| | | 2049 | | // case 283: |
| | | 2050 | | // default: |
| | | 2051 | | // return ExpItohTsujii2(B, m - 1, m, ks); |
| | | 2052 | | // } |
| | | 2053 | | |
| | | 2054 | | /* |
| | | 2055 | | * Inversion in F2m using the extended Euclidean algorithm |
| | | 2056 | | * |
| | | 2057 | | * Input: A nonzero polynomial a(z) of degree at most m-1 |
| | | 2058 | | * Output: a(z)^(-1) mod f(z) |
| | | 2059 | | */ |
| | 0 | 2060 | | int uzDegree = Degree(); |
| | 0 | 2061 | | if (uzDegree == 0) |
| | 0 | 2062 | | { |
| | 0 | 2063 | | throw new InvalidOperationException(); |
| | | 2064 | | } |
| | 0 | 2065 | | if (uzDegree == 1) |
| | 0 | 2066 | | { |
| | 0 | 2067 | | return this; |
| | | 2068 | | } |
| | | 2069 | | |
| | | 2070 | | // u(z) := a(z) |
| | 0 | 2071 | | LongArray uz = (LongArray)Copy(); |
| | | 2072 | | |
| | 0 | 2073 | | int t = (m + 63) >> 6; |
| | | 2074 | | |
| | | 2075 | | // v(z) := f(z) |
| | 0 | 2076 | | LongArray vz = new LongArray(t); |
| | 0 | 2077 | | ReduceBit(vz.m_ints, 0, m, m, ks); |
| | | 2078 | | |
| | | 2079 | | // g1(z) := 1, g2(z) := 0 |
| | 0 | 2080 | | LongArray g1z = new LongArray(t); |
| | 0 | 2081 | | g1z.m_ints[0] = 1L; |
| | 0 | 2082 | | LongArray g2z = new LongArray(t); |
| | | 2083 | | |
| | 0 | 2084 | | int[] uvDeg = new int[]{ uzDegree, m + 1 }; |
| | 0 | 2085 | | LongArray[] uv = new LongArray[]{ uz, vz }; |
| | | 2086 | | |
| | 0 | 2087 | | int[] ggDeg = new int[]{ 1, 0 }; |
| | 0 | 2088 | | LongArray[] gg = new LongArray[]{ g1z, g2z }; |
| | | 2089 | | |
| | 0 | 2090 | | int b = 1; |
| | 0 | 2091 | | int duv1 = uvDeg[b]; |
| | 0 | 2092 | | int dgg1 = ggDeg[b]; |
| | 0 | 2093 | | int j = duv1 - uvDeg[1 - b]; |
| | | 2094 | | |
| | | 2095 | | for (;;) |
| | 0 | 2096 | | { |
| | 0 | 2097 | | if (j < 0) |
| | 0 | 2098 | | { |
| | 0 | 2099 | | j = -j; |
| | 0 | 2100 | | uvDeg[b] = duv1; |
| | 0 | 2101 | | ggDeg[b] = dgg1; |
| | 0 | 2102 | | b = 1 - b; |
| | 0 | 2103 | | duv1 = uvDeg[b]; |
| | 0 | 2104 | | dgg1 = ggDeg[b]; |
| | 0 | 2105 | | } |
| | | 2106 | | |
| | 0 | 2107 | | uv[b].AddShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j); |
| | | 2108 | | |
| | 0 | 2109 | | int duv2 = uv[b].DegreeFrom(duv1); |
| | 0 | 2110 | | if (duv2 == 0) |
| | 0 | 2111 | | { |
| | 0 | 2112 | | return gg[1 - b]; |
| | | 2113 | | } |
| | | 2114 | | |
| | 0 | 2115 | | { |
| | 0 | 2116 | | int dgg2 = ggDeg[1 - b]; |
| | 0 | 2117 | | gg[b].AddShiftedByBitsSafe(gg[1 - b], dgg2, j); |
| | 0 | 2118 | | dgg2 += j; |
| | | 2119 | | |
| | 0 | 2120 | | if (dgg2 > dgg1) |
| | 0 | 2121 | | { |
| | 0 | 2122 | | dgg1 = dgg2; |
| | 0 | 2123 | | } |
| | 0 | 2124 | | else if (dgg2 == dgg1) |
| | 0 | 2125 | | { |
| | 0 | 2126 | | dgg1 = gg[b].DegreeFrom(dgg1); |
| | 0 | 2127 | | } |
| | 0 | 2128 | | } |
| | | 2129 | | |
| | 0 | 2130 | | j += (duv2 - duv1); |
| | 0 | 2131 | | duv1 = duv2; |
| | 0 | 2132 | | } |
| | 0 | 2133 | | } |
| | | 2134 | | |
| | | 2135 | | public override bool Equals(object obj) |
| | 0 | 2136 | | { |
| | 0 | 2137 | | return Equals(obj as LongArray); |
| | 0 | 2138 | | } |
| | | 2139 | | |
| | | 2140 | | public virtual bool Equals(LongArray other) |
| | 0 | 2141 | | { |
| | 0 | 2142 | | if (this == other) |
| | 0 | 2143 | | return true; |
| | 0 | 2144 | | if (null == other) |
| | 0 | 2145 | | return false; |
| | 0 | 2146 | | int usedLen = GetUsedLength(); |
| | 0 | 2147 | | if (other.GetUsedLength() != usedLen) |
| | 0 | 2148 | | { |
| | 0 | 2149 | | return false; |
| | | 2150 | | } |
| | 0 | 2151 | | for (int i = 0; i < usedLen; i++) |
| | 0 | 2152 | | { |
| | 0 | 2153 | | if (m_ints[i] != other.m_ints[i]) |
| | 0 | 2154 | | { |
| | 0 | 2155 | | return false; |
| | | 2156 | | } |
| | 0 | 2157 | | } |
| | 0 | 2158 | | return true; |
| | 0 | 2159 | | } |
| | | 2160 | | |
| | | 2161 | | public override int GetHashCode() |
| | 0 | 2162 | | { |
| | 0 | 2163 | | int usedLen = GetUsedLength(); |
| | 0 | 2164 | | int hash = 1; |
| | 0 | 2165 | | for (int i = 0; i < usedLen; i++) |
| | 0 | 2166 | | { |
| | 0 | 2167 | | long mi = m_ints[i]; |
| | 0 | 2168 | | hash *= 31; |
| | 0 | 2169 | | hash ^= (int)mi; |
| | 0 | 2170 | | hash *= 31; |
| | 0 | 2171 | | hash ^= (int)((ulong)mi >> 32); |
| | 0 | 2172 | | } |
| | 0 | 2173 | | return hash; |
| | 0 | 2174 | | } |
| | | 2175 | | |
| | | 2176 | | public LongArray Copy() |
| | 0 | 2177 | | { |
| | 0 | 2178 | | return new LongArray(Arrays.Clone(m_ints)); |
| | 0 | 2179 | | } |
| | | 2180 | | |
| | | 2181 | | public override string ToString() |
| | 0 | 2182 | | { |
| | 0 | 2183 | | int i = GetUsedLength(); |
| | 0 | 2184 | | if (i == 0) |
| | 0 | 2185 | | { |
| | 0 | 2186 | | return "0"; |
| | | 2187 | | } |
| | | 2188 | | |
| | 0 | 2189 | | StringBuilder sb = new StringBuilder(Convert.ToString(m_ints[--i], 2)); |
| | 0 | 2190 | | while (--i >= 0) |
| | 0 | 2191 | | { |
| | 0 | 2192 | | string s = Convert.ToString(m_ints[i], 2); |
| | | 2193 | | |
| | | 2194 | | // Add leading zeroes, except for highest significant word |
| | 0 | 2195 | | int len = s.Length; |
| | 0 | 2196 | | if (len < 64) |
| | 0 | 2197 | | { |
| | 0 | 2198 | | sb.Append(ZEROES.Substring(len)); |
| | 0 | 2199 | | } |
| | | 2200 | | |
| | 0 | 2201 | | sb.Append(s); |
| | 0 | 2202 | | } |
| | 0 | 2203 | | return sb.ToString(); |
| | 0 | 2204 | | } |
| | | 2205 | | } |
| | | 2206 | | } |