From 770ebbafc4a01227484ecc8f0dffa502ad156b0a Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 1 Sep 2014 11:13:31 -0500 Subject: [PATCH] Add a `Sequence` iterator for generating sequential keypairs; fix tests --- src/key.rs | 40 +++++++++++++++++++++++++++++++++++++++- src/secp256k1.rs | 25 +++++++++++++++---------- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/key.rs b/src/key.rs index 837182d..911ad63 100644 --- a/src/key.rs +++ b/src/key.rs @@ -32,6 +32,12 @@ impl_array_newtype!(Nonce, u8, constants::NONCE_SIZE) pub struct SecretKey([u8, ..constants::SECRET_KEY_SIZE]); impl_array_newtype!(SecretKey, u8, constants::SECRET_KEY_SIZE) +/// The number 1 encoded as a secret key +pub static ONE: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1]); + /// Public key #[deriving(Clone, PartialEq, Eq, Show)] pub struct PublicKey(PublicKeyData); @@ -76,13 +82,14 @@ impl SecretKey { /// Creates a new random secret key #[inline] pub fn new(rng: &mut R) -> SecretKey { + init(); let mut data = random_32_bytes(rng); unsafe { while ffi::secp256k1_ecdsa_seckey_verify(data.as_ptr()) == 0 { data = random_32_bytes(rng); } } - SecretKey(random_32_bytes(rng)) + SecretKey(data) } /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key @@ -121,6 +128,27 @@ impl SecretKey { } } } + + #[inline] + /// Returns an iterator for the (sk, pk) pairs starting one after this one, + /// and incrementing by one each time + pub fn sequence(&self, compressed: bool) -> Sequence { + Sequence { last_sk: *self, compressed: compressed } + } +} + +/// An iterator of keypairs `(sk + 1, pk*G)`, `(sk + 2, pk*2G)`, ... +pub struct Sequence { + compressed: bool, + last_sk: SecretKey, +} + +impl<'a> Iterator<(SecretKey, PublicKey)> for Sequence { + #[inline] + fn next(&mut self) -> Option<(SecretKey, PublicKey)> { + self.last_sk.add_assign(&ONE).unwrap(); + Some((self.last_sk, PublicKey::from_secret_key(&self.last_sk, self.compressed))) + } } impl PublicKey { @@ -293,6 +321,8 @@ impl fmt::Show for SecretKey { mod test { use std::rand::task_rng; + use test::Bencher; + use super::super::{Secp256k1, InvalidNonce, InvalidPublicKey, InvalidSecretKey}; use super::{Nonce, PublicKey, SecretKey}; @@ -383,6 +413,14 @@ mod test { assert!(pk2.add_exp_assign(&sk1).is_ok()); assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2); } + + #[bench] + pub fn sequence_iterate(bh: &mut Bencher) { + let mut s = Secp256k1::new().unwrap(); + let (sk, _) = s.generate_keypair(true); + let mut iter = sk.sequence(true); + bh.iter(|| iter.next()) + } } diff --git a/src/secp256k1.rs b/src/secp256k1.rs index 00134d0..757d29b 100644 --- a/src/secp256k1.rs +++ b/src/secp256k1.rs @@ -137,6 +137,7 @@ impl Secp256k1 { /// Generates a random keypair. Convenience function for `key::SecretKey::new` /// and `key::PublicKey::from_secret_key`; call those functions directly for /// batch key generation. + #[inline] pub fn generate_keypair(&mut self, compressed: bool) -> (key::SecretKey, key::PublicKey) { let sk = key::SecretKey::new(&mut self.rng); @@ -145,6 +146,7 @@ impl Secp256k1 { /// Generates a random nonce. Convenience function for `key::Nonce::new`; call /// that function directly for batch nonce generation + #[inline] pub fn generate_nonce(&mut self) -> key::Nonce { key::Nonce::new(&mut self.rng) } @@ -205,6 +207,7 @@ impl Secp256k1 { /// Checks that `sig` is a valid ECDSA signature for `msg` using the public /// key `pubkey`. Returns `Ok(true)` on success. + #[inline] pub fn verify(msg: &[u8], sig: &[u8], pk: &key::PublicKey) -> Result<()> { init(); // This is a static function, so we have to init let res = unsafe { @@ -229,7 +232,7 @@ mod tests { use std::rand; use std::rand::Rng; - use test::Bencher; + use test::{Bencher, black_box}; use key::PublicKey; use super::Secp256k1; @@ -237,15 +240,13 @@ mod tests { #[test] fn invalid_pubkey() { - let s = Secp256k1::new().unwrap(); - let mut msg = Vec::from_elem(32, 0u8); let sig = Vec::from_elem(32, 0u8); let pk = PublicKey::new(true); rand::task_rng().fill_bytes(msg.as_mut_slice()); - assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pk), Err(InvalidPublicKey)); + assert_eq!(Secp256k1::verify(msg.as_mut_slice(), sig.as_slice(), &pk), Err(InvalidPublicKey)); } #[test] @@ -259,7 +260,7 @@ mod tests { rand::task_rng().fill_bytes(msg.as_mut_slice()); - assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pk), Err(InvalidSignature)); + assert_eq!(Secp256k1::verify(msg.as_mut_slice(), sig.as_slice(), &pk), Err(InvalidSignature)); } #[test] @@ -272,7 +273,7 @@ mod tests { rand::task_rng().fill_bytes(msg.as_mut_slice()); - assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pk), Err(InvalidSignature)); + assert_eq!(Secp256k1::verify(msg.as_mut_slice(), sig.as_slice(), &pk), Err(InvalidSignature)); } #[test] @@ -300,7 +301,7 @@ mod tests { let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap(); - assert_eq!(s.verify(msg.as_slice(), sig.as_slice(), &pk), Ok(())); + assert_eq!(Secp256k1::verify(msg.as_slice(), sig.as_slice(), &pk), Ok(())); } #[test] @@ -316,7 +317,7 @@ mod tests { let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap(); rand::task_rng().fill_bytes(msg.as_mut_slice()); - assert_eq!(s.verify(msg.as_slice(), sig.as_slice(), &pk), Err(IncorrectSignature)); + assert_eq!(Secp256k1::verify(msg.as_slice(), sig.as_slice(), &pk), Err(IncorrectSignature)); } #[test] @@ -338,7 +339,9 @@ mod tests { pub fn generate_compressed(bh: &mut Bencher) { let mut s = Secp256k1::new().unwrap(); bh.iter( || { - let (_, _) = s.generate_keypair(true); + let (sk, pk) = s.generate_keypair(true); + black_box(sk); + black_box(pk); }); } @@ -346,7 +349,9 @@ mod tests { pub fn generate_uncompressed(bh: &mut Bencher) { let mut s = Secp256k1::new().unwrap(); bh.iter( || { - let (_, _) = s.generate_keypair(false); + let (sk, pk) = s.generate_keypair(false); + black_box(sk); + black_box(pk); }); } }