diff --git a/src/key.rs b/src/key.rs index 5efb2ffd1..358eb4698 100644 --- a/src/key.rs +++ b/src/key.rs @@ -13,7 +13,8 @@ // If not, see . // -//! # Public and secret keys +//! Public and secret keys. +//! #[cfg(any(test, feature = "rand"))] use rand::Rng; @@ -27,7 +28,20 @@ use Verification; use constants; use ffi::{self, CPtr}; -/// Secret 256-bit key used as `x` in an ECDSA signature +/// Secret 256-bit key used as `x` in an ECDSA signature. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # #[cfg(feature="rand")] { +/// use secp256k1::{rand, Secp256k1, SecretKey}; +/// +/// let secp = Secp256k1::new(); +/// let secret_key = SecretKey::new(&mut rand::thread_rng()); +/// # } +/// ``` pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]); impl_array_newtype!(SecretKey, u8, constants::SECRET_KEY_SIZE); impl_display_secret!(SecretKey); @@ -49,7 +63,19 @@ pub const ONE_KEY: 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, 1]); -/// A Secp256k1 public key, used for verification of signatures +/// A Secp256k1 public key, used for verification of signatures. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use secp256k1::{SecretKey, Secp256k1, PublicKey}; +/// +/// let secp = Secp256k1::new(); +/// let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); +/// let public_key = PublicKey::from_secret_key(&secp, &secret_key); +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[repr(transparent)] pub struct PublicKey(ffi::PublicKey); @@ -97,6 +123,15 @@ fn random_32_bytes(rng: &mut R) -> [u8; 32] { impl SecretKey { /// Generates a new random secret key. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{rand, SecretKey}; + /// let secret_key = SecretKey::new(&mut rand::thread_rng()); + /// # } + /// ``` #[inline] #[cfg(any(test, feature = "rand"))] #[cfg_attr(docsrs, doc(cfg(feature = "rand")))] @@ -114,7 +149,14 @@ impl SecretKey { SecretKey(data) } - /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key + /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key. + /// + /// # Examples + /// + /// ``` + /// use secp256k1::SecretKey; + /// let sk = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); + /// ``` #[inline] pub fn from_slice(data: &[u8])-> Result { match data.len() { @@ -136,7 +178,19 @@ impl SecretKey { } } - /// Creates a new secret key using data from BIP-340 [`KeyPair`] + /// Creates a new secret key using data from BIP-340 [`KeyPair`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{rand, Secp256k1, SecretKey, KeyPair}; + /// + /// let secp = Secp256k1::new(); + /// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); + /// let secret_key = SecretKey::from_keypair(&key_pair); + /// # } + /// ``` #[inline] pub fn from_keypair(keypair: &KeyPair) -> Self { let mut sk = [0u8; constants::SECRET_KEY_SIZE]; @@ -151,7 +205,7 @@ impl SecretKey { SecretKey(sk) } - /// Serialize the secret key as byte value + /// Serializes the secret key as byte value. #[inline] pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] { self.0 @@ -172,9 +226,12 @@ impl SecretKey { } #[inline] - /// Adds one secret key to another, modulo the curve order. WIll - /// return an error if the resulting key would be invalid or if - /// the tweak was not a 32-byte length slice. + /// Adds one secret key to another, modulo the curve order. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte + /// length slice. pub fn add_assign( &mut self, other: &[u8], @@ -253,19 +310,31 @@ impl<'de> ::serde::Deserialize<'de> for SecretKey { } impl PublicKey { - /// Obtains a raw const pointer suitable for use with FFI functions + /// Obtains a raw const pointer suitable for use with FFI functions. #[inline] pub fn as_ptr(&self) -> *const ffi::PublicKey { &self.0 } - /// Obtains a raw mutable pointer suitable for use with FFI functions + /// Obtains a raw mutable pointer suitable for use with FFI functions. #[inline] pub fn as_mut_ptr(&mut self) -> *mut ffi::PublicKey { &mut self.0 } - /// Creates a new public key from a secret key. + /// Creates a new public key from a [`SecretKey`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{rand, Secp256k1, SecretKey, PublicKey}; + /// + /// let secp = Secp256k1::new(); + /// let secret_key = SecretKey::new(&mut rand::thread_rng()); + /// let public_key = PublicKey::from_secret_key(&secp, &secret_key); + /// # } + /// ``` #[inline] pub fn from_secret_key(secp: &Secp256k1, sk: &SecretKey) @@ -280,7 +349,7 @@ impl PublicKey { } } - /// Creates a public key directly from a slice + /// Creates a public key directly from a slice. #[inline] pub fn from_slice(data: &[u8]) -> Result { if data.is_empty() {return Err(Error::InvalidPublicKey);} @@ -302,6 +371,18 @@ impl PublicKey { } /// Creates a new compressed public key using data from BIP-340 [`KeyPair`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{rand, Secp256k1, PublicKey, KeyPair}; + /// + /// let secp = Secp256k1::new(); + /// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); + /// let public_key = PublicKey::from_keypair(&key_pair); + /// # } + /// ``` #[inline] pub fn from_keypair(keypair: &KeyPair) -> Self { unsafe { @@ -317,9 +398,8 @@ impl PublicKey { } #[inline] - /// Serialize the key as a byte-encoded pair of values. In compressed form - /// the y-coordinate is represented by only a single bit, as x determines - /// it up to one bit. + /// Serializes the key as a byte-encoded pair of values. In compressed form the y-coordinate is + /// represented by only a single bit, as x determines it up to one bit. pub fn serialize(&self) -> [u8; constants::PUBLIC_KEY_SIZE] { let mut ret = [0u8; constants::PUBLIC_KEY_SIZE]; @@ -338,7 +418,7 @@ impl PublicKey { ret } - /// Serialize the key as a byte-encoded pair of values, in uncompressed form + /// Serializes the key as a byte-encoded pair of values, in uncompressed form. pub fn serialize_uncompressed(&self) -> [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE] { let mut ret = [0u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]; @@ -358,8 +438,7 @@ impl PublicKey { } #[inline] - /// Negates the pk to the pk `self` in place - /// Will return an error if the pk would be invalid. + /// Negates the public key in place. pub fn negate_assign( &mut self, secp: &Secp256k1 @@ -371,9 +450,12 @@ impl PublicKey { } #[inline] - /// Adds the pk corresponding to `other` to the pk `self` in place - /// Will return an error if the resulting key would be invalid or - /// if the tweak was not a 32-byte length slice. + /// Adds the `other` public key to `self` in place. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte + /// length slice. pub fn add_exp_assign( &mut self, secp: &Secp256k1, @@ -392,9 +474,12 @@ impl PublicKey { } #[inline] - /// Muliplies the pk `self` in place by the scalar `other` - /// Will return an error if the resulting key would be invalid or - /// if the tweak was not a 32-byte length slice. + /// Muliplies the public key in place by the scalar `other`. + /// + /// # Errors + /// + /// Returns an error if the resulting key would be invalid or if the tweak was not a 32-byte + /// length slice. pub fn mul_assign( &mut self, secp: &Secp256k1, @@ -412,17 +497,52 @@ impl PublicKey { } } - /// Adds a second key to this one, returning the sum. Returns an error if - /// the result would be the point at infinity, i.e. we are adding this point - /// to its own negation + /// Adds a second key to this one, returning the sum. + /// + /// # Errors + /// + /// If the result would be the point at infinity, i.e. adding this point to its own negation. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{rand, Secp256k1}; + /// + /// let secp = Secp256k1::new(); + /// let mut rng = rand::thread_rng(); + /// let (_, pk1) = secp.generate_keypair(&mut rng); + /// let (_, pk2) = secp.generate_keypair(&mut rng); + /// let sum = pk1.combine(&pk2).expect("It's improbable to fail for 2 random public keys"); + /// # } + ///``` pub fn combine(&self, other: &PublicKey) -> Result { PublicKey::combine_keys(&[self, other]) } - /// Adds the keys in the provided slice together, returning the sum. Returns - /// an error if the result would be the point at infinity, i.e. we are adding - /// a point to its own negation, if the provided slice has no element in it, - /// or if the number of element it contains is greater than i32::MAX. + /// Adds the keys in the provided slice together, returning the sum. + /// + /// # Errors + /// + /// Errors under any of the following conditions: + /// - The result would be the point at infinity, i.e. adding a point to its own negation. + /// - The provided slice is empty. + /// - The number of elements in the provided slice is greater than `i32::MAX`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{rand, Secp256k1, PublicKey}; + /// + /// let secp = Secp256k1::new(); + /// let mut rng = rand::thread_rng(); + /// let (_, pk1) = secp.generate_keypair(&mut rng); + /// let (_, pk2) = secp.generate_keypair(&mut rng); + /// let (_, pk3) = secp.generate_keypair(&mut rng); + /// let sum = PublicKey::combine_keys(&[&pk1, &pk2, &pk3]).expect("It's improbable to fail for 3 random public keys"); + /// # } + /// ``` pub fn combine_keys(keys: &[&PublicKey]) -> Result { use core::mem::transmute; use core::i32::MAX; @@ -514,6 +634,7 @@ impl Ord for PublicKey { /// Opaque data structure that holds a keypair consisting of a secret and a public key. /// /// # Serde support +/// /// [`Serialize`] and [`Deserialize`] are not implemented for this type, even with the `serde` /// feature active. This is due to security considerations, see the [`serde_keypair`] documentation /// for details. @@ -522,29 +643,41 @@ impl Ord for PublicKey { /// deserialized by annotating them with `#[serde(with = "secp256k1::serde_keypair")]` /// inside structs or enums for which [`Serialize`] and [`Deserialize`] are being derived. /// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # #[cfg(feature="rand")] { +/// use secp256k1::{rand, KeyPair, Secp256k1}; +/// +/// let secp = Secp256k1::new(); +/// let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng()); +/// let key_pair = KeyPair::from_secret_key(&secp, secret_key); +/// # } +/// ``` /// [`Deserialize`]: serde::Deserialize /// [`Serialize`]: serde::Serialize -// Should secrets implement Copy: https://github.com/rust-bitcoin/rust-secp256k1/issues/363 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct KeyPair(ffi::KeyPair); impl_display_secret!(KeyPair); impl KeyPair { - /// Obtains a raw const pointer suitable for use with FFI functions + /// 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 + /// 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 + /// Creates a Schnorr [`KeyPair`] directly from generic Secp256k1 secret key. /// - /// # Panic + /// # Panics /// /// 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 @@ -564,7 +697,7 @@ impl KeyPair { } } - /// Creates a Schnorr KeyPair directly from a secret key slice. + /// Creates a Schnorr [`KeyPair`] directly from a secret key slice. /// /// # Errors /// @@ -589,7 +722,7 @@ impl KeyPair { } } - /// Creates a Schnorr KeyPair directly from a secret key string + /// Creates a Schnorr [`KeyPair`] directly from a secret key string. /// /// # Errors /// @@ -606,6 +739,16 @@ impl KeyPair { } /// Generates a new random secret key. + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{rand, Secp256k1, SecretKey, KeyPair}; + /// + /// let secp = Secp256k1::new(); + /// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); + /// # } + /// ``` #[inline] #[cfg(any(test, feature = "rand"))] #[cfg_attr(docsrs, doc(cfg(feature = "rand")))] @@ -625,20 +768,38 @@ impl KeyPair { } } - /// Serialize the key pair as a secret key byte value + /// Serializes 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 + /// Tweaks 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 + /// # Errors + /// + /// Returns 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. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{Secp256k1, KeyPair}; + /// use secp256k1::rand::{RngCore, thread_rng}; + /// + /// let secp = Secp256k1::new(); + /// let mut tweak = [0u8; 32]; + /// thread_rng().fill_bytes(&mut tweak); + /// + /// let mut key_pair = KeyPair::new(&secp, &mut thread_rng()); + /// key_pair.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// # } + /// ``` // TODO: Add checked implementation #[inline] pub fn tweak_add_assign( @@ -744,7 +905,21 @@ impl<'de> ::serde::Deserialize<'de> for KeyPair { } } -/// A x-only public key, used for verification of Schnorr signatures and serialized according to BIP-340. +/// An x-only public key, used for verification of Schnorr signatures and serialized according to BIP-340. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # #[cfg(feature="rand")] { +/// use secp256k1::{rand, Secp256k1, KeyPair, XOnlyPublicKey}; +/// +/// let secp = Secp256k1::new(); +/// let key_pair = KeyPair::new(&secp, &mut rand::thread_rng()); +/// let xonly = XOnlyPublicKey::from_keypair(&key_pair); +/// # } +/// ``` #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)] pub struct XOnlyPublicKey(ffi::XOnlyPublicKey); @@ -778,13 +953,13 @@ impl str::FromStr for XOnlyPublicKey { } impl XOnlyPublicKey { - /// Obtains a raw const pointer suitable for use with FFI functions + /// Obtains a raw const pointer suitable for use with FFI functions. #[inline] pub fn as_ptr(&self) -> *const ffi::XOnlyPublicKey { &self.0 } - /// Obtains a raw mutable pointer suitable for use with FFI functions + /// Obtains a raw mutable pointer suitable for use with FFI functions. #[inline] pub fn as_mut_ptr(&mut self) -> *mut ffi::XOnlyPublicKey { &mut self.0 @@ -807,12 +982,12 @@ impl XOnlyPublicKey { } } - /// Creates a Schnorr public key directly from a slice + /// Creates a Schnorr public key directly from a slice. /// /// # Errors /// /// Returns [`Error::InvalidPublicKey`] if the length of the data slice is not 32 bytes or the - /// slice does not represent a valid Secp256k1 point x coordinate + /// slice does not represent a valid Secp256k1 point x coordinate. #[inline] pub fn from_slice(data: &[u8]) -> Result { if data.is_empty() || data.len() != constants::SCHNORRSIG_PUBLIC_KEY_SIZE { @@ -835,7 +1010,7 @@ impl XOnlyPublicKey { } #[inline] - /// Serialize the key as a byte-encoded x coordinate value (32 bytes). + /// Serializes the key as a byte-encoded x coordinate value (32 bytes). pub fn serialize(&self) -> [u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE] { let mut ret = [0u8; constants::SCHNORRSIG_PUBLIC_KEY_SIZE]; @@ -850,15 +1025,34 @@ impl XOnlyPublicKey { ret } - /// Tweak an x-only PublicKey by adding the generator multiplied with the given tweak to it. + /// Tweaks an x-only PublicKey by adding the generator multiplied with the given tweak to it. + /// + /// # Returns /// - /// # Return /// An opaque type representing the parity of the tweaked key, this should be provided to /// `tweak_add_check` which can be used to verify a tweak more efficiently than regenerating /// it and checking equality. /// - /// # Error + /// # Errors + /// /// If the resulting key would be invalid or if the tweak was not a 32-byte length slice. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{Secp256k1, KeyPair}; + /// use secp256k1::rand::{RngCore, thread_rng}; + /// + /// let secp = Secp256k1::new(); + /// let mut tweak = [0u8; 32]; + /// thread_rng().fill_bytes(&mut tweak); + /// + /// let mut key_pair = KeyPair::new(&secp, &mut thread_rng()); + /// let mut public_key = key_pair.public_key(); + /// public_key.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// # } + /// ``` pub fn tweak_add_assign( &mut self, secp: &Secp256k1, @@ -895,18 +1089,37 @@ impl XOnlyPublicKey { } } - /// Verify that a tweak produced by `tweak_add_assign` was computed correctly. + /// Verifies that a tweak produced by [`XOnlyPublicKey::tweak_add_assign`] was computed correctly. + /// + /// Should be called on the original untweaked key. Takes the tweaked key and output parity from + /// [`XOnlyPublicKey::tweak_add_assign`] as input. /// - /// Should be called on the original untweaked key. Takes the tweaked key and - /// output parity from `tweak_add_assign` as input. + /// Currently this is not much more efficient than just recomputing the tweak and checking + /// equality. However, in future this API will support batch verification, which is + /// significantly faster, so it is wise to design protocols with this in mind. /// - /// Currently this is not much more efficient than just recomputing the tweak - /// and checking equality. However, in future this API will support batch - /// verification, which is significantly faster, so it is wise to design - /// protocols with this in mind. + /// # Returns /// - /// # Return /// True if tweak and check is successful, false otherwise. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature="rand")] { + /// use secp256k1::{Secp256k1, KeyPair}; + /// use secp256k1::rand::{thread_rng, RngCore}; + /// + /// let secp = Secp256k1::new(); + /// let mut tweak = [0u8; 32]; + /// thread_rng().fill_bytes(&mut tweak); + /// + /// let mut key_pair = KeyPair::new(&secp, &mut thread_rng()); + /// let mut public_key = key_pair.public_key(); + /// let original = public_key; + /// let parity = public_key.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak"); + /// assert!(original.tweak_add_check(&secp, &public_key, parity, tweak)); + /// # } + /// ``` pub fn tweak_add_check( &self, secp: &Secp256k1, @@ -1039,7 +1252,7 @@ impl CPtr for XOnlyPublicKey { } } -/// Creates a new Schnorr public key from a FFI x-only public key +/// Creates a new Schnorr public key from a FFI x-only public key. impl From for XOnlyPublicKey { #[inline] fn from(pk: ffi::XOnlyPublicKey) -> XOnlyPublicKey { diff --git a/src/lib.rs b/src/lib.rs index de38e3970..0e742cd9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,13 +58,13 @@ //! Alternately, keys and messages can be parsed from slices, like //! //! ```rust -//! use self::secp256k1::{Secp256k1, Message, SecretKey, PublicKey}; +//! use secp256k1::{Secp256k1, Message, SecretKey, PublicKey}; //! //! let secp = Secp256k1::new(); //! let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); //! let public_key = PublicKey::from_secret_key(&secp, &secret_key); //! // This is unsafe unless the supplied byte slice is the output of a cryptographic hash function. -//! // See the above example for how to use this library together with bitcoin_hashes. +//! // See the above example for how to use this library together with `bitcoin_hashes`. //! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); //! //! let sig = secp.sign_ecdsa(&message, &secret_key); @@ -439,10 +439,8 @@ impl Secp256k1 { } 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. Requires a signing-capable context. Requires compilation - /// with the "rand" feature. + /// Generates a random keypair. Convenience function for [`SecretKey::new`] and + /// [`PublicKey::from_secret_key`]. #[inline] #[cfg(any(test, feature = "rand"))] #[cfg_attr(docsrs, doc(cfg(feature = "rand")))]