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"
|
thiserror = "1.0"
|
||||||
blake2b_simd = "0.5"
|
blake2b_simd = "0.5"
|
||||||
jubjub = "0.3"
|
jubjub = "0.3"
|
||||||
|
serde = { version = "1", optional = true, features = ["derive"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.7"
|
rand = "0.7"
|
||||||
rand_chacha = "0.2"
|
rand_chacha = "0.2"
|
||||||
proptest = "0.9"
|
proptest = "0.9"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
|
bincode = "1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
nightly = []
|
nightly = []
|
||||||
|
default = ["serde"]
|
||||||
|
|
|
@ -40,18 +40,18 @@ pub use signature::Signature;
|
||||||
pub trait SigType: private::Sealed {}
|
pub trait SigType: private::Sealed {}
|
||||||
|
|
||||||
/// A type variable corresponding to Zcash's `BindingSig`.
|
/// A type variable corresponding to Zcash's `BindingSig`.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum Binding {}
|
pub enum Binding {}
|
||||||
impl SigType for Binding {}
|
impl SigType for Binding {}
|
||||||
|
|
||||||
/// A type variable corresponding to Zcash's `SpendAuthSig`.
|
/// A type variable corresponding to Zcash's `SpendAuthSig`.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum SpendAuth {}
|
pub enum SpendAuth {}
|
||||||
impl SigType for SpendAuth {}
|
impl SigType for SpendAuth {}
|
||||||
|
|
||||||
pub(crate) mod private {
|
pub(crate) mod private {
|
||||||
use super::*;
|
use super::*;
|
||||||
pub trait Sealed: Copy + Clone + std::fmt::Debug {
|
pub trait Sealed: Copy + Clone + Eq + PartialEq + std::fmt::Debug {
|
||||||
fn basepoint() -> jubjub::ExtendedPoint;
|
fn basepoint() -> jubjub::ExtendedPoint;
|
||||||
}
|
}
|
||||||
impl Sealed for Binding {
|
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
|
/// [`PublicKey`] type in this library holds other decompressed state
|
||||||
/// used in signature verification.
|
/// used in signature verification.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct PublicKeyBytes<T: SigType> {
|
pub struct PublicKeyBytes<T: SigType> {
|
||||||
pub(crate) bytes: [u8; 32],
|
pub(crate) bytes: [u8; 32],
|
||||||
pub(crate) _marker: PhantomData<T>,
|
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
|
/// public key may not be used immediately, it is probably better to use
|
||||||
/// [`PublicKeyBytes`], which is a refinement type for `[u8; 32]`.
|
/// [`PublicKeyBytes`], which is a refinement type for `[u8; 32]`.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[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> {
|
pub struct PublicKey<T: SigType> {
|
||||||
// XXX-jubjub: this should just be Point
|
// XXX-jubjub: this should just be Point
|
||||||
pub(crate) point: jubjub::ExtendedPoint,
|
pub(crate) point: jubjub::ExtendedPoint,
|
||||||
|
|
|
@ -6,6 +6,10 @@ use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
/// A RedJubJub secret key.
|
/// A RedJubJub secret key.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[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> {
|
pub struct SecretKey<T: SigType> {
|
||||||
sk: Scalar,
|
sk: Scalar,
|
||||||
pk: PublicKey<T>,
|
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> {
|
impl SecretKey<SpendAuth> {
|
||||||
/// Randomize this public key with the given `randomizer`.
|
/// Randomize this public key with the given `randomizer`.
|
||||||
pub fn randomize(&self, randomizer: &Randomizer) -> SecretKey<SpendAuth> {
|
pub fn randomize(&self, randomizer: &Randomizer) -> SecretKey<SpendAuth> {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::SigType;
|
||||||
|
|
||||||
/// A RedJubJub signature.
|
/// A RedJubJub signature.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct Signature<T: SigType> {
|
pub struct Signature<T: SigType> {
|
||||||
pub(crate) r_bytes: [u8; 32],
|
pub(crate) r_bytes: [u8; 32],
|
||||||
pub(crate) s_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