zebra_chain/transaction/
sighash.rs

1//! Signature hashes for Zcash transactions
2
3use std::sync::Arc;
4
5use zcash_protocol::value::ZatBalance;
6use zcash_transparent::sighash::SighashType;
7
8use super::Transaction;
9
10use crate::parameters::NetworkUpgrade;
11use crate::{transparent, Error};
12
13use crate::primitives::zcash_primitives::{sighash, PrecomputedTxData};
14
15bitflags::bitflags! {
16    /// The different SigHash types, as defined in <https://zips.z.cash/zip-0143>
17    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
18    pub struct HashType: u32 {
19        /// Sign all the outputs
20        const ALL = 0b0000_0001;
21        /// Sign none of the outputs - anyone can spend
22        const NONE = 0b0000_0010;
23        /// Sign one of the outputs - anyone can spend the rest
24        const SINGLE = Self::ALL.bits() | Self::NONE.bits();
25        /// Anyone can add inputs to this transaction
26        const ANYONECANPAY = 0b1000_0000;
27
28        /// Sign all the outputs and Anyone can add inputs to this transaction
29        const ALL_ANYONECANPAY = Self::ALL.bits() | Self::ANYONECANPAY.bits();
30        /// Sign none of the outputs and Anyone can add inputs to this transaction
31        const NONE_ANYONECANPAY = Self::NONE.bits() | Self::ANYONECANPAY.bits();
32        /// Sign one of the outputs and Anyone can add inputs to this transaction
33        const SINGLE_ANYONECANPAY = Self::SINGLE.bits() | Self::ANYONECANPAY.bits();
34    }
35}
36
37impl TryFrom<HashType> for SighashType {
38    type Error = ();
39
40    fn try_from(hash_type: HashType) -> Result<Self, Self::Error> {
41        Ok(match hash_type {
42            HashType::ALL => Self::ALL,
43            HashType::NONE => Self::NONE,
44            HashType::SINGLE => Self::SINGLE,
45            HashType::ALL_ANYONECANPAY => Self::ALL_ANYONECANPAY,
46            HashType::NONE_ANYONECANPAY => Self::NONE_ANYONECANPAY,
47            HashType::SINGLE_ANYONECANPAY => Self::SINGLE_ANYONECANPAY,
48            _other => return Err(()),
49        })
50    }
51}
52
53/// A Signature Hash (or SIGHASH) as specified in
54/// <https://zips.z.cash/protocol/protocol.pdf#sighash>
55#[derive(Copy, Clone, Eq, PartialEq, Debug)]
56pub struct SigHash(pub [u8; 32]);
57
58impl AsRef<[u8; 32]> for SigHash {
59    fn as_ref(&self) -> &[u8; 32] {
60        &self.0
61    }
62}
63
64impl AsRef<[u8]> for SigHash {
65    fn as_ref(&self) -> &[u8] {
66        &self.0
67    }
68}
69
70impl From<SigHash> for [u8; 32] {
71    fn from(sighash: SigHash) -> Self {
72        sighash.0
73    }
74}
75
76/// A SigHasher context which stores precomputed data that is reused
77/// between sighash computations for the same transaction.
78#[derive(Debug)]
79pub struct SigHasher {
80    precomputed_tx_data: PrecomputedTxData,
81}
82
83impl SigHasher {
84    /// Create a new SigHasher for the given transaction.
85    ///
86    /// # Panics
87    ///
88    /// - If `trans` can't be converted to its `librustzcash` equivalent. This could happen, for
89    ///   example, if `trans` contains the `nConsensusBranchId` field, and `nu` doesn't match it.
90    ///   More details in [`PrecomputedTxData::new`].
91    /// - If `nu` doesn't contain a consensus branch id convertible to its `librustzcash`
92    ///   equivalent.
93    pub fn new(
94        trans: &Transaction,
95        nu: NetworkUpgrade,
96        all_previous_outputs: Arc<Vec<transparent::Output>>,
97    ) -> Result<Self, Error> {
98        Ok(SigHasher {
99            precomputed_tx_data: PrecomputedTxData::new(trans, nu, all_previous_outputs)?,
100        })
101    }
102
103    /// Calculate the sighash for the current transaction.
104    ///
105    /// # Details
106    ///
107    /// The `input_index_script_code` tuple indicates the index of the
108    /// transparent Input for which we are producing a sighash and the
109    /// respective script code being validated, or None if it's a shielded
110    /// input.
111    ///
112    /// # Panics
113    ///
114    /// - if the input index is out of bounds for self.inputs()
115    pub fn sighash(
116        &self,
117        hash_type: HashType,
118        input_index_script_code: Option<(usize, Vec<u8>)>,
119    ) -> SigHash {
120        sighash(
121            &self.precomputed_tx_data,
122            hash_type,
123            input_index_script_code,
124        )
125    }
126
127    /// Returns the Orchard bundle in the precomputed transaction data.
128    pub fn orchard_bundle(
129        &self,
130    ) -> Option<::orchard::bundle::Bundle<::orchard::bundle::Authorized, ZatBalance>> {
131        self.precomputed_tx_data.orchard_bundle()
132    }
133
134    /// Returns the Sapling bundle in the precomputed transaction data.
135    pub fn sapling_bundle(
136        &self,
137    ) -> Option<sapling_crypto::Bundle<sapling_crypto::bundle::Authorized, ZatBalance>> {
138        self.precomputed_tx_data.sapling_bundle()
139    }
140}