223 lines
7.7 KiB
C
223 lines
7.7 KiB
C
|
/*
|
||
|
Organization: Technical University of Kosice (TUKE),
|
||
|
Department: Department of Electronics and Multimedia Telecommunications (DEMT/KEMT),
|
||
|
Faculties: Faculty of Electrical Engineering and Informatics (FEI),
|
||
|
Feld of study: Informatics,
|
||
|
Study program: Computer Networks,
|
||
|
School year: 3., Bachelor study, 2020/2021
|
||
|
Author: Marek Rohac -- MR,
|
||
|
Compiler: Winlibs GCC -- MinGW-W64 x86_64-posix-seh, built by Brecht Sanders, v. 10.2.0,
|
||
|
-- also works with GCC 11.1.0
|
||
|
Compiling: gcc ./amdINC/secrng.c amdSPRNG.c -Wall -g -I./amdINC -mrdrnd -mrdseed -o amdSPRNG ,
|
||
|
Version: 1.1, 19.05.2021.
|
||
|
Description:
|
||
|
This program is only for educational purposes.
|
||
|
Program use 4 AMD APIs (defined in secrng.h) to generate random bytes:
|
||
|
is_RDRAND_supported();
|
||
|
is_RDSEED_supported();
|
||
|
get_rdseed_bytes_arr(unsigned char *rng_arr, unsigned int N, unsigned int retry_count)
|
||
|
get_rdrand_bytes_arr(unsigned char *rng_arr, unsigned int N, unsigned int retry_count)
|
||
|
Usage: In macro N define how much random bytes you want per one generating.
|
||
|
CYCLES then defined how much times you want to repeat generating process
|
||
|
Program then generate output according APIs and save values to .bin files with name by current RD name
|
||
|
*/
|
||
|
#define __USE_MINGW_ANSI_STDIO
|
||
|
#include <stdio.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <windows.h>
|
||
|
#include "secrng.h"
|
||
|
// count of API calls
|
||
|
#define CYCLES 1024
|
||
|
// output size per API call in Bytes
|
||
|
#define N 16384
|
||
|
// ULONG_MAX should be same as UINT_MAX -- 4GB
|
||
|
//N x CYCLES = output size in bytes
|
||
|
//33554432 B == 32 MB
|
||
|
//16777216 B == 16 MB
|
||
|
//16384 B == 16kB
|
||
|
//retry count if rng fails
|
||
|
#define NT 15
|
||
|
|
||
|
//Macros For time measurments
|
||
|
#define TIMER_INIT \
|
||
|
LARGE_INTEGER frequency; \
|
||
|
LARGE_INTEGER t1,t2; \
|
||
|
double elapsedTime; \
|
||
|
QueryPerformanceFrequency(&frequency);
|
||
|
|
||
|
|
||
|
/** Use to start the performance timer */
|
||
|
#define TIMER_START QueryPerformanceCounter(&t1);
|
||
|
|
||
|
/** Use to stop the performance timer and output the result to the standard stream. Less verbose than \c TIMER_STOP_VERBOSE */
|
||
|
#define TIMER_STOP \
|
||
|
QueryPerformanceCounter(&t2); \
|
||
|
elapsedTime=(float)(t2.QuadPart-t1.QuadPart)/frequency.QuadPart;
|
||
|
// divide frequency.QuadPart by 1000.0 if you want time in ms
|
||
|
/*
|
||
|
function to measure speed of generating process (output is number of number of cpu cycles)
|
||
|
CYCLES * AverageCycles* 1/ghzOfProcessor * 10^-9 = cca execution CPUTIME
|
||
|
Inspiration by --> https://github.com/newhopecrypto/newhope/tree/master/ref
|
||
|
- MR: asm changed to __asm__ for newer c standard support (before we need -std=gnu99 to compile)
|
||
|
*/
|
||
|
/*
|
||
|
int64_t cpucycles(void)
|
||
|
{
|
||
|
uint64_t result;
|
||
|
//function use rdts instruction and shift higher values from reg where rdtsc store values
|
||
|
//(rax, rdx)
|
||
|
__asm__ volatile(".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax"
|
||
|
: "=a" (result) :: "%rdx");
|
||
|
return result;
|
||
|
}
|
||
|
=================================================================================
|
||
|
REPLACED BY CPUID/RDTSC/RDTSCP INSTRUCTIONS -->below-->cpucyclesS(),cpucyclesE()
|
||
|
***FOR BETTER PRECISIOUS***
|
||
|
=================================================================================
|
||
|
https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf
|
||
|
CYCLES * AverageCycles* 1/ghzOfProcessor * 10^-9 = cca execution CPUTIME
|
||
|
*/
|
||
|
//cpucyclesS -- start measurment
|
||
|
static __inline__ uint64_t cpucyclesS(){
|
||
|
unsigned cycles_low, cycles_high;
|
||
|
__asm__ volatile ("CPUID\n\t"
|
||
|
"RDTSC\n\t"
|
||
|
"mov %%edx, %0\n\t"
|
||
|
"mov %%eax, %1\n\t": "=r" (cycles_high), "=r" (cycles_low)::
|
||
|
"%rax", "%rbx", "%rcx", "%rdx");
|
||
|
return (((uint64_t)cycles_high << 32) | cycles_low );
|
||
|
}
|
||
|
//cpucyclesE -- end measurment
|
||
|
static __inline__ uint64_t cpucyclesE(){
|
||
|
unsigned cycles_low, cycles_high;
|
||
|
__asm__ volatile ("RDTSCP\n\t"
|
||
|
"mov %%edx, %0\n\t"
|
||
|
"mov %%eax, %1\n\t"
|
||
|
"CPUID\n\t": "=r" (cycles_high), "=r" (cycles_low)::
|
||
|
"%rax", "%rbx", "%rcx", "%rdx");
|
||
|
return (((uint64_t)cycles_high << 32) | cycles_low );
|
||
|
}
|
||
|
/*
|
||
|
compare for qsort
|
||
|
*/
|
||
|
static int cmp_llu(const void *a, const void*b)
|
||
|
{
|
||
|
if(*(uint64_t *)a < *(uint64_t *)b) return -1;
|
||
|
if(*(uint64_t *)a > *(uint64_t *)b) return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
calculating of median value from measurment
|
||
|
*/
|
||
|
static uint64_t median(uint64_t *l, size_t llen)
|
||
|
{
|
||
|
if (llen<=1) {printf("Not enought values for median\n");
|
||
|
return l[llen-1];
|
||
|
}
|
||
|
qsort(l,llen,sizeof(uint64_t),cmp_llu);
|
||
|
if(llen%2) return l[llen/2];
|
||
|
else return (l[llen/2-1]+l[llen/2])/2;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
calculating of average value from measurment
|
||
|
*/
|
||
|
static uint64_t average(uint64_t *t, size_t tlen)
|
||
|
{
|
||
|
uint64_t acc=0;
|
||
|
size_t i;
|
||
|
for(i=0;i<tlen;i++)acc += t[i];
|
||
|
if(acc!=0)return acc/(tlen);
|
||
|
return t[tlen];
|
||
|
}
|
||
|
// storing random data from generating
|
||
|
void store_Data(FILE * fp, unsigned char * pbBuffer){
|
||
|
fwrite(pbBuffer,sizeof(unsigned char),N,fp);
|
||
|
if( feof(fp) ) {printf("Problem with %s file\n", (char*)fp);}
|
||
|
}
|
||
|
//storing time data from executions
|
||
|
void store_Time_Data(const char * name, uint64_t *t, size_t tlen,FILE * fp, double programRun){
|
||
|
uint64_t sum;
|
||
|
fprintf(fp, "%s\n",name);
|
||
|
for(size_t i=0;i<tlen;i++){
|
||
|
sum+=t[i];
|
||
|
// fprintf(fp, "%4.lld%s %llu %s\n", i+1, ".Time: ", t[i]," cpucycles");
|
||
|
if( feof(fp) ) {printf("Problem with %s file\n", name);}
|
||
|
}
|
||
|
fprintf(fp,"TOTAL: %llu\nMEDIAN: %llu cpucycles\nAVERAGE: %llu cpucycles\nEXECUTED in %f s\n",sum, median(t, tlen),average(t, tlen),programRun);
|
||
|
}
|
||
|
|
||
|
int rdseed(FILE * timeFile,unsigned char* rng_chararr){
|
||
|
FILE * RDSEED=fopen("RDSEED.bin","ab+");
|
||
|
int ret;
|
||
|
//Get random bytes of a given size
|
||
|
if (!rng_chararr){rng_chararr = (unsigned char*) malloc(sizeof(unsigned char) * N);}
|
||
|
uint64_t time[CYCLES],tick;
|
||
|
TIMER_INIT
|
||
|
{TIMER_START
|
||
|
for (int i = 0; i < CYCLES; i++){
|
||
|
tick = cpucyclesS();
|
||
|
ret = get_rdseed_bytes_arr(rng_chararr, N, NT);
|
||
|
time[i]=cpucyclesE() - tick;
|
||
|
if (ret != SECRNG_SUCCESS){
|
||
|
printf("Failure in %d. cycle -- RDRAND! \n",i);
|
||
|
}
|
||
|
store_Data(RDSEED,rng_chararr); //dont use for better time test}
|
||
|
}
|
||
|
TIMER_STOP}
|
||
|
store_Time_Data("RDSEED:",time,CYCLES,timeFile, elapsedTime);
|
||
|
fclose(RDSEED);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int rdrand(FILE * timeFile,unsigned char* rng_chararr){
|
||
|
//Get random bytes of given size
|
||
|
FILE * RDRAND=fopen("RDRAND.bin","ab+");
|
||
|
int ret;
|
||
|
if (!rng_chararr){rng_chararr = (unsigned char*) malloc(sizeof(unsigned char) * N);}
|
||
|
uint64_t time[CYCLES], tick;
|
||
|
TIMER_INIT
|
||
|
{TIMER_START
|
||
|
for (int i = 0; i < CYCLES; i++){
|
||
|
tick = cpucyclesS();
|
||
|
ret = get_rdrand_bytes_arr(rng_chararr, N, NT);
|
||
|
time[i] = cpucyclesE() - tick;
|
||
|
if (ret != SECRNG_SUCCESS){
|
||
|
printf("Failure in %d. cycle -- RDRAND! \n",i);
|
||
|
}
|
||
|
store_Data(RDRAND,rng_chararr); //dont use for better time test}
|
||
|
}
|
||
|
TIMER_STOP}
|
||
|
store_Time_Data("RDRAND:",time,CYCLES,timeFile, elapsedTime);
|
||
|
fclose(RDRAND);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int main(){
|
||
|
//RDTimeExecution
|
||
|
FILE * timeFile=fopen("rdResults.txt","a+");
|
||
|
int ret = 0;
|
||
|
unsigned char* rng_chararr = NULL;
|
||
|
|
||
|
|
||
|
ret = is_RDSEED_supported();
|
||
|
if (ret == SECRNG_SUPPORTED)
|
||
|
ret= rdseed(timeFile,rng_chararr);
|
||
|
else
|
||
|
printf("No support for RDSEED!\n");
|
||
|
|
||
|
ret = is_RDRAND_supported();
|
||
|
if (ret == SECRNG_SUPPORTED)
|
||
|
ret= rdrand(timeFile,rng_chararr);
|
||
|
else
|
||
|
printf("No support for RDRAND!\n");
|
||
|
|
||
|
if (rng_chararr) free(rng_chararr);
|
||
|
fclose(timeFile);
|
||
|
printf("PROGRAM COMPLETE!\n");
|
||
|
return ret;
|
||
|
}
|
||
|
|