package sun.security.ec;
import sun.security.ec.point.*;
import sun.security.util.math.*;
import sun.security.util.math.intpoly.*;
import java.math.BigInteger;
import java.security.ProviderException;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.EllipticCurve;
import java.util.Map;
import java.util.Optional;
public class ECOperations {
static class IntermediateValueException extends Exception {
private static final long serialVersionUID = 1;
}
static final Map<BigInteger, IntegerFieldModuloP> fields = Map.of(
IntegerPolynomialP256.MODULUS, new IntegerPolynomialP256(),
IntegerPolynomialP384.MODULUS, new IntegerPolynomialP384(),
IntegerPolynomialP521.MODULUS, new IntegerPolynomialP521()
);
static final Map<BigInteger, IntegerFieldModuloP> orderFields = Map.of(
P256OrderField.MODULUS, new P256OrderField(),
P384OrderField.MODULUS, new P384OrderField(),
P521OrderField.MODULUS, new P521OrderField()
);
public static Optional<ECOperations> forParameters(ECParameterSpec params) {
EllipticCurve curve = params.getCurve();
if (!(curve.getField() instanceof ECFieldFp)) {
return Optional.empty();
}
ECFieldFp primeField = (ECFieldFp) curve.getField();
BigInteger three = BigInteger.valueOf(3);
if (!primeField.getP().subtract(curve.getA()).equals(three)) {
return Optional.empty();
}
IntegerFieldModuloP field = fields.get(primeField.getP());
if (field == null) {
return Optional.empty();
}
IntegerFieldModuloP orderField = orderFields.get(params.getOrder());
if (orderField == null) {
return Optional.empty();
}
ImmutableIntegerModuloP b = field.getElement(curve.getB());
ECOperations ecOps = new ECOperations(b, orderField);
return Optional.of(ecOps);
}
final ImmutableIntegerModuloP b;
final SmallValue one;
final SmallValue two;
final SmallValue three;
final SmallValue four;
final ProjectivePoint.Immutable neutral;
private final IntegerFieldModuloP orderField;
public ECOperations(IntegerModuloP b, IntegerFieldModuloP orderField) {
this.b = b.fixed();
this.orderField = orderField;
this.one = b.getField().getSmallValue(1);
this.two = b.getField().getSmallValue(2);
this.three = b.getField().getSmallValue(3);
this.four = b.getField().getSmallValue(4);
IntegerFieldModuloP field = b.getField();
this.neutral = new ProjectivePoint.Immutable(field.get0(),
field.get1(), field.get0());
}
public IntegerFieldModuloP getField() {
return b.getField();
}
public IntegerFieldModuloP getOrderField() {
return orderField;
}
protected ProjectivePoint.Immutable getNeutral() {
return neutral;
}
public boolean isNeutral(Point p) {
ProjectivePoint<?> pp = (ProjectivePoint<?>) p;
IntegerModuloP z = pp.getZ();
IntegerFieldModuloP field = z.getField();
int byteLength = (field.getSize().bitLength() + 7) / 8;
byte[] zBytes = z.asByteArray(byteLength);
return allZero(zBytes);
}
byte[] seedToScalar(byte[] seedBytes)
throws IntermediateValueException {
int seedBits = orderField.getSize().bitLength() + 64;
if (seedBytes.length * 8 < seedBits) {
throw new ProviderException("Incorrect seed length: " +
seedBytes.length * 8 + " < " + seedBits);
}
int lastByteBits = seedBits % 8;
if (lastByteBits != 0) {
int lastByteIndex = seedBits / 8;
byte mask = (byte) (0xFF >>> (8 - lastByteBits));
seedBytes[lastByteIndex] &= mask;
}
int seedLength = (seedBits + 7) / 8;
IntegerModuloP scalarElem =
orderField.getElement(seedBytes, 0, seedLength, (byte) 0);
int scalarLength = (orderField.getSize().bitLength() + 7) / 8;
byte[] scalarArr = new byte[scalarLength];
scalarElem.asByteArray(scalarArr);
if (ECOperations.allZero(scalarArr)) {
throw new IntermediateValueException();
}
return scalarArr;
}
public static boolean allZero(byte[] arr) {
byte acc = 0;
for (int i = 0; i < arr.length; i++) {
acc |= arr[i];
}
return acc == 0;
}
private void lookup4(ProjectivePoint.Immutable[] arr, int index,
ProjectivePoint.Mutable result, IntegerModuloP zero) {
for (int i = 0; i < 16; i++) {
int xor = index ^ i;
int bit3 = (xor & 0x8) >>> 3;
int bit2 = (xor & 0x4) >>> 2;
int bit1 = (xor & 0x2) >>> 1;
int bit0 = (xor & 0x1);
int inverse = bit0 | bit1 | bit2 | bit3;
int set = 1 - inverse;
ProjectivePoint.Immutable pi = arr[i];
result.conditionalSet(pi, set);
}
}
private void double4(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
for (int i = 0; i < 4; i++) {
setDouble(p, t0, t1, t2, t3, t4);
}
}
public MutablePoint multiply(AffinePoint affineP, byte[] s) {
IntegerFieldModuloP field = affineP.getX().getField();
ImmutableIntegerModuloP zero = field.get0();
MutableIntegerModuloP t0 = zero.mutable();
MutableIntegerModuloP t1 = zero.mutable();
MutableIntegerModuloP t2 = zero.mutable();
MutableIntegerModuloP t3 = zero.mutable();
MutableIntegerModuloP t4 = zero.mutable();
ProjectivePoint.Mutable result = new ProjectivePoint.Mutable(field);
result.getY().setValue(field.get1().mutable());
ProjectivePoint.Immutable[] pointMultiples =
new ProjectivePoint.Immutable[16];
pointMultiples[0] = result.fixed();
ProjectivePoint.Mutable ps = new ProjectivePoint.Mutable(field);
ps.setValue(affineP);
pointMultiples[1] = ps.fixed();
for (int i = 2; i < 16; i++) {
setSum(ps, affineP, t0, t1, t2, t3, t4);
pointMultiples[i] = ps.fixed();
}
ProjectivePoint.Mutable lookupResult = ps.mutable();
for (int i = s.length - 1; i >= 0; i--) {
double4(result, t0, t1, t2, t3, t4);
int high = (0xFF & s[i]) >>> 4;
lookup4(pointMultiples, high, lookupResult, zero);
setSum(result, lookupResult, t0, t1, t2, t3, t4);
double4(result, t0, t1, t2, t3, t4);
int low = 0xF & s[i];
lookup4(pointMultiples, low, lookupResult, zero);
setSum(result, lookupResult, t0, t1, t2, t3, t4);
}
return result;
}
private void setDouble(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
MutableIntegerModuloP t1, MutableIntegerModuloP t2,
MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
t0.setValue(p.getX()).setSquare();
t1.setValue(p.getY()).setSquare();
t2.setValue(p.getZ()).setSquare();
t3.setValue(p.getX()).setProduct(p.getY());
t4.setValue(p.getY()).setProduct(p.getZ());
t3.setSum(t3);
p.getZ().setProduct(p.getX());
p.getZ().setProduct(two);
p.getY().setValue(t2).setProduct(b);
p.getY().setDifference(p.getZ());
p.getX().setValue(p.getY()).setProduct(two);
p.getY().setSum(p.getX());
p.getY().setReduced();
p.getX().setValue(t1).setDifference(p.getY());
p.getY().setSum(t1);
p.getY().setProduct(p.getX());
p.getX().setProduct(t3);
t3.setValue(t2).setProduct(two);
t2.setSum(t3);
p.getZ().setProduct(b);
t2.setReduced();
p.getZ().setDifference(t2);
p.getZ().setDifference(t0);
t3.setValue(p.getZ()).setProduct(two);
p.getZ().setReduced();
p.getZ().setSum(t3);
t0.setProduct(three);
t0.setDifference(t2);
t0.setProduct(p.getZ());
p.getY().setSum(t0);
t4.setSum(t4);
p.getZ().setProduct(t4);
p.getX().setDifference(p.getZ());
p.getZ().setValue(t4).setProduct(t1);
p.getZ().setProduct(four);
}
public void setSum(MutablePoint p, AffinePoint p2) {
IntegerModuloP zero = p.getField().get0();
MutableIntegerModuloP t0 = zero.mutable();
MutableIntegerModuloP t1 = zero.mutable();
MutableIntegerModuloP t2 = zero.mutable();
MutableIntegerModuloP t3 = zero.mutable();
MutableIntegerModuloP t4 = zero.mutable();
setSum((ProjectivePoint.Mutable) p, p2, t0, t1, t2, t3, t4);
}
private void setSum(ProjectivePoint.Mutable p, AffinePoint p2,
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
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());
t4.setValue(p.getX()).setSum(p.getY());
p.getX().setReduced();
t3.setProduct(t4);
t4.setValue(t0).setSum(t1);
t3.setDifference(t4);
t4.setValue(p2.getY()).setProduct(p.getZ());
t4.setSum(p.getY());
p.getY().setValue(p2.getX()).setProduct(p.getZ());
p.getY().setSum(p.getX());
t2.setValue(p.getZ());
p.getZ().setProduct(b);
p.getX().setValue(p.getY()).setDifference(p.getZ());
p.getX().setReduced();
p.getZ().setValue(p.getX()).setProduct(two);
p.getX().setSum(p.getZ());
p.getZ().setValue(t1).setDifference(p.getX());
p.getX().setSum(t1);
p.getY().setProduct(b);
t1.setValue(t2).setProduct(two);
t2.setSum(t1);
t2.setReduced();
p.getY().setDifference(t2);
p.getY().setDifference(t0);
p.getY().setReduced();
t1.setValue(p.getY()).setProduct(two);
p.getY().setSum(t1);
t1.setValue(t0).setProduct(two);
t0.setSum(t1);
t0.setDifference(t2);
t1.setValue(t4).setProduct(p.getY());
t2.setValue(t0).setProduct(p.getY());
p.getY().setValue(p.getX()).setProduct(p.getZ());
p.getY().setSum(t2);
p.getX().setProduct(t3);
p.getX().setDifference(t1);
p.getZ().setProduct(t4);
t1.setValue(t3).setProduct(t0);
p.getZ().setSum(t1);
}
private void setSum(ProjectivePoint.Mutable p, ProjectivePoint.Mutable p2,
MutableIntegerModuloP t0, MutableIntegerModuloP t1,
MutableIntegerModuloP t2, MutableIntegerModuloP t3,
MutableIntegerModuloP t4) {
t0.setValue(p.getX()).setProduct(p2.getX());
t1.setValue(p.getY()).setProduct(p2.getY());
t2.setValue(p.getZ()).setProduct(p2.getZ());
t3.setValue(p.getX()).setSum(p.getY());
t4.setValue(p2.getX()).setSum(p2.getY());
t3.setProduct(t4);
t4.setValue(t0).setSum(t1);
t3.setDifference(t4);
t4.setValue(p.getY()).setSum(p.getZ());
p.getY().setValue(p2.getY()).setSum(p2.getZ());
t4.setProduct(p.getY());
p.getY().setValue(t1).setSum(t2);
t4.setDifference(p.getY());
p.getX().setSum(p.getZ());
p.getY().setValue(p2.getX()).setSum(p2.getZ());
p.getX().setProduct(p.getY());
p.getY().setValue(t0).setSum(t2);
p.getY().setAdditiveInverse().setSum(p.getX());
p.getY().setReduced();
p.getZ().setValue(t2).setProduct(b);
p.getX().setValue(p.getY()).setDifference(p.getZ());
p.getZ().setValue(p.getX()).setProduct(two);
p.getX().setSum(p.getZ());
p.getX().setReduced();
p.getZ().setValue(t1).setDifference(p.getX());
p.getX().setSum(t1);
p.getY().setProduct(b);
t1.setValue(t2).setSum(t2);
t2.setSum(t1);
t2.setReduced();
p.getY().setDifference(t2);
p.getY().setDifference(t0);
p.getY().setReduced();
t1.setValue(p.getY()).setSum(p.getY());
p.getY().setSum(t1);
t1.setValue(t0).setProduct(two);
t0.setSum(t1);
t0.setDifference(t2);
t1.setValue(t4).setProduct(p.getY());
t2.setValue(t0).setProduct(p.getY());
p.getY().setValue(p.getX()).setProduct(p.getZ());
p.getY().setSum(t2);
p.getX().setProduct(t3);
p.getX().setDifference(t1);
p.getZ().setProduct(t4);
t1.setValue(t3).setProduct(t0);
p.getZ().setSum(t1);
}
}