diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 51b538b9..53301d2b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,9 +58,12 @@ jobs: uses: actions-rs/cargo@v1 with: command: tarpaulin - args: --verbose --count --workspace --timeout 180 --out Html + args: --verbose --count --workspace --timeout 300 --out Xml - name: Archive code coverage results uses: actions/upload-artifact@v1 with: name: code-coverage-report - path: tarpaulin-report.html + path: cobertura.xml + - uses: codecov/codecov-action@v1 + + diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index 633f1f21..afc8d081 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -15,7 +15,7 @@ pub mod block; pub mod equihash_solution; pub mod keys; pub mod note_commitment_tree; -pub mod note_encryption; +pub mod notes; pub mod proofs; pub mod serialization; pub mod transaction; diff --git a/zebra-chain/src/note_encryption.rs b/zebra-chain/src/notes.rs similarity index 85% rename from zebra-chain/src/note_encryption.rs rename to zebra-chain/src/notes.rs index 76027533..8f6cbf2e 100644 --- a/zebra-chain/src/note_encryption.rs +++ b/zebra-chain/src/notes.rs @@ -1,7 +1,7 @@ //! Note encryption types. mod memo; -mod sapling; -mod sprout; +pub mod sapling; +pub mod sprout; /// The randomness used in the Pedersen Hash for note commitment. #[derive(Copy, Clone, Debug, PartialEq)] diff --git a/zebra-chain/src/note_encryption/memo.rs b/zebra-chain/src/notes/memo.rs similarity index 100% rename from zebra-chain/src/note_encryption/memo.rs rename to zebra-chain/src/notes/memo.rs diff --git a/zebra-chain/src/note_encryption/sapling.rs b/zebra-chain/src/notes/sapling.rs similarity index 99% rename from zebra-chain/src/note_encryption/sapling.rs rename to zebra-chain/src/notes/sapling.rs index 550697f2..0a34a86c 100644 --- a/zebra-chain/src/note_encryption/sapling.rs +++ b/zebra-chain/src/notes/sapling.rs @@ -1,3 +1,5 @@ +//! + use std::{fmt, io}; #[cfg(test)] @@ -15,6 +17,7 @@ use super::*; #[derive(Copy, Clone, Debug, PartialEq)] pub struct Diversifier(pub [u8; 11]); +/// pub struct Note { diversifier: Diversifier, // TODO: refine as a type, derived from a scalar mult of the diff --git a/zebra-chain/src/note_encryption/sprout.rs b/zebra-chain/src/notes/sprout.rs similarity index 98% rename from zebra-chain/src/note_encryption/sprout.rs rename to zebra-chain/src/notes/sprout.rs index d80cdc15..70e12dcf 100644 --- a/zebra-chain/src/note_encryption/sprout.rs +++ b/zebra-chain/src/notes/sprout.rs @@ -1,3 +1,5 @@ +//! + use std::{ fmt, io::{self}, @@ -8,8 +10,9 @@ use proptest::{collection::vec, prelude::*}; use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; -use super::*; +use super::{memo::Memo, *}; +/// pub struct Note { // TODO: refine type as a SHA-256d output derived from a spending key. paying_key: [u8; 32], @@ -26,7 +29,7 @@ pub struct NotePlaintext { rho: [u8; 32], // TODO: refine as jub-jub appropriate in the base field. note_commitment_randomness: NoteCommitmentRandomness, - memo: memo::Memo, + memo: Memo, } /// A ciphertext component for encrypted output notes. diff --git a/zebra-chain/src/note_encryption/test_vectors.rs b/zebra-chain/src/notes/test_vectors.rs similarity index 100% rename from zebra-chain/src/note_encryption/test_vectors.rs rename to zebra-chain/src/notes/test_vectors.rs diff --git a/zebra-chain/src/note_encryption/tests.rs b/zebra-chain/src/notes/tests.rs similarity index 100% rename from zebra-chain/src/note_encryption/tests.rs rename to zebra-chain/src/notes/tests.rs diff --git a/zebra-chain/src/transaction/joinsplit.rs b/zebra-chain/src/transaction/joinsplit.rs index c9ecf3fb..aa58a84f 100644 --- a/zebra-chain/src/transaction/joinsplit.rs +++ b/zebra-chain/src/transaction/joinsplit.rs @@ -1,15 +1,7 @@ -use std::{ - fmt, - io::{self}, -}; - #[cfg(test)] use proptest::{array, collection::vec, prelude::*}; -use crate::{ - proofs::ZkSnarkProof, - serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}, -}; +use crate::{notes::sprout, proofs::ZkSnarkProof}; /// A _JoinSplit Description_, as described in [protocol specification §7.2][ps]. /// @@ -54,7 +46,7 @@ pub struct JoinSplit { /// [`Bctv14Proof`](crate::proofs::Bctv14Proof). pub zkproof: P, /// 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 @@ -91,7 +83,7 @@ impl Arbitrary for JoinSplit

{ array::uniform32(any::()), array::uniform2(array::uniform32(any::())), any::

(), - array::uniform2(any::()), + array::uniform2(any::()), ) .prop_map( |( @@ -184,83 +176,3 @@ impl Arbitrary for JoinSplitData

{ type Strategy = BoxedStrategy; } - -/// 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(&self, mut writer: W) -> Result<(), io::Error> { - writer.write_all(&self.0[..])?; - Ok(()) - } -} - -impl ZcashDeserialize for EncryptedCiphertext { - fn zcash_deserialize(mut reader: R) -> Result { - 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::(), 601)) - .prop_map(|v| { - let mut bytes = [0; 601]; - bytes.copy_from_slice(v.as_slice()); - return Self(bytes); - }) - .boxed() - } - - type Strategy = BoxedStrategy; -} - -#[cfg(test)] -proptest! { - - #[test] - fn encrypted_ciphertext_roundtrip(ec in any::()) { - - 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]; - } -} diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index bcaf42c1..88f25b04 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -4,6 +4,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use std::io::{self, Read}; +use crate::notes; use crate::proofs::ZkSnarkProof; use crate::serialization::{ ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize, @@ -259,8 +260,8 @@ impl ZcashDeserialize for JoinSplit

{ vmacs: [reader.read_32_bytes()?, reader.read_32_bytes()?], zkproof: P::zcash_deserialize(&mut reader)?, enc_ciphertexts: [ - joinsplit::EncryptedCiphertext::zcash_deserialize(&mut reader)?, - joinsplit::EncryptedCiphertext::zcash_deserialize(&mut reader)?, + notes::sprout::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()?, cmu: reader.read_32_bytes()?, ephemeral_key: jubjub::AffinePoint::from_bytes(reader.read_32_bytes()?).unwrap(), - enc_ciphertext: shielded_data::EncryptedCiphertext::zcash_deserialize(&mut reader)?, - out_ciphertext: shielded_data::OutCiphertext::zcash_deserialize(&mut reader)?, + enc_ciphertext: notes::sapling::EncryptedCiphertext::zcash_deserialize(&mut reader)?, + out_ciphertext: notes::sapling::OutCiphertext::zcash_deserialize(&mut reader)?, zkproof: Groth16Proof::zcash_deserialize(&mut reader)?, }) } diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs index 256c1395..75d52204 100644 --- a/zebra-chain/src/transaction/shielded_data.rs +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -1,18 +1,13 @@ -use std::{fmt, io}; - use futures::future::Either; #[cfg(test)] use proptest::{arbitrary::Arbitrary, array, collection::vec, prelude::*}; -#[cfg(test)] -use proptest_derive::Arbitrary; - // XXX this name seems too long? use crate::note_commitment_tree::SaplingNoteTreeRootHash; +use crate::notes::sapling; use crate::proofs::Groth16Proof; use crate::redjubjub::{self, Binding, SpendAuth}; -use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; /// 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. pub ephemeral_key: jubjub::AffinePoint, /// 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. - pub out_ciphertext: OutCiphertext, + pub out_ciphertext: sapling::OutCiphertext, /// The ZK output proof. pub zkproof: Groth16Proof, } @@ -108,8 +103,8 @@ impl Arbitrary for Output { array::uniform32(any::()).prop_filter("Valid jubjub::AffinePoint", |b| { jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1 }), - any::(), - any::(), + any::(), + any::(), any::(), ) .prop_map( @@ -236,158 +231,3 @@ impl Arbitrary for ShieldedData { type Strategy = BoxedStrategy; } - -/// 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(&self, mut writer: W) -> Result<(), io::Error> { - writer.write_all(&self.0[..])?; - Ok(()) - } -} - -impl ZcashDeserialize for EncryptedCiphertext { - fn zcash_deserialize(mut reader: R) -> Result { - 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::(), 580)) - .prop_map(|v| { - let mut bytes = [0; 580]; - bytes.copy_from_slice(v.as_slice()); - return Self(bytes); - }) - .boxed() - } - - type Strategy = BoxedStrategy; -} - -/// 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(&self, mut writer: W) -> Result<(), io::Error> { - writer.write_all(&self.0[..])?; - Ok(()) - } -} - -impl ZcashDeserialize for OutCiphertext { - fn zcash_deserialize(mut reader: R) -> Result { - 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::(), 80)) - .prop_map(|v| { - let mut bytes = [0; 80]; - bytes.copy_from_slice(v.as_slice()); - return Self(bytes); - }) - .boxed() - } - - type Strategy = BoxedStrategy; -} - -#[cfg(test)] -proptest! { - - #[test] - fn encrypted_ciphertext_roundtrip(ec in any::()) { - - 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::()) { - - 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]; - } -}