diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5ecda6e49..6ea608282 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.65.0" +channel = "1.71.0" components = [ "clippy", "rustfmt" ] diff --git a/src/bundle/burn_validation.rs b/src/bundle/burn_validation.rs index d6388f10c..2f9726c8d 100644 --- a/src/bundle/burn_validation.rs +++ b/src/bundle/burn_validation.rs @@ -64,6 +64,7 @@ impl fmt::Display for BurnError { #[cfg(test)] mod tests { + use crate::issuance::compute_asset_desc_hash; use crate::value::NoteValue; use super::*; @@ -88,7 +89,10 @@ mod tests { let isk = IssuanceAuthorizingKey::from_bytes([1u8; 32]).unwrap(); ( - AssetBase::derive(&IssuanceValidatingKey::from(&isk), asset_desc), + AssetBase::derive( + &IssuanceValidatingKey::from(&isk), + &compute_asset_desc_hash(asset_desc).unwrap(), + ), NoteValue::from_raw(value), ) } diff --git a/src/bundle/commitments.rs b/src/bundle/commitments.rs index 88679f046..eed1bf011 100644 --- a/src/bundle/commitments.rs +++ b/src/bundle/commitments.rs @@ -105,7 +105,7 @@ pub(crate) fn hash_issue_bundle_txid_data(bundle: &IssueBundle) ind.update(note.rseed().as_bytes()); } ia.update(ind.finalize().as_bytes()); - ia.update(action.asset_desc()); + ia.update(action.asset_desc_hash()); ia.update(&[u8::from(action.is_finalized())]); } h.update(ia.finalize().as_bytes()); diff --git a/src/issuance.rs b/src/issuance.rs index 531db1811..f1c7c599c 100644 --- a/src/issuance.rs +++ b/src/issuance.rs @@ -12,7 +12,7 @@ //! Errors related to issuance, such as invalid signatures or supply overflows, //! are handled through the `Error` enum. -use blake2b_simd::Hash as Blake2bHash; +use blake2b_simd::{Hash as Blake2bHash, Params}; use group::Group; use k256::schnorr; use nonempty::NonEmpty; @@ -32,10 +32,11 @@ use crate::{Address, Note}; use crate::asset_record::AssetRecord; use Error::{ - AssetBaseCannotBeIdentityPoint, CannotBeFirstIssuance, IssueActionNotFound, - IssueActionPreviouslyFinalizedAssetBase, IssueActionWithoutNoteNotFinalized, - IssueBundleIkMismatchAssetBase, IssueBundleInvalidSignature, - MissingReferenceNoteOnFirstIssuance, ValueOverflow, WrongAssetDescSize, + AssetBaseCannotBeIdentityPoint, CannotBeFirstIssuance, InvalidAssetDescHashLength, + IssueActionNotFound, IssueActionPreviouslyFinalizedAssetBase, + IssueActionWithoutNoteNotFinalized, IssueBundleIkMismatchAssetBase, + IssueBundleInvalidSignature, MissingReferenceNoteOnFirstIssuance, ValueOverflow, + WrongAssetDescSize, }; /// Checks if a given note is a reference note. @@ -63,8 +64,8 @@ pub struct IssueBundle { /// Externally, this creates new zsa notes (adding a commitment to the global ledger). #[derive(Debug, Clone, PartialEq, Eq)] pub struct IssueAction { - /// Asset description for verification. - asset_desc: Vec, + /// Asset description hash for verification. + asset_desc_hash: [u8; 32], /// The newly issued notes. notes: Vec, /// `finalize` will prevent further issuance of the same asset type. @@ -80,33 +81,49 @@ pub struct IssueInfo { pub value: NoteValue, } +/// Compute the asset description hash for a given asset description. +pub fn compute_asset_desc_hash(asset_desc: &[u8]) -> Result<[u8; 32], Error> { + if !is_asset_desc_of_valid_size(asset_desc) { + return Err(WrongAssetDescSize); + } + let mut ah = Params::new() + .hash_length(32) + .personal(b"ZSA-AssetDescCRH") + .to_state(); + ah.update(asset_desc); + ah.finalize() + .as_bytes() + .try_into() + .map_err(|_| InvalidAssetDescHashLength) +} + impl IssueAction { /// Constructs a new `IssueAction`. - pub fn new_with_flags(asset_desc: Vec, notes: Vec, flags: u8) -> Option { + pub fn new_with_flags(asset_desc_hash: [u8; 32], notes: Vec, flags: u8) -> Option { let finalize = match flags { 0b0000_0000 => false, 0b0000_0001 => true, _ => return None, }; Some(IssueAction { - asset_desc, + asset_desc_hash, notes, finalize, }) } /// Constructs an `IssueAction` from its constituent parts. - pub fn from_parts(asset_desc: Vec, notes: Vec, finalize: bool) -> Self { + pub fn from_parts(asset_desc_hash: [u8; 32], notes: Vec, finalize: bool) -> Self { IssueAction { - asset_desc, + asset_desc_hash, notes, finalize, } } - /// Returns the asset description for the note being created. - pub fn asset_desc(&self) -> &[u8] { - &self.asset_desc + /// Returns the asset description hash for the note being created. + pub fn asset_desc_hash(&self) -> &[u8; 32] { + &self.asset_desc_hash } /// Returns the issued notes. @@ -138,24 +155,19 @@ impl IssueAction { /// /// This function may return an error in any of the following cases: /// - /// * `WrongAssetDescSize`: The asset description size is invalid. /// * `ValueOverflow`: The total amount value of all notes in the `IssueAction` overflows. /// * `IssueBundleIkMismatchAssetBase`: The provided `ik` is not used to derive the /// `AssetBase` for **all** internal notes. /// * `IssueActionWithoutNoteNotFinalized`: The `IssueAction` contains no notes and is not finalized. fn verify(&self, ik: &IssuanceValidatingKey) -> Result<(AssetBase, NoteValue), Error> { - if !is_asset_desc_of_valid_size(self.asset_desc()) { - return Err(WrongAssetDescSize); - } - if self.notes.is_empty() && !self.is_finalized() { return Err(IssueActionWithoutNoteNotFinalized); } - let issue_asset = AssetBase::derive(ik, &self.asset_desc); + let issue_asset = AssetBase::derive(ik, &self.asset_desc_hash); // Calculate the value of the asset as a sum of values of all its notes - // and ensure all note types are equal the asset derived from asset_desc and ik. + // and ensure all note types are equal the asset derived from asset_desc_hash and ik. let value_sum = self .notes .iter() @@ -258,26 +270,26 @@ impl IssueBundle { &self.authorization } - /// Find the action corresponding to the `asset_desc` for a given `IssueBundle`. + /// Find the action corresponding to the `asset_desc_hash` for a given `IssueBundle`. /// /// # Returns /// /// If a single matching action is found, it is returned as `Some(&IssueAction)`. - /// If no action matches the given `asset_desc`, it returns `None`. + /// If no action matches the given `asset_desc_hash`, it returns `None`. /// /// # Panics /// /// Panics if multiple matching actions are found. - pub fn get_action_by_desc(&self, asset_desc: &[u8]) -> Option<&IssueAction> { + pub fn get_action_by_desc_hash(&self, asset_desc_hash: &[u8; 32]) -> Option<&IssueAction> { let issue_actions: Vec<&IssueAction> = self .actions .iter() - .filter(|a| a.asset_desc.eq(asset_desc)) + .filter(|a| a.asset_desc_hash.eq(asset_desc_hash)) .collect(); match issue_actions.len() { 0 => None, 1 => Some(issue_actions[0]), - _ => panic!("Multiple IssueActions with the same asset_desc"), + _ => panic!("Multiple IssueActions with the same asset_desc_hash"), } } @@ -295,7 +307,7 @@ impl IssueBundle { let issue_actions: Vec<&IssueAction> = self .actions .iter() - .filter(|a| AssetBase::derive(&self.ik, &a.asset_desc).eq(asset)) + .filter(|a| AssetBase::derive(&self.ik, &a.asset_desc_hash).eq(asset)) .collect(); match issue_actions.len() { 0 => None, @@ -347,25 +359,15 @@ impl IssueBundle { /// set to zero. The rho value will be updated later by calling the `update_rho` method. /// /// If `first_issuance` is true, the `IssueBundle` will contain a reference note for the asset - /// defined by (`asset_desc`, `ik`). - /// - /// # Errors - /// - /// This function may return an error in any of the following cases: - /// - /// * `WrongAssetDescSize`: The `asset_desc` is empty or longer than 512 bytes. + /// defined by (`asset_desc_hash`, `ik`). pub fn new( ik: IssuanceValidatingKey, - asset_desc: Vec, + asset_desc_hash: [u8; 32], issue_info: Option, first_issuance: bool, mut rng: impl RngCore, - ) -> Result<(IssueBundle, AssetBase), Error> { - if !is_asset_desc_of_valid_size(&asset_desc) { - return Err(WrongAssetDescSize); - } - - let asset = AssetBase::derive(&ik, &asset_desc); + ) -> (IssueBundle, AssetBase) { + let asset = AssetBase::derive(&ik, &asset_desc_hash); let mut notes = vec![]; if first_issuance { @@ -374,7 +376,7 @@ impl IssueBundle { let action = match issue_info { None => IssueAction { - asset_desc, + asset_desc_hash, notes, finalize: true, }, @@ -390,47 +392,37 @@ impl IssueBundle { notes.push(note); IssueAction { - asset_desc, + asset_desc_hash, notes, finalize: false, } } }; - Ok(( + ( IssueBundle { ik, actions: NonEmpty::new(action), authorization: AwaitingNullifier, }, asset, - )) + ) } /// Add a new note to the `IssueBundle`. /// /// Rho is set to zero. The rho value will be updated later by calling the `update_rho` method. /// If `first_issuance` is true, we will also add a reference note for the asset defined by - /// (`asset_desc`, `ik`). - /// - /// # Errors - /// - /// This function may return an error in any of the following cases: - /// - /// * `WrongAssetDescSize`: The `asset_desc` is empty or longer than 512 bytes. + /// (`asset_desc_hash`, `ik`). pub fn add_recipient( &mut self, - asset_desc: &[u8], + asset_desc_hash: [u8; 32], recipient: Address, value: NoteValue, first_issuance: bool, mut rng: impl RngCore, ) -> Result { - if !is_asset_desc_of_valid_size(asset_desc) { - return Err(WrongAssetDescSize); - } - - let asset = AssetBase::derive(&self.ik, asset_desc); + let asset = AssetBase::derive(&self.ik, &asset_desc_hash); let note = Note::new(recipient, value, asset, Rho::zero(), &mut rng); @@ -443,7 +435,7 @@ impl IssueBundle { let action = self .actions .iter_mut() - .find(|issue_action| issue_action.asset_desc.eq(asset_desc)); + .find(|issue_action| issue_action.asset_desc_hash.eq(&asset_desc_hash)); match action { Some(action) => { @@ -457,7 +449,7 @@ impl IssueBundle { None => { // Insert a new IssueAction. self.actions.push(IssueAction { - asset_desc: Vec::from(asset_desc), + asset_desc_hash, notes, finalize: false, }); @@ -468,19 +460,11 @@ impl IssueBundle { } /// Finalizes a given `IssueAction` - /// - /// # Panics - /// - /// Panics if `asset_desc` is empty or longer than 512 bytes. - pub fn finalize_action(&mut self, asset_desc: &[u8]) -> Result<(), Error> { - if !is_asset_desc_of_valid_size(asset_desc) { - return Err(WrongAssetDescSize); - } - + pub fn finalize_action(&mut self, asset_desc_hash: &[u8; 32]) -> Result<(), Error> { match self .actions .iter_mut() - .find(|issue_action| issue_action.asset_desc.eq(asset_desc)) + .find(|issue_action| issue_action.asset_desc_hash.eq(asset_desc_hash)) { Some(issue_action) => { issue_action.finalize = true; @@ -687,6 +671,8 @@ pub enum Error { IssueBundleIkMismatchAssetBase, /// `asset_desc` should be between 1 and 512 bytes. WrongAssetDescSize, + /// The length of the asset description hash is invalid. + InvalidAssetDescHashLength, /// The `IssueAction` is not finalized but contains no notes. IssueActionWithoutNoteNotFinalized, /// The `AssetBase` is the Pallas identity point, which is invalid. @@ -722,6 +708,9 @@ impl fmt::Display for Error { WrongAssetDescSize => { write!(f, "`asset_desc` should be between 1 and 512 bytes") } + InvalidAssetDescHashLength => { + write!(f, "the length of the asset description hash is invalid") + } IssueActionWithoutNoteNotFinalized => { write!( f, @@ -764,7 +753,7 @@ impl fmt::Display for Error { #[cfg(test)] mod tests { - use super::{AssetRecord, IssueBundle, IssueInfo}; + use super::{compute_asset_desc_hash, AssetRecord, IssueBundle, IssueInfo}; use crate::{ builder::{Builder, BundleType}, circuit::ProvingKey, @@ -857,8 +846,11 @@ mod tests { .. } = setup_params(); - let asset = AssetBase::derive(&ik, note1_asset_desc); - let note2_asset = note2_asset_desc.map_or(asset, |desc| AssetBase::derive(&ik, desc)); + let note1_asset_desc_hash = compute_asset_desc_hash(note1_asset_desc).unwrap(); + let asset = AssetBase::derive(&ik, ¬e1_asset_desc_hash); + let note2_asset = note2_asset_desc.map_or(asset, |desc| { + AssetBase::derive(&ik, &compute_asset_desc_hash(desc).unwrap()) + }); let note1 = Note::new( recipient, @@ -879,7 +871,7 @@ mod tests { ( ik, asset, - IssueAction::from_parts(note1_asset_desc.to_vec(), vec![note1, note2], finalize), + IssueAction::from_parts(note1_asset_desc_hash, vec![note1, note2], finalize), ) } @@ -928,8 +920,11 @@ mod tests { &mut rng, ); - let action = - IssueAction::from_parts("arbitrary asset_desc".into(), vec![note1, note2], false); + let action = IssueAction::from_parts( + compute_asset_desc_hash(b"arbitrary asset_desc").unwrap(), + vec![note1, note2], + false, + ); let bundle = IssueBundle::from_parts(ik, NonEmpty::new(action), AwaitingNullifier); @@ -1002,54 +997,30 @@ mod tests { .. } = setup_params(); - let str = "Halo".to_string(); - let str2 = "Halo2".to_string(); + let asset_desc_hash_1 = compute_asset_desc_hash(b"Halo").unwrap(); + let asset_desc_hash_2 = compute_asset_desc_hash(b"Halo2").unwrap(); assert_eq!( - IssueBundle::new( - ik.clone(), - vec![b'X'; 513], - Some(IssueInfo { - recipient, - value: NoteValue::unsplittable() - }), - true, - rng, - ) - .unwrap_err(), - WrongAssetDescSize + compute_asset_desc_hash(&vec![b'X'; 513]), + Err(WrongAssetDescSize) ); - assert_eq!( - IssueBundle::new( - ik.clone(), - b"".to_vec(), - Some(IssueInfo { - recipient, - value: NoteValue::unsplittable() - }), - true, - rng, - ) - .unwrap_err(), - WrongAssetDescSize - ); + assert_eq!(compute_asset_desc_hash(b""), Err(WrongAssetDescSize)); let (mut bundle, asset) = IssueBundle::new( ik.clone(), - str.clone().into_bytes(), + asset_desc_hash_1, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let another_asset = bundle .add_recipient( - &str.into_bytes(), + asset_desc_hash_1, recipient, NoteValue::from_raw(10), false, @@ -1060,7 +1031,7 @@ mod tests { let third_asset = bundle .add_recipient( - str2.as_bytes(), + asset_desc_hash_2, recipient, NoteValue::from_raw(15), true, @@ -1101,11 +1072,11 @@ mod tests { assert_eq!(second_note.recipient(), recipient); let action2 = awaiting_sighash_bundle - .get_action_by_desc(str2.as_bytes()) + .get_action_by_desc_hash(&asset_desc_hash_2) .unwrap(); assert_eq!(action2.notes.len(), 2); let reference_note = action2.notes.get(0).unwrap(); - verify_reference_note(reference_note, AssetBase::derive(&ik, str2.as_bytes())); + verify_reference_note(reference_note, AssetBase::derive(&ik, &asset_desc_hash_2)); let first_note = action2.notes().get(1).unwrap(); assert_eq!(first_note.value().inner(), 15); assert_eq!(first_note.asset(), third_asset); @@ -1120,33 +1091,30 @@ mod tests { rng, ik, recipient, .. } = setup_params(); + let nft_asset_desc_hash = compute_asset_desc_hash(b"NFT").unwrap(); + let another_nft_asset_desc_hash = compute_asset_desc_hash(b"Another NFT").unwrap(); + let (mut bundle, _) = IssueBundle::new( ik, - b"NFT".to_vec(), + nft_asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(u64::MIN), }), true, rng, - ) - .expect("Should properly add recipient"); + ); bundle - .finalize_action(b"NFT") + .finalize_action(&nft_asset_desc_hash) .expect("Should finalize properly"); assert_eq!( - bundle.finalize_action(b"Another NFT").unwrap_err(), + bundle + .finalize_action(&another_nft_asset_desc_hash) + .unwrap_err(), IssueActionNotFound ); - - assert_eq!( - bundle.finalize_action(&vec![b'X'; 513]).unwrap_err(), - WrongAssetDescSize - ); - - assert_eq!(bundle.finalize_action(b"").unwrap_err(), WrongAssetDescSize); } #[test] @@ -1160,17 +1128,18 @@ mod tests { .. } = setup_params(); + let asset_desc_hash = compute_asset_desc_hash(b"Frost").unwrap(); + let (bundle, _) = IssueBundle::new( ik, - b"Frost".to_vec(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let prepared = bundle.update_rho(&first_nullifier).prepare(sighash); assert_eq!(prepared.authorization().sighash, sighash); @@ -1187,17 +1156,18 @@ mod tests { first_nullifier, } = setup_params(); + let asset_desc_hash = compute_asset_desc_hash(b"Sign").unwrap(); + let (bundle, _) = IssueBundle::new( ik.clone(), - b"Sign".to_vec(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let signed = bundle .update_rho(&first_nullifier) @@ -1219,17 +1189,18 @@ mod tests { .. } = setup_params(); + let asset_desc_hash = compute_asset_desc_hash(b"IssueBundle").unwrap(); + let (bundle, _) = IssueBundle::new( ik, - b"IssueBundle".to_vec(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let wrong_isk: IssuanceAuthorizingKey = IssuanceAuthorizingKey::random(); @@ -1256,21 +1227,20 @@ mod tests { // Create a bundle with "normal" note let (mut bundle, _) = IssueBundle::new( ik, - b"IssueBundle".to_vec(), + compute_asset_desc_hash(b"IssueBundle").unwrap(), Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); // Add "bad" note let note = Note::new( recipient, NoteValue::from_raw(5), - AssetBase::derive(bundle.ik(), b"zsa_asset"), + AssetBase::derive(bundle.ik(), &compute_asset_desc_hash(b"zsa_asset").unwrap()), Rho::zero(), &mut rng, ); @@ -1296,17 +1266,18 @@ mod tests { first_nullifier, } = setup_params(); + let asset_desc_hash = compute_asset_desc_hash(b"Verify").unwrap(); + let (bundle, _) = IssueBundle::new( ik.clone(), - b"Verify".to_vec(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let signed = bundle .update_rho(&first_nullifier) @@ -1320,7 +1291,7 @@ mod tests { assert_eq!( issued_assets, HashMap::from([( - AssetBase::derive(&ik, b"Verify"), + AssetBase::derive(&ik, &asset_desc_hash), AssetRecord::new(NoteValue::from_raw(5), false, first_note) )]) ); @@ -1337,19 +1308,20 @@ mod tests { first_nullifier, } = setup_params(); + let asset_desc_hash = compute_asset_desc_hash(b"Verify with finalize").unwrap(); + let (mut bundle, _) = IssueBundle::new( ik.clone(), - b"Verify with finalize".to_vec(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(7), }), true, rng, - ) - .unwrap(); + ); - bundle.finalize_action(b"Verify with finalize").unwrap(); + bundle.finalize_action(&asset_desc_hash).unwrap(); let signed = bundle .update_rho(&first_nullifier) @@ -1363,7 +1335,7 @@ mod tests { assert_eq!( issued_assets, HashMap::from([( - AssetBase::derive(&ik, b"Verify with finalize"), + AssetBase::derive(&ik, &asset_desc_hash), AssetRecord::new(NoteValue::from_raw(7), true, first_note) )]) ); @@ -1380,40 +1352,57 @@ mod tests { first_nullifier, } = setup_params(); - let asset1_desc = b"Verify with issued assets 1".to_vec(); - let asset2_desc = b"Verify with issued assets 2".to_vec(); - let asset3_desc = b"Verify with issued assets 3".to_vec(); + let asset1_desc_hash = compute_asset_desc_hash(b"Verify with issued assets 1").unwrap(); + let asset2_desc_hash = compute_asset_desc_hash(b"Verify with issued assets 2").unwrap(); + let asset3_desc_hash = compute_asset_desc_hash(b"Verify with issued assets 3").unwrap(); - let asset1_base = AssetBase::derive(&ik, &asset1_desc); - let asset2_base = AssetBase::derive(&ik, &asset2_desc); - let asset3_base = AssetBase::derive(&ik, &asset3_desc); + let asset1_base = AssetBase::derive(&ik, &asset1_desc_hash); + let asset2_base = AssetBase::derive(&ik, &asset2_desc_hash); + let asset3_base = AssetBase::derive(&ik, &asset3_desc_hash); let (mut bundle, _) = IssueBundle::new( ik, - asset1_desc.clone(), + asset1_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(7), }), true, rng, - ) - .unwrap(); + ); bundle - .add_recipient(&asset1_desc, recipient, NoteValue::from_raw(8), false, rng) + .add_recipient( + asset1_desc_hash, + recipient, + NoteValue::from_raw(8), + false, + rng, + ) .unwrap(); - bundle.finalize_action(&asset1_desc).unwrap(); + bundle.finalize_action(&asset1_desc_hash).unwrap(); bundle - .add_recipient(&asset2_desc, recipient, NoteValue::from_raw(10), true, rng) + .add_recipient( + asset2_desc_hash, + recipient, + NoteValue::from_raw(10), + true, + rng, + ) .unwrap(); - bundle.finalize_action(&asset2_desc).unwrap(); + bundle.finalize_action(&asset2_desc_hash).unwrap(); bundle - .add_recipient(&asset3_desc, recipient, NoteValue::from_raw(5), true, rng) + .add_recipient( + asset3_desc_hash, + recipient, + NoteValue::from_raw(5), + true, + rng, + ) .unwrap(); let signed = bundle @@ -1467,17 +1456,18 @@ mod tests { first_nullifier, } = setup_params(); + let asset_desc_hash = compute_asset_desc_hash(b"already final").unwrap(); + let (bundle, _) = IssueBundle::new( ik.clone(), - b"already final".to_vec(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let signed = bundle .update_rho(&first_nullifier) @@ -1485,7 +1475,7 @@ mod tests { .sign(&isk) .unwrap(); - let final_type = AssetBase::derive(&ik, b"already final"); + let final_type = AssetBase::derive(&ik, &asset_desc_hash); let issued_assets = [( final_type, @@ -1531,15 +1521,14 @@ mod tests { let (bundle, _) = IssueBundle::new( ik, - b"bad sig".to_vec(), + crate::issuance::compute_asset_desc_hash(b"bad sig").unwrap(), Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let wrong_isk: IssuanceAuthorizingKey = IssuanceAuthorizingKey::random(); @@ -1572,15 +1561,14 @@ mod tests { let (bundle, _) = IssueBundle::new( ik, - b"Asset description".to_vec(), + compute_asset_desc_hash(b"Asset description").unwrap(), Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let sighash: [u8; 32] = bundle.commitment().into(); let signed = bundle @@ -1608,15 +1596,14 @@ mod tests { let (bundle, _) = IssueBundle::new( ik, - b"Asset description".to_vec(), + compute_asset_desc_hash(b"Asset description").unwrap(), Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let mut signed = bundle .update_rho(&first_nullifier) @@ -1628,7 +1615,7 @@ mod tests { let note = Note::new( recipient, NoteValue::from_raw(5), - AssetBase::derive(signed.ik(), b"zsa_asset"), + AssetBase::derive(signed.ik(), &compute_asset_desc_hash(b"zsa_asset").unwrap()), Rho::zero(), &mut rng, ); @@ -1643,7 +1630,7 @@ mod tests { #[test] fn issue_bundle_verify_fail_incorrect_ik() { - let asset_description = b"Asset".to_vec(); + let asset_desc_hash = compute_asset_desc_hash(b"Asset").unwrap(); let TestParams { mut rng, @@ -1656,15 +1643,14 @@ mod tests { let (bundle, _) = IssueBundle::new( ik, - asset_description.clone(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let mut signed = bundle .update_rho(&first_nullifier) @@ -1679,7 +1665,7 @@ mod tests { let note = Note::new( recipient, NoteValue::from_raw(55), - AssetBase::derive(&incorrect_ik, &asset_description), + AssetBase::derive(&incorrect_ik, &asset_desc_hash), Rho::zero(), &mut rng, ); @@ -1692,59 +1678,6 @@ mod tests { ); } - #[test] - fn issue_bundle_verify_fail_wrong_asset_descr_size() { - // we want to inject a "malformed" description for test purposes. - impl IssueAction { - pub fn modify_descr(&mut self, new_descr: Vec) { - self.asset_desc = new_descr; - } - } - - let TestParams { - rng, - isk, - ik, - recipient, - sighash, - first_nullifier, - } = setup_params(); - - let (bundle, _) = IssueBundle::new( - ik, - b"Asset description".to_vec(), - Some(IssueInfo { - recipient, - value: NoteValue::from_raw(5), - }), - true, - rng, - ) - .unwrap(); - - let mut signed = bundle - .update_rho(&first_nullifier) - .prepare(sighash) - .sign(&isk) - .unwrap(); - - // 1. Try a description that is too long - signed.actions.first_mut().modify_descr(vec![b'X'; 513]); - - assert_eq!( - verify_issue_bundle(&signed, sighash, |_| None).unwrap_err(), - WrongAssetDescSize - ); - - // 2. Try a description that is empty - signed.actions.first_mut().modify_descr(b"".to_vec()); - - assert_eq!( - verify_issue_bundle(&signed, sighash, |_| None).unwrap_err(), - WrongAssetDescSize - ); - } - #[test] fn issue_bundle_cannot_be_signed_with_asset_base_identity_point() { let (isk, bundle, sighash, first_nullifier) = identity_point_test_params(10, 20); @@ -1782,15 +1715,15 @@ mod tests { let mut rng = OsRng; let (_, _, note) = Note::dummy(&mut rng, None, AssetBase::native()); - let action = - IssueAction::new_with_flags(b"Asset description".to_vec(), vec![note], 0u8).unwrap(); + let asset_desc_hash = compute_asset_desc_hash(b"Asset description").unwrap(); + + let action = IssueAction::new_with_flags(asset_desc_hash, vec![note], 0u8).unwrap(); assert_eq!(action.flags(), 0b0000_0000); - let action = - IssueAction::new_with_flags(b"Asset description".to_vec(), vec![note], 1u8).unwrap(); + let action = IssueAction::new_with_flags(asset_desc_hash, vec![note], 1u8).unwrap(); assert_eq!(action.flags(), 0b0000_0001); - let action = IssueAction::new_with_flags(b"Asset description".to_vec(), vec![note], 2u8); + let action = IssueAction::new_with_flags(asset_desc_hash, vec![note], 2u8); assert!(action.is_none()); } @@ -1806,43 +1739,58 @@ mod tests { .as_bytes() .to_vec(); + let asset_desc_hash_1 = compute_asset_desc_hash(&asset_desc_1).unwrap(); + // Not well-formed as per Unicode 15.0 specification, Section 3.9, D92 let asset_desc_2: Vec = vec![0xc0, 0xaf]; + let asset_desc_hash_2 = compute_asset_desc_hash(&asset_desc_2).unwrap(); + // Confirm not valid UTF-8 assert!(String::from_utf8(asset_desc_2.clone()).is_err()); let (mut bundle, asset_base_1) = IssueBundle::new( ik, - asset_desc_1.clone(), + asset_desc_hash_1, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let asset_base_2 = bundle - .add_recipient(&asset_desc_2, recipient, NoteValue::from_raw(10), true, rng) + .add_recipient( + asset_desc_hash_2, + recipient, + NoteValue::from_raw(10), + true, + rng, + ) .unwrap(); // Checks for the case of UTF-8 encoded asset description. let action = bundle.get_action_by_asset(&asset_base_1).unwrap(); - assert_eq!(action.asset_desc(), &asset_desc_1); + assert_eq!(action.asset_desc_hash(), &asset_desc_hash_1); let reference_note = action.notes.get(0).unwrap(); verify_reference_note(reference_note, asset_base_1); assert_eq!(action.notes.get(1).unwrap().value().inner(), 5); - assert_eq!(bundle.get_action_by_desc(&asset_desc_1).unwrap(), action); + assert_eq!( + bundle.get_action_by_desc_hash(&asset_desc_hash_1).unwrap(), + action + ); // Checks for the case on non-UTF-8 encoded asset description. let action2 = bundle.get_action_by_asset(&asset_base_2).unwrap(); - assert_eq!(action2.asset_desc(), &asset_desc_2); + assert_eq!(action2.asset_desc_hash(), &asset_desc_hash_2); let reference_note = action2.notes.get(0).unwrap(); verify_reference_note(reference_note, asset_base_2); assert_eq!(action2.notes.get(1).unwrap().value().inner(), 10); - assert_eq!(bundle.get_action_by_desc(&asset_desc_2).unwrap(), action2); + assert_eq!( + bundle.get_action_by_desc_hash(&asset_desc_hash_2).unwrap(), + action2 + ); } #[test] @@ -1857,7 +1805,7 @@ mod tests { // Setup note and merkle tree let mut rng = OsRng; - let asset1 = AssetBase::derive(&ik, b"zsa_asset1"); + let asset1 = AssetBase::derive(&ik, &compute_asset_desc_hash(b"zsa_asset1").unwrap()); let note1 = Note::new( recipient, NoteValue::from_raw(10), @@ -1896,23 +1844,22 @@ mod tests { .unwrap(); // Create an issue bundle - let asset2 = "asset2".to_string(); - let asset3 = "asset3".to_string(); + let asset_desc_hash_2 = compute_asset_desc_hash(b"asset2").unwrap(); + let asset_desc_hash_3 = compute_asset_desc_hash(b"asset3").unwrap(); let (mut bundle, asset) = IssueBundle::new( ik, - asset2.clone().into_bytes(), + asset_desc_hash_2, Some(IssueInfo { recipient, value: NoteValue::from_raw(5), }), true, rng, - ) - .unwrap(); + ); let another_asset = bundle .add_recipient( - asset2.as_bytes(), + asset_desc_hash_2, recipient, NoteValue::from_raw(10), false, @@ -1923,7 +1870,7 @@ mod tests { let third_asset = bundle .add_recipient( - asset3.as_bytes(), + asset_desc_hash_3, recipient, NoteValue::from_raw(10), true, @@ -2001,15 +1948,15 @@ pub mod testing { prop_compose! { /// Generate an issue action - pub fn arb_issue_action(asset_desc: Vec) + pub fn arb_issue_action(asset_desc_hash: [u8; 32]) ( - asset in zsa_asset_base(asset_desc.clone()), + asset in zsa_asset_base(asset_desc_hash), ) ( note in arb_zsa_note(asset), )-> IssueAction { IssueAction{ - asset_desc: asset_desc.clone(), + asset_desc_hash, notes: vec![note], finalize: false, } @@ -2020,7 +1967,7 @@ pub mod testing { /// Generate an arbitrary issue bundle with fake authorization data. pub fn arb_awaiting_nullifier_issue_bundle(n_actions: usize) ( - actions in vec(arb_issue_action(b"asset_desc".to_vec()), n_actions), + actions in vec(arb_issue_action([1u8; 32]), n_actions), ik in arb_issuance_validating_key() ) -> IssueBundle { let actions = NonEmpty::from_vec(actions).unwrap(); @@ -2037,7 +1984,7 @@ pub mod testing { /// necessarily respect consensus rules pub fn arb_prepared_issue_bundle(n_actions: usize) ( - actions in vec(arb_issue_action(b"asset_desc".to_vec()), n_actions), + actions in vec(arb_issue_action([1u8; 32]), n_actions), ik in arb_issuance_validating_key(), fake_sighash in prop::array::uniform32(prop::num::u8::ANY) ) -> IssueBundle { @@ -2055,7 +2002,7 @@ pub mod testing { /// necessarily respect consensus rules pub fn arb_signed_issue_bundle(n_actions: usize) ( - actions in vec(arb_issue_action(b"asset_desc".to_vec()), n_actions), + actions in vec(arb_issue_action([1u8; 32]), n_actions), ik in arb_issuance_validating_key(), fake_sig in arb_signature(), ) -> IssueBundle { diff --git a/src/note/asset_base.rs b/src/note/asset_base.rs index dc00b873a..947216db5 100644 --- a/src/note/asset_base.rs +++ b/src/note/asset_base.rs @@ -6,10 +6,13 @@ use std::hash::{Hash, Hasher}; use subtle::{Choice, ConstantTimeEq, CtOption}; -use crate::constants::fixed_bases::{ - NATIVE_ASSET_BASE_V_BYTES, VALUE_COMMITMENT_PERSONALIZATION, ZSA_ASSET_BASE_PERSONALIZATION, +use crate::{ + constants::fixed_bases::{ + NATIVE_ASSET_BASE_V_BYTES, VALUE_COMMITMENT_PERSONALIZATION, ZSA_ASSET_BASE_PERSONALIZATION, + }, + issuance::compute_asset_desc_hash, + keys::{IssuanceAuthorizingKey, IssuanceValidatingKey}, }; -use crate::keys::{IssuanceAuthorizingKey, IssuanceValidatingKey}; /// Note type identifier. #[derive(Clone, Copy, Debug, Eq)] @@ -53,17 +56,12 @@ impl AssetBase { /// /// # Panics /// - /// Panics if `asset_desc` is empty or greater than `MAX_ASSET_DESCRIPTION_SIZE` or if the derived Asset Base is the identity point. + /// Panics if the derived Asset Base is the identity point. #[allow(non_snake_case)] - pub fn derive(ik: &IssuanceValidatingKey, asset_desc: &[u8]) -> Self { - assert!( - is_asset_desc_of_valid_size(asset_desc), - "The asset_desc string is not of valid size" - ); - - // EncodeAssetId(ik, asset_desc) = version_byte || ik || asset_desc + pub fn derive(ik: &IssuanceValidatingKey, asset_desc_hash: &[u8; 32]) -> Self { + // EncodeAssetId(ik, asset_desc_hash) = version_byte || ik || asset_desc_hash let version_byte = [0x00]; - let encode_asset_id = [&version_byte[..], &ik.to_bytes(), asset_desc].concat(); + let encode_asset_id = [&version_byte[..], &ik.to_bytes(), asset_desc_hash].concat(); let asset_digest = asset_digest(encode_asset_id); @@ -103,8 +101,7 @@ impl AssetBase { pub(crate) fn random() -> Self { let isk = IssuanceAuthorizingKey::random(); let ik = IssuanceValidatingKey::from(&isk); - let asset_descr = b"zsa_asset".to_vec(); - AssetBase::derive(&ik, &asset_descr) + AssetBase::derive(&ik, &compute_asset_desc_hash(b"zsa_asset").unwrap()) } } @@ -141,12 +138,12 @@ pub mod testing { pub fn arb_asset_base()( is_native in prop::bool::ANY, isk in arb_issuance_authorizing_key(), - asset_desc in prop::collection::vec(any::(), 1..=511), + asset_desc_hash in any::<[u8; 32]>(), ) -> AssetBase { if is_native { AssetBase::native() } else { - AssetBase::derive(&IssuanceValidatingKey::from(&isk), &asset_desc) + AssetBase::derive(&IssuanceValidatingKey::from(&isk), &asset_desc_hash) } } } @@ -163,19 +160,18 @@ pub mod testing { /// Generate an asset ID pub fn arb_zsa_asset_base()( isk in arb_issuance_authorizing_key(), - asset_desc in prop::collection::vec(any::(), 1..=511), + asset_desc_hash in any::<[u8; 32]>(), ) -> AssetBase { - AssetBase::derive(&IssuanceValidatingKey::from(&isk), &asset_desc) + AssetBase::derive(&IssuanceValidatingKey::from(&isk), &asset_desc_hash) } } prop_compose! { /// Generate an asset ID using a specific description - pub fn zsa_asset_base(asset_desc: Vec)( + pub fn zsa_asset_base(asset_desc_hash: [u8; 32])( isk in arb_issuance_authorizing_key(), ) -> AssetBase { - assert!(super::is_asset_desc_of_valid_size(&asset_desc)); - AssetBase::derive(&IssuanceValidatingKey::from(&isk), &asset_desc) + AssetBase::derive(&IssuanceValidatingKey::from(&isk), &asset_desc_hash) } } @@ -184,9 +180,11 @@ pub mod testing { let test_vectors = crate::test_vectors::asset_base::test_vectors(); for tv in test_vectors { + let asset_desc_hash = + crate::issuance::compute_asset_desc_hash(&tv.description).unwrap(); let calculated_asset_base = AssetBase::derive( &IssuanceValidatingKey::from_bytes(&tv.key).unwrap(), - &tv.description, + &asset_desc_hash, ); let test_vector_asset_base = AssetBase::from_bytes(&tv.asset_base).unwrap(); diff --git a/src/test_vectors/asset_base.rs b/src/test_vectors/asset_base.rs index b054359f2..f2769f9ba 100644 --- a/src/test_vectors/asset_base.rs +++ b/src/test_vectors/asset_base.rs @@ -6,6 +6,7 @@ pub(crate) struct TestVector { pub(crate) asset_base: [u8; 32], } +// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_zsa_asset_base.py pub(crate) fn test_vectors() -> Vec { vec![ TestVector { @@ -54,9 +55,9 @@ pub(crate) fn test_vectors() -> Vec { 0x8b, 0xe2, 0xb1, 0xb4, 0xc3, 0x85, 0xc8, 0xbe, ], asset_base: [ - 0xb2, 0x5c, 0xbe, 0xdd, 0x3c, 0xae, 0xa0, 0x46, 0x24, 0x08, 0x21, 0xa9, 0x22, 0xcd, - 0xae, 0xb7, 0xfe, 0xcc, 0x4f, 0xed, 0x1d, 0x60, 0xc1, 0x61, 0x57, 0x9c, 0xd9, 0xcf, - 0x4e, 0x0c, 0xc9, 0x1f, + 0x7e, 0x46, 0xc7, 0x8d, 0xdc, 0xba, 0x48, 0x8b, 0x25, 0x91, 0xff, 0xc9, 0x35, 0x43, + 0x7e, 0x57, 0x33, 0xd7, 0xc4, 0xea, 0x10, 0x0e, 0x22, 0xca, 0x32, 0x2a, 0x7d, 0x23, + 0x1b, 0xaf, 0xc9, 0x00, ], }, TestVector { @@ -105,9 +106,9 @@ pub(crate) fn test_vectors() -> Vec { 0x9e, 0xe1, 0x9b, 0x90, 0x4d, 0x70, 0xc8, 0xaf, ], asset_base: [ - 0xbd, 0x7f, 0x79, 0xe7, 0xda, 0xdd, 0x1d, 0x48, 0x27, 0x06, 0x04, 0xcd, 0xdb, 0x1d, - 0x65, 0x44, 0x09, 0x29, 0xea, 0x25, 0xe7, 0x7b, 0x72, 0x85, 0x5f, 0xf6, 0xfd, 0x99, - 0x18, 0xa5, 0x91, 0xb6, + 0xd7, 0xb2, 0xe4, 0x87, 0x84, 0x75, 0xf5, 0x3c, 0xf8, 0x91, 0x9b, 0x5b, 0x91, 0x0e, + 0x92, 0xe5, 0xb6, 0xb4, 0x23, 0x73, 0xf6, 0x2f, 0x3b, 0x1a, 0x4e, 0x20, 0xbf, 0x07, + 0x22, 0x9a, 0xdf, 0x99, ], }, TestVector { @@ -156,9 +157,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc5, 0x80, 0xc3, 0xa5, 0xe1, 0x9b, 0x83, 0x5a, ], asset_base: [ - 0x6f, 0x2d, 0x95, 0xed, 0x1d, 0x96, 0x0b, 0x7a, 0xe1, 0xcf, 0x9c, 0x0b, 0x66, 0xe8, - 0x5a, 0xdd, 0x2c, 0xf1, 0xcd, 0x44, 0x6e, 0x02, 0x74, 0x51, 0x2e, 0x3b, 0x99, 0x6d, - 0x8e, 0xe7, 0x77, 0xa2, + 0xa9, 0xd3, 0x61, 0x55, 0x2c, 0xe0, 0x29, 0x7b, 0x79, 0x10, 0x1c, 0xd0, 0x7e, 0xb7, + 0xf9, 0x6c, 0xbc, 0x01, 0x3f, 0xfa, 0x7d, 0xb0, 0xe2, 0x23, 0xe1, 0xb7, 0xdf, 0xb1, + 0x22, 0xe2, 0x8a, 0xb2, ], }, TestVector { @@ -207,9 +208,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc7, 0xab, 0xc7, 0xab, 0xe2, 0xb1, 0xbb, 0x48, ], asset_base: [ - 0x35, 0x3e, 0x4f, 0xa9, 0x48, 0x59, 0xab, 0x52, 0xfc, 0xc2, 0xdd, 0x1c, 0x91, 0x45, - 0x3c, 0x09, 0x3f, 0x15, 0x43, 0x31, 0x43, 0x65, 0x80, 0x38, 0xba, 0xc3, 0xaa, 0xf0, - 0x89, 0xf0, 0xd4, 0x23, + 0x01, 0x0d, 0xf0, 0x33, 0xb2, 0x76, 0xd3, 0x3c, 0x42, 0x7c, 0xa1, 0x9e, 0xae, 0x6c, + 0x57, 0xd9, 0x35, 0x78, 0x16, 0xb9, 0xc4, 0xb7, 0x52, 0xc5, 0xff, 0x8f, 0x5e, 0xa7, + 0x0b, 0x23, 0xc1, 0x8e, ], }, TestVector { @@ -258,9 +259,9 @@ pub(crate) fn test_vectors() -> Vec { 0xe1, 0x9b, 0x88, 0x61, 0xc6, 0xa9, 0xc4, 0xa2, ], asset_base: [ - 0x76, 0xe9, 0x3a, 0xa6, 0xa3, 0x60, 0x1a, 0x94, 0xdf, 0xde, 0x01, 0xd9, 0x8c, 0x63, - 0xc6, 0xf1, 0x28, 0x5b, 0x22, 0x28, 0x47, 0x16, 0x86, 0x05, 0x85, 0x93, 0x7c, 0x3d, - 0xaf, 0x60, 0x7b, 0xbc, + 0xa3, 0xd7, 0x7d, 0xcd, 0xb9, 0xa7, 0xa1, 0x5a, 0x78, 0x08, 0x8c, 0xff, 0xec, 0x67, + 0x85, 0xf8, 0x26, 0x84, 0x75, 0x7c, 0x98, 0x89, 0x3d, 0x52, 0xf9, 0x3c, 0xd8, 0x09, + 0x49, 0x0f, 0x8a, 0x0e, ], }, TestVector { @@ -309,9 +310,9 @@ pub(crate) fn test_vectors() -> Vec { 0x85, 0xc6, 0xa9, 0xc7, 0xac, 0xc7, 0x9f, 0x5a, ], asset_base: [ - 0x50, 0xf6, 0x66, 0x1f, 0x02, 0x22, 0x48, 0x1e, 0x18, 0x94, 0x80, 0x9a, 0x17, 0xd0, - 0xaf, 0xeb, 0x5e, 0xf9, 0x74, 0x34, 0x43, 0x5d, 0x32, 0xa0, 0x4b, 0x3b, 0x16, 0xb2, - 0x45, 0xc8, 0xed, 0x0a, + 0xd3, 0xd8, 0x13, 0xbb, 0xa4, 0x40, 0xb5, 0xff, 0xeb, 0x1c, 0xdd, 0x67, 0x03, 0xc7, + 0xf3, 0x45, 0xa5, 0x79, 0xc1, 0x34, 0x7c, 0xcd, 0xb5, 0x15, 0x2e, 0x89, 0x0f, 0x49, + 0x52, 0x61, 0xd4, 0x90, ], }, TestVector { @@ -360,9 +361,9 @@ pub(crate) fn test_vectors() -> Vec { 0xcd, 0xb4, 0xc7, 0x9a, 0x3f, 0xc4, 0x85, 0x5a, ], asset_base: [ - 0xc9, 0x01, 0x55, 0x24, 0x71, 0x2e, 0x93, 0xf3, 0x40, 0x41, 0x31, 0x02, 0xda, 0x68, - 0xaf, 0xb4, 0xf5, 0x5f, 0xa2, 0x94, 0x4a, 0xc4, 0xc8, 0x32, 0x34, 0xb5, 0x8a, 0x1d, - 0x7a, 0x9c, 0xb6, 0x95, + 0x98, 0x40, 0xad, 0x9e, 0x83, 0xd6, 0xb0, 0xe1, 0xe9, 0x5b, 0x71, 0xe9, 0x01, 0x84, + 0x06, 0xea, 0x41, 0x07, 0x90, 0xfb, 0x90, 0x17, 0x38, 0xac, 0x91, 0x26, 0xe8, 0x16, + 0xf8, 0x26, 0x42, 0xb8, ], }, TestVector { @@ -411,9 +412,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc3, 0xa7, 0x5c, 0xe1, 0x9b, 0x97, 0x47, 0x5a, ], asset_base: [ - 0x13, 0x42, 0x79, 0x82, 0x9b, 0x56, 0xe2, 0xb0, 0x4a, 0xa0, 0xfb, 0x95, 0xf7, 0xfc, - 0x73, 0x79, 0x67, 0x24, 0x5d, 0x49, 0x6a, 0x6d, 0xfa, 0xa0, 0x28, 0x35, 0x2c, 0x39, - 0x2a, 0x58, 0x0d, 0x22, + 0xe8, 0x86, 0xd9, 0x58, 0x68, 0xa3, 0x37, 0x06, 0x45, 0xd3, 0x31, 0xb1, 0x0a, 0xcf, + 0x65, 0x20, 0x52, 0xf8, 0x82, 0x21, 0x94, 0x95, 0xd7, 0x9b, 0x76, 0x73, 0xb1, 0xb7, + 0xdd, 0x1b, 0x92, 0xaa, ], }, TestVector { @@ -462,9 +463,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc3, 0xbd, 0xc3, 0xb2, 0xc8, 0x9a, 0xc8, 0x9f, ], asset_base: [ - 0xe4, 0xb5, 0xf3, 0x96, 0x78, 0x10, 0xbc, 0x94, 0xfe, 0x85, 0x44, 0x13, 0x38, 0x48, - 0xab, 0x35, 0xf6, 0xa5, 0x22, 0x2b, 0x0e, 0x74, 0xa8, 0xd3, 0xf0, 0x35, 0xdb, 0xdc, - 0x31, 0xa6, 0x3d, 0x04, + 0x9b, 0x83, 0xfb, 0x05, 0xd3, 0x83, 0x37, 0x66, 0xcb, 0xee, 0xf1, 0xde, 0xee, 0xcb, + 0x30, 0x77, 0x76, 0x16, 0x1a, 0x24, 0xa2, 0x64, 0x15, 0x44, 0x9a, 0x63, 0xe7, 0x61, + 0x17, 0xdf, 0x9e, 0x94, ], }, TestVector { @@ -513,9 +514,9 @@ pub(crate) fn test_vectors() -> Vec { 0xbc, 0xc6, 0xaf, 0xc2, 0xac, 0xc9, 0x89, 0x5a, ], asset_base: [ - 0x3f, 0xc0, 0xbc, 0x12, 0x07, 0x8b, 0xf1, 0xf2, 0x24, 0x09, 0x2d, 0xb5, 0x81, 0x0b, - 0x00, 0xaf, 0x8a, 0xe0, 0xb6, 0xe6, 0x35, 0x50, 0xcf, 0xdc, 0xf6, 0xd6, 0x01, 0x0f, - 0x73, 0xab, 0xb0, 0x3c, + 0xf4, 0x50, 0x63, 0x88, 0xca, 0xcb, 0xd0, 0xe5, 0x22, 0xf5, 0x19, 0xe0, 0x0b, 0x2a, + 0x6c, 0xcc, 0x9a, 0xf4, 0x38, 0x87, 0x17, 0x71, 0xb4, 0xc2, 0xb9, 0x06, 0x92, 0x3b, + 0x32, 0xf5, 0x5b, 0xa2, ], }, TestVector { @@ -564,9 +565,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc4, 0x94, 0xc5, 0x80, 0xc8, 0x96, 0xc6, 0xb3, ], asset_base: [ - 0x70, 0xc1, 0x47, 0xec, 0x23, 0x32, 0x10, 0xed, 0xdf, 0xab, 0x14, 0xcb, 0xca, 0x72, - 0x4d, 0xd2, 0x8e, 0x2b, 0xc5, 0x7f, 0xb7, 0xb0, 0xd3, 0x44, 0x6d, 0x79, 0x7f, 0x94, - 0xbc, 0xeb, 0xd0, 0xb8, + 0x5a, 0x04, 0x3d, 0x99, 0x0d, 0xb1, 0x1b, 0x51, 0x60, 0x67, 0x24, 0xe2, 0xdf, 0x9e, + 0x5b, 0xf3, 0xe6, 0x6a, 0xef, 0x7a, 0x89, 0xee, 0xb6, 0x01, 0x0b, 0xfc, 0x35, 0x76, + 0xb8, 0xc9, 0x84, 0x3d, ], }, TestVector { @@ -615,9 +616,9 @@ pub(crate) fn test_vectors() -> Vec { 0xb2, 0xc6, 0xb9, 0xc3, 0xb5, 0x74, 0xc2, 0xb3, ], asset_base: [ - 0x85, 0x94, 0x73, 0xb4, 0x98, 0xbb, 0x99, 0x99, 0x4a, 0x06, 0x71, 0x0e, 0x5c, 0xd2, - 0x10, 0x78, 0xa5, 0x22, 0xea, 0xa5, 0xf6, 0xad, 0x2d, 0x22, 0xe5, 0x12, 0x57, 0x6d, - 0x8c, 0x89, 0x65, 0x21, + 0x10, 0xa8, 0xbf, 0xf0, 0xed, 0x13, 0xb3, 0xc9, 0x10, 0x26, 0x17, 0xb2, 0x7c, 0xe8, + 0x51, 0x76, 0x2b, 0x0b, 0xa0, 0xb0, 0x92, 0x4f, 0xc2, 0x02, 0xae, 0x17, 0x95, 0x7f, + 0x27, 0xc8, 0xc6, 0x99, ], }, TestVector { @@ -666,9 +667,9 @@ pub(crate) fn test_vectors() -> Vec { 0xcd, 0xbc, 0xe1, 0x9a, 0xbc, 0xe2, 0xb1, 0xa8, ], asset_base: [ - 0xb2, 0xea, 0x85, 0x07, 0x94, 0x73, 0xf8, 0x06, 0xce, 0x30, 0xca, 0xe0, 0xbf, 0x6c, - 0xb9, 0xc9, 0xeb, 0x91, 0x72, 0xc0, 0xb9, 0x86, 0x47, 0x7a, 0xb9, 0x04, 0xd1, 0xfa, - 0x68, 0x49, 0x01, 0x2e, + 0xec, 0x69, 0x43, 0x25, 0xaf, 0x69, 0x09, 0x19, 0x89, 0x0c, 0x98, 0xf2, 0x1e, 0x68, + 0x0f, 0x6f, 0xce, 0x19, 0x3e, 0x83, 0x20, 0x86, 0xe3, 0xe3, 0x75, 0xc4, 0x2a, 0x31, + 0xbd, 0x8d, 0x4d, 0xb7, ], }, TestVector { @@ -717,9 +718,9 @@ pub(crate) fn test_vectors() -> Vec { 0x87, 0xe2, 0xb1, 0xbd, 0xc8, 0x8f, 0xc9, 0x8c, ], asset_base: [ - 0x1a, 0x51, 0xbf, 0x64, 0x82, 0x22, 0x09, 0x2a, 0x98, 0x5b, 0x0e, 0x94, 0xfa, 0x1d, - 0xb4, 0xb4, 0xbf, 0xad, 0x07, 0x8f, 0xbe, 0x75, 0xc1, 0xbf, 0x83, 0x1c, 0x47, 0xd3, - 0x54, 0x6f, 0xbc, 0x38, + 0x00, 0xd1, 0x7f, 0x46, 0x6a, 0x46, 0x7a, 0x61, 0x3b, 0x6e, 0xe2, 0x24, 0x85, 0xe3, + 0xa8, 0x9c, 0x86, 0xcc, 0x8d, 0x1a, 0xf3, 0x7b, 0xdb, 0x5b, 0x01, 0xa0, 0x9f, 0x6b, + 0x13, 0xfc, 0x74, 0x85, ], }, TestVector { @@ -768,9 +769,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc7, 0xab, 0xc5, 0x92, 0xc8, 0x8c, 0x5a, 0x5a, ], asset_base: [ - 0xb1, 0x08, 0xcf, 0xf7, 0x04, 0xbf, 0xce, 0x2b, 0xdb, 0x86, 0xdb, 0xb8, 0x40, 0x3f, - 0x02, 0x20, 0x3f, 0x1c, 0xa1, 0x50, 0x2d, 0x5e, 0x24, 0xe2, 0x21, 0xc2, 0x23, 0xd7, - 0xeb, 0x82, 0xb2, 0x18, + 0x89, 0x29, 0x91, 0xc7, 0xbe, 0xb5, 0x25, 0x9d, 0xc4, 0xc9, 0x9c, 0x2e, 0x6d, 0x34, + 0x93, 0x87, 0x01, 0x56, 0x06, 0x27, 0x1b, 0x9c, 0xb0, 0x23, 0xb1, 0x1b, 0xb8, 0xa9, + 0xdf, 0x99, 0xc1, 0x25, ], }, TestVector { @@ -819,9 +820,9 @@ pub(crate) fn test_vectors() -> Vec { 0xe2, 0xb1, 0xa5, 0xc8, 0x82, 0xc7, 0x8b, 0x5a, ], asset_base: [ - 0x9c, 0x64, 0x87, 0xfa, 0x7e, 0x3e, 0xd4, 0xc1, 0x7c, 0x02, 0x43, 0x93, 0x55, 0x14, - 0xc9, 0x45, 0x4a, 0x6f, 0x21, 0x3f, 0x7b, 0x1c, 0x5b, 0x32, 0xab, 0xd5, 0xa8, 0x6e, - 0x49, 0xe1, 0x35, 0x2d, + 0x65, 0xf8, 0x13, 0xc3, 0x65, 0x97, 0x2b, 0xbb, 0x33, 0xfc, 0x35, 0x17, 0x0e, 0x95, + 0x4f, 0xb0, 0x7c, 0x89, 0x94, 0x24, 0xca, 0x6a, 0x48, 0x2b, 0xce, 0x0d, 0x6d, 0x26, + 0x58, 0x71, 0x1b, 0xbe, ], }, TestVector { @@ -870,9 +871,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc5, 0x91, 0xc9, 0x8c, 0xc2, 0xab, 0xc6, 0x9d, ], asset_base: [ - 0xb2, 0x75, 0x51, 0xe5, 0x55, 0x32, 0x2a, 0x10, 0x94, 0x42, 0x4d, 0x4c, 0xe8, 0x6d, - 0xde, 0x6c, 0x6d, 0xf1, 0xbd, 0xec, 0xb6, 0x31, 0x5a, 0x6a, 0xa1, 0xc5, 0x58, 0xc9, - 0x82, 0x49, 0x54, 0x13, + 0xb6, 0xff, 0xe5, 0x46, 0x67, 0xba, 0xd3, 0x36, 0x0f, 0xf9, 0x7c, 0x51, 0xbc, 0x63, + 0xd0, 0x99, 0x70, 0xcf, 0x40, 0xbe, 0x92, 0x0a, 0xd0, 0x1c, 0x72, 0x40, 0x42, 0x0d, + 0x82, 0xb7, 0x1b, 0x0f, ], }, TestVector { @@ -921,9 +922,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc5, 0x91, 0x75, 0xc7, 0xbd, 0xe1, 0x9a, 0xb4, ], asset_base: [ - 0x97, 0xf4, 0x4c, 0x37, 0x3a, 0x55, 0x30, 0xbd, 0xc9, 0xd4, 0xbb, 0x76, 0x26, 0x65, - 0x03, 0xb4, 0xfd, 0x4a, 0x24, 0xf0, 0x22, 0x23, 0x13, 0xe4, 0xff, 0x45, 0x97, 0x74, - 0xa6, 0x9a, 0x4f, 0x34, + 0xde, 0x6b, 0x80, 0x19, 0x0e, 0x59, 0x02, 0x25, 0x7b, 0x37, 0xf0, 0xaa, 0xf0, 0xc4, + 0x68, 0xb0, 0xee, 0xa6, 0x20, 0x24, 0x29, 0x8f, 0xe6, 0xaa, 0x54, 0x2e, 0xf4, 0x67, + 0x8a, 0x88, 0x9f, 0xb0, ], }, TestVector { @@ -972,9 +973,9 @@ pub(crate) fn test_vectors() -> Vec { 0xe2, 0xb1, 0xb3, 0x47, 0xc6, 0xbb, 0xc8, 0x83, ], asset_base: [ - 0xe7, 0x25, 0x94, 0x56, 0x3c, 0xb3, 0x92, 0xab, 0xbe, 0x95, 0x61, 0x61, 0xfa, 0xed, - 0x3d, 0x8d, 0xc4, 0xa1, 0xa0, 0x4e, 0x7c, 0x0d, 0x6e, 0x5b, 0xb8, 0x7d, 0x6c, 0xba, - 0x68, 0xc4, 0x45, 0x27, + 0xb3, 0xab, 0xd0, 0x61, 0x3b, 0xd2, 0xa7, 0xa8, 0xf6, 0x74, 0x33, 0x6f, 0x0f, 0xdf, + 0x2c, 0x3b, 0x08, 0x16, 0xee, 0x04, 0x1c, 0x85, 0x04, 0xb4, 0x45, 0xcc, 0xe1, 0x53, + 0x15, 0x46, 0xc8, 0x1c, ], }, TestVector { @@ -1023,9 +1024,9 @@ pub(crate) fn test_vectors() -> Vec { 0xc2, 0xa9, 0xc5, 0x89, 0xc8, 0xb5, 0x5a, 0x5a, ], asset_base: [ - 0x0b, 0xcf, 0xbd, 0x87, 0x2f, 0xc5, 0xed, 0x4c, 0x82, 0x80, 0x35, 0x16, 0x69, 0x20, - 0x77, 0x21, 0xc6, 0xd2, 0x15, 0x67, 0xdd, 0x34, 0x10, 0x5c, 0x89, 0x7d, 0xbf, 0x66, - 0x19, 0x95, 0xa3, 0x1d, + 0x38, 0x52, 0x49, 0x24, 0x7a, 0xb3, 0x96, 0xdb, 0xd5, 0x07, 0x83, 0xa3, 0x51, 0xf6, + 0xbe, 0x50, 0x80, 0x3e, 0xf4, 0x4b, 0x2c, 0x29, 0x82, 0xbc, 0xdd, 0x81, 0xe7, 0x72, + 0x44, 0xbd, 0xa6, 0x8c, ], }, ] diff --git a/tests/issuance_global_state.rs b/tests/issuance_global_state.rs index 199138605..e5f95144c 100644 --- a/tests/issuance_global_state.rs +++ b/tests/issuance_global_state.rs @@ -5,7 +5,7 @@ use rand::{rngs::OsRng, RngCore}; use orchard::{ asset_record::AssetRecord, issuance::{ - verify_issue_bundle, + compute_asset_desc_hash, verify_issue_bundle, Error::{ IssueActionPreviouslyFinalizedAssetBase, MissingReferenceNoteOnFirstIssuance, ValueOverflow, @@ -126,20 +126,21 @@ fn build_issue_bundle(params: &TestParams, data: &[IssueTestNote]) -> IssueBundl first_issuance, } = data.first().unwrap().clone(); + let asset_desc_hash = compute_asset_desc_hash(&asset_desc).unwrap(); + let (mut bundle, _) = IssueBundle::new( ik.clone(), - asset_desc.clone(), + asset_desc_hash, Some(IssueInfo { recipient, value: NoteValue::from_raw(amount), }), first_issuance, rng, - ) - .unwrap(); + ); if is_finalized { - bundle.finalize_action(&asset_desc).unwrap(); + bundle.finalize_action(&asset_desc_hash).unwrap(); } for IssueTestNote { @@ -149,9 +150,10 @@ fn build_issue_bundle(params: &TestParams, data: &[IssueTestNote]) -> IssueBundl first_issuance, } in data.iter().skip(1).cloned() { + let asset_desc_hash = compute_asset_desc_hash(&asset_desc).unwrap(); bundle .add_recipient( - &asset_desc, + asset_desc_hash, recipient, NoteValue::from_raw(amount), first_issuance, @@ -160,7 +162,7 @@ fn build_issue_bundle(params: &TestParams, data: &[IssueTestNote]) -> IssueBundl .unwrap(); if is_finalized { - bundle.finalize_action(&asset_desc).unwrap(); + bundle.finalize_action(&asset_desc_hash).unwrap(); } } @@ -184,10 +186,10 @@ fn issue_bundle_verify_with_global_state() { let asset3_desc = b"Verify with issued assets 3".to_vec(); let asset4_desc = b"Verify with issued assets 4".to_vec(); - let asset1_base = AssetBase::derive(&ik, &asset1_desc); - let asset2_base = AssetBase::derive(&ik, &asset2_desc); - let asset3_base = AssetBase::derive(&ik, &asset3_desc); - let asset4_base = AssetBase::derive(&ik, &asset4_desc); + let asset1_base = AssetBase::derive(&ik, &compute_asset_desc_hash(&asset1_desc).unwrap()); + let asset2_base = AssetBase::derive(&ik, &compute_asset_desc_hash(&asset2_desc).unwrap()); + let asset3_base = AssetBase::derive(&ik, &compute_asset_desc_hash(&asset3_desc).unwrap()); + let asset4_base = AssetBase::derive(&ik, &compute_asset_desc_hash(&asset4_desc).unwrap()); let mut global_state = HashMap::new(); diff --git a/tests/zsa.rs b/tests/zsa.rs index 337c6fbf8..8253cdef1 100644 --- a/tests/zsa.rs +++ b/tests/zsa.rs @@ -4,7 +4,9 @@ use crate::builder::verify_bundle; use bridgetree::BridgeTree; use incrementalmerkletree::Hashable; use orchard::bundle::Authorized; -use orchard::issuance::{verify_issue_bundle, AwaitingNullifier, IssueBundle, IssueInfo, Signed}; +use orchard::issuance::{ + compute_asset_desc_hash, verify_issue_bundle, AwaitingNullifier, IssueBundle, IssueInfo, Signed, +}; use orchard::keys::{IssuanceAuthorizingKey, IssuanceValidatingKey}; use orchard::note::{AssetBase, ExtractedNoteCommitment, Nullifier}; @@ -144,9 +146,10 @@ fn issue_zsa_notes( ) -> (Note, Note, Note) { let mut rng = OsRng; // Create a issuance bundle - let awaiting_nullifier_bundle_asset = IssueBundle::new( + let asset_desc_hash = compute_asset_desc_hash(asset_descr).unwrap(); + let (mut awaiting_nullifier_bundle, _) = IssueBundle::new( keys.ik().clone(), - asset_descr.to_owned(), + asset_desc_hash, Some(IssueInfo { recipient: keys.recipient, value: NoteValue::from_raw(40), @@ -155,13 +158,9 @@ fn issue_zsa_notes( &mut rng, ); - assert!(awaiting_nullifier_bundle_asset.is_ok()); - - let (mut awaiting_nullifier_bundle, _) = awaiting_nullifier_bundle_asset.unwrap(); - assert!(awaiting_nullifier_bundle .add_recipient( - asset_descr, + asset_desc_hash, keys.recipient, NoteValue::from_raw(2), false, @@ -179,7 +178,7 @@ fn issue_zsa_notes( verify_reference_note( reference_note, - AssetBase::derive(&keys.ik().clone(), asset_descr), + AssetBase::derive(&keys.ik().clone(), &asset_desc_hash), ); assert!(verify_issue_bundle(&issue_bundle, issue_bundle.commitment().into(), |_| None).is_ok());