Skip to content

Commit e9fccd4

Browse files
Merge #708: Constant-time behaviour test using valgrind memtest.
08fb6c4 Run valgrind_ctime_test in travis (Jonas Nick) 3d23022 Constant-time behaviour test using valgrind memtest. (Gregory Maxwell) Pull request description: Valgrind does bit-level tracking of the "uninitialized" status of memory, property tracks memory which is tainted by any uninitialized memory, and warns if any branch or array access depends on an uninitialized bit. That is exactly the verification we need on secret data to test for constant-time behaviour. All we need to do is tell valgrind our secret key is actually uninitialized memory. This adds a valgrind_ctime_test which is compiled if valgrind is installed: Run it with libtool --mode=execute: $ libtool --mode=execute valgrind ./valgrind_ctime_test ACKs for top commit: sipa: ACK 08fb6c4 real-or-random: ACK 08fb6c4 jonasnick: ACK 08fb6c4 Tree-SHA512: d2eb829fb09f43ad1af70898e0eb9cf3f002c6bc418eca9e3e01a9c2c6e87c092aed23d6b0f311ddccbce1cce5f8ef39162cf9b2e68b83d160bc3d249e881493
2 parents 96d8ccb + 08fb6c4 commit e9fccd4

File tree

5 files changed

+127
-2
lines changed

5 files changed

+127
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ bench_internal
99
tests
1010
exhaustive_tests
1111
gen_context
12+
valgrind_ctime_test
1213
*.exe
1314
*.so
1415
*.a

.travis.yml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ addons:
55
packages:
66
- libgmp-dev
77
- valgrind
8+
- libtool-bin
89
compiler:
910
- clang
1011
- gcc
1112
env:
1213
global:
13-
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no
14+
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no CTIMETEST=yes
1415
matrix:
1516
- SCALAR=32bit RECOVERY=yes
1617
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
@@ -24,7 +25,7 @@ env:
2425
- BIGNUM=no
2526
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
2627
- BIGNUM=no STATICPRECOMPUTATION=no
27-
- BUILD=distcheck
28+
- BUILD=distcheck CTIMETEST=
2829
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
2930
- EXTRAFLAGS=CFLAGS=-O0
3031
- ECMULTGENPRECISION=2
@@ -39,25 +40,37 @@ matrix:
3940
packages:
4041
- gcc-multilib
4142
- libgmp-dev:i386
43+
- valgrind
44+
- libtool-bin
45+
- libc6-dbg:i386
4246
- compiler: clang
4347
env: HOST=i686-linux-gnu
4448
addons:
4549
apt:
4650
packages:
4751
- gcc-multilib
52+
- valgrind
53+
- libtool-bin
54+
- libc6-dbg:i386
4855
- compiler: gcc
4956
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
5057
addons:
5158
apt:
5259
packages:
5360
- gcc-multilib
61+
- valgrind
62+
- libtool-bin
63+
- libc6-dbg:i386
5464
- compiler: gcc
5565
env: HOST=i686-linux-gnu
5666
addons:
5767
apt:
5868
packages:
5969
- gcc-multilib
6070
- libgmp-dev:i386
71+
- valgrind
72+
- libtool-bin
73+
- libc6-dbg:i386
6174
- compiler: gcc
6275
env:
6376
- BIGNUM=no ENDOMORPHISM=yes ASM=x86_64 EXPERIMENTAL=yes ECDH=yes RECOVERY=yes
@@ -81,7 +94,11 @@ script:
8194
travis_wait 30 valgrind --error-exitcode=42 ./tests 16 &&
8295
travis_wait 30 valgrind --error-exitcode=42 ./exhaustive_tests;
8396
fi
97+
- if [ -n "$CTIMETEST" ]; then
98+
libtool --mode=execute valgrind ./valgrind_ctime_test &> valgrind_ctime_test.log;
99+
fi
84100

85101
after_script:
86102
- cat ./tests.log
87103
- cat ./exhaustive_tests.log
104+
- cat ./valgrind_ctime_test.log

Makefile.am

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ if USE_TESTS
9393
noinst_PROGRAMS += tests
9494
tests_SOURCES = src/tests.c
9595
tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
96+
if VALGRIND_ENABLED
97+
tests_CPPFLAGS += -DVALGRIND
98+
noinst_PROGRAMS += valgrind_ctime_test
99+
valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
100+
valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
101+
endif
96102
if !ENABLE_COVERAGE
97103
tests_CPPFLAGS += -DVERIFY
98104
endif

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ echo " scalar = $set_scalar"
556556
echo " ecmult window size = $set_ecmult_window"
557557
echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
558558
echo
559+
echo " valgrind = $enable_valgrind"
559560
echo " CC = $CC"
560561
echo " CFLAGS = $CFLAGS"
561562
echo " CPPFLAGS = $CPPFLAGS"

src/valgrind_ctime_test.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**********************************************************************
2+
* Copyright (c) 2020 Gregory Maxwell *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
#include <valgrind/memcheck.h>
8+
#include "include/secp256k1.h"
9+
#include "util.h"
10+
11+
#if ENABLE_MODULE_ECDH
12+
# include "include/secp256k1_ecdh.h"
13+
#endif
14+
15+
int main(void) {
16+
secp256k1_context* ctx;
17+
secp256k1_ecdsa_signature signature;
18+
secp256k1_pubkey pubkey;
19+
size_t siglen = 74;
20+
size_t outputlen = 33;
21+
int i;
22+
int ret;
23+
unsigned char msg[32];
24+
unsigned char key[32];
25+
unsigned char sig[74];
26+
unsigned char spubkey[33];
27+
28+
if (!RUNNING_ON_VALGRIND) {
29+
fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
30+
fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n");
31+
exit(1);
32+
}
33+
34+
/** In theory, testing with a single secret input should be sufficient:
35+
* If control flow depended on secrets the tool would generate an error.
36+
*/
37+
for (i = 0; i < 32; i++) {
38+
key[i] = i + 65;
39+
}
40+
for (i = 0; i < 32; i++) {
41+
msg[i] = i + 1;
42+
}
43+
44+
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_DECLASSIFY);
45+
46+
/* Test keygen. */
47+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
48+
ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key);
49+
VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(secp256k1_pubkey));
50+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
51+
CHECK(ret);
52+
CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
53+
54+
/* Test signing. */
55+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
56+
ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL);
57+
VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(secp256k1_ecdsa_signature));
58+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
59+
CHECK(ret);
60+
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature));
61+
62+
#if ENABLE_MODULE_ECDH
63+
/* Test ECDH. */
64+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
65+
ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL);
66+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
67+
CHECK(ret == 1);
68+
#endif
69+
70+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
71+
ret = secp256k1_ec_seckey_verify(ctx, key);
72+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
73+
CHECK(ret == 1);
74+
75+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
76+
ret = secp256k1_ec_privkey_negate(ctx, key);
77+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
78+
CHECK(ret == 1);
79+
80+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
81+
VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
82+
ret = secp256k1_ec_privkey_tweak_add(ctx, key, msg);
83+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
84+
CHECK(ret == 1);
85+
86+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
87+
VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
88+
ret = secp256k1_ec_privkey_tweak_mul(ctx, key, msg);
89+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
90+
CHECK(ret == 1);
91+
92+
/* Test context randomisation. Do this last because it leaves the context tainted. */
93+
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
94+
ret = secp256k1_context_randomize(ctx, key);
95+
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
96+
CHECK(ret);
97+
98+
secp256k1_context_destroy(ctx);
99+
return 0;
100+
}

0 commit comments

Comments
 (0)