zebra_chain/transaction/sighash.rs
1//! Signature hashes for Zcash transactions
2
3use super::Transaction;
4
5use crate::parameters::NetworkUpgrade;
6use crate::transparent;
7
8use crate::primitives::zcash_primitives::{sighash, PrecomputedTxData};
9
10bitflags::bitflags! {
11 /// The different SigHash types, as defined in <https://zips.z.cash/zip-0143>
12 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
13 pub struct HashType: u32 {
14 /// Sign all the outputs
15 const ALL = 0b0000_0001;
16 /// Sign none of the outputs - anyone can spend
17 const NONE = 0b0000_0010;
18 /// Sign one of the outputs - anyone can spend the rest
19 const SINGLE = Self::ALL.bits() | Self::NONE.bits();
20 /// Anyone can add inputs to this transaction
21 const ANYONECANPAY = 0b1000_0000;
22 }
23}
24
25/// A Signature Hash (or SIGHASH) as specified in
26/// <https://zips.z.cash/protocol/protocol.pdf#sighash>
27#[derive(Copy, Clone, Eq, PartialEq, Debug)]
28pub struct SigHash(pub [u8; 32]);
29
30impl AsRef<[u8; 32]> for SigHash {
31 fn as_ref(&self) -> &[u8; 32] {
32 &self.0
33 }
34}
35
36impl AsRef<[u8]> for SigHash {
37 fn as_ref(&self) -> &[u8] {
38 &self.0
39 }
40}
41
42/// A SigHasher context which stores precomputed data that is reused
43/// between sighash computations for the same transaction.
44#[derive(Debug)]
45pub struct SigHasher<'a> {
46 precomputed_tx_data: PrecomputedTxData<'a>,
47}
48
49impl<'a> SigHasher<'a> {
50 /// Create a new SigHasher for the given transaction.
51 ///
52 /// # Panics
53 ///
54 /// - If `trans` can't be converted to its `librustzcash` equivalent. This could happen, for
55 /// example, if `trans` contains the `nConsensusBranchId` field, and `nu` doesn't match it.
56 /// More details in [`PrecomputedTxData::new`].
57 /// - If `nu` doesn't contain a consensus branch id convertible to its `librustzcash`
58 /// equivalent.
59 pub fn new(
60 trans: &'a Transaction,
61 nu: NetworkUpgrade,
62 all_previous_outputs: &'a [transparent::Output],
63 ) -> Self {
64 SigHasher {
65 precomputed_tx_data: PrecomputedTxData::new(trans, nu, all_previous_outputs),
66 }
67 }
68
69 /// Calculate the sighash for the current transaction.
70 ///
71 /// # Details
72 ///
73 /// The `input_index_script_code` tuple indicates the index of the
74 /// transparent Input for which we are producing a sighash and the
75 /// respective script code being validated, or None if it's a shielded
76 /// input.
77 ///
78 /// # Panics
79 ///
80 /// - if the input index is out of bounds for self.inputs()
81 pub fn sighash(
82 &self,
83 hash_type: HashType,
84 input_index_script_code: Option<(usize, Vec<u8>)>,
85 ) -> SigHash {
86 sighash(
87 &self.precomputed_tx_data,
88 hash_type,
89 input_index_script_code,
90 )
91 }
92}