Skip to content

Commit 362495b

Browse files
committed
test: remove a ton of rand feature-gating
Sometihng like half the tests in this crate are gated on "rand", most of which are for dumb reasons (we are generating random keys from the thread rng). By adding a non-feature=rand "random key generator" we can enable these tests even without the rand feature. We typically also have a gate on "std", which is needed to get the thread rng, but in some cases this is the *only* reason to have a std gate. So by eliminating the rand requirement we can make tests work in nostd. We do this by implementing a parallel LCG which is obviously not cryptographic but is fine for testing. In the LLM-generated tests in musig2.rs we have some rand feature gates for literally no reason at all :/. My bad. In addition to dramatically increasing nostd test coverage, the new "generate random keys" function also gives us an opportunity to use the new global context API including rerandomization.
1 parent 5fa32b3 commit 362495b

File tree

7 files changed

+176
-131
lines changed

7 files changed

+176
-131
lines changed

src/ecdh.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,9 @@ mod tests {
192192
use crate::Secp256k1;
193193

194194
#[test]
195-
#[cfg(all(feature = "rand", feature = "std"))]
196195
fn ecdh() {
197-
let s = Secp256k1::signing_only();
198-
let (sk1, pk1) = s.generate_keypair(&mut rand::rng());
199-
let (sk2, pk2) = s.generate_keypair(&mut rand::rng());
196+
let (sk1, pk1) = crate::test_random_keypair();
197+
let (sk2, pk2) = crate::test_random_keypair();
200198

201199
let sec1 = SharedSecret::new(&pk2, &sk1);
202200
let sec2 = SharedSecret::new(&pk1, &sk2);

src/ecdsa/recovery.rs

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,17 @@ mod tests {
250250
use crate::{Error, Message, Secp256k1, SecretKey};
251251

252252
#[test]
253-
#[cfg(all(feature = "rand", feature = "std"))]
253+
#[cfg(feature = "std")]
254254
fn capabilities() {
255255
let sign = Secp256k1::signing_only();
256256
let vrfy = Secp256k1::verification_only();
257257
let full = Secp256k1::new();
258258

259-
let msg = crate::random_32_bytes(&mut rand::rng());
259+
let msg = crate::test_random_32_bytes();
260260
let msg = Message::from_digest(msg);
261261

262262
// Try key generation
263-
let (sk, pk) = full.generate_keypair(&mut rand::rng());
263+
let (sk, pk) = crate::test_random_keypair();
264264

265265
// Try signing
266266
assert_eq!(sign.sign_ecdsa_recoverable(msg, &sk), full.sign_ecdsa_recoverable(msg, &sk));
@@ -282,11 +282,10 @@ mod tests {
282282

283283
#[test]
284284
#[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs
285-
#[cfg(all(feature = "rand", feature = "std"))]
285+
#[cfg(feature = "std")]
286286
#[rustfmt::skip]
287287
fn sign() {
288-
let mut s = Secp256k1::new();
289-
s.randomize(&mut rand::rng());
288+
let s = Secp256k1::new();
290289

291290
let sk = SecretKey::from_byte_array(ONE).unwrap();
292291
let msg = Message::from_digest(ONE);
@@ -307,11 +306,10 @@ mod tests {
307306

308307
#[test]
309308
#[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs
310-
#[cfg(all(feature = "rand", feature = "std"))]
309+
#[cfg(feature = "std")]
311310
#[rustfmt::skip]
312311
fn sign_with_noncedata() {
313-
let mut s = Secp256k1::new();
314-
s.randomize(&mut rand::rng());
312+
let s = Secp256k1::new();
315313

316314
let sk = SecretKey::from_byte_array(ONE).unwrap();
317315
let msg = Message::from_digest(ONE);
@@ -332,68 +330,57 @@ mod tests {
332330
}
333331

334332
#[test]
335-
#[cfg(all(feature = "rand", feature = "std"))]
333+
#[cfg(feature = "std")]
336334
fn sign_and_verify_fail() {
337-
let mut s = Secp256k1::new();
338-
s.randomize(&mut rand::rng());
339-
340-
let msg = crate::random_32_bytes(&mut rand::rng());
341-
let msg = Message::from_digest(msg);
335+
let s = Secp256k1::new();
342336

343-
let (sk, pk) = s.generate_keypair(&mut rand::rng());
337+
let msg = Message::from_digest(crate::test_random_32_bytes());
338+
let (sk, pk) = crate::test_random_keypair();
344339

345340
let sigr = s.sign_ecdsa_recoverable(msg, &sk);
346341
let sig = sigr.to_standard();
347342

348-
let msg = crate::random_32_bytes(&mut rand::rng());
349-
let msg = Message::from_digest(msg);
343+
let msg = Message::from_digest(crate::test_random_32_bytes());
350344
assert_eq!(s.verify_ecdsa(&sig, msg, &pk), Err(Error::IncorrectSignature));
351345

352346
let recovered_key = s.recover_ecdsa(msg, &sigr).unwrap();
353347
assert!(recovered_key != pk);
354348
}
355349

356350
#[test]
357-
#[cfg(all(feature = "rand", feature = "std"))]
351+
#[cfg(feature = "std")]
358352
fn sign_with_recovery() {
359-
let mut s = Secp256k1::new();
360-
s.randomize(&mut rand::rng());
361-
362-
let msg = crate::random_32_bytes(&mut rand::rng());
363-
let msg = Message::from_digest(msg);
353+
let s = Secp256k1::new();
364354

365-
let (sk, pk) = s.generate_keypair(&mut rand::rng());
355+
let msg = Message::from_digest(crate::test_random_32_bytes());
356+
let (sk, pk) = crate::test_random_keypair();
366357

367358
let sig = s.sign_ecdsa_recoverable(msg, &sk);
368359

369360
assert_eq!(s.recover_ecdsa(msg, &sig), Ok(pk));
370361
}
371362

372363
#[test]
373-
#[cfg(all(feature = "rand", feature = "std"))]
364+
#[cfg(feature = "std")]
374365
fn sign_with_recovery_and_noncedata() {
375-
let mut s = Secp256k1::new();
376-
s.randomize(&mut rand::rng());
377-
378-
let msg = crate::random_32_bytes(&mut rand::rng());
379-
let msg = Message::from_digest(msg);
366+
let s = Secp256k1::new();
380367

381-
let noncedata = [42u8; 32];
368+
let msg = Message::from_digest(crate::test_random_32_bytes());
369+
let noncedata = crate::test_random_32_bytes();
382370

383-
let (sk, pk) = s.generate_keypair(&mut rand::rng());
371+
let (sk, pk) = crate::test_random_keypair();
384372

385373
let sig = s.sign_ecdsa_recoverable_with_noncedata(msg, &sk, &noncedata);
386374

387375
assert_eq!(s.recover_ecdsa(msg, &sig), Ok(pk));
388376
}
389377

390378
#[test]
391-
#[cfg(all(feature = "rand", feature = "std"))]
379+
#[cfg(feature = "std")]
392380
fn bad_recovery() {
393-
let mut s = Secp256k1::new();
394-
s.randomize(&mut rand::rng());
381+
let s = Secp256k1::new();
395382

396-
let msg = Message::from_digest([0x55; 32]);
383+
let msg = Message::from_digest(crate::test_random_32_bytes());
397384

398385
// Zero is not a valid sig
399386
let sig = RecoverableSignature::from_compact(&[0; 64], RecoveryId::Zero).unwrap();
@@ -454,22 +441,21 @@ mod tests {
454441
}
455442

456443
#[cfg(bench)]
457-
#[cfg(all(feature = "rand", feature = "std"))] // Currently only a single bench that requires "rand" + "std".
444+
#[cfg(feature = "std")] // Currently only a single bench that requires "rand" + "std".
458445
mod benches {
459446
use test::{black_box, Bencher};
460447

461-
use super::{Message, Secp256k1};
448+
use crate::{Message, Secp256k1, SecretKey};
462449

463450
#[bench]
464451
pub fn bench_recover(bh: &mut Bencher) {
465452
let s = Secp256k1::new();
466-
let msg = crate::random_32_bytes(&mut rand::rng());
467-
let msg = Message::from_digest(msg);
468-
let (sk, _) = s.generate_keypair(&mut rand::thread_rng());
469-
let sig = s.sign_ecdsa_recoverable(&msg, &sk);
453+
let msg = Message::from_digest(crate::test_random_32_bytes());
454+
let sk = SecretKey::test_random();
455+
let sig = s.sign_ecdsa_recoverable(msg, &sk);
470456

471457
bh.iter(|| {
472-
let res = s.recover_ecdsa(&msg, &sig).unwrap();
458+
let res = s.recover_ecdsa(msg, &sig).unwrap();
473459
black_box(res);
474460
});
475461
}

src/key.rs

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,22 @@ impl SecretKey {
367367
let kp = self.keypair(secp);
368368
XOnlyPublicKey::from_keypair(&kp)
369369
}
370+
371+
/// Constructor for unit testing.
372+
#[cfg(test)]
373+
#[cfg(all(feature = "rand", feature = "std"))]
374+
pub fn test_random() -> Self { Self::new(&mut rand::rng()) }
375+
376+
/// Constructor for unit testing.
377+
#[cfg(test)]
378+
#[cfg(not(all(feature = "rand", feature = "std")))]
379+
pub fn test_random() -> Self {
380+
loop {
381+
if let Ok(ret) = Self::from_byte_array(crate::test_random_32_bytes()) {
382+
return ret;
383+
}
384+
}
385+
}
370386
}
371387

372388
#[cfg(feature = "serde")]
@@ -1036,6 +1052,16 @@ impl Keypair {
10361052
/// [`zeroize`](https://docs.rs/zeroize) crate.
10371053
#[inline]
10381054
pub fn non_secure_erase(&mut self) { self.0.non_secure_erase(); }
1055+
1056+
/// Constructor for unit testing.
1057+
#[cfg(test)]
1058+
pub fn test_random() -> Self {
1059+
let sk = SecretKey::test_random();
1060+
crate::with_global_context(
1061+
|secp: &Secp256k1<crate::AllPreallocated>| Self::from_secret_key(secp, &sk),
1062+
Some(&sk.secret_bytes()),
1063+
)
1064+
}
10391065
}
10401066

10411067
impl fmt::Debug for Keypair {
@@ -1733,11 +1759,8 @@ mod test {
17331759
}
17341760

17351761
#[test]
1736-
#[cfg(all(feature = "rand", feature = "std"))]
17371762
fn keypair_slice_round_trip() {
1738-
let s = Secp256k1::new();
1739-
1740-
let (sk1, pk1) = s.generate_keypair(&mut rand::rng());
1763+
let (sk1, pk1) = crate::test_random_keypair();
17411764
assert_eq!(SecretKey::from_byte_array(sk1.secret_bytes()), Ok(sk1));
17421765
assert_eq!(PublicKey::from_slice(&pk1.serialize()[..]), Ok(pk1));
17431766
assert_eq!(PublicKey::from_slice(&pk1.serialize_uncompressed()[..]), Ok(pk1));
@@ -2010,15 +2033,15 @@ mod test {
20102033
}
20112034

20122035
#[test]
2013-
#[cfg(all(feature = "rand", feature = "std"))]
2036+
#[cfg(feature = "std")]
20142037
fn tweak_add_arbitrary_data() {
20152038
let s = Secp256k1::new();
20162039

2017-
let (sk, pk) = s.generate_keypair(&mut rand::rng());
2040+
let (sk, pk) = crate::test_random_keypair();
20182041
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
20192042

20202043
// TODO: This would be better tested with a _lot_ of different tweaks.
2021-
let tweak = Scalar::random();
2044+
let tweak = Scalar::test_random();
20222045

20232046
let tweaked_sk = sk.add_tweak(&tweak).unwrap();
20242047
assert_ne!(sk, tweaked_sk); // Make sure we did something.
@@ -2029,11 +2052,11 @@ mod test {
20292052
}
20302053

20312054
#[test]
2032-
#[cfg(all(feature = "rand", feature = "std"))]
2055+
#[cfg(feature = "std")]
20332056
fn tweak_add_zero() {
20342057
let s = Secp256k1::new();
20352058

2036-
let (sk, pk) = s.generate_keypair(&mut rand::rng());
2059+
let (sk, pk) = crate::test_random_keypair();
20372060

20382061
let tweak = Scalar::ZERO;
20392062

@@ -2044,40 +2067,38 @@ mod test {
20442067
}
20452068

20462069
#[test]
2047-
#[cfg(all(feature = "rand", feature = "std"))]
2070+
#[cfg(feature = "std")]
20482071
fn tweak_mul_arbitrary_data() {
20492072
let s = Secp256k1::new();
20502073

2051-
let (sk, pk) = s.generate_keypair(&mut rand::rng());
2074+
let (sk, pk) = crate::test_random_keypair();
20522075
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
20532076

2054-
// TODO: This would be better tested with a _lot_ of different tweaks.
2055-
let tweak = Scalar::random();
2056-
2057-
let tweaked_sk = sk.mul_tweak(&tweak).unwrap();
2058-
assert_ne!(sk, tweaked_sk); // Make sure we did something.
2059-
let tweaked_pk = pk.mul_tweak(&s, &tweak).unwrap();
2060-
assert_ne!(pk, tweaked_pk);
2077+
for _ in 0..10 {
2078+
let tweak = Scalar::test_random();
20612079

2062-
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
2080+
let tweaked_sk = sk.mul_tweak(&tweak).unwrap();
2081+
assert_ne!(sk, tweaked_sk); // Make sure we did something.
2082+
let tweaked_pk = pk.mul_tweak(&s, &tweak).unwrap();
2083+
assert_ne!(pk, tweaked_pk);
2084+
assert_eq!(PublicKey::from_secret_key(&s, &tweaked_sk), tweaked_pk);
2085+
}
20632086
}
20642087

20652088
#[test]
2066-
#[cfg(all(feature = "rand", feature = "std"))]
20672089
fn tweak_mul_zero() {
2068-
let s = Secp256k1::new();
2069-
let (sk, _) = s.generate_keypair(&mut rand::rng());
2090+
let (sk, _) = crate::test_random_keypair();
20702091

20712092
let tweak = Scalar::ZERO;
20722093
assert!(sk.mul_tweak(&tweak).is_err())
20732094
}
20742095

20752096
#[test]
2076-
#[cfg(all(feature = "rand", feature = "std"))]
2097+
#[cfg(feature = "std")]
20772098
fn test_negation() {
20782099
let s = Secp256k1::new();
20792100

2080-
let (sk, pk) = s.generate_keypair(&mut rand::rng());
2101+
let (sk, pk) = crate::test_random_keypair();
20812102

20822103
assert_eq!(PublicKey::from_secret_key(&s, &sk), pk); // Sanity check.
20832104

@@ -2095,7 +2116,7 @@ mod test {
20952116
}
20962117

20972118
#[test]
2098-
#[cfg(all(feature = "rand", feature = "std"))]
2119+
#[cfg(feature = "std")]
20992120
fn pubkey_hash() {
21002121
use std::collections::hash_map::DefaultHasher;
21012122
use std::collections::HashSet;
@@ -2107,11 +2128,10 @@ mod test {
21072128
s.finish()
21082129
}
21092130

2110-
let s = Secp256k1::new();
21112131
let mut set = HashSet::new();
21122132
const COUNT: usize = 1024;
21132133
for _ in 0..COUNT {
2114-
let (_, pk) = s.generate_keypair(&mut rand::rng());
2134+
let (_, pk) = crate::test_random_keypair();
21152135
let hash = hash(&pk);
21162136
assert!(!set.contains(&hash));
21172137
set.insert(hash);
@@ -2178,12 +2198,12 @@ mod test {
21782198
}
21792199

21802200
#[test]
2181-
#[cfg(all(feature = "rand", feature = "std"))]
2201+
#[cfg(feature = "std")]
21822202
fn create_pubkey_combine() {
21832203
let s = Secp256k1::new();
21842204

2185-
let (sk1, pk1) = s.generate_keypair(&mut rand::rng());
2186-
let (sk2, pk2) = s.generate_keypair(&mut rand::rng());
2205+
let (sk1, pk1) = crate::test_random_keypair();
2206+
let (sk2, pk2) = crate::test_random_keypair();
21872207

21882208
let sum1 = pk1.combine(&pk2);
21892209
assert!(sum1.is_ok());
@@ -2288,15 +2308,14 @@ mod test {
22882308
}
22892309

22902310
#[test]
2291-
#[cfg(all(feature = "rand", feature = "std"))]
2311+
#[cfg(feature = "std")]
22922312
fn test_tweak_add_then_tweak_add_check() {
22932313
let s = Secp256k1::new();
22942314

2295-
// TODO: 10 times is arbitrary, we should test this a _lot_ of times.
22962315
for _ in 0..10 {
2297-
let tweak = Scalar::random();
2316+
let tweak = Scalar::test_random();
22982317

2299-
let kp = Keypair::new(&s, &mut rand::rng());
2318+
let kp = Keypair::test_random();
23002319
let (xonly, _) = XOnlyPublicKey::from_keypair(&kp);
23012320

23022321
let tweaked_kp = kp.add_xonly_tweak(&s, &tweak).expect("keypair tweak add failed");
@@ -2548,10 +2567,8 @@ mod test {
25482567
}
25492568

25502569
#[test]
2551-
#[cfg(all(feature = "rand", feature = "std"))]
25522570
fn test_keypair_from_str() {
2553-
let ctx = crate::Secp256k1::new();
2554-
let keypair = Keypair::new(&ctx, &mut rand::rng());
2571+
let keypair = Keypair::test_random();
25552572
let mut buf = [0_u8; constants::SECRET_KEY_SIZE * 2]; // Holds hex digits.
25562573
let s = to_hex(&keypair.secret_key().secret_bytes(), &mut buf).unwrap();
25572574
let parsed_key = Keypair::from_str(s).unwrap();

0 commit comments

Comments
 (0)