Skip to content

Commit bc3f212

Browse files
committed
Add evp_rand perftool
1 parent c25386d commit bc3f212

File tree

3 files changed

+256
-0
lines changed

3 files changed

+256
-0
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,25 @@ thread-count - number of threads
307307
```sh
308308
./evp_kdf -o evp_shared 10
309309
```
310+
311+
## evp_rand
312+
313+
This CLI tool generates random data with HASH-DRGB.
314+
Runs for 5 seconds and prints the average execution time per computation.
315+
316+
Two modes of operation:
317+
- evp_shared (default): Use EVP API and allow shared data between computations
318+
- evp_isolated: Use EVP API and don't allow shared data between computations
319+
320+
```
321+
Usage: evp_rand [-h] [-t] [-o operation] [-V] thread-count
322+
-h - print this help output
323+
-t - terse output
324+
-o operation - mode of operation. One of [evp_isolated, evp_shared] (default: evp_shared)
325+
-V - print version information and exit
326+
thread-count - number of thread
327+
```
328+
329+
```sh
330+
./evp_rand -o evp_shared 10
331+
```

source/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,13 +218,17 @@ target_link_libraries(evp_mac PRIVATE perf)
218218
add_executable(evp_kdf evp_kdf.c)
219219
target_link_libraries(evp_kdf PRIVATE perf)
220220

221+
add_executable(evp_rand evp_rand.c)
222+
target_link_libraries(evp_rand PRIVATE perf)
223+
221224
## Running tests
222225
# Options
223226
set(run_tests evp_fetch
224227
evp_hash
225228
evp_cipher
226229
evp_mac
227230
evp_kdf
231+
evp_rand
228232
evp_setpeer
229233
handshake
230234
newrawkey
@@ -268,6 +272,9 @@ set(run_evp_mac_operations
268272
set(run_evp_kdf_operations
269273
evp_kdf "" "" "-o evp_shared" "-o evp_isolated" "-o deprecated_shared" "-o deprecated_isolated"
270274
CACHE STRING "Modes of operation for evp_kdf")
275+
set(run_evp_rand_operations
276+
evp_rand "" "" "-o evp_isolated" "-o evp_shared"
277+
CACHE STRING "Modes of operation for evp_rand")
271278
set(run_evp_setpeer_keys
272279
evp_setpeer "-k" dh ec256 ec521 x25519 all
273280
CACHE STRING "Key types for evp_setpeer")
@@ -311,6 +318,7 @@ set(run_opts run_evp_fetch_pqs
311318
run_evp_cipher_algorithms
312319
run_evp_mac_operations
313320
run_evp_kdf_operations
321+
run_evp_rand_operations
314322
run_evp_setpeer_keys
315323
run_newrawkey_algos
316324
run_pkeyread_keys

source/evp_rand.c

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/*
2+
* Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. You can obtain a copy
6+
* in the file LICENSE in the source distribution or at
7+
* https://www.openssl.org/source/license.html
8+
*/
9+
10+
/*
11+
* This CLI tool generates random data with HASH-DRGB.
12+
* Runs for 5 seconds and prints the average execution time per computation.
13+
*/
14+
15+
#define OPENSSL_SUPPRESS_DEPRECATED
16+
17+
#include <stdlib.h>
18+
#include <stdio.h>
19+
#ifndef _WIN32
20+
# include <unistd.h>
21+
#else
22+
# include "perflib/getopt.h"
23+
#endif /* _WIN32 */
24+
25+
#include <openssl/evp.h>
26+
#include <openssl/rand.h>
27+
#include <openssl/core_names.h>
28+
#include "perflib/perflib.h"
29+
#include "perflib/basename.h"
30+
31+
#define RUN_TIME 5
32+
#define DATA_SIZE 64
33+
34+
static int threadcount;
35+
static OSSL_TIME max_time;
36+
static size_t *counts = NULL;
37+
static int run_err = 0;
38+
39+
typedef enum {
40+
EVP_SHARED = 0,
41+
EVP_ISOLATED,
42+
} operation_type;
43+
44+
static int evp_isolated()
45+
{
46+
EVP_RAND *rand = EVP_RAND_fetch(NULL, "HASH-DRBG", NULL);
47+
EVP_RAND_CTX *ctx = NULL;
48+
unsigned char out[DATA_SIZE];
49+
int ret = 0;
50+
OSSL_PARAM params[] = {
51+
OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, SN_sha512, 0),
52+
OSSL_PARAM_construct_end(),
53+
};
54+
55+
if (rand == NULL
56+
|| (ctx = EVP_RAND_CTX_new(rand, NULL)) == NULL
57+
|| !EVP_RAND_CTX_set_params(ctx, params)
58+
|| !EVP_RAND_generate(ctx, out, sizeof(out), 0, 0, NULL, 0))
59+
goto err;
60+
61+
ret = 1;
62+
err:
63+
EVP_RAND_free(rand);
64+
EVP_RAND_CTX_free(ctx);
65+
66+
return ret;
67+
}
68+
69+
static void do_evp_isolated(size_t num)
70+
{
71+
OSSL_TIME time;
72+
size_t count = 0;
73+
74+
do {
75+
if (!evp_isolated()) {
76+
run_err = 1;
77+
return;
78+
}
79+
80+
count++;
81+
time = ossl_time_now();
82+
} while (time.t < max_time.t);
83+
84+
counts[num] = count;
85+
}
86+
87+
static void do_evp_shared(size_t num)
88+
{
89+
OSSL_TIME time;
90+
size_t count = 0;
91+
EVP_RAND *rand = EVP_RAND_fetch(NULL, "HASH-DRBG", NULL);
92+
EVP_RAND_CTX *ctx = NULL;
93+
unsigned char out[DATA_SIZE];
94+
OSSL_PARAM params[] = {
95+
OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, SN_sha512, 0),
96+
OSSL_PARAM_construct_end(),
97+
};
98+
99+
if (rand == NULL
100+
|| (ctx = EVP_RAND_CTX_new(rand, NULL)) == NULL
101+
|| !EVP_RAND_CTX_set_params(ctx, params)) {
102+
run_err = 1;
103+
goto err;
104+
}
105+
106+
do {
107+
if (!EVP_RAND_generate(ctx, out, sizeof(out), 0, 0, NULL, 0)) {
108+
run_err = 1;
109+
goto err;
110+
}
111+
112+
count++;
113+
time = ossl_time_now();
114+
} while (time.t < max_time.t);
115+
counts[num] = count;
116+
117+
err:
118+
EVP_RAND_free(rand);
119+
EVP_RAND_CTX_free(ctx);
120+
}
121+
122+
static void print_help(FILE *file)
123+
{
124+
fprintf(file, "Usage: evp_rand [-h] [-t] [-o operation] [-V] thread-count\n");
125+
fprintf(file, "-h - print this help output\n");
126+
fprintf(file, "-t - terse output\n");
127+
fprintf(file, "-o operation - mode of operation. One of [evp_isolated, evp_shared] (default: evp_shared)\n");
128+
fprintf(file, "-V - print version information and exit\n");
129+
fprintf(file, "thread-count - number of threads\n");
130+
}
131+
132+
int main(int argc, char *argv[])
133+
{
134+
OSSL_TIME duration;
135+
size_t total_count = 0;
136+
double av;
137+
int terse = 0, operation = EVP_SHARED;
138+
int j, opt, rc = EXIT_FAILURE;
139+
140+
while ((opt = getopt(argc, argv, "Vhto:")) != -1) {
141+
switch (opt) {
142+
case 't':
143+
terse = 1;
144+
break;
145+
case 'o':
146+
if (strcmp(optarg, "evp_isolated") == 0) {
147+
operation = EVP_ISOLATED;
148+
} else if (strcmp(optarg, "evp_shared") == 0) {
149+
operation = EVP_SHARED;
150+
} else {
151+
fprintf(stderr, "Invalid operation");
152+
print_help(stderr);
153+
goto err;
154+
}
155+
break;
156+
case 'V':
157+
perflib_print_version(basename(argv[0]));
158+
return EXIT_SUCCESS;
159+
case 'h':
160+
print_help(stdout);
161+
return EXIT_SUCCESS;
162+
default:
163+
print_help(stderr);
164+
goto err;
165+
}
166+
}
167+
168+
if (argc - optind != 1) {
169+
fprintf(stderr, "Incorrect number of arguments\n");
170+
print_help(stderr);
171+
goto err;
172+
}
173+
174+
threadcount = atoi(argv[optind]);
175+
if (threadcount < 1) {
176+
fprintf(stderr, "thread-count must be a positive integer\n");
177+
print_help(stderr);
178+
goto err;
179+
}
180+
181+
counts = OPENSSL_zalloc(sizeof(size_t) * threadcount);
182+
if (counts == NULL) {
183+
fprintf(stderr, "Failed to create counts array\n");
184+
goto err;
185+
}
186+
187+
max_time = ossl_time_add(ossl_time_now(), ossl_seconds2time(RUN_TIME));
188+
189+
switch (operation) {
190+
case EVP_SHARED:
191+
run_err = !perflib_run_multi_thread_test(do_evp_shared, threadcount, &duration) || run_err;
192+
break;
193+
case EVP_ISOLATED:
194+
run_err = !perflib_run_multi_thread_test(do_evp_isolated, threadcount, &duration) || run_err;
195+
break;
196+
default:
197+
goto err;
198+
}
199+
200+
if (run_err) {
201+
fprintf(stderr, "Error during test\n");
202+
goto err;
203+
}
204+
205+
for (j = 0; j < threadcount; j++)
206+
total_count += counts[j];
207+
208+
/*
209+
* Computation is pretty fast, running in only a few us. But ossl_time2us
210+
* does integer division and so because the average us computed above is
211+
* less than the value of OSSL_TIME_US, we wind up with truncation to zero
212+
* in the math. Instead, manually do the division, casting our values as
213+
* doubles so that we compute the proper time.
214+
*/
215+
av = (double)RUN_TIME * 1e6 * threadcount / total_count;
216+
217+
if (terse)
218+
printf("%lf\n", av);
219+
else
220+
printf("Average time per computation: %lfus\n", av);
221+
222+
rc = EXIT_SUCCESS;
223+
err:
224+
OPENSSL_free(counts);
225+
return rc;
226+
}

0 commit comments

Comments
 (0)