Skip to content

Instantly share code, notes, and snippets.

@astojanov
Last active March 25, 2016 02:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save astojanov/d09ef96b6ee92834e781 to your computer and use it in GitHub Desktop.
Save astojanov/d09ef96b6ee92834e781 to your computer and use it in GitHub Desktop.
RSA Key Generation: Intel IPP vs OpenSSL
#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;
}
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
#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 );
}
#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