michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include "mpi.h" michael@0: #include "mpi-priv.h" michael@0: michael@0: /* #define OLD_WAY 1 */ michael@0: michael@0: /* This key is the 1024-bit test key used for speed testing of RSA private michael@0: ** key ops. michael@0: */ michael@0: michael@0: #define CONST const michael@0: michael@0: static CONST unsigned char default_n[128] = { michael@0: 0xc2,0xae,0x96,0x89,0xaf,0xce,0xd0,0x7b,0x3b,0x35,0xfd,0x0f,0xb1,0xf4,0x7a,0xd1, michael@0: 0x3c,0x7d,0xb5,0x86,0xf2,0x68,0x36,0xc9,0x97,0xe6,0x82,0x94,0x86,0xaa,0x05,0x39, michael@0: 0xec,0x11,0x51,0xcc,0x5c,0xa1,0x59,0xba,0x29,0x18,0xf3,0x28,0xf1,0x9d,0xe3,0xae, michael@0: 0x96,0x5d,0x6d,0x87,0x73,0xf6,0xf6,0x1f,0xd0,0x2d,0xfb,0x2f,0x7a,0x13,0x7f,0xc8, michael@0: 0x0c,0x7a,0xe9,0x85,0xfb,0xce,0x74,0x86,0xf8,0xef,0x2f,0x85,0x37,0x73,0x0f,0x62, michael@0: 0x4e,0x93,0x17,0xb7,0x7e,0x84,0x9a,0x94,0x11,0x05,0xca,0x0d,0x31,0x4b,0x2a,0xc8, michael@0: 0xdf,0xfe,0xe9,0x0c,0x13,0xc7,0xf2,0xad,0x19,0x64,0x28,0x3c,0xb5,0x6a,0xc8,0x4b, michael@0: 0x79,0xea,0x7c,0xce,0x75,0x92,0x45,0x3e,0xa3,0x9d,0x64,0x6f,0x04,0x69,0x19,0x17 michael@0: }; michael@0: michael@0: static CONST unsigned char default_d[128] = { michael@0: 0x13,0xcb,0xbc,0xf2,0xf3,0x35,0x8c,0x6d,0x7b,0x6f,0xd9,0xf3,0xa6,0x9c,0xbd,0x80, michael@0: 0x59,0x2e,0x4f,0x2f,0x11,0xa7,0x17,0x2b,0x18,0x8f,0x0f,0xe8,0x1a,0x69,0x5f,0x6e, michael@0: 0xac,0x5a,0x76,0x7e,0xd9,0x4c,0x6e,0xdb,0x47,0x22,0x8a,0x57,0x37,0x7a,0x5e,0x94, michael@0: 0x7a,0x25,0xb5,0xe5,0x78,0x1d,0x3c,0x99,0xaf,0x89,0x7d,0x69,0x2e,0x78,0x9d,0x1d, michael@0: 0x84,0xc8,0xc1,0xd7,0x1a,0xb2,0x6d,0x2d,0x8a,0xd9,0xab,0x6b,0xce,0xae,0xb0,0xa0, michael@0: 0x58,0x55,0xad,0x5c,0x40,0x8a,0xd6,0x96,0x08,0x8a,0xe8,0x63,0xe6,0x3d,0x6c,0x20, michael@0: 0x49,0xc7,0xaf,0x0f,0x25,0x73,0xd3,0x69,0x43,0x3b,0xf2,0x32,0xf8,0x3d,0x5e,0xee, michael@0: 0x7a,0xca,0xd6,0x94,0x55,0xe5,0xbd,0x25,0x34,0x8d,0x63,0x40,0xb5,0x8a,0xc3,0x01 michael@0: }; michael@0: michael@0: michael@0: #define DEFAULT_ITERS 50 michael@0: michael@0: typedef clock_t timetype; michael@0: #define gettime(x) *(x) = clock() michael@0: #define subtime(a, b) a -= b michael@0: #define msec(x) ((clock_t)((double)x * 1000.0 / CLOCKS_PER_SEC)) michael@0: #define sec(x) (x / CLOCKS_PER_SEC) michael@0: michael@0: struct TimingContextStr { michael@0: timetype start; michael@0: timetype end; michael@0: timetype interval; michael@0: michael@0: int minutes; michael@0: int seconds; michael@0: int millisecs; michael@0: }; michael@0: michael@0: typedef struct TimingContextStr TimingContext; michael@0: michael@0: TimingContext *CreateTimingContext(void) michael@0: { michael@0: return (TimingContext *)malloc(sizeof(TimingContext)); michael@0: } michael@0: michael@0: void DestroyTimingContext(TimingContext *ctx) michael@0: { michael@0: free(ctx); michael@0: } michael@0: michael@0: void TimingBegin(TimingContext *ctx) michael@0: { michael@0: gettime(&ctx->start); michael@0: } michael@0: michael@0: static void timingUpdate(TimingContext *ctx) michael@0: { michael@0: michael@0: ctx->millisecs = msec(ctx->interval) % 1000; michael@0: ctx->seconds = sec(ctx->interval); michael@0: ctx->minutes = ctx->seconds / 60; michael@0: ctx->seconds %= 60; michael@0: michael@0: } michael@0: michael@0: void TimingEnd(TimingContext *ctx) michael@0: { michael@0: gettime(&ctx->end); michael@0: ctx->interval = ctx->end; michael@0: subtime(ctx->interval, ctx->start); michael@0: timingUpdate(ctx); michael@0: } michael@0: michael@0: char *TimingGenerateString(TimingContext *ctx) michael@0: { michael@0: static char sBuf[4096]; michael@0: michael@0: sprintf(sBuf, "%d minutes, %d.%03d seconds", ctx->minutes, michael@0: ctx->seconds, ctx->millisecs); michael@0: return sBuf; michael@0: } michael@0: michael@0: static void michael@0: dumpBytes( unsigned char * b, int l) michael@0: { michael@0: int i; michael@0: if (l <= 0) michael@0: return; michael@0: for (i = 0; i < l; ++i) { michael@0: if (i % 16 == 0) michael@0: printf("\t"); michael@0: printf(" %02x", b[i]); michael@0: if (i % 16 == 15) michael@0: printf("\n"); michael@0: } michael@0: if ((i % 16) != 0) michael@0: printf("\n"); michael@0: printf("\n"); michael@0: } michael@0: michael@0: static mp_err michael@0: testNewFuncs(const unsigned char * modulusBytes, int modulus_len) michael@0: { michael@0: mp_err mperr = MP_OKAY; michael@0: mp_int modulus; michael@0: unsigned char buf[512]; michael@0: michael@0: mperr = mp_init(&modulus); michael@0: mperr = mp_read_unsigned_octets(&modulus, modulusBytes, modulus_len ); michael@0: mperr = mp_to_fixlen_octets(&modulus, buf, modulus_len); michael@0: mperr = mp_to_fixlen_octets(&modulus, buf, modulus_len+1); michael@0: mperr = mp_to_fixlen_octets(&modulus, buf, modulus_len+4); michael@0: mperr = mp_to_unsigned_octets(&modulus, buf, modulus_len); michael@0: mperr = mp_to_signed_octets(&modulus, buf, modulus_len + 1); michael@0: mp_clear(&modulus); michael@0: return mperr; michael@0: } michael@0: michael@0: int michael@0: testModExp( const unsigned char * modulusBytes, michael@0: const unsigned int expo, michael@0: const unsigned char * input, michael@0: unsigned char * output, michael@0: int modulus_len) michael@0: { michael@0: mp_err mperr = MP_OKAY; michael@0: mp_int modulus; michael@0: mp_int base; michael@0: mp_int exponent; michael@0: mp_int result; michael@0: michael@0: mperr = mp_init(&modulus); michael@0: mperr += mp_init(&base); michael@0: mperr += mp_init(&exponent); michael@0: mperr += mp_init(&result); michael@0: /* we initialize all mp_ints unconditionally, even if some fail. michael@0: ** This guarantees that the DIGITS pointer is valid (even if null). michael@0: ** So, mp_clear will do the right thing below. michael@0: */ michael@0: if (mperr == MP_OKAY) { michael@0: mperr = mp_read_unsigned_octets(&modulus, michael@0: modulusBytes + (sizeof default_n - modulus_len), modulus_len ); michael@0: mperr += mp_read_unsigned_octets(&base, input, modulus_len ); michael@0: mp_set(&exponent, expo); michael@0: if (mperr == MP_OKAY) { michael@0: #if OLD_WAY michael@0: mperr = s_mp_exptmod(&base, &exponent, &modulus, &result); michael@0: #else michael@0: mperr = mp_exptmod(&base, &exponent, &modulus, &result); michael@0: #endif michael@0: if (mperr == MP_OKAY) { michael@0: mperr = mp_to_fixlen_octets(&result, output, modulus_len); michael@0: } michael@0: } michael@0: } michael@0: mp_clear(&base); michael@0: mp_clear(&result); michael@0: michael@0: mp_clear(&modulus); michael@0: mp_clear(&exponent); michael@0: michael@0: return (int)mperr; michael@0: } michael@0: michael@0: int michael@0: doModExp( const unsigned char * modulusBytes, michael@0: const unsigned char * exponentBytes, michael@0: const unsigned char * input, michael@0: unsigned char * output, michael@0: int modulus_len) michael@0: { michael@0: mp_err mperr = MP_OKAY; michael@0: mp_int modulus; michael@0: mp_int base; michael@0: mp_int exponent; michael@0: mp_int result; michael@0: michael@0: mperr = mp_init(&modulus); michael@0: mperr += mp_init(&base); michael@0: mperr += mp_init(&exponent); michael@0: mperr += mp_init(&result); michael@0: /* we initialize all mp_ints unconditionally, even if some fail. michael@0: ** This guarantees that the DIGITS pointer is valid (even if null). michael@0: ** So, mp_clear will do the right thing below. michael@0: */ michael@0: if (mperr == MP_OKAY) { michael@0: mperr = mp_read_unsigned_octets(&modulus, michael@0: modulusBytes + (sizeof default_n - modulus_len), modulus_len ); michael@0: mperr += mp_read_unsigned_octets(&exponent, exponentBytes, modulus_len ); michael@0: mperr += mp_read_unsigned_octets(&base, input, modulus_len ); michael@0: if (mperr == MP_OKAY) { michael@0: #if OLD_WAY michael@0: mperr = s_mp_exptmod(&base, &exponent, &modulus, &result); michael@0: #else michael@0: mperr = mp_exptmod(&base, &exponent, &modulus, &result); michael@0: #endif michael@0: if (mperr == MP_OKAY) { michael@0: mperr = mp_to_fixlen_octets(&result, output, modulus_len); michael@0: } michael@0: } michael@0: } michael@0: mp_clear(&base); michael@0: mp_clear(&result); michael@0: michael@0: mp_clear(&modulus); michael@0: mp_clear(&exponent); michael@0: michael@0: return (int)mperr; michael@0: } michael@0: michael@0: int michael@0: main(int argc, char **argv) michael@0: { michael@0: TimingContext * timeCtx; michael@0: char * progName; michael@0: long iters = DEFAULT_ITERS; michael@0: unsigned int modulus_len; michael@0: int i; michael@0: int rv; michael@0: unsigned char buf [1024]; michael@0: unsigned char buf2[1024]; michael@0: michael@0: progName = strrchr(argv[0], '/'); michael@0: if (!progName) michael@0: progName = strrchr(argv[0], '\\'); michael@0: progName = progName ? progName+1 : argv[0]; michael@0: michael@0: if (argc >= 2) { michael@0: iters = atol(argv[1]); michael@0: } michael@0: michael@0: if (argc >= 3) { michael@0: modulus_len = atol(argv[2]); michael@0: } else michael@0: modulus_len = sizeof default_n; michael@0: michael@0: /* no library init function !? */ michael@0: michael@0: memset(buf, 0x41, sizeof buf); michael@0: michael@0: if (iters < 2) { michael@0: testNewFuncs( default_n, modulus_len); michael@0: testNewFuncs( default_n+1, modulus_len - 1); michael@0: testNewFuncs( default_n+2, modulus_len - 2); michael@0: testNewFuncs( default_n+3, modulus_len - 3); michael@0: michael@0: printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies); michael@0: rv = testModExp(default_n, 0, buf, buf2, modulus_len); michael@0: dumpBytes((unsigned char *)buf2, modulus_len); michael@0: michael@0: printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies); michael@0: rv = testModExp(default_n, 1, buf, buf2, modulus_len); michael@0: dumpBytes((unsigned char *)buf2, modulus_len); michael@0: michael@0: printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies); michael@0: rv = testModExp(default_n, 2, buf, buf2, modulus_len); michael@0: dumpBytes((unsigned char *)buf2, modulus_len); michael@0: michael@0: printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies); michael@0: rv = testModExp(default_n, 3, buf, buf2, modulus_len); michael@0: dumpBytes((unsigned char *)buf2, modulus_len); michael@0: } michael@0: printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies); michael@0: rv = doModExp(default_n, default_d, buf, buf2, modulus_len); michael@0: if (rv != 0) { michael@0: fprintf(stderr, "Error in modexp operation:\n"); michael@0: exit(1); michael@0: } michael@0: dumpBytes((unsigned char *)buf2, modulus_len); michael@0: printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies); michael@0: michael@0: timeCtx = CreateTimingContext(); michael@0: TimingBegin(timeCtx); michael@0: i = iters; michael@0: while (i--) { michael@0: rv = doModExp(default_n, default_d, buf, buf2, modulus_len); michael@0: if (rv != 0) { michael@0: fprintf(stderr, "Error in modexp operation\n"); michael@0: exit(1); michael@0: } michael@0: } michael@0: TimingEnd(timeCtx); michael@0: printf("%ld iterations in %s\n", iters, TimingGenerateString(timeCtx)); michael@0: printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies); michael@0: michael@0: return 0; michael@0: }