zebra_chain/primitives/
zcash_primitives.rs1use std::{io, ops::Deref, sync::Arc};
5
6use zcash_primitives::transaction::{self as zp_tx, TxDigests};
7use zcash_protocol::value::{BalanceError, ZatBalance, Zatoshis};
8use zcash_script::script;
9
10use crate::{
11 amount::{Amount, NonNegative},
12 parameters::NetworkUpgrade,
13 serialization::ZcashSerialize,
14 transaction::{AuthDigest, HashType, SigHash, Transaction},
15 transparent::{self, Script},
16 Error,
17};
18
19#[derive(Clone, Debug)]
24struct TransparentAuth {
25 all_prev_outputs: Arc<Vec<transparent::Output>>,
26}
27
28impl zcash_transparent::bundle::Authorization for TransparentAuth {
29 type ScriptSig = zcash_transparent::address::Script;
30}
31
32impl zcash_transparent::sighash::TransparentAuthorizingContext for TransparentAuth {
35 fn input_amounts(&self) -> Vec<Zatoshis> {
36 self.all_prev_outputs
37 .iter()
38 .map(|prevout| {
39 prevout
40 .value
41 .try_into()
42 .expect("will not fail since it was previously validated")
43 })
44 .collect()
45 }
46
47 fn input_scriptpubkeys(&self) -> Vec<zcash_transparent::address::Script> {
48 self.all_prev_outputs
49 .iter()
50 .map(|prevout| {
51 zcash_transparent::address::Script(script::Code(
52 prevout.lock_script.as_raw_bytes().into(),
53 ))
54 })
55 .collect()
56 }
57}
58
59struct MapTransparent {
64 auth: TransparentAuth,
65}
66
67impl zcash_transparent::bundle::MapAuth<zcash_transparent::bundle::Authorized, TransparentAuth>
68 for MapTransparent
69{
70 fn map_script_sig(
71 &self,
72 s: <zcash_transparent::bundle::Authorized as zcash_transparent::bundle::Authorization>::ScriptSig,
73 ) -> <TransparentAuth as zcash_transparent::bundle::Authorization>::ScriptSig {
74 s
75 }
76
77 fn map_authorization(&self, _: zcash_transparent::bundle::Authorized) -> TransparentAuth {
78 self.auth.clone()
80 }
81}
82
83struct IdentityMap;
84
85impl
86 zp_tx::components::sapling::MapAuth<
87 sapling_crypto::bundle::Authorized,
88 sapling_crypto::bundle::Authorized,
89 > for IdentityMap
90{
91 fn map_spend_proof(
92 &mut self,
93 p: <sapling_crypto::bundle::Authorized as sapling_crypto::bundle::Authorization>::SpendProof,
94 ) -> <sapling_crypto::bundle::Authorized as sapling_crypto::bundle::Authorization>::SpendProof
95 {
96 p
97 }
98
99 fn map_output_proof(
100 &mut self,
101 p: <sapling_crypto::bundle::Authorized as sapling_crypto::bundle::Authorization>::OutputProof,
102 ) -> <sapling_crypto::bundle::Authorized as sapling_crypto::bundle::Authorization>::OutputProof
103 {
104 p
105 }
106
107 fn map_auth_sig(
108 &mut self,
109 s: <sapling_crypto::bundle::Authorized as sapling_crypto::bundle::Authorization>::AuthSig,
110 ) -> <sapling_crypto::bundle::Authorized as sapling_crypto::bundle::Authorization>::AuthSig
111 {
112 s
113 }
114
115 fn map_authorization(
116 &mut self,
117 a: sapling_crypto::bundle::Authorized,
118 ) -> sapling_crypto::bundle::Authorized {
119 a
120 }
121}
122
123impl zp_tx::components::orchard::MapAuth<orchard::bundle::Authorized, orchard::bundle::Authorized>
124 for IdentityMap
125{
126 fn map_spend_auth(
127 &self,
128 s: <orchard::bundle::Authorized as orchard::bundle::Authorization>::SpendAuth,
129 ) -> <orchard::bundle::Authorized as orchard::bundle::Authorization>::SpendAuth {
130 s
131 }
132
133 fn map_authorization(&self, a: orchard::bundle::Authorized) -> orchard::bundle::Authorized {
134 a
135 }
136}
137
138#[derive(Debug)]
139struct PrecomputedAuth {}
140
141impl zp_tx::Authorization for PrecomputedAuth {
142 type TransparentAuth = TransparentAuth;
143 type SaplingAuth = sapling_crypto::bundle::Authorized;
144 type OrchardAuth = orchard::bundle::Authorized;
145
146 #[cfg(zcash_unstable = "zfuture")]
147 type TzeAuth = zp_tx::components::tze::Authorized;
148}
149
150impl TryFrom<&transparent::Output> for zcash_transparent::bundle::TxOut {
154 type Error = io::Error;
155
156 #[allow(clippy::unwrap_in_result)]
157 fn try_from(output: &transparent::Output) -> Result<Self, Self::Error> {
158 let serialized_output_bytes = output
159 .zcash_serialize_to_vec()
160 .expect("zcash_primitives and Zebra transparent output formats must be compatible");
161
162 zcash_transparent::bundle::TxOut::read(&mut serialized_output_bytes.as_slice())
163 }
164}
165
166impl TryFrom<transparent::Output> for zcash_transparent::bundle::TxOut {
168 type Error = io::Error;
169
170 #[allow(clippy::needless_borrow)]
172 fn try_from(output: transparent::Output) -> Result<Self, Self::Error> {
173 (&output).try_into()
174 }
175}
176
177impl TryFrom<Amount<NonNegative>> for zcash_protocol::value::Zatoshis {
179 type Error = BalanceError;
180
181 fn try_from(amount: Amount<NonNegative>) -> Result<Self, Self::Error> {
182 zcash_protocol::value::Zatoshis::from_nonnegative_i64(amount.into())
183 }
184}
185
186impl TryFrom<Amount> for ZatBalance {
187 type Error = BalanceError;
188
189 fn try_from(amount: Amount) -> Result<Self, Self::Error> {
190 ZatBalance::from_i64(amount.into())
191 }
192}
193
194impl From<&Script> for zcash_transparent::address::Script {
196 fn from(script: &Script) -> Self {
197 zcash_transparent::address::Script(script::Code(script.as_raw_bytes().to_vec()))
198 }
199}
200
201impl From<Script> for zcash_transparent::address::Script {
203 #[allow(clippy::needless_borrow)]
205 fn from(script: Script) -> Self {
206 (&script).into()
207 }
208}
209
210#[derive(Debug)]
212pub(crate) struct PrecomputedTxData {
213 tx_data: zp_tx::TransactionData<PrecomputedAuth>,
214 txid_parts: TxDigests<blake2b_simd::Hash>,
215 all_previous_outputs: Arc<Vec<transparent::Output>>,
216}
217
218impl PrecomputedTxData {
219 pub(crate) fn new(
253 tx: &Transaction,
254 nu: NetworkUpgrade,
255 all_previous_outputs: Arc<Vec<transparent::Output>>,
256 ) -> Result<PrecomputedTxData, Error> {
257 let tx = tx.to_librustzcash(nu)?;
258
259 let txid_parts = tx.deref().digest(zp_tx::txid::TxIdDigester);
260
261 let f_transparent = MapTransparent {
262 auth: TransparentAuth {
263 all_prev_outputs: all_previous_outputs.clone(),
264 },
265 };
266
267 let tx_data: zp_tx::TransactionData<PrecomputedAuth> = tx.into_data().map_authorization(
268 f_transparent,
269 IdentityMap,
270 IdentityMap,
271 #[cfg(zcash_unstable = "zfuture")]
272 (),
273 );
274
275 Ok(PrecomputedTxData {
276 tx_data,
277 txid_parts,
278 all_previous_outputs,
279 })
280 }
281
282 pub fn orchard_bundle(
284 &self,
285 ) -> Option<orchard::bundle::Bundle<orchard::bundle::Authorized, ZatBalance>> {
286 self.tx_data.orchard_bundle().cloned()
287 }
288
289 pub fn sapling_bundle(
291 &self,
292 ) -> Option<sapling_crypto::Bundle<sapling_crypto::bundle::Authorized, ZatBalance>> {
293 self.tx_data.sapling_bundle().cloned()
294 }
295}
296
297pub(crate) fn sighash(
308 precomputed_tx_data: &PrecomputedTxData,
309 hash_type: HashType,
310 input_index_script_code: Option<(usize, Vec<u8>)>,
311) -> SigHash {
312 let lock_script: zcash_transparent::address::Script;
313 let unlock_script: zcash_transparent::address::Script;
314 let signable_input = match input_index_script_code {
315 Some((input_index, script_code)) => {
316 let output = &precomputed_tx_data.all_previous_outputs[input_index];
317 lock_script = output.lock_script.clone().into();
318 unlock_script = zcash_transparent::address::Script(script::Code(script_code));
319 zp_tx::sighash::SignableInput::Transparent(
320 zcash_transparent::sighash::SignableInput::from_parts(
321 hash_type.try_into().expect("hash type should be ALL"),
322 input_index,
323 &unlock_script,
324 &lock_script,
325 output
326 .value
327 .try_into()
328 .expect("amount was previously validated"),
329 ),
330 )
331 }
332 None => zp_tx::sighash::SignableInput::Shielded,
333 };
334
335 SigHash(
336 *zp_tx::sighash::signature_hash(
337 &precomputed_tx_data.tx_data,
338 &signable_input,
339 &precomputed_tx_data.txid_parts,
340 )
341 .as_ref(),
342 )
343}
344
345pub(crate) fn auth_digest(tx: &Transaction) -> AuthDigest {
353 let nu = tx.network_upgrade().expect("V5 tx has a network upgrade");
354
355 AuthDigest(
356 tx.to_librustzcash(nu)
357 .expect("V5 tx is convertible to its `zcash_params` equivalent")
358 .auth_commitment()
359 .as_ref()
360 .try_into()
361 .expect("digest has the correct size"),
362 )
363}