bc/
sigcache.rs

1// Bitcoin protocol consensus library.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2019-2024 by
6//     Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved.
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21
22use 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
32/// Used for signature hash for invalid use of SIGHASH_SINGLE.
33const 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    /// invalid input index {index} in {txid} which has only {inputs} inputs.
52    InvalidInputIndex {
53        txid: Txid,
54        index: usize,
55        inputs: usize,
56    },
57
58    /// transaction {txid} input {index} uses SIGHASH_SINGLE, but the total
59    /// number of outputs is {outputs} and thus no signature can be produced.
60    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/// Efficiently calculates signature hash message for legacy, segwit and taproot
72/// inputs.
73#[derive(Debug)]
74pub struct SighashCache<Prevout: Borrow<TxOut> = TxOut, Tx: Borrow<Transaction> = Transaction> {
75    /// Access to transaction required for transaction introspection.
76    tx: Tx,
77
78    prevouts: Vec<Prevout>,
79
80    /// Common cache for taproot and segwit inputs, `None` for legacy inputs.
81    common_cache: Option<CommonCache>,
82
83    /// Cache for segwit v0 inputs (the result of another round of sha256 on
84    /// `common_cache`).
85    segwit_cache: Option<SegwitCache>,
86
87    /// Cache for taproot v1 inputs.
88    taproot_cache: Option<TaprootCache>,
89}
90
91/// Common values cached between segwit and taproot inputs.
92#[derive(Copy, Clone, Debug)]
93struct CommonCache {
94    prevouts: Bytes32,
95    sequences: Bytes32,
96
97    /// In theory `outputs` could be an `Option` since `SIGHASH_NONE` and
98    /// `SIGHASH_SINGLE` do not need it, but since `SIGHASH_ALL` is by far
99    /// the most used variant we don't bother.
100    outputs: Bytes32,
101}
102
103/// Values cached for segwit inputs, equivalent to [`CommonCache`] plus another
104/// round of `sha256`.
105#[derive(Copy, Clone, Debug)]
106struct SegwitCache {
107    prevouts: Bytes32,
108    sequences: Bytes32,
109    outputs: Bytes32,
110}
111
112/// Values cached for taproot inputs.
113#[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    /// Constructs a new `SighashCache` from an unsigned transaction.
121    ///
122    /// The sighash components are computed in a lazy manner when required. For
123    /// the generated sighashes to be valid, no fields in the transaction
124    /// may change except for script_sig and witness.
125    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    /// Computes the BIP341 sighash for any type with a fine-grained control
144    /// over annex and code separator.
145    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        // epoch
160        0u8.consensus_encode(&mut hasher)?;
161
162        // * Control:
163        // hash_type (1).
164        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            // * Transaction Data:
172            // nVersion (4): the nVersion of the transaction.
173            tx.version.consensus_encode(&mut hasher)?;
174
175            // nLockTime (4): the nLockTime of the transaction.
176            tx.lock_time.consensus_encode(&mut hasher)?;
177        }
178
179        // If the hash_type & 0x80 does not equal SIGHASH_ANYONECANPAY:
180        //     sha_prevouts (32): the SHA256 of the serialization of all input
181        // outpoints.     sha_amounts (32): the SHA256 of the serialization of
182        // all spent output amounts.     sha_scriptpubkeys (32): the SHA256 of
183        // the serialization of all spent output scriptPubKeys.
184        // sha_sequences (32): the SHA256 of the serialization of all
185        // input nSequence.
186        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 hash_type & 3 does not equal SIGHASH_NONE or SIGHASH_SINGLE:
194        //     sha_outputs (32): the SHA256 of the serialization of all outputs in
195        // CTxOut format.
196        if sighash_flag != SighashFlag::None && sighash_flag != SighashFlag::Single {
197            self.common_cache().outputs.consensus_encode(&mut hasher)?;
198        }
199
200        // * Data about this input:
201        // spend_type (1): equal to (ext_flag * 2) + annex_present, where annex_present
202        // is 0 if no annex is present, or 1 otherwise
203        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 hash_type & 0x80 equals SIGHASH_ANYONECANPAY:
215        //      outpoint (36): the COutPoint of this input (32-byte hash + 4-byte
216        // little-endian).      amount (8): value of the previous output spent
217        // by this input.      scriptPubKey (35): scriptPubKey of the previous
218        // output spent by this input, serialized as script inside CTxOut. Its
219        // size is always 35 bytes.      nSequence (4): nSequence of this input.
220        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 an annex is present (the lowest bit of spend_type is set):
236        //      sha_annex (32): the SHA256 of (compact_size(size of annex) || annex),
237        // where annex      includes the mandatory 0x50 prefix.
238        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        // * Data about this output:
246        // If hash_type & 3 equals SIGHASH_SINGLE:
247        //      sha_single_output (32): the SHA256 of the corresponding output in CTxOut
248        // format.
249        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 (scriptpath):
264        //         ss += TaggedHash("TapLeaf", bytes([leaf_ver]) + ser_string(script))
265        //         ss += bytes([0])
266        //         ss += struct.pack("<i", codeseparator_pos)
267        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    /// Computes the BIP341 sighash for a key spend.
277    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    /// Computes the BIP341 sighash for a script spend.
286    ///
287    /// Assumes the default `OP_CODESEPARATOR` position of `0xFFFFFFFF`.
288    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    /// Computes the BIP143 sighash for any flag type.
303    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    /// Computes the legacy sighash for any `sighash_type`.
369    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        // Build tx to sign
396        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        // Add all necessary inputs...
404        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        // ...then all outputs
428        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)  // sign all outputs up to and including this one, but erase
433                    .enumerate()            // all of them except for this one
434                    .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        // hash the result
440        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}