Add a `Sequence` iterator for generating sequential keypairs; fix tests

This commit is contained in:
Andrew Poelstra 2014-09-01 11:13:31 -05:00
parent 204524117c
commit 770ebbafc4
2 changed files with 54 additions and 11 deletions

View File

@ -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<R:Rng>(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())
}
}

View File

@ -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);
});
}
}