blob: 74d86b75720e13b20ac7d55ac61421c9041ac1ff [file]
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.ec.ed;
import sun.security.ec.point.*;
import sun.security.util.math.*;
import java.math.BigInteger;
import java.util.function.Function;
/*
* Elliptic curve point arithmetic, decoding, and other operations for the
* family of curves including edwards25519 and its related group. Though the
* operations in this class are optimized for edwards25519, they are correct
* for any twisted Edwards curve ax^2 + y^2 = 1 + dx^2y^2 (mod p) with the
* following properties:
* 1) a = -1 (mod p)
* 2) a is square (mod p)
* 3) d is not square (mod p)
*/
public class Ed25519Operations extends EdECOperations {
private final SmallValue two;
private final ImmutableIntegerModuloP d;
private final ExtendedHomogeneousPoint.Immutable basePoint;
private static final BigInteger TWO = BigInteger.valueOf(2);
private static final BigInteger SEVEN = BigInteger.valueOf(7);
private final BigInteger sizeMinus5;
public Ed25519Operations(ImmutableIntegerModuloP d, BigInteger baseX,
BigInteger baseY) {
this.two = d.getField().getSmallValue(2);
this.d = d;
this.basePoint = of(new AffinePoint(
d.getField().getElement(baseX), d.getField().getElement(baseY)
));
this.sizeMinus5 =
d.getField().getSize().subtract(BigInteger.valueOf(5));
}
@Override
public Point basePointMultiply(byte[] scalar) {
return setProduct(basePoint.mutable(), scalar);
}
@Override
protected ExtendedHomogeneousPoint.Immutable getNeutral() {
IntegerFieldModuloP field = d.getField();
return new ExtendedHomogeneousPoint.Immutable(field.get0(),
field.get1(), field.get0(), field.get1());
}
@Override
protected MutablePoint setSum(MutablePoint p1, MutablePoint p2,
MutableIntegerModuloP t1,
MutableIntegerModuloP t2,
MutableIntegerModuloP t3) {
ExtendedHomogeneousPoint.Mutable ehp1 =
(ExtendedHomogeneousPoint.Mutable) p1;
ExtendedHomogeneousPoint.Mutable ehp2 =
(ExtendedHomogeneousPoint.Mutable) p2;
return setSum(ehp1, ehp2, t1, t2, t3);
}
@Override
protected MutablePoint setDouble(MutablePoint p, MutableIntegerModuloP t1,
MutableIntegerModuloP t2) {
ExtendedHomogeneousPoint.Mutable ehp =
(ExtendedHomogeneousPoint.Mutable) p;
return setDouble(ehp, t1, t2);
}
@Override
public ExtendedHomogeneousPoint.Immutable of(AffinePoint p) {
return new ExtendedHomogeneousPoint.Immutable(p.getX(), p.getY(),
p.getX().multiply(p.getY()), p.getX().getField().get1());
}
@Override
public <T extends Throwable>
AffinePoint decodeAffinePoint(Function<String, T> exception,
int xLSB, IntegerModuloP y) throws T {
IntegerFieldModuloP field = d.getField();
BigInteger p = field.getSize();
ImmutableIntegerModuloP y2 = y.square();
ImmutableIntegerModuloP u = y2.subtract(field.get1());
MutableIntegerModuloP v = d.mutable().setProduct(y2)
.setSum(field.get1());
MutableIntegerModuloP x =
u.mutable().setProduct(v.pow(BigInteger.valueOf(3)));
ImmutableIntegerModuloP uv7pow =
u.multiply(v.pow(SEVEN)).pow(sizeMinus5.shiftRight(3));
x.setProduct(uv7pow);
v.setProduct(x).setProduct(x);
// v now holds vx^2
BigInteger bigVX2 = v.asBigInteger();
if (bigVX2.equals(u.asBigInteger())) {
// do nothing---x is correct
} else if (bigVX2.equals(u.additiveInverse().asBigInteger())) {
BigInteger exp = p.subtract(BigInteger.ONE).shiftRight(2);
IntegerModuloP twoPow = field.getElement(TWO.modPow(exp, p));
x.setProduct(twoPow);
} else {
throw exception.apply("Invalid point");
}
if (x.asBigInteger().equals(BigInteger.ZERO) && xLSB == 1) {
throw exception.apply("Invalid point");
}
if (xLSB != (x.asBigInteger().intValue() & 1)) {
x.setAdditiveInverse();
}
return new AffinePoint(x.fixed(), y.fixed());
}
ExtendedHomogeneousPoint.Mutable setSum(
ExtendedHomogeneousPoint.Mutable p1,
ExtendedHomogeneousPoint.Mutable p2,
MutableIntegerModuloP t1,
MutableIntegerModuloP t2,
MutableIntegerModuloP t3) {
t1.setValue(p2.getY()).setDifference(p2.getX());
// t1 holds y2 - x2
t2.setValue(p1.getY()).setDifference(p1.getX()).setProduct(t1);
// t2 holds A = (y1 - x1) * (y2 - x2)
t1.setValue(p2.getY()).setSum(p2.getX());
// t1 holds y2 + x2
t3.setValue(p1.getY()).setSum(p1.getX()).setProduct(t1);
// t3 holds B = (y1 + x1) * (y2 + x2)
p1.getX().setValue(t3).setDifference(t2);
// x holds E = B - A
t3.setSum(t2);
// t3 holds H = B + A, t2 is unused
t2.setValue(d).setSum(d).setProduct(p1.getT()).setProduct(p2.getT());
// t2 holds C
t1.setValue(p1.getZ()).setProduct(p2.getZ()).setProduct(two);
// t1 holds D
p1.getY().setValue(t1).setSum(t2);
// y holds G
p1.getZ().setValue(t1).setDifference(t2);
// z holds F
p1.getT().setValue(p1.getX()).setProduct(t3);
p1.getX().setProduct(p1.getZ());
p1.getZ().setProduct(p1.getY());
p1.getY().setProduct(t3);
return p1;
}
protected ExtendedHomogeneousPoint.Mutable setDouble(
ExtendedHomogeneousPoint.Mutable p,
MutableIntegerModuloP t1, MutableIntegerModuloP t2) {
t1.setValue(p.getX()).setSum(p.getY()).setSquare();
// t1 holds (x + y)^2
p.getX().setSquare();
// x = A = x^2
p.getY().setSquare();
// y = B = y^2
t2.setValue(p.getX()).setSum(p.getY());
// t2 holds H
p.getZ().setSquare().setProduct(two);
// z holds C
p.getT().setValue(t2).setDifference(t1);
// t holds E
t1.setValue(p.getX()).setDifference(p.getY());
// t1 holds G
p.getZ().setSum(t1);
// z holds F
p.getX().setValue(p.getT()).setProduct(p.getZ());
p.getY().setValue(t1).setProduct(t2);
p.getT().setProduct(t2);
p.getZ().setProduct(t1);
return p;
}
}