Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F22948030
bench-slope.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
76 KB
Subscribers
None
bench-slope.c
View Options
/* bench-slope.c - for libgcrypt
* Copyright (C) 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
*
* This file is part of Libgcrypt.
*
* Libgcrypt is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include
<config.h>
#endif
#include
<stdio.h>
#include
<stdlib.h>
#include
<stdarg.h>
#include
<string.h>
#include
<assert.h>
#include
<float.h>
#include
<time.h>
#ifdef _WIN32
#include
<windows.h>
#endif
#ifdef _GCRYPT_IN_LIBGCRYPT
# include "../src/gcrypt-int.h"
# include "../compat/libcompat.h"
#else
# include <gcrypt.h>
#endif
#ifndef STR
#define STR(v) #v
#define STR2(v) STR(v)
#endif
#define PGM "bench-slope"
#include
"t-common.h"
static
int
verbose
;
static
int
csv_mode
;
static
int
unaligned_mode
;
static
int
num_measurement_repetitions
;
/* CPU Ghz value provided by user, allows constructing cycles/byte and other
results. */
static
double
cpu_ghz
=
-1
;
/* Attempt to autodetect CPU Ghz. */
static
int
auto_ghz
;
/* Whether we are running as part of the regression test suite. */
static
int
in_regression_test
;
/* The name of the currently printed section. */
static
char
*
current_section_name
;
/* The name of the currently printed algorithm. */
static
char
*
current_algo_name
;
/* The name of the currently printed mode. */
static
char
*
current_mode_name
;
/* Currently used CPU Ghz (either user input or auto-detected. */
static
double
bench_ghz
;
/* Current accuracy of auto-detected CPU Ghz. */
static
double
bench_ghz_diff
;
static
int
in_fips_mode
;
/*************************************** Default parameters for measurements. */
/* Start at small buffer size, to get reasonable timer calibration for fast
* implementations (AES-NI etc). Sixteen selected to support the largest block
* size of current set cipher blocks. */
#define BUF_START_SIZE 16
/* From ~0 to ~4kbytes give comparable results with results from academia
* (SUPERCOP). */
#define BUF_END_SIZE (BUF_START_SIZE + 4096)
/* With 128 byte steps, we get (4096)/64 = 64 data points. */
#define BUF_STEP_SIZE 64
/* Number of repeated measurements at each data point. The median of these
* measurements is selected as data point further analysis. */
#define NUM_MEASUREMENT_REPETITIONS 64
/* Target accuracy for auto-detected CPU Ghz. */
#define AUTO_GHZ_TARGET_DIFF (5e-5)
/**************************************************** High-resolution timers. */
/* This benchmarking module needs needs high resolution timer. */
#undef NO_GET_NSEC_TIME
#if defined(_WIN32)
struct
nsec_time
{
LARGE_INTEGER
perf_count
;
};
static
void
get_nsec_time
(
struct
nsec_time
*
t
)
{
BOOL
ok
;
ok
=
QueryPerformanceCounter
(
&
t
->
perf_count
);
assert
(
ok
);
}
static
double
get_time_nsec_diff
(
struct
nsec_time
*
start
,
struct
nsec_time
*
end
)
{
static
double
nsecs_per_count
=
0.0
;
double
nsecs
;
if
(
nsecs_per_count
==
0.0
)
{
LARGE_INTEGER
perf_freq
;
BOOL
ok
;
/* Get counts per second. */
ok
=
QueryPerformanceFrequency
(
&
perf_freq
);
assert
(
ok
);
nsecs_per_count
=
1.0
/
perf_freq
.
QuadPart
;
nsecs_per_count
*=
1000000.0
*
1000.0
;
/* sec => nsec */
assert
(
nsecs_per_count
>
0.0
);
}
nsecs
=
end
->
perf_count
.
QuadPart
-
start
->
perf_count
.
QuadPart
;
/* counts */
nsecs
*=
nsecs_per_count
;
/* counts * (nsecs / count) => nsecs */
return
nsecs
;
}
#elif defined(HAVE_CLOCK_GETTIME)
struct
nsec_time
{
struct
timespec
ts
;
};
static
void
get_nsec_time
(
struct
nsec_time
*
t
)
{
int
err
;
err
=
clock_gettime
(
CLOCK_REALTIME
,
&
t
->
ts
);
assert
(
err
==
0
);
}
static
double
get_time_nsec_diff
(
struct
nsec_time
*
start
,
struct
nsec_time
*
end
)
{
double
nsecs
;
nsecs
=
end
->
ts
.
tv_sec
-
start
->
ts
.
tv_sec
;
nsecs
*=
1000000.0
*
1000.0
;
/* sec => nsec */
/* This way we don't have to care if tv_nsec unsigned or signed. */
if
(
end
->
ts
.
tv_nsec
>=
start
->
ts
.
tv_nsec
)
nsecs
+=
end
->
ts
.
tv_nsec
-
start
->
ts
.
tv_nsec
;
else
nsecs
-=
start
->
ts
.
tv_nsec
-
end
->
ts
.
tv_nsec
;
return
nsecs
;
}
#elif defined(HAVE_GETTIMEOFDAY)
struct
nsec_time
{
struct
timeval
tv
;
};
static
void
get_nsec_time
(
struct
nsec_time
*
t
)
{
int
err
;
err
=
gettimeofday
(
&
t
->
tv
,
NULL
);
assert
(
err
==
0
);
}
static
double
get_time_nsec_diff
(
struct
nsec_time
*
start
,
struct
nsec_time
*
end
)
{
double
nsecs
;
nsecs
=
end
->
tv
.
tv_sec
-
start
->
tv
.
tv_sec
;
nsecs
*=
1000000
;
/* sec => µsec */
/* This way we don't have to care if tv_usec unsigned or signed. */
if
(
end
->
tv
.
tv_usec
>=
start
->
tv
.
tv_usec
)
nsecs
+=
end
->
tv
.
tv_usec
-
start
->
tv
.
tv_usec
;
else
nsecs
-=
start
->
tv
.
tv_usec
-
end
->
tv
.
tv_usec
;
nsecs
*=
1000
;
/* µsec => nsec */
return
nsecs
;
}
#else
#define NO_GET_NSEC_TIME 1
#endif
/* If no high resolution timer found, provide dummy bench-slope. */
#ifdef NO_GET_NSEC_TIME
int
main
(
void
)
{
/* No nsec timer => SKIP test. */
return
77
;
}
#else
/* !NO_GET_NSEC_TIME */
/********************************************** Slope benchmarking framework. */
struct
bench_obj
{
const
struct
bench_ops
*
ops
;
unsigned
int
num_measure_repetitions
;
unsigned
int
min_bufsize
;
unsigned
int
max_bufsize
;
unsigned
int
step_size
;
void
*
priv
;
void
*
hd
;
};
typedef
int
(
*
const
bench_initialize_t
)
(
struct
bench_obj
*
obj
);
typedef
void
(
*
const
bench_finalize_t
)
(
struct
bench_obj
*
obj
);
typedef
void
(
*
const
bench_do_run_t
)
(
struct
bench_obj
*
obj
,
void
*
buffer
,
size_t
buflen
);
struct
bench_ops
{
bench_initialize_t
initialize
;
bench_finalize_t
finalize
;
bench_do_run_t
do_run
;
};
static
double
safe_div
(
double
x
,
double
y
)
{
union
{
double
d
;
char
buf
[
sizeof
(
double
)];
}
u_neg_zero
,
u_y
;
if
(
y
!=
0
)
return
x
/
y
;
u_neg_zero
.
d
=
-0.0
;
u_y
.
d
=
y
;
if
(
memcmp
(
u_neg_zero
.
buf
,
u_y
.
buf
,
sizeof
(
double
))
==
0
)
return
-
DBL_MAX
;
return
DBL_MAX
;
}
static
double
get_slope
(
double
(
*
const
get_x
)
(
unsigned
int
idx
,
void
*
priv
),
void
*
get_x_priv
,
double
y_points
[],
unsigned
int
npoints
,
double
*
overhead
)
{
double
sumx
,
sumy
,
sumx2
,
sumy2
,
sumxy
;
unsigned
int
i
;
double
b
,
a
;
sumx
=
sumy
=
sumx2
=
sumy2
=
sumxy
=
0
;
if
(
npoints
<=
1
)
{
/* No slope with zero or one point. */
return
0
;
}
for
(
i
=
0
;
i
<
npoints
;
i
++
)
{
double
x
,
y
;
x
=
get_x
(
i
,
get_x_priv
);
/* bytes */
y
=
y_points
[
i
];
/* nsecs */
sumx
+=
x
;
sumy
+=
y
;
sumx2
+=
x
*
x
;
/*sumy2 += y * y;*/
sumxy
+=
x
*
y
;
}
b
=
safe_div
(
npoints
*
sumxy
-
sumx
*
sumy
,
npoints
*
sumx2
-
sumx
*
sumx
);
if
(
overhead
)
{
a
=
safe_div
(
sumy
-
b
*
sumx
,
npoints
);
*
overhead
=
a
;
/* nsecs */
}
return
b
;
/* nsecs per byte */
}
double
get_bench_obj_point_x
(
unsigned
int
idx
,
void
*
priv
)
{
struct
bench_obj
*
obj
=
priv
;
return
(
double
)
(
obj
->
min_bufsize
+
(
idx
*
obj
->
step_size
));
}
unsigned
int
get_num_measurements
(
struct
bench_obj
*
obj
)
{
unsigned
int
buf_range
=
obj
->
max_bufsize
-
obj
->
min_bufsize
;
unsigned
int
num
=
buf_range
/
obj
->
step_size
+
1
;
while
(
obj
->
min_bufsize
+
(
num
*
obj
->
step_size
)
>
obj
->
max_bufsize
)
num
--
;
return
num
+
1
;
}
static
int
double_cmp
(
const
void
*
_a
,
const
void
*
_b
)
{
const
double
*
a
,
*
b
;
a
=
_a
;
b
=
_b
;
if
(
*
a
>
*
b
)
return
1
;
if
(
*
a
<
*
b
)
return
-1
;
return
0
;
}
double
do_bench_obj_measurement
(
struct
bench_obj
*
obj
,
void
*
buffer
,
size_t
buflen
,
double
*
measurement_raw
,
unsigned
int
loop_iterations
)
{
const
unsigned
int
num_repetitions
=
obj
->
num_measure_repetitions
;
const
bench_do_run_t
do_run
=
obj
->
ops
->
do_run
;
struct
nsec_time
start
,
end
;
unsigned
int
rep
,
loop
;
double
res
;
if
(
num_repetitions
<
1
||
loop_iterations
<
1
)
return
0.0
;
for
(
rep
=
0
;
rep
<
num_repetitions
;
rep
++
)
{
get_nsec_time
(
&
start
);
for
(
loop
=
0
;
loop
<
loop_iterations
;
loop
++
)
do_run
(
obj
,
buffer
,
buflen
);
get_nsec_time
(
&
end
);
measurement_raw
[
rep
]
=
get_time_nsec_diff
(
&
start
,
&
end
);
}
/* Return median of repeated measurements. */
qsort
(
measurement_raw
,
num_repetitions
,
sizeof
(
measurement_raw
[
0
]),
double_cmp
);
if
(
num_repetitions
%
2
==
1
)
return
measurement_raw
[
num_repetitions
/
2
];
res
=
measurement_raw
[
num_repetitions
/
2
]
+
measurement_raw
[
num_repetitions
/
2
-
1
];
return
res
/
2
;
}
unsigned
int
adjust_loop_iterations_to_timer_accuracy
(
struct
bench_obj
*
obj
,
void
*
buffer
,
double
*
measurement_raw
)
{
const
double
increase_thres
=
3.0
;
double
tmp
,
nsecs
;
unsigned
int
loop_iterations
;
unsigned
int
test_bufsize
;
test_bufsize
=
obj
->
min_bufsize
;
if
(
test_bufsize
==
0
)
test_bufsize
+=
obj
->
step_size
;
loop_iterations
=
0
;
do
{
/* Increase loop iterations until we get other results than zero. */
nsecs
=
do_bench_obj_measurement
(
obj
,
buffer
,
test_bufsize
,
measurement_raw
,
++
loop_iterations
);
}
while
(
nsecs
<
1.0
-
0.1
);
do
{
/* Increase loop iterations until we get reasonable increase for elapsed time. */
tmp
=
do_bench_obj_measurement
(
obj
,
buffer
,
test_bufsize
,
measurement_raw
,
++
loop_iterations
);
}
while
(
tmp
<
nsecs
*
(
increase_thres
-
0.1
));
return
loop_iterations
;
}
/* Benchmark and return linear regression slope in nanoseconds per byte. */
double
slope_benchmark
(
struct
bench_obj
*
obj
)
{
unsigned
int
num_measurements
;
double
*
measurements
=
NULL
;
double
*
measurement_raw
=
NULL
;
double
slope
,
overhead
;
unsigned
int
loop_iterations
,
midx
,
i
;
unsigned
char
*
real_buffer
=
NULL
;
unsigned
char
*
buffer
;
size_t
cur_bufsize
;
int
err
;
err
=
obj
->
ops
->
initialize
(
obj
);
if
(
err
<
0
)
return
-1
;
num_measurements
=
get_num_measurements
(
obj
);
measurements
=
calloc
(
num_measurements
,
sizeof
(
*
measurements
));
if
(
!
measurements
)
goto
err_free
;
measurement_raw
=
calloc
(
obj
->
num_measure_repetitions
,
sizeof
(
*
measurement_raw
));
if
(
!
measurement_raw
)
goto
err_free
;
if
(
num_measurements
<
1
||
obj
->
num_measure_repetitions
<
1
||
obj
->
max_bufsize
<
1
||
obj
->
min_bufsize
>
obj
->
max_bufsize
)
goto
err_free
;
real_buffer
=
malloc
(
obj
->
max_bufsize
+
128
+
unaligned_mode
);
if
(
!
real_buffer
)
goto
err_free
;
/* Get aligned buffer */
buffer
=
real_buffer
;
buffer
+=
128
-
((
uintptr_t
)
real_buffer
&
(
128
-
1
));
if
(
unaligned_mode
)
buffer
+=
unaligned_mode
;
/* Make buffer unaligned */
for
(
i
=
0
;
i
<
obj
->
max_bufsize
;
i
++
)
buffer
[
i
]
=
0x55
^
(
-
i
);
/* Adjust number of loop iterations up to timer accuracy. */
loop_iterations
=
adjust_loop_iterations_to_timer_accuracy
(
obj
,
buffer
,
measurement_raw
);
/* Perform measurements */
for
(
midx
=
0
,
cur_bufsize
=
obj
->
min_bufsize
;
cur_bufsize
<=
obj
->
max_bufsize
;
cur_bufsize
+=
obj
->
step_size
,
midx
++
)
{
measurements
[
midx
]
=
do_bench_obj_measurement
(
obj
,
buffer
,
cur_bufsize
,
measurement_raw
,
loop_iterations
);
measurements
[
midx
]
/=
loop_iterations
;
}
assert
(
midx
==
num_measurements
);
slope
=
get_slope
(
&
get_bench_obj_point_x
,
obj
,
measurements
,
num_measurements
,
&
overhead
);
free
(
measurement_raw
);
free
(
measurements
);
free
(
real_buffer
);
obj
->
ops
->
finalize
(
obj
);
return
slope
;
err_free
:
if
(
measurement_raw
)
free
(
measurement_raw
);
if
(
measurements
)
free
(
measurements
);
if
(
real_buffer
)
free
(
real_buffer
);
obj
->
ops
->
finalize
(
obj
);
return
-1
;
}
/********************************************* CPU frequency auto-detection. */
static
volatile
size_t
vone
=
1
;
static
int
auto_ghz_init
(
struct
bench_obj
*
obj
)
{
obj
->
min_bufsize
=
16
;
obj
->
max_bufsize
=
64
+
obj
->
min_bufsize
;
obj
->
step_size
=
8
;
obj
->
num_measure_repetitions
=
16
;
return
0
;
}
static
void
auto_ghz_free
(
struct
bench_obj
*
obj
)
{
(
void
)
obj
;
}
static
void
auto_ghz_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
size_t
one
=
vone
;
size_t
two
=
one
+
vone
;
(
void
)
obj
;
(
void
)
buf
;
buflen
*=
1024
;
/* Turbo frequency detection benchmark. Without CPU turbo-boost, this
* function will give cycles/iteration result 1024.0 on high-end CPUs.
* With turbo, result will be less and can be used detect turbo-clock. */
/* Auto-ghz operation takes two CPU cycles to perform. Variables are
* generated through volatile object and therefore compiler is unable
* to optimize these operations to immediate values. */
#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
/* Auto-ghz operation takes two CPU cycles to perform. Memory barriers
* are used to prevent compiler from optimizing this loop away. */
#define AUTO_GHZ_OPERATION \
asm volatile ("":"+r"(buflen),"+r"(one),"+r"(two)::"memory"); \
buflen ^= one; \
asm volatile ("":"+r"(buflen),"+r"(one),"+r"(two)::"memory"); \
buflen -= two
#else
/* TODO: Needs alternative way of preventing compiler optimizations.
* Mix of XOR and subtraction appears to do the trick for now. */
#define AUTO_GHZ_OPERATION \
buflen ^= one; \
buflen -= two
#endif
#define AUTO_GHZ_OPERATION_2 \
AUTO_GHZ_OPERATION; \
AUTO_GHZ_OPERATION
#define AUTO_GHZ_OPERATION_4 \
AUTO_GHZ_OPERATION_2; \
AUTO_GHZ_OPERATION_2
#define AUTO_GHZ_OPERATION_8 \
AUTO_GHZ_OPERATION_4; \
AUTO_GHZ_OPERATION_4
#define AUTO_GHZ_OPERATION_16 \
AUTO_GHZ_OPERATION_8; \
AUTO_GHZ_OPERATION_8
#define AUTO_GHZ_OPERATION_32 \
AUTO_GHZ_OPERATION_16; \
AUTO_GHZ_OPERATION_16
#define AUTO_GHZ_OPERATION_64 \
AUTO_GHZ_OPERATION_32; \
AUTO_GHZ_OPERATION_32
#define AUTO_GHZ_OPERATION_128 \
AUTO_GHZ_OPERATION_64; \
AUTO_GHZ_OPERATION_64
do
{
/* 1024 auto-ghz operations per loop, total 2048 instructions. */
AUTO_GHZ_OPERATION_128
;
AUTO_GHZ_OPERATION_128
;
AUTO_GHZ_OPERATION_128
;
AUTO_GHZ_OPERATION_128
;
AUTO_GHZ_OPERATION_128
;
AUTO_GHZ_OPERATION_128
;
AUTO_GHZ_OPERATION_128
;
AUTO_GHZ_OPERATION_128
;
}
while
(
buflen
);
}
static
struct
bench_ops
auto_ghz_detect_ops
=
{
&
auto_ghz_init
,
&
auto_ghz_free
,
&
auto_ghz_bench
};
double
get_auto_ghz
(
void
)
{
struct
bench_obj
obj
=
{
0
};
double
nsecs_per_iteration
;
double
cycles_per_iteration
;
obj
.
ops
=
&
auto_ghz_detect_ops
;
nsecs_per_iteration
=
slope_benchmark
(
&
obj
);
cycles_per_iteration
=
nsecs_per_iteration
*
cpu_ghz
;
/* Adjust CPU Ghz so that cycles per iteration would give '1024.0'. */
return
safe_div
(
cpu_ghz
*
1024
,
cycles_per_iteration
);
}
double
do_slope_benchmark
(
struct
bench_obj
*
obj
)
{
unsigned
int
try_count
=
0
;
double
ret
;
if
(
!
auto_ghz
)
{
/* Perform measurement without autodetection of CPU frequency. */
do
{
ret
=
slope_benchmark
(
obj
);
}
while
(
ret
<=
0
&&
try_count
++
<=
4
);
bench_ghz
=
cpu_ghz
;
bench_ghz_diff
=
0
;
}
else
{
double
target_diff
=
AUTO_GHZ_TARGET_DIFF
;
double
cpu_auto_ghz_before
;
double
cpu_auto_ghz_after
;
double
nsecs_per_iteration
;
double
diff
;
/* Perform measurement with CPU frequency autodetection. */
do
{
/* Repeat measurement until CPU turbo frequency has stabilized. */
if
((
++
try_count
%
4
)
==
0
)
{
/* Too much frequency instability on the system, relax target
* accuracy. */
target_diff
*=
2
;
}
cpu_auto_ghz_before
=
get_auto_ghz
();
nsecs_per_iteration
=
slope_benchmark
(
obj
);
cpu_auto_ghz_after
=
get_auto_ghz
();
diff
=
1.0
-
safe_div
(
cpu_auto_ghz_before
,
cpu_auto_ghz_after
);
diff
=
diff
<
0
?
-
diff
:
diff
;
}
while
((
nsecs_per_iteration
<=
0
||
diff
>
target_diff
)
&&
try_count
<
1000
);
ret
=
nsecs_per_iteration
;
bench_ghz
=
(
cpu_auto_ghz_before
+
cpu_auto_ghz_after
)
/
2
;
bench_ghz_diff
=
diff
;
}
return
ret
;
}
/********************************************************** Printing results. */
static
void
double_to_str
(
char
*
out
,
size_t
outlen
,
double
value
)
{
const
char
*
fmt
;
if
(
value
<
1.0
)
fmt
=
"%.3f"
;
else
if
(
value
<
100.0
)
fmt
=
"%.2f"
;
else
if
(
value
<
1000.0
)
fmt
=
"%.1f"
;
else
fmt
=
"%.0f"
;
snprintf
(
out
,
outlen
,
fmt
,
value
);
}
static
void
bench_print_result_csv
(
double
nsecs_per_byte
)
{
double
cycles_per_byte
,
mbytes_per_sec
;
char
nsecpbyte_buf
[
16
];
char
mbpsec_buf
[
16
];
char
cpbyte_buf
[
16
];
char
mhz_buf
[
16
];
char
mhz_diff_buf
[
32
];
strcpy
(
mhz_diff_buf
,
""
);
*
cpbyte_buf
=
0
;
*
mhz_buf
=
0
;
double_to_str
(
nsecpbyte_buf
,
sizeof
(
nsecpbyte_buf
),
nsecs_per_byte
);
/* If user didn't provide CPU speed, we cannot show cycles/byte results. */
if
(
bench_ghz
>
0.0
)
{
cycles_per_byte
=
nsecs_per_byte
*
bench_ghz
;
double_to_str
(
cpbyte_buf
,
sizeof
(
cpbyte_buf
),
cycles_per_byte
);
double_to_str
(
mhz_buf
,
sizeof
(
mhz_buf
),
bench_ghz
*
1000
);
if
(
auto_ghz
&&
bench_ghz_diff
*
1000
>=
1
)
{
snprintf
(
mhz_diff_buf
,
sizeof
(
mhz_diff_buf
),
",%.0f,Mhz-diff"
,
bench_ghz_diff
*
1000
);
}
}
mbytes_per_sec
=
safe_div
(
1000.0
*
1000.0
*
1000.0
,
nsecs_per_byte
*
1024
*
1024
);
double_to_str
(
mbpsec_buf
,
sizeof
(
mbpsec_buf
),
mbytes_per_sec
);
/* We print two empty fields to allow for future enhancements. */
if
(
auto_ghz
)
{
printf
(
"%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B,%s,Mhz%s
\n
"
,
current_section_name
,
current_algo_name
?
current_algo_name
:
""
,
current_mode_name
?
current_mode_name
:
""
,
nsecpbyte_buf
,
mbpsec_buf
,
cpbyte_buf
,
mhz_buf
,
mhz_diff_buf
);
}
else
{
printf
(
"%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B
\n
"
,
current_section_name
,
current_algo_name
?
current_algo_name
:
""
,
current_mode_name
?
current_mode_name
:
""
,
nsecpbyte_buf
,
mbpsec_buf
,
cpbyte_buf
);
}
}
static
void
bench_print_result_std
(
double
nsecs_per_byte
)
{
double
cycles_per_byte
,
mbytes_per_sec
;
char
nsecpbyte_buf
[
16
];
char
mbpsec_buf
[
16
];
char
cpbyte_buf
[
16
];
char
mhz_buf
[
16
];
char
mhz_diff_buf
[
32
];
strcpy
(
mhz_diff_buf
,
""
);
double_to_str
(
nsecpbyte_buf
,
sizeof
(
nsecpbyte_buf
),
nsecs_per_byte
);
/* If user didn't provide CPU speed, we cannot show cycles/byte results. */
if
(
bench_ghz
>
0.0
)
{
cycles_per_byte
=
nsecs_per_byte
*
bench_ghz
;
double_to_str
(
cpbyte_buf
,
sizeof
(
cpbyte_buf
),
cycles_per_byte
);
double_to_str
(
mhz_buf
,
sizeof
(
mhz_buf
),
bench_ghz
*
1000
);
if
(
auto_ghz
&&
bench_ghz_diff
*
1000
>=
0.5
)
{
snprintf
(
mhz_diff_buf
,
sizeof
(
mhz_diff_buf
),
"±%.0f"
,
bench_ghz_diff
*
1000
);
}
}
else
{
strcpy
(
cpbyte_buf
,
"-"
);
strcpy
(
mhz_buf
,
"-"
);
}
mbytes_per_sec
=
safe_div
(
1000.0
*
1000.0
*
1000.0
,
nsecs_per_byte
*
1024
*
1024
);
double_to_str
(
mbpsec_buf
,
sizeof
(
mbpsec_buf
),
mbytes_per_sec
);
if
(
auto_ghz
)
{
printf
(
"%9s ns/B %9s MiB/s %9s c/B %9s%s
\n
"
,
nsecpbyte_buf
,
mbpsec_buf
,
cpbyte_buf
,
mhz_buf
,
mhz_diff_buf
);
}
else
{
printf
(
"%9s ns/B %9s MiB/s %9s c/B
\n
"
,
nsecpbyte_buf
,
mbpsec_buf
,
cpbyte_buf
);
}
}
static
void
bench_print_result
(
double
nsecs_per_byte
)
{
if
(
csv_mode
)
bench_print_result_csv
(
nsecs_per_byte
);
else
bench_print_result_std
(
nsecs_per_byte
);
}
static
void
bench_print_result_nsec_per_iteration
(
double
nsecs_per_iteration
)
{
double
cycles_per_iteration
;
char
nsecpiter_buf
[
16
];
char
cpiter_buf
[
16
];
char
mhz_buf
[
16
];
strcpy
(
cpiter_buf
,
csv_mode
?
""
:
"-"
);
strcpy
(
mhz_buf
,
csv_mode
?
""
:
"-"
);
double_to_str
(
nsecpiter_buf
,
sizeof
(
nsecpiter_buf
),
nsecs_per_iteration
);
/* If user didn't provide CPU speed, we cannot show cycles/iter results. */
if
(
bench_ghz
>
0.0
)
{
cycles_per_iteration
=
nsecs_per_iteration
*
bench_ghz
;
double_to_str
(
cpiter_buf
,
sizeof
(
cpiter_buf
),
cycles_per_iteration
);
double_to_str
(
mhz_buf
,
sizeof
(
mhz_buf
),
bench_ghz
*
1000
);
}
if
(
csv_mode
)
{
if
(
auto_ghz
)
printf
(
"%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter,%s,Mhz
\n
"
,
current_section_name
,
current_algo_name
?
current_algo_name
:
""
,
current_mode_name
?
current_mode_name
:
""
,
nsecpiter_buf
,
cpiter_buf
,
mhz_buf
);
else
printf
(
"%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter
\n
"
,
current_section_name
,
current_algo_name
?
current_algo_name
:
""
,
current_mode_name
?
current_mode_name
:
""
,
nsecpiter_buf
,
cpiter_buf
);
}
else
{
if
(
auto_ghz
)
printf
(
"%14s %13s %9s
\n
"
,
nsecpiter_buf
,
cpiter_buf
,
mhz_buf
);
else
printf
(
"%14s %13s
\n
"
,
nsecpiter_buf
,
cpiter_buf
);
}
}
static
void
bench_print_section
(
const
char
*
section_name
,
const
char
*
print_name
)
{
if
(
csv_mode
)
{
gcry_free
(
current_section_name
);
current_section_name
=
gcry_xstrdup
(
section_name
);
}
else
printf
(
"%s:
\n
"
,
print_name
);
}
static
void
bench_print_header
(
int
algo_width
,
const
char
*
algo_name
)
{
if
(
csv_mode
)
{
gcry_free
(
current_algo_name
);
current_algo_name
=
gcry_xstrdup
(
algo_name
);
}
else
{
if
(
algo_width
<
0
)
printf
(
" %-*s | "
,
-
algo_width
,
algo_name
);
else
printf
(
" %-*s | "
,
algo_width
,
algo_name
);
if
(
auto_ghz
)
printf
(
"%14s %15s %13s %9s
\n
"
,
"nanosecs/byte"
,
"mebibytes/sec"
,
"cycles/byte"
,
"auto Mhz"
);
else
printf
(
"%14s %15s %13s
\n
"
,
"nanosecs/byte"
,
"mebibytes/sec"
,
"cycles/byte"
);
}
}
static
void
bench_print_header_nsec_per_iteration
(
int
algo_width
,
const
char
*
algo_name
)
{
if
(
csv_mode
)
{
gcry_free
(
current_algo_name
);
current_algo_name
=
gcry_xstrdup
(
algo_name
);
}
else
{
if
(
algo_width
<
0
)
printf
(
" %-*s | "
,
-
algo_width
,
algo_name
);
else
printf
(
" %-*s | "
,
algo_width
,
algo_name
);
if
(
auto_ghz
)
printf
(
"%14s %13s %9s
\n
"
,
"nanosecs/iter"
,
"cycles/iter"
,
"auto Mhz"
);
else
printf
(
"%14s %13s
\n
"
,
"nanosecs/iter"
,
"cycles/iter"
);
}
}
static
void
bench_print_algo
(
int
algo_width
,
const
char
*
algo_name
)
{
if
(
csv_mode
)
{
gcry_free
(
current_algo_name
);
current_algo_name
=
gcry_xstrdup
(
algo_name
);
}
else
{
if
(
algo_width
<
0
)
printf
(
" %-*s | "
,
-
algo_width
,
algo_name
);
else
printf
(
" %-*s | "
,
algo_width
,
algo_name
);
}
}
static
void
bench_print_mode
(
int
width
,
const
char
*
mode_name
)
{
if
(
csv_mode
)
{
gcry_free
(
current_mode_name
);
current_mode_name
=
gcry_xstrdup
(
mode_name
);
}
else
{
if
(
width
<
0
)
printf
(
" %-*s | "
,
-
width
,
mode_name
);
else
printf
(
" %*s | "
,
width
,
mode_name
);
fflush
(
stdout
);
}
}
static
void
bench_print_footer
(
int
algo_width
)
{
if
(
!
csv_mode
)
printf
(
" %-*s =
\n
"
,
algo_width
,
""
);
}
/********************************************************* Cipher benchmarks. */
struct
bench_cipher_mode
{
int
mode
;
const
char
*
name
;
struct
bench_ops
*
ops
;
int
algo
;
};
static
void
bench_set_cipher_key
(
gcry_cipher_hd_t
hd
,
int
keylen
)
{
char
*
key
;
int
err
,
i
;
key
=
malloc
(
keylen
);
if
(
!
key
)
{
fprintf
(
stderr
,
PGM
": couldn't allocate %d bytes
\n
"
,
keylen
);
gcry_cipher_close
(
hd
);
exit
(
1
);
}
for
(
i
=
0
;
i
<
keylen
;
i
++
)
key
[
i
]
=
0x33
^
(
11
-
i
);
err
=
gcry_cipher_setkey
(
hd
,
key
,
keylen
);
free
(
key
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_setkey failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
int
bench_encrypt_init
(
struct
bench_obj
*
obj
)
{
struct
bench_cipher_mode
*
mode
=
obj
->
priv
;
gcry_cipher_hd_t
hd
;
int
err
,
keylen
;
obj
->
min_bufsize
=
BUF_START_SIZE
;
obj
->
max_bufsize
=
BUF_END_SIZE
;
obj
->
step_size
=
BUF_STEP_SIZE
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
;
err
=
gcry_cipher_open
(
&
hd
,
mode
->
algo
,
mode
->
mode
,
0
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": error opening cipher `%s'
\n
"
,
gcry_cipher_algo_name
(
mode
->
algo
));
exit
(
1
);
}
keylen
=
gcry_cipher_get_algo_keylen
(
mode
->
algo
);
if
(
mode
->
mode
==
GCRY_CIPHER_MODE_SIV
)
{
keylen
*=
2
;
}
if
(
keylen
)
{
bench_set_cipher_key
(
hd
,
keylen
);
}
else
{
fprintf
(
stderr
,
PGM
": failed to get key length for algorithm `%s'
\n
"
,
gcry_cipher_algo_name
(
mode
->
algo
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
obj
->
hd
=
hd
;
return
0
;
}
static
void
bench_encrypt_free
(
struct
bench_obj
*
obj
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
gcry_cipher_close
(
hd
);
}
static
void
bench_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
err
=
gcry_cipher_reset
(
hd
);
if
(
!
err
)
err
=
gcry_cipher_encrypt
(
hd
,
buf
,
buflen
,
buf
,
buflen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_encrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
void
bench_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
err
=
gcry_cipher_reset
(
hd
);
if
(
!
err
)
err
=
gcry_cipher_decrypt
(
hd
,
buf
,
buflen
,
buf
,
buflen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_encrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
struct
bench_ops
encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_encrypt_do_bench
};
static
struct
bench_ops
decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_decrypt_do_bench
};
static
int
bench_xts_encrypt_init
(
struct
bench_obj
*
obj
)
{
struct
bench_cipher_mode
*
mode
=
obj
->
priv
;
gcry_cipher_hd_t
hd
;
int
err
,
keylen
;
obj
->
min_bufsize
=
BUF_START_SIZE
;
obj
->
max_bufsize
=
BUF_END_SIZE
;
obj
->
step_size
=
BUF_STEP_SIZE
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
;
err
=
gcry_cipher_open
(
&
hd
,
mode
->
algo
,
mode
->
mode
,
0
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": error opening cipher `%s'
\n
"
,
gcry_cipher_algo_name
(
mode
->
algo
));
exit
(
1
);
}
/* Double key-length for XTS. */
keylen
=
gcry_cipher_get_algo_keylen
(
mode
->
algo
)
*
2
;
if
(
keylen
)
{
bench_set_cipher_key
(
hd
,
keylen
);
}
else
{
fprintf
(
stderr
,
PGM
": failed to get key length for algorithm `%s'
\n
"
,
gcry_cipher_algo_name
(
mode
->
algo
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
obj
->
hd
=
hd
;
return
0
;
}
static
struct
bench_ops
xts_encrypt_ops
=
{
&
bench_xts_encrypt_init
,
&
bench_encrypt_free
,
&
bench_encrypt_do_bench
};
static
struct
bench_ops
xts_decrypt_ops
=
{
&
bench_xts_encrypt_init
,
&
bench_encrypt_free
,
&
bench_decrypt_do_bench
};
static
void
bench_ccm_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
char
tag
[
8
];
char
nonce
[
11
]
=
{
0x80
,
0x01
,
};
u64
params
[
3
];
gcry_cipher_setiv
(
hd
,
nonce
,
sizeof
(
nonce
));
/* Set CCM lengths */
params
[
0
]
=
buflen
;
params
[
1
]
=
0
;
/*aadlen */
params
[
2
]
=
sizeof
(
tag
);
err
=
gcry_cipher_ctl
(
hd
,
GCRYCTL_SET_CCM_LENGTHS
,
params
,
sizeof
(
params
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_ctl failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_encrypt
(
hd
,
buf
,
buflen
,
buf
,
buflen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_encrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_gettag
(
hd
,
tag
,
sizeof
(
tag
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_gettag failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
void
bench_ccm_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
char
tag
[
8
]
=
{
0
,
};
char
nonce
[
11
]
=
{
0x80
,
0x01
,
};
u64
params
[
3
];
gcry_cipher_setiv
(
hd
,
nonce
,
sizeof
(
nonce
));
/* Set CCM lengths */
params
[
0
]
=
buflen
;
params
[
1
]
=
0
;
/*aadlen */
params
[
2
]
=
sizeof
(
tag
);
err
=
gcry_cipher_ctl
(
hd
,
GCRYCTL_SET_CCM_LENGTHS
,
params
,
sizeof
(
params
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_ctl failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_decrypt
(
hd
,
buf
,
buflen
,
buf
,
buflen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_encrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_checktag
(
hd
,
tag
,
sizeof
(
tag
));
if
(
gpg_err_code
(
err
)
==
GPG_ERR_CHECKSUM
)
err
=
gpg_error
(
GPG_ERR_NO_ERROR
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_gettag failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
void
bench_ccm_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
char
tag
[
8
]
=
{
0
,
};
char
nonce
[
11
]
=
{
0x80
,
0x01
,
};
u64
params
[
3
];
char
data
=
0xff
;
gcry_cipher_setiv
(
hd
,
nonce
,
sizeof
(
nonce
));
/* Set CCM lengths */
params
[
0
]
=
sizeof
(
data
);
/*datalen */
params
[
1
]
=
buflen
;
/*aadlen */
params
[
2
]
=
sizeof
(
tag
);
err
=
gcry_cipher_ctl
(
hd
,
GCRYCTL_SET_CCM_LENGTHS
,
params
,
sizeof
(
params
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_ctl failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_authenticate
(
hd
,
buf
,
buflen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_authenticate failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_encrypt
(
hd
,
&
data
,
sizeof
(
data
),
&
data
,
sizeof
(
data
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_encrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_gettag
(
hd
,
tag
,
sizeof
(
tag
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_gettag failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
struct
bench_ops
ccm_encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_ccm_encrypt_do_bench
};
static
struct
bench_ops
ccm_decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_ccm_decrypt_do_bench
};
static
struct
bench_ops
ccm_authenticate_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_ccm_authenticate_do_bench
};
static
void
bench_aead_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
,
const
char
*
nonce
,
size_t
noncelen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
char
tag
[
16
];
gcry_cipher_reset
(
hd
);
gcry_cipher_setiv
(
hd
,
nonce
,
noncelen
);
gcry_cipher_final
(
hd
);
err
=
gcry_cipher_encrypt
(
hd
,
buf
,
buflen
,
buf
,
buflen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_encrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_gettag
(
hd
,
tag
,
sizeof
(
tag
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_gettag failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
void
bench_aead_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
,
const
char
*
nonce
,
size_t
noncelen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
char
tag
[
16
]
=
{
0
,
};
gcry_cipher_reset
(
hd
);
gcry_cipher_set_decryption_tag
(
hd
,
tag
,
16
);
gcry_cipher_setiv
(
hd
,
nonce
,
noncelen
);
gcry_cipher_final
(
hd
);
err
=
gcry_cipher_decrypt
(
hd
,
buf
,
buflen
,
buf
,
buflen
);
if
(
gpg_err_code
(
err
)
==
GPG_ERR_CHECKSUM
)
err
=
gpg_error
(
GPG_ERR_NO_ERROR
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_decrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_checktag
(
hd
,
tag
,
sizeof
(
tag
));
if
(
gpg_err_code
(
err
)
==
GPG_ERR_CHECKSUM
)
err
=
gpg_error
(
GPG_ERR_NO_ERROR
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_gettag failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
void
bench_aead_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
,
const
char
*
nonce
,
size_t
noncelen
)
{
gcry_cipher_hd_t
hd
=
obj
->
hd
;
int
err
;
char
tag
[
16
]
=
{
0
,
};
char
data
=
0xff
;
gcry_cipher_reset
(
hd
);
if
(
noncelen
>
0
)
{
err
=
gcry_cipher_setiv
(
hd
,
nonce
,
noncelen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_setiv failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
err
=
gcry_cipher_authenticate
(
hd
,
buf
,
buflen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_authenticate failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
gcry_cipher_final
(
hd
);
err
=
gcry_cipher_encrypt
(
hd
,
&
data
,
sizeof
(
data
),
&
data
,
sizeof
(
data
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_encrypt failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
err
=
gcry_cipher_gettag
(
hd
,
tag
,
sizeof
(
tag
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_cipher_gettag failed: %s
\n
"
,
gpg_strerror
(
err
));
gcry_cipher_close
(
hd
);
exit
(
1
);
}
}
static
void
bench_gcm_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
12
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
};
bench_aead_encrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_gcm_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
12
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
};
bench_aead_decrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_gcm_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
12
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
};
bench_aead_authenticate_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
struct
bench_ops
gcm_encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_gcm_encrypt_do_bench
};
static
struct
bench_ops
gcm_decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_gcm_decrypt_do_bench
};
static
struct
bench_ops
gcm_authenticate_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_gcm_authenticate_do_bench
};
static
void
bench_ocb_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
15
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
,
0x00
,
0x00
,
0x01
};
bench_aead_encrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_ocb_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
15
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
,
0x00
,
0x00
,
0x01
};
bench_aead_decrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_ocb_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
15
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
,
0x00
,
0x00
,
0x01
};
bench_aead_authenticate_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
struct
bench_ops
ocb_encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_ocb_encrypt_do_bench
};
static
struct
bench_ops
ocb_decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_ocb_decrypt_do_bench
};
static
struct
bench_ops
ocb_authenticate_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_ocb_authenticate_do_bench
};
static
void
bench_siv_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
bench_aead_encrypt_do_bench
(
obj
,
buf
,
buflen
,
NULL
,
0
);
}
static
void
bench_siv_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
bench_aead_decrypt_do_bench
(
obj
,
buf
,
buflen
,
NULL
,
0
);
}
static
void
bench_siv_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
bench_aead_authenticate_do_bench
(
obj
,
buf
,
buflen
,
NULL
,
0
);
}
static
struct
bench_ops
siv_encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_siv_encrypt_do_bench
};
static
struct
bench_ops
siv_decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_siv_decrypt_do_bench
};
static
struct
bench_ops
siv_authenticate_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_siv_authenticate_do_bench
};
static
void
bench_gcm_siv_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
12
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
};
bench_aead_encrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_gcm_siv_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
12
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
};
bench_aead_decrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_gcm_siv_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
12
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
};
bench_aead_authenticate_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
struct
bench_ops
gcm_siv_encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_gcm_siv_encrypt_do_bench
};
static
struct
bench_ops
gcm_siv_decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_gcm_siv_decrypt_do_bench
};
static
struct
bench_ops
gcm_siv_authenticate_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_gcm_siv_authenticate_do_bench
};
static
void
bench_eax_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
16
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
,
0x00
,
0x00
,
0x01
,
0x00
};
bench_aead_encrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_eax_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
16
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
,
0x00
,
0x00
,
0x01
,
0x00
};
bench_aead_decrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_eax_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
16
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
,
0xde
,
0xca
,
0xf8
,
0x88
,
0x00
,
0x00
,
0x01
,
0x00
};
bench_aead_authenticate_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
struct
bench_ops
eax_encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_eax_encrypt_do_bench
};
static
struct
bench_ops
eax_decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_eax_decrypt_do_bench
};
static
struct
bench_ops
eax_authenticate_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_eax_authenticate_do_bench
};
static
void
bench_poly1305_encrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
8
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
};
bench_aead_encrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_poly1305_decrypt_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
8
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
};
bench_aead_decrypt_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
void
bench_poly1305_authenticate_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
char
nonce
[
8
]
=
{
0xca
,
0xfe
,
0xba
,
0xbe
,
0xfa
,
0xce
,
0xdb
,
0xad
};
bench_aead_authenticate_do_bench
(
obj
,
buf
,
buflen
,
nonce
,
sizeof
(
nonce
));
}
static
struct
bench_ops
poly1305_encrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_poly1305_encrypt_do_bench
};
static
struct
bench_ops
poly1305_decrypt_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_poly1305_decrypt_do_bench
};
static
struct
bench_ops
poly1305_authenticate_ops
=
{
&
bench_encrypt_init
,
&
bench_encrypt_free
,
&
bench_poly1305_authenticate_do_bench
};
static
struct
bench_cipher_mode
cipher_modes
[]
=
{
{
GCRY_CIPHER_MODE_ECB
,
"ECB enc"
,
&
encrypt_ops
},
{
GCRY_CIPHER_MODE_ECB
,
"ECB dec"
,
&
decrypt_ops
},
{
GCRY_CIPHER_MODE_CBC
,
"CBC enc"
,
&
encrypt_ops
},
{
GCRY_CIPHER_MODE_CBC
,
"CBC dec"
,
&
decrypt_ops
},
{
GCRY_CIPHER_MODE_CFB
,
"CFB enc"
,
&
encrypt_ops
},
{
GCRY_CIPHER_MODE_CFB
,
"CFB dec"
,
&
decrypt_ops
},
{
GCRY_CIPHER_MODE_OFB
,
"OFB enc"
,
&
encrypt_ops
},
{
GCRY_CIPHER_MODE_OFB
,
"OFB dec"
,
&
decrypt_ops
},
{
GCRY_CIPHER_MODE_CTR
,
"CTR enc"
,
&
encrypt_ops
},
{
GCRY_CIPHER_MODE_CTR
,
"CTR dec"
,
&
decrypt_ops
},
{
GCRY_CIPHER_MODE_XTS
,
"XTS enc"
,
&
xts_encrypt_ops
},
{
GCRY_CIPHER_MODE_XTS
,
"XTS dec"
,
&
xts_decrypt_ops
},
{
GCRY_CIPHER_MODE_CCM
,
"CCM enc"
,
&
ccm_encrypt_ops
},
{
GCRY_CIPHER_MODE_CCM
,
"CCM dec"
,
&
ccm_decrypt_ops
},
{
GCRY_CIPHER_MODE_CCM
,
"CCM auth"
,
&
ccm_authenticate_ops
},
{
GCRY_CIPHER_MODE_EAX
,
"EAX enc"
,
&
eax_encrypt_ops
},
{
GCRY_CIPHER_MODE_EAX
,
"EAX dec"
,
&
eax_decrypt_ops
},
{
GCRY_CIPHER_MODE_EAX
,
"EAX auth"
,
&
eax_authenticate_ops
},
{
GCRY_CIPHER_MODE_GCM
,
"GCM enc"
,
&
gcm_encrypt_ops
},
{
GCRY_CIPHER_MODE_GCM
,
"GCM dec"
,
&
gcm_decrypt_ops
},
{
GCRY_CIPHER_MODE_GCM
,
"GCM auth"
,
&
gcm_authenticate_ops
},
{
GCRY_CIPHER_MODE_OCB
,
"OCB enc"
,
&
ocb_encrypt_ops
},
{
GCRY_CIPHER_MODE_OCB
,
"OCB dec"
,
&
ocb_decrypt_ops
},
{
GCRY_CIPHER_MODE_OCB
,
"OCB auth"
,
&
ocb_authenticate_ops
},
{
GCRY_CIPHER_MODE_SIV
,
"SIV enc"
,
&
siv_encrypt_ops
},
{
GCRY_CIPHER_MODE_SIV
,
"SIV dec"
,
&
siv_decrypt_ops
},
{
GCRY_CIPHER_MODE_SIV
,
"SIV auth"
,
&
siv_authenticate_ops
},
{
GCRY_CIPHER_MODE_GCM_SIV
,
"GCM-SIV enc"
,
&
gcm_siv_encrypt_ops
},
{
GCRY_CIPHER_MODE_GCM_SIV
,
"GCM-SIV dec"
,
&
gcm_siv_decrypt_ops
},
{
GCRY_CIPHER_MODE_GCM_SIV
,
"GCM-SIV auth"
,
&
gcm_siv_authenticate_ops
},
{
GCRY_CIPHER_MODE_POLY1305
,
"POLY1305 enc"
,
&
poly1305_encrypt_ops
},
{
GCRY_CIPHER_MODE_POLY1305
,
"POLY1305 dec"
,
&
poly1305_decrypt_ops
},
{
GCRY_CIPHER_MODE_POLY1305
,
"POLY1305 auth"
,
&
poly1305_authenticate_ops
},
{
0
},
};
static
void
cipher_bench_one
(
int
algo
,
struct
bench_cipher_mode
*
pmode
)
{
struct
bench_cipher_mode
mode
=
*
pmode
;
struct
bench_obj
obj
=
{
0
};
double
result
;
unsigned
int
blklen
;
unsigned
int
keylen
;
mode
.
algo
=
algo
;
/* Check if this mode is ok */
blklen
=
gcry_cipher_get_algo_blklen
(
algo
);
if
(
!
blklen
)
return
;
keylen
=
gcry_cipher_get_algo_keylen
(
algo
);
if
(
!
keylen
)
return
;
/* Stream cipher? Only test with "ECB" and POLY1305. */
if
(
blklen
==
1
&&
(
mode
.
mode
!=
GCRY_CIPHER_MODE_ECB
&&
mode
.
mode
!=
GCRY_CIPHER_MODE_POLY1305
))
return
;
if
(
blklen
==
1
&&
mode
.
mode
==
GCRY_CIPHER_MODE_ECB
)
{
mode
.
mode
=
GCRY_CIPHER_MODE_STREAM
;
mode
.
name
=
mode
.
ops
==
&
encrypt_ops
?
"STREAM enc"
:
"STREAM dec"
;
}
/* Poly1305 has restriction for cipher algorithm */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_POLY1305
&&
algo
!=
GCRY_CIPHER_CHACHA20
)
return
;
/* CCM has restrictions for block-size */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_CCM
&&
blklen
!=
GCRY_CCM_BLOCK_LEN
)
return
;
/* GCM has restrictions for block-size; not allowed in FIPS mode */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_GCM
&&
(
in_fips_mode
||
blklen
!=
GCRY_GCM_BLOCK_LEN
))
return
;
/* XTS has restrictions for block-size */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_XTS
&&
blklen
!=
GCRY_XTS_BLOCK_LEN
)
return
;
/* SIV has restrictions for block-size */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_SIV
&&
blklen
!=
GCRY_SIV_BLOCK_LEN
)
return
;
/* GCM-SIV has restrictions for block-size */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_GCM_SIV
&&
blklen
!=
GCRY_SIV_BLOCK_LEN
)
return
;
/* GCM-SIV has restrictions for key length */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_GCM_SIV
&&
!
(
keylen
==
16
||
keylen
==
32
))
return
;
/* Our OCB implementation has restrictions for block-size. */
if
(
mode
.
mode
==
GCRY_CIPHER_MODE_OCB
&&
blklen
!=
GCRY_OCB_BLOCK_LEN
)
return
;
bench_print_mode
(
14
,
mode
.
name
);
obj
.
ops
=
mode
.
ops
;
obj
.
priv
=
&
mode
;
result
=
do_slope_benchmark
(
&
obj
);
bench_print_result
(
result
);
}
static
void
_cipher_bench
(
int
algo
)
{
const
char
*
algoname
;
int
i
;
algoname
=
gcry_cipher_algo_name
(
algo
);
bench_print_header
(
14
,
algoname
);
for
(
i
=
0
;
cipher_modes
[
i
].
mode
;
i
++
)
cipher_bench_one
(
algo
,
&
cipher_modes
[
i
]);
bench_print_footer
(
14
);
}
void
cipher_bench
(
char
**
argv
,
int
argc
)
{
int
i
,
algo
;
bench_print_section
(
"cipher"
,
"Cipher"
);
if
(
argv
&&
argc
)
{
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
algo
=
gcry_cipher_map_name
(
argv
[
i
]);
if
(
algo
)
_cipher_bench
(
algo
);
}
}
else
{
for
(
i
=
1
;
i
<
400
;
i
++
)
if
(
!
gcry_cipher_test_algo
(
i
))
_cipher_bench
(
i
);
}
}
/*********************************************************** Hash benchmarks. */
struct
bench_hash_mode
{
const
char
*
name
;
struct
bench_ops
*
ops
;
int
algo
;
};
static
int
bench_hash_init
(
struct
bench_obj
*
obj
)
{
struct
bench_hash_mode
*
mode
=
obj
->
priv
;
gcry_md_hd_t
hd
;
int
err
;
obj
->
min_bufsize
=
BUF_START_SIZE
;
obj
->
max_bufsize
=
BUF_END_SIZE
;
obj
->
step_size
=
BUF_STEP_SIZE
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
;
err
=
gcry_md_open
(
&
hd
,
mode
->
algo
,
0
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": error opening hash `%s'
\n
"
,
gcry_md_algo_name
(
mode
->
algo
));
exit
(
1
);
}
obj
->
hd
=
hd
;
return
0
;
}
static
void
bench_hash_free
(
struct
bench_obj
*
obj
)
{
gcry_md_hd_t
hd
=
obj
->
hd
;
gcry_md_close
(
hd
);
}
static
void
bench_hash_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
gcry_md_hd_t
hd
=
obj
->
hd
;
gcry_md_reset
(
hd
);
gcry_md_write
(
hd
,
buf
,
buflen
);
gcry_md_final
(
hd
);
}
static
struct
bench_ops
hash_ops
=
{
&
bench_hash_init
,
&
bench_hash_free
,
&
bench_hash_do_bench
};
static
struct
bench_hash_mode
hash_modes
[]
=
{
{
""
,
&
hash_ops
},
{
0
},
};
static
void
hash_bench_one
(
int
algo
,
struct
bench_hash_mode
*
pmode
)
{
struct
bench_hash_mode
mode
=
*
pmode
;
struct
bench_obj
obj
=
{
0
};
double
result
;
mode
.
algo
=
algo
;
if
(
mode
.
name
[
0
]
==
'\0'
)
bench_print_algo
(
-14
,
gcry_md_algo_name
(
algo
));
else
bench_print_algo
(
14
,
mode
.
name
);
obj
.
ops
=
mode
.
ops
;
obj
.
priv
=
&
mode
;
result
=
do_slope_benchmark
(
&
obj
);
bench_print_result
(
result
);
}
static
void
_hash_bench
(
int
algo
)
{
int
i
;
for
(
i
=
0
;
hash_modes
[
i
].
name
;
i
++
)
hash_bench_one
(
algo
,
&
hash_modes
[
i
]);
}
void
hash_bench
(
char
**
argv
,
int
argc
)
{
int
i
,
algo
;
bench_print_section
(
"hash"
,
"Hash"
);
bench_print_header
(
14
,
""
);
if
(
argv
&&
argc
)
{
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
algo
=
gcry_md_map_name
(
argv
[
i
]);
if
(
algo
)
_hash_bench
(
algo
);
}
}
else
{
for
(
i
=
1
;
i
<
400
;
i
++
)
if
(
i
==
GCRY_MD_CSHAKE128
||
i
==
GCRY_MD_CSHAKE256
)
;
/* Skip the bench. */
else
if
(
!
gcry_md_test_algo
(
i
))
_hash_bench
(
i
);
}
bench_print_footer
(
14
);
}
/************************************************************ MAC benchmarks. */
struct
bench_mac_mode
{
const
char
*
name
;
struct
bench_ops
*
ops
;
int
algo
;
};
static
int
bench_mac_init
(
struct
bench_obj
*
obj
)
{
struct
bench_mac_mode
*
mode
=
obj
->
priv
;
gcry_mac_hd_t
hd
;
int
err
;
unsigned
int
keylen
;
void
*
key
;
obj
->
min_bufsize
=
BUF_START_SIZE
;
obj
->
max_bufsize
=
BUF_END_SIZE
;
obj
->
step_size
=
BUF_STEP_SIZE
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
;
keylen
=
gcry_mac_get_algo_keylen
(
mode
->
algo
);
if
(
keylen
==
0
)
keylen
=
32
;
key
=
malloc
(
keylen
);
if
(
!
key
)
{
fprintf
(
stderr
,
PGM
": couldn't allocate %d bytes
\n
"
,
keylen
);
exit
(
1
);
}
memset
(
key
,
42
,
keylen
);
err
=
gcry_mac_open
(
&
hd
,
mode
->
algo
,
0
,
NULL
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": error opening mac `%s'
\n
"
,
gcry_mac_algo_name
(
mode
->
algo
));
free
(
key
);
exit
(
1
);
}
err
=
gcry_mac_setkey
(
hd
,
key
,
keylen
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": error setting key for mac `%s'
\n
"
,
gcry_mac_algo_name
(
mode
->
algo
));
free
(
key
);
exit
(
1
);
}
switch
(
mode
->
algo
)
{
default
:
break
;
case
GCRY_MAC_POLY1305_AES
:
case
GCRY_MAC_POLY1305_CAMELLIA
:
case
GCRY_MAC_POLY1305_TWOFISH
:
case
GCRY_MAC_POLY1305_SERPENT
:
case
GCRY_MAC_POLY1305_SEED
:
case
GCRY_MAC_POLY1305_SM4
:
case
GCRY_MAC_POLY1305_ARIA
:
gcry_mac_setiv
(
hd
,
key
,
16
);
break
;
}
obj
->
hd
=
hd
;
free
(
key
);
return
0
;
}
static
void
bench_mac_free
(
struct
bench_obj
*
obj
)
{
gcry_mac_hd_t
hd
=
obj
->
hd
;
gcry_mac_close
(
hd
);
}
static
void
bench_mac_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
gcry_mac_hd_t
hd
=
obj
->
hd
;
size_t
bs
;
char
b
;
gcry_mac_reset
(
hd
);
gcry_mac_write
(
hd
,
buf
,
buflen
);
bs
=
sizeof
(
b
);
gcry_mac_read
(
hd
,
&
b
,
&
bs
);
}
static
struct
bench_ops
mac_ops
=
{
&
bench_mac_init
,
&
bench_mac_free
,
&
bench_mac_do_bench
};
static
struct
bench_mac_mode
mac_modes
[]
=
{
{
""
,
&
mac_ops
},
{
0
},
};
static
void
mac_bench_one
(
int
algo
,
struct
bench_mac_mode
*
pmode
)
{
struct
bench_mac_mode
mode
=
*
pmode
;
struct
bench_obj
obj
=
{
0
};
double
result
;
mode
.
algo
=
algo
;
if
(
mode
.
name
[
0
]
==
'\0'
)
bench_print_algo
(
-18
,
gcry_mac_algo_name
(
algo
));
else
bench_print_algo
(
18
,
mode
.
name
);
obj
.
ops
=
mode
.
ops
;
obj
.
priv
=
&
mode
;
result
=
do_slope_benchmark
(
&
obj
);
bench_print_result
(
result
);
}
static
void
_mac_bench
(
int
algo
)
{
int
i
;
for
(
i
=
0
;
mac_modes
[
i
].
name
;
i
++
)
mac_bench_one
(
algo
,
&
mac_modes
[
i
]);
}
void
mac_bench
(
char
**
argv
,
int
argc
)
{
int
i
,
algo
;
bench_print_section
(
"mac"
,
"MAC"
);
bench_print_header
(
18
,
""
);
if
(
argv
&&
argc
)
{
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
algo
=
gcry_mac_map_name
(
argv
[
i
]);
if
(
algo
)
_mac_bench
(
algo
);
}
}
else
{
for
(
i
=
1
;
i
<
600
;
i
++
)
if
(
!
gcry_mac_test_algo
(
i
))
_mac_bench
(
i
);
}
bench_print_footer
(
18
);
}
/************************************************************ KDF benchmarks. */
struct
bench_kdf_mode
{
struct
bench_ops
*
ops
;
int
algo
;
int
subalgo
;
};
static
int
bench_kdf_init
(
struct
bench_obj
*
obj
)
{
struct
bench_kdf_mode
*
mode
=
obj
->
priv
;
if
(
mode
->
algo
==
GCRY_KDF_PBKDF2
)
{
int
n
=
in_fips_mode
?
1000
:
2
;
obj
->
min_bufsize
=
n
;
obj
->
max_bufsize
=
n
*
32
;
obj
->
step_size
=
n
;
}
obj
->
num_measure_repetitions
=
num_measurement_repetitions
;
return
0
;
}
static
void
bench_kdf_free
(
struct
bench_obj
*
obj
)
{
(
void
)
obj
;
}
static
void
bench_kdf_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
struct
bench_kdf_mode
*
mode
=
obj
->
priv
;
char
keybuf
[
16
];
(
void
)
buf
;
if
(
mode
->
algo
==
GCRY_KDF_PBKDF2
)
{
gcry_kdf_derive
(
"qwertyuiop"
,
10
,
mode
->
algo
,
mode
->
subalgo
,
"0123456789ABCDEF"
,
16
,
buflen
,
sizeof
(
keybuf
),
keybuf
);
}
}
static
struct
bench_ops
kdf_ops
=
{
&
bench_kdf_init
,
&
bench_kdf_free
,
&
bench_kdf_do_bench
};
static
void
kdf_bench_one
(
int
algo
,
int
subalgo
)
{
struct
bench_kdf_mode
mode
=
{
&
kdf_ops
};
struct
bench_obj
obj
=
{
0
};
double
nsecs_per_iteration
;
char
algo_name
[
32
];
mode
.
algo
=
algo
;
mode
.
subalgo
=
subalgo
;
switch
(
subalgo
)
{
case
GCRY_MD_CRC32
:
case
GCRY_MD_CRC32_RFC1510
:
case
GCRY_MD_CRC24_RFC2440
:
case
GCRY_MD_MD4
:
/* Skip CRC32s. */
return
;
}
if
(
gcry_md_get_algo_dlen
(
subalgo
)
==
0
)
{
/* Skip XOFs */
return
;
}
*
algo_name
=
0
;
if
(
algo
==
GCRY_KDF_PBKDF2
)
{
snprintf
(
algo_name
,
sizeof
(
algo_name
),
"PBKDF2-HMAC-%s"
,
gcry_md_algo_name
(
subalgo
));
}
bench_print_algo
(
-24
,
algo_name
);
obj
.
ops
=
mode
.
ops
;
obj
.
priv
=
&
mode
;
nsecs_per_iteration
=
do_slope_benchmark
(
&
obj
);
bench_print_result_nsec_per_iteration
(
nsecs_per_iteration
);
}
void
kdf_bench
(
char
**
argv
,
int
argc
)
{
char
algo_name
[
32
];
int
i
,
j
;
bench_print_section
(
"kdf"
,
"KDF"
);
bench_print_header_nsec_per_iteration
(
24
,
""
);
if
(
argv
&&
argc
)
{
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
for
(
j
=
1
;
j
<
400
;
j
++
)
{
if
(
i
==
GCRY_MD_CSHAKE128
||
i
==
GCRY_MD_CSHAKE256
)
continue
;
/* Skip the bench. */
if
(
gcry_md_test_algo
(
j
))
continue
;
snprintf
(
algo_name
,
sizeof
(
algo_name
),
"PBKDF2-HMAC-%s"
,
gcry_md_algo_name
(
j
));
if
(
!
strcmp
(
argv
[
i
],
algo_name
))
kdf_bench_one
(
GCRY_KDF_PBKDF2
,
j
);
}
}
}
else
{
for
(
i
=
1
;
i
<
400
;
i
++
)
if
(
i
==
GCRY_MD_CSHAKE128
||
i
==
GCRY_MD_CSHAKE256
)
;
/* Skip the bench. */
else
if
(
!
gcry_md_test_algo
(
i
))
kdf_bench_one
(
GCRY_KDF_PBKDF2
,
i
);
}
bench_print_footer
(
24
);
}
/************************************************************ ECC benchmarks. */
#if USE_ECC
enum
bench_ecc_algo
{
ECC_ALGO_ED25519
=
0
,
ECC_ALGO_ED448
,
ECC_ALGO_X25519
,
ECC_ALGO_X448
,
ECC_ALGO_NIST_P192
,
ECC_ALGO_NIST_P224
,
ECC_ALGO_NIST_P256
,
ECC_ALGO_NIST_P384
,
ECC_ALGO_NIST_P521
,
ECC_ALGO_SECP256K1
,
ECC_ALGO_BRAINP256R1
,
__MAX_ECC_ALGO
};
enum
bench_ecc_operation
{
ECC_OPER_MULT
=
0
,
ECC_OPER_KEYGEN
,
ECC_OPER_SIGN
,
ECC_OPER_VERIFY
,
__MAX_ECC_OPER
};
struct
bench_ecc_oper
{
enum
bench_ecc_operation
oper
;
const
char
*
name
;
struct
bench_ops
*
ops
;
enum
bench_ecc_algo
algo
;
};
struct
bench_ecc_mult_hd
{
gcry_ctx_t
ec
;
gcry_mpi_t
k
,
x
,
y
;
gcry_mpi_point_t
G
,
Q
;
};
struct
bench_ecc_hd
{
gcry_sexp_t
key_spec
;
gcry_sexp_t
data
;
gcry_sexp_t
pub_key
;
gcry_sexp_t
sec_key
;
gcry_sexp_t
sig
;
};
static
int
ecc_algo_fips_allowed
(
int
algo
)
{
switch
(
algo
)
{
case
ECC_ALGO_NIST_P224
:
case
ECC_ALGO_NIST_P256
:
case
ECC_ALGO_NIST_P384
:
case
ECC_ALGO_NIST_P521
:
case
ECC_ALGO_ED25519
:
case
ECC_ALGO_ED448
:
return
1
;
case
ECC_ALGO_SECP256K1
:
case
ECC_ALGO_BRAINP256R1
:
case
ECC_ALGO_X25519
:
case
ECC_ALGO_X448
:
case
ECC_ALGO_NIST_P192
:
default
:
return
0
;
}
}
static
const
char
*
ecc_algo_name
(
int
algo
)
{
switch
(
algo
)
{
case
ECC_ALGO_ED25519
:
return
"Ed25519"
;
case
ECC_ALGO_ED448
:
return
"Ed448"
;
case
ECC_ALGO_X25519
:
return
"X25519"
;
case
ECC_ALGO_X448
:
return
"X448"
;
case
ECC_ALGO_NIST_P192
:
return
"NIST-P192"
;
case
ECC_ALGO_NIST_P224
:
return
"NIST-P224"
;
case
ECC_ALGO_NIST_P256
:
return
"NIST-P256"
;
case
ECC_ALGO_NIST_P384
:
return
"NIST-P384"
;
case
ECC_ALGO_NIST_P521
:
return
"NIST-P521"
;
case
ECC_ALGO_SECP256K1
:
return
"secp256k1"
;
case
ECC_ALGO_BRAINP256R1
:
return
"brainpoolP256r1"
;
default
:
return
NULL
;
}
}
static
const
char
*
ecc_algo_curve
(
int
algo
)
{
switch
(
algo
)
{
case
ECC_ALGO_ED25519
:
return
"Ed25519"
;
case
ECC_ALGO_ED448
:
return
"Ed448"
;
case
ECC_ALGO_X25519
:
return
"Curve25519"
;
case
ECC_ALGO_X448
:
return
"X448"
;
case
ECC_ALGO_NIST_P192
:
return
"NIST P-192"
;
case
ECC_ALGO_NIST_P224
:
return
"NIST P-224"
;
case
ECC_ALGO_NIST_P256
:
return
"NIST P-256"
;
case
ECC_ALGO_NIST_P384
:
return
"NIST P-384"
;
case
ECC_ALGO_NIST_P521
:
return
"NIST P-521"
;
case
ECC_ALGO_SECP256K1
:
return
"secp256k1"
;
case
ECC_ALGO_BRAINP256R1
:
return
"brainpoolP256r1"
;
default
:
return
NULL
;
}
}
static
int
ecc_nbits
(
int
algo
)
{
switch
(
algo
)
{
case
ECC_ALGO_ED25519
:
return
255
;
case
ECC_ALGO_ED448
:
return
448
;
case
ECC_ALGO_X25519
:
return
255
;
case
ECC_ALGO_X448
:
return
448
;
case
ECC_ALGO_NIST_P192
:
return
192
;
case
ECC_ALGO_NIST_P224
:
return
224
;
case
ECC_ALGO_NIST_P256
:
return
256
;
case
ECC_ALGO_NIST_P384
:
return
384
;
case
ECC_ALGO_NIST_P521
:
return
521
;
case
ECC_ALGO_SECP256K1
:
return
256
;
case
ECC_ALGO_BRAINP256R1
:
return
256
;
default
:
return
0
;
}
}
static
int
ecc_map_name
(
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
__MAX_ECC_ALGO
;
i
++
)
{
if
(
strcmp
(
ecc_algo_name
(
i
),
name
)
==
0
)
{
return
i
;
}
}
return
-1
;
}
static
int
bench_ecc_mult_init
(
struct
bench_obj
*
obj
)
{
struct
bench_ecc_oper
*
oper
=
obj
->
priv
;
struct
bench_ecc_mult_hd
*
hd
;
int
p_size
=
ecc_nbits
(
oper
->
algo
);
gpg_error_t
err
;
gcry_mpi_t
p
;
obj
->
min_bufsize
=
1
;
obj
->
max_bufsize
=
4
;
obj
->
step_size
=
1
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
/
obj
->
max_bufsize
;
while
(
obj
->
num_measure_repetitions
==
0
)
{
if
(
obj
->
max_bufsize
==
2
)
{
obj
->
num_measure_repetitions
=
2
;
}
else
{
obj
->
max_bufsize
--
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
/
obj
->
max_bufsize
;
}
}
hd
=
calloc
(
1
,
sizeof
(
*
hd
));
if
(
!
hd
)
return
-1
;
err
=
gcry_mpi_ec_new
(
&
hd
->
ec
,
NULL
,
ecc_algo_curve
(
oper
->
algo
));
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_mpi_ec_new failed: %s
\n
"
,
gpg_strerror
(
err
));
exit
(
1
);
}
hd
->
G
=
gcry_mpi_ec_get_point
(
"g"
,
hd
->
ec
,
1
);
hd
->
Q
=
gcry_mpi_point_new
(
0
);
hd
->
x
=
gcry_mpi_new
(
0
);
hd
->
y
=
gcry_mpi_new
(
0
);
hd
->
k
=
gcry_mpi_new
(
p_size
);
gcry_mpi_randomize
(
hd
->
k
,
p_size
,
GCRY_WEAK_RANDOM
);
p
=
gcry_mpi_ec_get_mpi
(
"p"
,
hd
->
ec
,
1
);
gcry_mpi_mod
(
hd
->
k
,
hd
->
k
,
p
);
gcry_mpi_release
(
p
);
obj
->
hd
=
hd
;
return
0
;
}
static
void
bench_ecc_mult_free
(
struct
bench_obj
*
obj
)
{
struct
bench_ecc_mult_hd
*
hd
=
obj
->
hd
;
gcry_mpi_release
(
hd
->
k
);
gcry_mpi_release
(
hd
->
y
);
gcry_mpi_release
(
hd
->
x
);
gcry_mpi_point_release
(
hd
->
Q
);
gcry_mpi_point_release
(
hd
->
G
);
gcry_ctx_release
(
hd
->
ec
);
free
(
hd
);
obj
->
hd
=
NULL
;
}
static
void
bench_ecc_mult_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
num_iter
)
{
struct
bench_ecc_oper
*
oper
=
obj
->
priv
;
struct
bench_ecc_mult_hd
*
hd
=
obj
->
hd
;
gcry_mpi_t
y
;
size_t
i
;
(
void
)
buf
;
if
(
oper
->
algo
==
ECC_ALGO_X25519
||
oper
->
algo
==
ECC_ALGO_X448
)
{
y
=
NULL
;
}
else
{
y
=
hd
->
y
;
}
for
(
i
=
0
;
i
<
num_iter
;
i
++
)
{
gcry_mpi_ec_mul
(
hd
->
Q
,
hd
->
k
,
hd
->
G
,
hd
->
ec
);
if
(
gcry_mpi_ec_get_affine
(
hd
->
x
,
y
,
hd
->
Q
,
hd
->
ec
))
{
fprintf
(
stderr
,
PGM
": gcry_mpi_ec_get_affine failed
\n
"
);
exit
(
1
);
}
}
}
static
int
bench_ecc_init
(
struct
bench_obj
*
obj
)
{
struct
bench_ecc_oper
*
oper
=
obj
->
priv
;
struct
bench_ecc_hd
*
hd
;
int
p_size
=
ecc_nbits
(
oper
->
algo
);
gpg_error_t
err
;
gcry_mpi_t
x
;
obj
->
min_bufsize
=
1
;
obj
->
max_bufsize
=
4
;
obj
->
step_size
=
1
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
/
obj
->
max_bufsize
;
while
(
obj
->
num_measure_repetitions
==
0
)
{
if
(
obj
->
max_bufsize
==
2
)
{
obj
->
num_measure_repetitions
=
2
;
}
else
{
obj
->
max_bufsize
--
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
/
obj
->
max_bufsize
;
}
}
hd
=
calloc
(
1
,
sizeof
(
*
hd
));
if
(
!
hd
)
return
-1
;
x
=
gcry_mpi_new
(
p_size
);
gcry_mpi_randomize
(
x
,
p_size
,
GCRY_WEAK_RANDOM
);
switch
(
oper
->
algo
)
{
default
:
gcry_mpi_release
(
x
);
free
(
hd
);
return
-1
;
case
ECC_ALGO_ED25519
:
err
=
gcry_sexp_build
(
&
hd
->
key_spec
,
NULL
,
"(genkey (ecdsa (curve
\"
Ed25519
\"
)"
"(flags eddsa)))"
);
if
(
err
)
break
;
err
=
gcry_sexp_build
(
&
hd
->
data
,
NULL
,
"(data (flags eddsa)(hash-algo sha512)"
" (value %m))"
,
x
);
break
;
case
ECC_ALGO_ED448
:
err
=
gcry_sexp_build
(
&
hd
->
key_spec
,
NULL
,
"(genkey (ecdsa (curve
\"
Ed448
\"
)"
"(flags eddsa)))"
);
if
(
err
)
break
;
err
=
gcry_sexp_build
(
&
hd
->
data
,
NULL
,
"(data (flags eddsa)(hash-algo shake256)"
" (value %m))"
,
x
);
break
;
case
ECC_ALGO_NIST_P192
:
case
ECC_ALGO_NIST_P224
:
case
ECC_ALGO_NIST_P256
:
case
ECC_ALGO_NIST_P384
:
case
ECC_ALGO_NIST_P521
:
err
=
gcry_sexp_build
(
&
hd
->
key_spec
,
NULL
,
"(genkey (ECDSA (nbits %d)))"
,
p_size
);
if
(
err
)
break
;
err
=
gcry_sexp_build
(
&
hd
->
data
,
NULL
,
"(data (flags raw) (value %m))"
,
x
);
break
;
case
ECC_ALGO_BRAINP256R1
:
err
=
gcry_sexp_build
(
&
hd
->
key_spec
,
NULL
,
"(genkey (ECDSA (curve brainpoolP256r1)))"
);
if
(
err
)
break
;
err
=
gcry_sexp_build
(
&
hd
->
data
,
NULL
,
"(data (flags raw) (value %m))"
,
x
);
break
;
}
gcry_mpi_release
(
x
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_sexp_build failed: %s
\n
"
,
gpg_strerror
(
err
));
exit
(
1
);
}
obj
->
hd
=
hd
;
return
0
;
}
static
void
bench_ecc_free
(
struct
bench_obj
*
obj
)
{
struct
bench_ecc_hd
*
hd
=
obj
->
hd
;
gcry_sexp_release
(
hd
->
sig
);
gcry_sexp_release
(
hd
->
pub_key
);
gcry_sexp_release
(
hd
->
sec_key
);
gcry_sexp_release
(
hd
->
data
);
gcry_sexp_release
(
hd
->
key_spec
);
free
(
hd
);
obj
->
hd
=
NULL
;
}
static
void
bench_ecc_keygen
(
struct
bench_ecc_hd
*
hd
)
{
gcry_sexp_t
key_pair
;
gpg_error_t
err
;
err
=
gcry_pk_genkey
(
&
key_pair
,
hd
->
key_spec
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_pk_genkey failed: %s
\n
"
,
gpg_strerror
(
err
));
exit
(
1
);
}
hd
->
pub_key
=
gcry_sexp_find_token
(
key_pair
,
"public-key"
,
0
);
if
(
!
hd
->
pub_key
)
{
fprintf
(
stderr
,
PGM
": public part missing in key
\n
"
);
exit
(
1
);
}
hd
->
sec_key
=
gcry_sexp_find_token
(
key_pair
,
"private-key"
,
0
);
if
(
!
hd
->
sec_key
)
{
fprintf
(
stderr
,
PGM
": private part missing in key
\n
"
);
exit
(
1
);
}
gcry_sexp_release
(
key_pair
);
}
static
void
bench_ecc_keygen_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
num_iter
)
{
struct
bench_ecc_hd
*
hd
=
obj
->
hd
;
size_t
i
;
(
void
)
buf
;
for
(
i
=
0
;
i
<
num_iter
;
i
++
)
{
bench_ecc_keygen
(
hd
);
gcry_sexp_release
(
hd
->
pub_key
);
gcry_sexp_release
(
hd
->
sec_key
);
}
hd
->
pub_key
=
NULL
;
hd
->
sec_key
=
NULL
;
}
static
void
bench_ecc_sign_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
num_iter
)
{
struct
bench_ecc_hd
*
hd
=
obj
->
hd
;
gpg_error_t
err
;
size_t
i
;
(
void
)
buf
;
bench_ecc_keygen
(
hd
);
for
(
i
=
0
;
i
<
num_iter
;
i
++
)
{
err
=
gcry_pk_sign
(
&
hd
->
sig
,
hd
->
data
,
hd
->
sec_key
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_pk_sign failed: %s
\n
"
,
gpg_strerror
(
err
));
exit
(
1
);
}
gcry_sexp_release
(
hd
->
sig
);
}
gcry_sexp_release
(
hd
->
pub_key
);
gcry_sexp_release
(
hd
->
sec_key
);
hd
->
sig
=
NULL
;
hd
->
pub_key
=
NULL
;
hd
->
sec_key
=
NULL
;
}
static
void
bench_ecc_verify_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
num_iter
)
{
struct
bench_ecc_hd
*
hd
=
obj
->
hd
;
gpg_error_t
err
;
int
i
;
(
void
)
buf
;
bench_ecc_keygen
(
hd
);
err
=
gcry_pk_sign
(
&
hd
->
sig
,
hd
->
data
,
hd
->
sec_key
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_pk_sign failed: %s
\n
"
,
gpg_strerror
(
err
));
exit
(
1
);
}
for
(
i
=
0
;
i
<
num_iter
;
i
++
)
{
err
=
gcry_pk_verify
(
hd
->
sig
,
hd
->
data
,
hd
->
pub_key
);
if
(
err
)
{
fprintf
(
stderr
,
PGM
": gcry_pk_verify failed: %s
\n
"
,
gpg_strerror
(
err
));
exit
(
1
);
}
}
gcry_sexp_release
(
hd
->
sig
);
gcry_sexp_release
(
hd
->
pub_key
);
gcry_sexp_release
(
hd
->
sec_key
);
hd
->
sig
=
NULL
;
hd
->
pub_key
=
NULL
;
hd
->
sec_key
=
NULL
;
}
static
struct
bench_ops
ecc_mult_ops
=
{
&
bench_ecc_mult_init
,
&
bench_ecc_mult_free
,
&
bench_ecc_mult_do_bench
};
static
struct
bench_ops
ecc_keygen_ops
=
{
&
bench_ecc_init
,
&
bench_ecc_free
,
&
bench_ecc_keygen_do_bench
};
static
struct
bench_ops
ecc_sign_ops
=
{
&
bench_ecc_init
,
&
bench_ecc_free
,
&
bench_ecc_sign_do_bench
};
static
struct
bench_ops
ecc_verify_ops
=
{
&
bench_ecc_init
,
&
bench_ecc_free
,
&
bench_ecc_verify_do_bench
};
static
struct
bench_ecc_oper
ecc_operations
[]
=
{
{
ECC_OPER_MULT
,
"mult"
,
&
ecc_mult_ops
},
{
ECC_OPER_KEYGEN
,
"keygen"
,
&
ecc_keygen_ops
},
{
ECC_OPER_SIGN
,
"sign"
,
&
ecc_sign_ops
},
{
ECC_OPER_VERIFY
,
"verify"
,
&
ecc_verify_ops
},
{
0
,
NULL
,
NULL
}
};
static
void
cipher_ecc_one
(
enum
bench_ecc_algo
algo
,
struct
bench_ecc_oper
*
poper
)
{
struct
bench_ecc_oper
oper
=
*
poper
;
struct
bench_obj
obj
=
{
0
};
double
result
;
if
((
algo
==
ECC_ALGO_X25519
||
algo
==
ECC_ALGO_X448
||
algo
==
ECC_ALGO_SECP256K1
)
&&
oper
.
oper
!=
ECC_OPER_MULT
)
return
;
oper
.
algo
=
algo
;
bench_print_mode
(
14
,
oper
.
name
);
obj
.
ops
=
oper
.
ops
;
obj
.
priv
=
&
oper
;
result
=
do_slope_benchmark
(
&
obj
);
bench_print_result_nsec_per_iteration
(
result
);
}
static
void
_ecc_bench
(
int
algo
)
{
const
char
*
algo_name
;
int
i
;
/* Skip not allowed mechanisms */
if
(
in_fips_mode
&&
!
ecc_algo_fips_allowed
(
algo
))
return
;
algo_name
=
ecc_algo_name
(
algo
);
bench_print_header_nsec_per_iteration
(
14
,
algo_name
);
for
(
i
=
0
;
ecc_operations
[
i
].
name
;
i
++
)
cipher_ecc_one
(
algo
,
&
ecc_operations
[
i
]);
bench_print_footer
(
14
);
}
#endif
void
ecc_bench
(
char
**
argv
,
int
argc
)
{
#if USE_ECC
int
i
,
algo
;
bench_print_section
(
"ecc"
,
"ECC"
);
if
(
argv
&&
argc
)
{
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
algo
=
ecc_map_name
(
argv
[
i
]);
if
(
algo
>=
0
)
_ecc_bench
(
algo
);
}
}
else
{
for
(
i
=
0
;
i
<
__MAX_ECC_ALGO
;
i
++
)
_ecc_bench
(
i
);
}
#else
(
void
)
argv
;
(
void
)
argc
;
#endif
}
/************************************************************ MPI benchmarks. */
#define MPI_START_SIZE 64
#define MPI_END_SIZE 1024
#define MPI_STEP_SIZE 8
#define MPI_NUM_STEPS (((MPI_END_SIZE - MPI_START_SIZE) / MPI_STEP_SIZE) + 1)
enum
bench_mpi_test
{
MPI_TEST_ADD
=
0
,
MPI_TEST_SUB
,
MPI_TEST_RSHIFT3
,
MPI_TEST_LSHIFT3
,
MPI_TEST_RSHIFT65
,
MPI_TEST_LSHIFT65
,
MPI_TEST_MUL4
,
MPI_TEST_MUL8
,
MPI_TEST_MUL16
,
MPI_TEST_MUL32
,
MPI_TEST_DIV4
,
MPI_TEST_DIV8
,
MPI_TEST_DIV16
,
MPI_TEST_DIV32
,
MPI_TEST_MOD4
,
MPI_TEST_MOD8
,
MPI_TEST_MOD16
,
MPI_TEST_MOD32
,
__MAX_MPI_TEST
};
static
const
char
*
const
mpi_test_names
[]
=
{
"add"
,
"sub"
,
"rshift3"
,
"lshift3"
,
"rshift65"
,
"lshift65"
,
"mul4"
,
"mul8"
,
"mul16"
,
"mul32"
,
"div4"
,
"div8"
,
"div16"
,
"div32"
,
"mod4"
,
"mod8"
,
"mod16"
,
"mod32"
,
NULL
,
};
struct
bench_mpi_mode
{
const
char
*
name
;
struct
bench_ops
*
ops
;
enum
bench_mpi_test
test_id
;
};
struct
bench_mpi_hd
{
gcry_mpi_t
bytes
[
MPI_NUM_STEPS
+
1
];
gcry_mpi_t
y
;
};
static
int
bench_mpi_init
(
struct
bench_obj
*
obj
)
{
struct
bench_mpi_mode
*
mode
=
obj
->
priv
;
struct
bench_mpi_hd
*
hd
;
int
y_bytes
;
int
i
,
j
;
(
void
)
mode
;
obj
->
min_bufsize
=
MPI_START_SIZE
;
obj
->
max_bufsize
=
MPI_END_SIZE
;
obj
->
step_size
=
MPI_STEP_SIZE
;
obj
->
num_measure_repetitions
=
num_measurement_repetitions
;
hd
=
calloc
(
1
,
sizeof
(
*
hd
));
if
(
!
hd
)
return
-1
;
/* Generate input MPIs for benchmark. */
for
(
i
=
MPI_START_SIZE
,
j
=
0
;
j
<
DIM
(
hd
->
bytes
);
i
+=
MPI_STEP_SIZE
,
j
++
)
{
hd
->
bytes
[
j
]
=
gcry_mpi_new
(
i
*
8
);
gcry_mpi_randomize
(
hd
->
bytes
[
j
],
i
*
8
,
GCRY_WEAK_RANDOM
);
gcry_mpi_set_bit
(
hd
->
bytes
[
j
],
i
*
8
-
1
);
}
switch
(
mode
->
test_id
)
{
case
MPI_TEST_MUL4
:
case
MPI_TEST_DIV4
:
case
MPI_TEST_MOD4
:
y_bytes
=
4
;
break
;
case
MPI_TEST_MUL8
:
case
MPI_TEST_DIV8
:
case
MPI_TEST_MOD8
:
y_bytes
=
8
;
break
;
case
MPI_TEST_MUL16
:
case
MPI_TEST_DIV16
:
case
MPI_TEST_MOD16
:
y_bytes
=
16
;
break
;
case
MPI_TEST_MUL32
:
case
MPI_TEST_DIV32
:
case
MPI_TEST_MOD32
:
y_bytes
=
32
;
break
;
default
:
y_bytes
=
0
;
break
;
}
hd
->
y
=
gcry_mpi_new
(
y_bytes
*
8
);
if
(
y_bytes
)
{
gcry_mpi_randomize
(
hd
->
y
,
y_bytes
*
8
,
GCRY_WEAK_RANDOM
);
gcry_mpi_set_bit
(
hd
->
y
,
y_bytes
*
8
-
1
);
}
obj
->
hd
=
hd
;
return
0
;
}
static
void
bench_mpi_free
(
struct
bench_obj
*
obj
)
{
struct
bench_mpi_hd
*
hd
=
obj
->
hd
;
int
i
;
gcry_mpi_release
(
hd
->
y
);
for
(
i
=
DIM
(
hd
->
bytes
)
-
1
;
i
>=
0
;
i
--
)
gcry_mpi_release
(
hd
->
bytes
[
i
]);
free
(
hd
);
}
static
void
bench_mpi_do_bench
(
struct
bench_obj
*
obj
,
void
*
buf
,
size_t
buflen
)
{
struct
bench_mpi_hd
*
hd
=
obj
->
hd
;
struct
bench_mpi_mode
*
mode
=
obj
->
priv
;
int
bytes_idx
=
(
buflen
-
MPI_START_SIZE
)
/
MPI_STEP_SIZE
;
gcry_mpi_t
x
;
(
void
)
buf
;
x
=
gcry_mpi_new
(
2
*
(
MPI_END_SIZE
+
1
)
*
8
);
switch
(
mode
->
test_id
)
{
case
MPI_TEST_ADD
:
gcry_mpi_add
(
x
,
hd
->
bytes
[
bytes_idx
],
hd
->
bytes
[
bytes_idx
]);
break
;
case
MPI_TEST_SUB
:
gcry_mpi_sub
(
x
,
hd
->
bytes
[
bytes_idx
+
1
],
hd
->
bytes
[
bytes_idx
]);
break
;
case
MPI_TEST_RSHIFT3
:
gcry_mpi_rshift
(
x
,
hd
->
bytes
[
bytes_idx
],
3
);
break
;
case
MPI_TEST_LSHIFT3
:
gcry_mpi_lshift
(
x
,
hd
->
bytes
[
bytes_idx
],
3
);
break
;
case
MPI_TEST_RSHIFT65
:
gcry_mpi_rshift
(
x
,
hd
->
bytes
[
bytes_idx
],
65
);
break
;
case
MPI_TEST_LSHIFT65
:
gcry_mpi_lshift
(
x
,
hd
->
bytes
[
bytes_idx
],
65
);
break
;
case
MPI_TEST_MUL4
:
case
MPI_TEST_MUL8
:
case
MPI_TEST_MUL16
:
case
MPI_TEST_MUL32
:
gcry_mpi_mul
(
x
,
hd
->
bytes
[
bytes_idx
],
hd
->
y
);
break
;
case
MPI_TEST_DIV4
:
case
MPI_TEST_DIV8
:
case
MPI_TEST_DIV16
:
case
MPI_TEST_DIV32
:
gcry_mpi_div
(
x
,
NULL
,
hd
->
bytes
[
bytes_idx
],
hd
->
y
,
0
);
break
;
case
MPI_TEST_MOD4
:
case
MPI_TEST_MOD8
:
case
MPI_TEST_MOD16
:
case
MPI_TEST_MOD32
:
gcry_mpi_mod
(
x
,
hd
->
bytes
[
bytes_idx
],
hd
->
y
);
break
;
default
:
break
;
}
gcry_mpi_release
(
x
);
}
static
struct
bench_ops
mpi_ops
=
{
&
bench_mpi_init
,
&
bench_mpi_free
,
&
bench_mpi_do_bench
};
static
struct
bench_mpi_mode
mpi_modes
[]
=
{
{
""
,
&
mpi_ops
},
{
0
},
};
static
void
mpi_bench_one
(
int
test_id
,
struct
bench_mpi_mode
*
pmode
)
{
struct
bench_mpi_mode
mode
=
*
pmode
;
struct
bench_obj
obj
=
{
0
};
double
result
;
mode
.
test_id
=
test_id
;
if
(
mode
.
name
[
0
]
==
'\0'
)
bench_print_algo
(
-18
,
mpi_test_names
[
test_id
]);
else
bench_print_algo
(
18
,
mode
.
name
);
obj
.
ops
=
mode
.
ops
;
obj
.
priv
=
&
mode
;
result
=
do_slope_benchmark
(
&
obj
);
bench_print_result
(
result
);
}
static
void
_mpi_bench
(
int
test_id
)
{
int
i
;
for
(
i
=
0
;
mpi_modes
[
i
].
name
;
i
++
)
mpi_bench_one
(
test_id
,
&
mpi_modes
[
i
]);
}
static
int
mpi_match_test
(
const
char
*
name
)
{
int
i
;
for
(
i
=
0
;
i
<
__MAX_MPI_TEST
;
i
++
)
if
(
strcmp
(
name
,
mpi_test_names
[
i
])
==
0
)
return
i
;
return
-1
;
}
void
mpi_bench
(
char
**
argv
,
int
argc
)
{
int
i
,
test_id
;
bench_print_section
(
"mpi"
,
"MPI"
);
bench_print_header
(
18
,
""
);
if
(
argv
&&
argc
)
{
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
test_id
=
mpi_match_test
(
argv
[
i
]);
if
(
test_id
>=
0
)
_mpi_bench
(
test_id
);
}
}
else
{
for
(
i
=
0
;
i
<
__MAX_MPI_TEST
;
i
++
)
_mpi_bench
(
i
);
}
bench_print_footer
(
18
);
}
/************************************************************** Main program. */
void
print_help
(
void
)
{
static
const
char
*
help_lines
[]
=
{
"usage: bench-slope [options] [hash|mac|cipher|kdf|ecc|mpi [algonames]]"
,
""
,
" options:"
,
" --cpu-mhz <mhz> Set CPU speed for calculating cycles"
,
" per bytes results. Set as
\"
auto
\"
"
,
" for auto-detection of CPU speed."
,
" --disable-hwf <features> Disable hardware acceleration feature(s)"
,
" for benchmarking."
,
" --repetitions <n> Use N repetitions (default "
STR2
(
NUM_MEASUREMENT_REPETITIONS
)
")"
,
" --unaligned Use unaligned input buffers."
,
" --csv Use CSV output format"
,
NULL
};
const
char
**
line
;
for
(
line
=
help_lines
;
*
line
;
line
++
)
fprintf
(
stdout
,
"%s
\n
"
,
*
line
);
}
/* Warm up CPU. */
static
void
warm_up_cpu
(
void
)
{
struct
nsec_time
start
,
end
;
if
(
in_regression_test
)
return
;
get_nsec_time
(
&
start
);
do
{
get_nsec_time
(
&
end
);
}
while
(
get_time_nsec_diff
(
&
start
,
&
end
)
<
1000.0
*
1000.0
*
1000.0
);
}
int
main
(
int
argc
,
char
**
argv
)
{
int
last_argc
=
-1
;
if
(
argc
)
{
argc
--
;
argv
++
;
}
/* We skip this test if we are running under the test suite (no args
and srcdir defined) and GCRYPT_NO_BENCHMARKS is set. */
if
(
!
argc
&&
getenv
(
"srcdir"
)
&&
getenv
(
"GCRYPT_NO_BENCHMARKS"
))
exit
(
77
);
if
(
getenv
(
"GCRYPT_IN_REGRESSION_TEST"
))
{
in_regression_test
=
1
;
num_measurement_repetitions
=
2
;
}
else
num_measurement_repetitions
=
NUM_MEASUREMENT_REPETITIONS
;
while
(
argc
&&
last_argc
!=
argc
)
{
last_argc
=
argc
;
if
(
!
strcmp
(
*
argv
,
"--"
))
{
argc
--
;
argv
++
;
break
;
}
else
if
(
!
strcmp
(
*
argv
,
"--help"
))
{
print_help
();
exit
(
0
);
}
else
if
(
!
strcmp
(
*
argv
,
"--verbose"
))
{
verbose
++
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--debug"
))
{
verbose
+=
2
;
debug
++
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--csv"
))
{
csv_mode
=
1
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--unaligned"
))
{
unaligned_mode
=
1
;
argc
--
;
argv
++
;
}
else
if
(
!
strcmp
(
*
argv
,
"--disable-hwf"
))
{
argc
--
;
argv
++
;
if
(
argc
)
{
if
(
gcry_control
(
GCRYCTL_DISABLE_HWF
,
*
argv
,
NULL
))
fprintf
(
stderr
,
PGM
": unknown hardware feature `%s' - option ignored
\n
"
,
*
argv
);
argc
--
;
argv
++
;
}
}
else
if
(
!
strcmp
(
*
argv
,
"--cpu-mhz"
))
{
argc
--
;
argv
++
;
if
(
argc
)
{
if
(
!
strcmp
(
*
argv
,
"auto"
))
{
auto_ghz
=
1
;
}
else
{
cpu_ghz
=
atof
(
*
argv
);
cpu_ghz
/=
1000
;
/* Mhz => Ghz */
}
argc
--
;
argv
++
;
}
}
else
if
(
!
strcmp
(
*
argv
,
"--repetitions"
))
{
argc
--
;
argv
++
;
if
(
argc
)
{
num_measurement_repetitions
=
atof
(
*
argv
);
if
(
num_measurement_repetitions
<
2
)
{
fprintf
(
stderr
,
PGM
": value for --repetitions too small - using %d
\n
"
,
NUM_MEASUREMENT_REPETITIONS
);
num_measurement_repetitions
=
NUM_MEASUREMENT_REPETITIONS
;
}
argc
--
;
argv
++
;
}
}
}
xgcry_control
((
GCRYCTL_SET_VERBOSITY
,
(
int
)
verbose
));
if
(
!
gcry_check_version
(
GCRYPT_VERSION
))
{
fprintf
(
stderr
,
PGM
": version mismatch; pgm=%s, library=%s
\n
"
,
GCRYPT_VERSION
,
gcry_check_version
(
NULL
));
exit
(
1
);
}
if
(
debug
)
xgcry_control
((
GCRYCTL_SET_DEBUG_FLAGS
,
1u
,
0
));
xgcry_control
((
GCRYCTL_DISABLE_SECMEM
,
0
));
xgcry_control
((
GCRYCTL_INITIALIZATION_FINISHED
,
0
));
xgcry_control
((
GCRYCTL_ENABLE_QUICK_RANDOM
,
0
));
if
(
gcry_fips_mode_active
())
in_fips_mode
=
1
;
if
(
in_regression_test
)
fputs
(
"Note: "
PGM
" running in quick regression test mode.
\n
"
,
stdout
);
if
(
!
argc
)
{
warm_up_cpu
();
hash_bench
(
NULL
,
0
);
mac_bench
(
NULL
,
0
);
cipher_bench
(
NULL
,
0
);
kdf_bench
(
NULL
,
0
);
ecc_bench
(
NULL
,
0
);
mpi_bench
(
NULL
,
0
);
}
else
if
(
!
strcmp
(
*
argv
,
"hash"
))
{
argc
--
;
argv
++
;
warm_up_cpu
();
hash_bench
((
argc
==
0
)
?
NULL
:
argv
,
argc
);
}
else
if
(
!
strcmp
(
*
argv
,
"mac"
))
{
argc
--
;
argv
++
;
warm_up_cpu
();
mac_bench
((
argc
==
0
)
?
NULL
:
argv
,
argc
);
}
else
if
(
!
strcmp
(
*
argv
,
"cipher"
))
{
argc
--
;
argv
++
;
warm_up_cpu
();
cipher_bench
((
argc
==
0
)
?
NULL
:
argv
,
argc
);
}
else
if
(
!
strcmp
(
*
argv
,
"kdf"
))
{
argc
--
;
argv
++
;
warm_up_cpu
();
kdf_bench
((
argc
==
0
)
?
NULL
:
argv
,
argc
);
}
else
if
(
!
strcmp
(
*
argv
,
"ecc"
))
{
argc
--
;
argv
++
;
warm_up_cpu
();
ecc_bench
((
argc
==
0
)
?
NULL
:
argv
,
argc
);
}
else
if
(
!
strcmp
(
*
argv
,
"mpi"
))
{
argc
--
;
argv
++
;
warm_up_cpu
();
mpi_bench
((
argc
==
0
)
?
NULL
:
argv
,
argc
);
}
else
{
fprintf
(
stderr
,
PGM
": unknown argument: %s
\n
"
,
*
argv
);
print_help
();
}
return
0
;
}
#endif
/* !NO_GET_NSEC_TIME */
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 10, 8:51 AM (1 d, 20 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
fc/30/6399efcc3831e11a8d55de1234ad
Attached To
rC libgcrypt
Event Timeline
Log In to Comment