Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.crypto.ec/share/classes/sun/security/ec/ECOperations.java
41161 views
1
/*
2
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.ec;
27
28
import sun.security.ec.point.*;
29
import sun.security.util.math.*;
30
import sun.security.util.math.intpoly.*;
31
32
import java.math.BigInteger;
33
import java.security.ProviderException;
34
import java.security.spec.ECFieldFp;
35
import java.security.spec.ECParameterSpec;
36
import java.security.spec.EllipticCurve;
37
import java.util.Map;
38
import java.util.Optional;
39
40
/*
41
* Elliptic curve point arithmetic for prime-order curves where a=-3.
42
* Formulas are derived from "Complete addition formulas for prime order
43
* elliptic curves" by Renes, Costello, and Batina.
44
*/
45
46
public class ECOperations {
47
48
/*
49
* An exception indicating a problem with an intermediate value produced
50
* by some part of the computation. For example, the signing operation
51
* will throw this exception to indicate that the r or s value is 0, and
52
* that the signing operation should be tried again with a different nonce.
53
*/
54
static class IntermediateValueException extends Exception {
55
private static final long serialVersionUID = 1;
56
}
57
58
static final Map<BigInteger, IntegerFieldModuloP> fields = Map.of(
59
IntegerPolynomialP256.MODULUS, new IntegerPolynomialP256(),
60
IntegerPolynomialP384.MODULUS, new IntegerPolynomialP384(),
61
IntegerPolynomialP521.MODULUS, new IntegerPolynomialP521()
62
);
63
64
static final Map<BigInteger, IntegerFieldModuloP> orderFields = Map.of(
65
P256OrderField.MODULUS, new P256OrderField(),
66
P384OrderField.MODULUS, new P384OrderField(),
67
P521OrderField.MODULUS, new P521OrderField()
68
);
69
70
public static Optional<ECOperations> forParameters(ECParameterSpec params) {
71
72
EllipticCurve curve = params.getCurve();
73
if (!(curve.getField() instanceof ECFieldFp)) {
74
return Optional.empty();
75
}
76
ECFieldFp primeField = (ECFieldFp) curve.getField();
77
78
BigInteger three = BigInteger.valueOf(3);
79
if (!primeField.getP().subtract(curve.getA()).equals(three)) {
80
return Optional.empty();
81
}
82
IntegerFieldModuloP field = fields.get(primeField.getP());
83
if (field == null) {
84
return Optional.empty();
85
}
86
87
IntegerFieldModuloP orderField = orderFields.get(params.getOrder());
88
if (orderField == null) {
89
return Optional.empty();
90
}
91
92
ImmutableIntegerModuloP b = field.getElement(curve.getB());
93
ECOperations ecOps = new ECOperations(b, orderField);
94
return Optional.of(ecOps);
95
}
96
97
final ImmutableIntegerModuloP b;
98
final SmallValue one;
99
final SmallValue two;
100
final SmallValue three;
101
final SmallValue four;
102
final ProjectivePoint.Immutable neutral;
103
private final IntegerFieldModuloP orderField;
104
105
public ECOperations(IntegerModuloP b, IntegerFieldModuloP orderField) {
106
this.b = b.fixed();
107
this.orderField = orderField;
108
109
this.one = b.getField().getSmallValue(1);
110
this.two = b.getField().getSmallValue(2);
111
this.three = b.getField().getSmallValue(3);
112
this.four = b.getField().getSmallValue(4);
113
114
IntegerFieldModuloP field = b.getField();
115
this.neutral = new ProjectivePoint.Immutable(field.get0(),
116
field.get1(), field.get0());
117
}
118
119
public IntegerFieldModuloP getField() {
120
return b.getField();
121
}
122
public IntegerFieldModuloP getOrderField() {
123
return orderField;
124
}
125
126
protected ProjectivePoint.Immutable getNeutral() {
127
return neutral;
128
}
129
130
public boolean isNeutral(Point p) {
131
ProjectivePoint<?> pp = (ProjectivePoint<?>) p;
132
133
IntegerModuloP z = pp.getZ();
134
135
IntegerFieldModuloP field = z.getField();
136
int byteLength = (field.getSize().bitLength() + 7) / 8;
137
byte[] zBytes = z.asByteArray(byteLength);
138
return allZero(zBytes);
139
}
140
141
byte[] seedToScalar(byte[] seedBytes)
142
throws IntermediateValueException {
143
144
// Produce a nonce from the seed using FIPS 186-4,section B.5.1:
145
// Per-Message Secret Number Generation Using Extra Random Bits
146
// or
147
// Produce a scalar from the seed using FIPS 186-4, section B.4.1:
148
// Key Pair Generation Using Extra Random Bits
149
150
// To keep the implementation simple, sample in the range [0,n)
151
// and throw IntermediateValueException in the (unlikely) event
152
// that the result is 0.
153
154
// Get 64 extra bits and reduce in to the nonce
155
int seedBits = orderField.getSize().bitLength() + 64;
156
if (seedBytes.length * 8 < seedBits) {
157
throw new ProviderException("Incorrect seed length: " +
158
seedBytes.length * 8 + " < " + seedBits);
159
}
160
161
// input conversion only works on byte boundaries
162
// clear high-order bits of last byte so they don't influence nonce
163
int lastByteBits = seedBits % 8;
164
if (lastByteBits != 0) {
165
int lastByteIndex = seedBits / 8;
166
byte mask = (byte) (0xFF >>> (8 - lastByteBits));
167
seedBytes[lastByteIndex] &= mask;
168
}
169
170
int seedLength = (seedBits + 7) / 8;
171
IntegerModuloP scalarElem =
172
orderField.getElement(seedBytes, 0, seedLength, (byte) 0);
173
int scalarLength = (orderField.getSize().bitLength() + 7) / 8;
174
byte[] scalarArr = new byte[scalarLength];
175
scalarElem.asByteArray(scalarArr);
176
if (ECOperations.allZero(scalarArr)) {
177
throw new IntermediateValueException();
178
}
179
return scalarArr;
180
}
181
182
/*
183
* Compare all values in the array to 0 without branching on any value
184
*
185
*/
186
public static boolean allZero(byte[] arr) {
187
byte acc = 0;
188
for (int i = 0; i < arr.length; i++) {
189
acc |= arr[i];
190
}
191
return acc == 0;
192
}
193
194
/*
195
* 4-bit branchless array lookup for projective points.
196
*/
197
private void lookup4(ProjectivePoint.Immutable[] arr, int index,
198
ProjectivePoint.Mutable result, IntegerModuloP zero) {
199
200
for (int i = 0; i < 16; i++) {
201
int xor = index ^ i;
202
int bit3 = (xor & 0x8) >>> 3;
203
int bit2 = (xor & 0x4) >>> 2;
204
int bit1 = (xor & 0x2) >>> 1;
205
int bit0 = (xor & 0x1);
206
int inverse = bit0 | bit1 | bit2 | bit3;
207
int set = 1 - inverse;
208
209
ProjectivePoint.Immutable pi = arr[i];
210
result.conditionalSet(pi, set);
211
}
212
}
213
214
private void double4(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
215
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
216
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
217
218
for (int i = 0; i < 4; i++) {
219
setDouble(p, t0, t1, t2, t3, t4);
220
}
221
}
222
223
/**
224
* Multiply an affine point by a scalar and return the result as a mutable
225
* point.
226
*
227
* @param affineP the point
228
* @param s the scalar as a little-endian array
229
* @return the product
230
*/
231
public MutablePoint multiply(AffinePoint affineP, byte[] s) {
232
233
// 4-bit windowed multiply with branchless lookup.
234
// The mixed addition is faster, so it is used to construct the array
235
// at the beginning of the operation.
236
237
IntegerFieldModuloP field = affineP.getX().getField();
238
ImmutableIntegerModuloP zero = field.get0();
239
// temporaries
240
MutableIntegerModuloP t0 = zero.mutable();
241
MutableIntegerModuloP t1 = zero.mutable();
242
MutableIntegerModuloP t2 = zero.mutable();
243
MutableIntegerModuloP t3 = zero.mutable();
244
MutableIntegerModuloP t4 = zero.mutable();
245
246
ProjectivePoint.Mutable result = new ProjectivePoint.Mutable(field);
247
result.getY().setValue(field.get1().mutable());
248
249
ProjectivePoint.Immutable[] pointMultiples =
250
new ProjectivePoint.Immutable[16];
251
// 0P is neutral---same as initial result value
252
pointMultiples[0] = result.fixed();
253
254
ProjectivePoint.Mutable ps = new ProjectivePoint.Mutable(field);
255
ps.setValue(affineP);
256
// 1P = P
257
pointMultiples[1] = ps.fixed();
258
259
// the rest are calculated using mixed point addition
260
for (int i = 2; i < 16; i++) {
261
setSum(ps, affineP, t0, t1, t2, t3, t4);
262
pointMultiples[i] = ps.fixed();
263
}
264
265
ProjectivePoint.Mutable lookupResult = ps.mutable();
266
267
for (int i = s.length - 1; i >= 0; i--) {
268
269
double4(result, t0, t1, t2, t3, t4);
270
271
int high = (0xFF & s[i]) >>> 4;
272
lookup4(pointMultiples, high, lookupResult, zero);
273
setSum(result, lookupResult, t0, t1, t2, t3, t4);
274
275
double4(result, t0, t1, t2, t3, t4);
276
277
int low = 0xF & s[i];
278
lookup4(pointMultiples, low, lookupResult, zero);
279
setSum(result, lookupResult, t0, t1, t2, t3, t4);
280
}
281
282
return result;
283
284
}
285
286
/*
287
* Point double
288
*/
289
private void setDouble(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
290
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
291
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
292
293
t0.setValue(p.getX()).setSquare();
294
t1.setValue(p.getY()).setSquare();
295
t2.setValue(p.getZ()).setSquare();
296
t3.setValue(p.getX()).setProduct(p.getY());
297
t4.setValue(p.getY()).setProduct(p.getZ());
298
299
t3.setSum(t3);
300
p.getZ().setProduct(p.getX());
301
302
p.getZ().setProduct(two);
303
304
p.getY().setValue(t2).setProduct(b);
305
p.getY().setDifference(p.getZ());
306
307
p.getX().setValue(p.getY()).setProduct(two);
308
p.getY().setSum(p.getX());
309
p.getY().setReduced();
310
p.getX().setValue(t1).setDifference(p.getY());
311
312
p.getY().setSum(t1);
313
p.getY().setProduct(p.getX());
314
p.getX().setProduct(t3);
315
316
t3.setValue(t2).setProduct(two);
317
t2.setSum(t3);
318
p.getZ().setProduct(b);
319
320
t2.setReduced();
321
p.getZ().setDifference(t2);
322
p.getZ().setDifference(t0);
323
t3.setValue(p.getZ()).setProduct(two);
324
p.getZ().setReduced();
325
p.getZ().setSum(t3);
326
t0.setProduct(three);
327
328
t0.setDifference(t2);
329
t0.setProduct(p.getZ());
330
p.getY().setSum(t0);
331
332
t4.setSum(t4);
333
p.getZ().setProduct(t4);
334
335
p.getX().setDifference(p.getZ());
336
p.getZ().setValue(t4).setProduct(t1);
337
338
p.getZ().setProduct(four);
339
340
}
341
342
/*
343
* Mixed point addition. This method constructs new temporaries each time
344
* it is called. For better efficiency, the method that reuses temporaries
345
* should be used if more than one sum will be computed.
346
*/
347
public void setSum(MutablePoint p, AffinePoint p2) {
348
349
IntegerModuloP zero = p.getField().get0();
350
MutableIntegerModuloP t0 = zero.mutable();
351
MutableIntegerModuloP t1 = zero.mutable();
352
MutableIntegerModuloP t2 = zero.mutable();
353
MutableIntegerModuloP t3 = zero.mutable();
354
MutableIntegerModuloP t4 = zero.mutable();
355
setSum((ProjectivePoint.Mutable) p, p2, t0, t1, t2, t3, t4);
356
357
}
358
359
/*
360
* Mixed point addition
361
*/
362
private void setSum(ProjectivePoint.Mutable p, AffinePoint p2,
363
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
364
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
365
MutableIntegerModuloP t4) {
366
367
t0.setValue(p.getX()).setProduct(p2.getX());
368
t1.setValue(p.getY()).setProduct(p2.getY());
369
t3.setValue(p2.getX()).setSum(p2.getY());
370
t4.setValue(p.getX()).setSum(p.getY());
371
p.getX().setReduced();
372
t3.setProduct(t4);
373
t4.setValue(t0).setSum(t1);
374
375
t3.setDifference(t4);
376
t4.setValue(p2.getY()).setProduct(p.getZ());
377
t4.setSum(p.getY());
378
379
p.getY().setValue(p2.getX()).setProduct(p.getZ());
380
p.getY().setSum(p.getX());
381
t2.setValue(p.getZ());
382
p.getZ().setProduct(b);
383
384
p.getX().setValue(p.getY()).setDifference(p.getZ());
385
p.getX().setReduced();
386
p.getZ().setValue(p.getX()).setProduct(two);
387
p.getX().setSum(p.getZ());
388
389
p.getZ().setValue(t1).setDifference(p.getX());
390
p.getX().setSum(t1);
391
p.getY().setProduct(b);
392
393
t1.setValue(t2).setProduct(two);
394
t2.setSum(t1);
395
t2.setReduced();
396
p.getY().setDifference(t2);
397
398
p.getY().setDifference(t0);
399
p.getY().setReduced();
400
t1.setValue(p.getY()).setProduct(two);
401
p.getY().setSum(t1);
402
403
t1.setValue(t0).setProduct(two);
404
t0.setSum(t1);
405
t0.setDifference(t2);
406
407
t1.setValue(t4).setProduct(p.getY());
408
t2.setValue(t0).setProduct(p.getY());
409
p.getY().setValue(p.getX()).setProduct(p.getZ());
410
411
p.getY().setSum(t2);
412
p.getX().setProduct(t3);
413
p.getX().setDifference(t1);
414
415
p.getZ().setProduct(t4);
416
t1.setValue(t3).setProduct(t0);
417
p.getZ().setSum(t1);
418
419
}
420
421
/*
422
* Projective point addition
423
*/
424
private void setSum(ProjectivePoint.Mutable p, ProjectivePoint.Mutable p2,
425
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
426
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
427
MutableIntegerModuloP t4) {
428
429
t0.setValue(p.getX()).setProduct(p2.getX());
430
t1.setValue(p.getY()).setProduct(p2.getY());
431
t2.setValue(p.getZ()).setProduct(p2.getZ());
432
433
t3.setValue(p.getX()).setSum(p.getY());
434
t4.setValue(p2.getX()).setSum(p2.getY());
435
t3.setProduct(t4);
436
437
t4.setValue(t0).setSum(t1);
438
t3.setDifference(t4);
439
t4.setValue(p.getY()).setSum(p.getZ());
440
441
p.getY().setValue(p2.getY()).setSum(p2.getZ());
442
t4.setProduct(p.getY());
443
p.getY().setValue(t1).setSum(t2);
444
445
t4.setDifference(p.getY());
446
p.getX().setSum(p.getZ());
447
p.getY().setValue(p2.getX()).setSum(p2.getZ());
448
449
p.getX().setProduct(p.getY());
450
p.getY().setValue(t0).setSum(t2);
451
p.getY().setAdditiveInverse().setSum(p.getX());
452
p.getY().setReduced();
453
454
p.getZ().setValue(t2).setProduct(b);
455
p.getX().setValue(p.getY()).setDifference(p.getZ());
456
p.getZ().setValue(p.getX()).setProduct(two);
457
458
p.getX().setSum(p.getZ());
459
p.getX().setReduced();
460
p.getZ().setValue(t1).setDifference(p.getX());
461
p.getX().setSum(t1);
462
463
p.getY().setProduct(b);
464
t1.setValue(t2).setSum(t2);
465
t2.setSum(t1);
466
t2.setReduced();
467
468
p.getY().setDifference(t2);
469
p.getY().setDifference(t0);
470
p.getY().setReduced();
471
t1.setValue(p.getY()).setSum(p.getY());
472
473
p.getY().setSum(t1);
474
t1.setValue(t0).setProduct(two);
475
t0.setSum(t1);
476
477
t0.setDifference(t2);
478
t1.setValue(t4).setProduct(p.getY());
479
t2.setValue(t0).setProduct(p.getY());
480
481
p.getY().setValue(p.getX()).setProduct(p.getZ());
482
p.getY().setSum(t2);
483
p.getX().setProduct(t3);
484
485
p.getX().setDifference(t1);
486
p.getZ().setProduct(t4);
487
t1.setValue(t3).setProduct(t0);
488
489
p.getZ().setSum(t1);
490
491
}
492
}
493
494
495