Skip to content

Commit 6842383

Browse files
committed
Use fixed width serde impls for keys
Currently we serialize keys using the `BytesVisitor`, this causes the serialized data to contain additional metadata encoding the length (an extra 8 bytes) when serialized with the `bincode` crate. This extra data is unnecessary since we know in advance the length of these types. It would be useful for users of the lib to be able to get a fixed width binary serialization, this can be done but it depends on the crate used to do the serialization. We elect to optimise for `bincode` and add docs noting that other binary serialization crates may differ (rustdocs added in separate patches). Implement a tuple based visitor that encodes the keys as fixed width data. Do fixed width serde implementations for: - `SecretKey` - `PublicKey` - `KeyPair` - `XOnlyPublicKey`
1 parent 4f7f138 commit 6842383

File tree

3 files changed

+159
-27
lines changed

3 files changed

+159
-27
lines changed

src/key.rs

Lines changed: 98 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey
2525
use crate::ffi::{self, CPtr, impl_array_newtype};
2626
use crate::ffi::types::c_uint;
2727

28+
#[cfg(feature = "serde")]
29+
use serde::ser::SerializeTuple;
30+
2831
#[cfg(feature = "global-context")]
2932
use crate::{Message, ecdsa, SECP256K1};
3033
#[cfg(all(feature = "global-context", feature = "rand-std"))]
@@ -322,7 +325,11 @@ impl serde::Serialize for SecretKey {
322325
let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2];
323326
s.serialize_str(crate::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
324327
} else {
325-
s.serialize_bytes(&self[..])
328+
let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?;
329+
for byte in self.0.iter() {
330+
tuple.serialize_element(byte)?;
331+
}
332+
tuple.end()
326333
}
327334
}
328335
}
@@ -336,10 +343,11 @@ impl<'de> serde::Deserialize<'de> for SecretKey {
336343
"a hex string representing 32 byte SecretKey"
337344
))
338345
} else {
339-
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
346+
let visitor = super::serde_util::Tuple32Visitor::new(
340347
"raw 32 bytes SecretKey",
341348
SecretKey::from_slice
342-
))
349+
);
350+
d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor)
343351
}
344352
}
345353
}
@@ -664,7 +672,11 @@ impl serde::Serialize for PublicKey {
664672
if s.is_human_readable() {
665673
s.collect_str(self)
666674
} else {
667-
s.serialize_bytes(&self.serialize())
675+
let mut tuple = s.serialize_tuple(constants::PUBLIC_KEY_SIZE)?;
676+
for byte in self.serialize().iter() { // Serialize in compressed form.
677+
tuple.serialize_element(&byte)?;
678+
}
679+
tuple.end()
668680
}
669681
}
670682
}
@@ -678,10 +690,11 @@ impl<'de> serde::Deserialize<'de> for PublicKey {
678690
"an ASCII hex string representing a public key"
679691
))
680692
} else {
681-
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
682-
"a bytestring representing a public key",
693+
let visitor = super::serde_util::Tuple33Visitor::new(
694+
"33 bytes compressed public key",
683695
PublicKey::from_slice
684-
))
696+
);
697+
d.deserialize_tuple(constants::PUBLIC_KEY_SIZE, visitor)
685698
}
686699
}
687700
}
@@ -987,7 +1000,11 @@ impl serde::Serialize for KeyPair {
9871000
s.serialize_str(crate::to_hex(&self.secret_bytes(), &mut buf)
9881001
.expect("fixed-size hex serialization"))
9891002
} else {
990-
s.serialize_bytes(&self.0[..])
1003+
let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?;
1004+
for byte in self.secret_bytes().iter() {
1005+
tuple.serialize_element(&byte)?;
1006+
}
1007+
tuple.end()
9911008
}
9921009
}
9931010
}
@@ -1001,13 +1018,14 @@ impl<'de> serde::Deserialize<'de> for KeyPair {
10011018
"a hex string representing 32 byte KeyPair"
10021019
))
10031020
} else {
1004-
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
1021+
let visitor = super::serde_util::Tuple32Visitor::new(
10051022
"raw 32 bytes KeyPair",
10061023
|data| unsafe {
10071024
let ctx = Secp256k1::from_raw_all(ffi::secp256k1_context_no_precomp as *mut ffi::Context);
10081025
KeyPair::from_seckey_slice(&ctx, data)
10091026
}
1010-
))
1027+
);
1028+
d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor)
10111029
}
10121030
}
10131031
}
@@ -1438,7 +1456,11 @@ impl serde::Serialize for XOnlyPublicKey {
14381456
if s.is_human_readable() {
14391457
s.collect_str(self)
14401458
} else {
1441-
s.serialize_bytes(&self.serialize())
1459+
let mut tuple = s.serialize_tuple(constants::SCHNORR_PUBLIC_KEY_SIZE)?;
1460+
for byte in self.serialize().iter() {
1461+
tuple.serialize_element(&byte)?;
1462+
}
1463+
tuple.end()
14421464
}
14431465
}
14441466
}
@@ -1452,10 +1474,11 @@ impl<'de> serde::Deserialize<'de> for XOnlyPublicKey {
14521474
"a hex string representing 32 byte schnorr public key"
14531475
))
14541476
} else {
1455-
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
1477+
let visitor = super::serde_util::Tuple32Visitor::new(
14561478
"raw 32 bytes schnorr public key",
14571479
XOnlyPublicKey::from_slice
1458-
))
1480+
);
1481+
d.deserialize_tuple(constants::SCHNORR_PUBLIC_KEY_SIZE, visitor)
14591482
}
14601483
}
14611484
}
@@ -1501,6 +1524,8 @@ pub mod serde_keypair {
15011524
#[cfg(test)]
15021525
#[allow(unused_imports)]
15031526
mod test {
1527+
use super::*;
1528+
15041529
use core::str::FromStr;
15051530

15061531
#[cfg(any(feature = "alloc", feature = "std"))]
@@ -1953,6 +1978,7 @@ mod test {
19531978
static SK_STR: &'static str = "\
19541979
01010101010101010001020304050607ffff0000ffff00006363636363636363\
19551980
";
1981+
#[cfg(fuzzing)]
19561982
static PK_BYTES: [u8; 33] = [
19571983
0x02,
19581984
0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f,
@@ -1975,22 +2001,32 @@ mod test {
19752001
#[cfg(fuzzing)]
19762002
let pk = PublicKey::from_slice(&PK_BYTES).expect("pk");
19772003

1978-
assert_tokens(&sk.compact(), &[Token::BorrowedBytes(&SK_BYTES[..])]);
1979-
assert_tokens(&sk.compact(), &[Token::Bytes(&SK_BYTES)]);
1980-
assert_tokens(&sk.compact(), &[Token::ByteBuf(&SK_BYTES)]);
2004+
assert_tokens(&sk.compact(), &[
2005+
Token::Tuple{ len: 32 },
2006+
Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1),
2007+
Token::U8(0), Token::U8(1), Token::U8(2), Token::U8(3), Token::U8(4), Token::U8(5), Token::U8(6), Token::U8(7),
2008+
Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0), Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0),
2009+
Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99),
2010+
Token::TupleEnd
2011+
]);
19812012

19822013
assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]);
19832014
assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]);
19842015
assert_tokens(&sk.readable(), &[Token::String(SK_STR)]);
19852016

1986-
assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]);
1987-
assert_tokens(&pk.compact(), &[Token::Bytes(&PK_BYTES)]);
1988-
assert_tokens(&pk.compact(), &[Token::ByteBuf(&PK_BYTES)]);
2017+
assert_tokens(&pk.compact(), &[
2018+
Token::Tuple{ len: 33 },
2019+
Token::U8(0x02),
2020+
Token::U8(0x18), Token::U8(0x84), Token::U8(0x57), Token::U8(0x81), Token::U8(0xf6), Token::U8(0x31), Token::U8(0xc4), Token::U8(0x8f),
2021+
Token::U8(0x1c), Token::U8(0x97), Token::U8(0x09), Token::U8(0xe2), Token::U8(0x30), Token::U8(0x92), Token::U8(0x06), Token::U8(0x7d),
2022+
Token::U8(0x06), Token::U8(0x83), Token::U8(0x7f), Token::U8(0x30), Token::U8(0xaa), Token::U8(0x0c), Token::U8(0xd0), Token::U8(0x54),
2023+
Token::U8(0x4a), Token::U8(0xc8), Token::U8(0x87), Token::U8(0xfe), Token::U8(0x91), Token::U8(0xdd), Token::U8(0xd1), Token::U8(0x66),
2024+
Token::TupleEnd
2025+
]);
19892026

19902027
assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]);
19912028
assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]);
19922029
assert_tokens(&pk.readable(), &[Token::String(PK_STR)]);
1993-
19942030
}
19952031

19962032
#[test]
@@ -2071,10 +2107,14 @@ mod test {
20712107
";
20722108

20732109
let sk = KeyPairWrapper(KeyPair::from_seckey_slice(&crate::SECP256K1, &SK_BYTES).unwrap());
2074-
2075-
assert_tokens(&sk.compact(), &[Token::BorrowedBytes(&SK_BYTES[..])]);
2076-
assert_tokens(&sk.compact(), &[Token::Bytes(&SK_BYTES)]);
2077-
assert_tokens(&sk.compact(), &[Token::ByteBuf(&SK_BYTES)]);
2110+
assert_tokens(&sk.compact(), &[
2111+
Token::Tuple{ len: 32 },
2112+
Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1), Token::U8(1),
2113+
Token::U8(0), Token::U8(1), Token::U8(2), Token::U8(3), Token::U8(4), Token::U8(5), Token::U8(6), Token::U8(7),
2114+
Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0), Token::U8(0xff), Token::U8(0xff), Token::U8(0), Token::U8(0),
2115+
Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99), Token::U8(99),
2116+
Token::TupleEnd
2117+
]);
20782118

20792119
assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]);
20802120
assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]);
@@ -2226,4 +2266,38 @@ mod test {
22262266

22272267
assert_eq!(got, want)
22282268
}
2269+
2270+
#[test]
2271+
#[cfg(not(fuzzing))]
2272+
#[cfg(all(feature = "global-context", feature = "serde"))]
2273+
fn test_serde_x_only_pubkey() {
2274+
use serde_test::{Configure, Token, assert_tokens};
2275+
2276+
static SK_BYTES: [u8; 32] = [
2277+
1, 1, 1, 1, 1, 1, 1, 1,
2278+
0, 1, 2, 3, 4, 5, 6, 7,
2279+
0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0,
2280+
99, 99, 99, 99, 99, 99, 99, 99
2281+
];
2282+
2283+
static PK_STR: &'static str = "\
2284+
18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\
2285+
";
2286+
2287+
let kp = KeyPair::from_seckey_slice(&crate::SECP256K1, &SK_BYTES).unwrap();
2288+
let (pk, _parity) = XOnlyPublicKey::from_keypair(&kp);
2289+
2290+
assert_tokens(&pk.compact(), &[
2291+
Token::Tuple{ len: 32 },
2292+
Token::U8(0x18), Token::U8(0x84), Token::U8(0x57), Token::U8(0x81), Token::U8(0xf6), Token::U8(0x31), Token::U8(0xc4), Token::U8(0x8f),
2293+
Token::U8(0x1c), Token::U8(0x97), Token::U8(0x09), Token::U8(0xe2), Token::U8(0x30), Token::U8(0x92), Token::U8(0x06), Token::U8(0x7d),
2294+
Token::U8(0x06), Token::U8(0x83), Token::U8(0x7f), Token::U8(0x30), Token::U8(0xaa), Token::U8(0x0c), Token::U8(0xd0), Token::U8(0x54),
2295+
Token::U8(0x4a), Token::U8(0xc8), Token::U8(0x87), Token::U8(0xfe), Token::U8(0x91), Token::U8(0xdd), Token::U8(0xd1), Token::U8(0x66),
2296+
Token::TupleEnd
2297+
]);
2298+
2299+
assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]);
2300+
assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]);
2301+
assert_tokens(&pk.readable(), &[Token::String(PK_STR)]);
2302+
}
22292303
}

src/schnorr.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,14 @@ mod tests {
569569
assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]);
570570
assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]);
571571

572-
assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]);
573-
assert_tokens(&pk.compact(), &[Token::Bytes(&PK_BYTES[..])]);
574-
assert_tokens(&pk.compact(), &[Token::ByteBuf(&PK_BYTES[..])]);
572+
assert_tokens(&pk.compact(), &[
573+
Token::Tuple{ len: 32 },
574+
Token::U8(24), Token::U8(132), Token::U8(87), Token::U8(129), Token::U8(246), Token::U8(49), Token::U8(196), Token::U8(143),
575+
Token::U8(28), Token::U8(151), Token::U8(9), Token::U8(226), Token::U8(48), Token::U8(146), Token::U8(6), Token::U8(125),
576+
Token::U8(6), Token::U8(131), Token::U8(127), Token::U8(48), Token::U8(170), Token::U8(12), Token::U8(208), Token::U8(84),
577+
Token::U8(74), Token::U8(200), Token::U8(135), Token::U8(254), Token::U8(145), Token::U8(221), Token::U8(209), Token::U8(102),
578+
Token::TupleEnd
579+
]);
575580

576581
assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]);
577582
assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]);

src/serde_util.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,56 @@ where
6767
(self.parse_fn)(v).map_err(E::custom)
6868
}
6969
}
70+
71+
macro_rules! impl_tuple_visitor {
72+
($thing:ident, $len:expr) => {
73+
pub(crate) struct $thing<F> {
74+
expectation: &'static str,
75+
parse_fn: F,
76+
}
77+
78+
impl<F, T, E> $thing<F>
79+
where
80+
F: FnOnce(&[u8]) -> Result<T, E>,
81+
E: fmt::Display,
82+
{
83+
pub fn new(expectation: &'static str, parse_fn: F) -> Self {
84+
$thing {
85+
expectation,
86+
parse_fn,
87+
}
88+
}
89+
}
90+
91+
impl<'de, F, T, E> de::Visitor<'de> for $thing<F>
92+
where
93+
F: FnOnce(&[u8]) -> Result<T, E>,
94+
E: fmt::Display,
95+
{
96+
type Value = T;
97+
98+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
99+
formatter.write_str(self.expectation)
100+
}
101+
102+
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
103+
where
104+
V: de::SeqAccess<'de>,
105+
{
106+
let mut bytes = [0u8; $len];
107+
108+
for (i, byte) in bytes.iter_mut().enumerate() {
109+
if let Some(value) = seq.next_element()? {
110+
*byte = value;
111+
} else {
112+
return Err(de::Error::invalid_length(i, &self));
113+
}
114+
}
115+
(self.parse_fn)(&bytes).map_err(de::Error::custom)
116+
}
117+
}
118+
}
119+
}
120+
121+
impl_tuple_visitor!(Tuple32Visitor, 32);
122+
impl_tuple_visitor!(Tuple33Visitor, 33);

0 commit comments

Comments
 (0)