Move note encryption types around (#362)
* Move around and dedupe note *Cipertext types * Bump code coverage test timeout to 5 minutes * Try uploading coverage to codecov.io
This commit is contained in:
parent
21eca164d8
commit
df7ed7ae81
|
|
@ -58,9 +58,12 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: tarpaulin
|
command: tarpaulin
|
||||||
args: --verbose --count --workspace --timeout 180 --out Html
|
args: --verbose --count --workspace --timeout 300 --out Xml
|
||||||
- name: Archive code coverage results
|
- name: Archive code coverage results
|
||||||
uses: actions/upload-artifact@v1
|
uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: code-coverage-report
|
name: code-coverage-report
|
||||||
path: tarpaulin-report.html
|
path: cobertura.xml
|
||||||
|
- uses: codecov/codecov-action@v1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub mod block;
|
||||||
pub mod equihash_solution;
|
pub mod equihash_solution;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub mod note_commitment_tree;
|
pub mod note_commitment_tree;
|
||||||
pub mod note_encryption;
|
pub mod notes;
|
||||||
pub mod proofs;
|
pub mod proofs;
|
||||||
pub mod serialization;
|
pub mod serialization;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Note encryption types.
|
//! Note encryption types.
|
||||||
mod memo;
|
mod memo;
|
||||||
mod sapling;
|
pub mod sapling;
|
||||||
mod sprout;
|
pub mod sprout;
|
||||||
|
|
||||||
/// The randomness used in the Pedersen Hash for note commitment.
|
/// The randomness used in the Pedersen Hash for note commitment.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//!
|
||||||
|
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -15,6 +17,7 @@ use super::*;
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct Diversifier(pub [u8; 11]);
|
pub struct Diversifier(pub [u8; 11]);
|
||||||
|
|
||||||
|
///
|
||||||
pub struct Note {
|
pub struct Note {
|
||||||
diversifier: Diversifier,
|
diversifier: Diversifier,
|
||||||
// TODO: refine as a type, derived from a scalar mult of the
|
// TODO: refine as a type, derived from a scalar mult of the
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
//!
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
io::{self},
|
io::{self},
|
||||||
|
|
@ -8,8 +10,9 @@ use proptest::{collection::vec, prelude::*};
|
||||||
|
|
||||||
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
|
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
|
||||||
|
|
||||||
use super::*;
|
use super::{memo::Memo, *};
|
||||||
|
|
||||||
|
///
|
||||||
pub struct Note {
|
pub struct Note {
|
||||||
// TODO: refine type as a SHA-256d output derived from a spending key.
|
// TODO: refine type as a SHA-256d output derived from a spending key.
|
||||||
paying_key: [u8; 32],
|
paying_key: [u8; 32],
|
||||||
|
|
@ -26,7 +29,7 @@ pub struct NotePlaintext {
|
||||||
rho: [u8; 32],
|
rho: [u8; 32],
|
||||||
// TODO: refine as jub-jub appropriate in the base field.
|
// TODO: refine as jub-jub appropriate in the base field.
|
||||||
note_commitment_randomness: NoteCommitmentRandomness,
|
note_commitment_randomness: NoteCommitmentRandomness,
|
||||||
memo: memo::Memo,
|
memo: Memo,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A ciphertext component for encrypted output notes.
|
/// A ciphertext component for encrypted output notes.
|
||||||
|
|
@ -1,15 +1,7 @@
|
||||||
use std::{
|
|
||||||
fmt,
|
|
||||||
io::{self},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use proptest::{array, collection::vec, prelude::*};
|
use proptest::{array, collection::vec, prelude::*};
|
||||||
|
|
||||||
use crate::{
|
use crate::{notes::sprout, proofs::ZkSnarkProof};
|
||||||
proofs::ZkSnarkProof,
|
|
||||||
serialization::{SerializationError, ZcashDeserialize, ZcashSerialize},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A _JoinSplit Description_, as described in [protocol specification §7.2][ps].
|
/// A _JoinSplit Description_, as described in [protocol specification §7.2][ps].
|
||||||
///
|
///
|
||||||
|
|
@ -54,7 +46,7 @@ pub struct JoinSplit<P: ZkSnarkProof> {
|
||||||
/// [`Bctv14Proof`](crate::proofs::Bctv14Proof).
|
/// [`Bctv14Proof`](crate::proofs::Bctv14Proof).
|
||||||
pub zkproof: P,
|
pub zkproof: P,
|
||||||
/// A ciphertext component for this output note.
|
/// A ciphertext component for this output note.
|
||||||
pub enc_ciphertexts: [EncryptedCiphertext; 2],
|
pub enc_ciphertexts: [sprout::EncryptedCiphertext; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because x25519_dalek::PublicKey does not impl PartialEq
|
// Because x25519_dalek::PublicKey does not impl PartialEq
|
||||||
|
|
@ -91,7 +83,7 @@ impl<P: ZkSnarkProof + Arbitrary + 'static> Arbitrary for JoinSplit<P> {
|
||||||
array::uniform32(any::<u8>()),
|
array::uniform32(any::<u8>()),
|
||||||
array::uniform2(array::uniform32(any::<u8>())),
|
array::uniform2(array::uniform32(any::<u8>())),
|
||||||
any::<P>(),
|
any::<P>(),
|
||||||
array::uniform2(any::<EncryptedCiphertext>()),
|
array::uniform2(any::<sprout::EncryptedCiphertext>()),
|
||||||
)
|
)
|
||||||
.prop_map(
|
.prop_map(
|
||||||
|(
|
|(
|
||||||
|
|
@ -184,83 +176,3 @@ impl<P: ZkSnarkProof + Arbitrary + 'static> Arbitrary for JoinSplitData<P> {
|
||||||
|
|
||||||
type Strategy = BoxedStrategy<Self>;
|
type Strategy = BoxedStrategy<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A ciphertext component for encrypted output notes.
|
|
||||||
// XXX move as part of #181 (note encryption implementation)
|
|
||||||
pub struct EncryptedCiphertext(pub [u8; 601]);
|
|
||||||
|
|
||||||
impl fmt::Debug for EncryptedCiphertext {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_tuple("EncryptedCiphertext")
|
|
||||||
.field(&hex::encode(&self.0[..]))
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These impls all only exist because of array length restrictions.
|
|
||||||
|
|
||||||
impl Copy for EncryptedCiphertext {}
|
|
||||||
|
|
||||||
impl Clone for EncryptedCiphertext {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let mut bytes = [0; 601];
|
|
||||||
bytes[..].copy_from_slice(&self.0[..]);
|
|
||||||
Self(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for EncryptedCiphertext {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.0[..] == other.0[..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for EncryptedCiphertext {}
|
|
||||||
|
|
||||||
impl ZcashSerialize for EncryptedCiphertext {
|
|
||||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
|
||||||
writer.write_all(&self.0[..])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZcashDeserialize for EncryptedCiphertext {
|
|
||||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
|
||||||
let mut bytes = [0; 601];
|
|
||||||
reader.read_exact(&mut bytes[..])?;
|
|
||||||
Ok(Self(bytes))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
impl Arbitrary for EncryptedCiphertext {
|
|
||||||
type Parameters = ();
|
|
||||||
|
|
||||||
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
|
||||||
(vec(any::<u8>(), 601))
|
|
||||||
.prop_map(|v| {
|
|
||||||
let mut bytes = [0; 601];
|
|
||||||
bytes.copy_from_slice(v.as_slice());
|
|
||||||
return Self(bytes);
|
|
||||||
})
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Strategy = BoxedStrategy<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
proptest! {
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encrypted_ciphertext_roundtrip(ec in any::<EncryptedCiphertext>()) {
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
|
|
||||||
ec.zcash_serialize(&mut data).expect("EncryptedCiphertext should serialize");
|
|
||||||
|
|
||||||
let ec2 = EncryptedCiphertext::zcash_deserialize(&data[..]).expect("randomized EncryptedCiphertext should deserialize");
|
|
||||||
|
|
||||||
prop_assert_eq![ec, ec2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
|
|
||||||
|
use crate::notes;
|
||||||
use crate::proofs::ZkSnarkProof;
|
use crate::proofs::ZkSnarkProof;
|
||||||
use crate::serialization::{
|
use crate::serialization::{
|
||||||
ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
|
ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
|
||||||
|
|
@ -259,8 +260,8 @@ impl<P: ZkSnarkProof> ZcashDeserialize for JoinSplit<P> {
|
||||||
vmacs: [reader.read_32_bytes()?, reader.read_32_bytes()?],
|
vmacs: [reader.read_32_bytes()?, reader.read_32_bytes()?],
|
||||||
zkproof: P::zcash_deserialize(&mut reader)?,
|
zkproof: P::zcash_deserialize(&mut reader)?,
|
||||||
enc_ciphertexts: [
|
enc_ciphertexts: [
|
||||||
joinsplit::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
notes::sprout::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
||||||
joinsplit::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
notes::sprout::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -346,8 +347,8 @@ impl ZcashDeserialize for Output {
|
||||||
cv: reader.read_32_bytes()?,
|
cv: reader.read_32_bytes()?,
|
||||||
cmu: reader.read_32_bytes()?,
|
cmu: reader.read_32_bytes()?,
|
||||||
ephemeral_key: jubjub::AffinePoint::from_bytes(reader.read_32_bytes()?).unwrap(),
|
ephemeral_key: jubjub::AffinePoint::from_bytes(reader.read_32_bytes()?).unwrap(),
|
||||||
enc_ciphertext: shielded_data::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
enc_ciphertext: notes::sapling::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
||||||
out_ciphertext: shielded_data::OutCiphertext::zcash_deserialize(&mut reader)?,
|
out_ciphertext: notes::sapling::OutCiphertext::zcash_deserialize(&mut reader)?,
|
||||||
zkproof: Groth16Proof::zcash_deserialize(&mut reader)?,
|
zkproof: Groth16Proof::zcash_deserialize(&mut reader)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
use std::{fmt, io};
|
|
||||||
|
|
||||||
use futures::future::Either;
|
use futures::future::Either;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use proptest::{arbitrary::Arbitrary, array, collection::vec, prelude::*};
|
use proptest::{arbitrary::Arbitrary, array, collection::vec, prelude::*};
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use proptest_derive::Arbitrary;
|
|
||||||
|
|
||||||
// XXX this name seems too long?
|
// XXX this name seems too long?
|
||||||
use crate::note_commitment_tree::SaplingNoteTreeRootHash;
|
use crate::note_commitment_tree::SaplingNoteTreeRootHash;
|
||||||
|
use crate::notes::sapling;
|
||||||
use crate::proofs::Groth16Proof;
|
use crate::proofs::Groth16Proof;
|
||||||
use crate::redjubjub::{self, Binding, SpendAuth};
|
use crate::redjubjub::{self, Binding, SpendAuth};
|
||||||
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
|
|
||||||
|
|
||||||
/// A _Spend Description_, as described in [protocol specification §7.3][ps].
|
/// A _Spend Description_, as described in [protocol specification §7.3][ps].
|
||||||
///
|
///
|
||||||
|
|
@ -88,9 +83,9 @@ pub struct Output {
|
||||||
/// An encoding of an ephemeral Jubjub public key.
|
/// An encoding of an ephemeral Jubjub public key.
|
||||||
pub ephemeral_key: jubjub::AffinePoint,
|
pub ephemeral_key: jubjub::AffinePoint,
|
||||||
/// A ciphertext component for the encrypted output note.
|
/// A ciphertext component for the encrypted output note.
|
||||||
pub enc_ciphertext: EncryptedCiphertext,
|
pub enc_ciphertext: sapling::EncryptedCiphertext,
|
||||||
/// A ciphertext component for the encrypted output note.
|
/// A ciphertext component for the encrypted output note.
|
||||||
pub out_ciphertext: OutCiphertext,
|
pub out_ciphertext: sapling::OutCiphertext,
|
||||||
/// The ZK output proof.
|
/// The ZK output proof.
|
||||||
pub zkproof: Groth16Proof,
|
pub zkproof: Groth16Proof,
|
||||||
}
|
}
|
||||||
|
|
@ -108,8 +103,8 @@ impl Arbitrary for Output {
|
||||||
array::uniform32(any::<u8>()).prop_filter("Valid jubjub::AffinePoint", |b| {
|
array::uniform32(any::<u8>()).prop_filter("Valid jubjub::AffinePoint", |b| {
|
||||||
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
|
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
|
||||||
}),
|
}),
|
||||||
any::<EncryptedCiphertext>(),
|
any::<sapling::EncryptedCiphertext>(),
|
||||||
any::<OutCiphertext>(),
|
any::<sapling::OutCiphertext>(),
|
||||||
any::<Groth16Proof>(),
|
any::<Groth16Proof>(),
|
||||||
)
|
)
|
||||||
.prop_map(
|
.prop_map(
|
||||||
|
|
@ -236,158 +231,3 @@ impl Arbitrary for ShieldedData {
|
||||||
|
|
||||||
type Strategy = BoxedStrategy<Self>;
|
type Strategy = BoxedStrategy<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A ciphertext component for encrypted output notes.
|
|
||||||
// XXX move as part of #181 (note encryption implementation)
|
|
||||||
pub struct EncryptedCiphertext(pub [u8; 580]);
|
|
||||||
|
|
||||||
impl fmt::Debug for EncryptedCiphertext {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_tuple("EncryptedCiphertext")
|
|
||||||
.field(&hex::encode(&self.0[..]))
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These impls all only exist because of array length restrictions.
|
|
||||||
|
|
||||||
impl Copy for EncryptedCiphertext {}
|
|
||||||
|
|
||||||
impl Clone for EncryptedCiphertext {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let mut bytes = [0; 580];
|
|
||||||
bytes[..].copy_from_slice(&self.0[..]);
|
|
||||||
Self(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for EncryptedCiphertext {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.0[..] == other.0[..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for EncryptedCiphertext {}
|
|
||||||
|
|
||||||
impl ZcashSerialize for EncryptedCiphertext {
|
|
||||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
|
||||||
writer.write_all(&self.0[..])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZcashDeserialize for EncryptedCiphertext {
|
|
||||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
|
||||||
let mut bytes = [0; 580];
|
|
||||||
reader.read_exact(&mut bytes[..])?;
|
|
||||||
Ok(Self(bytes))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
impl Arbitrary for EncryptedCiphertext {
|
|
||||||
type Parameters = ();
|
|
||||||
|
|
||||||
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
|
||||||
(vec(any::<u8>(), 580))
|
|
||||||
.prop_map(|v| {
|
|
||||||
let mut bytes = [0; 580];
|
|
||||||
bytes.copy_from_slice(v.as_slice());
|
|
||||||
return Self(bytes);
|
|
||||||
})
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Strategy = BoxedStrategy<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A ciphertext component for encrypted output notes.
|
|
||||||
pub struct OutCiphertext(pub [u8; 80]);
|
|
||||||
|
|
||||||
impl fmt::Debug for OutCiphertext {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_tuple("OutCiphertext")
|
|
||||||
.field(&hex::encode(&self.0[..]))
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These impls all only exist because of array length restrictions.
|
|
||||||
|
|
||||||
impl Copy for OutCiphertext {}
|
|
||||||
|
|
||||||
impl Clone for OutCiphertext {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
let mut bytes = [0; 80];
|
|
||||||
bytes[..].copy_from_slice(&self.0[..]);
|
|
||||||
Self(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for OutCiphertext {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.0[..] == other.0[..]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for OutCiphertext {}
|
|
||||||
|
|
||||||
impl ZcashSerialize for OutCiphertext {
|
|
||||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
|
||||||
writer.write_all(&self.0[..])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZcashDeserialize for OutCiphertext {
|
|
||||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
|
||||||
let mut bytes = [0; 80];
|
|
||||||
reader.read_exact(&mut bytes[..])?;
|
|
||||||
Ok(Self(bytes))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
impl Arbitrary for OutCiphertext {
|
|
||||||
type Parameters = ();
|
|
||||||
|
|
||||||
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
|
||||||
(vec(any::<u8>(), 80))
|
|
||||||
.prop_map(|v| {
|
|
||||||
let mut bytes = [0; 80];
|
|
||||||
bytes.copy_from_slice(v.as_slice());
|
|
||||||
return Self(bytes);
|
|
||||||
})
|
|
||||||
.boxed()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Strategy = BoxedStrategy<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
proptest! {
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encrypted_ciphertext_roundtrip(ec in any::<EncryptedCiphertext>()) {
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
|
|
||||||
ec.zcash_serialize(&mut data).expect("EncryptedCiphertext should serialize");
|
|
||||||
|
|
||||||
let ec2 = EncryptedCiphertext::zcash_deserialize(&data[..]).expect("randomized EncryptedCiphertext should deserialize");
|
|
||||||
|
|
||||||
prop_assert_eq![ec, ec2];
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn out_ciphertext_roundtrip(oc in any::<OutCiphertext>()) {
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
|
|
||||||
oc.zcash_serialize(&mut data).expect("OutCiphertext should serialize");
|
|
||||||
|
|
||||||
let oc2 = OutCiphertext::zcash_deserialize(&data[..]).expect("randomized OutCiphertext should deserialize");
|
|
||||||
|
|
||||||
prop_assert_eq![oc, oc2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue