diff --git a/bramble-core/src/test/java/org/briarproject/bramble/crypto/EllipticCurvePerformanceTest.java b/bramble-core/src/test/java/org/briarproject/bramble/crypto/EllipticCurvePerformanceTest.java index ac42f290e31c8f5018c2a0af6d06fd24cef81cc2..ed61badfe5c6dc8b4226d3ff6534ba371e3f644a 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/crypto/EllipticCurvePerformanceTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/crypto/EllipticCurvePerformanceTest.java @@ -1,17 +1,21 @@ package org.briarproject.bramble.crypto; +import net.i2p.crypto.eddsa.EdDSASecurityProvider; +import net.i2p.crypto.eddsa.KeyPairGenerator; + import org.spongycastle.asn1.sec.SECNamedCurves; import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves; import org.spongycastle.asn1.x9.X9ECParameters; import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.BasicAgreement; import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.agreement.ECDHBasicAgreement; import org.spongycastle.crypto.agreement.ECDHCBasicAgreement; import org.spongycastle.crypto.digests.Blake2bDigest; +import org.spongycastle.crypto.ec.CustomNamedCurves; import org.spongycastle.crypto.generators.ECKeyPairGenerator; import org.spongycastle.crypto.params.ECDomainParameters; import org.spongycastle.crypto.params.ECKeyGenerationParameters; -import org.spongycastle.crypto.params.ECPrivateKeyParameters; -import org.spongycastle.crypto.params.ECPublicKeyParameters; import org.spongycastle.crypto.params.ParametersWithRandom; import org.spongycastle.crypto.signers.DSADigestSigner; import org.spongycastle.crypto.signers.DSAKCalculator; @@ -22,12 +26,19 @@ import org.spongycastle.math.ec.ECPoint; import org.spongycastle.math.ec.MontgomeryLadderMultiplier; import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.Provider; import java.security.SecureRandom; +import java.security.Signature; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import static net.i2p.crypto.eddsa.EdDSAEngine.SIGNATURE_ALGORITHM; +import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS; + // Not a JUnit test public class EllipticCurvePerformanceTest { @@ -38,8 +49,9 @@ public class EllipticCurvePerformanceTest { "secp256k1", "secp256r1", "secp384r1", "secp521r1"); private static final List<String> BRAINPOOL_NAMES = Arrays.asList( "brainpoolp256r1", "brainpoolp384r1", "brainpoolp512r1"); + private static final Provider ED_PROVIDER = new EdDSASecurityProvider(); - public static void main(String[] args) { + public static void main(String[] args) throws GeneralSecurityException { for (String name : SEC_NAMES) { ECDomainParameters params = convertParams(SECNamedCurves.getByName(name)); @@ -52,43 +64,35 @@ public class EllipticCurvePerformanceTest { runTest(name + " default", params); runTest(name + " constant", constantTime(params)); } - runTest("ours", EllipticCurveConstants.PARAMETERS); + runTest("ours", PARAMETERS); + ECDomainParameters params = + convertParams(CustomNamedCurves.getByName("curve25519")); + runAgreementTest("curve25519 default", params); + runAgreementTest("curve25519 constant", constantTime(params)); + runEdTest(); } private static void runTest(String name, ECDomainParameters params) { // Generate two key pairs using the given parameters - ECKeyGenerationParameters generatorParams = - new ECKeyGenerationParameters(params, random); ECKeyPairGenerator generator = new ECKeyPairGenerator(); - generator.init(generatorParams); + generator.init(new ECKeyGenerationParameters(params, random)); AsymmetricCipherKeyPair keyPair1 = generator.generateKeyPair(); - ECPublicKeyParameters public1 = - (ECPublicKeyParameters) keyPair1.getPublic(); - ECPrivateKeyParameters private1 = - (ECPrivateKeyParameters) keyPair1.getPrivate(); AsymmetricCipherKeyPair keyPair2 = generator.generateKeyPair(); - ECPublicKeyParameters public2 = - (ECPublicKeyParameters) keyPair2.getPublic(); - // Time some ECDH key agreements - List<Long> samples = new ArrayList<>(); - for (int i = 0; i < SAMPLES; i++) { - ECDHCBasicAgreement agreement = new ECDHCBasicAgreement(); - long start = System.nanoTime(); - agreement.init(private1); - agreement.calculateAgreement(public2); - samples.add(System.nanoTime() - start); - } - long agreementMedian = median(samples); + // Time some ECDH and ECDHC key agreements + long agreementMedian = runAgreementTest(keyPair1, keyPair2, false); + long agreementWithCofactorMedian = + runAgreementTest(keyPair1, keyPair2, true); // Time some signatures + List<Long> samples = new ArrayList<>(); List<byte[]> signatures = new ArrayList<>(); - samples.clear(); for (int i = 0; i < SAMPLES; i++) { Digest digest = new Blake2bDigest(256); DSAKCalculator calculator = new HMacDSAKCalculator(digest); DSADigestSigner signer = new DSADigestSigner(new ECDSASigner( calculator), digest); long start = System.nanoTime(); - signer.init(true, new ParametersWithRandom(private1, random)); + signer.init(true, + new ParametersWithRandom(keyPair1.getPrivate(), random)); signer.update(new byte[BYTES_TO_SIGN], 0, BYTES_TO_SIGN); signatures.add(signer.generateSignature()); samples.add(System.nanoTime() - start); @@ -102,17 +106,81 @@ public class EllipticCurvePerformanceTest { DSADigestSigner signer = new DSADigestSigner(new ECDSASigner( calculator), digest); long start = System.nanoTime(); - signer.init(false, public1); + signer.init(false, keyPair1.getPublic()); signer.update(new byte[BYTES_TO_SIGN], 0, BYTES_TO_SIGN); if (!signer.verifySignature(signatures.get(i))) throw new AssertionError(); samples.add(System.nanoTime() - start); } long verificationMedian = median(samples); - System.out.println(name + ": " - + agreementMedian + " " - + signatureMedian + " " - + verificationMedian); + System.out.println(String.format("%s: %,d %,d %,d %,d", name, + agreementMedian, agreementWithCofactorMedian, + signatureMedian, verificationMedian)); + } + + private static long runAgreementTest(AsymmetricCipherKeyPair keyPair1, + AsymmetricCipherKeyPair keyPair2, boolean withCofactor) { + List<Long> samples = new ArrayList<>(); + for (int i = 0; i < SAMPLES; i++) { + BasicAgreement agreement = createAgreement(withCofactor); + long start = System.nanoTime(); + agreement.init(keyPair1.getPrivate()); + agreement.calculateAgreement(keyPair2.getPublic()); + samples.add(System.nanoTime() - start); + } + return median(samples); + } + + private static BasicAgreement createAgreement(boolean withCofactor) { + if (withCofactor) return new ECDHCBasicAgreement(); + else return new ECDHBasicAgreement(); + } + + private static void runAgreementTest(String name, + ECDomainParameters params) { + // Generate two key pairs using the given parameters + ECKeyPairGenerator generator = new ECKeyPairGenerator(); + generator.init(new ECKeyGenerationParameters(params, random)); + AsymmetricCipherKeyPair keyPair1 = generator.generateKeyPair(); + AsymmetricCipherKeyPair keyPair2 = generator.generateKeyPair(); + // Time some ECDH and ECDHC key agreements + long agreementMedian = runAgreementTest(keyPair1, keyPair2, false); + long agreementWithCofactorMedian = + runAgreementTest(keyPair1, keyPair2, true); + System.out.println(String.format("%s: %,d %,d N/A N/A", name, + agreementMedian, agreementWithCofactorMedian)); + } + + private static void runEdTest() throws GeneralSecurityException { + KeyPair keyPair = new KeyPairGenerator().generateKeyPair(); + // Time some signatures + List<Long> samples = new ArrayList<>(); + List<byte[]> signatures = new ArrayList<>(); + for (int i = 0; i < SAMPLES; i++) { + Signature signature = + Signature.getInstance(SIGNATURE_ALGORITHM, ED_PROVIDER); + long start = System.nanoTime(); + signature.initSign(keyPair.getPrivate(), random); + signature.update(new byte[BYTES_TO_SIGN], 0, BYTES_TO_SIGN); + signatures.add(signature.sign()); + samples.add(System.nanoTime() - start); + } + long signatureMedian = median(samples); + // Time some signature verifications + samples.clear(); + for (int i = 0; i < SAMPLES; i++) { + Signature signature = + Signature.getInstance(SIGNATURE_ALGORITHM, ED_PROVIDER); + long start = System.nanoTime(); + signature.initVerify(keyPair.getPublic()); + signature.update(new byte[BYTES_TO_SIGN], 0, BYTES_TO_SIGN); + if (!signature.verify(signatures.get(i))) + throw new AssertionError(); + samples.add(System.nanoTime() - start); + } + long verificationMedian = median(samples); + System.out.println(String.format("Ed25519: N/A %,d %,d", + signatureMedian, verificationMedian)); } private static long median(List<Long> list) {