aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader/ECTesterReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/reader/ECTesterReader.java')
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java184
1 files changed, 81 insertions, 103 deletions
diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index 7a9d3eb..cb64b4c 100644
--- a/src/cz/crcs/ectester/reader/ECTesterReader.java
+++ b/src/cz/crcs/ectester/reader/ECTesterReader.java
@@ -1,6 +1,7 @@
/*
* ECTester, tool for testing Elliptic curve cryptography implementations.
- * Copyright (c) 2016-2018 Petr Svenda <petr@svenda.com>
+ * Copyright (c) 2016-2019 Petr Svenda <petr@svenda.com>
+ * Copyright (c) 2016-2019 Jan Jancar <johny@neuromancer.sk>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,10 +30,8 @@ import cz.crcs.ectester.common.cli.Colors;
import cz.crcs.ectester.common.ec.EC_Curve;
import cz.crcs.ectester.common.output.OutputLogger;
import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.common.util.ECUtil;
-import cz.crcs.ectester.common.util.FileUtil;
+import cz.crcs.ectester.common.util.Util;
+import cz.crcs.ectester.common.util.*;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.command.Command;
import cz.crcs.ectester.reader.output.FileTestWriter;
@@ -77,13 +76,13 @@ public class ECTesterReader {
public static final String VERSION = "v0.3.2";
public static String GIT_COMMIT = "";
private static String DESCRIPTION;
- private static String LICENSE = "MIT Licensed\nCopyright (c) 2016-2018 Petr Svenda <petr@svenda.com>";
+ private static String LICENSE = "MIT Licensed\nCopyright © 2016-2019 Petr Svenda <petr@svenda.com>\nCopyright © 2016-2019 Jan Jancar <johny@neuromancer.sk>";
private static String CLI_HEADER;
private static String CLI_FOOTER = "\n" + LICENSE;
- private static final byte[] SELECT_ECTESTERAPPLET = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0a,
- (byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31};
- private static final byte[] AID = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x31};
+ private static final byte[] SELECT_PREFIX = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0c};
+ private static final byte[] AID_221 = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x62}; // VERSION v0.3.2
+ private static final byte[] AID_222 = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x30, (byte) 0x33, (byte) 0x32, (byte) 0x78}; // VERSION v0.3.2
private static final byte[] INSTALL_DATA = new byte[10];
static {
@@ -137,20 +136,27 @@ public class ECTesterReader {
//connect or simulate connection
if (cfg.simulate) {
- if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) {
+ if (!cardManager.prepareLocalSimulatorApplet(AID_221, INSTALL_DATA, ECTesterApplet.class)) {
System.err.println(Colors.error("Failed to establish a simulator."));
System.exit(1);
+ } else {
+ cardManager.setChunking(true);
}
} else {
if (!cardManager.connectToCardSelect()) {
System.err.println(Colors.error("Failed to connect to card."));
System.exit(1);
}
- ResponseAPDU selectResp = cardManager.send(SELECT_ECTESTERAPPLET);
+ ResponseAPDU selectResp = cardManager.send(ByteUtil.concatenate(SELECT_PREFIX, AID_222));
if ((short) selectResp.getSW() != ISO7816.SW_NO_ERROR) {
- System.err.println(Colors.error("Failed to select ECTester applet, is it installed?"));
- cardManager.disconnectFromCard();
- System.exit(1);
+ selectResp = cardManager.send(ByteUtil.concatenate(SELECT_PREFIX, AID_221));
+ if ((short) selectResp.getSW() != ISO7816.SW_NO_ERROR) {
+ System.err.println(Colors.error("Failed to select ECTester applet, is it installed?"));
+ cardManager.disconnectFromCard();
+ System.exit(1);
+ } else {
+ cardManager.setChunking(true);
+ }
}
}
@@ -163,6 +169,9 @@ public class ECTesterReader {
Security.addProvider(new BouncyCastleProvider());
} catch (SecurityException | NoClassDefFoundError ignored) {
}
+ // Make BouncyCastle more lenient when we work with signatures in ASN.1 DER format,
+ // cards sometimes are not fully compliant.
+ System.setProperty("org.bouncycastle.asn1.allow_unsafe_integer", "true");
//do action
if (cli.hasOption("export")) {
@@ -239,54 +248,6 @@ public class ECTesterReader {
* @throws ParseException if there are any problems encountered while parsing the command line tokens
*/
private CommandLine parseArgs(String[] args) throws ParseException {
- /*
- * Actions:
- * -V / --version
- * -h / --help
- * -e / --export
- * -g / --generate [amount]
- * -t / --test [test_suite]
- * -dh / --ecdh [count]]
- * -dsa / --ecdsa [count]
- * -ln / --list-named [obj]
- * -ls / --list-suites
- * -nfo / --info
- *
- * Options:
- * -b / --bit-size <b> // -a / --all
- *
- * -fp / --prime-field
- * -f2m / --binary-field
- *
- * -u / --custom
- * -nc / --named-curve <cat/id>
- * -c / --curve <curve_file> field,a,b,gx,gy,r,k
- *
- * -pub / --public <pubkey_file> wx,wy
- * -npub / --named-public <cat/id>
- *
- * -priv / --private <privkey_file> s
- * -npriv / --named-private <cat/id>
- *
- * -k / --key <key_file> wx,wy,s
- * -nk / --named-key <cat/id>
- *
- * -v / --verbose
- *
- * -i / --input <input_file>
- * -o / --output <output_file>
- * --format <format>
- * -l / --log [log_file]
- *
- * -f / --fresh
- * --cleanup
- * -s / --simulate
- * -y / --yes
- * -ka/ --ka-type <type>
- * -sig/--sig-type <type>
- * -C / --color
- * -to/ --test-options <opts>
- */
OptionGroup actions = new OptionGroup();
actions.setRequired(true);
actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build());
@@ -338,10 +299,11 @@ public class ECTesterReader {
opts.addOption(Option.builder().longOpt("fixed-public").desc("Generate public key only once, keep it for later ECDH.").build());
opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build());
opts.addOption(Option.builder().longOpt("time").desc("Output better timing values, by running command in dry run mode and normal mode, and subtracting the two.").build());
+ opts.addOption(Option.builder().longOpt("time-unit").desc("Use given time unit in measurement, one of: milli, micro, nano.").hasArg().argName("unit").build());
opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build());
opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build());
opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build());
- opts.addOption(Option.builder("to").longOpt("test-options").desc("Test options to use:\n- preset: Use preset semi-random private keys instead of generating keypairs on the cards when the test needs one.").hasArg().argName("options").build());
+ opts.addOption(Option.builder("to").longOpt("test-options").desc("Test options to use:\n- preset: Use preset semi-random private keys (derived from curve) instead of generating keypairs on the cards when the test needs one.\n- random: Use fully random private keys instead of generating keypairs.").hasArg().argName("options").build());
opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build());
opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build());
@@ -380,11 +342,13 @@ public class ECTesterReader {
private void info() throws CardException {
Response.GetInfo info = new Command.GetInfo(cardManager).send();
- System.out.println(String.format("ECTester applet version: %s", info.getVersion()));
- System.out.println(String.format("ECTester applet APDU support: %s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length"));
- System.out.println(String.format("JavaCard API version: %.1f", info.getJavaCardVersion()));
- System.out.println(String.format("JavaCard supports system cleanup: %s", info.getCleanupSupport()));
- System.out.println(String.format("Array sizes (apduBuf, ram, ram2, apduArr): %d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength()));
+ System.out.println(String.format("Card ATR:\t\t\t\t%s", ByteUtil.bytesToHex(cardManager.getATR().getBytes(), false)));
+ System.out.println(String.format("Card protocol:\t\t\t\t%s", cardManager.getProtocol()));
+ System.out.println(String.format("ECTester applet version:\t\t%s", info.getVersion()));
+ System.out.println(String.format("ECTester applet APDU support:\t\t%s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length"));
+ System.out.println(String.format("JavaCard API version:\t\t\t%.1f", info.getJavaCardVersion()));
+ System.out.println(String.format("JavaCard supports system cleanup:\t%s", info.getCleanupSupport()));
+ System.out.println(String.format("Array sizes (apduBuf,ram,ram2,apduArr):\t%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength()));
}
/**
@@ -402,7 +366,7 @@ public class ECTesterReader {
sent.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
// Also support exporting set parameters, to verify they are set correctly.
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
if (curve != null) {
sent.add(curve.send());
}
@@ -445,13 +409,13 @@ public class ECTesterReader {
*/
private void generate() throws CardException, IOException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
Response allocate = new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass).send();
respWriter.outputResponse(allocate);
OutputStreamWriter keysFile = FileUtil.openFiles(cfg.outputs);
- keysFile.write("index;genTime[milli];exportTime[milli];pubW;privS\n");
+ keysFile.write(String.format("index;genTime[%s];exportTime[%s];pubW;privS\n", cfg.timeUnit, cfg.timeUnit));
int generated = 0;
int retry = 0;
@@ -485,7 +449,7 @@ public class ECTesterReader {
String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
- String line = String.format("%d;%d;%d;%s;%s\n", generated, time / 1000000, export.getDuration() / 1000000, pub, priv);
+ String line = String.format("%d;%d;%d;%s;%s\n", generated, Util.convertTime(time, cfg.timeUnit), Util.convertTime(export.getDuration(), cfg.timeUnit), pub, priv);
keysFile.write(line);
keysFile.flush();
generated++;
@@ -518,7 +482,6 @@ public class ECTesterReader {
case "compression":
suite = new CardCompressionSuite(writer, cfg, cardManager);
break;
- case "misc":
case "miscellaneous":
suite = new CardMiscSuite(writer, cfg, cardManager);
break;
@@ -578,7 +541,7 @@ public class ECTesterReader {
*/
private void ecdh() throws IOException, CardException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass);
List<Response> prepare = new LinkedList<>();
prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.ECKAType).send()); // Prepare KeyAgreement or required type
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass).send());
@@ -592,17 +555,17 @@ public class ECTesterReader {
OutputStreamWriter out = null;
if (cfg.outputs != null) {
out = FileUtil.openFiles(cfg.outputs);
- out.write("index;time[milli];pubW;privS;secret\n");
+ out.write(String.format("index;time[%s];pubW;privS;secret\n", cfg.timeUnit));
}
Response gen = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH).send();
respWriter.outputResponse(gen);
if (cfg.anyPublicKey || cfg.anyKey) {
- Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE).send();
+ Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W).send();
respWriter.outputResponse(prep);
}
if (cfg.anyPrivateKey || cfg.anyKey) {
- Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL).send();
+ Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S).send();
respWriter.outputResponse(prep);
}
@@ -630,10 +593,12 @@ public class ECTesterReader {
respWriter.outputResponse(regen);
}
- Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
- respWriter.outputResponse(export);
- byte[] pubkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W);
- byte[] privkey_bytes = export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S);
+ Response.Export exportRemote = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send();
+ respWriter.outputResponse(exportRemote);
+ Response.Export exportLocal = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S).send();
+ respWriter.outputResponse(exportLocal);
+ byte[] pubkey_bytes = exportRemote.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W);
+ byte[] privkey_bytes = exportLocal.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S);
Command.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType);
@@ -658,7 +623,7 @@ public class ECTesterReader {
if (out != null) {
time += result.getDuration();
- out.write(String.format("%d;%d;%s;%s;%s\n", done, time / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(result.getSecret(), false)));
+ out.write(String.format("%d;%d;%s;%s;%s\n", done, Util.convertTime(time, cfg.timeUnit), ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(result.getSecret(), false)));
out.flush();
}
@@ -697,7 +662,7 @@ public class ECTesterReader {
Command generate;
if (cfg.anyKeypart) {
- generate = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL);
+ generate = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETERS_KEYPAIR);
} else {
generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
}
@@ -706,7 +671,7 @@ public class ECTesterReader {
List<Response> prepare = new LinkedList<>();
prepare.add(new Command.AllocateSignature(cardManager, cfg.ECDSAType).send());
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
+ Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
if (curve != null)
prepare.add(curve.send());
@@ -716,7 +681,7 @@ public class ECTesterReader {
OutputStreamWriter out = FileUtil.openFiles(cfg.outputs);
if (out != null) {
- out.write("index;signTime[milli];verifyTime[milli];data;pubW;privS;signature;nonce;valid\n");
+ out.write(String.format("index;signTime[%s];verifyTime[%s];data;pubW;privS;signature;nonce;valid\n", cfg.timeUnit, cfg.timeUnit));
}
Command.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR);
@@ -780,7 +745,7 @@ public class ECTesterReader {
String priv = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
String dataString = (cfg.input != null) ? "" : ByteUtil.bytesToHex(data, false);
BigInteger privkey = new BigInteger(1, exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S));
- EC_Curve actualCurve = Command.findCurve(EC_Store.getInstance(), cfg, cfg.bits, keyClass);
+ EC_Curve actualCurve = Command.findCurve(cfg, cfg.bits, keyClass);
String k = "";
if (actualCurve != null) {
ECParameterSpec params = actualCurve.toSpec();
@@ -789,7 +754,7 @@ public class ECTesterReader {
k = ByteUtil.bytesToHex(kValue.toByteArray(), false);
}
}
- out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, signTime / 1000000, verifyTime / 1000000, dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verifyResp.successful() ? 1 : 0));
+ out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, Util.convertTime(signTime, cfg.timeUnit), Util.convertTime(verifyTime, cfg.timeUnit), dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verifyResp.successful() ? 1 : 0));
out.flush();
}
@@ -845,6 +810,7 @@ public class ECTesterReader {
public String[] outputs;
public boolean fresh = false;
public boolean time = false;
+ public String timeUnit;
public boolean cleanup = false;
public boolean simulate = false;
public boolean yes = false;
@@ -911,6 +877,13 @@ public class ECTesterReader {
color = cli.hasOption("color");
Colors.enabled = color;
+ timeUnit = cli.getOptionValue("time-unit", "micro");
+ String[] times = new String[]{"milli", "micro", "nano"};
+ if (!Arrays.asList(times).contains(timeUnit)) {
+ System.err.println(Colors.error("Wrong time unit " + timeUnit + ". Should be one of " + Arrays.toString(times)));
+ return false;
+ }
+
if (cli.hasOption("list-named")) {
listNamed = cli.getOptionValue("list-named");
return true;
@@ -1011,40 +984,45 @@ public class ECTesterReader {
testFrom = 0;
testTo = -1;
}
-
+
String[] tests = new String[]{"default", "composite", "compression", "invalid", "degenerate", "test-vectors", "wrong", "twist", "cofactor", "edge-cases", "miscellaneous", "signature"};
- String selected = null;
- for (String test : tests) {
- if (test.startsWith(testSuite)) {
- if (selected != null) {
- System.err.println(Colors.error("Test suite ambiguous " + test + " or " + selected + "?"));
- return false;
- } else {
- selected = test;
- }
- }
- }
- if (selected == null) {
+ String selected = null;
+ for (String test : tests) {
+ if (test.startsWith(testSuite)) {
+ if (selected != null) {
+ System.err.println(Colors.error("Test suite ambiguous " + test + " or " + selected + "?"));
+ return false;
+ } else {
+ selected = test;
+ }
+ }
+ }
+ if (selected == null) {
System.err.println(Colors.error("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests)));
return false;
} else {
- testSuite = selected;
+ testSuite = selected;
}
String[] opts = cli.getOptionValue("test-options", "").split(",");
- List<String> validOpts = Arrays.asList("preset");
+ List<String> validOpts = Arrays.asList("preset", "random");
testOptions = new HashSet<>();
for (String opt : opts) {
if (opt.equals("")) {
continue;
}
if (!validOpts.contains(opt)) {
- System.err.println(Colors.error("Unknown test option " + opt + ". Should be one of: " + "preset."));
+ System.err.println(Colors.error("Unknown test option " + opt + ". Should be one of: " + Arrays.toString(validOpts.toArray())));
return false;
} else {
testOptions.add(opt);
}
}
+
+ if (testOptions.contains("preset") && testOptions.contains("random")) {
+ System.err.println("Cannot have both preset and random option enabled.");
+ return false;
+ }
} else if (cli.hasOption("ecdh")) {
if (primeField == binaryField) {
System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)"));