aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java6
-rw-r--r--src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java9
-rw-r--r--src/cz/crcs/ectester/standalone/test/base/PerformanceTest.java109
-rw-r--r--src/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java142
4 files changed, 265 insertions, 1 deletions
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 034dbc5..0442593 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -321,7 +321,8 @@ public class ECTesterStandalone {
new StandaloneSignatureSuite(null, null, null),
new StandaloneCompositeSuite(null, null, null),
new StandaloneTwistSuite(null, null, null),
- new StandaloneMiscSuite(null, null, null)};
+ new StandaloneMiscSuite(null, null, null),
+ new StandalonePerformanceSuite(null, null, null)};
for (StandaloneTestSuite suite : suites) {
System.out.println(" - " + suite.getName());
for (String line : suite.getDescription()) {
@@ -782,6 +783,9 @@ public class ECTesterStandalone {
case "miscellaneous":
suite = new StandaloneMiscSuite(writer, cfg, cli);
break;
+ case "performance":
+ suite = new StandalonePerformanceSuite(writer, cfg, cli);
+ break;
case "default":
default:
suite = new StandaloneDefaultSuite(writer, cfg, cli);
diff --git a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java
index 1382c28..7fd1c5a 100644
--- a/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java
+++ b/src/cz/crcs/ectester/standalone/test/base/KeyAgreementTestable.java
@@ -4,6 +4,7 @@ import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.AlgorithmParameterSpec;
@@ -160,6 +161,14 @@ public class KeyAgreementTestable extends StandaloneTestable<KeyAgreementTestabl
hasRun = true;
}
+ @Override
+ public void reset() {
+ super.reset();
+ try {
+ ka = KeyAgreement.getInstance(ka.getAlgorithm(), ka.getProvider());
+ } catch (NoSuchAlgorithmException e) { }
+ }
+
public enum KeyAgreementStage {
GetPrivate,
GetPublic,
diff --git a/src/cz/crcs/ectester/standalone/test/base/PerformanceTest.java b/src/cz/crcs/ectester/standalone/test/base/PerformanceTest.java
new file mode 100644
index 0000000..258ca12
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/base/PerformanceTest.java
@@ -0,0 +1,109 @@
+package cz.crcs.ectester.standalone.test.base;
+
+import cz.crcs.ectester.common.test.BaseTestable;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.SimpleTest;
+import cz.crcs.ectester.common.test.TestCallback;
+
+import java.util.Arrays;
+
+/**
+ * @author David Hofman
+ */
+public class PerformanceTest extends SimpleTest<BaseTestable> {
+ private long[] times;
+ private long mean;
+ private long median;
+ private long mode;
+ private final int count;
+ private final String desc;
+
+ private PerformanceTest(BaseTestable testable, int count, String desc) {
+ super(testable, new TestCallback<BaseTestable>() {
+ @Override
+ public Result apply(BaseTestable testable) {
+ return new Result(Result.Value.SUCCESS);
+ }
+ });
+ this.count = count;
+ this.desc = desc;
+ }
+
+ public static PerformanceTest repeat(BaseTestable testable, int count) {
+ return new PerformanceTest(testable, count, null);
+ }
+
+ public static PerformanceTest repeat(BaseTestable testable, String desc, int count) {
+ return new PerformanceTest(testable, count, desc);
+ }
+
+ @Override
+ public String getDescription() {
+ String rest = String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode);
+ return (desc == null ? rest : desc + " (" + rest + ")");
+ }
+
+ @Override
+ protected void runSelf() {
+
+ times = new long[count];
+ for (int i = 0; i < count; ++i) {
+ times[i] = measureTime();
+ }
+
+ mean = Arrays.stream(times).sum() / count;
+
+ long[] sorted = times.clone();
+ Arrays.sort(sorted);
+ if (count % 2 == 0) {
+ median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2;
+ } else {
+ median = sorted[count / 2];
+ }
+
+ long max_occurrences = 0;
+ int i = 0;
+ while (i < count) {
+ long current_value = sorted[i];
+ long current_occurrences = 0;
+ while (i < count && sorted[i] == current_value) {
+ i++;
+ current_occurrences++;
+ }
+ if (current_occurrences > max_occurrences) {
+ max_occurrences = current_occurrences;
+ mode = current_value;
+ }
+ }
+ result = callback.apply(testable);
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public long[] getTimes() {
+ return times;
+ }
+
+ public long getMean() {
+ return mean;
+ }
+
+ public long getMedian() {
+ return median;
+ }
+
+ public long getMode() {
+ return mode;
+ }
+
+ private long measureTime() {
+ if(testable.hasRun()) {
+ testable.reset();
+ }
+ long startTime = System.nanoTime();
+ testable.run();
+ return System.nanoTime() - startTime;
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java b/src/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java
new file mode 100644
index 0000000..dd50862
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/test/suites/StandalonePerformanceSuite.java
@@ -0,0 +1,142 @@
+package cz.crcs.ectester.standalone.test.suites;
+
+import cz.crcs.ectester.common.cli.TreeCommandLine;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.output.TestWriter;
+import cz.crcs.ectester.common.test.CompoundTest;
+import cz.crcs.ectester.common.test.Result;
+import cz.crcs.ectester.common.test.Test;
+import cz.crcs.ectester.data.EC_Store;
+import cz.crcs.ectester.standalone.ECTesterStandalone;
+import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
+import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
+import cz.crcs.ectester.standalone.consts.SignatureIdent;
+import cz.crcs.ectester.standalone.test.base.*;
+
+import javax.crypto.KeyAgreement;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author David Hofman
+ */
+public class StandalonePerformanceSuite extends StandaloneTestSuite {
+ private final int count = 100;
+
+ public StandalonePerformanceSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) {
+ super(writer, cfg, cli, "performance", "The performance test suite measures performance of KeyPair generation, KeyAgreement and Signature operations.",
+ "Supports options:",
+ "\t - gt/kpg-type (select multiple types by separating them with commas)",
+ "\t - kt/ka-type (select multiple types by separating them with commas)",
+ "\t - st/sig-type (select multiple types by separating them with commas)",
+ "\t - key-type");
+ }
+
+ @Override
+ protected void runTests() throws Exception {
+ String kpgAlgo = cli.getOptionValue("test.kpg-type");
+ String kaAlgo = cli.getOptionValue("test.ka-type");
+ String sigAlgo = cli.getOptionValue("test.sig-type");
+ String keyAlgo = cli.getOptionValue("test.key-type", "AES");
+
+ List<String> kpgTypes = kpgAlgo != null ? Arrays.asList(kpgAlgo.split(",")) : new ArrayList<>();
+ List<String> kaTypes = kaAlgo != null ? Arrays.asList(kaAlgo.split(",")) : new ArrayList<>();
+ List<String> sigTypes = sigAlgo != null ? Arrays.asList(sigAlgo.split(",")) : new ArrayList<>();
+
+ List<KeyPairGeneratorIdent> kpgIdents = new LinkedList<>();
+ if (kpgAlgo == null) {
+ // try EC, if not, fail with: need to specify kpg algo.
+ Optional<KeyPairGeneratorIdent> kpgIdentOpt = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.contains("EC"))
+ .findFirst();
+ if (kpgIdentOpt.isPresent()) {
+ kpgIdents.add(kpgIdentOpt.get());
+ } else {
+ System.err.println("The default KeyPairGenerator algorithm type of \"EC\" was not found. Need to specify a type.");
+ return;
+ }
+ } else {
+ // try the specified, if not, fail with: wrong kpg algo/not found.
+ kpgIdents = cfg.selected.getKPGs().stream()
+ .filter((ident) -> ident.containsAny(kpgTypes)).collect(Collectors.toList());
+ if (kpgIdents.isEmpty()) {
+ System.err.println("No KeyPairGenerator algorithms of specified types were found.");
+ return;
+ }
+ }
+
+ KeyGeneratorTestable kgtOne = null;
+ KeyGeneratorTestable kgtOther = null;
+ ECParameterSpec spec = null;
+ List<Test> kpgTests = new LinkedList<>();
+ for(KeyPairGeneratorIdent kpgIdent : kpgIdents) {
+ KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider());
+ if (cli.hasOption("test.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("test.bits"));
+ kgtOne = new KeyGeneratorTestable(kpg, bits);
+ kgtOther = new KeyGeneratorTestable(kpg, bits);
+ } else if (cli.hasOption("test.named-curve")) {
+ String curveName = cli.getOptionValue("test.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
+ }
+ spec = curve.toSpec();
+ kgtOne = new KeyGeneratorTestable(kpg, spec);
+ kgtOther = new KeyGeneratorTestable(kpg, spec);
+ } else {
+ kgtOne = new KeyGeneratorTestable(kpg);
+ kgtOther = new KeyGeneratorTestable(kpg);
+ }
+ kpgTests.add(PerformanceTest.repeat(kgtOne, kpgIdent.getName(), count));
+ }
+ runTest(KeyGeneratorTest.expect(kgtOther, Result.ExpectedValue.SUCCESS));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPairGenerator performance tests", kpgTests.toArray(new Test[0])));
+
+ List<Test> kaTests = new LinkedList<>();
+ for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) {
+ if (kaAlgo == null || kaIdent.containsAny(kaTypes)) {
+ KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider());
+ KeyAgreementTestable testable;
+ if (kaIdent.requiresKeyAlgo()) {
+ testable = new KeyAgreementTestable(ka, kgtOne, kgtOther, spec, keyAlgo);
+ } else {
+ testable = new KeyAgreementTestable(ka, kgtOne, kgtOther, spec);
+ }
+ kaTests.add(PerformanceTest.repeat(testable, kaIdent.getName(), count));
+ }
+ }
+ if(kaTests.isEmpty()) {
+ kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified KeyAgreement types is supported by the library."));
+ }
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement performance tests", kaTests.toArray(new Test[0])));
+
+ List<Test> sigTests = new LinkedList<>();
+ List<Test> sigTestsNoVerification = new LinkedList<>();
+ for (SignatureIdent sigIdent : cfg.selected.getSigs()) {
+ if (sigAlgo == null || sigIdent.containsAny(sigTypes)) {
+ Signature sig = sigIdent.getInstance(cfg.selected.getProvider());
+ sigTests.add(PerformanceTest.repeat(new SignatureTestable(sig, kgtOne, null), sigIdent.getName(),count));
+ if(kgtOne.getKeyPair() != null) {
+ ECPrivateKey signKey = (ECPrivateKey) kgtOne.getKeyPair().getPrivate();
+ sigTestsNoVerification.add(PerformanceTest.repeat(new SignatureTestable(sig, signKey, null, null), sigIdent.getName(), count));
+ }
+ }
+ }
+ if(sigTestsNoVerification.isEmpty() & !sigTests.isEmpty()) {
+ sigTestsNoVerification.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Signature tests with no verification require a successfully generated private key."));
+ }
+ if(sigTests.isEmpty()) {
+ sigTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library."));
+ sigTestsNoVerification.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "None of the specified Signature types is supported by the library."));
+ }
+ Test signAndVerify = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Sign and verify", sigTests.toArray(new Test[0]));
+ Test signOnly = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Sign only, no verification", sigTestsNoVerification.toArray(new Test[0]));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Signature performance tests", signAndVerify, signOnly));
+ }
+}