From 53c356b03b0cdd9b688a7142a88078250eabc5ba Mon Sep 17 00:00:00 2001 From: LLFourn Date: Wed, 12 Jan 2022 17:43:10 +1100 Subject: [PATCH] Use proptest rather than "TEST_SOUNDNESS" --- schnorr_fun/src/adaptor/mod.rs | 79 +++++++++++++++++-------------- schnorr_fun/src/keypair.rs | 2 +- schnorr_fun/src/schnorr.rs | 85 +++++++++++++++++----------------- 3 files changed, 87 insertions(+), 79 deletions(-) diff --git a/schnorr_fun/src/adaptor/mod.rs b/schnorr_fun/src/adaptor/mod.rs index 36cc10bb..ba9893b7 100644 --- a/schnorr_fun/src/adaptor/mod.rs +++ b/schnorr_fun/src/adaptor/mod.rs @@ -271,48 +271,55 @@ where mod test { use super::*; - use crate::nonce::{self, Deterministic}; - use secp256kfun::TEST_SOUNDNESS; + use crate::nonce::{Deterministic, GlobalRng, Synthetic}; + use rand::rngs::ThreadRng; + use secp256kfun::proptest::prelude::*; + use sha2::Sha256; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; - fn test_schnorr(schnorr: Schnorr) { - for _ in 0..TEST_SOUNDNESS { - let signing_keypair = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng())); - let verification_key = signing_keypair.verification_key(); - let decryption_key = Scalar::random(&mut rand::thread_rng()); - let encryption_key = schnorr.encryption_key_for(&decryption_key); - let message = Message::::plain("test", b"give 100 coins to Bob".as_ref()); - - let encrypted_signature = - schnorr.encrypted_sign(&signing_keypair, &encryption_key, message); - - assert!(schnorr.verify_encrypted_signature( - &signing_keypair.verification_key(), - &encryption_key, - message, - &encrypted_signature, - )); + proptest! { + #[test] + fn signing_tests_deterministic(secret_key in any::(), decryption_key in any::()) { + let schnorr = Schnorr::>::default(); + test_it(schnorr, secret_key, decryption_key); + } - let decryption_key = decryption_key.mark::(); - let signature = - schnorr.decrypt_signature(decryption_key.clone(), encrypted_signature.clone()); - assert!(schnorr.verify(&verification_key, message, &signature)); - let rec_decryption_key = schnorr - .recover_decryption_key(&encryption_key, &encrypted_signature, &signature) - .expect("recovery works"); - assert_eq!(rec_decryption_key, decryption_key); + #[test] + fn signing_tests_synthetic(secret_key in any::(), decryption_key in any::()) { + let schnorr = Schnorr::>>::default(); + test_it(schnorr, secret_key, decryption_key); } + } - #[test] - fn sign_plain_message() { - use rand::rngs::ThreadRng; - use sha2::Sha256; - test_schnorr(Schnorr::new(Deterministic::::default())); - test_schnorr(Schnorr::new(nonce::Synthetic::< - Sha256, - nonce::GlobalRng, - >::default())); + fn test_it( + schnorr: Schnorr, + secret_key: Scalar, + decryption_key: Scalar, + ) { + let signing_keypair = schnorr.new_keypair(secret_key); + let verification_key = signing_keypair.verification_key(); + let encryption_key = schnorr.encryption_key_for(&decryption_key); + let message = Message::::plain("test", b"give 100 coins to Bob".as_ref()); + + let encrypted_signature = + schnorr.encrypted_sign(&signing_keypair, &encryption_key, message); + + assert!(schnorr.verify_encrypted_signature( + &signing_keypair.verification_key(), + &encryption_key, + message, + &encrypted_signature, + )); + + let decryption_key = decryption_key.mark::(); + let signature = + schnorr.decrypt_signature(decryption_key.clone(), encrypted_signature.clone()); + assert!(schnorr.verify(&verification_key, message, &signature)); + let rec_decryption_key = schnorr + .recover_decryption_key(&encryption_key, &encrypted_signature, &signature) + .expect("recovery works"); + assert_eq!(rec_decryption_key, decryption_key); } } diff --git a/schnorr_fun/src/keypair.rs b/schnorr_fun/src/keypair.rs index 73037cc1..17435355 100644 --- a/schnorr_fun/src/keypair.rs +++ b/schnorr_fun/src/keypair.rs @@ -15,7 +15,7 @@ use secp256kfun::{marker::*, Point, Scalar, XOnly}; /// ``` /// /// [`Schnorr`]: crate::Schnorr -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct KeyPair { pub(crate) sk: Scalar, pub(crate) pk: XOnly, diff --git a/schnorr_fun/src/schnorr.rs b/schnorr_fun/src/schnorr.rs index 6999978d..ba7a42b0 100644 --- a/schnorr_fun/src/schnorr.rs +++ b/schnorr_fun/src/schnorr.rs @@ -260,15 +260,45 @@ pub mod test { use crate::fun::nonce::Deterministic; use super::*; - use crate::fun::TEST_SOUNDNESS; + use crate::fun::proptest::prelude::*; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; #[test] - fn anticipated_signature_on_should_correspond_to_actual_signature() { - for _ in 0..TEST_SOUNDNESS { + fn deterministic_nonces_for_different_message_kinds() { + use core::str::FromStr; + use sha2::Sha256; + let schnorr = Schnorr::::new(Deterministic::::default()); + let x = + Scalar::from_str("18451f9e08af9530814243e202a4a977130e672079f5c14dcf15bd4dee723072") + .unwrap(); + let keypair = schnorr.new_keypair(x); + assert_ne!( + schnorr.sign(&keypair, Message::::raw(b"foo")).R, + schnorr + .sign(&keypair, Message::::plain("one", b"foo")) + .R + ); + assert_ne!( + schnorr + .sign(&keypair, Message::::plain("one", b"foo")) + .R, + schnorr + .sign(&keypair, Message::::plain("two", b"foo")) + .R + ); + + // make sure deterministic signatures don't change + assert_eq!(schnorr.sign(&keypair, Message::::raw(b"foo")), Signature::::from_str("fe9e5d0319d5d221988d6fd7fe1c4bedd2fb4465f592f1002f461503332a266977bb4a0b00c00d07072c796212cbea0957ebaaa5139143761c45d997ebe36cbe").unwrap()); + assert_eq!(schnorr.sign(&keypair, Message::::plain("one", b"foo")), Signature::::from_str("2fcf6fd140bbc4048e802c62f028e24f6534e0d15d450963265b67eead774d8b4aa7638bec9d70aa60b97e86bc4a60bf43ad2ff58e981ee1bba4f45ce02ff2c0").unwrap()); + } + + proptest! { + + #[test] + fn anticipated_signature_on_should_correspond_to_actual_signature(sk in any::()) { let schnorr = crate::test_instance!(); - let keypair = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng())); + let keypair = schnorr.new_keypair(sk); let msg = Message::::plain( "test", b"Chancellor on brink of second bailout for banks", @@ -286,14 +316,12 @@ pub mod test { "should anticipate the same value as actual signature" ) } - } - #[test] - fn sign_deterministic() { - let schnorr = crate::test_instance!(); - for _ in 0..TEST_SOUNDNESS { - let keypair_1 = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng())); - let keypair_2 = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng())); + #[test] + fn sign_deterministic(s1 in any::(), s2 in any::()) { + let schnorr = crate::test_instance!(); + let keypair_1 = schnorr.new_keypair(s1); + let keypair_2 = schnorr.new_keypair(s2); let msg_atkdwn = Message::::plain("test", b"attack at dawn"); let msg_rtrtnoon = Message::::plain("test", b"retreat at noon"); let signature_1 = schnorr.sign(&keypair_1, msg_atkdwn); @@ -303,37 +331,10 @@ pub mod test { assert!(schnorr.verify(&keypair_1.verification_key(), msg_atkdwn, &signature_1)); assert_eq!(signature_1, signature_2); - assert_ne!(signature_3.R, signature_1.R); - assert_ne!(signature_1.R, signature_4.R); + if keypair_1 != keypair_2 { + assert_ne!(signature_3.R, signature_1.R); + assert_ne!(signature_1.R, signature_4.R); + } } } - - #[test] - fn deterministic_nonces_for_different_message_kinds() { - use core::str::FromStr; - use sha2::Sha256; - let schnorr = Schnorr::::new(Deterministic::::default()); - let x = - Scalar::from_str("18451f9e08af9530814243e202a4a977130e672079f5c14dcf15bd4dee723072") - .unwrap(); - let keypair = schnorr.new_keypair(x); - assert_ne!( - schnorr.sign(&keypair, Message::::raw(b"foo")).R, - schnorr - .sign(&keypair, Message::::plain("one", b"foo")) - .R - ); - assert_ne!( - schnorr - .sign(&keypair, Message::::plain("one", b"foo")) - .R, - schnorr - .sign(&keypair, Message::::plain("two", b"foo")) - .R - ); - - // make sure deterministic signatures don't change - assert_eq!(schnorr.sign(&keypair, Message::::raw(b"foo")), Signature::::from_str("fe9e5d0319d5d221988d6fd7fe1c4bedd2fb4465f592f1002f461503332a266977bb4a0b00c00d07072c796212cbea0957ebaaa5139143761c45d997ebe36cbe").unwrap()); - assert_eq!(schnorr.sign(&keypair, Message::::plain("one", b"foo")), Signature::::from_str("2fcf6fd140bbc4048e802c62f028e24f6534e0d15d450963265b67eead774d8b4aa7638bec9d70aa60b97e86bc4a60bf43ad2ff58e981ee1bba4f45ce02ff2c0").unwrap()); - } }