From 2e0e731664daf956f29b55ea3511f774d7b78a82 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Thu, 9 Sep 2021 19:34:48 +1000 Subject: [PATCH] Move `KeyPair` to `key` module The `KeyPair` type is semantically unrelated to the schnorr signature algorithm. --- src/key.rs | 177 ++++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 1 + src/schnorrsig.rs | 171 +------------------------------------------- src/secret.rs | 4 +- 4 files changed, 177 insertions(+), 176 deletions(-) diff --git a/src/key.rs b/src/key.rs index 04bfd25..4da3818 100644 --- a/src/key.rs +++ b/src/key.rs @@ -134,9 +134,9 @@ impl SecretKey { } } - /// Creates a new secret key using data from BIP-340 [`::schnorrsig::KeyPair`] + /// Creates a new secret key using data from BIP-340 [`KeyPair`] #[inline] - pub fn from_keypair(keypair: &::schnorrsig::KeyPair) -> Self { + pub fn from_keypair(keypair: &KeyPair) -> Self { let mut sk = [0u8; constants::SECRET_KEY_SIZE]; unsafe { let ret = ffi::secp256k1_keypair_sec( @@ -297,9 +297,9 @@ impl PublicKey { } } - /// Creates a new compressed public key key using data from BIP-340 [`::schnorrsig::KeyPair`] + /// Creates a new compressed public key key using data from BIP-340 [`KeyPair`] #[inline] - pub fn from_keypair(keypair: &::schnorrsig::KeyPair) -> Self { + pub fn from_keypair(keypair: &KeyPair) -> Self { unsafe { let mut pk = ffi::PublicKey::new(); let ret = ffi::secp256k1_keypair_pub( @@ -505,6 +505,175 @@ impl Ord for PublicKey { } } +/// Opaque data structure that holds a keypair consisting of a secret and a public key. +#[derive(Clone)] +pub struct KeyPair(ffi::KeyPair); +impl_display_secret!(KeyPair); + +impl KeyPair { + /// Obtains a raw const pointer suitable for use with FFI functions + #[inline] + pub fn as_ptr(&self) -> *const ffi::KeyPair { + &self.0 + } + + /// Obtains a raw mutable pointer suitable for use with FFI functions + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut ffi::KeyPair { + &mut self.0 + } + + /// Creates a Schnorr KeyPair directly from generic Secp256k1 secret key + /// + /// # Panic + /// + /// Panics if internal representation of the provided [`SecretKey`] does not hold correct secret + /// key value obtained from Secp256k1 library previously, specifically when secret key value is + /// out-of-range (0 or in excess of the group order). + #[inline] + pub fn from_secret_key( + secp: &Secp256k1, + sk: SecretKey, + ) -> KeyPair { + unsafe { + let mut kp = ffi::KeyPair::new(); + if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, sk.as_c_ptr()) == 1 { + KeyPair(kp) + } else { + panic!("the provided secret key is invalid: it is corrupted or was not produced by Secp256k1 library") + } + } + } + + /// Creates a Schnorr KeyPair directly from a secret key slice. + /// + /// # Errors + /// + /// [`Error::InvalidSecretKey`] if the provided data has an incorrect length, exceeds Secp256k1 + /// field `p` value or the corresponding public key is not even. + #[inline] + pub fn from_seckey_slice( + secp: &Secp256k1, + data: &[u8], + ) -> Result { + if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE { + return Err(Error::InvalidSecretKey); + } + + unsafe { + let mut kp = ffi::KeyPair::new(); + if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, data.as_c_ptr()) == 1 { + Ok(KeyPair(kp)) + } else { + Err(Error::InvalidSecretKey) + } + } + } + + /// Creates a Schnorr KeyPair directly from a secret key string + /// + /// # Errors + /// + /// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even. + #[inline] + pub fn from_seckey_str(secp: &Secp256k1, s: &str) -> Result { + let mut res = [0u8; constants::SECRET_KEY_SIZE]; + match from_hex(s, &mut res) { + Ok(constants::SECRET_KEY_SIZE) => { + KeyPair::from_seckey_slice(secp, &res[0..constants::SECRET_KEY_SIZE]) + } + _ => Err(Error::InvalidPublicKey), + } + } + + /// Creates a new random secret key. Requires compilation with the "rand" feature. + #[inline] + #[cfg(any(test, feature = "rand"))] + pub fn new(secp: &Secp256k1, rng: &mut R) -> KeyPair { + let mut random_32_bytes = || { + let mut ret = [0u8; 32]; + rng.fill_bytes(&mut ret); + ret + }; + let mut data = random_32_bytes(); + unsafe { + let mut keypair = ffi::KeyPair::new(); + while ffi::secp256k1_keypair_create(secp.ctx, &mut keypair, data.as_c_ptr()) == 0 { + data = random_32_bytes(); + } + KeyPair(keypair) + } + } + + /// Serialize the key pair as a secret key byte value + #[inline] + pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] { + *SecretKey::from_keypair(self).as_ref() + } + + /// Tweak a keypair by adding the given tweak to the secret key and updating the public key + /// accordingly. + /// + /// Will return an error if the resulting key would be invalid or if the tweak was not a 32-byte + /// length slice. + /// + /// NB: Will not error if the tweaked public key has an odd value and can't be used for + /// BIP 340-342 purposes. + // TODO: Add checked implementation + #[inline] + pub fn tweak_add_assign( + &mut self, + secp: &Secp256k1, + tweak: &[u8], + ) -> Result<(), Error> { + if tweak.len() != 32 { + return Err(Error::InvalidTweak); + } + + unsafe { + let err = ffi::secp256k1_keypair_xonly_tweak_add( + secp.ctx, + &mut self.0, + tweak.as_c_ptr(), + ); + + if err == 1 { + Ok(()) + } else { + Err(Error::InvalidTweak) + } + } + } +} + +impl From for SecretKey { + #[inline] + fn from(pair: KeyPair) -> Self { + SecretKey::from_keypair(&pair) + } +} + +impl<'a> From<&'a KeyPair> for SecretKey { + #[inline] + fn from(pair: &'a KeyPair) -> Self { + SecretKey::from_keypair(pair) + } +} + +impl From for PublicKey { + #[inline] + fn from(pair: KeyPair) -> Self { + PublicKey::from_keypair(&pair) + } +} + +impl<'a> From<&'a KeyPair> for PublicKey { + #[inline] + fn from(pair: &'a KeyPair) -> Self { + PublicKey::from_keypair(pair) + } +} + #[cfg(test)] mod test { use Secp256k1; diff --git a/src/lib.rs b/src/lib.rs index b007b94..17c006c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,6 +155,7 @@ mod serde_util; pub use key::SecretKey; pub use key::PublicKey; pub use key::ONE_KEY; +pub use key::KeyPair; pub use context::*; use core::marker::PhantomData; use core::{mem, fmt, ptr, str}; diff --git a/src/schnorrsig.rs b/src/schnorrsig.rs index e750b16..00de83d 100644 --- a/src/schnorrsig.rs +++ b/src/schnorrsig.rs @@ -12,7 +12,7 @@ use core::{fmt, ptr, str}; use ffi::{self, CPtr}; use {constants, Secp256k1}; use {Message, Signing, Verification}; -use SecretKey; +use KeyPair; /// Represents a Schnorr signature. pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]); @@ -74,11 +74,6 @@ impl str::FromStr for Signature { } } -/// Opaque data structure that holds a keypair consisting of a secret and a public key. -#[derive(Clone)] -pub struct KeyPair(ffi::KeyPair); -impl_display_secret!(KeyPair); - /// A Schnorr public key, used for verification of Schnorr signatures #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)] pub struct PublicKey(ffi::XOnlyPublicKey); @@ -127,142 +122,6 @@ impl Signature { } } -impl KeyPair { - /// Obtains a raw const pointer suitable for use with FFI functions - #[inline] - pub fn as_ptr(&self) -> *const ffi::KeyPair { - &self.0 - } - - /// Obtains a raw mutable pointer suitable for use with FFI functions - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut ffi::KeyPair { - &mut self.0 - } - - /// Creates a Schnorr KeyPair directly from generic Secp256k1 secret key - /// - /// # Panic - /// - /// Panics if internal representation of the provided [`SecretKey`] does not hold correct secret - /// key value obtained from Secp256k1 library previously, specifically when secret key value is - /// out-of-range (0 or in excess of the group order). - #[inline] - pub fn from_secret_key( - secp: &Secp256k1, - sk: ::key::SecretKey, - ) -> KeyPair { - unsafe { - let mut kp = ffi::KeyPair::new(); - if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, sk.as_c_ptr()) == 1 { - KeyPair(kp) - } else { - panic!("the provided secret key is invalid: it is corrupted or was not produced by Secp256k1 library") - } - } - } - - /// Creates a Schnorr KeyPair directly from a secret key slice. - /// - /// # Errors - /// - /// [`Error::InvalidSecretKey`] if the provided data has an incorrect length, exceeds Secp256k1 - /// field `p` value or the corresponding public key is not even. - #[inline] - pub fn from_seckey_slice( - secp: &Secp256k1, - data: &[u8], - ) -> Result { - if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE { - return Err(Error::InvalidSecretKey); - } - - unsafe { - let mut kp = ffi::KeyPair::new(); - if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, data.as_c_ptr()) == 1 { - Ok(KeyPair(kp)) - } else { - Err(Error::InvalidSecretKey) - } - } - } - - /// Creates a Schnorr KeyPair directly from a secret key string - /// - /// # Errors - /// - /// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even. - #[inline] - pub fn from_seckey_str(secp: &Secp256k1, s: &str) -> Result { - let mut res = [0u8; constants::SECRET_KEY_SIZE]; - match from_hex(s, &mut res) { - Ok(constants::SECRET_KEY_SIZE) => { - KeyPair::from_seckey_slice(secp, &res[0..constants::SECRET_KEY_SIZE]) - } - _ => Err(Error::InvalidPublicKey), - } - } - - /// Creates a new random secret key. Requires compilation with the "rand" feature. - #[inline] - #[cfg(any(test, feature = "rand"))] - pub fn new(secp: &Secp256k1, rng: &mut R) -> KeyPair { - let mut random_32_bytes = || { - let mut ret = [0u8; 32]; - rng.fill_bytes(&mut ret); - ret - }; - let mut data = random_32_bytes(); - unsafe { - let mut keypair = ffi::KeyPair::new(); - while ffi::secp256k1_keypair_create(secp.ctx, &mut keypair, data.as_c_ptr()) == 0 { - data = random_32_bytes(); - } - KeyPair(keypair) - } - } - - /// Serialize the key pair as a secret key byte value - #[inline] - pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] { - *SecretKey::from_keypair(self).as_ref() - } - - /// Tweak a keypair by adding the given tweak to the secret key and updating the public key - /// accordingly. - /// - /// Will return an error if the resulting key would be invalid or if the tweak was not a 32-byte - /// length slice. - /// - /// NB: Will not error if the tweaked public key has an odd value and can't be used for - /// BIP 340-342 purposes. - // TODO: Add checked implementation - #[inline] - pub fn tweak_add_assign( - &mut self, - secp: &Secp256k1, - tweak: &[u8], - ) -> Result<(), Error> { - if tweak.len() != 32 { - return Err(Error::InvalidTweak); - } - - unsafe { - let err = ffi::secp256k1_keypair_xonly_tweak_add( - secp.ctx, - &mut self.0, - tweak.as_c_ptr(), - ); - - if err == 1 { - Ok(()) - } else { - Err(Error::InvalidTweak) - } - } - } -} - impl PublicKey { /// Obtains a raw const pointer suitable for use with FFI functions #[inline] @@ -475,34 +334,6 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey { } } -impl From for SecretKey { - #[inline] - fn from(pair: KeyPair) -> Self { - SecretKey::from_keypair(&pair) - } -} - -impl<'a> From<&'a KeyPair> for SecretKey { - #[inline] - fn from(pair: &'a KeyPair) -> Self { - SecretKey::from_keypair(pair) - } -} - -impl From for ::key::PublicKey { - #[inline] - fn from(pair: KeyPair) -> Self { - ::key::PublicKey::from_keypair(&pair) - } -} - -impl<'a> From<&'a KeyPair> for ::key::PublicKey { - #[inline] - fn from(pair: &'a KeyPair) -> Self { - ::key::PublicKey::from_keypair(pair) - } -} - impl Secp256k1 { fn schnorrsig_sign_helper( &self, diff --git a/src/secret.rs b/src/secret.rs index f7fc22e..564e17e 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -15,7 +15,7 @@ //! Helpers for displaying secret values use ::core::fmt; -use ::{SecretKey, schnorrsig::KeyPair, to_hex}; +use ::{SecretKey, KeyPair, to_hex}; use constants::SECRET_KEY_SIZE; macro_rules! impl_display_secret { @@ -124,7 +124,7 @@ impl KeyPair { /// /// ``` /// use secp256k1::ONE_KEY; - /// use secp256k1::schnorrsig::KeyPair; + /// use secp256k1::KeyPair; /// use secp256k1::Secp256k1; /// /// let secp = Secp256k1::new();