Skip to main content

orchard/
bundle.rs

1//! Structs related to bundles of Orchard actions.
2
3use alloc::vec::Vec;
4
5pub mod commitments;
6
7#[cfg(feature = "circuit")]
8mod batch;
9#[cfg(feature = "circuit")]
10pub use batch::BatchValidator;
11
12use core::fmt;
13
14use blake2b_simd::Hash as Blake2bHash;
15use nonempty::NonEmpty;
16use zcash_note_encryption::{try_note_decryption, try_output_recovery_with_ovk};
17
18#[cfg(feature = "std")]
19use memuse::DynamicUsage;
20
21use crate::{
22    action::Action,
23    address::Address,
24    bundle::commitments::{hash_bundle_auth_data, hash_bundle_txid_data},
25    keys::{IncomingViewingKey, OutgoingViewingKey, PreparedIncomingViewingKey},
26    note::Note,
27    note_encryption::OrchardDomain,
28    primitives::redpallas::{self, Binding, SpendAuth},
29    tree::Anchor,
30    value::{ValueCommitTrapdoor, ValueCommitment, ValueSum},
31    Proof,
32};
33
34#[cfg(feature = "circuit")]
35use crate::circuit::{Instance, VerifyingKey};
36
37#[cfg(feature = "circuit")]
38impl<T> Action<T> {
39    /// Prepares the public instance for this action, for creating and verifying the
40    /// bundle proof.
41    pub fn to_instance(&self, flags: Flags, anchor: Anchor) -> Instance {
42        Instance {
43            anchor,
44            cv_net: self.cv_net().clone(),
45            nf_old: *self.nullifier(),
46            rk: self.rk().clone(),
47            cmx: *self.cmx(),
48            enable_spend: flags.spends_enabled,
49            enable_output: flags.outputs_enabled,
50        }
51    }
52}
53
54/// Orchard-specific flags.
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub struct Flags {
57    /// Flag denoting whether Orchard spends are enabled in the transaction.
58    ///
59    /// If `false`, spent notes within [`Action`]s in the transaction's [`Bundle`] are
60    /// guaranteed to be dummy notes. If `true`, the spent notes may be either real or
61    /// dummy notes.
62    spends_enabled: bool,
63    /// Flag denoting whether Orchard outputs are enabled in the transaction.
64    ///
65    /// If `false`, created notes within [`Action`]s in the transaction's [`Bundle`] are
66    /// guaranteed to be dummy notes. If `true`, the created notes may be either real or
67    /// dummy notes.
68    outputs_enabled: bool,
69}
70
71const FLAG_SPENDS_ENABLED: u8 = 0b0000_0001;
72const FLAG_OUTPUTS_ENABLED: u8 = 0b0000_0010;
73const FLAGS_EXPECTED_UNSET: u8 = !(FLAG_SPENDS_ENABLED | FLAG_OUTPUTS_ENABLED);
74
75impl Flags {
76    /// Construct a set of flags from its constituent parts
77    pub(crate) const fn from_parts(spends_enabled: bool, outputs_enabled: bool) -> Self {
78        Flags {
79            spends_enabled,
80            outputs_enabled,
81        }
82    }
83
84    /// The flag set with both spends and outputs enabled.
85    pub const ENABLED: Flags = Flags {
86        spends_enabled: true,
87        outputs_enabled: true,
88    };
89
90    /// The flag set with spends disabled.
91    pub const SPENDS_DISABLED: Flags = Flags {
92        spends_enabled: false,
93        outputs_enabled: true,
94    };
95
96    /// The flag set with outputs disabled.
97    pub const OUTPUTS_DISABLED: Flags = Flags {
98        spends_enabled: true,
99        outputs_enabled: false,
100    };
101
102    /// Flag denoting whether Orchard spends are enabled in the transaction.
103    ///
104    /// If `false`, spent notes within [`Action`]s in the transaction's [`Bundle`] are
105    /// guaranteed to be dummy notes. If `true`, the spent notes may be either real or
106    /// dummy notes.
107    pub fn spends_enabled(&self) -> bool {
108        self.spends_enabled
109    }
110
111    /// Flag denoting whether Orchard outputs are enabled in the transaction.
112    ///
113    /// If `false`, created notes within [`Action`]s in the transaction's [`Bundle`] are
114    /// guaranteed to be dummy notes. If `true`, the created notes may be either real or
115    /// dummy notes.
116    pub fn outputs_enabled(&self) -> bool {
117        self.outputs_enabled
118    }
119
120    /// Serialize flags to a byte as defined in [Zcash Protocol Spec § 7.1: Transaction
121    /// Encoding And Consensus][txencoding].
122    ///
123    /// [txencoding]: https://zips.z.cash/protocol/protocol.pdf#txnencoding
124    pub fn to_byte(&self) -> u8 {
125        let mut value = 0u8;
126        if self.spends_enabled {
127            value |= FLAG_SPENDS_ENABLED;
128        }
129        if self.outputs_enabled {
130            value |= FLAG_OUTPUTS_ENABLED;
131        }
132        value
133    }
134
135    /// Parses flags from a single byte as defined in [Zcash Protocol Spec § 7.1:
136    /// Transaction Encoding And Consensus][txencoding].
137    ///
138    /// Returns `None` if unexpected bits are set in the flag byte.
139    ///
140    /// [txencoding]: https://zips.z.cash/protocol/protocol.pdf#txnencoding
141    pub fn from_byte(value: u8) -> Option<Self> {
142        // https://p.z.cash/TCR:bad-txns-v5-reserved-bits-nonzero
143        if value & FLAGS_EXPECTED_UNSET == 0 {
144            Some(Self {
145                spends_enabled: value & FLAG_SPENDS_ENABLED != 0,
146                outputs_enabled: value & FLAG_OUTPUTS_ENABLED != 0,
147            })
148        } else {
149            None
150        }
151    }
152}
153
154/// Defines the authorization type of an Orchard bundle.
155pub trait Authorization: fmt::Debug {
156    /// The authorization type of an Orchard action.
157    type SpendAuth: fmt::Debug;
158}
159
160/// A bundle of actions to be applied to the ledger.
161#[derive(Clone)]
162pub struct Bundle<T: Authorization, V> {
163    /// The list of actions that make up this bundle.
164    actions: NonEmpty<Action<T::SpendAuth>>,
165    /// Orchard-specific transaction-level flags for this bundle.
166    flags: Flags,
167    /// The net value moved out of the Orchard shielded pool.
168    ///
169    /// This is the sum of Orchard spends minus the sum of Orchard outputs.
170    value_balance: V,
171    /// The root of the Orchard commitment tree that this bundle commits to.
172    anchor: Anchor,
173    /// The authorization for this bundle.
174    authorization: T,
175}
176
177impl<T: Authorization, V: fmt::Debug> fmt::Debug for Bundle<T, V> {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        /// Helper struct for debug-printing actions without exposing `NonEmpty`.
180        struct Actions<'a, T>(&'a NonEmpty<Action<T>>);
181        impl<T: fmt::Debug> fmt::Debug for Actions<'_, T> {
182            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183                f.debug_list().entries(self.0.iter()).finish()
184            }
185        }
186
187        f.debug_struct("Bundle")
188            .field("actions", &Actions(&self.actions))
189            .field("flags", &self.flags)
190            .field("value_balance", &self.value_balance)
191            .field("anchor", &self.anchor)
192            .field("authorization", &self.authorization)
193            .finish()
194    }
195}
196
197impl<T: Authorization, V> Bundle<T, V> {
198    /// Constructs a `Bundle` from its constituent parts.
199    pub fn from_parts(
200        actions: NonEmpty<Action<T::SpendAuth>>,
201        flags: Flags,
202        value_balance: V,
203        anchor: Anchor,
204        authorization: T,
205    ) -> Self {
206        Bundle {
207            actions,
208            flags,
209            value_balance,
210            anchor,
211            authorization,
212        }
213    }
214
215    /// Returns the list of actions that make up this bundle.
216    pub fn actions(&self) -> &NonEmpty<Action<T::SpendAuth>> {
217        &self.actions
218    }
219
220    /// Returns the Orchard-specific transaction-level flags for this bundle.
221    pub fn flags(&self) -> &Flags {
222        &self.flags
223    }
224
225    /// Returns the net value moved into or out of the Orchard shielded pool.
226    ///
227    /// This is the sum of Orchard spends minus the sum Orchard outputs.
228    pub fn value_balance(&self) -> &V {
229        &self.value_balance
230    }
231
232    /// Returns the root of the Orchard commitment tree that this bundle commits to.
233    pub fn anchor(&self) -> &Anchor {
234        &self.anchor
235    }
236
237    /// Returns the authorization for this bundle.
238    ///
239    /// In the case of a `Bundle<Authorized>`, this is the proof and binding signature.
240    pub fn authorization(&self) -> &T {
241        &self.authorization
242    }
243
244    /// Construct a new bundle by applying a transformation that might fail
245    /// to the value balance.
246    pub fn try_map_value_balance<V0, E, F: FnOnce(V) -> Result<V0, E>>(
247        self,
248        f: F,
249    ) -> Result<Bundle<T, V0>, E> {
250        Ok(Bundle {
251            actions: self.actions,
252            flags: self.flags,
253            value_balance: f(self.value_balance)?,
254            anchor: self.anchor,
255            authorization: self.authorization,
256        })
257    }
258
259    /// Transitions this bundle from one authorization state to another.
260    pub fn map_authorization<R, U: Authorization>(
261        self,
262        context: &mut R,
263        mut spend_auth: impl FnMut(&mut R, &T, T::SpendAuth) -> U::SpendAuth,
264        step: impl FnOnce(&mut R, T) -> U,
265    ) -> Bundle<U, V> {
266        let authorization = self.authorization;
267        Bundle {
268            actions: self
269                .actions
270                .map(|a| a.map(|a_auth| spend_auth(context, &authorization, a_auth))),
271            flags: self.flags,
272            value_balance: self.value_balance,
273            anchor: self.anchor,
274            authorization: step(context, authorization),
275        }
276    }
277
278    /// Transitions this bundle from one authorization state to another.
279    pub fn try_map_authorization<R, U: Authorization, E>(
280        self,
281        context: &mut R,
282        mut spend_auth: impl FnMut(&mut R, &T, T::SpendAuth) -> Result<U::SpendAuth, E>,
283        step: impl FnOnce(&mut R, T) -> Result<U, E>,
284    ) -> Result<Bundle<U, V>, E> {
285        let authorization = self.authorization;
286        let new_actions = self
287            .actions
288            .into_iter()
289            .map(|a| a.try_map(|a_auth| spend_auth(context, &authorization, a_auth)))
290            .collect::<Result<Vec<_>, E>>()?;
291
292        Ok(Bundle {
293            actions: NonEmpty::from_vec(new_actions).unwrap(),
294            flags: self.flags,
295            value_balance: self.value_balance,
296            anchor: self.anchor,
297            authorization: step(context, authorization)?,
298        })
299    }
300
301    #[cfg(feature = "circuit")]
302    pub(crate) fn to_instances(&self) -> Vec<Instance> {
303        self.actions
304            .iter()
305            .map(|a| a.to_instance(self.flags, self.anchor))
306            .collect()
307    }
308
309    /// Performs trial decryption of each action in the bundle with each of the
310    /// specified incoming viewing keys, and returns a vector of each decrypted
311    /// note plaintext contents along with the index of the action from which it
312    /// was derived.
313    pub fn decrypt_outputs_with_keys(
314        &self,
315        keys: &[IncomingViewingKey],
316    ) -> Vec<(usize, IncomingViewingKey, Note, Address, [u8; 512])> {
317        let prepared_keys: Vec<_> = keys
318            .iter()
319            .map(|ivk| (ivk, PreparedIncomingViewingKey::new(ivk)))
320            .collect();
321        self.actions
322            .iter()
323            .enumerate()
324            .filter_map(|(idx, action)| {
325                let domain = OrchardDomain::for_action(action);
326                prepared_keys.iter().find_map(|(ivk, prepared_ivk)| {
327                    try_note_decryption(&domain, prepared_ivk, action)
328                        .map(|(n, a, m)| (idx, (*ivk).clone(), n, a, m))
329                })
330            })
331            .collect()
332    }
333
334    /// Performs trial decryption of the action at `action_idx` in the bundle with the
335    /// specified incoming viewing key, and returns the decrypted note plaintext
336    /// contents if successful.
337    pub fn decrypt_output_with_key(
338        &self,
339        action_idx: usize,
340        key: &IncomingViewingKey,
341    ) -> Option<(Note, Address, [u8; 512])> {
342        let prepared_ivk = PreparedIncomingViewingKey::new(key);
343        self.actions.get(action_idx).and_then(move |action| {
344            let domain = OrchardDomain::for_action(action);
345            try_note_decryption(&domain, &prepared_ivk, action)
346        })
347    }
348
349    /// Performs trial decryption of each action in the bundle with each of the
350    /// specified outgoing viewing keys, and returns a vector of each decrypted
351    /// note plaintext contents along with the index of the action from which it
352    /// was derived.
353    pub fn recover_outputs_with_ovks(
354        &self,
355        keys: &[OutgoingViewingKey],
356    ) -> Vec<(usize, OutgoingViewingKey, Note, Address, [u8; 512])> {
357        self.actions
358            .iter()
359            .enumerate()
360            .filter_map(|(idx, action)| {
361                let domain = OrchardDomain::for_action(action);
362                keys.iter().find_map(move |key| {
363                    try_output_recovery_with_ovk(
364                        &domain,
365                        key,
366                        action,
367                        action.cv_net(),
368                        &action.encrypted_note().out_ciphertext,
369                    )
370                    .map(|(n, a, m)| (idx, key.clone(), n, a, m))
371                })
372            })
373            .collect()
374    }
375
376    /// Attempts to decrypt the action at the specified index with the specified
377    /// outgoing viewing key, and returns the decrypted note plaintext contents
378    /// if successful.
379    pub fn recover_output_with_ovk(
380        &self,
381        action_idx: usize,
382        key: &OutgoingViewingKey,
383    ) -> Option<(Note, Address, [u8; 512])> {
384        self.actions.get(action_idx).and_then(move |action| {
385            let domain = OrchardDomain::for_action(action);
386            try_output_recovery_with_ovk(
387                &domain,
388                key,
389                action,
390                action.cv_net(),
391                &action.encrypted_note().out_ciphertext,
392            )
393        })
394    }
395}
396
397impl<T: Authorization, V: Copy + Into<i64>> Bundle<T, V> {
398    /// Computes a commitment to the effects of this bundle, suitable for inclusion within
399    /// a transaction ID.
400    pub fn commitment(&self) -> BundleCommitment {
401        BundleCommitment(hash_bundle_txid_data(self))
402    }
403
404    /// Returns the transaction binding validating key for this bundle.
405    ///
406    /// This can be used to validate the [`Authorized::binding_signature`] returned from
407    /// [`Bundle::authorization`].
408    pub fn binding_validating_key(&self) -> redpallas::VerificationKey<Binding> {
409        // https://p.z.cash/TCR:bad-txns-orchard-binding-signature-invalid?partial
410        (self
411            .actions
412            .iter()
413            .map(|a| a.cv_net())
414            .sum::<ValueCommitment>()
415            - ValueCommitment::derive(
416                ValueSum::from_raw(self.value_balance.into()),
417                ValueCommitTrapdoor::zero(),
418            ))
419        .into_bvk()
420    }
421}
422
423/// Marker type for a bundle that contains no authorizing data.
424#[derive(Clone, Debug)]
425pub struct EffectsOnly;
426
427impl Authorization for EffectsOnly {
428    type SpendAuth = ();
429}
430
431/// Authorizing data for a bundle of actions, ready to be committed to the ledger.
432#[derive(Debug, Clone)]
433pub struct Authorized {
434    proof: Proof,
435    binding_signature: redpallas::Signature<Binding>,
436}
437
438impl Authorization for Authorized {
439    type SpendAuth = redpallas::Signature<SpendAuth>;
440}
441
442impl Authorized {
443    /// Constructs the authorizing data for a bundle of actions from its constituent parts.
444    pub fn from_parts(proof: Proof, binding_signature: redpallas::Signature<Binding>) -> Self {
445        Authorized {
446            proof,
447            binding_signature,
448        }
449    }
450
451    /// Return the proof component of the authorizing data.
452    pub fn proof(&self) -> &Proof {
453        &self.proof
454    }
455
456    /// Return the binding signature.
457    pub fn binding_signature(&self) -> &redpallas::Signature<Binding> {
458        &self.binding_signature
459    }
460}
461
462impl<V> Bundle<Authorized, V> {
463    /// Computes a commitment to the authorizing data within for this bundle.
464    ///
465    /// This together with `Bundle::commitment` bind the entire bundle.
466    pub fn authorizing_commitment(&self) -> BundleAuthorizingCommitment {
467        BundleAuthorizingCommitment(hash_bundle_auth_data(self))
468    }
469
470    /// Verifies the proof for this bundle.
471    #[cfg(feature = "circuit")]
472    pub fn verify_proof(&self, vk: &VerifyingKey) -> Result<(), halo2_proofs::plonk::Error> {
473        self.authorization()
474            .proof()
475            .verify(vk, &self.to_instances())
476    }
477}
478
479#[cfg(feature = "std")]
480impl<V: DynamicUsage> DynamicUsage for Bundle<Authorized, V> {
481    fn dynamic_usage(&self) -> usize {
482        self.actions.tail.dynamic_usage()
483            + self.value_balance.dynamic_usage()
484            + self.authorization.proof.dynamic_usage()
485    }
486
487    fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
488        let bounds = (
489            self.actions.tail.dynamic_usage_bounds(),
490            self.value_balance.dynamic_usage_bounds(),
491            self.authorization.proof.dynamic_usage_bounds(),
492        );
493        (
494            bounds.0 .0 + bounds.1 .0 + bounds.2 .0,
495            bounds
496                .0
497                 .1
498                .zip(bounds.1 .1)
499                .zip(bounds.2 .1)
500                .map(|((a, b), c)| a + b + c),
501        )
502    }
503}
504
505/// A commitment to a bundle of actions.
506///
507/// This commitment is non-malleable, in the sense that a bundle's commitment will only
508/// change if the effects of the bundle are altered.
509#[derive(Debug)]
510pub struct BundleCommitment(pub Blake2bHash);
511
512impl From<BundleCommitment> for [u8; 32] {
513    fn from(commitment: BundleCommitment) -> Self {
514        // The commitment uses BLAKE2b-256.
515        commitment.0.as_bytes().try_into().unwrap()
516    }
517}
518
519/// A commitment to the authorizing data within a bundle of actions.
520#[derive(Debug)]
521pub struct BundleAuthorizingCommitment(pub Blake2bHash);
522
523/// Generators for property testing.
524#[cfg(any(test, feature = "test-dependencies"))]
525#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
526pub mod testing {
527    use alloc::vec::Vec;
528
529    use group::ff::FromUniformBytes;
530    use nonempty::NonEmpty;
531    use pasta_curves::pallas;
532    use rand::{rngs::StdRng, SeedableRng};
533    use reddsa::orchard::SpendAuth;
534
535    use proptest::collection::vec;
536    use proptest::prelude::*;
537
538    use crate::{
539        primitives::redpallas::{self, testing::arb_binding_signing_key},
540        value::{testing::arb_note_value_bounded, NoteValue, ValueSum, MAX_NOTE_VALUE},
541        Anchor, Proof,
542    };
543
544    use super::{Action, Authorized, Bundle, Flags};
545
546    pub use crate::action::testing::{arb_action, arb_unauthorized_action};
547
548    /// Marker type for a bundle that contains no authorizing data.
549    pub type Unauthorized = super::EffectsOnly;
550
551    /// Generate an unauthorized action having spend and output values less than MAX_NOTE_VALUE / n_actions.
552    pub fn arb_unauthorized_action_n(
553        n_actions: usize,
554        flags: Flags,
555    ) -> impl Strategy<Value = (ValueSum, Action<()>)> {
556        let spend_value_gen = if flags.spends_enabled {
557            Strategy::boxed(arb_note_value_bounded(MAX_NOTE_VALUE / n_actions as u64))
558        } else {
559            Strategy::boxed(Just(NoteValue::zero()))
560        };
561
562        spend_value_gen.prop_flat_map(move |spend_value| {
563            let output_value_gen = if flags.outputs_enabled {
564                Strategy::boxed(arb_note_value_bounded(MAX_NOTE_VALUE / n_actions as u64))
565            } else {
566                Strategy::boxed(Just(NoteValue::zero()))
567            };
568
569            output_value_gen.prop_flat_map(move |output_value| {
570                arb_unauthorized_action(spend_value, output_value)
571                    .prop_map(move |a| (spend_value - output_value, a))
572            })
573        })
574    }
575
576    /// Generate an authorized action having spend and output values less than MAX_NOTE_VALUE / n_actions.
577    pub fn arb_action_n(
578        n_actions: usize,
579        flags: Flags,
580    ) -> impl Strategy<Value = (ValueSum, Action<redpallas::Signature<SpendAuth>>)> {
581        let spend_value_gen = if flags.spends_enabled {
582            Strategy::boxed(arb_note_value_bounded(MAX_NOTE_VALUE / n_actions as u64))
583        } else {
584            Strategy::boxed(Just(NoteValue::zero()))
585        };
586
587        spend_value_gen.prop_flat_map(move |spend_value| {
588            let output_value_gen = if flags.outputs_enabled {
589                Strategy::boxed(arb_note_value_bounded(MAX_NOTE_VALUE / n_actions as u64))
590            } else {
591                Strategy::boxed(Just(NoteValue::zero()))
592            };
593
594            output_value_gen.prop_flat_map(move |output_value| {
595                arb_action(spend_value, output_value)
596                    .prop_map(move |a| (spend_value - output_value, a))
597            })
598        })
599    }
600
601    prop_compose! {
602        /// Create an arbitrary set of flags.
603        pub fn arb_flags()(spends_enabled in prop::bool::ANY, outputs_enabled in prop::bool::ANY) -> Flags {
604            Flags::from_parts(spends_enabled, outputs_enabled)
605        }
606    }
607
608    prop_compose! {
609        fn arb_base()(bytes in prop::array::uniform32(0u8..)) -> pallas::Base {
610            // Instead of rejecting out-of-range bytes, let's reduce them.
611            let mut buf = [0; 64];
612            buf[..32].copy_from_slice(&bytes);
613            pallas::Base::from_uniform_bytes(&buf)
614        }
615    }
616
617    prop_compose! {
618        /// Generate an arbitrary unauthorized bundle. This bundle does not
619        /// necessarily respect consensus rules; for that use
620        /// [`crate::builder::testing::arb_bundle`]
621        pub fn arb_unauthorized_bundle(n_actions: usize)
622        (
623            flags in arb_flags(),
624        )
625        (
626            acts in vec(arb_unauthorized_action_n(n_actions, flags), n_actions),
627            anchor in arb_base().prop_map(Anchor::from),
628            flags in Just(flags)
629        ) -> Bundle<Unauthorized, ValueSum> {
630            let (balances, actions): (Vec<ValueSum>, Vec<Action<_>>) = acts.into_iter().unzip();
631
632            Bundle::from_parts(
633                NonEmpty::from_vec(actions).unwrap(),
634                flags,
635                balances.into_iter().sum::<Result<ValueSum, _>>().unwrap(),
636                anchor,
637                super::EffectsOnly,
638            )
639        }
640    }
641
642    prop_compose! {
643        /// Generate an arbitrary bundle with fake authorization data. This bundle does not
644        /// necessarily respect consensus rules; for that use
645        /// [`crate::builder::testing::arb_bundle`]
646        pub fn arb_bundle(n_actions: usize)
647        (
648            flags in arb_flags(),
649        )
650        (
651            acts in vec(arb_action_n(n_actions, flags), n_actions),
652            anchor in arb_base().prop_map(Anchor::from),
653            sk in arb_binding_signing_key(),
654            rng_seed in prop::array::uniform32(prop::num::u8::ANY),
655            fake_proof in vec(prop::num::u8::ANY, 1973),
656            fake_sighash in prop::array::uniform32(prop::num::u8::ANY),
657            flags in Just(flags)
658        ) -> Bundle<Authorized, ValueSum> {
659            let (balances, actions): (Vec<ValueSum>, Vec<Action<_>>) = acts.into_iter().unzip();
660            let rng = StdRng::from_seed(rng_seed);
661
662            Bundle::from_parts(
663                NonEmpty::from_vec(actions).unwrap(),
664                flags,
665                balances.into_iter().sum::<Result<ValueSum, _>>().unwrap(),
666                anchor,
667                Authorized {
668                    proof: Proof::new(fake_proof),
669                    binding_signature: sk.sign(rng, &fake_sighash),
670                }
671            )
672        }
673    }
674}