/* 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 compile: gcc winAPIprng.c -o rng -Wall -Wextra -Werror -g -std=c11 -lbcrypt, version: 1.2 , 20.05.2021. Description: This program is only for educational purposes. Program use 3 different windows APIs to generate random data cryptGenRandom, BCryptGenRandom and RtlGenRandom Usage: In macro RNG_PER_CYCLE_BITS define how much random bits you want by one cycle. Then define number of cycles in macro RNG_CYCLES Program then generate output according APIs and save values to .bin files with name by current API */ #define __USE_MINGW_ANSI_STDIO #include #include #include #include #include /* 64MB = 536870912b ULONG_MAX = 4096 MB --> 4. meranie 32MB = 268435456b --> 3. meranie 16MB = 134217728b --> 2. meranie 16KB = 131072b --> 1. meranie YOU CAN SET NUMBER OF BYTES IN RNG_BYTE_OUTPUT_SIZE TO AVOID CALCULATING TO BITS */ // bit size per API call .. #define RNG_PER_CYKLE_BITS 16*1024*1024*8 //number of calls --> 32gb now #define RNG_CYCLES 1024 // byte size of output #define RNG_BYTE_OUTPUT_SIZE RNG_PER_CYKLE_BITS/8 //uint size of output #define RNG_UINT_OUTPUT_SIZE RNG_PER_CYKLE_BITS/32 //we work with big endian values, there's check macro -- NOT USE, BUT USEFULL #define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1}) //32 GB output --> 268435456*1024/8/1024/1024/1024 //8b = 1 BYTE //32b = 1 UINT /*############################################################ FUNCTIONS FOR MEASURMENTS ##############################################################*/ //MACROS FOR EASIER TIMER MEASURMENT, VIA WINAPI QueryPerformanceCounter #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=(double)(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 rand_s function on AMD processors NOT USE, BUT USEFULL */ void castUintToByte(uint32_t *uintArray,BYTE* output){ int i=0; int n=4; //because uint have 32b and BYTE 8b -- 32/8 = 4 for (int j = 0; j < RNG_UINT_OUTPUT_SIZE; j++) { for(; n-->0; i++) output[i]=(uintArray[j]>>(n*8))& 0xFF; n=4; } } //storing generated random data void store_Data(FILE * fp, void * pbBuffer){ fwrite(pbBuffer,sizeof(BYTE),RNG_BYTE_OUTPUT_SIZE,fp); if( feof(fp) ) {printf("Problem with %s file\n", (char*)fp);} //else printf("File successfully create!\n"); } //storing time datas of 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