diff --git a/src/key.rs b/src/key.rs index 0f8f182..aeb777a 100644 --- a/src/key.rs +++ b/src/key.rs @@ -559,28 +559,11 @@ mod test { #[test] fn test_serialize_serde() { - use serde::{Serialize, Deserialize}; - use json; - - macro_rules! round_trip ( - ($var:ident) => ({ - let start = $var; - let mut encoded = Vec::new(); - { - let mut serializer = json::ser::Serializer::new(&mut encoded); - start.serialize(&mut serializer).unwrap(); - } - let mut deserializer = json::de::Deserializer::from_slice(&encoded); - let decoded = Deserialize::deserialize(&mut deserializer); - assert_eq!(Some(start), decoded.ok()); - }) - ); - let s = Secp256k1::new(); for _ in 0..500 { let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); - round_trip!(sk); - round_trip!(pk); + round_trip_serde!(sk); + round_trip_serde!(pk); } } diff --git a/src/lib.rs b/src/lib.rs index 8e6ef07..d7cc58b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -202,6 +202,66 @@ impl Signature { } } +impl serde::Serialize for Signature { + fn serialize(&self, s: S) -> Result + where S: serde::Serializer + { + let secp = Secp256k1::with_caps(::ContextFlag::None); + (&self.serialize_compact(&secp)[..]).serialize(s) + } +} + +impl<'de> serde::Deserialize<'de> for Signature { + fn deserialize(d: D) -> Result + where D: serde::Deserializer<'de> + { + use serde::de; + struct Visitor { + marker: std::marker::PhantomData, + } + impl<'de> de::Visitor<'de> for Visitor { + type Value = Signature; + + #[inline] + fn visit_seq(self, mut a: A) -> Result + where A: de::SeqAccess<'de> + { + let s = Secp256k1::with_caps(::ContextFlag::None); + unsafe { + use std::mem; + let mut ret: [u8; constants::COMPACT_SIGNATURE_SIZE] = mem::uninitialized(); + + for i in 0..constants::COMPACT_SIGNATURE_SIZE { + ret[i] = match try!(a.next_element()) { + Some(c) => c, + None => return Err(::serde::de::Error::invalid_length(i, &self)) + }; + } + let one_after_last : Option = try!(a.next_element()); + if one_after_last.is_some() { + return Err(serde::de::Error::invalid_length(constants::COMPACT_SIGNATURE_SIZE + 1, &self)); + } + + Signature::from_compact(&s, &ret).map_err( + |e| match e { + Error::InvalidSignature => de::Error::invalid_value(de::Unexpected::Seq, &self), + _ => de::Error::custom(&e.to_string()), + } + ) + } + } + + fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "a sequence of {} bytes representing a syntactically well-formed compact signature", + constants::COMPACT_SIGNATURE_SIZE) + } + } + + // Begin actual function + d.deserialize_seq(Visitor { marker: std::marker::PhantomData }) + } +} + /// Creates a new signature from a FFI signature impl From for Signature { #[inline] @@ -698,6 +758,8 @@ mod tests { let sig2 = Signature::from_compact(&s, &compact[..]).unwrap(); assert_eq!(sig1, sig2); + round_trip_serde!(sig1); + assert!(Signature::from_compact(&s, &der[..]).is_err()); assert!(Signature::from_compact(&s, &compact[0..4]).is_err()); assert!(Signature::from_der(&s, &compact[..]).is_err()); diff --git a/src/macros.rs b/src/macros.rs index ea40823..4f5b8d5 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -225,3 +225,18 @@ macro_rules! impl_raw_debug { } } +#[cfg(test)] +// A macro useful for serde (de)serialization tests +macro_rules! round_trip_serde ( + ($var:ident) => ({ + let start = $var; + let mut encoded = Vec::new(); + { + let mut serializer = ::json::ser::Serializer::new(&mut encoded); + ::serde::Serialize::serialize(&start, &mut serializer).unwrap(); + } + let mut deserializer = ::json::de::Deserializer::from_slice(&encoded); + let decoded = ::serde::Deserialize::deserialize(&mut deserializer); + assert_eq!(Some(start), decoded.ok()); + }) +);