Fix for upstream, add some address generation benchmarks

This commit is contained in:
Andrew Poelstra 2014-09-01 09:24:17 -07:00
parent 931df9f68d
commit f66b4ff6b3
5 changed files with 144 additions and 7 deletions

View File

@ -1365,7 +1365,7 @@ pub fn read_uint<'a, I:Iterator<&'a u8>>(mut iter: I, size: uint)
/// Check a signature -- returns an error that is currently just translated /// Check a signature -- returns an error that is currently just translated
/// into a 0/1 to push onto the script stack /// into a 0/1 to push onto the script stack
fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script: Vec<u8>, fn check_signature(sig_slice: &[u8], pk_slice: &[u8], script: Vec<u8>,
tx: &Transaction, input_index: uint) -> Result<(), ScriptError> { tx: &Transaction, input_index: uint) -> Result<(), ScriptError> {
// Check public key // Check public key
@ -1451,7 +1451,7 @@ fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script:
serialize(&Sha256dHash::from_data(data_to_sign.as_slice())).unwrap() serialize(&Sha256dHash::from_data(data_to_sign.as_slice())).unwrap()
}; };
secp.verify(signature_hash.as_slice(), sig_slice, &pubkey).map_err(|e| EcdsaError(e)) Secp256k1::verify(signature_hash.as_slice(), sig_slice, &pubkey).map_err(|e| EcdsaError(e))
} }
// Macro to translate English stack instructions into Rust code. // Macro to translate English stack instructions into Rust code.
@ -1678,7 +1678,6 @@ impl Script {
mut trace: Option<&mut Vec<TraceIteration>>) mut trace: Option<&mut Vec<TraceIteration>>)
-> Result<(), ScriptError> { -> Result<(), ScriptError> {
let &Script(ref raw) = self; let &Script(ref raw) = self;
let secp = Secp256k1::new();
let mut codeseparator_index = 0u; let mut codeseparator_index = 0u;
let mut exec_stack = vec![]; let mut exec_stack = vec![];
@ -1916,7 +1915,7 @@ impl Script {
// Otherwise unwrap it // Otherwise unwrap it
let (tx, input_index) = input_context.unwrap(); let (tx, input_index) = input_context.unwrap();
match check_signature(&secp, sig_slice, pk_slice, script, tx, input_index) { match check_signature( sig_slice, pk_slice, script, tx, input_index) {
Ok(()) => stack.push(Slice(SCRIPT_TRUE)), Ok(()) => stack.push(Slice(SCRIPT_TRUE)),
_ => stack.push(Slice(SCRIPT_FALSE)), _ => stack.push(Slice(SCRIPT_FALSE)),
} }
@ -1977,7 +1976,7 @@ impl Script {
// Try to validate the signature with the given key // Try to validate the signature with the given key
(Some(k), Some(s)) => { (Some(k), Some(s)) => {
// Move to the next signature if it is valid for the current key // Move to the next signature if it is valid for the current key
if check_signature(&secp, s.as_slice(), k.as_slice(), if check_signature(s.as_slice(), k.as_slice(),
script.clone(), tx, input_index).is_ok() { script.clone(), tx, input_index).is_ok() {
sig = sig_iter.next(); sig = sig_iter.next();
} }

View File

@ -55,6 +55,7 @@ extern crate rand;
extern crate rustrt; extern crate rustrt;
extern crate serialize; extern crate serialize;
extern crate sync; extern crate sync;
extern crate test;
extern crate time; extern crate time;
extern crate secp256k1 = "bitcoin-secp256k1-rs"; extern crate secp256k1 = "bitcoin-secp256k1-rs";

View File

@ -25,7 +25,8 @@ use std::hash;
use serialize::json::{mod, ToJson}; use serialize::json::{mod, ToJson};
use crypto::digest::Digest; use crypto::digest::Digest;
use crypto::sha2; use crypto::sha2::Sha256;
use crypto::ripemd160::Ripemd160;
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{RawEncoder, BitcoinHash, SimpleDecoder}; use network::serialize::{RawEncoder, BitcoinHash, SimpleDecoder};
@ -130,6 +131,19 @@ impl Default for DumbHasher {
fn default() -> DumbHasher { DumbHasher } fn default() -> DumbHasher { DumbHasher }
} }
impl Ripemd160Hash {
/// Create a hash by hashing some data
pub fn from_data(data: &[u8]) -> Ripemd160Hash {
let mut ret = [0, ..20];
let mut rmd = Ripemd160::new();
rmd.input(data);
rmd.result(ret.as_mut_slice());
Ripemd160Hash(ret)
}
}
// This doesn't make much sense to me, but is implicit behaviour
// in the C++ reference client
impl Default for Sha256dHash { impl Default for Sha256dHash {
#[inline] #[inline]
fn default() -> Sha256dHash { Sha256dHash([0u8, ..32]) } fn default() -> Sha256dHash { Sha256dHash([0u8, ..32]) }
@ -139,7 +153,7 @@ impl Sha256dHash {
/// Create a hash by hashing some data /// Create a hash by hashing some data
pub fn from_data(data: &[u8]) -> Sha256dHash { pub fn from_data(data: &[u8]) -> Sha256dHash {
let Sha256dHash(mut ret): Sha256dHash = Default::default(); let Sha256dHash(mut ret): Sha256dHash = Default::default();
let mut sha2 = sha2::Sha256::new(); let mut sha2 = Sha256::new();
sha2.input(data); sha2.input(data);
sha2.result(ret.as_mut_slice()); sha2.result(ret.as_mut_slice());
sha2.reset(); sha2.reset();

View File

@ -16,6 +16,12 @@
//! Support for ordinary base58 Bitcoin addresses //! Support for ordinary base58 Bitcoin addresses
//! //!
use secp256k1::key::PublicKey;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use blockdata::script::Script;
use blockdata::opcodes::all;
use network::constants::{Network, Bitcoin, BitcoinTestnet}; use network::constants::{Network, Bitcoin, BitcoinTestnet};
use util::hash::Ripemd160Hash; use util::hash::Ripemd160Hash;
use util::base58::{Base58Error, use util::base58::{Base58Error,
@ -29,6 +35,31 @@ pub struct Address {
hash: Ripemd160Hash hash: Ripemd160Hash
} }
impl Address {
/// Creates an address from a public key
pub fn from_key(network: Network, pk: &PublicKey) -> Address {
let mut sha = Sha256::new();
let mut out = [0, ..32];
sha.input(pk.as_slice());
sha.result(out.as_mut_slice());
Address {
network: network,
hash: Ripemd160Hash::from_data(out)
}
}
/// Generates a script pubkey spending to this address
pub fn script_pubkey(&self) -> Script {
let mut script = Script::new();
script.push_opcode(all::OP_DUP);
script.push_opcode(all::OP_HASH160);
script.push_slice(self.hash.as_slice());
script.push_opcode(all::OP_EQUALVERIFY);
script.push_opcode(all::OP_CHECKSIG);
script
}
}
impl ToBase58 for Address { impl ToBase58 for Address {
fn base58_layout(&self) -> Vec<u8> { fn base58_layout(&self) -> Vec<u8> {
let mut ret = vec![ let mut ret = vec![
@ -68,6 +99,9 @@ impl ::std::fmt::Show for Address {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serialize::hex::FromHex; use serialize::hex::FromHex;
use test::{Bencher, black_box};
use secp256k1::Secp256k1;
use network::constants::Bitcoin; use network::constants::Bitcoin;
use util::hash::Ripemd160Hash; use util::hash::Ripemd160Hash;
@ -84,5 +118,42 @@ mod tests {
assert_eq!(addr.to_base58check().as_slice(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); assert_eq!(addr.to_base58check().as_slice(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
assert_eq!(FromBase58::from_base58check("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"), Ok(addr)); assert_eq!(FromBase58::from_base58check("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"), Ok(addr));
} }
#[bench]
pub fn generate_address(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap();
bh.iter( || {
let (sk, pk) = s.generate_keypair(true);
black_box(sk);
black_box(pk);
let addr = Address::from_key(Bitcoin, &pk);
black_box(addr);
});
}
#[bench]
pub fn generate_uncompressed_address(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap();
bh.iter( || {
let (sk, pk) = s.generate_keypair(false);
black_box(sk);
black_box(pk);
let addr = Address::from_key(Bitcoin, &pk);
black_box(addr);
});
}
#[bench]
pub fn generate_sequential_address(bh: &mut Bencher) {
let mut s = Secp256k1::new().unwrap();
let (sk, _) = s.generate_keypair(true);
let mut iter = sk.sequence(true);
bh.iter( || {
let (sk, pk) = iter.next().unwrap();
black_box(sk);
let addr = Address::from_key(Bitcoin, &pk);
black_box(addr);
});
}
} }

View File

@ -353,6 +353,7 @@ impl FromBase58 for ExtendedPubKey {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serialize::hex::FromHex; use serialize::hex::FromHex;
use test::{Bencher, black_box};
use network::constants::{Network, Bitcoin}; use network::constants::{Network, Bitcoin};
use util::base58::{FromBase58, ToBase58}; use util::base58::{FromBase58, ToBase58};
@ -460,5 +461,56 @@ mod tests {
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j", "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt");
} }
#[bench]
pub fn generate_sequential_normal_children(bh: &mut Bencher) {
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap();
let mut i = 0;
bh.iter( || {
black_box(msk.ckd_priv(Normal(i)));
i += 1;
})
}
#[bench]
pub fn generate_sequential_hardened_children(bh: &mut Bencher) {
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap();
let mut i = 0;
bh.iter( || {
black_box(msk.ckd_priv(Hardened(i)));
i += 1;
})
}
#[bench]
pub fn generate_sequential_public_children(bh: &mut Bencher) {
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap();
let mpk = ExtendedPubKey::from_private(&msk);
let mut i = 0;
bh.iter( || {
black_box(mpk.ckd_pub(Normal(i)));
i += 1;
})
}
#[bench]
pub fn generate_sequential_public_child_addresses(bh: &mut Bencher) {
use wallet::address::Address;
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap();
let mpk = ExtendedPubKey::from_private(&msk);
let mut i = 0;
bh.iter( || {
let epk = mpk.ckd_pub(Normal(i)).unwrap();
black_box(Address::from_key(Bitcoin, &epk.public_key));
i += 1;
})
}
} }