Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import sun.security.util.ECUtil;
import sun.security.util.NamedCurve;
import sun.security.util.math.IntegerFieldModuloP;
import sun.security.util.math.IntegerMontgomeryFieldModuloP;
import sun.security.util.math.MutableIntegerModuloP;
import sun.security.util.math.SmallValue;

Expand Down Expand Up @@ -265,6 +266,11 @@ byte[] deriveKeyImpl(ECPrivateKey priv, ECOperations ops,
ECPublicKey pubKey) throws InvalidKeyException {

IntegerFieldModuloP field = ops.getField();
if (field instanceof IntegerMontgomeryFieldModuloP) {
// No point of doing a single SmallValue operation in Montgomery domain
field = ((IntegerMontgomeryFieldModuloP)field).residueField();
}

// convert s array into field element and multiply by the cofactor
MutableIntegerModuloP scalar = field.getElement(priv.getS()).mutable();
SmallValue cofactor =
Expand Down
192 changes: 67 additions & 125 deletions src/java.base/share/classes/sun/security/ec/ECOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,31 +202,28 @@ public static boolean allZero(byte[] arr) {
* @return the product
*/
public MutablePoint multiply(AffinePoint affineP, byte[] s) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like there could be some combining of both multiply(). If multiply(AffinePoint, ...) is called, it can call DefaultMultiplier with the affineP, but internally call the other multiply(ECPoint, ...) for the other situations. I'd rather not have two methods doing most of the same code, but different methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, they indeed look identical, didnt notice. Fixed. (repeated the same hashmap refactoring and didnt notice I produced identical code twice)

return multiply(affineP.toECPoint(), s);
PointMultiplier multiplier = null;
if (getField() instanceof IntegerMontgomeryFieldModuloP
&& affineP.equals(Secp256R1GeneratorMontgomeryMultiplier.generator)) {
// Lazy class loading when this function is called (large static constant table)
multiplier = Secp256R1GeneratorMontgomeryMultiplier.multiplier;
} else {
multiplier = new DefaultMultiplier(this, affineP);
}

return multiplier.pointMultiply(s);
}

/**
* Multiply an affine ecpoint point by a scalar and return the result as a mutable
* point.
*
* @param affineP the point
* @param ecPoint the point
* @param s the scalar as a little-endian array
* @return the product
*/
public MutablePoint multiply(ECPoint ecPoint, byte[] s) {
// Route to Basepoint and/or Montgomery pointMultiply as appropriate

PointMultiplier multiplier = null;
if (!(b.getField() instanceof IntegerMontgomeryFieldModuloP)) {
multiplier = new DefaultMultiplier(this, ecPoint);
} else if (ecPoint.equals(Secp256R1GeneratorMontgomeryMultiplier.generator)) {
// Lazy class loading upon function call (large static constant table)
multiplier = Secp256R1GeneratorMontgomeryMultiplier.multiplier;
} else {
multiplier = new DefaultMontgomeryMultiplier(this, ecPoint);
}

return multiplier.pointMultiply(s);
return multiply(AffinePoint.fromECPoint(ecPoint, getField()), s);
}

/*
Expand Down Expand Up @@ -308,18 +305,18 @@ private void setSum(ProjectivePoint.Mutable p, AffinePoint p2,
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
MutableIntegerModuloP t4) {

t0.setValue(p.getX()).setProduct(p2.getX());
t1.setValue(p.getY()).setProduct(p2.getY());
t3.setValue(p2.getX()).setSum(p2.getY());
t0.setValue(p.getX()).setProduct(p2.getX(false));
t1.setValue(p.getY()).setProduct(p2.getY(false));
t3.setValue(p2.getX(false)).setSum(p2.getY(false));
t4.setValue(p.getX()).setSum(p.getY());
t3.setProduct(t4);
t4.setValue(t0).setSum(t1);

t3.setDifference(t4);
t4.setValue(p2.getY()).setProduct(p.getZ());
t4.setValue(p2.getY(false)).setProduct(p.getZ());
t4.setSum(p.getY());

p.getY().setValue(p2.getX()).setProduct(p.getZ());
p.getY().setValue(p2.getX(false)).setProduct(p.getZ());
p.getY().setSum(p.getX());
t2.setValue(p.getZ());
p.getZ().setProduct(b);
Expand Down Expand Up @@ -432,7 +429,7 @@ public boolean checkOrder(ECPoint point) {
}

sealed interface PointMultiplier
permits SmallWindowMultiplier, P256LargeTableMultiplier {
permits DefaultMultiplier, Secp256R1GeneratorMontgomeryMultiplier {
// Multiply the point by a scalar and return the result as a mutable
// point. The multiplier point is specified by the implementation of
// this interface, which could be a general EC point or EC generator
Expand Down Expand Up @@ -463,12 +460,11 @@ private static void lookup(
}
}

sealed static abstract class SmallWindowMultiplier implements PointMultiplier
permits DefaultMultiplier, DefaultMontgomeryMultiplier {
final static class DefaultMultiplier implements PointMultiplier {
private final ECOperations ecOps;
private final ProjectivePoint.Immutable[] pointMultiples;

protected SmallWindowMultiplier(ECOperations ecOps, AffinePoint affineP) {
DefaultMultiplier(ECOperations ecOps, AffinePoint affineP) {
this.ecOps = ecOps;

// Precompute and cache point multiples
Expand Down Expand Up @@ -548,52 +544,31 @@ private void double4(ProjectivePoint.Mutable p,
}

// Represents a multiplier with a larger precomputed table. Intended to be used for Basepoint multiplication
sealed static abstract class P256LargeTableMultiplier implements PointMultiplier
permits Secp256R1GeneratorMontgomeryMultiplier {
final static class Secp256R1GeneratorMontgomeryMultiplier implements PointMultiplier {
private static final ECOperations secp256r1Ops = new ECOperations(
MontgomeryIntegerPolynomialP256.ONE.getElement(CurveDB.P_256.getCurve().getB()),
P256OrderField.ONE);
public static final AffinePoint generator = AffinePoint.fromECPoint(CurveDB.P_256.getGenerator(), secp256r1Ops.getField());
public static final PointMultiplier multiplier = new Secp256R1GeneratorMontgomeryMultiplier();

private final ImmutableIntegerModuloP zero;
private final ImmutableIntegerModuloP one;
private final ECOperations secp256r1Ops;
private final ProjectivePoint.Immutable[][] points;
private final BigInteger[] base;

public ProjectivePoint.Mutable pointMultiply(byte[] s) {
MutableIntegerModuloP t0 = zero.mutable();
MutableIntegerModuloP t1 = zero.mutable();
MutableIntegerModuloP t2 = zero.mutable();
MutableIntegerModuloP t3 = zero.mutable();
MutableIntegerModuloP t4 = zero.mutable();

ProjectivePoint.Mutable d = new ProjectivePoint.Mutable(
zero.mutable(),
one.mutable(),
zero.mutable());
ProjectivePoint.Mutable r = d.mutable();
for (int i = 15; i >= 0; i--) {
secp256r1Ops.setDouble(d, t0, t1, t2, t3, t4);
for (int j = 3; j >= 0; j--) {
int pos = i + j * 16;
int index = (bit(s, pos + 192) << 3) |
(bit(s, pos + 128) << 2) |
(bit(s, pos + 64) << 1) |
bit(s, pos);
private Secp256R1GeneratorMontgomeryMultiplier() {
this(MontgomeryIntegerPolynomialP256.ONE,
new DefaultMultiplier(secp256r1Ops, generator));

PointMultiplier.lookup(points[j], index, r);
secp256r1Ops.setSum(d, r, t0, t1, t2, t3, t4);
}
// Check that the tables are correctly generated.
if (ECOperations.class.desiredAssertionStatus()) {
verifyTables(this);
}

return d;
}

private static int bit(byte[] k, int i) {
return (k[i >> 3] >> (i & 0x07)) & 0x01;
}

protected P256LargeTableMultiplier(ECOperations secp256r1Ops, IntegerFieldModuloP field, PointMultiplier smallTableMultiplier) {
private Secp256R1GeneratorMontgomeryMultiplier(IntegerFieldModuloP field, PointMultiplier smallTableMultiplier) {
zero = field.get0();
one = field.get1();
this.secp256r1Ops = secp256r1Ops;

// Pre-computed table to speed up the point multiplication.
//
Expand Down Expand Up @@ -664,6 +639,39 @@ protected P256LargeTableMultiplier(ECOperations secp256r1Ops, IntegerFieldModulo
}
}

public ProjectivePoint.Mutable pointMultiply(byte[] s) {
MutableIntegerModuloP t0 = zero.mutable();
MutableIntegerModuloP t1 = zero.mutable();
MutableIntegerModuloP t2 = zero.mutable();
MutableIntegerModuloP t3 = zero.mutable();
MutableIntegerModuloP t4 = zero.mutable();

ProjectivePoint.Mutable d = new ProjectivePoint.Mutable(
zero.mutable(),
one.mutable(),
zero.mutable());
ProjectivePoint.Mutable r = d.mutable();
for (int i = 15; i >= 0; i--) {
secp256r1Ops.setDouble(d, t0, t1, t2, t3, t4);
for (int j = 3; j >= 0; j--) {
int pos = i + j * 16;
int index = (bit(s, pos + 192) << 3) |
(bit(s, pos + 128) << 2) |
(bit(s, pos + 64) << 1) |
bit(s, pos);

PointMultiplier.lookup(points[j], index, r);
secp256r1Ops.setSum(d, r, t0, t1, t2, t3, t4);
}
}

return d;
}

private static int bit(byte[] k, int i) {
return (k[i >> 3] >> (i & 0x07)) & 0x01;
}

protected void verifyTables(PointMultiplier multiplier) {
for (int d = 0; d < 4; d++) {
for (int w = 0; w < 16; w++) {
Expand All @@ -680,8 +688,7 @@ protected void verifyTables(PointMultiplier multiplier) {
// Compare this multiplier to the table (generated by Default multiplier)
AffinePoint m = multiplier.pointMultiply(s).asAffine();
AffinePoint v = points[d][w].asAffine();
if (!v.getX().asBigInteger().equals(m.getX().asBigInteger()) ||
!v.getY().asBigInteger().equals(m.getY().asBigInteger())) {
if (!m.equals(v)) {
java.util.HexFormat hex = java.util.HexFormat.of();
throw new RuntimeException("Bad multiple found at ["+d+"]["+w+"]" + hex.formatHex(s) + " " + m.getX().asBigInteger());
}
Expand All @@ -690,69 +697,4 @@ protected void verifyTables(PointMultiplier multiplier) {
}
}
}

final static class DefaultMultiplier extends SmallWindowMultiplier {
public DefaultMultiplier(ECOperations ecOps, AffinePoint affineP) {
super(ecOps, affineP);
}

public DefaultMultiplier(ECOperations ecOps, ECPoint ecPoint) {
super(ecOps, AffinePoint.fromECPoint(ecPoint, ecOps.getField()));
}
}

final static class DefaultMontgomeryMultiplier extends SmallWindowMultiplier {
private final IntegerMontgomeryFieldModuloP montField;

public DefaultMontgomeryMultiplier(ECOperations ecOps, ECPoint ecPoint) {
super(ecOps, AffinePoint.fromECPoint(ecPoint, ecOps.getField()));
this.montField = (IntegerMontgomeryFieldModuloP)ecOps.getField();
}

/**
* Returns result ProjectivePoint in Montgomery domain, so that subsequent operations can also be done in Montgomery domain
* Conversion to residue domain is implicit when this ProjectivePoint is converted to asAffine().
*/
@Override
public ProjectivePoint.Mutable pointMultiply(byte[] s) {
ProjectivePoint.Mutable result = super.pointMultiply(s);
return new ProjectivePoint.MontgomeryMutable(montField,
result.getX(),
result.getY(),
result.getZ());
}
}

final static class Secp256R1GeneratorMontgomeryMultiplier extends P256LargeTableMultiplier {
private static final ECOperations secp256r1Ops = new ECOperations(
MontgomeryIntegerPolynomialP256.ONE.getElement(CurveDB.P_256.getCurve().getB()),
P256OrderField.ONE);
public static final ECPoint generator = CurveDB.P_256.getGenerator();
public static final PointMultiplier multiplier = new Secp256R1GeneratorMontgomeryMultiplier();

private Secp256R1GeneratorMontgomeryMultiplier() {
super(
secp256r1Ops,
MontgomeryIntegerPolynomialP256.ONE,
new DefaultMontgomeryMultiplier(secp256r1Ops, generator));

// Check that the tables are correctly generated.
if (ECOperations.class.desiredAssertionStatus()) {
verifyTables(this);
}
}

/**
* Returns result ProjectivePoint in Montgomery domain, so that subsequent operations can also be done in Montgomery domain
* Conversion to residue domain is implicit when this ProjectivePoint is converted to asAffine().
*/
@Override
public ProjectivePoint.Mutable pointMultiply(byte[] s) {
ProjectivePoint.Mutable result = super.pointMultiply/*Base*/(s);
return new ProjectivePoint.MontgomeryMutable(MontgomeryIntegerPolynomialP256.ONE,
result.getX(),
result.getY(),
result.getZ());
}
}
}
37 changes: 34 additions & 3 deletions src/java.base/share/classes/sun/security/ec/point/AffinePoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import sun.security.util.math.ImmutableIntegerModuloP;
import sun.security.util.math.IntegerFieldModuloP;
import sun.security.util.math.IntegerMontgomeryFieldModuloP;

import java.security.spec.ECPoint;
import java.util.Objects;
Expand Down Expand Up @@ -54,14 +55,30 @@ public static AffinePoint fromECPoint(
}

public ECPoint toECPoint() {
return new ECPoint(x.asBigInteger(), y.asBigInteger());
return new ECPoint(getX().asBigInteger(), getY().asBigInteger());
}

public ImmutableIntegerModuloP getX() {
return getX(true);
}

public ImmutableIntegerModuloP getX(boolean fieldCheck) {
IntegerFieldModuloP field = x.getField();
if (fieldCheck && field instanceof IntegerMontgomeryFieldModuloP) {
return ((IntegerMontgomeryFieldModuloP)field).fromMontgomery(x);
}
return x;
}

public ImmutableIntegerModuloP getY() {
return getY(true);
}

public ImmutableIntegerModuloP getY(boolean fieldCheck) {
IntegerFieldModuloP field = y.getField();
if (fieldCheck && field instanceof IntegerMontgomeryFieldModuloP) {
return ((IntegerMontgomeryFieldModuloP)field).fromMontgomery(y);
}
return y;
}

Expand All @@ -71,8 +88,22 @@ public boolean equals(Object obj) {
return false;
}
AffinePoint p = (AffinePoint) obj;
boolean xEquals = x.asBigInteger().equals(p.x.asBigInteger());
boolean yEquals = y.asBigInteger().equals(p.y.asBigInteger());
boolean xEquals, yEquals;
boolean thisMont = x.getField() instanceof IntegerMontgomeryFieldModuloP;
boolean objMont = p.x.getField() instanceof IntegerMontgomeryFieldModuloP;
if (thisMont ^ objMont == false) {
// both fields same
xEquals = x.asBigInteger().equals(p.x.asBigInteger());
yEquals = y.asBigInteger().equals(p.y.asBigInteger());
} else if (thisMont) { // mismatched fields should not happen in production, but useful in testing
IntegerMontgomeryFieldModuloP field = (IntegerMontgomeryFieldModuloP)x.getField();
xEquals = x.asBigInteger().equals(field.getElement(p.x.asBigInteger()).asBigInteger());
yEquals = y.asBigInteger().equals(field.getElement(p.y.asBigInteger()).asBigInteger());
} else {
IntegerMontgomeryFieldModuloP field = (IntegerMontgomeryFieldModuloP)p.x.getField();
xEquals = field.getElement(x.asBigInteger()).asBigInteger().equals(p.x.asBigInteger());
yEquals = field.getElement(y.asBigInteger()).asBigInteger().equals(p.y.asBigInteger());
}
return xEquals && yEquals;
}

Expand Down
Loading