1use std::borrow::Borrow;
23
24use amplify::{Bytes32, IoError};
25use commit_verify::{Digest, DigestExt, Sha256};
26
27use crate::{
28 Annex, ConsensusEncode, Sats, ScriptCode, ScriptPubkey, SeqNo, SigScript, Sighash, SighashFlag,
29 SighashType, TapLeafHash, TapSighash, Tx as Transaction, TxIn, TxOut, Txid, VarIntArray,
30};
31
32const UINT256_ONE: [u8; 32] = [
34 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
35];
36
37#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
38#[display(
39 "number of inputs ({inputs}) doesn't match to the number of provided prevouts ({prevouts}) \
40 for signature hasher on tx {txid}."
41)]
42pub struct PrevoutMismatch {
43 txid: Txid,
44 inputs: usize,
45 prevouts: usize,
46}
47
48#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
49#[display(doc_comments)]
50pub enum SighashError {
51 InvalidInputIndex {
53 txid: Txid,
54 index: usize,
55 inputs: usize,
56 },
57
58 NoSingleOutputMatch {
61 txid: Txid,
62 index: usize,
63 outputs: usize,
64 },
65}
66
67impl From<IoError> for SighashError {
68 fn from(_: IoError) -> Self { unreachable!("in-memory I/O doesn't error in Rust") }
69}
70
71#[derive(Debug)]
74pub struct SighashCache<Prevout: Borrow<TxOut> = TxOut, Tx: Borrow<Transaction> = Transaction> {
75 tx: Tx,
77
78 prevouts: Vec<Prevout>,
79
80 common_cache: Option<CommonCache>,
82
83 segwit_cache: Option<SegwitCache>,
86
87 taproot_cache: Option<TaprootCache>,
89}
90
91#[derive(Copy, Clone, Debug)]
93struct CommonCache {
94 prevouts: Bytes32,
95 sequences: Bytes32,
96
97 outputs: Bytes32,
101}
102
103#[derive(Copy, Clone, Debug)]
106struct SegwitCache {
107 prevouts: Bytes32,
108 sequences: Bytes32,
109 outputs: Bytes32,
110}
111
112#[derive(Copy, Clone, Debug)]
114struct TaprootCache {
115 amounts: Bytes32,
116 script_pubkeys: Bytes32,
117}
118
119impl<Prevout: Borrow<TxOut>, Tx: Borrow<Transaction>> SighashCache<Prevout, Tx> {
120 pub fn new(tx: Tx, prevouts: Vec<Prevout>) -> Result<Self, PrevoutMismatch> {
126 if tx.borrow().inputs.len() != prevouts.len() {
127 return Err(PrevoutMismatch {
128 txid: tx.borrow().txid(),
129 inputs: tx.borrow().inputs.len(),
130 prevouts: prevouts.len(),
131 });
132 }
133
134 Ok(SighashCache {
135 tx,
136 prevouts,
137 common_cache: None,
138 taproot_cache: None,
139 segwit_cache: None,
140 })
141 }
142
143 pub fn tap_sighash_custom(
146 &mut self,
147 input_index: usize,
148 annex: Option<Annex>,
149 leaf_hash_code_separator: Option<(TapLeafHash, u32)>,
150 sighash_type: Option<SighashType>,
151 ) -> Result<TapSighash, SighashError> {
152 let mut hasher = TapSighash::engine();
153
154 let SighashType {
155 flag: sighash_flag,
156 anyone_can_pay,
157 } = sighash_type.unwrap_or_default();
158
159 0u8.consensus_encode(&mut hasher)?;
161
162 match sighash_type {
165 None => 0u8.consensus_encode(&mut hasher)?,
166 Some(sighash_type) => sighash_type.to_consensus_u8().consensus_encode(&mut hasher)?,
167 };
168
169 {
170 let tx = self.tx.borrow();
171 tx.version.consensus_encode(&mut hasher)?;
174
175 tx.lock_time.consensus_encode(&mut hasher)?;
177 }
178
179 if !anyone_can_pay {
187 self.common_cache().prevouts.consensus_encode(&mut hasher)?;
188 self.taproot_cache().amounts.consensus_encode(&mut hasher)?;
189 self.taproot_cache().script_pubkeys.consensus_encode(&mut hasher)?;
190 self.common_cache().sequences.consensus_encode(&mut hasher)?;
191 }
192
193 if sighash_flag != SighashFlag::None && sighash_flag != SighashFlag::Single {
197 self.common_cache().outputs.consensus_encode(&mut hasher)?;
198 }
199
200 let mut spend_type = 0u8;
204 if annex.is_some() {
205 spend_type |= 1u8;
206 }
207 if leaf_hash_code_separator.is_some() {
208 spend_type |= 2u8;
209 }
210 spend_type.consensus_encode(&mut hasher)?;
211
212 let tx = self.tx.borrow();
213
214 if anyone_can_pay {
221 let txin = tx.inputs.get(input_index).ok_or(SighashError::InvalidInputIndex {
222 txid: tx.txid(),
223 index: input_index,
224 inputs: tx.inputs.len(),
225 })?;
226 let previous_output = self.prevouts[input_index].borrow();
227 txin.prev_output.consensus_encode(&mut hasher)?;
228 previous_output.value.consensus_encode(&mut hasher)?;
229 previous_output.script_pubkey.consensus_encode(&mut hasher)?;
230 txin.sequence.consensus_encode(&mut hasher)?;
231 } else {
232 (input_index as u32).consensus_encode(&mut hasher)?;
233 }
234
235 if let Some(annex) = annex {
239 let mut enc = Sha256::default();
240 annex.consensus_encode(&mut enc)?;
241 let hash = enc.finish();
242 hash.consensus_encode(&mut hasher)?;
243 }
244
245 if sighash_flag == SighashFlag::Single {
250 let mut enc = Sha256::default();
251 tx.outputs
252 .get(input_index)
253 .ok_or(SighashError::NoSingleOutputMatch {
254 txid: tx.txid(),
255 index: input_index,
256 outputs: tx.outputs.len(),
257 })?
258 .consensus_encode(&mut enc)?;
259 let hash = enc.finish();
260 hash.consensus_encode(&mut hasher)?;
261 }
262
263 if let Some((hash, code_separator_pos)) = leaf_hash_code_separator {
268 hash.consensus_encode(&mut hasher)?;
269 0u8.consensus_encode(&mut hasher)?;
270 code_separator_pos.consensus_encode(&mut hasher)?;
271 }
272
273 Ok(TapSighash::from_engine(hasher))
274 }
275
276 pub fn tap_sighash_key(
278 &mut self,
279 input_index: usize,
280 sighash_type: Option<SighashType>,
281 ) -> Result<TapSighash, SighashError> {
282 self.tap_sighash_custom(input_index, None, None, sighash_type)
283 }
284
285 pub fn tap_sighash_script(
289 &mut self,
290 input_index: usize,
291 leaf_hash: impl Into<TapLeafHash>,
292 sighash_type: Option<SighashType>,
293 ) -> Result<TapSighash, SighashError> {
294 self.tap_sighash_custom(
295 input_index,
296 None,
297 Some((leaf_hash.into(), 0xFFFFFFFF)),
298 sighash_type,
299 )
300 }
301
302 pub fn segwit_sighash(
304 &mut self,
305 input_index: usize,
306 script_code: &ScriptCode,
307 value: Sats,
308 sighash_type: SighashType,
309 ) -> Result<Sighash, SighashError> {
310 let mut hasher = Sighash::engine();
311
312 let zero_hash = [0u8; 32];
313
314 let SighashType {
315 flag: sighash_flag,
316 anyone_can_pay,
317 } = sighash_type;
318
319 self.tx.borrow().version.consensus_encode(&mut hasher)?;
320
321 if !anyone_can_pay {
322 self.segwit_cache().prevouts.consensus_encode(&mut hasher)?;
323 } else {
324 zero_hash.consensus_encode(&mut hasher)?;
325 }
326
327 if !anyone_can_pay
328 && sighash_flag != SighashFlag::Single
329 && sighash_flag != SighashFlag::None
330 {
331 self.segwit_cache().sequences.consensus_encode(&mut hasher)?;
332 } else {
333 zero_hash.consensus_encode(&mut hasher)?;
334 }
335
336 {
337 let tx = self.tx.borrow();
338 let txin = tx.inputs.get(input_index).ok_or(SighashError::InvalidInputIndex {
339 txid: tx.txid(),
340 index: input_index,
341 inputs: tx.inputs.len(),
342 })?;
343
344 txin.prev_output.consensus_encode(&mut hasher)?;
345 script_code.consensus_encode(&mut hasher)?;
346 value.consensus_encode(&mut hasher)?;
347 txin.sequence.consensus_encode(&mut hasher)?;
348 }
349
350 if sighash_flag != SighashFlag::Single && sighash_flag != SighashFlag::None {
351 self.segwit_cache().outputs.consensus_encode(&mut hasher)?;
352 } else if sighash_flag == SighashFlag::Single
353 && input_index < self.tx.borrow().outputs.len()
354 {
355 let mut single_enc = Sighash::engine();
356 self.tx.borrow().outputs[input_index].consensus_encode(&mut single_enc)?;
357 Sighash::from_engine(single_enc).consensus_encode(&mut hasher)?;
358 } else {
359 zero_hash.consensus_encode(&mut hasher)?;
360 }
361
362 self.tx.borrow().lock_time.consensus_encode(&mut hasher)?;
363 sighash_type.to_consensus_u32().consensus_encode(&mut hasher)?;
364
365 Ok(Sighash::from_engine(hasher))
366 }
367
368 pub fn legacy_sighash(
370 &self,
371 input_index: usize,
372 script_pubkey: &ScriptPubkey,
373 sighash_type: u32,
374 ) -> Result<Sighash, SighashError> {
375 let tx_src = self.tx.borrow();
376 let mut hasher = Sighash::engine();
377
378 if input_index >= tx_src.inputs.len() {
379 return Err(SighashError::InvalidInputIndex {
380 txid: tx_src.txid(),
381 index: input_index,
382 inputs: tx_src.inputs.len(),
383 });
384 }
385
386 let SighashType {
387 flag: sighash_flag,
388 anyone_can_pay,
389 } = SighashType::from_consensus_u32(sighash_type);
390
391 if sighash_flag == SighashFlag::Single && input_index >= tx_src.outputs.len() {
392 return Ok(Sighash::from(UINT256_ONE));
393 }
394
395 let mut tx = Transaction {
397 version: tx_src.version,
398 lock_time: tx_src.lock_time,
399 inputs: none!(),
400 outputs: none!(),
401 };
402
403 let sig_script = script_pubkey.as_script_bytes().clone().into();
405 if anyone_can_pay {
406 tx.inputs = VarIntArray::from_checked(vec![TxIn {
407 prev_output: tx_src.inputs[input_index].prev_output,
408 sig_script,
409 sequence: tx_src.inputs[input_index].sequence,
410 witness: none!(),
411 }]);
412 } else {
413 let inputs = tx_src.inputs.iter().enumerate().map(|(n, input)| TxIn {
414 prev_output: input.prev_output,
415 sig_script: if n == input_index { sig_script.clone() } else { SigScript::new() },
416 sequence: if n != input_index
417 && (sighash_flag == SighashFlag::Single || sighash_flag == SighashFlag::None)
418 {
419 SeqNo::ZERO
420 } else {
421 input.sequence
422 },
423 witness: none!(),
424 });
425 tx.inputs = VarIntArray::from_iter_checked(inputs);
426 }
427 tx.outputs = match sighash_flag {
429 SighashFlag::All => tx_src.outputs.clone(),
430 SighashFlag::Single => {
431 let outputs = tx_src.outputs.iter()
432 .take(input_index + 1) .enumerate() .map(|(n, out)| if n == input_index { out.clone() } else { TxOut::default() });
435 VarIntArray::from_iter_checked(outputs)
436 }
437 SighashFlag::None => none!(),
438 };
439 tx.consensus_encode(&mut hasher)?;
441 sighash_type.consensus_encode(&mut hasher)?;
442
443 Ok(Sighash::from_engine(hasher))
444 }
445
446 fn common_cache(&mut self) -> &CommonCache {
447 let tx = self.tx.borrow();
448 self.common_cache.get_or_insert_with(|| {
449 let mut enc_prevouts = Sha256::default();
450 let mut enc_sequences = Sha256::default();
451 for txin in &tx.inputs {
452 let _ = txin.prev_output.consensus_encode(&mut enc_prevouts);
453 let _ = txin.sequence.consensus_encode(&mut enc_sequences);
454 }
455 let mut enc_outputs = Sha256::default();
456 for txout in &tx.outputs {
457 let _ = txout.consensus_encode(&mut enc_outputs);
458 }
459 CommonCache {
460 prevouts: enc_prevouts.finish().into(),
461 sequences: enc_sequences.finish().into(),
462 outputs: enc_outputs.finish().into(),
463 }
464 })
465 }
466
467 fn segwit_cache(&mut self) -> &SegwitCache {
468 let common_cache = *self.common_cache();
469 self.segwit_cache.get_or_insert_with(|| SegwitCache {
470 prevouts: <[u8; 32]>::from(Sha256::digest(common_cache.prevouts)).into(),
471 sequences: <[u8; 32]>::from(Sha256::digest(common_cache.sequences)).into(),
472 outputs: <[u8; 32]>::from(Sha256::digest(common_cache.outputs)).into(),
473 })
474 }
475
476 fn taproot_cache(&mut self) -> &TaprootCache {
477 self.taproot_cache.get_or_insert_with(|| {
478 let mut enc_amounts = Sha256::default();
479 let mut enc_script_pubkeys = Sha256::default();
480 for prevout in &self.prevouts {
481 let _ = prevout.borrow().value.consensus_encode(&mut enc_amounts);
482 let _ = prevout.borrow().script_pubkey.consensus_encode(&mut enc_script_pubkeys);
483 }
484 TaprootCache {
485 amounts: enc_amounts.finish().into(),
486 script_pubkeys: enc_script_pubkeys.finish().into(),
487 }
488 })
489 }
490}