Pull out initialization code so that `PublicKey::from_secret_key` can be used safely

This commit is contained in:
Andrew Poelstra 2014-08-09 20:34:16 -07:00
parent 522bafe433
commit d6bf4039bd
2 changed files with 35 additions and 20 deletions

View File

@ -7,6 +7,7 @@ use constants;
use ffi; use ffi;
use super::{Result, InvalidNonce, InvalidPublicKey, InvalidSecretKey}; use super::{Result, InvalidNonce, InvalidPublicKey, InvalidSecretKey};
use super::init;
/// Secret 256-bit nonce used as `k` in an ECDSA signature /// Secret 256-bit nonce used as `k` in an ECDSA signature
pub struct Nonce([u8, ..constants::NONCE_SIZE]); pub struct Nonce([u8, ..constants::NONCE_SIZE]);
@ -124,20 +125,22 @@ impl PublicKey {
) )
} }
/// Creates a new public key from a secret key /// Creates a new public key from a secret key. Marked `unsafe` since you must
/// call `init()` (or construct a `Secp256k1`, which does this for you) before
/// using this function
#[inline] #[inline]
pub fn from_secret_key(sk: &SecretKey, compressed: bool) -> PublicKey { pub unsafe fn from_secret_key(sk: &SecretKey, compressed: bool) -> PublicKey {
let mut pk = PublicKey::new(compressed); let mut pk = PublicKey::new(compressed);
let compressed = if compressed {1} else {0}; let compressed = if compressed {1} else {0};
unsafe {
let mut len = 0; let mut len = 0;
while ffi::secp256k1_ecdsa_pubkey_create( while ffi::secp256k1_ecdsa_pubkey_create(
pk.as_mut_ptr(), &mut len, pk.as_mut_ptr(), &mut len,
sk.as_ptr(), compressed) != 1 { sk.as_ptr(), compressed) != 1 {
// loop // loop
} }
assert_eq!(len as uint, pk.len()); assert_eq!(len as uint, pk.len());
};
pk pk
} }

View File

@ -25,7 +25,7 @@
extern crate libc; extern crate libc;
extern crate sync; extern crate sync;
use std::io::IoError; use std::io::{IoError, IoResult};
use std::rand::OsRng; use std::rand::OsRng;
use libc::c_int; use libc::c_int;
use sync::one::{Once, ONCE_INIT}; use sync::one::{Once, ONCE_INIT};
@ -84,28 +84,40 @@ pub struct Secp256k1 {
rng: OsRng rng: OsRng
} }
impl Secp256k1 { /// Does one-time initialization of the secp256k1 engine. Can be called
/// Constructs a new secp256k1 engine. /// multiple times, and is called by the `Secp256k1` constructor. This
pub fn new() -> Result<Secp256k1> { /// only needs to be called directly if you are using the library without
/// a `Secp256k1` object, e.g. batch key generation through
/// `key::PublicKey::from_secret_key`.
pub fn init() {
unsafe { unsafe {
Secp256k1_init.doit(|| { Secp256k1_init.doit(|| {
ffi::secp256k1_start(); ffi::secp256k1_start();
}); });
} }
}
impl Secp256k1 {
/// Constructs a new secp256k1 engine.
pub fn new() -> Result<Secp256k1> {
init();
match OsRng::new() { match OsRng::new() {
Ok(rng) => Ok(Secp256k1 { rng: rng }), Ok(rng) => Ok(Secp256k1 { rng: rng }),
Err(e) => Err(RngError(e)) Err(e) => Err(RngError(e))
} }
} }
/// Generates a randam keypair /// Generates a random keypair. Convenience function for `key::SecretKey::new`
/// and `key::PublicKey::from_secret_key`; call those functions directly for
/// batch key generation.
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);
(sk, key::PublicKey::from_secret_key(&sk, compressed)) unsafe { (sk, key::PublicKey::from_secret_key(&sk, compressed)) }
} }
/// Generates a random nonce /// Generates a random nonce. Convenience function for `key::Nonce::new`; call
/// that function directly for batch nonce generation
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)
} }