diff --git a/Cargo.toml b/Cargo.toml index 16b06c522..87e85b1e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ multicore = ["halo2_proofs?/multicore"] dev-graph = ["halo2_proofs?/dev-graph", "image", "plotters"] test-dependencies = ["proptest", "rand/std"] zsa-issuance = ["dep:secp256k1"] +temporary-zebra = [] [[bench]] name = "note_decryption" diff --git a/src/bundle.rs b/src/bundle.rs index a4377e9a7..8d97e8463 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -460,7 +460,7 @@ pub(crate) fn derive_bvk<'a, A: 'a, V: Clone + Into, Pr: 'a + OrchardPrimit ) -> redpallas::VerificationKey { derive_bvk_raw( actions.into_iter().map(|a| a.cv_net()), - ValueSum::from_raw(value_balance.into()), + ValueSum::from_raw_inner(value_balance.into()), burn, ) } @@ -553,7 +553,7 @@ impl Bundle { /// for a given [`OrchardSighashKind`]. pub fn authorizing_commitment( &self, - sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> &'static [u8], + sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> Vec, ) -> BundleAuthorizingCommitment { BundleAuthorizingCommitment(hash_bundle_auth_data(self, sighash_info_for_kind)) } diff --git a/src/bundle/commitments.rs b/src/bundle/commitments.rs index 3622cfa73..aca7d2198 100644 --- a/src/bundle/commitments.rs +++ b/src/bundle/commitments.rs @@ -80,7 +80,7 @@ pub fn hash_bundle_txid_empty() -> Blake2bHash { /// [zip246]: https://zips.z.cash/zip-0246 pub(crate) fn hash_bundle_auth_data( bundle: &Bundle, - sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> &'static [u8], + sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> Vec, ) -> Blake2bHash { Pr::hash_bundle_auth_data(bundle, sighash_info_for_kind) } diff --git a/src/bundle/commitments/issuance.rs b/src/bundle/commitments/issuance.rs index c2822fe4e..22eb266eb 100644 --- a/src/bundle/commitments/issuance.rs +++ b/src/bundle/commitments/issuance.rs @@ -1,5 +1,6 @@ //! Issuance-related commitment functions (ZSA feature) +use alloc::vec::Vec; use blake2b_simd::Hash as Blake2bHash; use crate::{ @@ -67,12 +68,12 @@ pub fn hash_issue_bundle_auth_empty() -> Blake2bHash { /// [zip246]: https://zips.z.cash/zip-0246 pub(crate) fn hash_issue_bundle_auth_data( bundle: &IssueBundle, - sighash_info_for_kind: impl Fn(&IssueSighashKind) -> &'static [u8], + sighash_info_for_kind: impl Fn(&IssueSighashKind) -> Vec, ) -> Blake2bHash { let mut h = hasher(ZCASH_ORCHARD_ZSA_ISSUE_SIG_PERSONALIZATION); let sighash_info = sighash_info_for_kind(bundle.authorization().signature().sighash_kind()); h.update(&get_compact_size(sighash_info.len())); - h.update(sighash_info); + h.update(sighash_info.as_slice()); let sig_enc = bundle.authorization().signature().sig().encode(); assert_eq!(sig_enc.len(), 65); diff --git a/src/issuance.rs b/src/issuance.rs index 5a13d463a..a5227657f 100644 --- a/src/issuance.rs +++ b/src/issuance.rs @@ -245,7 +245,7 @@ impl IssueAction { } // The total amount should not overflow - (value_sum + note.value()).ok_or(ValueOverflow) + value_sum.add(note.value()).ok_or(ValueOverflow) })?; Ok((issue_asset, value_sum)) @@ -638,7 +638,7 @@ impl IssueBundle { /// for a given [`IssueSighashKind`]. pub fn authorizing_commitment( &self, - sighash_info_for_kind: impl Fn(&IssueSighashKind) -> &'static [u8], + sighash_info_for_kind: impl Fn(&IssueSighashKind) -> Vec, ) -> IssueBundleAuthorizingCommitment { IssueBundleAuthorizingCommitment(hash_issue_bundle_auth_data(self, sighash_info_for_kind)) } @@ -735,7 +735,7 @@ pub fn verify_issue_bundle( // Subsequent issuance of the asset Some(current_record) => { - let amount = (current_record.amount + amount).ok_or(ValueOverflow)?; + let amount = current_record.amount.add(amount).ok_or(ValueOverflow)?; if current_record.is_finalized { return Err(IssueActionPreviouslyFinalizedAssetBase); diff --git a/src/issuance/sighash_kind.rs b/src/issuance/sighash_kind.rs index 7410978d9..bea2a77e6 100644 --- a/src/issuance/sighash_kind.rs +++ b/src/issuance/sighash_kind.rs @@ -2,6 +2,9 @@ use crate::issuance::auth::{IssueAuthSig, IssueAuthSigScheme, ZSASchnorr}; +#[cfg(test)] +use alloc::vec::Vec; + /// The kind of data that a sighash commits to. /// /// This is used to implement [sighash versioning] for issuance transactions. @@ -45,8 +48,8 @@ pub type BIP340IssueAuthSig = IssueSig; /// /// This helper is only intended for use in tests. #[cfg(test)] -pub fn test_sighash_info_for_kind(kind: &IssueSighashKind) -> &'static [u8] { +pub fn test_sighash_info_for_kind(kind: &IssueSighashKind) -> Vec { match kind { - IssueSighashKind::AllEffecting => &[0], + IssueSighashKind::AllEffecting => vec![0], } } diff --git a/src/primitives/orchard_primitives.rs b/src/primitives/orchard_primitives.rs index 8361d2c5f..afccabdc3 100644 --- a/src/primitives/orchard_primitives.rs +++ b/src/primitives/orchard_primitives.rs @@ -1,6 +1,7 @@ //! The OrchardPrimitives trait represents the difference between the `OrchardVanilla` and the //! `OrchardZSA` commitment, encryption and decryption procedures. +use alloc::vec::Vec; use core::fmt; use blake2b_simd::Hash as Blake2bHash; @@ -66,7 +67,7 @@ pub trait OrchardPrimitives: fmt::Debug + Clone { /// [zip246]: https://zips.z.cash/zip-0246 fn hash_bundle_auth_data( bundle: &Bundle, - sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> &'static [u8], + sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> Vec, ) -> Blake2bHash; /// Returns true if the note plaintext leadByte is equal to diff --git a/src/primitives/orchard_primitives_vanilla.rs b/src/primitives/orchard_primitives_vanilla.rs index 30edf14f0..4335ad325 100644 --- a/src/primitives/orchard_primitives_vanilla.rs +++ b/src/primitives/orchard_primitives_vanilla.rs @@ -1,6 +1,7 @@ //! This module implements the note encryption and commitment logic specific for the //! `OrchardVanilla` flavor. +use alloc::vec::Vec; use blake2b_simd::Hash as Blake2bHash; use zcash_note_encryption::note_bytes::NoteBytesData; @@ -96,7 +97,7 @@ impl OrchardPrimitives for OrchardVanilla { /// [zip244]: https://zips.z.cash/zip-0244 fn hash_bundle_auth_data( bundle: &Bundle, - _sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> &'static [u8], + _sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> Vec, ) -> Blake2bHash { let mut h = hasher(ZCASH_ORCHARD_SIGS_HASH_PERSONALIZATION); h.update(bundle.authorization().proof().as_ref()); diff --git a/src/primitives/orchard_primitives_zsa.rs b/src/primitives/orchard_primitives_zsa.rs index a63d296e2..74af182c3 100644 --- a/src/primitives/orchard_primitives_zsa.rs +++ b/src/primitives/orchard_primitives_zsa.rs @@ -1,6 +1,7 @@ //! This module implements the note encryption and commitment logic specific for the `OrchardZSA` //! flavor. +use alloc::vec::Vec; use blake2b_simd::Hash as Blake2bHash; use zcash_note_encryption::note_bytes::NoteBytesData; @@ -128,7 +129,7 @@ impl OrchardPrimitives for OrchardZSA { /// [zip246]: https://zips.z.cash/zip-0246 fn hash_bundle_auth_data( bundle: &Bundle, - sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> &'static [u8], + sighash_info_for_kind: impl Fn(&OrchardSighashKind) -> Vec, ) -> Blake2bHash { let mut h = hasher(ZCASH_ORCHARD_SIGS_HASH_PERSONALIZATION); let mut agh = hasher(ZCASH_ORCHARD_ACTION_GROUPS_SIGS_HASH_PERSONALIZATION); @@ -137,7 +138,7 @@ impl OrchardPrimitives for OrchardZSA { for action in bundle.actions().iter() { let sighash_info = sighash_info_for_kind(action.authorization().sighash_kind()); sash.update(&get_compact_size(sighash_info.len())); - sash.update(sighash_info); + sash.update(sighash_info.as_slice()); sash.update(&<[u8; 64]>::from(action.authorization().sig())); } agh.update(sash.finalize().as_bytes()); @@ -146,7 +147,7 @@ impl OrchardPrimitives for OrchardZSA { let sighash_info = sighash_info_for_kind(bundle.authorization().binding_signature().sighash_kind()); h.update(&get_compact_size(sighash_info.len())); - h.update(sighash_info); + h.update(sighash_info.as_slice()); h.update(&<[u8; 64]>::from( bundle.authorization().binding_signature().sig(), )); diff --git a/src/sighash_kind.rs b/src/sighash_kind.rs index 1e98751df..22277b6d2 100644 --- a/src/sighash_kind.rs +++ b/src/sighash_kind.rs @@ -2,6 +2,9 @@ use crate::primitives::redpallas::{Binding, SigType, Signature, SpendAuth}; +#[cfg(test)] +use alloc::vec::Vec; + /// The kind of data that a sighash commits to. /// /// This is used to implement [sighash versioning] for transactions containing Orchard @@ -49,8 +52,8 @@ pub type OrchardBindingSig = OrchardSig; /// /// This helper is only intended for use in tests. #[cfg(test)] -pub fn test_sighash_info_for_kind(kind: &OrchardSighashKind) -> &'static [u8] { +pub fn test_sighash_info_for_kind(kind: &OrchardSighashKind) -> Vec { match kind { - OrchardSighashKind::AllEffecting => &[0], + OrchardSighashKind::AllEffecting => vec![0], } } diff --git a/src/value.rs b/src/value.rs index 28503f5c1..5bce4e448 100644 --- a/src/value.rs +++ b/src/value.rs @@ -120,6 +120,18 @@ impl NoteValue { pub(crate) fn to_le_bits(self) -> BitArray<[u8; 8], Lsb0> { BitArray::<_, Lsb0>::new(self.0.to_le_bytes()) } + + /// Adds two `NoteValue`s. + /// + /// This helper performs checked addition over `NoteValue`s and returns `None` on overflow. + /// It is required by the issuance flow to aggregate per-asset issuance amounts before + /// validating and applying supply changes to the global state. + /// + /// This function is intended for use only by the issuance logic + /// (`IssueAction::verify` and `verify_issue_bundle`). + pub(crate) fn add(self, rhs: Self) -> Option { + self.0.checked_add(rhs.0).map(NoteValue) + } } #[cfg(feature = "circuit")] @@ -143,14 +155,6 @@ impl Sub for NoteValue { } } -impl Add for NoteValue { - type Output = Option; - - fn add(self, rhs: Self) -> Self::Output { - self.0.checked_add(rhs.0).map(NoteValue) - } -} - /// The sign of a [`ValueSum`]. #[derive(Debug)] pub enum Sign { @@ -176,13 +180,19 @@ impl ValueSum { /// in `Bundle::binding_validating_key`, where we are converting from the user-defined /// `valueBalance` type that enforces any additional constraints on the value's valid /// range. + pub(crate) fn from_raw_inner(value: i64) -> Self { + ValueSum(value as i128) + } + + /// Creates a value sum from a raw i64 (which is always in range for this type). /// /// This function needs to be public because Zebra constructs `ValueCommitment`s using /// `ValueCommitment::derive`, which takes a `ValueSum` as input. In order to avoid duplicating /// the `ValueSum` construction logic between Zebra and Orchard, Zebra must be able to create a /// `ValueSum` directly. + #[cfg(feature = "temporary-zebra")] pub fn from_raw(value: i64) -> Self { - ValueSum(value as i128) + Self::from_raw_inner(value) } /// Constructs a value sum from its magnitude and sign.