Skip to content

Commit a310e79

Browse files
Merge bitcoin-core/secp256k1#1052: Use xoshiro256++ instead of RFC6979 for tests
77a1975 Use xoshiro256++ PRNG instead of RFC6979 in tests (Pieter Wuille) 5f2efe6 secp256k1_testrand_int(2**N) -> secp256k1_testrand_bits(N) (Pieter Wuille) Pull request description: Just some easy low-hanging fruit. It's complete overkill to use the RFC6979 RNG for our test randomness. Replace it with a modern non-cryptographic RNG with good properties. It's a few % speedup for me. Given the internal naming of all these functions to be "testrand", I'm not concerned about the risk of someone using this for something that needs actual cryptographic randomness. ACKs for top commit: robot-dreams: ACK 77a1975 real-or-random: utACK 77a1975 Tree-SHA512: 2706f37689e037e84b5df25c98af924c0756e6d59f5f822b23aec5ba381b2d536e0848f134026e2568396427218f1c770f1bb07613d702efb23a84015dc9271d
2 parents 423b6d1 + 77a1975 commit a310e79

File tree

4 files changed

+74
-32
lines changed

4 files changed

+74
-32
lines changed

src/modules/schnorrsig/tests_impl.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void run_nonce_function_bip340_tests(void) {
8787
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0);
8888
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
8989
/* Other algo is fine */
90-
secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, algo, algolen);
90+
secp256k1_testrand_bytes_test(algo, algolen);
9191
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
9292

9393
for (i = 0; i < count; i++) {
@@ -795,18 +795,18 @@ void test_schnorrsig_sign_verify(void) {
795795
/* Flip a few bits in the signature and in the message and check that
796796
* verify and verify_batch (TODO) fail */
797797
size_t sig_idx = secp256k1_testrand_int(N_SIGS);
798-
size_t byte_idx = secp256k1_testrand_int(32);
798+
size_t byte_idx = secp256k1_testrand_bits(5);
799799
unsigned char xorbyte = secp256k1_testrand_int(254)+1;
800800
sig[sig_idx][byte_idx] ^= xorbyte;
801801
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
802802
sig[sig_idx][byte_idx] ^= xorbyte;
803803

804-
byte_idx = secp256k1_testrand_int(32);
804+
byte_idx = secp256k1_testrand_bits(5);
805805
sig[sig_idx][32+byte_idx] ^= xorbyte;
806806
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
807807
sig[sig_idx][32+byte_idx] ^= xorbyte;
808808

809-
byte_idx = secp256k1_testrand_int(32);
809+
byte_idx = secp256k1_testrand_bits(5);
810810
msg[sig_idx][byte_idx] ^= xorbyte;
811811
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
812812
msg[sig_idx][byte_idx] ^= xorbyte;

src/testrand.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717
SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16);
1818

1919
/** Generate a pseudorandom number in the range [0..2**32-1]. */
20-
static uint32_t secp256k1_testrand32(void);
20+
SECP256K1_INLINE static uint32_t secp256k1_testrand32(void);
21+
22+
/** Generate a pseudorandom number in the range [0..2**64-1]. */
23+
SECP256K1_INLINE static uint64_t secp256k1_testrand64(void);
2124

2225
/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or
2326
* more. */
24-
static uint32_t secp256k1_testrand_bits(int bits);
27+
SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits);
2528

2629
/** Generate a pseudorandom number in the range [0..range-1]. */
2730
static uint32_t secp256k1_testrand_int(uint32_t range);

src/testrand_impl.h

+56-17
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,64 @@
1414
#include "testrand.h"
1515
#include "hash.h"
1616

17-
static secp256k1_rfc6979_hmac_sha256 secp256k1_test_rng;
18-
static uint32_t secp256k1_test_rng_precomputed[8];
19-
static int secp256k1_test_rng_precomputed_used = 8;
17+
static uint64_t secp256k1_test_state[4];
2018
static uint64_t secp256k1_test_rng_integer;
2119
static int secp256k1_test_rng_integer_bits_left = 0;
2220

2321
SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16) {
24-
secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16);
22+
static const unsigned char PREFIX[19] = "secp256k1 test init";
23+
unsigned char out32[32];
24+
secp256k1_sha256 hash;
25+
int i;
26+
27+
/* Use SHA256(PREFIX || seed16) as initial state. */
28+
secp256k1_sha256_initialize(&hash);
29+
secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX));
30+
secp256k1_sha256_write(&hash, seed16, 16);
31+
secp256k1_sha256_finalize(&hash, out32);
32+
for (i = 0; i < 4; ++i) {
33+
uint64_t s = 0;
34+
int j;
35+
for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j];
36+
secp256k1_test_state[i] = s;
37+
}
38+
secp256k1_test_rng_integer_bits_left = 0;
2539
}
2640

27-
SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) {
28-
if (secp256k1_test_rng_precomputed_used == 8) {
29-
secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed));
30-
secp256k1_test_rng_precomputed_used = 0;
31-
}
32-
return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++];
41+
SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) {
42+
return (x << k) | (x >> (64 - k));
43+
}
44+
45+
SECP256K1_INLINE static uint64_t secp256k1_testrand64(void) {
46+
/* Test-only Xoshiro256++ RNG. See https://prng.di.unimi.it/ */
47+
const uint64_t result = rotl(secp256k1_test_state[0] + secp256k1_test_state[3], 23) + secp256k1_test_state[0];
48+
const uint64_t t = secp256k1_test_state[1] << 17;
49+
secp256k1_test_state[2] ^= secp256k1_test_state[0];
50+
secp256k1_test_state[3] ^= secp256k1_test_state[1];
51+
secp256k1_test_state[1] ^= secp256k1_test_state[2];
52+
secp256k1_test_state[0] ^= secp256k1_test_state[3];
53+
secp256k1_test_state[2] ^= t;
54+
secp256k1_test_state[3] = rotl(secp256k1_test_state[3], 45);
55+
return result;
3356
}
3457

35-
static uint32_t secp256k1_testrand_bits(int bits) {
36-
uint32_t ret;
58+
SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits) {
59+
uint64_t ret;
3760
if (secp256k1_test_rng_integer_bits_left < bits) {
38-
secp256k1_test_rng_integer |= (((uint64_t)secp256k1_testrand32()) << secp256k1_test_rng_integer_bits_left);
39-
secp256k1_test_rng_integer_bits_left += 32;
61+
secp256k1_test_rng_integer = secp256k1_testrand64();
62+
secp256k1_test_rng_integer_bits_left = 64;
4063
}
4164
ret = secp256k1_test_rng_integer;
4265
secp256k1_test_rng_integer >>= bits;
4366
secp256k1_test_rng_integer_bits_left -= bits;
44-
ret &= ((~((uint32_t)0)) >> (32 - bits));
67+
ret &= ((~((uint64_t)0)) >> (64 - bits));
4568
return ret;
4669
}
4770

71+
SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) {
72+
return secp256k1_testrand_bits(32);
73+
}
74+
4875
static uint32_t secp256k1_testrand_int(uint32_t range) {
4976
/* We want a uniform integer between 0 and range-1, inclusive.
5077
* B is the smallest number such that range <= 2**B.
@@ -85,7 +112,19 @@ static uint32_t secp256k1_testrand_int(uint32_t range) {
85112
}
86113

87114
static void secp256k1_testrand256(unsigned char *b32) {
88-
secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32);
115+
int i;
116+
for (i = 0; i < 4; ++i) {
117+
uint64_t val = secp256k1_testrand64();
118+
b32[0] = val;
119+
b32[1] = val >> 8;
120+
b32[2] = val >> 16;
121+
b32[3] = val >> 24;
122+
b32[4] = val >> 32;
123+
b32[5] = val >> 40;
124+
b32[6] = val >> 48;
125+
b32[7] = val >> 56;
126+
b32 += 8;
127+
}
89128
}
90129

91130
static void secp256k1_testrand_bytes_test(unsigned char *bytes, size_t len) {
@@ -109,7 +148,7 @@ static void secp256k1_testrand256_test(unsigned char *b32) {
109148
}
110149

111150
static void secp256k1_testrand_flip(unsigned char *b, size_t len) {
112-
b[secp256k1_testrand_int(len)] ^= (1 << secp256k1_testrand_int(8));
151+
b[secp256k1_testrand_int(len)] ^= (1 << secp256k1_testrand_bits(3));
113152
}
114153

115154
static void secp256k1_testrand_init(const char* hexseed) {

src/tests.c

+9-9
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ void signed30_to_uint16(uint16_t* out, const secp256k1_modinv32_signed30* in) {
790790
void mutate_sign_signed30(secp256k1_modinv32_signed30* x) {
791791
int i;
792792
for (i = 0; i < 16; ++i) {
793-
int pos = secp256k1_testrand_int(8);
793+
int pos = secp256k1_testrand_bits(3);
794794
if (x->v[pos] > 0 && x->v[pos + 1] <= 0x3fffffff) {
795795
x->v[pos] -= 0x40000000;
796796
x->v[pos + 1] += 1;
@@ -862,7 +862,7 @@ void mutate_sign_signed62(secp256k1_modinv64_signed62* x) {
862862
static const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
863863
int i;
864864
for (i = 0; i < 8; ++i) {
865-
int pos = secp256k1_testrand_int(4);
865+
int pos = secp256k1_testrand_bits(2);
866866
if (x->v[pos] > 0 && x->v[pos + 1] <= M62) {
867867
x->v[pos] -= (M62 + 1);
868868
x->v[pos + 1] += 1;
@@ -4261,7 +4261,7 @@ void test_secp256k1_pippenger_bucket_window_inv(void) {
42614261
* for a given scratch space.
42624262
*/
42634263
void test_ecmult_multi_pippenger_max_points(void) {
4264-
size_t scratch_size = secp256k1_testrand_int(256);
4264+
size_t scratch_size = secp256k1_testrand_bits(8);
42654265
size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12);
42664266
secp256k1_scratch *scratch;
42674267
size_t n_points_supported;
@@ -6023,14 +6023,14 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
60236023
/* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */
60246024
nlow[n] = der ? 1 : (secp256k1_testrand_bits(3) != 0);
60256025
/* The length of the number in bytes (the first byte of which will always be nonzero) */
6026-
nlen[n] = nlow[n] ? secp256k1_testrand_int(33) : 32 + secp256k1_testrand_int(200) * secp256k1_testrand_int(8) / 8;
6026+
nlen[n] = nlow[n] ? secp256k1_testrand_int(33) : 32 + secp256k1_testrand_int(200) * secp256k1_testrand_bits(3) / 8;
60276027
CHECK(nlen[n] <= 232);
60286028
/* The top bit of the number. */
60296029
nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_testrand_bits(1));
60306030
/* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */
60316031
nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_testrand_bits(7) : 1 + secp256k1_testrand_int(127));
60326032
/* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */
6033-
nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_testrand_int(3) : secp256k1_testrand_int(300 - nlen[n]) * secp256k1_testrand_int(8) / 8);
6033+
nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_testrand_int(3) : secp256k1_testrand_int(300 - nlen[n]) * secp256k1_testrand_bits(3) / 8);
60346034
if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) {
60356035
*certainly_not_der = 1;
60366036
}
@@ -6039,7 +6039,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
60396039
nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2);
60406040
if (!der) {
60416041
/* nlenlen[n] max 127 bytes */
6042-
int add = secp256k1_testrand_int(127 - nlenlen[n]) * secp256k1_testrand_int(16) * secp256k1_testrand_int(16) / 256;
6042+
int add = secp256k1_testrand_int(127 - nlenlen[n]) * secp256k1_testrand_bits(4) * secp256k1_testrand_bits(4) / 256;
60436043
nlenlen[n] += add;
60446044
if (add != 0) {
60456045
*certainly_not_der = 1;
@@ -6053,15 +6053,15 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
60536053
CHECK(tlen <= 856);
60546054

60556055
/* The length of the garbage inside the tuple. */
6056-
elen = (der || indet) ? 0 : secp256k1_testrand_int(980 - tlen) * secp256k1_testrand_int(8) / 8;
6056+
elen = (der || indet) ? 0 : secp256k1_testrand_int(980 - tlen) * secp256k1_testrand_bits(3) / 8;
60576057
if (elen != 0) {
60586058
*certainly_not_der = 1;
60596059
}
60606060
tlen += elen;
60616061
CHECK(tlen <= 980);
60626062

60636063
/* The length of the garbage after the end of the tuple. */
6064-
glen = der ? 0 : secp256k1_testrand_int(990 - tlen) * secp256k1_testrand_int(8) / 8;
6064+
glen = der ? 0 : secp256k1_testrand_int(990 - tlen) * secp256k1_testrand_bits(3) / 8;
60656065
if (glen != 0) {
60666066
*certainly_not_der = 1;
60676067
}
@@ -6076,7 +6076,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly
60766076
} else {
60776077
int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2);
60786078
if (!der) {
6079-
int add = secp256k1_testrand_int(127 - tlenlen) * secp256k1_testrand_int(16) * secp256k1_testrand_int(16) / 256;
6079+
int add = secp256k1_testrand_int(127 - tlenlen) * secp256k1_testrand_bits(4) * secp256k1_testrand_bits(4) / 256;
60806080
tlenlen += add;
60816081
if (add != 0) {
60826082
*certainly_not_der = 1;

0 commit comments

Comments
 (0)