Skip to content

Commit c042b8e

Browse files
committed
8294731: Improve multiplicative inverse for secp256r1 implementation
Reviewed-by: djelinski, jjiang
1 parent d3051a7 commit c042b8e

File tree

1 file changed

+201
-2
lines changed

1 file changed

+201
-2
lines changed

src/java.base/share/classes/sun/security/util/math/IntegerModuloP.java

Lines changed: 201 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525

2626
package sun.security.util.math;
2727

28+
import sun.security.util.math.intpoly.IntegerPolynomialP256;
29+
import sun.security.util.math.intpoly.P256OrderField;
30+
2831
import java.math.BigInteger;
2932

3033
/**
@@ -163,7 +166,7 @@ default ImmutableIntegerModuloP multiplicativeInverse() {
163166
// might be zero (infinity). However, since the infinity
164167
// is represented as (0, 0) in 2D, it's OK returning 0 as
165168
// the inverse of 0, i.e. (1, 1, 0) == (1/0, 1/0) == (0, 0).
166-
return pow(getField().getSize().subtract(BigInteger.valueOf(2)));
169+
return MultiplicativeInverser.of(getField().getSize()).inverse(this);
167170
}
168171

169172
/**
@@ -208,5 +211,201 @@ default ImmutableIntegerModuloP pow(BigInteger b) {
208211
return y.fixed();
209212
}
210213

211-
}
214+
sealed interface MultiplicativeInverser {
215+
static MultiplicativeInverser of(BigInteger m) {
216+
if (m.equals(IntegerPolynomialP256.MODULUS)) {
217+
return Secp256R1.instance;
218+
} else if (m.equals(P256OrderField.MODULUS)) {
219+
return Secp256R1Field.instance;
220+
} else {
221+
return new Default(m);
222+
}
223+
}
224+
225+
/**
226+
* Compute the multiplicative inverse of {@code imp}.
227+
*
228+
* @return the multiplicative inverse (1 / imp)
229+
*/
230+
ImmutableIntegerModuloP inverse(IntegerModuloP imp);
231+
232+
final class Default implements MultiplicativeInverser {
233+
private final BigInteger b;
234+
235+
Default(BigInteger b) {
236+
this.b = b.subtract(BigInteger.TWO);
237+
}
238+
239+
@Override
240+
public ImmutableIntegerModuloP inverse(IntegerModuloP imp) {
241+
MutableIntegerModuloP y = imp.getField().get1().mutable();
242+
MutableIntegerModuloP x = imp.mutable();
243+
int bitLength = b.bitLength();
244+
for (int bit = 0; bit < bitLength; bit++) {
245+
if (b.testBit(bit)) {
246+
// odd
247+
y.setProduct(x);
248+
}
249+
x.setSquare();
250+
}
251+
252+
return y.fixed();
253+
}
254+
}
255+
256+
final class Secp256R1 implements MultiplicativeInverser {
257+
private static final Secp256R1 instance = new Secp256R1();
258+
259+
@Override
260+
public ImmutableIntegerModuloP inverse(IntegerModuloP imp) {
261+
// Invert imp with a modular exponentiation: the modulus is
262+
// p = FFFFFFFF 00000001 00000000 00000000
263+
// 00000000 FFFFFFFF FFFFFFFF FFFFFFFF
264+
// and the exponent is (p -2).
265+
// p -2 = FFFFFFFF 00000001 00000000 00000000
266+
// 00000000 FFFFFFFF FFFFFFFF FFFFFFFD
267+
//
268+
// There are 3 contiguous 32-bit set, and 1 contiguous 30-bit
269+
// set. Thus values imp^(2^32 - 1) and imp^(2^30 - 1) are
270+
// pre-computed to speed up the computation.
271+
272+
// calculate imp ^ (2^32 - 1)
273+
MutableIntegerModuloP t = imp.mutable();
274+
MutableIntegerModuloP v = null;
275+
MutableIntegerModuloP w = null;
276+
for (int i = 0; i < 31; i++) {
277+
t.setSquare();
278+
switch (i) {
279+
case 0 -> {
280+
t.setProduct(imp);
281+
v = t.mutable(); // 2: imp ^ (2^2 - 1)
282+
}
283+
case 4 -> {
284+
t.setProduct(v);
285+
w = t.mutable(); // 4: imp ^ (2^6 - 1)
286+
}
287+
case 12, 28 -> {
288+
t.setProduct(w);
289+
w = t.mutable(); // 12: imp ^ (2^14 - 1)
290+
// 28: imp ^ (2^30 - 1)
291+
}
292+
case 2, 6, 14, 30 -> {
293+
t.setProduct(v);
294+
}
295+
}
296+
}
212297

298+
// here we have:
299+
// v = imp ^ (2^2 - 1)
300+
// w = imp ^ (2^30 - 1)
301+
// t = imp ^ (2^32 - 1)
302+
303+
// calculate (1 / imp)
304+
MutableIntegerModuloP d = t.mutable();
305+
for (int i = 32; i < 256; i++) {
306+
d.setSquare();
307+
switch (i) {
308+
// For contiguous 32-bit set.
309+
case 191, 223 -> {
310+
d.setProduct(t);
311+
}
312+
// For contiguous 30-bit set.
313+
case 253 -> {
314+
d.setProduct(w);
315+
}
316+
// For individual 1-bit set.
317+
case 63, 255 -> {
318+
d.setProduct(imp);
319+
}
320+
}
321+
}
322+
323+
return d.fixed();
324+
}
325+
}
326+
327+
final class Secp256R1Field implements MultiplicativeInverser {
328+
private static final Secp256R1Field instance = new Secp256R1Field();
329+
private static final BigInteger b =
330+
P256OrderField.MODULUS.subtract(BigInteger.TWO);
331+
@Override
332+
public ImmutableIntegerModuloP inverse(IntegerModuloP imp) {
333+
// Invert imp with a modular exponentiation: the modulus is
334+
// n = FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
335+
// BCE6FAAD A7179E84 F3B9CAC2 FC632551
336+
// and the exponent is (n -2).
337+
// n - 2 = FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
338+
// BCE6FAAD A7179E84 F3B9CAC2 FC63254F
339+
//
340+
// There are 3 contiguous 32-bit set, and imp^(2^32 - 1)
341+
// is pre-computed to speed up the computation.
342+
343+
// calculate and cache imp ^ (2^2 - 1) - imp ^ (2^4 - 1)
344+
IntegerModuloP[] w = new IntegerModuloP[4];
345+
w[0] = imp.fixed();
346+
MutableIntegerModuloP t = imp.mutable();
347+
for (int i = 1; i < 4; i++) {
348+
t.setSquare();
349+
t.setProduct(imp);
350+
w[i] = t.fixed();
351+
}
352+
353+
// calculate imp ^ (2^32 - 1)
354+
MutableIntegerModuloP d = null;
355+
for (int i = 4; i < 32; i++) {
356+
t.setSquare();
357+
switch (i) {
358+
case 7 -> {
359+
t.setProduct(w[3]);
360+
d = t.mutable(); // 7: imp ^ (2^8 - 1)
361+
}
362+
case 15 -> {
363+
t.setProduct(d);
364+
d = t.mutable(); // 15: imp ^ (2^16 - 1)
365+
}
366+
case 31 -> {
367+
t.setProduct(d); // 31: imp ^ (2^32 - 1)
368+
}
369+
}
370+
}
371+
372+
// Here we have:
373+
// w[i] = imp ^ (2 ^ ( i + 1) - 1), i = {0, 1, 2, 3}
374+
// t = imp ^ (2^32 - 1)
375+
//
376+
// calculate for bit 32-128, for contiguous 32-bit set.
377+
d = t.mutable();
378+
for (int i = 32; i < 128; i++) {
379+
d.setSquare();
380+
if (i == 95 || i == 127) {
381+
d.setProduct(t);
382+
}
383+
}
384+
385+
// Calculate for bit 128-255, for individual 1-bit set.
386+
for (int k = -1, i = 127; i >= 0; i--) {
387+
if (b.testBit(i)) {
388+
if (k == w.length - 2) {
389+
// calculate the current & reserved bits
390+
d.setSquare();
391+
d.setProduct(w[w.length - 1]);
392+
k = -1;
393+
} else {
394+
k++;
395+
d.setSquare();
396+
}
397+
} else { // calculate the reserved bits
398+
if (k >= 0) {
399+
// add back the reserved bits
400+
d.setProduct(w[k]);
401+
k = -1;
402+
}
403+
d.setSquare();
404+
}
405+
}
406+
407+
return d.fixed();
408+
}
409+
}
410+
}
411+
}

0 commit comments

Comments
 (0)