diff options
Diffstat (limited to 'core/src/test/java/org/spongycastle/math/ec/test/ECPointPerformanceTest.java')
-rw-r--r-- | core/src/test/java/org/spongycastle/math/ec/test/ECPointPerformanceTest.java | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/core/src/test/java/org/spongycastle/math/ec/test/ECPointPerformanceTest.java b/core/src/test/java/org/spongycastle/math/ec/test/ECPointPerformanceTest.java new file mode 100644 index 00000000..6be0c00b --- /dev/null +++ b/core/src/test/java/org/spongycastle/math/ec/test/ECPointPerformanceTest.java @@ -0,0 +1,198 @@ +package org.spongycastle.math.ec.test; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import junit.framework.TestCase; +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.x9.ECNamedCurveTable; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.crypto.ec.CustomNamedCurves; +import org.spongycastle.math.ec.ECCurve; +import org.spongycastle.math.ec.ECPoint; +import org.spongycastle.util.Times; + +/** + * Compares the performance of the the window NAF point multiplication against conventional point + * multiplication. + */ +public class ECPointPerformanceTest extends TestCase +{ + static final int MILLIS_PER_ROUND = 200; + static final int MILLIS_WARMUP = 1000; + + static final int MULTS_PER_CHECK = 16; + static final int NUM_ROUNDS = 10; + + private static String[] COORD_NAMES = new String[]{ "AFFINE", "HOMOGENEOUS", "JACOBIAN", "JACOBIAN-CHUDNOVSKY", + "JACOBIAN-MODIFIED", "LAMBDA-AFFINE", "LAMBDA-PROJECTIVE", "SKEWED" }; + + private void randMult(String curveName) throws Exception + { + X9ECParameters spec = ECNamedCurveTable.getByName(curveName); + if (spec != null) + { + randMult(curveName, spec); + } + + spec = CustomNamedCurves.getByName(curveName); + if (spec != null) + { + randMult(curveName + " (custom)", spec); + } + } + + private void randMult(String label, X9ECParameters spec) throws Exception + { + ECCurve C = spec.getCurve(); + ECPoint G = (ECPoint)spec.getG(); + BigInteger n = spec.getN(); + + SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN"); + random.setSeed(System.currentTimeMillis()); + + System.out.println(label); + + int[] coords = ECCurve.getAllCoordinateSystems(); + for (int i = 0; i < coords.length; ++i) + { + int coord = coords[i]; + if (C.supportsCoordinateSystem(coord)) + { + ECCurve c = C; + ECPoint g = G; + + boolean defaultCoord = (c.getCoordinateSystem() == coord); + if (!defaultCoord) + { + c = C.configure().setCoordinateSystem(coord).create(); + g = c.importPoint(G); + } + + double avgRate = randMult(random, g, n); + String coordName = COORD_NAMES[coord]; + StringBuffer sb = new StringBuffer(); + sb.append(" "); + sb.append(defaultCoord ? '*' : ' '); + sb.append(coordName); + for (int j = sb.length(); j < 30; ++j) + { + sb.append(' '); + } + sb.append(": "); + sb.append(avgRate); + sb.append(" mults/sec"); + for (int j = sb.length(); j < 64; ++j) + { + sb.append(' '); + } + sb.append('('); + sb.append(1000.0 / avgRate); + sb.append(" millis/mult)"); + System.out.println(sb.toString()); + } + } + } + + private double randMult(SecureRandom random, ECPoint g, BigInteger n) throws Exception + { + BigInteger[] ks = new BigInteger[128]; + for (int i = 0; i < ks.length; ++i) + { + ks[i] = new BigInteger(n.bitLength() - 1, random); + } + + int ki = 0; + ECPoint p = g; + + { + long startTime = Times.nanoTime(); + long goalTime = startTime + 1000000L * MILLIS_WARMUP; + + do + { + BigInteger k = ks[ki]; + p = g.multiply(k); + if ((ki & 1) != 0) + { + g = p; + } + if (++ki == ks.length) + { + ki = 0; + } + } + while (Times.nanoTime() < goalTime); + } + + double minRate = Double.MAX_VALUE, maxRate = Double.MIN_VALUE, totalRate = 0.0; + + for (int i = 1; i <= NUM_ROUNDS; i++) + { + long startTime = Times.nanoTime(); + long goalTime = startTime + 1000000L * MILLIS_PER_ROUND; + long count = 0, endTime; + + do + { + ++count; + + for (int j = 0; j < MULTS_PER_CHECK; ++j) + { + BigInteger k = ks[ki]; + p = g.multiply(k); + if ((ki & 1) != 0) + { + g = p; + } + if (++ki == ks.length) + { + ki = 0; + } + } + + endTime = Times.nanoTime(); + } + while (endTime < goalTime); + + double roundElapsed = (double)(endTime - startTime); + double roundRate = count * MULTS_PER_CHECK * 1000000000L / roundElapsed; + + minRate = Math.min(minRate, roundRate); + maxRate = Math.max(maxRate, roundRate); + totalRate += roundRate; + } + + return (totalRate - minRate - maxRate) / (NUM_ROUNDS - 2); + } + + public void testMultiply() throws Exception + { + SortedSet names = new TreeSet(AllTests.enumToList(ECNamedCurveTable.getNames())); + names.addAll(AllTests.enumToList(CustomNamedCurves.getNames())); + + Set oids = new HashSet(); + + Iterator it = names.iterator(); + while (it.hasNext()) + { + String name = (String)it.next(); + ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name); + if (oid == null) + { + oid = CustomNamedCurves.getOID(name); + } + if (oid != null && !oids.add(oid)) + { + continue; + } + + randMult(name); + } + } +} |