--- /dev/null
+/*
+ * atomTime.c - measure performance of mulg, gsquare, feemod,
+ * gshift{left,right}, elliptic, ellMulProj
+ */
+
+#include "ckconfig.h"
+#include "ckutilsPlatform.h"
+#include "CryptKitSA.h"
+#include "ckutilities.h" /* needs private headers */
+#include "curveParams.h" /* ditto */
+#include "falloc.h" /* ditto */
+#include "elliptic.h"
+#include "ellipticProj.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+/* default loops for "fast" and "slow" ops respecitively */
+#define LOOPS_DEF_FAST 10000
+#define LOOPS_DEF_SLOW 100
+
+#define NUM_BORROW 100
+
+/* individual enables - normally all on, disable to zero in on one test */
+#define MULG_ENABLE 1
+#define GSQUARE_ENABLE 1
+#define FEEMOD_ENABLE 1
+#define BORROW_ENABLE 1
+#define SHIFT_ENABLE 1
+#define BINVAUX_ENABLE 1
+#define MAKE_RECIP_ENABLE 1
+#define MODGRECIP_ENABLE 1
+#define KEYGEN_ENABLE 1
+#define ELLIPTIC_ENABLE 1
+#define ELL_SIMPLE_ENABLE 1
+
+static void usage(char **argv)
+{
+ printf("Usage: %s [l=loops_fast] [L=loops_slow] [q(uick)] [D=depth]\n", argv[0]);
+ exit(1);
+}
+
+/*
+ * Fill numGiants with random data of length bits.
+ */
+static void genRandGiants(giant *giants,
+ unsigned numGiants,
+ unsigned bits,
+ feeRand rand)
+{
+ int i;
+ giant g;
+ unsigned char *rdata;
+ unsigned bytes = (bits + 7) / 8;
+ giantDigit mask = 0;
+ unsigned giantMsd = 0; // index of MSD
+ unsigned log2BitsPerDigit;
+ unsigned bitsPerDigit;
+
+ /* just to satisfy compiler - make sure it's always called */
+ if(giants == NULL) {
+ return;
+ }
+
+ log2BitsPerDigit = GIANT_LOG2_BITS_PER_DIGIT;
+ bitsPerDigit = GIANT_BITS_PER_DIGIT;
+
+ if((bits & 7) != 0) {
+ /*
+ * deserializeGiant() has a resolution of one byte. We
+ * need more resolution - that is, we'll be creating
+ * giants a little larger than we need, and we'll mask off
+ * some bits in the giants' m.s. digit.
+ * This assumes that data fills the giantDigits such
+ * that if bytes mod GIANT_BYTES_PER_DIGIT != 0, the
+ * empty byte(s) in the MSD are in the m.s. byte(s).
+ */
+ giantMsd = bits >> log2BitsPerDigit;
+ mask = (1 << (bits & (bitsPerDigit - 1))) - 1;
+ }
+ rdata = fmalloc(bytes);
+ for(i=0; i<numGiants; i++) {
+ g = giants[i];
+ feeRandBytes(rand, rdata, bytes);
+ deserializeGiant(rdata, g, bytes);
+ if(mask != 0) {
+ int j;
+
+ g->n[giantMsd] &= mask;
+
+ /*
+ * We've zeroed out some bits; we might have to
+ * adjust the sign of the giant as well. Note that
+ * deserializeGiant always yields positive
+ * giants....
+ */
+ for(j=(g->sign - 1); j!=0; j--) {
+ if(g->n[j] == 0) {
+ (g->sign)--;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ ffree(rdata);
+ return;
+}
+
+#if CRYPTKIT_ELL_PROJ_ENABLE
+/*
+ * Assumes the presence of numEllPoints items in *points, and that the
+ * x coordinate in each point is init'd to a random giant. Uses the x
+ * coords as seeds to make normalized points of the entire *points array.
+ */
+static void makePoints(pointProjStruct *points,
+ unsigned numEllPoints,
+ curveParams *cp)
+{
+ int i;
+ giant seed = newGiant(cp->maxDigits);
+
+ for(i=0; i<numEllPoints; i++) {
+ gtog(points[i].x, seed);
+ findPointProj(&points[i], seed, cp);
+ }
+ freeGiant(seed);
+}
+
+#endif /* CRYPTKIT_ELL_PROJ_ENABLE */
+
+int main(int argc, char **argv)
+{
+ int arg;
+ char *argp;
+ unsigned loopsFast = LOOPS_DEF_FAST;
+ unsigned loopsSlow = LOOPS_DEF_SLOW;
+ unsigned maxLoops;
+ unsigned depth;
+ feeRand rand;
+ giant *giants;
+ unsigned seed;
+ int i;
+ int j;
+ PLAT_TIME startTime;
+ PLAT_TIME endTime;
+ double elapsed;
+ unsigned numGiants;
+ #if CRYPTKIT_ELL_PROJ_ENABLE
+ unsigned numEllGiants; // for elliptic ops
+ unsigned numEllPoints; // for elliptic ops
+ #endif
+ curveParams *cp;
+ unsigned quick = 0;
+ unsigned minDepth = 0;
+ unsigned maxDepth = FEE_DEPTH_MAX;
+ unsigned basePrimeLen;
+ int *shiftCnt;
+ char *curveType;
+ #if CRYPTKIT_ELL_PROJ_ENABLE
+ pointProjStruct *points;
+ #endif
+ giant z = NULL;
+ giant modGiant = NULL;
+ giant recip = NULL;
+ feePubKey *keyArray = NULL;
+ giant gborrow[NUM_BORROW];
+
+ /* just to satisfy compiler - make sure it's always called */
+ genRandGiants(NULL, 0, 0, 0);
+
+ for(arg=1; arg<argc; arg++) {
+ argp = argv[arg];
+ switch(argp[0]) {
+ case 'l':
+ loopsFast = atoi(&argp[2]);
+ break;
+ case 'L':
+ loopsSlow = atoi(&argp[2]);
+ break;
+ case 'q':
+ quick = 1;
+ break;
+ case 'D':
+ minDepth = maxDepth = atoi(&argp[2]);
+ break;
+ default:
+ usage(argv);
+ break;
+ }
+ }
+
+ /*
+ * Common random generator
+ */
+ time((unsigned long *)&seed);
+ rand = feeRandAllocWithSeed(seed);
+
+ maxLoops = loopsFast;
+ if(loopsSlow > maxLoops) {
+ maxLoops = loopsSlow;
+ }
+
+ /*
+ * Alloc array of giants big enough for squaring at the largest
+ * key size, enough of them for 'loops' mulgs
+ */
+ cp = curveParamsForDepth(FEE_DEPTH_LARGEST);
+ numGiants = maxLoops * 2; // 2 giants per loop
+ if(loopsSlow > (maxLoops / 4)) {
+ /* findPointProj needs 4 giants per loop */
+ numGiants *= 4;
+ }
+ #if CRYPTKIT_ELL_PROJ_ENABLE
+ numEllGiants = loopsSlow * 2;
+ numEllPoints = loopsSlow * 2;
+ #endif
+ giants = fmalloc(numGiants * sizeof(giant));
+ if(giants == NULL) {
+ printf("malloc failure\n");
+ exit(1);
+ }
+ for(i=0; i<numGiants; i++) {
+ giants[i] = newGiant(cp->maxDigits);
+ if(giants[i] == NULL) {
+ printf("malloc failure\n");
+ exit(1);
+ }
+ }
+ freeCurveParams(cp);
+
+ #if CRYPTKIT_ELL_PROJ_ENABLE
+ /*
+ * Projective points - two per ellLoop. The giants come from
+ * giants[]. We reserve an extra giant per point.
+ * We're assuming that numEllPoints < (4 * numGiants).
+ */
+ points = fmalloc(numEllPoints * sizeof(pointProjStruct));
+ if(points == NULL) {
+ printf("malloc failure\n");
+ exit(1);
+ }
+ j=0;
+ for(i=0; i<numEllPoints; i++) {
+ points[i].x = giants[j++];
+ points[i].y = giants[j++];
+ points[i].z = giants[j++];
+ j++; // skip a giant
+ }
+ #endif
+
+ /* feePubKey array */
+ keyArray = fmalloc(sizeof(feePubKey) * loopsSlow);
+ if(keyArray == NULL) {
+ printf("malloc failure\n");
+ exit(1);
+ }
+
+ /*
+ * Alloc an array of shiftCnt ints
+ */
+ shiftCnt = fmalloc(maxLoops * sizeof(int));
+ if(shiftCnt == NULL) {
+ printf("malloc failure\n");
+ exit(1);
+ }
+
+ for(depth=minDepth; depth<=maxDepth; depth++) {
+
+ if(quick) {
+ if((depth != FEE_DEPTH_127M) &&
+ (depth != FEE_DEPTH_161W)) {
+ continue;
+ }
+ }
+
+ /*
+ * Get curve params for this depth
+ */
+ cp = curveParamsForDepth(depth);
+ if(cp == NULL) {
+ printf("malloc failure\n");
+ exit(1);
+ }
+ switch(cp->curveType) {
+ case FCT_Montgomery:
+ curveType = "FCT_Montgomery";
+ break;
+ case FCT_Weierstrass:
+ curveType = "FCT_Weierstrass";
+ break;
+ case FCT_General:
+ curveType = "FCT_General";
+ break;
+ default:
+ printf("***Unknown curveType!\n");
+ exit(1);
+ }
+
+ switch(cp->primeType) {
+ case FPT_General:
+ printf("depth=%d; FPT_General, %s; keysize=%d;\n",
+ depth, curveType, bitlen(cp->basePrime));
+ break;
+ case FPT_Mersenne:
+ printf("depth=%d; FPT_Mersenne, %s; q=%d\n",
+ depth, curveType, cp->q);
+ break;
+ default:
+ printf("depth=%d; FPT_FEE, %s; q=%d k=%d\n",
+ depth, curveType, cp->q, cp->k);
+ break;
+ }
+ basePrimeLen = bitlen(cp->basePrime);
+
+ /*
+ * mulg test
+ * bitlen(giant) <= bitlen(basePrime);
+ * giants[n+1] *= giants[n]
+ */
+ #if MULG_ENABLE
+ genRandGiants(giants, numGiants, basePrimeLen, rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<numGiants; i+=2) {
+ mulg(giants[i], giants[i+1]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" mulg: %12.2f ns per op\n",
+ elapsed / (numGiants / 2));
+ #endif /* MULG_ENABLE */
+
+ /*
+ * gsquare test
+ * bitlen(giant) <= bitlen(basePrime);
+ * gsquare(giants[n])
+ */
+ #if GSQUARE_ENABLE
+ genRandGiants(giants, numGiants, basePrimeLen, rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsFast; i++) {
+ gsquare(giants[i]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" gsquare: %12.2f ns per op\n", elapsed / loopsFast);
+ #endif /* GSQUARE_ENABLE */
+
+ /*
+ * feemod test
+ * bitlen(giant) <= ((2 * bitlen(basePrime) - 2);
+ * feemod(giants[n])
+ */
+ #if FEEMOD_ENABLE
+ genRandGiants(giants, numGiants, (basePrimeLen * 2) - 2,
+ rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsFast; i++) {
+ feemod(cp, giants[i]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" feemod: %12.2f ns per op\n", elapsed / loopsFast);
+ #endif /* FEEMOD_ENABLE */
+
+
+ /*
+ * borrowGiant test
+ */
+ #if BORROW_ENABLE
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsFast; i++) {
+ for(j=0; j<NUM_BORROW; j++) {
+ gborrow[j] = borrowGiant(cp->maxDigits);
+ }
+ for(j=0; j<NUM_BORROW; j++) {
+ returnGiant(gborrow[j]);
+ }
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" borrow/return: %12.2f ns per op\n",
+ elapsed / (loopsFast * NUM_BORROW));
+ #endif /* BORROW_ENABLE */
+
+ /*
+ * shiftright test
+ * bitlen(giant) <= bitlen(basePrime)
+ * 0 <= shiftCnt <= bitlen(basePrime)
+ * gshiftright(giants[i])
+ */
+ #if SHIFT_ENABLE
+ genRandGiants(giants, numGiants, basePrimeLen, rand);
+ for(i=0; i<loopsFast; i++) {
+ shiftCnt[i] = feeRandNextNum(rand) % basePrimeLen;
+ }
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsFast; i++) {
+ gshiftright(shiftCnt[i], giants[i]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" gshiftright: %12.2f ns per op\n", elapsed / loopsFast);
+
+ /*
+ * shiftleft test
+ * bitlen(giant) <= bitlen(basePrime)
+ * 1 <= shiftCnt <= bitlen(basePrime)
+ * gshiftleft(giants[i]
+ */
+ genRandGiants(giants, numGiants, basePrimeLen, rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsFast; i++) {
+ gshiftright(shiftCnt[i], giants[i]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" gshiftleft: %12.2f ns per op\n", elapsed / loopsFast);
+ #endif /* SHIFT_ENABLE */
+
+ /*
+ * binvaux test
+ * bitlen(giant) <= bitlen(basePrime);
+ * binvaux(basePrime, giants[n+1])
+ */
+ #if BINVAUX_ENABLE
+ genRandGiants(giants, loopsSlow, basePrimeLen, rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i++) {
+ binvaux(cp->basePrime, giants[i]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" binvaux: %12.2f us per op\n",
+ elapsed / loopsSlow);
+ #endif /* BINVAUX_ENABLE */
+
+ /*
+ * make_recip test
+ * bitlen(giant) <= bitlen(basePrime);
+ * make_recip(giants[n], giants[n+1]
+ */
+ #if MAKE_RECIP_ENABLE
+ genRandGiants(giants, numGiants, basePrimeLen, rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow*2; i+=2) {
+ make_recip(giants[i], giants[i+1]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" make_recip: %12.2f us per op\n",
+ elapsed / loopsSlow);
+ #endif /* MAKE_RECIP_ENABLE */
+
+ /*
+ * modg_via_recip test
+ * bitlen(giant) <= ((2 * bitlen(basePrime) - 2);
+ * bitlen(modGiant) <= bitlen(basePrime)
+ * calc recip of modGiant
+ * modg_via_recip(giants[i])
+ */
+ #if MODGRECIP_ENABLE
+ genRandGiants(giants, numGiants, (basePrimeLen * 2) - 2,
+ rand);
+ modGiant = borrowGiant(cp->maxDigits);
+ recip = borrowGiant(cp->maxDigits);
+ genRandGiants(&modGiant, 1, basePrimeLen, rand);
+ make_recip(modGiant, recip);
+
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i++) {
+ modg_via_recip(modGiant, recip, giants[i]);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" modg_via_recip: %12.2f ns per op\n",
+ elapsed / loopsSlow);
+ returnGiant(modGiant);
+ modGiant = NULL;
+ returnGiant(recip);
+ recip = NULL;
+ #endif /* MODGRECIP_ENABLE */
+
+ /*
+ * key generate test
+ * keyArray[n] = feePubKeyAlloc();
+ * feePubKeyInitFromPrivData(keyArray[n] );
+ */
+ #if KEYGEN_ENABLE
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i++) {
+ keyArray[i] = feePubKeyAlloc();
+ if(keyArray[i] == NULL) {
+ printf("malloc failure\n");
+ exit(1);
+ }
+ /* fixme how about some better seed data */
+ feePubKeyInitFromPrivDataDepth(keyArray[i],
+ (unsigned char *)"somePrivData",
+ 12,
+ depth,
+ 1);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" keygen: %12.2f us per op\n",
+ elapsed / loopsSlow);
+ for(i=0; i<loopsSlow; i++) {
+ feePubKeyFree(keyArray[i]);
+ }
+ #endif /* KEYGEN_ENABLE*/
+
+ /*
+ * elliptic test
+ * bitlen(giant) <= bitlen(basePrime);
+ * {giants[n], 1} *= giants[n+1] (elliptic mult)
+ */
+ #if ELLIPTIC_ENABLE
+ genRandGiants(giants, numGiants, basePrimeLen, rand);
+ z = borrowGiant(cp->maxDigits);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i+=2) {
+ /* superoptimized int_to_giant(1) */
+ z->n[0] = 1;
+ z->sign = 1;
+ elliptic(giants[i], z, giants[i+1], cp);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" elliptic: %12.2f us per op\n",
+ elapsed / (loopsSlow / 2));
+ #endif /* ELLIPTIC_ENABLE*/
+
+ /*
+ * elliptic_simple test
+ * bitlen(giant) <= bitlen(basePrime);
+ * giants[n] *= giants[n+1] (elliptic mult)
+ */
+ #if ELL_SIMPLE_ENABLE
+ genRandGiants(giants, numGiants, basePrimeLen, rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow*2; i+=2) {
+ elliptic_simple(giants[i], giants[i+1], cp);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" elliptic_simple: %12.2f us per op\n",
+ elapsed / loopsSlow);
+ #endif /* ELL_SIMPLE_ENABLE */
+
+ if(cp->curveType != FCT_Weierstrass) {
+ goto loopEnd;
+ }
+
+ #if CRYPTKIT_ELL_PROJ_ENABLE
+ /*
+ * ellMulProj test
+ * bitlen(giant) <= bitlen(basePrime);
+ * point[n+1] = point[n] * giants[4n+3]
+ *
+ * note we're cooking up way more giants than we have to;
+ * we really only need the x's and k's. But what the heck.
+ */
+ genRandGiants(giants, 4 * numEllPoints, basePrimeLen, rand);
+ makePoints(points, numEllPoints, cp);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i+=2) {
+ ellMulProj(&points[i], &points[i+1],
+ giants[4*i+3], cp);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" ellMulProj: %12.2f us per op\n",
+ elapsed / (loopsSlow / 2));
+
+ /*
+ * ellMulProjSimple test
+ * bitlen(giant) <= bitlen(basePrime);
+ * point[n] *= giants[4n+3] (projective elliptic mult)
+ */
+ genRandGiants(giants, 4 * numEllPoints, basePrimeLen, rand);
+ makePoints(points, numEllPoints, cp);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i++) {
+ ellMulProjSimple(&points[i], giants[4*i+3], cp);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" ellMulProjSimple: %12.2f us per op\n",
+ elapsed / loopsSlow);
+
+ /*
+ * ellAddProj test
+ * bitlen(giant) <= bitlen(basePrime);
+ * point[n] += point[n+1] (projective elliptic add)
+ */
+ genRandGiants(giants, 4 * numEllPoints, basePrimeLen, rand);
+ makePoints(points, numEllPoints, cp);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i+=2) {
+ ellAddProj(&points[i], &points[i+1], cp);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" ellAddProj: %12.2f ns per op\n",
+ elapsed / loopsSlow);
+
+ /*
+ * ellDoubleProj test
+ * bitlen(giant) <= bitlen(basePrime);
+ * ellDoubleProj(point[n])
+ */
+ genRandGiants(giants, 4 * numEllPoints, basePrimeLen, rand);
+ makePoints(points, numEllPoints, cp);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i++) {
+ ellDoubleProj(&points[i], cp);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_NS(startTime, endTime);
+ printf(" ellDoubleProj: %12.2f ns per op\n",
+ elapsed / loopsSlow);
+
+ /*
+ * findPointProj test
+ * bitlen(giant) <= bitlen(basePrime);
+ * findPointProj(point[n], giants[4n+3])
+ */
+ genRandGiants(giants, 4 * loopsSlow, basePrimeLen, rand);
+ PLAT_GET_TIME(startTime);
+ for(i=0; i<loopsSlow; i++) {
+ findPointProj(&points[i], giants[4*i + 3], cp);
+ }
+ PLAT_GET_TIME(endTime);
+ elapsed = PLAT_GET_US(startTime, endTime);
+ printf(" findPointProj: %12.2f us per op\n",
+ elapsed / loopsSlow);
+
+ #endif /* CRYPTKIT_ELL_PROJ_ENABLE */
+
+loopEnd:
+ freeCurveParams(cp);
+ }
+
+ feeRandFree(rand);
+ for(i=0; i<numGiants; i++) {
+ freeGiant(giants[i]);
+ }
+ ffree(giants);
+ if(z) {
+ freeGiant(z);
+ }
+ if(recip) {
+ freeGiant(recip);
+ }
+ if(modGiant) {
+ freeGiant(modGiant);
+ }
+ return 0;
+}
+