-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_speed.c
223 lines (192 loc) · 5.72 KB
/
test_speed.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#if defined(__APPLE__)
#include <mach/mach_time.h>
#endif
#include "multiarch.h"
#ifndef SPEED_ROUNDS
#define SPEED_ROUNDS 10000
#endif
static uint64_t get_percentile(const uint64_t *arr, size_t arrlen,
double percentile) {
int index = (int)ceil(percentile * (arrlen - 1)); // Calculate index
return arr[index];
}
static int uint64_t_cmp(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;
}
/**
* Return the current CPU time. Good for measuring CPU cycles
*/
static uint64_t get_clock_cpu(void) {
#if defined(__APPLE__)
#if defined(__DEBUG__)
printf("Using Apple Silicon\n");
#endif
// on Apple Silicon use high level API
return mach_absolute_time();
#else
#if defined(__DEBUG__)
printf("Using x86_64 register RDTSC\n");
#endif
uint64_t result;
__asm__ volatile("rdtsc; shlq $32,%%rdx; orq %%rdx,%%rax"
: "=a"(result)
:
: "%rdx");
return result;
#endif
}
/**
* Return the current hardware clock in nanosecond. Good for measuring actual
* time
*/
static uint64_t get_clock_ns(void) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec * 1000000000 + now.tv_nsec;
}
/**
* Return the current real-time clock in microseconds.
*/
static uint64_t get_clock_us(void) {
struct timespec timer;
clock_gettime(CLOCK_MONOTONIC, &timer);
return (timer.tv_sec * 1000000) + (timer.tv_nsec / 1000);
}
/**
* Compute the medium duration given an array of timestamps
*
* THIS FUNCTION IS DESTRUCTIVE! the timestamps array will be mutated
*/
static void println_medium_from_timestamps(char *prefix, uint64_t *tsarr,
size_t tsarr_len) {
for (size_t i = 0; i < tsarr_len - 1; i++)
tsarr[i] = tsarr[i + 1] - tsarr[i];
uint64_t *durs = tsarr;
uint64_t durslen = tsarr_len - 1;
qsort(durs, durslen, sizeof(uint64_t), uint64_t_cmp);
uint64_t medium = 0;
if (durslen % 2) {
medium = durs[durslen / 2];
} else {
medium = (durs[durslen / 2 - 1] + durs[durslen / 2]) / 2;
}
printf("%-32s medium: %16llu\n", prefix, medium);
printf("%-32s P90 : %16llu\n", "", get_percentile(durs, durslen, 0.90));
printf("%-32s P99 : %16llu\n", "", get_percentile(durs, durslen, 0.99));
}
static void println_hexstr(uint8_t *bytes, size_t byteslen) {
printf("0x");
for (size_t i = 0; i < byteslen; i++) {
printf("%02X", bytes[i]);
}
printf("\n");
}
uint64_t timestamps[SPEED_ROUNDS + 1];
static void benchmark_kem_enc(void) {
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t sk[CRYPTO_SECRETKEYBYTES];
uint8_t ct[CRYPTO_CIPHERTEXTBYTES];
uint8_t ss[CRYPTO_BYTES];
crypto_kem_keypair(pk, sk);
timestamps[0] = get_clock_cpu();
for (int i = 0; i < SPEED_ROUNDS; i++) {
crypto_kem_enc(ct, ss, pk);
timestamps[i + 1] = get_clock_cpu();
}
println_medium_from_timestamps("KEM encap", timestamps, SPEED_ROUNDS + 1);
}
static void benchmark_kem_dec(void) {
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t sk[CRYPTO_SECRETKEYBYTES];
uint8_t ct[CRYPTO_CIPHERTEXTBYTES];
uint8_t ss[CRYPTO_BYTES];
uint8_t ss_cmp[CRYPTO_BYTES];
crypto_kem_keypair(pk, sk);
crypto_kem_enc(ct, ss, pk);
timestamps[0] = get_clock_cpu();
for (int i = 0; i < SPEED_ROUNDS; i++) {
crypto_kem_dec(ss_cmp, ct, sk);
timestamps[i + 1] = get_clock_cpu();
}
println_medium_from_timestamps("KEM decap", timestamps, SPEED_ROUNDS + 1);
}
#if defined(ARCH_AVX)
static void benchmark_cpa_dec(void) {
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t sk[CRYPTO_SECRETKEYBYTES];
uint8_t ct[CRYPTO_CIPHERTEXTBYTES];
uint8_t ss[CRYPTO_BYTES];
uint8_t ss_cmp[CRYPTO_BYTES];
uint8_t e[SYS_N / 8];
crypto_kem_keypair(pk, sk);
crypto_kem_enc(ct, ss, pk);
timestamps[0] = get_clock_cpu();
for (int i = 0; i < SPEED_ROUNDS; i++) {
decrypt(e, sk, ct);
timestamps[i + 1] = get_clock_cpu();
}
println_medium_from_timestamps("PKE decap with check", timestamps, SPEED_ROUNDS + 1);
timestamps[0] = get_clock_cpu();
for (int i = 0; i < SPEED_ROUNDS; i++) {
cpa_decrypt(e, sk, ct);
timestamps[i + 1] = get_clock_cpu();
}
println_medium_from_timestamps("PKE decap w/o check", timestamps, SPEED_ROUNDS + 1);
}
static void benchmark_cpa_enc(void) {
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t sk[CRYPTO_SECRETKEYBYTES];
uint8_t ct[CRYPTO_CIPHERTEXTBYTES];
uint8_t ss[CRYPTO_BYTES];
uint8_t ss_cmp[CRYPTO_BYTES];
uint8_t e[SYS_N / 8];
crypto_kem_keypair(pk, sk);
crypto_kem_enc(ct, ss, pk);
timestamps[0] = get_clock_cpu();
for (int i = 0; i < SPEED_ROUNDS; i++) {
gen_e(e);
timestamps[i + 1] = get_clock_cpu();
}
println_medium_from_timestamps("Sample error vec", timestamps, SPEED_ROUNDS + 1);
timestamps[0] = get_clock_cpu();
for (int i = 0; i < SPEED_ROUNDS; i++) {
syndrome(ct, pk, e);
timestamps[i + 1] = get_clock_cpu();
}
println_medium_from_timestamps("Synd in Enc", timestamps, SPEED_ROUNDS + 1);
}
#endif
static void benchmark_kem_keypair(int keygen_rounds) {
uint8_t pk[CRYPTO_PUBLICKEYBYTES];
uint8_t sk[CRYPTO_SECRETKEYBYTES];
timestamps[0] = get_clock_cpu();
for (int i = 0; i < keygen_rounds; i++) {
crypto_kem_keypair(pk, sk);
timestamps[i + 1] = get_clock_cpu();
}
println_medium_from_timestamps("KEM keygen", timestamps, keygen_rounds + 1);
}
int main(void) {
#ifdef __DEBUG__
printf("Speed rounds: %d\n", SPEED_ROUNDS);
#endif
benchmark_kem_keypair(SPEED_ROUNDS > 10 ? 10 : SPEED_ROUNDS);
benchmark_kem_enc();
benchmark_kem_dec();
#ifdef ARCH_AVX
benchmark_cpa_dec();
benchmark_cpa_enc();
#endif
return 0;
}