diff --git a/Cargo.toml b/Cargo.toml index 0e7f64ea6..828085335 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,4 +92,4 @@ debug = true debug = true [patch.crates-io] -zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", tag = "orchard_zsa_0.5.0_compatible" } +zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization" } diff --git a/src/bundle/commitments.rs b/src/bundle/commitments.rs index 97cc8ab09..306296508 100644 --- a/src/bundle/commitments.rs +++ b/src/bundle/commitments.rs @@ -96,6 +96,16 @@ pub fn hash_bundle_auth_empty() -> Blake2bHash { hasher(ZCASH_ORCHARD_SIGS_HASH_PERSONALIZATION).finalize() } +/// Construct the commitment for an absent issue bundle +pub fn hash_issue_bundle_auth_empty() -> Blake2bHash { + hasher(ZCASH_ORCHARD_ZSA_ISSUE_PERSONALIZATION).finalize() +} + +/// Construct the commitment for the absent issue bundle +pub fn hash_issue_bundle_txid_empty() -> Blake2bHash { + hasher(ZCASH_ORCHARD_ZSA_ISSUE_PERSONALIZATION).finalize() +} + /// Construct the commitment for the issue bundle pub(crate) fn hash_issue_bundle_txid_data(bundle: &IssueBundle) -> Blake2bHash { let mut h = hasher(ZCASH_ORCHARD_ZSA_ISSUE_PERSONALIZATION); @@ -119,14 +129,6 @@ pub(crate) fn hash_issue_bundle_txid_data(bundle: &IssueBundle) h.finalize() } -/// Construct the commitment for the absent issue bundle as defined in -/// [ZIP-227: Issuance of Zcash Shielded Assets][zip227] -/// -/// [zip227]: https://qed-it.github.io/zips/zip-0227 -pub fn hash_issue_bundle_txid_empty() -> Blake2bHash { - hasher(ZCASH_ORCHARD_ZSA_ISSUE_PERSONALIZATION).finalize() -} - /// Construct the commitment to the authorizing data of an /// authorized issue bundle pub(crate) fn hash_issue_bundle_auth_data(bundle: &IssueBundle) -> Blake2bHash { @@ -134,11 +136,3 @@ pub(crate) fn hash_issue_bundle_auth_data(bundle: &IssueBundle) -> Blake h.update(&<[u8; 64]>::from(bundle.authorization().signature())); h.finalize() } - -/// Construct the commitment for an absent issue bundle as defined in -/// [ZIP-227: Issuance of Zcash Shielded Assets][zip227] -/// -/// [zip227]: https://qed-it.github.io/zips/zip-0227 -pub fn hash_issue_bundle_auth_empty() -> Blake2bHash { - hasher(ZCASH_ORCHARD_ZSA_ISSUE_SIG_PERSONALIZATION).finalize() -} diff --git a/src/issuance.rs b/src/issuance.rs index c2fc7ca28..8eececbd0 100644 --- a/src/issuance.rs +++ b/src/issuance.rs @@ -1,6 +1,7 @@ //! Structs related to issuance bundles and the associated logic. use blake2b_simd::Hash as Blake2bHash; use group::Group; +use memuse::DynamicUsage; use nonempty::NonEmpty; use rand::{CryptoRng, RngCore}; use std::collections::HashSet; @@ -49,6 +50,25 @@ pub struct IssueAction { finalize: bool, } +impl DynamicUsage for IssueAction { + #[inline(always)] + fn dynamic_usage(&self) -> usize { + self.asset_desc.dynamic_usage() + self.notes.dynamic_usage() + } + + #[inline(always)] + fn dynamic_usage_bounds(&self) -> (usize, Option) { + let bounds = ( + self.asset_desc.dynamic_usage_bounds(), + self.notes.dynamic_usage_bounds(), + ); + ( + bounds.0 .0 + bounds.1 .0, + bounds.0 .1.zip(bounds.1 .1).map(|(a, b)| a + b), + ) + } +} + /// The parameters required to add a Note into an IssueAction. #[derive(Debug)] pub struct IssueInfo { @@ -197,6 +217,15 @@ impl IssueAuth for Unauthorized {} impl IssueAuth for Prepared {} impl IssueAuth for Signed {} +impl DynamicUsage for Signed { + fn dynamic_usage(&self) -> usize { + 0 + } + fn dynamic_usage_bounds(&self) -> (usize, Option) { + (0, Some(0)) + } +} + impl IssueBundle { /// Returns the issuer verification key for the bundle. pub fn ik(&self) -> &IssuanceValidatingKey { @@ -455,6 +484,29 @@ impl IssueBundle { } } +impl DynamicUsage for IssueBundle { + fn dynamic_usage(&self) -> usize { + self.actions.dynamic_usage() + self.ik.dynamic_usage() + self.authorization.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + let bounds = ( + self.actions.dynamic_usage_bounds(), + self.ik.dynamic_usage_bounds(), + self.authorization.dynamic_usage_bounds(), + ); + ( + bounds.0 .0 + bounds.1 .0 + bounds.2 .0, + bounds + .0 + .1 + .zip(bounds.1 .1) + .zip(bounds.2 .1) + .map(|((a, b), c)| a + b + c), + ) + } +} + /// Validation for Orchard IssueBundles /// /// A set of previously finalized asset types must be provided in `finalized` argument. @@ -1395,14 +1447,27 @@ mod tests { #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] pub mod testing { use crate::issuance::{IssueAction, IssueBundle, Prepared, Signed, Unauthorized}; - use crate::keys::testing::{arb_issuance_authorizing_key, arb_issuance_validating_key}; + use crate::keys::testing::arb_issuance_validating_key; use crate::note::asset_base::testing::zsa_asset_id; use crate::note::testing::arb_zsa_note; + use crate::primitives::redpallas::Signature; use nonempty::NonEmpty; use proptest::collection::vec; use proptest::prelude::*; use proptest::prop_compose; - use rand::{rngs::StdRng, SeedableRng}; + use reddsa::orchard::SpendAuth; + + prop_compose! { + /// Generate a uniformly distributed signature + pub(crate) fn arb_signature()( + half_bytes in prop::array::uniform32(prop::num::u8::ANY) + ) -> Signature { + // prop::array can only generate 32 elements max, so we duplicate it + let sig_bytes: [u8; 64] = [half_bytes, half_bytes].concat().try_into().unwrap(); + let sig: Signature = Signature::from(sig_bytes); + sig + } + } prop_compose! { /// Generate an issue action @@ -1462,17 +1527,14 @@ pub mod testing { ( actions in vec(arb_issue_action("asset_desc".to_string()), n_actions), ik in arb_issuance_validating_key(), - isk in arb_issuance_authorizing_key(), - rng_seed in prop::array::uniform32(prop::num::u8::ANY), - fake_sighash in prop::array::uniform32(prop::num::u8::ANY) + fake_sig in arb_signature(), ) -> IssueBundle { - let rng = StdRng::from_seed(rng_seed); let actions = NonEmpty::from_vec(actions).unwrap(); IssueBundle { ik, actions, - authorization: Prepared { sighash: fake_sighash }, - }.sign(rng, &isk).unwrap() + authorization: Signed { signature: fake_sig }, + } } } } diff --git a/src/keys.rs b/src/keys.rs index 7853d4920..7238b0684 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -11,6 +11,7 @@ use group::{ prime::PrimeCurveAffine, Curve, GroupEncoding, }; +use memuse::DynamicUsage; use pasta_curves::{pallas, pallas::Scalar}; use rand::{CryptoRng, RngCore}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -349,6 +350,18 @@ impl PartialEq for IssuanceValidatingKey { impl Eq for IssuanceValidatingKey {} +impl DynamicUsage for IssuanceValidatingKey { + #[inline(always)] + fn dynamic_usage(&self) -> usize { + 0 + } + + #[inline(always)] + fn dynamic_usage_bounds(&self) -> (usize, Option) { + (0, Some(0)) + } +} + impl IssuanceValidatingKey { /// Converts this spend validating key to its serialized form, /// I2LEOSP_256(ik). diff --git a/src/note.rs b/src/note.rs index 61a9f9a99..79cfbca8d 100644 --- a/src/note.rs +++ b/src/note.rs @@ -2,6 +2,7 @@ use core::fmt; use group::GroupEncoding; +use memuse::DynamicUsage; use pasta_curves::pallas; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, CtOption}; @@ -306,6 +307,18 @@ impl Note { } } +impl DynamicUsage for Note { + #[inline(always)] + fn dynamic_usage(&self) -> usize { + 0 + } + + #[inline(always)] + fn dynamic_usage_bounds(&self) -> (usize, Option) { + (0, Some(0)) + } +} + /// An encrypted note. #[derive(Clone)] pub struct TransmittedNoteCiphertext {