Merge pull request #15 from ZcashFoundation/serde
This commit is contained in:
commit
80239164f2
|
@ -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"]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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[..]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue