Merge pull request #107 from jonasnick/human-readable-sk

Add human readable serialization and deserialization to Secret Key
This commit is contained in:
Andrew Poelstra 2019-05-17 13:37:55 +00:00 committed by GitHub
commit b843f72955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 26 deletions

View File

@ -187,30 +187,7 @@ 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))
}
}
serde_impl!(SecretKey, constants::SECRET_KEY_SIZE);
impl PublicKey {
/// Obtains a raw const pointer suitable for use with FFI functions
@ -739,13 +716,16 @@ mod test {
#[cfg(feature = "serde")]
#[test]
fn test_signature_serde() {
use serde_test::{Token, assert_tokens};
use serde_test::{Configure, Token, assert_tokens};
static SK_BYTES: [u8; 32] = [
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
];
static SK_STR: &'static str = "\
01010101010101010001020304050607ffff0000ffff00006363636363636363\
";
static PK_BYTES: [u8; 33] = [
0x02,
0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f,
@ -759,7 +739,8 @@ mod test {
let sk = SecretKey::from_slice(&SK_BYTES).unwrap();
let pk = PublicKey::from_secret_key(&s, &sk);
assert_tokens(&sk, &[Token::BorrowedBytes(&SK_BYTES[..])]);
assert_tokens(&sk.compact(), &[Token::BorrowedBytes(&SK_BYTES[..])]);
assert_tokens(&sk.readable(), &[Token::BorrowedStr(SK_STR)]);
assert_tokens(&pk, &[Token::BorrowedBytes(&PK_BYTES[..])]);
}
}

View File

@ -158,3 +158,47 @@ macro_rules! impl_raw_debug {
}
}
}
#[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)?;
SecretKey::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) => ()
);