Merge pull request #15 from ZcashFoundation/serde

This commit is contained in:
Henry de Valence 2019-12-09 11:59:16 -08:00 committed by GitHub
commit 80239164f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 138 additions and 3 deletions

View File

@ -9,12 +9,15 @@ rand_core = "0.5"
thiserror = "1.0"
blake2b_simd = "0.5"
jubjub = "0.3"
serde = { version = "1", optional = true, features = ["derive"] }
[dev-dependencies]
rand = "0.7"
rand_chacha = "0.2"
proptest = "0.9"
lazy_static = "1.4"
bincode = "1"
[features]
nightly = []
default = ["serde"]

View File

@ -40,18 +40,18 @@ pub use signature::Signature;
pub trait SigType: private::Sealed {}
/// A type variable corresponding to Zcash's `BindingSig`.
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Binding {}
impl SigType for Binding {}
/// A type variable corresponding to Zcash's `SpendAuthSig`.
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum SpendAuth {}
impl SigType for SpendAuth {}
pub(crate) mod private {
use super::*;
pub trait Sealed: Copy + Clone + std::fmt::Debug {
pub trait Sealed: Copy + Clone + Eq + PartialEq + std::fmt::Debug {
fn basepoint() -> jubjub::ExtendedPoint;
}
impl Sealed for Binding {

View File

@ -9,6 +9,7 @@ use crate::{Error, Randomizer, Scalar, SigType, Signature, SpendAuth};
/// [`PublicKey`] type in this library holds other decompressed state
/// used in signature verification.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PublicKeyBytes<T: SigType> {
pub(crate) bytes: [u8; 32],
pub(crate) _marker: PhantomData<T>,
@ -35,6 +36,10 @@ impl<T: SigType> From<PublicKeyBytes<T>> for [u8; 32] {
/// public key may not be used immediately, it is probably better to use
/// [`PublicKeyBytes`], which is a refinement type for `[u8; 32]`.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "PublicKeyBytes<T>"))]
#[cfg_attr(feature = "serde", serde(into = "PublicKeyBytes<T>"))]
#[cfg_attr(feature = "serde", serde(bound = "T: SigType"))]
pub struct PublicKey<T: SigType> {
// XXX-jubjub: this should just be Point
pub(crate) point: jubjub::ExtendedPoint,

View File

@ -6,6 +6,10 @@ use rand_core::{CryptoRng, RngCore};
/// A RedJubJub secret key.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(from = "SerdeHelper"))]
#[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))]
#[cfg_attr(feature = "serde", serde(bound = "T: SigType"))]
pub struct SecretKey<T: SigType> {
sk: Scalar,
pk: PublicKey<T>,
@ -37,6 +41,21 @@ impl<T: SigType> From<[u8; 32]> for SecretKey<T> {
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
struct SerdeHelper([u8; 32]);
impl<T: SigType> From<SerdeHelper> for SecretKey<T> {
fn from(helper: SerdeHelper) -> Self {
helper.0.into()
}
}
impl<T: SigType> From<SecretKey<T>> for SerdeHelper {
fn from(sk: SecretKey<T>) -> Self {
Self(sk.into())
}
}
impl SecretKey<SpendAuth> {
/// Randomize this public key with the given `randomizer`.
pub fn randomize(&self, randomizer: &Randomizer) -> SecretKey<SpendAuth> {

View File

@ -4,6 +4,7 @@ use crate::SigType;
/// A RedJubJub signature.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Signature<T: SigType> {
pub(crate) r_bytes: [u8; 32],
pub(crate) s_bytes: [u8; 32],

107
tests/bincode.rs Normal file
View File

@ -0,0 +1,107 @@
use std::convert::TryFrom;
use proptest::prelude::*;
use redjubjub_zebra::*;
proptest! {
#[test]
fn secretkey_serialization(
bytes in prop::array::uniform32(any::<u8>()),
) {
let sk_from = SecretKey::<SpendAuth>::from(bytes);
let sk_bincode: SecretKey::<SpendAuth>
= bincode::deserialize(&bytes[..]).unwrap();
// Check 1: both decoding methods should have the same public key
let pk_bytes_from = PublicKeyBytes::from(PublicKey::from(&sk_from));
let pk_bytes_bincode = PublicKeyBytes::from(PublicKey::from(&sk_bincode));
assert_eq!(pk_bytes_from, pk_bytes_bincode);
// The below tests fail because we do not require canonically-encoded secret keys.
/*
// Check 2: bincode encoding should match original bytes.
let bytes_bincode = bincode::serialize(&sk_from).unwrap();
assert_eq!(&bytes[..], &bytes_bincode[..]);
// Check 3: From encoding should match original bytes.
let bytes_from: [u8; 32] = sk_bincode.into();
assert_eq!(&bytes[..], &bytes_from[..]);
*/
}
#[test]
fn publickeybytes_serialization(
bytes in prop::array::uniform32(any::<u8>()),
) {
let pk_bytes_from = PublicKeyBytes::<SpendAuth>::from(bytes);
let pk_bytes_bincode: PublicKeyBytes::<SpendAuth>
= bincode::deserialize(&bytes[..]).unwrap();
// Check 1: both decoding methods should have the same result.
assert_eq!(pk_bytes_from, pk_bytes_bincode);
// Check 2: bincode encoding should match original bytes.
let bytes_bincode = bincode::serialize(&pk_bytes_from).unwrap();
assert_eq!(&bytes[..], &bytes_bincode[..]);
// Check 3: From encoding should match original bytes.
let bytes_from: [u8; 32] = pk_bytes_bincode.into();
assert_eq!(&bytes[..], &bytes_from[..]);
}
#[test]
fn publickey_serialization(
bytes in prop::array::uniform32(any::<u8>()),
) {
let pk_result_try_from = PublicKey::<SpendAuth>::try_from(bytes);
let pk_result_bincode: Result<PublicKey::<SpendAuth>, _>
= bincode::deserialize(&bytes[..]);
// Check 1: both decoding methods should have the same result
match (pk_result_try_from, pk_result_bincode) {
// Both agree on success
(Ok(pk_try_from), Ok(pk_bincode)) => {
// Check 2: bincode encoding should match original bytes
let bytes_bincode = bincode::serialize(&pk_try_from).unwrap();
assert_eq!(&bytes[..], &bytes_bincode[..]);
// Check 3: From encoding should match original bytes
let bytes_from: [u8; 32] = pk_bincode.into();
assert_eq!(&bytes[..], &bytes_from[..]);
},
// Both agree on failure
(Err(_), Err(_)) => {},
_ => panic!("bincode and try_from do not agree"),
}
}
#[test]
fn signature_serialization(
lo in prop::array::uniform32(any::<u8>()),
hi in prop::array::uniform32(any::<u8>()),
) {
// array length hack
let bytes = {
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&lo[..]);
bytes[32..64].copy_from_slice(&hi[..]);
bytes
};
let sig_bytes_from = Signature::<SpendAuth>::from(bytes);
let sig_bytes_bincode: Signature::<SpendAuth>
= bincode::deserialize(&bytes[..]).unwrap();
// Check 1: both decoding methods should have the same result.
assert_eq!(sig_bytes_from, sig_bytes_bincode);
// Check 2: bincode encoding should match original bytes.
let bytes_bincode = bincode::serialize(&sig_bytes_from).unwrap();
assert_eq!(&bytes[..], &bytes_bincode[..]);
// Check 3: From encoding should match original bytes.
let bytes_from: [u8; 64] = sig_bytes_bincode.into();
assert_eq!(&bytes[..], &bytes_from[..]);
}
}