Skip to content

Commit

Permalink
add feature-gated serde 1.0 support for Signature, SecretKey, PublicKey
Browse files Browse the repository at this point in the history
  • Loading branch information
apoelstra committed Jul 25, 2018
1 parent 54ddbc7 commit 57ca05d
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ script:
- cargo build --verbose --features=fuzztarget
- cargo build --verbose --features=rand
- cargo test --verbose --features=rand
- cargo test --verbose --features="rand serde"
- cargo build --verbose
- cargo test --verbose
- cargo build --release
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@ fuzztarget = []

[dev-dependencies]
rand = "0.3"
serde_test = "1.0"

[dependencies]
libc = "0.2"

[dependencies.rand]
version = "0.3"
optional = true

[dependencies.serde]
version = "1.0"
optional = true
69 changes: 69 additions & 0 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,31 @@ impl SecretKey {
}
}

#[cfg(feature = "serde")]
impl ::serde::Serialize for SecretKey {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
s.serialize_bytes(&self.0)
}
}

#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for SecretKey {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<SecretKey, D::Error> {
use ::serde::de::Error;

// serde can actually deserialize a 32-byte array directly rather than deserializing
// a byte slice and copying, but it has special code for byte-slices and no special
// code for byte-arrays, meaning this is actually simpler and more efficient
let mut arr = [0; 32];
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
if sl.len() != constants::SECRET_KEY_SIZE {
return Err(D::Error::invalid_length(sl.len(), &"32"));
}
arr.copy_from_slice(sl);
Ok(SecretKey(arr))
}
}

impl PublicKey {
/// Obtains a raw pointer suitable for use with FFI functions
#[inline]
Expand Down Expand Up @@ -254,6 +279,24 @@ impl From<ffi::PublicKey> for PublicKey {
}
}

#[cfg(feature = "serde")]
impl ::serde::Serialize for PublicKey {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
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> {
use ::serde::de::Error;

let secp = Secp256k1::without_caps();
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
PublicKey::from_slice(&secp, sl).map_err(D::Error::custom)
}
}

#[cfg(test)]
mod test {
use super::super::{Secp256k1};
Expand Down Expand Up @@ -529,6 +572,32 @@ mod test {
assert!(pk3 <= pk1);
assert!(pk1 >= pk3);
}

#[cfg(feature = "serde")]
#[test]
fn test_signature_serde() {
use serde_test::{Token, assert_tokens};
let sk_bytes: &'static [u8] = &[
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 2, 3, 4, 5, 6, 7,
0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0,
99, 99, 99, 99, 99, 99, 99, 99
];

let s = Secp256k1::new();

let sk = SecretKey::from_slice(&s, sk_bytes).unwrap();
let pk = PublicKey::from_secret_key(&s, &sk);

assert_tokens(&sk, &[Token::BorrowedBytes(sk_bytes)]);
assert_tokens(&pk, &[Token::BorrowedBytes(&[
0x02,
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,
])]);
}
}


44 changes: 44 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#![cfg_attr(all(test, feature = "unstable"), feature(test))]
#[cfg(all(test, feature = "unstable"))] extern crate test;
#[cfg(any(test, feature = "rand"))] extern crate rand;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(all(test, feature = "serde"))] extern crate serde_test;

extern crate libc;

Expand Down Expand Up @@ -305,6 +307,25 @@ impl ops::Index<ops::RangeFull> for Signature {
}
}

#[cfg(feature = "serde")]
impl ::serde::Serialize for Signature {
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
let secp = Secp256k1::without_caps();
s.serialize_bytes(&self.serialize_der(&secp))
}
}

#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for Signature {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Signature, D::Error> {
use ::serde::de::Error;

let secp = Secp256k1::without_caps();
let sl: &[u8] = ::serde::Deserialize::deserialize(d)?;
Signature::from_der(&secp, sl).map_err(D::Error::custom)
}
}

/// A (hashed) message input to an ECDSA signature
pub struct Message([u8; constants::MESSAGE_SIZE]);
impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE);
Expand Down Expand Up @@ -903,6 +924,29 @@ mod tests {
sig.normalize_s(&secp);
assert_eq!(secp.verify(&msg, &sig, &pk), Ok(()));
}

#[cfg(feature = "serde")]
#[test]
fn test_signature_serde() {
use serde_test::{Token, assert_tokens};

let s = Secp256k1::new();

let msg = Message::from_slice(&[1; 32]).unwrap();
let sk = SecretKey::from_slice(&s, &[2; 32]).unwrap();
let sig = s.sign(&msg, &sk);

assert_tokens(
&sig,
&[Token::BorrowedBytes(&[
48, 69, 2, 33, 0, 157, 11, 173, 87, 103, 25, 211, 42, 231, 107, 237,
179, 76, 119, 72, 102, 103, 60, 189, 227, 244, 225, 41, 81, 85, 92, 148,
8, 230, 206, 119, 75, 2, 32, 40, 118, 231, 16, 47, 32, 79, 107, 254,
226, 108, 150, 124, 57, 38, 206, 112, 44, 249, 125, 75, 1, 0, 98, 225,
147, 247, 99, 25, 15, 103, 118
])]
);
}
}

#[cfg(all(test, feature = "unstable"))]
Expand Down

0 comments on commit 57ca05d

Please sign in to comment.