Merge rust-bitcoin/rust-secp256k1#430: Add convenience methods for keys
f08276adfc
Add convenience methods for keys (Tobin Harding)b4c7fa0d4e
Let the compiler work out int size (Tobin Harding)c612130864
Borrow secret key (Tobin Harding) Pull request description: We have a bunch of `from_<key>` methods for converting between key types. To make the API more ergonomic to use we can add methods that do the same but called on a variable e.g., once applied the following are equivalent: - `let pk = PublicKey::from_keypair(kp)` - `let pk = kp.public_key()` Do this for `SecretKey`, `PublicKey`, `KeyPair`, and `XOnlyKeyPair`. Fixes: #428 ### Note to reviewers - `XOnlyPublicKey` -> `PublicKey` logic is made up by me, I could not work out how to get `libsecp256k1` to do this. - Please review the tests carefully, they include assumptions based on my current understanding of the cryptography :) ACKs for top commit: sanket1729: ACKf08276adfc
. Thanks for going through all the iterations. apoelstra: ACKf08276adfc
Tree-SHA512: 1503a6e570a3958110c6f24cd6d075fe5694b3b32b91a7a9d332c63aa0806198ff10bdd95e7f9de0cf73cbf4e3655c6826bd04e5044d1b019f551471b187c8ea
This commit is contained in:
commit
a30e9bb9ff
265
src/key.rs
265
src/key.rs
|
@ -292,6 +292,31 @@ impl SecretKey {
|
||||||
pub fn sign_ecdsa(&self, msg: Message) -> ecdsa::Signature {
|
pub fn sign_ecdsa(&self, msg: Message) -> ecdsa::Signature {
|
||||||
SECP256K1.sign_ecdsa(&msg, self)
|
SECP256K1.sign_ecdsa(&msg, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`KeyPair`] for this [`SecretKey`].
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`KeyPair::from_secret_key`].
|
||||||
|
#[inline]
|
||||||
|
pub fn keypair<C: Signing>(&self, secp: &Secp256k1<C>) -> KeyPair {
|
||||||
|
KeyPair::from_secret_key(secp, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`PublicKey`] for this [`SecretKey`].
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`PublicKey::from_secret_key`].
|
||||||
|
#[inline]
|
||||||
|
pub fn public_key<C: Signing>(&self, secp: &Secp256k1<C>) -> PublicKey {
|
||||||
|
PublicKey::from_secret_key(secp, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`XOnlyPublicKey`] (and it's [`Parity`]) for this [`SecretKey`].
|
||||||
|
///
|
||||||
|
/// This is equivalent to `XOnlyPublicKey::from_keypair(self.keypair(secp))`.
|
||||||
|
#[inline]
|
||||||
|
pub fn x_only_public_key<C: Signing>(&self, secp: &Secp256k1<C>) -> (XOnlyPublicKey, Parity) {
|
||||||
|
let kp = self.keypair(secp);
|
||||||
|
XOnlyPublicKey::from_keypair(&kp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -418,6 +443,20 @@ impl PublicKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a [`PublicKey`] using the key material from `pk` combined with the `parity`.
|
||||||
|
pub fn from_x_only_public_key(pk: XOnlyPublicKey, parity: Parity) -> PublicKey {
|
||||||
|
let mut buf = [0u8; 33];
|
||||||
|
|
||||||
|
// First byte of a compressed key should be `0x02 AND parity`.
|
||||||
|
buf[0] = match parity {
|
||||||
|
Parity::Even => 0x02,
|
||||||
|
Parity::Odd => 0x03,
|
||||||
|
};
|
||||||
|
buf[1..].clone_from_slice(&pk.serialize());
|
||||||
|
|
||||||
|
PublicKey::from_slice(&buf).expect("we know the buffer is valid")
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Serializes the key as a byte-encoded pair of values. In compressed form the y-coordinate is
|
/// 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.
|
/// represented by only a single bit, as x determines it up to one bit.
|
||||||
|
@ -589,6 +628,25 @@ impl PublicKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`XOnlyPublicKey`] (and it's [`Parity`]) for this [`PublicKey`].
|
||||||
|
#[inline]
|
||||||
|
pub fn x_only_public_key(&self) -> (XOnlyPublicKey, Parity) {
|
||||||
|
let mut pk_parity = 0;
|
||||||
|
unsafe {
|
||||||
|
let mut xonly_pk = ffi::XOnlyPublicKey::new();
|
||||||
|
let ret = ffi::secp256k1_xonly_pubkey_from_pubkey(
|
||||||
|
ffi::secp256k1_context_no_precomp,
|
||||||
|
&mut xonly_pk,
|
||||||
|
&mut pk_parity,
|
||||||
|
self.as_ptr(),
|
||||||
|
);
|
||||||
|
debug_assert_eq!(ret, 1);
|
||||||
|
let parity = Parity::from_i32(pk_parity).expect("should not panic, pk_parity is 0 or 1");
|
||||||
|
|
||||||
|
(XOnlyPublicKey(xonly_pk), parity)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CPtr for PublicKey {
|
impl CPtr for PublicKey {
|
||||||
|
@ -674,7 +732,7 @@ impl Ord for PublicKey {
|
||||||
///
|
///
|
||||||
/// let secp = Secp256k1::new();
|
/// let secp = Secp256k1::new();
|
||||||
/// let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng());
|
/// let (secret_key, public_key) = secp.generate_keypair(&mut rand::thread_rng());
|
||||||
/// let key_pair = KeyPair::from_secret_key(&secp, secret_key);
|
/// let key_pair = KeyPair::from_secret_key(&secp, &secret_key);
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
/// [`Deserialize`]: serde::Deserialize
|
/// [`Deserialize`]: serde::Deserialize
|
||||||
|
@ -700,7 +758,7 @@ impl KeyPair {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_secret_key<C: Signing>(
|
pub fn from_secret_key<C: Signing>(
|
||||||
secp: &Secp256k1<C>,
|
secp: &Secp256k1<C>,
|
||||||
sk: SecretKey,
|
sk: &SecretKey,
|
||||||
) -> KeyPair {
|
) -> KeyPair {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut kp = ffi::KeyPair::new();
|
let mut kp = ffi::KeyPair::new();
|
||||||
|
@ -860,9 +918,27 @@ impl KeyPair {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the [XOnlyPublicKey] for this [KeyPair].
|
/// Returns the [`SecretKey`] for this [`KeyPair`].
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`SecretKey::from_keypair`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn public_key(&self) -> XOnlyPublicKey {
|
pub fn secret_key(&self) -> SecretKey {
|
||||||
|
SecretKey::from_keypair(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`PublicKey`] for this [`KeyPair`].
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`PublicKey::from_keypair`].
|
||||||
|
#[inline]
|
||||||
|
pub fn public_key(&self) -> PublicKey {
|
||||||
|
PublicKey::from_keypair(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`XOnlyPublicKey`] (and it's [`Parity`]) for this [`KeyPair`].
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`XOnlyPublicKey::from_keypair`].
|
||||||
|
#[inline]
|
||||||
|
pub fn x_only_public_key(&self) -> (XOnlyPublicKey, Parity) {
|
||||||
XOnlyPublicKey::from_keypair(self)
|
XOnlyPublicKey::from_keypair(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,9 +1084,9 @@ impl XOnlyPublicKey {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new Schnorr public key from a Schnorr key pair.
|
/// Returns the [`XOnlyPublicKey`] (and it's [`Parity`]) for `keypair`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_keypair(keypair: &KeyPair) -> XOnlyPublicKey {
|
pub fn from_keypair(keypair: &KeyPair) -> (XOnlyPublicKey, Parity) {
|
||||||
let mut pk_parity = 0;
|
let mut pk_parity = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut xonly_pk = ffi::XOnlyPublicKey::new();
|
let mut xonly_pk = ffi::XOnlyPublicKey::new();
|
||||||
|
@ -1021,7 +1097,9 @@ impl XOnlyPublicKey {
|
||||||
keypair.as_ptr(),
|
keypair.as_ptr(),
|
||||||
);
|
);
|
||||||
debug_assert_eq!(ret, 1);
|
debug_assert_eq!(ret, 1);
|
||||||
XOnlyPublicKey(xonly_pk)
|
let parity = Parity::from_i32(pk_parity).expect("should not panic, pk_parity is 0 or 1");
|
||||||
|
|
||||||
|
(XOnlyPublicKey(xonly_pk), parity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1092,7 +1170,7 @@ impl XOnlyPublicKey {
|
||||||
/// thread_rng().fill_bytes(&mut tweak);
|
/// thread_rng().fill_bytes(&mut tweak);
|
||||||
///
|
///
|
||||||
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
||||||
/// let mut public_key = key_pair.public_key();
|
/// let (mut public_key, _parity) = key_pair.x_only_public_key();
|
||||||
/// public_key.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
|
/// public_key.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -1105,6 +1183,7 @@ impl XOnlyPublicKey {
|
||||||
return Err(Error::InvalidTweak);
|
return Err(Error::InvalidTweak);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut pk_parity = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut pubkey = ffi::PublicKey::new();
|
let mut pubkey = ffi::PublicKey::new();
|
||||||
let mut err = ffi::secp256k1_xonly_pubkey_tweak_add(
|
let mut err = ffi::secp256k1_xonly_pubkey_tweak_add(
|
||||||
|
@ -1117,18 +1196,17 @@ impl XOnlyPublicKey {
|
||||||
return Err(Error::InvalidTweak);
|
return Err(Error::InvalidTweak);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parity: ::secp256k1_sys::types::c_int = 0;
|
|
||||||
err = ffi::secp256k1_xonly_pubkey_from_pubkey(
|
err = ffi::secp256k1_xonly_pubkey_from_pubkey(
|
||||||
secp.ctx,
|
secp.ctx,
|
||||||
&mut self.0,
|
&mut self.0,
|
||||||
&mut parity,
|
&mut pk_parity,
|
||||||
&pubkey,
|
&pubkey,
|
||||||
);
|
);
|
||||||
if err == 0 {
|
if err == 0 {
|
||||||
return Err(Error::InvalidPublicKey);
|
return Err(Error::InvalidPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parity::from_i32(parity).map_err(Into::into)
|
Parity::from_i32(pk_parity).map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1157,7 +1235,7 @@ impl XOnlyPublicKey {
|
||||||
/// thread_rng().fill_bytes(&mut tweak);
|
/// thread_rng().fill_bytes(&mut tweak);
|
||||||
///
|
///
|
||||||
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
/// let mut key_pair = KeyPair::new(&secp, &mut thread_rng());
|
||||||
/// let mut public_key = key_pair.public_key();
|
/// let (mut public_key, _) = key_pair.x_only_public_key();
|
||||||
/// let original = public_key;
|
/// let original = public_key;
|
||||||
/// let parity = public_key.tweak_add_assign(&secp, &tweak).expect("Improbable to fail with a randomly generated tweak");
|
/// 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));
|
/// assert!(original.tweak_add_check(&secp, &public_key, parity, tweak));
|
||||||
|
@ -1183,6 +1261,14 @@ impl XOnlyPublicKey {
|
||||||
err == 1
|
err == 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [`PublicKey`] for this [`XOnlyPublicKey`].
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`PublicKey::from_xonly_and_parity(self, parity)`].
|
||||||
|
#[inline]
|
||||||
|
pub fn public_key(&self, parity: Parity) -> PublicKey {
|
||||||
|
PublicKey::from_x_only_public_key(*self, parity)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the parity passed between FFI function calls.
|
/// Represents the parity passed between FFI function calls.
|
||||||
|
@ -1420,7 +1506,7 @@ pub mod serde_keypair {
|
||||||
|
|
||||||
Ok(KeyPair::from_secret_key(
|
Ok(KeyPair::from_secret_key(
|
||||||
&::SECP256K1,
|
&::SECP256K1,
|
||||||
secret_key,
|
&secret_key,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1972,12 +2058,15 @@ mod test {
|
||||||
thread_rng().fill_bytes(&mut tweak);
|
thread_rng().fill_bytes(&mut tweak);
|
||||||
|
|
||||||
let mut kp = KeyPair::new(&s, &mut thread_rng());
|
let mut kp = KeyPair::new(&s, &mut thread_rng());
|
||||||
let mut pk = kp.public_key();
|
let (mut pk, _parity) = kp.x_only_public_key();
|
||||||
|
|
||||||
let orig_pk = pk;
|
let orig_pk = pk;
|
||||||
kp.tweak_add_assign(&s, &tweak).expect("Tweak error");
|
kp.tweak_add_assign(&s, &tweak).expect("Tweak error");
|
||||||
let parity = pk.tweak_add_assign(&s, &tweak).expect("Tweak error");
|
let parity = pk.tweak_add_assign(&s, &tweak).expect("Tweak error");
|
||||||
assert_eq!(XOnlyPublicKey::from_keypair(&kp), pk);
|
|
||||||
|
let (back, _) = XOnlyPublicKey::from_keypair(&kp);
|
||||||
|
|
||||||
|
assert_eq!(back, pk);
|
||||||
assert!(orig_pk.tweak_add_check(&s, &pk, parity, tweak));
|
assert!(orig_pk.tweak_add_check(&s, &pk, parity, tweak));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2046,4 +2135,150 @@ mod test {
|
||||||
assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]);
|
assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]);
|
||||||
assert_tokens(&sk.readable(), &[Token::String(SK_STR)]);
|
assert_tokens(&sk.readable(), &[Token::String(SK_STR)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn keys() -> (SecretKey, PublicKey, KeyPair, XOnlyPublicKey) {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
|
||||||
|
static SK_BYTES: [u8; 32] = [
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
|
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
|
||||||
|
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
|
||||||
|
];
|
||||||
|
|
||||||
|
static PK_BYTES: [u8; 32] = [
|
||||||
|
0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f,
|
||||||
|
0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d,
|
||||||
|
0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54,
|
||||||
|
0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut pk_bytes = [0u8; 33];
|
||||||
|
pk_bytes[0] = 0x02; // Use positive Y co-ordinate.
|
||||||
|
pk_bytes[1..].clone_from_slice(&PK_BYTES);
|
||||||
|
|
||||||
|
let sk = SecretKey::from_slice(&SK_BYTES).expect("failed to parse sk bytes");
|
||||||
|
let pk = PublicKey::from_slice(&pk_bytes).expect("failed to create pk from iterator");
|
||||||
|
let kp = KeyPair::from_secret_key(&secp, &sk);
|
||||||
|
let xonly = XOnlyPublicKey::from_slice(&PK_BYTES).expect("failed to get xonly from slice");
|
||||||
|
|
||||||
|
(sk, pk, kp, xonly)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn convert_public_key_to_xonly_public_key() {
|
||||||
|
let (_sk, pk, _kp, want) = keys();
|
||||||
|
let (got, parity) = pk.x_only_public_key();
|
||||||
|
|
||||||
|
assert_eq!(parity, Parity::Even);
|
||||||
|
assert_eq!(got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn convert_secret_key_to_public_key() {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
|
||||||
|
let (sk, want, _kp, _xonly) = keys();
|
||||||
|
let got = sk.public_key(&secp);
|
||||||
|
|
||||||
|
assert_eq!(got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn convert_secret_key_to_x_only_public_key() {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
|
||||||
|
let (sk, _pk, _kp, want) = keys();
|
||||||
|
let (got, parity) = sk.x_only_public_key(&secp);
|
||||||
|
|
||||||
|
assert_eq!(parity, Parity::Even);
|
||||||
|
assert_eq!(got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn convert_keypair_to_public_key() {
|
||||||
|
let (_sk, want, kp, _xonly) = keys();
|
||||||
|
let got = kp.public_key();
|
||||||
|
|
||||||
|
assert_eq!(got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn convert_keypair_to_x_only_public_key() {
|
||||||
|
let (_sk, _pk, kp, want) = keys();
|
||||||
|
let (got, parity) = kp.x_only_public_key();
|
||||||
|
|
||||||
|
assert_eq!(parity, Parity::Even);
|
||||||
|
assert_eq!(got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretKey -> KeyPair -> SecretKey
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn roundtrip_secret_key_via_keypair() {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
let (sk, _pk, _kp, _xonly) = keys();
|
||||||
|
|
||||||
|
let kp = sk.keypair(&secp);
|
||||||
|
let back = kp.secret_key();
|
||||||
|
|
||||||
|
assert_eq!(back, sk)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyPair -> SecretKey -> KeyPair
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn roundtrip_keypair_via_secret_key() {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
let (_sk, _pk, kp, _xonly) = keys();
|
||||||
|
|
||||||
|
let sk = kp.secret_key();
|
||||||
|
let back = sk.keypair(&secp);
|
||||||
|
|
||||||
|
assert_eq!(back, kp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOnlyPublicKey -> PublicKey -> XOnlyPublicKey
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn roundtrip_x_only_public_key_via_public_key() {
|
||||||
|
let (_sk, _pk, _kp, xonly) = keys();
|
||||||
|
|
||||||
|
let pk = xonly.public_key(Parity::Even);
|
||||||
|
let (back, parity) = pk.x_only_public_key();
|
||||||
|
|
||||||
|
assert_eq!(parity, Parity::Even);
|
||||||
|
assert_eq!(back, xonly)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKey -> XOnlyPublicKey -> PublicKey
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(not(fuzzing), any(feature = "alloc", feature = "std")))]
|
||||||
|
fn roundtrip_public_key_via_x_only_public_key() {
|
||||||
|
let (_sk, pk, _kp, _xonly) = keys();
|
||||||
|
|
||||||
|
let (xonly, parity) = pk.x_only_public_key();
|
||||||
|
let back = xonly.public_key(parity);
|
||||||
|
|
||||||
|
assert_eq!(back, pk)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn public_key_from_x_only_public_key_and_odd_parity() {
|
||||||
|
let s = "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166";
|
||||||
|
let mut want = String::from("03");
|
||||||
|
want.push_str(s);
|
||||||
|
|
||||||
|
let xonly = XOnlyPublicKey::from_str(s).expect("failed to parse xonly pubkey string");
|
||||||
|
let pk = xonly.public_key(Parity::Odd);
|
||||||
|
let got = format!("{}", pk);
|
||||||
|
|
||||||
|
assert_eq!(got, want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,7 @@ impl <C: Signing> Secp256k1<C> {
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> (KeyPair, XOnlyPublicKey) {
|
) -> (KeyPair, XOnlyPublicKey) {
|
||||||
let sk = KeyPair::new(self, rng);
|
let sk = KeyPair::new(self, rng);
|
||||||
let pubkey = XOnlyPublicKey::from_keypair(&sk);
|
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&sk);
|
||||||
(sk, pubkey)
|
(sk, pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ mod tests {
|
||||||
|
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
let kp = KeyPair::new(&secp, &mut rng);
|
let kp = KeyPair::new(&secp, &mut rng);
|
||||||
let pk = kp.public_key();
|
let (pk, _parity) = kp.x_only_public_key();
|
||||||
|
|
||||||
let mut msg = [0u8; 32];
|
let mut msg = [0u8; 32];
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ mod tests {
|
||||||
fn test_pubkey_serialize_roundtrip() {
|
fn test_pubkey_serialize_roundtrip() {
|
||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let kp = KeyPair::new(&secp, &mut thread_rng());
|
let kp = KeyPair::new(&secp, &mut thread_rng());
|
||||||
let pk = kp.public_key();
|
let (pk, _parity) = kp.x_only_public_key();
|
||||||
|
|
||||||
let ser = pk.serialize();
|
let ser = pk.serialize();
|
||||||
let pubkey2 = XOnlyPublicKey::from_slice(&ser).unwrap();
|
let pubkey2 = XOnlyPublicKey::from_slice(&ser).unwrap();
|
||||||
|
@ -431,7 +431,7 @@ mod tests {
|
||||||
assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk);
|
assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk);
|
||||||
let pk = ::key::PublicKey::from_keypair(&keypair);
|
let pk = ::key::PublicKey::from_keypair(&keypair);
|
||||||
assert_eq!(::key::PublicKey::from_secret_key(&secp, &sk), pk);
|
assert_eq!(::key::PublicKey::from_secret_key(&secp, &sk), pk);
|
||||||
let xpk = keypair.public_key();
|
let (xpk, _parity) = keypair.x_only_public_key();
|
||||||
assert_eq!(XOnlyPublicKey::from(pk), xpk);
|
assert_eq!(XOnlyPublicKey::from(pk), xpk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +478,8 @@ mod tests {
|
||||||
|
|
||||||
// In fuzzing mode secret->public key derivation is different, so
|
// In fuzzing mode secret->public key derivation is different, so
|
||||||
// hard-code the expected result.
|
// hard-code the expected result.
|
||||||
kp.public_key()
|
let (pk, _parity) = kp.x_only_public_key();
|
||||||
|
pk
|
||||||
};
|
};
|
||||||
#[cfg(fuzzing)]
|
#[cfg(fuzzing)]
|
||||||
let pk = XOnlyPublicKey::from_slice(&[0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66]).expect("pk");
|
let pk = XOnlyPublicKey::from_slice(&[0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92, 0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe, 0x91, 0xdd, 0xd1, 0x66]).expect("pk");
|
||||||
|
@ -544,7 +545,7 @@ mod tests {
|
||||||
|
|
||||||
let secp = Secp256k1::new();
|
let secp = Secp256k1::new();
|
||||||
let kp = KeyPair::new(&secp, &mut DumbRng(0));
|
let kp = KeyPair::new(&secp, &mut DumbRng(0));
|
||||||
let pk = kp.public_key();
|
let (pk, _parity) = kp.x_only_public_key();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&pk.serialize()[..],
|
&pk.serialize()[..],
|
||||||
&[
|
&[
|
||||||
|
|
|
@ -160,7 +160,7 @@ impl KeyPair {
|
||||||
///
|
///
|
||||||
/// let secp = Secp256k1::new();
|
/// let secp = Secp256k1::new();
|
||||||
/// let key = ONE_KEY;
|
/// let key = ONE_KEY;
|
||||||
/// let key = KeyPair::from_secret_key(&secp, key);
|
/// let key = KeyPair::from_secret_key(&secp, &key);
|
||||||
/// // Here we explicitly display the secret value:
|
/// // Here we explicitly display the secret value:
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// "0000000000000000000000000000000000000000000000000000000000000001",
|
/// "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
|
Loading…
Reference in New Issue