Add a `Sequence` iterator for generating sequential keypairs; fix tests
This commit is contained in:
parent
204524117c
commit
770ebbafc4
40
src/key.rs
40
src/key.rs
|
@ -32,6 +32,12 @@ impl_array_newtype!(Nonce, u8, constants::NONCE_SIZE)
|
||||||
pub struct SecretKey([u8, ..constants::SECRET_KEY_SIZE]);
|
pub struct SecretKey([u8, ..constants::SECRET_KEY_SIZE]);
|
||||||
impl_array_newtype!(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
|
/// Public key
|
||||||
#[deriving(Clone, PartialEq, Eq, Show)]
|
#[deriving(Clone, PartialEq, Eq, Show)]
|
||||||
pub struct PublicKey(PublicKeyData);
|
pub struct PublicKey(PublicKeyData);
|
||||||
|
@ -76,13 +82,14 @@ impl SecretKey {
|
||||||
/// Creates a new random secret key
|
/// Creates a new random secret key
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<R:Rng>(rng: &mut R) -> SecretKey {
|
pub fn new<R:Rng>(rng: &mut R) -> SecretKey {
|
||||||
|
init();
|
||||||
let mut data = random_32_bytes(rng);
|
let mut data = random_32_bytes(rng);
|
||||||
unsafe {
|
unsafe {
|
||||||
while ffi::secp256k1_ecdsa_seckey_verify(data.as_ptr()) == 0 {
|
while ffi::secp256k1_ecdsa_seckey_verify(data.as_ptr()) == 0 {
|
||||||
data = random_32_bytes(rng);
|
data = random_32_bytes(rng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SecretKey(random_32_bytes(rng))
|
SecretKey(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key
|
/// 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 {
|
impl PublicKey {
|
||||||
|
@ -293,6 +321,8 @@ impl fmt::Show for SecretKey {
|
||||||
mod test {
|
mod test {
|
||||||
use std::rand::task_rng;
|
use std::rand::task_rng;
|
||||||
|
|
||||||
|
use test::Bencher;
|
||||||
|
|
||||||
use super::super::{Secp256k1, InvalidNonce, InvalidPublicKey, InvalidSecretKey};
|
use super::super::{Secp256k1, InvalidNonce, InvalidPublicKey, InvalidSecretKey};
|
||||||
use super::{Nonce, PublicKey, SecretKey};
|
use super::{Nonce, PublicKey, SecretKey};
|
||||||
|
|
||||||
|
@ -383,6 +413,14 @@ mod test {
|
||||||
assert!(pk2.add_exp_assign(&sk1).is_ok());
|
assert!(pk2.add_exp_assign(&sk1).is_ok());
|
||||||
assert_eq!(PublicKey::from_secret_key(&sk2, true), pk2);
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,7 @@ impl Secp256k1 {
|
||||||
/// Generates a random keypair. Convenience function for `key::SecretKey::new`
|
/// Generates a random keypair. Convenience function for `key::SecretKey::new`
|
||||||
/// and `key::PublicKey::from_secret_key`; call those functions directly for
|
/// and `key::PublicKey::from_secret_key`; call those functions directly for
|
||||||
/// batch key generation.
|
/// batch key generation.
|
||||||
|
#[inline]
|
||||||
pub fn generate_keypair(&mut self, compressed: bool)
|
pub fn generate_keypair(&mut self, compressed: bool)
|
||||||
-> (key::SecretKey, key::PublicKey) {
|
-> (key::SecretKey, key::PublicKey) {
|
||||||
let sk = key::SecretKey::new(&mut self.rng);
|
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
|
/// Generates a random nonce. Convenience function for `key::Nonce::new`; call
|
||||||
/// that function directly for batch nonce generation
|
/// that function directly for batch nonce generation
|
||||||
|
#[inline]
|
||||||
pub fn generate_nonce(&mut self) -> key::Nonce {
|
pub fn generate_nonce(&mut self) -> key::Nonce {
|
||||||
key::Nonce::new(&mut self.rng)
|
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
|
/// Checks that `sig` is a valid ECDSA signature for `msg` using the public
|
||||||
/// key `pubkey`. Returns `Ok(true)` on success.
|
/// key `pubkey`. Returns `Ok(true)` on success.
|
||||||
|
#[inline]
|
||||||
pub fn verify(msg: &[u8], sig: &[u8], pk: &key::PublicKey) -> Result<()> {
|
pub fn verify(msg: &[u8], sig: &[u8], pk: &key::PublicKey) -> Result<()> {
|
||||||
init(); // This is a static function, so we have to init
|
init(); // This is a static function, so we have to init
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
|
@ -229,7 +232,7 @@ mod tests {
|
||||||
use std::rand;
|
use std::rand;
|
||||||
use std::rand::Rng;
|
use std::rand::Rng;
|
||||||
|
|
||||||
use test::Bencher;
|
use test::{Bencher, black_box};
|
||||||
|
|
||||||
use key::PublicKey;
|
use key::PublicKey;
|
||||||
use super::Secp256k1;
|
use super::Secp256k1;
|
||||||
|
@ -237,15 +240,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_pubkey() {
|
fn invalid_pubkey() {
|
||||||
let s = Secp256k1::new().unwrap();
|
|
||||||
|
|
||||||
let mut msg = Vec::from_elem(32, 0u8);
|
let mut msg = Vec::from_elem(32, 0u8);
|
||||||
let sig = Vec::from_elem(32, 0u8);
|
let sig = Vec::from_elem(32, 0u8);
|
||||||
let pk = PublicKey::new(true);
|
let pk = PublicKey::new(true);
|
||||||
|
|
||||||
rand::task_rng().fill_bytes(msg.as_mut_slice());
|
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]
|
#[test]
|
||||||
|
@ -259,7 +260,7 @@ mod tests {
|
||||||
|
|
||||||
rand::task_rng().fill_bytes(msg.as_mut_slice());
|
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]
|
#[test]
|
||||||
|
@ -272,7 +273,7 @@ mod tests {
|
||||||
|
|
||||||
rand::task_rng().fill_bytes(msg.as_mut_slice());
|
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]
|
#[test]
|
||||||
|
@ -300,7 +301,7 @@ mod tests {
|
||||||
|
|
||||||
let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap();
|
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]
|
#[test]
|
||||||
|
@ -316,7 +317,7 @@ mod tests {
|
||||||
let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap();
|
let sig = s.sign(msg.as_slice(), &sk, &nonce).unwrap();
|
||||||
|
|
||||||
rand::task_rng().fill_bytes(msg.as_mut_slice());
|
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]
|
#[test]
|
||||||
|
@ -338,7 +339,9 @@ mod tests {
|
||||||
pub fn generate_compressed(bh: &mut Bencher) {
|
pub fn generate_compressed(bh: &mut Bencher) {
|
||||||
let mut s = Secp256k1::new().unwrap();
|
let mut s = Secp256k1::new().unwrap();
|
||||||
bh.iter( || {
|
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) {
|
pub fn generate_uncompressed(bh: &mut Bencher) {
|
||||||
let mut s = Secp256k1::new().unwrap();
|
let mut s = Secp256k1::new().unwrap();
|
||||||
bh.iter( || {
|
bh.iter( || {
|
||||||
let (_, _) = s.generate_keypair(false);
|
let (sk, pk) = s.generate_keypair(false);
|
||||||
|
black_box(sk);
|
||||||
|
black_box(pk);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue