Add global context API

Our API often involves a `Secp256k1` parameter, when users enable the
`global-context` feature they must then pass `SECP256K1` into these
functions. This is kind of clunky since the global is by definition
available everywhere.

Make the API more ergonomic for `global-context` builds by adding
various API functions/methods that use the global context implicitly.
This commit is contained in:
Tobin Harding 2022-02-08 06:11:05 +00:00
parent 3ecb5e41b3
commit eb453b8227
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
4 changed files with 80 additions and 0 deletions

View File

@ -12,6 +12,9 @@ mod recovery;
#[cfg_attr(docsrs, doc(cfg(feature = "recovery")))] #[cfg_attr(docsrs, doc(cfg(feature = "recovery")))]
pub use self::recovery::{RecoveryId, RecoverableSignature}; pub use self::recovery::{RecoveryId, RecoverableSignature};
#[cfg(feature = "global-context")]
use SECP256K1;
/// An ECDSA signature /// An ECDSA signature
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub struct Signature(pub(crate) ffi::Signature); pub struct Signature(pub(crate) ffi::Signature);
@ -269,6 +272,14 @@ impl Signature {
} }
ret ret
} }
/// Verifies an ECDSA signature for `msg` using `pk` and the global [`SECP256K1`] context.
#[inline]
#[cfg(feature = "global-context")]
#[cfg_attr(docsrs, doc(cfg(feature = "global-context")))]
pub fn verify(&self, msg: &Message, pk: &PublicKey) -> Result<(), Error> {
SECP256K1.verify_ecdsa(msg, self, pk)
}
} }
impl CPtr for Signature { impl CPtr for Signature {

View File

@ -121,6 +121,15 @@ impl RecoverableSignature {
Signature(ret) Signature(ret)
} }
} }
/// Determines the public key for which this [`Signature`] is valid for `msg`. Requires a
/// verify-capable context.
#[inline]
#[cfg(feature = "global-context")]
#[cfg_attr(docsrs, doc(cfg(feature = "global-context")))]
pub fn recover(&self, msg: &Message) -> Result<key::PublicKey, Error> {
SECP256K1.recover_ecdsa(msg, self)
}
} }

View File

@ -28,6 +28,11 @@ use Verification;
use constants; use constants;
use ffi::{self, CPtr}; use ffi::{self, CPtr};
#[cfg(feature = "global-context")]
use {Message, ecdsa, SECP256K1};
#[cfg(all(feature = "global-context", feature = "rand-std"))]
use schnorr;
/// Secret 256-bit key used as `x` in an ECDSA signature. /// Secret 256-bit key used as `x` in an ECDSA signature.
/// ///
/// # Examples /// # Examples
@ -279,6 +284,14 @@ impl SecretKey {
} }
} }
} }
/// Constructs an ECDSA signature for `msg` using the global [`SECP256K1`] context.
#[inline]
#[cfg(feature = "global-context")]
#[cfg_attr(docsrs, doc(cfg(feature = "global-context")))]
pub fn sign_ecdsa(&self, msg: Message) -> ecdsa::Signature {
SECP256K1.sign_ecdsa(&msg, self)
}
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -349,6 +362,14 @@ impl PublicKey {
} }
} }
/// Creates a new public key from a [`SecretKey`] and the global [`SECP256K1`] context.
#[inline]
#[cfg(feature = "global-context")]
#[cfg_attr(docsrs, doc(cfg(feature = "global-context")))]
pub fn from_secret_key_global(sk: &SecretKey) -> PublicKey {
PublicKey::from_secret_key(&SECP256K1, sk)
}
/// Creates a public key directly from a slice. /// Creates a public key directly from a slice.
#[inline] #[inline]
pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> { pub fn from_slice(data: &[u8]) -> Result<PublicKey, Error> {
@ -738,6 +759,18 @@ impl KeyPair {
} }
} }
/// Creates a Schnorr [`KeyPair`] directly from a secret key string and the global [`SECP256K1`] context.
///
/// # Errors
///
/// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even.
#[inline]
#[cfg(feature = "global-context")]
#[cfg_attr(docsrs, doc(cfg(feature = "global-context")))]
pub fn from_seckey_str_global(s: &str) -> Result<KeyPair, Error> {
KeyPair::from_seckey_str(SECP256K1, s)
}
/// Generates a new random secret key. /// Generates a new random secret key.
/// # Examples /// # Examples
/// ///
@ -768,6 +801,14 @@ impl KeyPair {
} }
} }
/// Generates a new random secret key using the global [`SECP256K1`] context.
#[inline]
#[cfg(all(feature = "global-context", feature = "rand"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "global-context", feature = "rand"))))]
pub fn new_global<R: ::rand::Rng + ?Sized>(rng: &mut R) -> KeyPair {
KeyPair::new(SECP256K1, rng)
}
/// Serializes the key pair as a secret key byte value. /// Serializes the key pair as a secret key byte value.
#[inline] #[inline]
pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] { pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] {
@ -830,6 +871,14 @@ impl KeyPair {
pub fn public_key(&self) -> XOnlyPublicKey { pub fn public_key(&self) -> XOnlyPublicKey {
XOnlyPublicKey::from_keypair(self) XOnlyPublicKey::from_keypair(self)
} }
/// Constructs an schnorr signature for `msg` using the global [`SECP256K1`] context.
#[inline]
#[cfg(all(feature = "global-context", feature = "rand-std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "global-context", feature = "rand-std"))))]
pub fn sign_schnorr(&self, msg: Message) -> schnorr::Signature {
SECP256K1.sign_schnorr(&msg, self)
}
} }
impl From<KeyPair> for SecretKey { impl From<KeyPair> for SecretKey {

View File

@ -13,6 +13,9 @@ use ffi::{self, CPtr};
use {constants, Secp256k1}; use {constants, Secp256k1};
use {Message, Signing, Verification, KeyPair, XOnlyPublicKey}; use {Message, Signing, Verification, KeyPair, XOnlyPublicKey};
#[cfg(all(feature = "global-context", feature = "rand-std"))]
use SECP256K1;
/// Represents a Schnorr signature. /// Represents a Schnorr signature.
pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]); pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]);
impl_array_newtype!(Signature, u8, constants::SCHNORRSIG_SIGNATURE_SIZE); impl_array_newtype!(Signature, u8, constants::SCHNORRSIG_SIGNATURE_SIZE);
@ -88,6 +91,14 @@ impl Signature {
_ => Err(Error::InvalidSignature), _ => Err(Error::InvalidSignature),
} }
} }
/// Verifies a schnorr signature for `msg` using `pk` and the global [`SECP256K1`] context.
#[inline]
#[cfg(all(feature = "global-context", feature = "rand-std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "global-context", feature = "rand-std"))))]
pub fn verify(&self, msg: &Message, pk: &XOnlyPublicKey) -> Result<(), Error> {
SECP256K1.verify_schnorr(self, msg, pk)
}
} }
impl<C: Signing> Secp256k1<C> { impl<C: Signing> Secp256k1<C> {