Skip to content

Commit c16582e

Browse files
committed
Add serde impl for KeyPair
The impl is added as a module instead of being a direct implementation since it uses the global context and users should be aware that.
1 parent 045896d commit c16582e

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

src/key.rs

+98
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,18 @@ impl Ord for PublicKey {
511511
}
512512

513513
/// Opaque data structure that holds a keypair consisting of a secret and a public key.
514+
///
515+
/// # Serde support
516+
/// [`Serialize`] and [`Deserialize`] are not implemented for this type, even with the `serde`
517+
/// feature active. This is due to security considerations, see the [`serde_keypair`] documentation
518+
/// for details.
519+
///
520+
/// If the `serde` and `global-context[-less-secure]` features are active `KeyPair`s can be serialized and
521+
/// deserialized by annotating them with `#[serde(with = "secp256k1::serde_keypair")]`
522+
/// inside structs or enums for which [`Serialize`] and [`Deserialize`] are being derived.
523+
///
524+
/// [`Deserialize`]: serde::Deserialize
525+
/// [`Serialize`]: serde::Serialize
514526
// Should secrets implement Copy: https://github.com/rust-bitcoin/rust-secp256k1/issues/363
515527
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
516528
pub struct KeyPair(ffi::KeyPair);
@@ -1031,6 +1043,45 @@ impl<'de> ::serde::Deserialize<'de> for XOnlyPublicKey {
10311043
}
10321044
}
10331045

1046+
/// Serde implementation for the [`KeyPair`] type.
1047+
///
1048+
/// Only the secret key part of the [`KeyPair`] is serialized using the [`SecretKey`] serde
1049+
/// implementation, meaning the public key has to be regenerated on deserialization.
1050+
///
1051+
/// **Attention:** The deserialization algorithm uses the [global context] to generate the public key
1052+
/// belonging to the secret key to form a [`KeyPair`]. The typical caveats regarding use of the
1053+
/// [global context] with secret data apply.
1054+
///
1055+
/// [`SecretKey`]: crate::SecretKey
1056+
/// [global context]: crate::SECP256K1
1057+
#[cfg(all(feature = "global-context-less-secure", feature = "serde"))]
1058+
pub mod serde_keypair {
1059+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1060+
use key::KeyPair;
1061+
use key::SecretKey;
1062+
1063+
#[allow(missing_docs)]
1064+
pub fn serialize<S>(key: &KeyPair, serializer: S) -> Result<S::Ok, S::Error>
1065+
where
1066+
S: Serializer,
1067+
{
1068+
SecretKey::from_keypair(key).serialize(serializer)
1069+
}
1070+
1071+
#[allow(missing_docs)]
1072+
pub fn deserialize<'de, D>(deserializer: D) -> Result<KeyPair, D::Error>
1073+
where
1074+
D: Deserializer<'de>,
1075+
{
1076+
let secret_key = SecretKey::deserialize(deserializer)?;
1077+
1078+
Ok(KeyPair::from_secret_key(
1079+
&crate::SECP256K1,
1080+
secret_key,
1081+
))
1082+
}
1083+
}
1084+
10341085
#[cfg(test)]
10351086
mod test {
10361087
use super::*;
@@ -1582,4 +1633,51 @@ mod test {
15821633
assert_eq!(pk1.serialize()[..], kpk1.serialize()[1..]);
15831634
assert_eq!(pk2.serialize()[..], kpk2.serialize()[1..]);
15841635
}
1636+
1637+
#[test]
1638+
#[cfg(all(feature = "global-context-less-secure", feature = "serde"))]
1639+
fn test_serde_keypair() {
1640+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1641+
use serde_test::{Configure, Token, assert_tokens};
1642+
use super::serde_keypair;
1643+
use key::KeyPair;
1644+
1645+
// Normally users would derive the serde traits, but we can't easily enable the serde macros
1646+
// here, so they are implemented manually to be able to test the behaviour.
1647+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1648+
struct KeyPairWrapper(KeyPair);
1649+
1650+
impl<'de> Deserialize<'de> for KeyPairWrapper {
1651+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1652+
where D: Deserializer<'de> {
1653+
serde_keypair::deserialize(deserializer).map(KeyPairWrapper)
1654+
}
1655+
}
1656+
1657+
impl Serialize for KeyPairWrapper {
1658+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
1659+
serde_keypair::serialize(&self.0, serializer)
1660+
}
1661+
}
1662+
1663+
static SK_BYTES: [u8; 32] = [
1664+
1, 1, 1, 1, 1, 1, 1, 1,
1665+
0, 1, 2, 3, 4, 5, 6, 7,
1666+
0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0,
1667+
99, 99, 99, 99, 99, 99, 99, 99
1668+
];
1669+
static SK_STR: &'static str = "\
1670+
01010101010101010001020304050607ffff0000ffff00006363636363636363\
1671+
";
1672+
1673+
let sk = KeyPairWrapper(KeyPair::from_seckey_slice(&crate::SECP256K1, &SK_BYTES).unwrap());
1674+
1675+
assert_tokens(&sk.compact(), &[Token::BorrowedBytes(&SK_BYTES[..])]);
1676+
assert_tokens(&sk.compact(), &[Token::Bytes(&SK_BYTES)]);
1677+
assert_tokens(&sk.compact(), &[Token::ByteBuf(&SK_BYTES)]);
1678+
1679+
assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]);
1680+
assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]);
1681+
assert_tokens(&sk.readable(), &[Token::String(SK_STR)]);
1682+
}
15851683
}

0 commit comments

Comments
 (0)