-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBigInt.java
528 lines (491 loc) · 17.7 KB
/
BigInt.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
// see: https://github.com/AlexandreLadriere/Big-Numbers-Handler
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BigInt {
private int bitLength = 256; // Length of the BigInt in bits
private int blockSize = 32; // Length of each block used to represent the BigInt, in bits
private int base = 0x80000000; // 2**31 (signed int)
private long resMask = 0x7FFFFFFFL; // mask used to get the 32 LSB in a long
private List<Integer> representation = new ArrayList<>(); // List representation of the BigInt
/**
* Creates a BigInt object
*
* @param representation Representation of the BigInt object (List<Integer>)
*/
BigInt(List<Integer> representation) {
ini();
this.copy(representation);
}
/**
* Creates a BigInt object
*
* @param representation Representation of the BigInt object (List<Integer>)
* @param bitLength Length of the BigInt in bits (int)
*/
BigInt(List<Integer> representation, int bitLength) {
try {
if (bitLength % blockSize == 0) {
this.bitLength = bitLength;
ini();
this.copy(representation);
} else {
throw new Exception("Constructor: BigInteger can not be created. bitLength parameter is not correct. " +
"It must be a multiple of 32.");
}
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
/**
* Creates a BigInt object
*
* @param representation Representation of the BigInt object (int[])
*/
BigInt(int[] representation) {
ini();
this.copy(representation);
}
/**
* Creates a BigInt object
*
* @param representation Representation of the BigInt object (int[])
* @param bitLength Length of the BigInt in bits (int)
*/
BigInt(int[] representation, int bitLength) {
try {
if (bitLength % blockSize == 0) {
this.bitLength = bitLength;
ini();
this.copy(representation);
} else {
throw new Exception("Constructor: BigInteger can not be created. bitLength parameter is not correct. " +
"It must be a multiple of 32.");
}
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
/**
* Creates a BigInt object
*/
BigInt() {
ini();
}
/**
* Creates a BigInt object
*
* @param bitLength Length of the BigInt in bits (int)
*/
BigInt(int bitLength) {
try {
if (bitLength % blockSize == 0) {
this.bitLength = bitLength;
ini();
} else {
throw new Exception("Constructor: BigInteger can not be created. bitLength parameter is not correct. " +
"It must be a multiple of 32.");
}
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
/**
* Compares the calling BigInt to the one given in parameter
*
* @param b BigInt to compare (BigInt)
* @return Result of the comparison (true: this >= b, false: b > this) (boolean)
*/
public boolean isGreater(BigInt b) {
boolean isGreater = false;
if (this.bitLength != b.getBitLength()) {
return isGreater;
}
int i = 0;
while (i < this.representation.size()) {
if (this.representation.get(i) > b.getRepresentation().get(i)) {
isGreater = true;
i = this.representation.size();
} else if (this.representation.get(i) < b.getRepresentation().get(i)) {
i = this.representation.size();
}
i++;
}
return isGreater;
}
/**
* Checks if two BigInt are equals
*
* @param b The BigInt to compare to (BigInt)
* @return Boolean to indicate if equals or not (true: equals; false: not equals) (boolean)
*/
public boolean isEqual(BigInt b) {
if (this.bitLength != b.getBitLength()) {
return false;
}
boolean isEq = true;
for (int i = 0; i < this.representation.size(); i++) {
if (!this.representation.get(i).equals(b.getRepresentation().get(i))) {
isEq = false;
break;
}
}
return isEq;
}
/**
* Initializes the representation to 0
*/
private void ini() {
for (int i = 0; i < this.bitLength / this.blockSize; i++) {
this.representation.add(0);
}
}
// faire un getK()
public BigInt mul_montgomery(BigInt b, BigInt mod, BigInt r, BigInt v, int k) {
System.out.println("\nmul_montgomery function:");
BigInt result = new BigInt(this.bitLength);
BigInt s; // new BigInt(this.bitLength + b.getBitLength())
BigInt sBis;
BigInt t;
BigInt m;
BigInt u = new BigInt(this.bitLength);
int[] u_tmpArray = new int[u.getRepresentation().size()];
Arrays.fill(u_tmpArray, 0);
sBis = this.mul(b); // s = a x b
s = sBis.castTo512bits();
System.out.println("sBis = " + sBis.toString());
System.out.println("s = " + s.toString());
BigInt t_tmp = s.mul(v); // t_tmp = s.v
System.out.println("t_tmp = " + t_tmp.toString());
t = t_tmp.modulusR(k); // t = t_tmp mod r
System.out.println("t = " + t.toString());
BigInt t_time_n = t.mul(mod);
System.out.println("t.mul(mod) = " + t_time_n.toString());
System.out.println("s = " + s.toString());
m = t_time_n.add(s); // m = s + t.n
System.out.println("m = " + m.toString());
String bigIntBinStr = "";
// transform m to bit string
for (int i = 0; i < m.getRepresentation().size(); i++) {
bigIntBinStr += convertIntToBinString(m.getRepresentation().get(i));
}
System.out.println("m before removink k bits at the end = " + bigIntBinStr);
// removing last k bits
String newBigIntBinStr = bigIntBinStr.substring(0, bigIntBinStr.length() - k);
System.out.println("m after removink k bits at the end = " + newBigIntBinStr);
System.out.println("length after removing k = " + newBigIntBinStr.length());
// adding k 0 at the beginning
for (int i = 0; i < bigIntBinStr.length() - k; i++) {
newBigIntBinStr = "0" + newBigIntBinStr;
}
System.out.println("length after adding k 0 = " + newBigIntBinStr.length());
// ERROR: ERREUR DANS CETTE PARTIE DE CODE
// convert the previous string to BigInt object
System.out.println("Length = " + newBigIntBinStr.length());
for (int i = 0; i < u_tmpArray.length; i++) {
u_tmpArray[i] = Integer.parseInt(newBigIntBinStr.substring(i * (blockSize - 1), (i + 1) * (this.blockSize - 1)), 2);
}
// FIN DE LA PARTIE DE L'ERREUR
u.setRepresentation(u_tmpArray);
System.out.println("u = " + u.toString());
if (u.isGreater(mod) || u.isEqual(mod)) {
result = u.sub(mod);
System.out.println("u <= n");
} else {
result = u;
System.out.println("u < n");
}
return result;
}
/**
* Computes the result of calling BigInt modulus 2^k (with 0 <= k <= 256)
*
* @param k the power of 2 of the modulus (Integer)
* @return Result of calling BigInt modulus 2^k (BigInt)
*/
public BigInt modulusR(int k) {
BigInt result = new BigInt();
int realBitNumberShift = k + (k / this.blockSize); // integers are on 31 bits, he first one is for the sign
int blockNumber = realBitNumberShift / this.blockSize; // number of blocks
int remainingBits = realBitNumberShift % this.blockSize; // number of remaining bits
int[] res_tmpArray = new int[result.getRepresentation().size()];
Arrays.fill(res_tmpArray, 0);
for (int i = this.getRepresentation().size() - 1; i >= this.getRepresentation().size() - blockNumber; i--) {
res_tmpArray[i] = this.getRepresentation().get(i);
}
int r_tmp = this.getRepresentation().get(this.getRepresentation().size() - blockNumber - 1);
int r_tmpL = r_tmp << (this.blockSize - remainingBits);
int r_tmpR = r_tmpL >>> (this.blockSize - remainingBits); // unsigned shift operator
res_tmpArray[result.getRepresentation().size() - blockNumber - 1] = r_tmpR;
result.setRepresentation(res_tmpArray);
return result;
}
/**
* Multiplies the calling BigInt with the given BigInt (they can have a different bit size)
*
* @param b BigInt to multiply with (BigInt)
* @return The result of the multiplication (BigInt)
*/
public BigInt mul(BigInt b) {
BigInt result = new BigInt(b.getBitLength() + this.bitLength);
BigInt tmp = new BigInt(b.getBitLength() + this.bitLength);
int[] tmpArray = new int[result.getRepresentation().size()];
Arrays.fill(tmpArray, 0);
int shift = blockSize - 1;
long tmpMul;
for (int i = b.getRepresentation().size() - 1; i >= 0; i--) {
for (int j = this.representation.size() - 1; j >= 0; j--) {
Arrays.fill(tmpArray, 0);
tmpMul = (long) this.representation.get(j) * (long) b.getRepresentation().get(i);
long tmp2 = (tmpMul >> shift);
int leftBlock = (int) (tmp2);
int rightBlock = (int) (tmpMul & resMask);
tmpArray[i + j + 1] = rightBlock;
tmpArray[i + j] = leftBlock;
tmp.setRepresentation(tmpArray);
result = result.add(tmp);
}
}
return result;
}
/**
* Modular addition with another BigInt
*
* @param b BigInt to add (BigInt)
* @param mod Modular (BigInt)
* @return The result of the modular addition (BigInt)
*/
public BigInt add_mod(BigInt b, BigInt mod) {
// check modulo size
// this and b must be mod mod
BigInt result = this.add(b);
if (!result.isGreater(mod) || result.isEqual(mod)) {
return result;
} else {
return result.sub(mod);
}
}
/**
* Adds a BigInt to the calling BigInt object (without mod)
*
* @param b BigInt object to add (BigInt)
* @return the result of the addition (BigInt)
*/
public BigInt add(BigInt b) {
int carry = 0;
long tmpRes; // intermediate result
int[] resultArray = new int[this.representation.size()];
BigInt result = new BigInt(this.bitLength); // use another constructor
int stop = 0;
int start = 0;
for (int i = this.representation.size() - 1; i >= 0; i--) {
tmpRes = (long) this.representation.get(i) + (long) b.getRepresentation().get(i) + (long) carry;
carry = (int) (tmpRes >> blockSize - 1); // get the carry and transform it to a int
resultArray[i] = (int) (tmpRes & resMask);
}
result.setRepresentation(resultArray);
return result;
}
/**
* Modular subtraction between BigInt objects (this minus b mod mod)
*
* @param b The BigInt you want to subtract (BigInt)
* @param mod the modulus (BigInt)
* @return Result of the modular subtraction (BigInt)
*/
public BigInt sub_mod(BigInt b, BigInt mod) {
BigInt result;
if (this.isGreater(b) || this.isEqual(b)) {
result = this.sub(b);
} else {
result = this.add(mod);
result = result.sub(b);
}
return result;
}
/**
* Classic subtraction 32bits-words by 32bits-word
*
* @param b BigInt to subtract (BigInt)
* @return the result of the classic subtraction (BigInt)
*/
public BigInt sub(BigInt b) {
BigInt result = new BigInt();
try {
if (this.representation.size() != b.getRepresentation().size()) {
throw new Exception("sub: A and B must have the same size");
} else {
int[] resultRepresentation = new int[this.representation.size()];
int carry = 1;
for (int i = this.representation.size() - 1; i > 0; i--) {
int ai = this.representation.get(i);
int bi = b.getRepresentation().get(i);
if (ai >= bi) { //a[i] >= b[i]
resultRepresentation[i] = ai - bi;
} else {
resultRepresentation[i] = ai + base - bi;
b.getRepresentation().set(i - 1, b.getRepresentation().get(i - 1) + carry);
}
}
result.setRepresentation(resultRepresentation);
}
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return result;
}
/**
* Extends the length of the calling BigInt by 2
*/
public BigInt extendLengthByTwo() {
BigInt result = new BigInt(2 * this.bitLength);
int[] tmpArray = new int[this.getRepresentation().size() * 2];
Arrays.fill(tmpArray, 0);
for (int i = 0; i < this.getRepresentation().size(); i++) {
tmpArray[i] = this.getRepresentation().get(i);
}
int[] tmpArrayInv = reverse(tmpArray);
result.setRepresentation(tmpArrayInv);
return result;
}
/**
* Sets the bit length of the calling BigInt object
*
* @param bitLength new bit length (int)
*/
private void setBitLength(int bitLength) {
this.bitLength = bitLength;
}
/**
* Reverses an array ([1, 2, 3] will become [3, 2, 1])
*
* @param a The integer array to reverse (int[])
* @return A new array which is the inverted array
*/
public int[] reverse(int[] a) {
int n = a.length;
int[] b = new int[n];
int j = n;
for (int value : a) {
b[j - 1] = value;
j = j - 1;
}
return b;
}
/**
* Copies a BigInt object into the calling BigInt
*
* @param toCopy The BigInt object to copy into the current BigInt (BigInt)
*/
public void copy(BigInt toCopy) {
try {
for (int i = 0; i < toCopy.getRepresentation().size(); i++) {
this.representation.set(i, toCopy.representation.get(i));
}
} catch (Exception e) {
System.out.println("copy: A must have at least the same size as B");
}
}
/**
* Returns a string representation of the object
*
* @return String representation of the object (String)
*/
public String toString() {
return "BigInt" + this.representation.toString();
}
/**
* Gets the bitLength of the BigInt
*
* @return bitLength og the BigInt (int)
*/
public int getBitLength() {
return bitLength;
}
/**
* Gets the representation
*
* @return The object representation (List<Integer>)
*/
public List<Integer> getRepresentation() {
return representation;
}
/**
* Sets the representation
*
* @param representation New representation (List<Integer>)
*/
public void setRepresentation(List<Integer> representation) {
copy(representation);
}
/**
* Sets the representation
*
* @param representation New representation (int[])
*/
public void setRepresentation(int[] representation) {
copy(representation);
}
/**
* Copies an integer list into the representation list
*
* @param toCopy The integer list to copy into the representation (List<Integer>)
*/
private void copy(List<Integer> toCopy) {
try {
for (int i = 0; i < toCopy.size(); i++) {
this.representation.set(i, toCopy.get(i));
}
} catch (Exception e) {
System.out.println("copy: A must have at least the same size as B");
}
}
/**
* Copies an integer array into the representation list
*
* @param toCopy The integer array to copy into the representation (int[])
*/
private void copy(int[] toCopy) {
try {
for (int i = 0; i < toCopy.length; i++) {
this.representation.set(i, toCopy[i]);
}
} catch (Exception e) {
System.out.println("copy: A must have at least the same size as B");
}
}
/**
* Converts an integer into a bin string of size blockSize - 1
*
* @param a the integer to convert (int)
* @return the string of the binary transformation of the integer (String)
*/
private String convertIntToBinString(int a) {
StringBuilder result = new StringBuilder(Integer.toBinaryString(a));
if (result.length() < blockSize - 1) {
for (int i = 0; i < (blockSize - 1) - result.length(); i++) {
result.insert(0, "0");
}
}
return result.toString();
}
/**
* Truncates the calling BigInt to 512bits
* Avoid using this function !!
*
* @return A new BigInt on 512 bits
*/
private BigInt castTo512bits() {
BigInt result = new BigInt(512);
int[] rep = new int[16];
for (int i = 0; i < result.getRepresentation().size(); i++) {
rep[rep.length - 1 - i] = this.getRepresentation().get(this.getRepresentation().size() - 1 - i);
}
result.setRepresentation(rep);
return result;
}
}