From 36529629bc60b138d7eff1f844b6fe804164e334 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 23 Apr 2021 13:04:45 -0600 Subject: [PATCH 1/7] Expose Flags constructor & accessors. --- src/bundle.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/bundle.rs b/src/bundle.rs index 96964a02..c9aa4456 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -126,6 +126,31 @@ pub struct Flags { outputs_enabled: bool, } +impl Flags { + /// Construct a set of flags from its constituent parts + pub fn from_parts(spends_enabled: bool, outputs_enabled: bool) -> Self { + Flags { spends_enabled, outputs_enabled } + } + + /// Flag denoting whether Orchard spends are enabled in the transaction. + /// + /// If `true`, spent notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be dummy notes. If `false`, the spent notes may be either real or + /// dummy notes. + pub fn spends_enabled(&self) -> bool { + self.spends_enabled + } + + /// Flag denoting whether Orchard outputs are enabled in the transaction. + /// + /// If `true`, created notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be dummy notes. If `false`, the created notes may be either real or + /// dummy notes. + pub fn outputs_enabled(&self) -> bool { + self.outputs_enabled + } +} + /// Defines the authorization type of an Orchard bundle. pub trait Authorization { /// The authorization type of an Orchard action. From 29b3071c676faa08146e1773b0d156e4cb51b79d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 27 Apr 2021 09:10:32 +1200 Subject: [PATCH 2/7] Fix doc comments for bundle flags --- src/bundle.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bundle.rs b/src/bundle.rs index c9aa4456..5fc863c1 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -114,14 +114,14 @@ impl Action { pub struct Flags { /// Flag denoting whether Orchard spends are enabled in the transaction. /// - /// If `true`, spent notes within [`Action`]s in the transaction's [`Bundle`] are - /// guaranteed to be dummy notes. If `false`, the spent notes may be either real or + /// If `false`, spent notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be dummy notes. If `true`, the spent notes may be either real or /// dummy notes. spends_enabled: bool, /// Flag denoting whether Orchard outputs are enabled in the transaction. /// - /// If `true`, created notes within [`Action`]s in the transaction's [`Bundle`] are - /// guaranteed to be dummy notes. If `false`, the created notes may be either real or + /// If `false`, created notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be dummy notes. If `true`, the created notes may be either real or /// dummy notes. outputs_enabled: bool, } @@ -134,8 +134,8 @@ impl Flags { /// Flag denoting whether Orchard spends are enabled in the transaction. /// - /// If `true`, spent notes within [`Action`]s in the transaction's [`Bundle`] are - /// guaranteed to be dummy notes. If `false`, the spent notes may be either real or + /// If `false`, spent notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be dummy notes. If `true`, the spent notes may be either real or /// dummy notes. pub fn spends_enabled(&self) -> bool { self.spends_enabled @@ -143,8 +143,8 @@ impl Flags { /// Flag denoting whether Orchard outputs are enabled in the transaction. /// - /// If `true`, created notes within [`Action`]s in the transaction's [`Bundle`] are - /// guaranteed to be dummy notes. If `false`, the created notes may be either real or + /// If `false`, created notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be dummy notes. If `true`, the created notes may be either real or /// dummy notes. pub fn outputs_enabled(&self) -> bool { self.outputs_enabled From 5ec65c5d2ad9362e3db224bfad7210e59dcaff03 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 27 Apr 2021 12:22:04 +1200 Subject: [PATCH 3/7] Add a mutable context to Bundle::{try_}authorize This enables us to work around lifetime restrictions on e.g. the randomness source at signing time, where it is needed for both per-Action and Bundle-level signatures. --- src/bundle.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/bundle.rs b/src/bundle.rs index 5fc863c1..9b626ad2 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -228,34 +228,36 @@ impl Bundle { } /// Transitions this bundle from one authorization state to another. - pub fn authorize( + pub fn authorize( self, - mut spend_auth: impl FnMut(&T, T::SpendAuth) -> U::SpendAuth, - step: impl FnOnce(T) -> U, + context: &mut R, + mut spend_auth: impl FnMut(&mut R, &T, T::SpendAuth) -> U::SpendAuth, + step: impl FnOnce(&mut R, T) -> U, ) -> Bundle { let authorization = self.authorization; Bundle { actions: self .actions - .map(|a| a.map(|a_auth| spend_auth(&authorization, a_auth))), + .map(|a| a.map(|a_auth| spend_auth(context, &authorization, a_auth))), flags: self.flags, value_balance: self.value_balance, anchor: self.anchor, - authorization: step(authorization), + authorization: step(context, authorization), } } /// Transitions this bundle from one authorization state to another. - pub fn try_authorize( + pub fn try_authorize( self, - mut spend_auth: impl FnMut(&T, T::SpendAuth) -> Result, - step: impl FnOnce(T) -> Result, + context: &mut R, + mut spend_auth: impl FnMut(&mut R, &T, T::SpendAuth) -> Result, + step: impl FnOnce(&mut R, T) -> Result, ) -> Result, E> { let authorization = self.authorization; let new_actions = self .actions .into_iter() - .map(|a| a.try_map(|a_auth| spend_auth(&authorization, a_auth))) + .map(|a| a.try_map(|a_auth| spend_auth(context, &authorization, a_auth))) .collect::, E>>()?; Ok(Bundle { @@ -263,7 +265,7 @@ impl Bundle { flags: self.flags, value_balance: self.value_balance, anchor: self.anchor, - authorization: step(authorization)?, + authorization: step(context, authorization)?, }) } } From 52d87e257cb732f398a3da363103ad6f6415249d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 27 Apr 2021 12:25:03 +1200 Subject: [PATCH 4/7] Return SpendingKey from Note::dummy We need the spending keys to create valid spendAuth signatures for Actions containing dummy spent notes. --- src/circuit.rs | 4 ++-- src/note.rs | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index b993f845..2bf53bc2 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -180,13 +180,13 @@ mod tests { let (circuits, instances): (Vec<_>, Vec<_>) = iter::once(()) .map(|()| { - let (fvk, spent_note) = Note::dummy(&mut rng, None); + let (_, fvk, spent_note) = Note::dummy(&mut rng, None); let nf_old = spent_note.nullifier(&fvk); let ak: SpendValidatingKey = fvk.into(); let alpha = pallas::Scalar::random(&mut rng); let rk = ak.randomize(&alpha); - let (_, output_note) = Note::dummy(&mut rng, Some(nf_old.clone())); + let (_, _, output_note) = Note::dummy(&mut rng, Some(nf_old.clone())); let cmx = output_note.commitment().into(); let value = spent_note.value() - output_note.value(); diff --git a/src/note.rs b/src/note.rs index 417e665b..39227cf1 100644 --- a/src/note.rs +++ b/src/note.rs @@ -65,8 +65,12 @@ impl Note { /// Defined in [Zcash Protocol Spec ยง 4.8.3: Dummy Notes (Orchard)][orcharddummynotes]. /// /// [orcharddummynotes]: https://zips.z.cash/protocol/nu5.pdf#orcharddummynotes - pub(crate) fn dummy(rng: &mut impl RngCore, rho: Option) -> (FullViewingKey, Self) { - let fvk: FullViewingKey = (&SpendingKey::random(rng)).into(); + pub(crate) fn dummy( + rng: &mut impl RngCore, + rho: Option, + ) -> (SpendingKey, FullViewingKey, Self) { + let sk = SpendingKey::random(rng); + let fvk: FullViewingKey = (&sk).into(); let recipient = fvk.default_address(); let note = Note { @@ -76,7 +80,7 @@ impl Note { rseed: RandomSeed::random(rng), }; - (fvk, note) + (sk, fvk, note) } /// Returns the value of this note. From a60051c8a20ae61c7f003e6cdcb891e20b210657 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 27 Apr 2021 12:27:23 +1200 Subject: [PATCH 5/7] Add from_raw constructors to NoteValue and ValueSum These might be replaced later with APIs that can provide more useful bounds checks, but we do need some way to construct these types. --- src/value.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/value.rs b/src/value.rs index 75fe837c..ce1ae43c 100644 --- a/src/value.rs +++ b/src/value.rs @@ -52,6 +52,14 @@ impl NoteValue { Default::default() } + /// Creates a note value from its raw numeric value. + /// + /// This only enforces that the value is an unsigned 64-bit integer. Callers should + /// enforce any additional constraints on the value's valid range themselves. + pub fn from_raw(value: u64) -> Self { + NoteValue(value) + } + pub(crate) fn to_le_bits(self) -> BitArray { BitArray::::new(self.0.to_le_bytes()) } @@ -71,6 +79,16 @@ impl Sub for NoteValue { #[derive(Clone, Copy, Debug, Default)] pub struct ValueSum(i64); +impl ValueSum { + /// Creates a value sum from its raw numeric value. + /// + /// This only enforces that the value is a signed 63-bit integer. Callers should + /// enforce any additional constraints on the value's valid range themselves. + pub fn from_raw(value: i64) -> Self { + ValueSum(value) + } +} + impl Add for ValueSum { type Output = Result; From 316729302db05e2bd651012848469e486fa1c83d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 27 Apr 2021 12:28:42 +1200 Subject: [PATCH 6/7] cargo fmt --- src/bundle.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bundle.rs b/src/bundle.rs index 9b626ad2..32200867 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -129,7 +129,10 @@ pub struct Flags { impl Flags { /// Construct a set of flags from its constituent parts pub fn from_parts(spends_enabled: bool, outputs_enabled: bool) -> Self { - Flags { spends_enabled, outputs_enabled } + Flags { + spends_enabled, + outputs_enabled, + } } /// Flag denoting whether Orchard spends are enabled in the transaction. From 497f7e0b862c6ede6e41d8b9558641767d2ebdd1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 27 Apr 2021 12:30:16 +1200 Subject: [PATCH 7/7] Remove bundle::Unauthorized type It is being replaced by context-specific unauthorized or partially-authorized types. The only general type we need is Authorized which is used in transactions. --- src/bundle.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/bundle.rs b/src/bundle.rs index 32200867..5141b472 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -273,14 +273,6 @@ impl Bundle { } } -/// Marker for an unauthorized bundle with no proofs or signatures. -#[derive(Debug)] -pub struct Unauthorized {} - -impl Authorization for Unauthorized { - type SpendAuth = (); -} - /// Authorizing data for a bundle of actions, ready to be committed to the ledger. #[derive(Debug)] pub struct Authorized {