Last active
March 25, 2016 02:56
-
-
Save astojanov/d09ef96b6ee92834e781 to your computer and use it in GitHub Desktop.
RSA Key Generation: Intel IPP vs OpenSSL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdlib> | |
#include <iostream> | |
#include <openssl/rsa.h> | |
#include <openssl/sha.h> | |
#include <openssl/x509.h> | |
#include <openssl/opensslv.h> | |
#include <ippcore.h> | |
#include <ippcp.h> | |
#include <ipps.h> | |
#include <ippdefs.h> | |
#include "perf.h" | |
using namespace std; | |
IppsBigNumState* createBigNumState(int len, const Ipp32u* pData) { | |
int size; | |
ippsBigNumGetSize(len, &size); | |
IppsBigNumState* pBN = (IppsBigNumState*) ippMalloc(size);; | |
ippsBigNumInit(len, pBN); | |
if (pData != NULL) { | |
ippsSet_BN(IppsBigNumPOS, len, pData, pBN); | |
} | |
return pBN; | |
} | |
IppStatus RSA_IPPCrypto (int bitsRSA) { | |
IppStatus status; | |
// Security parameter specified for the | |
// Miller-Rabin test for probable primality. | |
int nTrials = 1; | |
// Number of bits of the exponent | |
int bitsExp = 24; | |
int sizeOfPrimeGen = -1; | |
int sizeOfRandomGen = -1; | |
int sizeOfPublicKey = -1; | |
int sizeOfPrivateKey = -1; | |
int sizeOfScratchBuffer = -1; | |
IppsPrimeState * primeGen = NULL; | |
IppsPRNGState * randomGen = NULL; | |
IppsRSAPublicKeyState * publicKey = NULL; | |
IppsRSAPrivateKeyState * privateKey = NULL; | |
Ipp8u * scratchBuffer = NULL; | |
Ipp32u E = 65537; | |
IppsBigNumState * pSrcPublicExp = createBigNumState (1, &E); | |
IppsBigNumState * pModulus = createBigNumState (bitsRSA / 32, NULL); | |
IppsBigNumState * pPublicExp = createBigNumState (bitsRSA / 32, NULL); | |
IppsBigNumState * pPrivateExp = createBigNumState (bitsRSA / 32, NULL); | |
// Prime Number Generator | |
ippsPrimeGetSize(bitsRSA, &sizeOfPrimeGen); | |
primeGen = (IppsPrimeState *) ippMalloc(sizeOfPrimeGen); | |
ippsPrimeInit(bitsRSA, primeGen); | |
// Pseudo Random Generator (default settings) | |
ippsPRNGGetSize(&sizeOfRandomGen); | |
randomGen = (IppsPRNGState*) ippMalloc (sizeOfRandomGen); | |
ippsPRNGInit(160, randomGen); | |
// Initialize the Public Key State | |
ippsRSA_GetSizePublicKey(bitsRSA, bitsExp, &sizeOfPublicKey); | |
publicKey = (IppsRSAPublicKeyState *)ippMalloc(sizeOfPublicKey); | |
ippsRSA_InitPublicKey(bitsRSA, bitsExp, publicKey, sizeOfPublicKey); | |
// Initialize the Private Key State | |
int bitsP = (bitsRSA + 1) / 2; | |
int bitsQ = bitsRSA - bitsP; | |
ippsRSA_GetSizePrivateKeyType2(bitsRSA, bitsRSA, &sizeOfPrivateKey); | |
privateKey = (IppsRSAPrivateKeyState *) ippMalloc(sizeOfPrivateKey); | |
ippsRSA_InitPrivateKeyType2(bitsP, bitsQ, privateKey, sizeOfPrivateKey); | |
// Initialize scratch buffer | |
ippsRSA_GetBufferSizePrivateKey(&sizeOfScratchBuffer, privateKey); | |
scratchBuffer = (Ipp8u *) ippMalloc (sizeOfScratchBuffer); | |
int runs = 10; | |
int repetitions = 10; | |
myInt64 values[repetitions]; | |
measurement_init(); | |
for (int i = 0; i < repetitions; ++i) { | |
measurement_start(); | |
for (int j = 0; j < runs; ++j) { | |
status = ippsRSA_GenerateKeys( | |
pSrcPublicExp, | |
pModulus, pPublicExp, pPrivateExp, | |
privateKey, scratchBuffer, nTrials, | |
primeGen, ippsPRNGen, randomGen | |
); | |
} | |
measurement_stop(); | |
meas_values[i] = meas_values[i] / runs; | |
} | |
measurement_finish(values); | |
qsort(values, meas_i, sizeof(myInt64), cmpMyInt64); | |
printf("%4d : %llu\n", bitsRSA, values[repetitions / 2]); | |
ippFree(pSrcPublicExp); | |
ippFree(pModulus); | |
ippFree(pPublicExp); | |
ippFree(pPrivateExp); | |
ippFree(primeGen); | |
ippFree(randomGen); | |
ippFree(publicKey); | |
ippFree(privateKey); | |
ippFree(scratchBuffer); | |
return status; | |
} | |
RSA * RSA_OpenSSL (int bitsRSA) { | |
int E = 65537; | |
int runs = 10; | |
int repetitions = 10; | |
myInt64 values[repetitions]; | |
RSA* rsa [runs * repetitions]; | |
measurement_init(); | |
for (int i = 0; i < repetitions; ++i) { | |
measurement_start(); | |
for (int j = 0; j < runs; ++j) { | |
rsa[i * runs + j] = RSA_generate_key(bitsRSA, E, NULL, NULL); | |
} | |
measurement_stop(); | |
meas_values[i] = meas_values[i] / runs; | |
} | |
measurement_finish(values); | |
qsort(values, meas_i, sizeof(myInt64), cmpMyInt64); | |
printf("%4d : %llu\n", bitsRSA, values[repetitions / 2]); | |
for (int i = 0; i < runs * repetitions; i += 1) { | |
free(rsa[i]); | |
} | |
return NULL; | |
} | |
int main() { | |
cout << "Getting Performance of OpenSSL" << endl; | |
cout << OPENSSL_VERSION_TEXT << endl; | |
cout << "================================================" << endl; | |
for (int i = 0; i < 64; i += 1) { | |
RSA_OpenSSL((i + 1) * 32); | |
} | |
cout << endl << endl; | |
ippInit(); | |
cout << "Getting Performance of Intel IPP Crypto" << endl; | |
const IppLibraryVersion * version = ippsGetLibVersion (); | |
printf("%s %s %s\n", version->Name, version->Version, version->BuildDate); | |
cout << "================================================" << endl; | |
for (int i = 0; i < 64; i += 1) { | |
RSA_IPPCrypto((i + 1) * 32); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CPPFLAGS = -O3 -xHost -no-multibyte-chars | |
INCLUDE = -I/opt/local/include/ -I/opt/intel/ipp/include | |
LIBS = -L/opt/local/lib/ -lssl -lcrypto -L/opt/intel/ipp/lib -ipp=crypto | |
all: perf.h | |
icpc $(INCLUDE) $(CFLAGS) -c main.cpp -o main.o | |
icpc $(INCLUDE) $(CFLAGS) -c perf.cpp -o perf.o | |
icpc $(LIBS) perf.o main.o -o rsatest | |
clean: | |
rm -rf *.o rsatest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <math.h> | |
#include <stdlib.h> | |
#include <sys/time.h> | |
#include <sys/resource.h> | |
#include "perf.h" | |
myInt64 meas_values[MAX_NUM_MEASUREMENTS]; | |
int meas_i = 0; | |
myInt64 meas_start = 0; | |
myInt64 meas_overhead = 0; | |
static void swap(myInt64 *x, myInt64 *y) { | |
myInt64 temp; | |
temp = *x; | |
*x = *y; | |
*y = temp; | |
} | |
/********************************************************************************/ | |
// These can be used if we want to access the values of the perf. counters from our code | |
__attribute__((noinline)) void init_tsc() { | |
; | |
} | |
__attribute__((noinline)) myInt64 start_tsc(void) { | |
tsc_counter start; | |
CPUID(); | |
RDTSC(start); | |
return COUNTER_VAL(start); | |
} | |
__attribute__((noinline)) myInt64 stop_tsc(myInt64 start) { | |
tsc_counter end; | |
RDTSC(end); | |
CPUID(); | |
return COUNTER_VAL(end) - start; | |
} | |
__attribute__((noinline)) myInt64 get_tsc_overhead(void) { | |
myInt64 t1, t2, t3, t; | |
t = start_tsc(); stop_tsc(t); | |
t = start_tsc(); stop_tsc(t); | |
t = start_tsc(); stop_tsc(t); | |
t1 = start_tsc(); t1 = stop_tsc(t1); | |
t2 = start_tsc(); t2 = stop_tsc(t2); | |
t3 = start_tsc(); t3 = stop_tsc(t3); | |
if (t1 > t2) | |
swap(&t1, &t2); | |
if (t2 > t3) | |
swap(&t2, &t3); | |
if (t1 > t2) | |
swap(&t1, &t2); | |
return t2; | |
} | |
/********************************************************************************/ | |
// These can be used if we don't care about the values of the perf. conters | |
// in our code and we just want the measurements to be written in measurements.txt | |
__attribute__((noinline)) void measurement_start(void) { | |
tsc_counter start; | |
CPUID(); | |
RDTSC(start); | |
meas_start = COUNTER_VAL(start); | |
} | |
__attribute__((noinline)) void measurement_stop(void) { | |
tsc_counter end; | |
RDTSC(end); | |
CPUID(); | |
meas_values[meas_i++] = COUNTER_VAL(end) - meas_start; | |
} | |
__attribute__((noinline)) myInt64 get_measurement_overhead(void) { | |
myInt64 t1, t2, t3; | |
int init_i = meas_i; | |
measurement_start(); measurement_stop(); | |
measurement_start(); measurement_stop(); | |
measurement_start(); measurement_stop(); | |
measurement_start(); measurement_stop(); | |
measurement_start(); measurement_stop(); | |
measurement_start(); measurement_stop(); | |
t1 = meas_values[init_i]; t2 = meas_values[init_i + 1]; t3 = meas_values[init_i + 2]; | |
if (t1 > t2) | |
swap(&t1, &t2); | |
if (t2 > t3) | |
swap(&t2, &t3); | |
if (t1 > t2) | |
swap(&t1, &t2); | |
meas_i = init_i; | |
return t2; | |
} | |
__attribute__((noinline)) void measurement_init(void) { | |
meas_i = 0; | |
meas_overhead = get_measurement_overhead(); | |
} | |
__attribute__((noinline)) void measurement_finish(myInt64 * values) { | |
int i; | |
for (i = 0; i < meas_i; i++) { | |
values[i] = meas_values[i] - meas_overhead; | |
} | |
} | |
int cmpMyInt64(const void * a, const void * b) { | |
return ( *(myInt64*)a - *(myInt64*)b ); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef MEASURE_H | |
#define MEASURE_H | |
#include <stdlib.h> | |
#include <stdio.h> | |
/* ==================== GNU C and possibly other UNIX compilers ===================== */ | |
#ifndef WINK | |
#if defined(__GNUC__) || defined(__linux__) | |
#define VOLATILE __volatile__ | |
#define ASM __asm__ | |
#else | |
/* if we're neither compiling with gcc or under linux, we can hope | |
* the following lines work, they probably won't */ | |
#define ASM asm | |
#define VOLATILE | |
#endif | |
#define myInt64 unsigned long long | |
#define INTK unsigned int | |
/* ======================== WINK ======================= */ | |
#else | |
#define myInt64 signed __int64 | |
#define INTK unsigned __intK | |
#endif | |
#define COUNTER_LO(a) ((a).intK.lo) | |
#define COUNTER_HI(a) ((a).intK.hi) | |
#define COUNTER_VAL(a) ((a).int64) | |
#define COUNTER(a) \ | |
((unsigned long long)COUNTER_VAL(a)) | |
#define COUNTER_DIFF(a,b) \ | |
(COUNTER(a)-COUNTER(b)) | |
/* ==================== GNU C and possibly other UNIX compilers ===================== */ | |
#ifndef WINK | |
typedef union | |
{ myInt64 int64; | |
struct {INTK lo, hi;} intK; | |
} tsc_counter; | |
#if defined(__ia64__) | |
#if defined(__INTEL_COMPILER) | |
#define RDTSC(tsc) (tsc).int64=__getReg(3116) | |
#else | |
#define RDTSC(tsc) ASM VOLATILE ("mov %0=ar.itc" : "=r" ((tsc).int64) ) | |
#endif | |
#define CPUID() do{/*No need for serialization on Itanium*/}while(0) | |
#else | |
#define RDTSC(cpu_c) \ | |
ASM VOLATILE ("rdtsc" : "=a" ((cpu_c).intK.lo), "=d"((cpu_c).intK.hi)) | |
#define CPUID() \ | |
ASM VOLATILE ("cpuid" : : "a" (0) : "bx", "cx", "dx" ) | |
#endif | |
/* ======================== WINK ======================= */ | |
#else | |
typedef union | |
{ myInt64 int64; | |
struct {INTK lo, hi;} intK; | |
} tsc_counter; | |
#define RDTSC(cpu_c) \ | |
{ __asm rdtsc \ | |
__asm mov (cpu_c).intK.lo,eax \ | |
__asm mov (cpu_c).intK.hi,edx \ | |
} | |
#define CPUID() \ | |
{ \ | |
__asm mov eax, 0 \ | |
__asm cpuid \ | |
} | |
#endif | |
#ifndef MAX_NUM_MEASUREMENTS | |
#define MAX_NUM_MEASUREMENTS 2000 | |
#endif | |
extern myInt64 meas_values[MAX_NUM_MEASUREMENTS]; | |
extern int meas_i; | |
extern myInt64 meas_start; | |
extern myInt64 meas_overhead; | |
/********************************************************************************/ | |
// These can be used if we want to access the values of the perf. counters from our code | |
__attribute__((noinline)) void init_tsc(); | |
__attribute__((noinline)) myInt64 start_tsc(void); | |
__attribute__((noinline)) myInt64 stop_tsc(myInt64 start); | |
__attribute__((noinline)) myInt64 get_tsc_overhead(void); | |
int cmpMyInt64(const void * a, const void * b); | |
/********************************************************************************/ | |
// These can be used if we don't care about the values of the perf. conters | |
// in our code and we just want the measurements to be written in measurements.txt | |
__attribute__((noinline)) void measurement_start(void); | |
__attribute__((noinline)) void measurement_stop(void); | |
__attribute__((noinline)) myInt64 get_measurement_overhead(void); | |
__attribute__((noinline)) void measurement_init(void); | |
__attribute__((noinline)) void measurement_finish(myInt64 * meas_values); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment