diff --git a/secp256k1-sys/src/lib.rs b/secp256k1-sys/src/lib.rs index 330ca5b..974a60f 100644 --- a/secp256k1-sys/src/lib.rs +++ b/secp256k1-sys/src/lib.rs @@ -518,6 +518,20 @@ extern "C" { internal_pubkey: *const XOnlyPublicKey, tweak32: *const c_uchar, ) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_4_1_keypair_sec")] + pub fn secp256k1_keypair_sec( + cx: *const Context, + output_seckey: *mut c_uchar, + keypair: *const KeyPair + ) -> c_int; + + #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_4_1_keypair_pub")] + pub fn secp256k1_keypair_pub( + cx: *const Context, + output_pubkey: *mut PublicKey, + keypair: *const KeyPair + ) -> c_int; } /// A reimplementation of the C function `secp256k1_context_create` in rust. diff --git a/src/key.rs b/src/key.rs index 0491b8e..834137c 100644 --- a/src/key.rs +++ b/src/key.rs @@ -27,7 +27,7 @@ use constants; use ffi::{self, CPtr}; /// Secret 256-bit key used as `x` in an ECDSA signature -pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]); +pub struct SecretKey(pub(crate) [u8; constants::SECRET_KEY_SIZE]); impl_array_newtype!(SecretKey, u8, constants::SECRET_KEY_SIZE); impl_pretty_debug!(SecretKey); @@ -66,7 +66,7 @@ pub const ONE_KEY: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0, /// A Secp256k1 public key, used for verification of signatures #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[repr(transparent)] -pub struct PublicKey(ffi::PublicKey); +pub struct PublicKey(pub(crate) ffi::PublicKey); impl fmt::LowerHex for PublicKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/schnorrsig.rs b/src/schnorrsig.rs index ab3b6f4..d8c48a0 100644 --- a/src/schnorrsig.rs +++ b/src/schnorrsig.rs @@ -13,6 +13,7 @@ use core::{fmt, ptr, str}; use ffi::{self, CPtr}; use {constants, Secp256k1}; use {Message, Signing, Verification}; +use SecretKey; /// Represents a Schnorr signature. pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]); @@ -449,6 +450,38 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey { } } +impl SecretKey { + /// Creates a new secret key using data from BIP-340 [`KeyPair`] + pub fn from_keypair(secp: &Secp256k1, keypair: &KeyPair) -> Self { + let mut sk = [0; constants::SECRET_KEY_SIZE]; + unsafe { + let ret = ffi::secp256k1_keypair_sec( + secp.ctx, + sk.as_mut_c_ptr(), + keypair.as_ptr() + ); + debug_assert_eq!(ret, 1); + } + SecretKey(sk) + } +} + +impl ::key::PublicKey { + /// Creates a new compressed public key key using data from BIP-340 [`KeyPair`] + pub fn from_keypair(secp: &Secp256k1, keypair: &KeyPair) -> Self { + unsafe { + let mut pk = ffi::PublicKey::new(); + let ret = ffi::secp256k1_keypair_pub( + secp.ctx, + &mut pk, + keypair.as_ptr() + ); + debug_assert_eq!(ret, 1); + ::key::PublicKey(pk) + } + } +} + impl Secp256k1 { fn schnorrsig_sign_helper( &self, @@ -573,6 +606,7 @@ mod tests { #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; + use SecretKey; macro_rules! hex_32 { ($hex:expr) => {{ @@ -669,7 +703,7 @@ mod tests { } #[test] - fn pubkey_from_slice() { + fn test_pubkey_from_slice() { assert_eq!(PublicKey::from_slice(&[]), Err(InvalidPublicKey)); assert_eq!(PublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey)); let pk = PublicKey::from_slice(&[ @@ -681,7 +715,7 @@ mod tests { } #[test] - fn pubkey_serialize_roundtrip() { + fn test_pubkey_serialize_roundtrip() { let secp = Secp256k1::new(); let (_, pubkey) = secp.generate_schnorrsig_keypair(&mut thread_rng()); let ser = pubkey.serialize(); @@ -689,6 +723,19 @@ mod tests { assert_eq!(pubkey, pubkey2); } + #[test] + fn test_xonly_key_extraction() { + let secp = Secp256k1::new(); + let sk_str = "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF"; + let keypair = KeyPair::from_seckey_str(&secp, sk_str).unwrap(); + let sk = SecretKey::from_keypair(&secp, &keypair); + assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk); + let pk = ::key::PublicKey::from_keypair(&secp, &keypair); + assert_eq!(::key::PublicKey::from_secret_key(&secp, &sk), pk); + let xpk = PublicKey::from_keypair(&secp, &keypair); + assert_eq!(PublicKey::from(pk), xpk); + } + #[test] fn test_pubkey_from_bad_slice() { // Bad sizes