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