#include <assert.h>
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "align.h"
#include "KangarooTwelve.h"
#include "KeccakP-1600-SnP.h"
#include "timing.h"
#include "testPerformance.h"
#if !defined(__x86_64__) && !defined(_M_X64) && !defined(__i386__) && !defined(_M_IX86)
#undef KeccakP1600_enable_simd_options
#endif
#define BIG_BUFFER_SIZE (2*1024*1024)
ALIGN(64) uint8_t bigBuffer[BIG_BUFFER_SIZE];
cycles_t measurePerformance(int (*impl)(const unsigned char*, size_t,
unsigned char*, size_t,
const unsigned char*, size_t),
cycles_t dtMin, unsigned int inputLen)
{
ALIGN(64) unsigned char output[32];
measureTimingDeclare
assert(inputLen <= BIG_BUFFER_SIZE);
memset(bigBuffer, 0xA5, 16);
measureTimingBeginDeclared
impl(bigBuffer, inputLen, output, 32, (const unsigned char *)"", 0);
measureTimingEnd
}
#if defined(KeccakP1600_enable_simd_options) && !defined(KeccakP1600_disableParallelism)
void KangarooTwelve_SetProcessorCapabilities();
#endif
void printKangarooTwelvePerformanceHeader(int securityLevel)
{
#if defined(KeccakP1600_enable_simd_options) && !defined(KeccakP1600_disableParallelism)
KangarooTwelve_SetProcessorCapabilities();
#endif
printf("*** KT%d ***\n", securityLevel);
printf("Using Keccak-p[1600,12] implementations:\n");
printf("- \303\2271: %s\n", KeccakP1600_GetImplementation());
#if defined(KeccakP1600_12rounds_FastLoop_supported)
printf(" + KeccakP1600_12rounds_FastLoop_Absorb()\n");
#endif
#ifndef KeccakP1600_disableParallelism
if (KeccakP1600times2_IsAvailable()) {
printf("- \303\2272: %s\n", KeccakP1600times2_GetImplementation());
#if defined(KeccakP1600times2_12rounds_FastLoop_supported)
printf(" + KeccakP1600times2_12rounds_FastLoop_Absorb()\n");
#endif
}
else
printf("- \303\2272: not used\n");
if (KeccakP1600times4_IsAvailable()) {
printf("- \303\2274: %s\n", KeccakP1600times4_GetImplementation());
#if defined(KeccakP1600times4_12rounds_FastLoop_supported)
printf(" + KeccakP1600times4_12rounds_FastLoop_Absorb()\n");
#endif
}
else
printf("- \303\2274: not used\n");
if (KeccakP1600times8_IsAvailable()) {
printf("- \303\2278: %s\n", KeccakP1600times8_GetImplementation());
#if defined(KeccakP1600times8_12rounds_FastLoop_supported)
printf(" + KeccakP1600times8_12rounds_FastLoop_Absorb()\n");
#endif
}
else
printf("- \303\2278: not used\n");
#endif
printf("\n");
}
void testPerformanceFull(int (*impl)(const unsigned char*, size_t,
unsigned char*, size_t,
const unsigned char*, size_t), int extra)
{
const unsigned int chunkSize = 8192;
unsigned halfTones;
cycles_t calibration = CalibrateTimer();
unsigned int chunkSizeLog = (unsigned int)floor(log(chunkSize)/log(2.0)+0.5);
int displaySlope = 0;
measurePerformance(impl, calibration, 500000);
for(halfTones=chunkSizeLog*12-28; halfTones<=13*12; halfTones+=4) {
double I = pow(2.0, halfTones/12.0);
unsigned int i = (unsigned int)floor(I+0.5);
cycles_t time, timePlus1Block, timePlus2Blocks, timePlus4Blocks, timePlus8Blocks;
cycles_t timePlus168Blocks;
time = measurePerformance(impl, calibration, i);
if (i == chunkSize) {
displaySlope = 1;
timePlus1Block = measurePerformance(impl, calibration, i+1*chunkSize);
timePlus2Blocks = measurePerformance(impl, calibration, i+2*chunkSize);
timePlus4Blocks = measurePerformance(impl, calibration, i+4*chunkSize);
timePlus8Blocks = measurePerformance(impl, calibration, i+8*chunkSize);
timePlus168Blocks = measurePerformance(impl, calibration, i+extra*chunkSize);
}
printf("%8u bytes: %9"PRId64" %s, %6.3f %s/byte\n", i, time, getTimerUnit(), time*1.0/i, getTimerUnit());
if (displaySlope) {
printf(" +1 block: %9"PRId64" %s, %6.3f %s/byte (slope)\n", timePlus1Block, getTimerUnit(), (timePlus1Block-(double)(time))*1.0/chunkSize/1.0, getTimerUnit());
printf(" +2 blocks: %9"PRId64" %s, %6.3f %s/byte (slope)\n", timePlus2Blocks, getTimerUnit(), (timePlus2Blocks-(double)(time))*1.0/chunkSize/2.0, getTimerUnit());
printf(" +4 blocks: %9"PRId64" %s, %6.3f %s/byte (slope)\n", timePlus4Blocks, getTimerUnit(), (timePlus4Blocks-(double)(time))*1.0/chunkSize/4.0, getTimerUnit());
printf(" +8 blocks: %9"PRId64" %s, %6.3f %s/byte (slope)\n", timePlus8Blocks, getTimerUnit(), (timePlus8Blocks-(double)(time))*1.0/chunkSize/8.0, getTimerUnit());
printf(" +%d blocks: %9"PRId64" %s, %6.3f %s/byte (slope)\n", extra, timePlus168Blocks, getTimerUnit(), (timePlus168Blocks-(double)(time))*1.0/chunkSize/(extra*1.0), getTimerUnit());
displaySlope = 0;
}
}
for(halfTones=12*12; halfTones<=20*12; halfTones+=4) {
double I = chunkSize + pow(2.0, halfTones/12.0);
unsigned int i = (unsigned int)floor(I+0.5);
cycles_t time;
time = measurePerformance(impl, calibration, i);
printf("%8u bytes: %9"PRId64" %s, %6.3f %s/byte\n", i, time, getTimerUnit(), time*1.0/i, getTimerUnit());
}
printf("\n\n");
}
void testKangarooTwelvePerformance()
{
printKangarooTwelvePerformanceHeader(128);
testPerformanceFull(KT128, 168);
printKangarooTwelvePerformanceHeader(256);
testPerformanceFull(KT256, 136);
}
void testPerformance()
{
#if defined(KeccakP1600_enable_simd_options) && !defined(KeccakP1600_disableParallelism)
KangarooTwelve_EnableAllCpuFeatures();
int cpu_has_AVX512 = KangarooTwelve_DisableAVX512();
int cpu_has_AVX2 = KangarooTwelve_DisableAVX2();
int cpu_has_SSSE3 = KangarooTwelve_DisableSSSE3();
#endif
testKangarooTwelvePerformance();
#if defined(KeccakP1600_enable_simd_options) && !defined(KeccakP1600_disableParallelism)
if (cpu_has_SSSE3) {
printf("\n");
KangarooTwelve_EnableAllCpuFeatures();
KangarooTwelve_DisableAVX512();
KangarooTwelve_DisableAVX2();
testKangarooTwelvePerformance();
}
if (cpu_has_AVX2) {
printf("\n");
KangarooTwelve_EnableAllCpuFeatures();
KangarooTwelve_DisableAVX512();
testKangarooTwelvePerformance();
}
if (cpu_has_AVX512) {
printf("\n");
KangarooTwelve_EnableAllCpuFeatures();
testKangarooTwelvePerformance();
}
#endif
int (*comparison)(const unsigned char*, size_t,
unsigned char*, size_t,
const unsigned char*, size_t) = NULL;
if (comparison != NULL) {
printf("\n*** Non-K12 function for comparison: ***\n");
testPerformanceFull(comparison, 128);
}
}