import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.signers.DSAKCalculator;
import org.bouncycastle.crypto.signers.ECDSASigner;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.sec.SecP256K1Curve;
import org.bouncycastle.util.encoders.Hex;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.stream.Stream;
import static java.math.BigInteger.valueOf;
import static org.junit.jupiter.api.Assertions.*;
public class ECPointTest {
@Test
public void validateECPoints() {
ECCurve.Fp curve = new ECCurve.Fp(valueOf(223), valueOf(0), valueOf(7), null, null);
curve.validatePoint(valueOf(192), valueOf(105));
curve.validatePoint(valueOf(17), valueOf(56));
curve.validatePoint(valueOf(1), valueOf(193));
}
@Test
public void invalidECPoints() {
ECCurve.Fp curve = new ECCurve.Fp(valueOf(223), valueOf(0), valueOf(7), null, null);
assertThrows(IllegalArgumentException.class, () -> curve.validatePoint(valueOf(200), valueOf(119)));
assertThrows(IllegalArgumentException.class, () -> curve.validatePoint(valueOf(42), valueOf(99)));
}
@ParameterizedTest
@MethodSource("addECPointsParameters")
public void addECPoints(ECPoint p1, ECPoint p2, ECPoint expectedResult) {
ECPoint result = p1.add(p2).normalize();
assertEquals(expectedResult, result);
}
@ParameterizedTest
@MethodSource("scalarMultiplyECPointsParameters")
public void scalarMultiplyECPoints(ECPoint p1, BigInteger scalar, ECPoint expectedResult) {
ECPoint result = p1.multiply(scalar).normalize();
assertEquals(expectedResult, result);
}
@Test
public void SecP256k1PointTest() {
BigInteger order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
SecP256K1Curve curve = new SecP256K1Curve();
ECPoint point = curve.createPoint(
new BigInteger(1, Hex.decodeStrict("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")),
new BigInteger(1, Hex.decodeStrict("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"))
);
assertTrue(point.multiply(order).equals(curve.getInfinity()));
}
@ParameterizedTest
@MethodSource("SecP256k1ECDSASignatureTestParameters")
public void SecP256k1ECDSASignatureVerifyTest(BigInteger z, BigInteger r, BigInteger s, ECPoint point) {
BigInteger order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
SecP256K1Curve curve = new SecP256K1Curve();
ECPoint G = curve.createPoint(
new BigInteger(1, Hex.decodeStrict("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")),
new BigInteger(1, Hex.decodeStrict("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"))
);
BigInteger sInv = s.modPow(order.subtract(valueOf(2)), order);
BigInteger u = z.multiply(sInv).mod(order);
BigInteger v = r.multiply(sInv).mod(order);
assertEquals(G.multiply(u).add(point.multiply(v)).normalize().getAffineXCoord().toBigInteger(), r);
}
@ParameterizedTest
@MethodSource("SecP256k1ECDSASignatureTestParameters")
public void SecP256k1ECDSASignatureVerify2Test(BigInteger z, BigInteger r, BigInteger s, ECPoint point) {
BigInteger order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
SecP256K1Curve curve = new SecP256K1Curve();
ECPoint G = curve.createPoint(
new BigInteger(1, Hex.decodeStrict("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")),
new BigInteger(1, Hex.decodeStrict("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"))
);
ECDSASigner ecdsaSigner = new ECDSASigner();
ecdsaSigner.init(false, new ECPublicKeyParameters(point, new ECDomainParameters(curve, G, order)));
ecdsaSigner.verifySignature(z.toByteArray(), r, s);
}
@ParameterizedTest
@MethodSource("SecP256k1ECDSASignatureCreateTestParams")
public void SecP256k1ECDSASignatureCreateTest(
Object secret,
String message,
String expectedPointX,
String expectedPointY,
String expectedZ,
String expectedR,
String expectedS
) throws NoSuchAlgorithmException {
BigInteger order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
SecP256K1Curve curve = new SecP256K1Curve();
ECPoint G = curve.createPoint(
new BigInteger(1, Hex.decodeStrict("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")),
new BigInteger(1, Hex.decodeStrict("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"))
);
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
BigInteger e;
if (secret instanceof String) {
e = new BigInteger(1, messageDigest.digest(messageDigest.digest(((String) secret).getBytes(StandardCharsets.UTF_8))));
} else {
e = valueOf(((Long) secret));
}
byte[] zBytes = messageDigest.digest(messageDigest.digest(message.getBytes(StandardCharsets.UTF_8)));
BigInteger z = new BigInteger(1, zBytes);
BigInteger k = valueOf(1234567890);
ECDSASigner ecdsaSigner = new ECDSASigner(new DSAKCalculator() {
@Override
public boolean isDeterministic() {
return true;
}
@Override
public void init(BigInteger n, SecureRandom random) {
}
@Override
public void init(BigInteger n, BigInteger d, byte[] message) {
}
@Override
public BigInteger nextK() {
return k;
}
});
ecdsaSigner.init(true, new ECPrivateKeyParameters(e, new ECDomainParameters(curve, G, order)));
ECPoint point = G.multiply(e).normalize();
assertEquals(new BigInteger(1, Hex.decodeStrict(expectedPointX)), point.getAffineXCoord().toBigInteger());
assertEquals(new BigInteger(1, Hex.decodeStrict(expectedPointY)), point.getAffineYCoord().toBigInteger());
assertEquals(expectedZ, z.toString(16));
BigInteger[] signature = ecdsaSigner.generateSignature(zBytes);
assertEquals(expectedR, signature[0].toString(16));
assertEquals(expectedS, signature[1].toString(16));
}
private static Stream