Skip to content

Commit 2e0e731

Browse files
Move KeyPair to key module
The `KeyPair` type is semantically unrelated to the schnorr signature algorithm.
1 parent c47ead9 commit 2e0e731

File tree

4 files changed

+177
-176
lines changed

4 files changed

+177
-176
lines changed

src/key.rs

Lines changed: 173 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ impl SecretKey {
134134
}
135135
}
136136

137-
/// Creates a new secret key using data from BIP-340 [`::schnorrsig::KeyPair`]
137+
/// Creates a new secret key using data from BIP-340 [`KeyPair`]
138138
#[inline]
139-
pub fn from_keypair(keypair: &::schnorrsig::KeyPair) -> Self {
139+
pub fn from_keypair(keypair: &KeyPair) -> Self {
140140
let mut sk = [0u8; constants::SECRET_KEY_SIZE];
141141
unsafe {
142142
let ret = ffi::secp256k1_keypair_sec(
@@ -297,9 +297,9 @@ impl PublicKey {
297297
}
298298
}
299299

300-
/// Creates a new compressed public key key using data from BIP-340 [`::schnorrsig::KeyPair`]
300+
/// Creates a new compressed public key key using data from BIP-340 [`KeyPair`]
301301
#[inline]
302-
pub fn from_keypair(keypair: &::schnorrsig::KeyPair) -> Self {
302+
pub fn from_keypair(keypair: &KeyPair) -> Self {
303303
unsafe {
304304
let mut pk = ffi::PublicKey::new();
305305
let ret = ffi::secp256k1_keypair_pub(
@@ -505,6 +505,175 @@ impl Ord for PublicKey {
505505
}
506506
}
507507

508+
/// Opaque data structure that holds a keypair consisting of a secret and a public key.
509+
#[derive(Clone)]
510+
pub struct KeyPair(ffi::KeyPair);
511+
impl_display_secret!(KeyPair);
512+
513+
impl KeyPair {
514+
/// Obtains a raw const pointer suitable for use with FFI functions
515+
#[inline]
516+
pub fn as_ptr(&self) -> *const ffi::KeyPair {
517+
&self.0
518+
}
519+
520+
/// Obtains a raw mutable pointer suitable for use with FFI functions
521+
#[inline]
522+
pub fn as_mut_ptr(&mut self) -> *mut ffi::KeyPair {
523+
&mut self.0
524+
}
525+
526+
/// Creates a Schnorr KeyPair directly from generic Secp256k1 secret key
527+
///
528+
/// # Panic
529+
///
530+
/// Panics if internal representation of the provided [`SecretKey`] does not hold correct secret
531+
/// key value obtained from Secp256k1 library previously, specifically when secret key value is
532+
/// out-of-range (0 or in excess of the group order).
533+
#[inline]
534+
pub fn from_secret_key<C: Signing>(
535+
secp: &Secp256k1<C>,
536+
sk: SecretKey,
537+
) -> KeyPair {
538+
unsafe {
539+
let mut kp = ffi::KeyPair::new();
540+
if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, sk.as_c_ptr()) == 1 {
541+
KeyPair(kp)
542+
} else {
543+
panic!("the provided secret key is invalid: it is corrupted or was not produced by Secp256k1 library")
544+
}
545+
}
546+
}
547+
548+
/// Creates a Schnorr KeyPair directly from a secret key slice.
549+
///
550+
/// # Errors
551+
///
552+
/// [`Error::InvalidSecretKey`] if the provided data has an incorrect length, exceeds Secp256k1
553+
/// field `p` value or the corresponding public key is not even.
554+
#[inline]
555+
pub fn from_seckey_slice<C: Signing>(
556+
secp: &Secp256k1<C>,
557+
data: &[u8],
558+
) -> Result<KeyPair, Error> {
559+
if data.is_empty() || data.len() != constants::SECRET_KEY_SIZE {
560+
return Err(Error::InvalidSecretKey);
561+
}
562+
563+
unsafe {
564+
let mut kp = ffi::KeyPair::new();
565+
if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, data.as_c_ptr()) == 1 {
566+
Ok(KeyPair(kp))
567+
} else {
568+
Err(Error::InvalidSecretKey)
569+
}
570+
}
571+
}
572+
573+
/// Creates a Schnorr KeyPair directly from a secret key string
574+
///
575+
/// # Errors
576+
///
577+
/// [`Error::InvalidSecretKey`] if corresponding public key for the provided secret key is not even.
578+
#[inline]
579+
pub fn from_seckey_str<C: Signing>(secp: &Secp256k1<C>, s: &str) -> Result<KeyPair, Error> {
580+
let mut res = [0u8; constants::SECRET_KEY_SIZE];
581+
match from_hex(s, &mut res) {
582+
Ok(constants::SECRET_KEY_SIZE) => {
583+
KeyPair::from_seckey_slice(secp, &res[0..constants::SECRET_KEY_SIZE])
584+
}
585+
_ => Err(Error::InvalidPublicKey),
586+
}
587+
}
588+
589+
/// Creates a new random secret key. Requires compilation with the "rand" feature.
590+
#[inline]
591+
#[cfg(any(test, feature = "rand"))]
592+
pub fn new<R: Rng + ?Sized, C: Signing>(secp: &Secp256k1<C>, rng: &mut R) -> KeyPair {
593+
let mut random_32_bytes = || {
594+
let mut ret = [0u8; 32];
595+
rng.fill_bytes(&mut ret);
596+
ret
597+
};
598+
let mut data = random_32_bytes();
599+
unsafe {
600+
let mut keypair = ffi::KeyPair::new();
601+
while ffi::secp256k1_keypair_create(secp.ctx, &mut keypair, data.as_c_ptr()) == 0 {
602+
data = random_32_bytes();
603+
}
604+
KeyPair(keypair)
605+
}
606+
}
607+
608+
/// Serialize the key pair as a secret key byte value
609+
#[inline]
610+
pub fn serialize_secret(&self) -> [u8; constants::SECRET_KEY_SIZE] {
611+
*SecretKey::from_keypair(self).as_ref()
612+
}
613+
614+
/// Tweak a keypair by adding the given tweak to the secret key and updating the public key
615+
/// accordingly.
616+
///
617+
/// Will return an error if the resulting key would be invalid or if the tweak was not a 32-byte
618+
/// length slice.
619+
///
620+
/// NB: Will not error if the tweaked public key has an odd value and can't be used for
621+
/// BIP 340-342 purposes.
622+
// TODO: Add checked implementation
623+
#[inline]
624+
pub fn tweak_add_assign<C: Verification>(
625+
&mut self,
626+
secp: &Secp256k1<C>,
627+
tweak: &[u8],
628+
) -> Result<(), Error> {
629+
if tweak.len() != 32 {
630+
return Err(Error::InvalidTweak);
631+
}
632+
633+
unsafe {
634+
let err = ffi::secp256k1_keypair_xonly_tweak_add(
635+
secp.ctx,
636+
&mut self.0,
637+
tweak.as_c_ptr(),
638+
);
639+
640+
if err == 1 {
641+
Ok(())
642+
} else {
643+
Err(Error::InvalidTweak)
644+
}
645+
}
646+
}
647+
}
648+
649+
impl From<KeyPair> for SecretKey {
650+
#[inline]
651+
fn from(pair: KeyPair) -> Self {
652+
SecretKey::from_keypair(&pair)
653+
}
654+
}
655+
656+
impl<'a> From<&'a KeyPair> for SecretKey {
657+
#[inline]
658+
fn from(pair: &'a KeyPair) -> Self {
659+
SecretKey::from_keypair(pair)
660+
}
661+
}
662+
663+
impl From<KeyPair> for PublicKey {
664+
#[inline]
665+
fn from(pair: KeyPair) -> Self {
666+
PublicKey::from_keypair(&pair)
667+
}
668+
}
669+
670+
impl<'a> From<&'a KeyPair> for PublicKey {
671+
#[inline]
672+
fn from(pair: &'a KeyPair) -> Self {
673+
PublicKey::from_keypair(pair)
674+
}
675+
}
676+
508677
#[cfg(test)]
509678
mod test {
510679
use Secp256k1;

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ mod serde_util;
155155
pub use key::SecretKey;
156156
pub use key::PublicKey;
157157
pub use key::ONE_KEY;
158+
pub use key::KeyPair;
158159
pub use context::*;
159160
use core::marker::PhantomData;
160161
use core::{mem, fmt, ptr, str};

0 commit comments

Comments
 (0)