Add support for serde (de)serialization; add unit tests
This commit is contained in:
parent
1b2858bc8a
commit
ac61baf040
|
@ -16,4 +16,5 @@ git = "https://github.com/DaGenix/rust-crypto.git"
|
|||
rand = "*"
|
||||
libc = "*"
|
||||
rustc-serialize = "*"
|
||||
serde = "*"
|
||||
|
||||
|
|
121
src/key.rs
121
src/key.rs
|
@ -16,9 +16,10 @@
|
|||
//! Public/Private keys
|
||||
|
||||
use std::intrinsics::copy_nonoverlapping;
|
||||
use std::{fmt, ops};
|
||||
use std::{fmt, marker, ops};
|
||||
use rand::Rng;
|
||||
use serialize::{Decoder, Decodable, Encoder, Encodable};
|
||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||
|
||||
use super::init;
|
||||
use super::Error::{self, InvalidPublicKey, InvalidSecretKey, Unknown};
|
||||
|
@ -410,6 +411,64 @@ impl Encodable for PublicKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl Deserialize for PublicKey {
|
||||
fn deserialize<D>(d: &mut D) -> Result<PublicKey, D::Error>
|
||||
where D: Deserializer
|
||||
{
|
||||
use serde::de;
|
||||
struct Visitor {
|
||||
marker: marker::PhantomData<PublicKey>,
|
||||
}
|
||||
impl de::Visitor for Visitor {
|
||||
type Value = PublicKey;
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(&mut self, mut v: V) -> Result<PublicKey, V::Error>
|
||||
where V: de::SeqVisitor
|
||||
{
|
||||
assert!(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE >= constants::COMPRESSED_PUBLIC_KEY_SIZE);
|
||||
|
||||
unsafe {
|
||||
use std::mem;
|
||||
let mut ret_u: [u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE] = mem::uninitialized();
|
||||
let mut ret_c: [u8; constants::COMPRESSED_PUBLIC_KEY_SIZE] = mem::uninitialized();
|
||||
|
||||
let mut read_len = 0;
|
||||
while read_len < constants::UNCOMPRESSED_PUBLIC_KEY_SIZE {
|
||||
let read_ch = match try!(v.visit()) {
|
||||
Some(c) => c,
|
||||
None => break
|
||||
};
|
||||
ret_u[read_len] = read_ch;
|
||||
if read_len < constants::COMPRESSED_PUBLIC_KEY_SIZE { ret_c[read_len] = read_ch; }
|
||||
read_len += 1;
|
||||
}
|
||||
try!(v.end());
|
||||
|
||||
if read_len == constants::UNCOMPRESSED_PUBLIC_KEY_SIZE {
|
||||
Ok(PublicKey(PublicKeyData::Uncompressed(ret_u)))
|
||||
} else if read_len == constants::COMPRESSED_PUBLIC_KEY_SIZE {
|
||||
Ok(PublicKey(PublicKeyData::Compressed(ret_c)))
|
||||
} else {
|
||||
return Err(de::Error::syntax_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Begin actual function
|
||||
d.visit(Visitor { marker: ::std::marker::PhantomData })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for PublicKey {
|
||||
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
(&self.0[..]).serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SecretKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
(&self[..]).fmt(f)
|
||||
|
@ -478,6 +537,66 @@ mod test {
|
|||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
use std::io::Cursor;
|
||||
use serialize::{json, Decodable, Encodable};
|
||||
|
||||
macro_rules! round_trip (
|
||||
($var:ident) => ({
|
||||
let start = $var;
|
||||
let mut encoded = String::new();
|
||||
{
|
||||
let mut encoder = json::Encoder::new(&mut encoded);
|
||||
start.encode(&mut encoder).unwrap();
|
||||
}
|
||||
let json = json::Json::from_reader(&mut Cursor::new(encoded.as_bytes())).unwrap();
|
||||
let mut decoder = json::Decoder::new(json);
|
||||
let decoded = Decodable::decode(&mut decoder);
|
||||
assert_eq!(Some(start), decoded.ok());
|
||||
})
|
||||
);
|
||||
|
||||
let mut s = Secp256k1::new().unwrap();
|
||||
for _ in 0..500 {
|
||||
let (sk, pk) = s.generate_keypair(false);
|
||||
round_trip!(sk);
|
||||
round_trip!(pk);
|
||||
let (sk, pk) = s.generate_keypair(true);
|
||||
round_trip!(sk);
|
||||
round_trip!(pk);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_serde() {
|
||||
use serde::{json, Serialize, Deserialize};
|
||||
|
||||
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::new(encoded.iter().map(|c| Ok(*c))).unwrap();
|
||||
let decoded = Deserialize::deserialize(&mut deserializer);
|
||||
assert_eq!(Some(start), decoded.ok());
|
||||
})
|
||||
);
|
||||
|
||||
let mut s = Secp256k1::new().unwrap();
|
||||
for _ in 0..500 {
|
||||
let (sk, pk) = s.generate_keypair(false);
|
||||
round_trip!(sk);
|
||||
round_trip!(pk);
|
||||
let (sk, pk) = s.generate_keypair(true);
|
||||
round_trip!(sk);
|
||||
round_trip!(pk);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_addition() {
|
||||
let mut s = Secp256k1::new().unwrap();
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
extern crate crypto;
|
||||
extern crate rustc_serialize as serialize;
|
||||
extern crate serde;
|
||||
#[cfg(test)] extern crate test;
|
||||
|
||||
extern crate libc;
|
||||
|
|
|
@ -141,6 +141,51 @@ macro_rules! impl_array_newtype {
|
|||
self[..].encode(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::serde::Deserialize for $thing {
|
||||
fn deserialize<D>(d: &mut D) -> Result<$thing, D::Error>
|
||||
where D: ::serde::Deserializer
|
||||
{
|
||||
// We have to define the Visitor struct inside the function
|
||||
// to make it local ... all we really need is that it's
|
||||
// local to the macro, but this works too :)
|
||||
struct Visitor {
|
||||
marker: ::std::marker::PhantomData<$thing>,
|
||||
}
|
||||
impl ::serde::de::Visitor for Visitor {
|
||||
type Value = $thing;
|
||||
|
||||
#[inline]
|
||||
fn visit_seq<V>(&mut self, mut v: V) -> Result<$thing, V::Error>
|
||||
where V: ::serde::de::SeqVisitor
|
||||
{
|
||||
unsafe {
|
||||
use std::mem;
|
||||
let mut ret: [$ty; $len] = mem::uninitialized();
|
||||
for i in 0..$len {
|
||||
ret[i] = match try!(v.visit()) {
|
||||
Some(c) => c,
|
||||
None => return Err(::serde::de::Error::end_of_stream_error())
|
||||
};
|
||||
}
|
||||
try!(v.end());
|
||||
Ok($thing(ret))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Begin actual function
|
||||
d.visit(Visitor { marker: ::std::marker::PhantomData })
|
||||
}
|
||||
}
|
||||
|
||||
impl ::serde::Serialize for $thing {
|
||||
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
|
||||
where S: ::serde::Serializer
|
||||
{
|
||||
(&self.0[..]).serialize(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue