Merge pull request #270 from thomaseizinger/serde-owned-types

Rebased version of `[Alternative] Allow deserializing from owned types` + support for new schnorr module
This commit is contained in:
Elichai Turkel 2021-04-21 19:06:29 +03:00 committed by GitHub
commit 3c2bee31f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 228 additions and 134 deletions

View File

@ -213,7 +213,32 @@ impl SecretKey {
} }
} }
serde_impl!(SecretKey, constants::SECRET_KEY_SIZE); #[cfg(feature = "serde")]
impl ::serde::Serialize for SecretKey {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.collect_str(self)
} else {
s.serialize_bytes(&self[..])
}
}
}
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for SecretKey {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
if d.is_human_readable() {
d.deserialize_str(super::serde_util::FromStrVisitor::new(
"a hex string representing 32 byte SecretKey"
))
} else {
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
"raw 32 bytes SecretKey",
SecretKey::from_slice
))
}
}
}
impl PublicKey { impl PublicKey {
/// Obtains a raw const pointer suitable for use with FFI functions /// Obtains a raw const pointer suitable for use with FFI functions
@ -402,7 +427,32 @@ impl From<ffi::PublicKey> for PublicKey {
} }
} }
serde_impl_from_slice!(PublicKey); #[cfg(feature = "serde")]
impl ::serde::Serialize for PublicKey {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.collect_str(self)
} else {
s.serialize_bytes(&self.serialize())
}
}
}
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for PublicKey {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<PublicKey, D::Error> {
if d.is_human_readable() {
d.deserialize_str(super::serde_util::FromStrVisitor::new(
"an ASCII hex string representing a public key"
))
} else {
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
"a bytestring representing a public key",
PublicKey::from_slice
))
}
}
}
impl PartialOrd for PublicKey { impl PartialOrd for PublicKey {
fn partial_cmp(&self, other: &PublicKey) -> Option<::core::cmp::Ordering> { fn partial_cmp(&self, other: &PublicKey) -> Option<::core::cmp::Ordering> {
@ -818,7 +868,7 @@ mod test {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[test] #[test]
fn test_signature_serde() { fn test_serde() {
use serde_test::{Configure, Token, assert_tokens}; use serde_test::{Configure, Token, assert_tokens};
static SK_BYTES: [u8; 32] = [ static SK_BYTES: [u8; 32] = [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -846,8 +896,20 @@ mod test {
let pk = PublicKey::from_secret_key(&s, &sk); let pk = PublicKey::from_secret_key(&s, &sk);
assert_tokens(&sk.compact(), &[Token::BorrowedBytes(&SK_BYTES[..])]); assert_tokens(&sk.compact(), &[Token::BorrowedBytes(&SK_BYTES[..])]);
assert_tokens(&sk.compact(), &[Token::Bytes(&SK_BYTES)]);
assert_tokens(&sk.compact(), &[Token::ByteBuf(&SK_BYTES)]);
assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]); assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]);
assert_tokens(&sk.readable(), &[Token::Str(SK_STR)]);
assert_tokens(&sk.readable(), &[Token::String(SK_STR)]);
assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]); assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]);
assert_tokens(&pk.compact(), &[Token::Bytes(&PK_BYTES)]);
assert_tokens(&pk.compact(), &[Token::ByteBuf(&PK_BYTES)]);
assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]); assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]);
assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]);
assert_tokens(&pk.readable(), &[Token::String(PK_STR)]);
} }
} }

View File

@ -147,6 +147,8 @@ pub mod key;
pub mod schnorrsig; pub mod schnorrsig;
#[cfg(feature = "recovery")] #[cfg(feature = "recovery")]
pub mod recovery; pub mod recovery;
#[cfg(feature = "serde")]
mod serde_util;
pub use key::SecretKey; pub use key::SecretKey;
pub use key::PublicKey; pub use key::PublicKey;
@ -435,21 +437,21 @@ impl ::serde::Serialize for Signature {
} else { } else {
s.serialize_bytes(&self.serialize_der()) s.serialize_bytes(&self.serialize_der())
} }
} }
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for Signature { impl<'de> ::serde::Deserialize<'de> for Signature {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Signature, D::Error> { fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
use ::serde::de::Error;
use str::FromStr;
if d.is_human_readable() { if d.is_human_readable() {
let sl: &str = ::serde::Deserialize::deserialize(d)?; d.deserialize_str(serde_util::FromStrVisitor::new(
Signature::from_str(sl).map_err(D::Error::custom) "a hex string representing a DER encoded Signature"
))
} else { } else {
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?; d.deserialize_bytes(serde_util::BytesVisitor::new(
Signature::from_der(sl).map_err(D::Error::custom) "raw byte stream, that represents a DER encoded Signature",
Signature::from_der
))
} }
} }
} }
@ -1237,7 +1239,7 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs #[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
#[test] #[test]
fn test_signature_serde() { fn test_serde() {
use serde_test::{Configure, Token, assert_tokens}; use serde_test::{Configure, Token, assert_tokens};
let s = Secp256k1::new(); let s = Secp256k1::new();
@ -1258,7 +1260,13 @@ mod tests {
"; ";
assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]); assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES)]);
assert_tokens(&sig.compact(), &[Token::ByteBuf(&SIG_BYTES)]);
assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]); assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]);
assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]);
} }
#[cfg(feature = "global-context")] #[cfg(feature = "global-context")]

View File

@ -43,121 +43,3 @@ macro_rules! impl_from_array_len {
)+ )+
} }
} }
#[cfg(feature="serde")]
/// Implements `Serialize` and `Deserialize` for a type `$t` which represents
/// a newtype over a byte-slice over length `$len`. Type `$t` must implement
/// the `FromStr` and `Display` trait.
macro_rules! serde_impl(
($t:ident, $len:expr) => (
impl ::serde::Serialize for $t {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.collect_str(self)
} else {
s.serialize_bytes(&self[..])
}
}
}
impl<'de> ::serde::Deserialize<'de> for $t {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<$t, D::Error> {
use ::serde::de::Error;
use core::str::FromStr;
if d.is_human_readable() {
let sl: &str = ::serde::Deserialize::deserialize(d)?;
$t::from_str(sl).map_err(D::Error::custom)
} else {
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
if sl.len() != $len {
Err(D::Error::invalid_length(sl.len(), &stringify!($len)))
} else {
let mut ret = [0; $len];
ret.copy_from_slice(sl);
Ok($t(ret))
}
}
}
}
)
);
#[cfg(not(feature="serde"))]
macro_rules! serde_impl(
($t:ident, $len:expr) => ()
);
#[cfg(feature = "serde")]
macro_rules! serde_impl_from_slice {
($t: ident) => {
impl ::serde::Serialize for $t {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.collect_str(self)
} else {
s.serialize_bytes(&self.serialize())
}
}
}
impl<'de> ::serde::Deserialize<'de> for $t {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<$t, D::Error> {
if d.is_human_readable() {
struct HexVisitor;
impl<'de> ::serde::de::Visitor<'de> for HexVisitor {
type Value = $t;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an ASCII hex string")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: ::serde::de::Error,
{
if let Ok(hex) = str::from_utf8(v) {
str::FromStr::from_str(hex).map_err(E::custom)
} else {
Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self))
}
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: ::serde::de::Error,
{
str::FromStr::from_str(v).map_err(E::custom)
}
}
d.deserialize_str(HexVisitor)
} else {
struct BytesVisitor;
impl<'de> ::serde::de::Visitor<'de> for BytesVisitor {
type Value = $t;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a bytestring")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: ::serde::de::Error,
{
$t::from_slice(v).map_err(E::custom)
}
}
d.deserialize_bytes(BytesVisitor)
}
}
}
};
}
#[cfg(not(feature = "serde"))]
macro_rules! serde_impl_from_slice(
($t:ident) => ()
);

View File

@ -18,7 +18,33 @@ use {Message, Signing, Verification};
pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]); pub struct Signature([u8; constants::SCHNORRSIG_SIGNATURE_SIZE]);
impl_array_newtype!(Signature, u8, constants::SCHNORRSIG_SIGNATURE_SIZE); impl_array_newtype!(Signature, u8, constants::SCHNORRSIG_SIGNATURE_SIZE);
impl_pretty_debug!(Signature); impl_pretty_debug!(Signature);
serde_impl!(Signature, constants::SCHNORRSIG_SIGNATURE_SIZE);
#[cfg(feature = "serde")]
impl ::serde::Serialize for Signature {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.collect_str(self)
} else {
s.serialize_bytes(&self[..])
}
}
}
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for Signature {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
if d.is_human_readable() {
d.deserialize_str(super::serde_util::FromStrVisitor::new(
"a hex string representing 64 byte schnorr signature"
))
} else {
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
"raw 64 bytes schnorr signature",
Signature::from_slice
))
}
}
}
impl fmt::LowerHex for Signature { impl fmt::LowerHex for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -376,7 +402,32 @@ impl From<::key::PublicKey> for PublicKey {
} }
} }
serde_impl_from_slice!(PublicKey); #[cfg(feature = "serde")]
impl ::serde::Serialize for PublicKey {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.collect_str(self)
} else {
s.serialize_bytes(&self.serialize())
}
}
}
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for PublicKey {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
if d.is_human_readable() {
d.deserialize_str(super::serde_util::FromStrVisitor::new(
"a hex string representing 32 byte schnorr public key"
))
} else {
d.deserialize_bytes(super::serde_util::BytesVisitor::new(
"raw 32 bytes schnorr public key",
PublicKey::from_slice
))
}
}
}
impl<C: Signing> Secp256k1<C> { impl<C: Signing> Secp256k1<C> {
fn schnorrsig_sign_helper( fn schnorrsig_sign_helper(
@ -724,7 +775,7 @@ mod tests {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs #[cfg(not(fuzzing))] // fixed sig vectors can't work with fuzz-sigs
#[test] #[test]
fn test_signature_serde() { fn test_serde() {
use serde_test::{assert_tokens, Configure, Token}; use serde_test::{assert_tokens, Configure, Token};
let s = Secp256k1::new(); let s = Secp256k1::new();
@ -745,8 +796,30 @@ mod tests {
14d0bf1a8953506fb460f58be141af767fd112535fb3922ef217308e2c26706f1eeb432b3dba9a01082f9e4d4ef5678ad0d9d532c0dfa907b568722d0b0119ba\ 14d0bf1a8953506fb460f58be141af767fd112535fb3922ef217308e2c26706f1eeb432b3dba9a01082f9e4d4ef5678ad0d9d532c0dfa907b568722d0b0119ba\
"; ";
static PK_BYTES: [u8; 32] = [
24, 132, 87, 129, 246, 49, 196, 143, 28, 151, 9, 226, 48, 146, 6, 125, 6, 131, 127,
48, 170, 12, 208, 84, 74, 200, 135, 254, 145, 221, 209, 102
];
static PK_STR: &'static str = "\
18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166\
";
let pk = PublicKey::from_slice(&PK_BYTES).unwrap();
assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]); assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES[..])]);
assert_tokens(&sig.compact(), &[Token::ByteBuf(&SIG_BYTES[..])]);
assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]); assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]);
assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]);
assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]);
assert_tokens(&pk.compact(), &[Token::Bytes(&PK_BYTES[..])]);
assert_tokens(&pk.compact(), &[Token::ByteBuf(&PK_BYTES[..])]);
assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]);
assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]);
assert_tokens(&pk.readable(), &[Token::String(PK_STR)]);
} }
#[test] #[test]
fn test_addition() { fn test_addition() {

69
src/serde_util.rs Normal file
View File

@ -0,0 +1,69 @@
use core::fmt;
use core::marker::PhantomData;
use core::str::{self, FromStr};
use serde::de;
/// A serde visitor that works for `T`s implementing `FromStr`.
pub struct FromStrVisitor<T> {
expectation: &'static str,
_pd: PhantomData<T>,
}
impl<T> FromStrVisitor<T> {
pub fn new(expectation: &'static str) -> Self {
FromStrVisitor {
expectation,
_pd: PhantomData,
}
}
}
impl<'de, T> de::Visitor<'de> for FromStrVisitor<T>
where
T: FromStr,
<T as FromStr>::Err: fmt::Display,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.expectation)
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
FromStr::from_str(v).map_err(E::custom)
}
}
pub struct BytesVisitor<F> {
expectation: &'static str,
parse_fn: F,
}
impl<F, T, Err> BytesVisitor<F>
where
F: FnOnce(&[u8]) -> Result<T, Err>,
Err: fmt::Display,
{
pub fn new(expectation: &'static str, parse_fn: F) -> Self {
BytesVisitor {
expectation,
parse_fn,
}
}
}
impl<'de, F, T, Err> de::Visitor<'de> for BytesVisitor<F>
where
F: FnOnce(&[u8]) -> Result<T, Err>,
Err: fmt::Display,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(self.expectation)
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
(self.parse_fn)(v).map_err(E::custom)
}
}