Skip to main content

tidecoin_consensus_core/
sighash.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use alloc::string::{String, ToString};
4use core::borrow::{Borrow, BorrowMut};
5use core::{fmt, str};
6
7use encoding::CompactSizeEncoder;
8use hashes::{hash_newtype, sha256, sha256d, sha512};
9use io::Write;
10use primitives::{script::Script, Amount, ScriptPubKey, Sequence, Transaction};
11
12#[rustfmt::skip]
13const UINT256_ONE: [u8; 32] = [
14    1, 0, 0, 0, 0, 0, 0, 0,
15    0, 0, 0, 0, 0, 0, 0, 0,
16    0, 0, 0, 0, 0, 0, 0, 0,
17    0, 0, 0, 0, 0, 0, 0, 0
18];
19
20#[rustfmt::skip]
21const UINT512_ONE: [u8; 64] = [
22    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
23    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
25    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
26];
27
28hash_newtype! {
29    /// Hash of a transaction according to the legacy signature algorithm.
30    #[hash_newtype(forward)]
31    pub struct LegacySighash(sha256d::Hash);
32
33    /// Hash of a transaction according to the SegWit version 0 signature algorithm.
34    #[hash_newtype(forward)]
35    pub struct SegwitV0Sighash(sha256d::Hash);
36
37    /// Hash of a transaction according to the Tidecoin witness-v1 SHA-512 algorithm.
38    #[hash_newtype(forward)]
39    pub struct Sighash512(sha512::Hash);
40}
41
42#[cfg(feature = "hex")]
43hashes::impl_hex_for_newtype!(LegacySighash, SegwitV0Sighash, Sighash512);
44#[cfg(feature = "serde")]
45hashes::impl_serde_for_newtype!(LegacySighash, SegwitV0Sighash, Sighash512);
46#[cfg(not(feature = "hex"))]
47hashes::impl_debug_only_for_newtype!(LegacySighash, SegwitV0Sighash, Sighash512);
48
49impl LegacySighash {
50    fn engine() -> sha256d::HashEngine {
51        sha256d::Hash::engine()
52    }
53
54    fn from_engine(e: sha256d::HashEngine) -> Self {
55        Self(sha256d::Hash::from_engine(e))
56    }
57}
58
59impl SegwitV0Sighash {
60    fn engine() -> sha256d::HashEngine {
61        sha256d::Hash::engine()
62    }
63
64    fn from_engine(e: sha256d::HashEngine) -> Self {
65        Self(sha256d::Hash::from_engine(e))
66    }
67}
68
69impl Sighash512 {
70    fn engine() -> sha512::HashEngine {
71        sha512::Hash::engine()
72    }
73
74    fn from_engine(e: sha512::HashEngine) -> Self {
75        Self(sha512::Hash::from_engine(e))
76    }
77}
78
79/// Hashtype of an input's signature, encoded in the last byte of the signature.
80#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
81pub enum TxSighashType {
82    /// 0x1: Sign all outputs.
83    All = 0x01,
84    /// 0x2: Sign no outputs.
85    None = 0x02,
86    /// 0x3: Sign the output matching this input index, or `1` if absent.
87    Single = 0x03,
88    /// 0x81: Sign all outputs and only this input.
89    AllPlusAnyoneCanPay = 0x81,
90    /// 0x82: Sign no outputs and only this input.
91    NonePlusAnyoneCanPay = 0x82,
92    /// 0x83: Sign one output and only this input.
93    SinglePlusAnyoneCanPay = 0x83,
94}
95
96impl TxSighashType {
97    fn split_anyonecanpay_flag(self) -> (Self, bool) {
98        match self {
99            Self::All => (Self::All, false),
100            Self::None => (Self::None, false),
101            Self::Single => (Self::Single, false),
102            Self::AllPlusAnyoneCanPay => (Self::All, true),
103            Self::NonePlusAnyoneCanPay => (Self::None, true),
104            Self::SinglePlusAnyoneCanPay => (Self::Single, true),
105        }
106    }
107
108    /// Checks if the sighash type is `SINGLE`, with or without `ANYONECANPAY`.
109    pub fn is_single(&self) -> bool {
110        matches!(self, Self::Single | Self::SinglePlusAnyoneCanPay)
111    }
112
113    /// Constructs a new sighash type from a raw consensus `u32`.
114    pub fn from_consensus(n: u32) -> Self {
115        let mask = 0x1f | 0x80;
116        match n & mask {
117            0x01 => Self::All,
118            0x02 => Self::None,
119            0x03 => Self::Single,
120            0x81 => Self::AllPlusAnyoneCanPay,
121            0x82 => Self::NonePlusAnyoneCanPay,
122            0x83 => Self::SinglePlusAnyoneCanPay,
123            x if x & 0x80 == 0x80 => Self::AllPlusAnyoneCanPay,
124            _ => Self::All,
125        }
126    }
127
128    /// Constructs a sighash type from a standard raw `u32`.
129    ///
130    /// # Errors
131    ///
132    /// Returns an error if `n` is a non-standard sighash value.
133    pub fn from_standard(n: u32) -> Result<Self, NonStandardSighashTypeError> {
134        match n {
135            0x01 => Ok(Self::All),
136            0x02 => Ok(Self::None),
137            0x03 => Ok(Self::Single),
138            0x81 => Ok(Self::AllPlusAnyoneCanPay),
139            0x82 => Ok(Self::NonePlusAnyoneCanPay),
140            0x83 => Ok(Self::SinglePlusAnyoneCanPay),
141            non_standard => Err(NonStandardSighashTypeError(non_standard)),
142        }
143    }
144
145    /// Converts the sighash type to its consensus `u32` value.
146    pub fn to_u32(self) -> u32 {
147        self as u32
148    }
149}
150
151impl fmt::Display for TxSighashType {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        let s = match self {
154            Self::All => "SIGHASH_ALL",
155            Self::None => "SIGHASH_NONE",
156            Self::Single => "SIGHASH_SINGLE",
157            Self::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY",
158            Self::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY",
159            Self::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY",
160        };
161        f.write_str(s)
162    }
163}
164
165impl str::FromStr for TxSighashType {
166    type Err = SighashTypeParseError;
167
168    fn from_str(s: &str) -> Result<Self, Self::Err> {
169        match s {
170            "SIGHASH_ALL" => Ok(Self::All),
171            "SIGHASH_NONE" => Ok(Self::None),
172            "SIGHASH_SINGLE" => Ok(Self::Single),
173            "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(Self::AllPlusAnyoneCanPay),
174            "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(Self::NonePlusAnyoneCanPay),
175            "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(Self::SinglePlusAnyoneCanPay),
176            _ => Err(SighashTypeParseError { unrecognized: s.to_string() }),
177        }
178    }
179}
180
181#[cfg(feature = "serde")]
182internals::serde_string_impl!(TxSighashType, "a TxSighashType data");
183
184/// Error returned for a non-standard sighash type.
185#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct NonStandardSighashTypeError(pub u32);
187
188impl fmt::Display for NonStandardSighashTypeError {
189    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190        write!(f, "non-standard sighash type {}", self.0)
191    }
192}
193
194#[cfg(feature = "std")]
195impl std::error::Error for NonStandardSighashTypeError {}
196
197/// Error returned for failure during parsing one of the sighash types.
198#[derive(Debug, Clone, PartialEq, Eq)]
199#[non_exhaustive]
200pub struct SighashTypeParseError {
201    /// The unrecognized string we attempted to parse.
202    pub unrecognized: String,
203}
204
205impl fmt::Display for SighashTypeParseError {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        write!(f, "unrecognized SIGHASH string '{}'", self.unrecognized)
208    }
209}
210
211#[cfg(feature = "std")]
212impl std::error::Error for SighashTypeParseError {}
213
214/// Indexing error while computing a sighash.
215#[derive(Debug, Clone, PartialEq, Eq)]
216pub struct InputsIndexError {
217    /// Requested input index.
218    pub index: usize,
219    /// Total number of inputs.
220    pub length: usize,
221}
222
223impl fmt::Display for InputsIndexError {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        write!(f, "input index {} out of bounds for length {}", self.index, self.length)
226    }
227}
228
229#[cfg(feature = "std")]
230impl std::error::Error for InputsIndexError {}
231
232/// Efficiently calculates signature hash messages needed by consensus verification.
233#[derive(Debug)]
234pub struct SighashCache<T: Borrow<Transaction>> {
235    tx: T,
236    common_cache: Option<CommonCache>,
237    segwit_cache: Option<SegwitCache>,
238    segwit_cache_512: Option<SegwitV1512Cache>,
239}
240
241#[derive(Debug)]
242struct CommonCache {
243    prevouts: sha256::Hash,
244    sequences: sha256::Hash,
245    outputs: sha256::Hash,
246}
247
248#[derive(Debug)]
249struct SegwitCache {
250    prevouts: sha256d::Hash,
251    sequences: sha256d::Hash,
252    outputs: sha256d::Hash,
253}
254
255#[derive(Debug)]
256struct SegwitV1512Cache {
257    prevouts: sha512::Hash,
258    sequences: sha512::Hash,
259    outputs: sha512::Hash,
260}
261
262impl<R: Borrow<Transaction>> SighashCache<R> {
263    /// Constructs a new sighash cache from a transaction.
264    pub fn new(tx: R) -> Self {
265        Self { tx, common_cache: None, segwit_cache: None, segwit_cache_512: None }
266    }
267
268    /// Returns the transaction cached for sighash computation.
269    pub fn transaction(&self) -> &Transaction {
270        self.tx.borrow()
271    }
272
273    /// Destroys the cache and recovers the stored transaction.
274    pub fn into_transaction(self) -> R {
275        self.tx
276    }
277
278    fn input(&self, input_index: usize) -> Result<&primitives::TxIn, InputsIndexError> {
279        self.tx
280            .borrow()
281            .inputs
282            .get(input_index)
283            .ok_or(InputsIndexError { index: input_index, length: self.tx.borrow().inputs.len() })
284    }
285
286    /// Computes a legacy signature hash from raw script bytes.
287    pub fn legacy_signature_hash(
288        &self,
289        input_index: usize,
290        script_bytes: &[u8],
291        sighash_type: u32,
292    ) -> Result<LegacySighash, InputsIndexError> {
293        self.input(input_index)?;
294
295        if is_invalid_use_of_sighash_single(
296            sighash_type,
297            input_index,
298            self.tx.borrow().outputs.len(),
299        ) {
300            return Ok(LegacySighash::from_byte_array(UINT256_ONE));
301        }
302
303        let tx = self.tx.borrow();
304        let (sighash, anyone_can_pay) =
305            TxSighashType::from_consensus(sighash_type).split_anyonecanpay_flag();
306
307        let mut engine = LegacySighash::engine();
308        io::encode_to_writer(&tx.version, &mut engine).expect("hash engine does not fail");
309
310        encode_compact_size(if anyone_can_pay { 1 } else { tx.inputs.len() }, &mut engine)
311            .expect("hash engine does not fail");
312        if anyone_can_pay {
313            let input = &tx.inputs[input_index];
314            io::encode_to_writer(&input.previous_output, &mut engine)
315                .expect("hash engine does not fail");
316            encode_script_bytes(script_bytes, &mut engine).expect("hash engine does not fail");
317            io::encode_to_writer(&input.sequence, &mut engine).expect("hash engine does not fail");
318        } else {
319            for (n, input) in tx.inputs.iter().enumerate() {
320                io::encode_to_writer(&input.previous_output, &mut engine)
321                    .expect("hash engine does not fail");
322                if n == input_index {
323                    encode_script_bytes(script_bytes, &mut engine)
324                        .expect("hash engine does not fail");
325                } else {
326                    io::encode_to_writer(ScriptPubKey::new(), &mut engine)
327                        .expect("hash engine does not fail");
328                }
329                if n != input_index
330                    && (sighash == TxSighashType::Single || sighash == TxSighashType::None)
331                {
332                    io::encode_to_writer(&Sequence::ZERO, &mut engine)
333                        .expect("hash engine does not fail");
334                } else {
335                    io::encode_to_writer(&input.sequence, &mut engine)
336                        .expect("hash engine does not fail");
337                }
338            }
339        }
340
341        match sighash {
342            TxSighashType::All => {
343                encode_compact_size(tx.outputs.len(), &mut engine)
344                    .expect("hash engine does not fail");
345                for output in &tx.outputs {
346                    io::encode_to_writer(output, &mut engine).expect("hash engine does not fail");
347                }
348            }
349            TxSighashType::Single => {
350                let count = input_index.min(tx.outputs.len() - 1);
351                encode_compact_size(count + 1, &mut engine).expect("hash engine does not fail");
352                for _ in 0..count {
353                    engine
354                        .write_all(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00])
355                        .expect("hash engine does not fail");
356                }
357                io::encode_to_writer(&tx.outputs[count], &mut engine)
358                    .expect("hash engine does not fail");
359            }
360            TxSighashType::None => {
361                encode_compact_size(0, &mut engine).expect("hash engine does not fail");
362            }
363            _ => unreachable!(),
364        }
365
366        io::encode_to_writer(&tx.lock_time, &mut engine).expect("hash engine does not fail");
367        engine.write_all(&sighash_type.to_le_bytes()).expect("hash engine does not fail");
368        Ok(LegacySighash::from_engine(engine))
369    }
370
371    /// Computes a witness-v0 signature hash from raw witness script bytes.
372    pub fn p2wsh_signature_hash(
373        &mut self,
374        input_index: usize,
375        witness_script_bytes: &[u8],
376        amount: Amount,
377        sighash_type: TxSighashType,
378    ) -> Result<SegwitV0Sighash, InputsIndexError> {
379        let zero_hash = [0; 32];
380        let mut engine = SegwitV0Sighash::engine();
381        let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
382        let prevouts =
383            if !anyone_can_pay { Some(self.segwit_cache().prevouts.to_byte_array()) } else { None };
384        let sequences = if !anyone_can_pay
385            && sighash != TxSighashType::Single
386            && sighash != TxSighashType::None
387        {
388            Some(self.segwit_cache().sequences.to_byte_array())
389        } else {
390            None
391        };
392        let outputs = if sighash != TxSighashType::Single && sighash != TxSighashType::None {
393            Some(self.segwit_cache().outputs.to_byte_array())
394        } else {
395            None
396        };
397        let tx = self.tx.borrow();
398
399        io::encode_to_writer(&tx.version, &mut engine).expect("hash engine does not fail");
400        if let Some(prevouts) = prevouts {
401            engine.write_all(&prevouts).expect("hash engine does not fail");
402        } else {
403            engine.write_all(&zero_hash).expect("hash engine does not fail");
404        }
405
406        if let Some(sequences) = sequences {
407            engine.write_all(&sequences).expect("hash engine does not fail");
408        } else {
409            engine.write_all(&zero_hash).expect("hash engine does not fail");
410        }
411
412        let txin = self.input(input_index)?;
413        io::encode_to_writer(&txin.previous_output, &mut engine)
414            .expect("hash engine does not fail");
415        encode_script_bytes(witness_script_bytes, &mut engine).expect("hash engine does not fail");
416        io::encode_to_writer(&amount, &mut engine).expect("hash engine does not fail");
417        io::encode_to_writer(&txin.sequence, &mut engine).expect("hash engine does not fail");
418
419        if let Some(outputs) = outputs {
420            engine.write_all(&outputs).expect("hash engine does not fail");
421        } else if sighash == TxSighashType::Single && input_index < tx.outputs.len() {
422            let mut single_enc = LegacySighash::engine();
423            single_enc = hashes::encode_to_engine(&tx.outputs[input_index], single_enc);
424            let hash = LegacySighash::from_engine(single_enc);
425            engine.write_all(hash.as_byte_array()).expect("hash engine does not fail");
426        } else {
427            engine.write_all(&zero_hash).expect("hash engine does not fail");
428        }
429
430        io::encode_to_writer(&tx.lock_time, &mut engine).expect("hash engine does not fail");
431        engine.write_all(&sighash_type.to_u32().to_le_bytes()).expect("hash engine does not fail");
432        Ok(SegwitV0Sighash::from_engine(engine))
433    }
434
435    /// Computes a witness-v1-512 signature hash from raw witness script bytes.
436    pub fn p2wsh512_signature_hash(
437        &mut self,
438        input_index: usize,
439        witness_script_bytes: &[u8],
440        amount: Amount,
441        sighash_type: TxSighashType,
442    ) -> Result<Sighash512, InputsIndexError> {
443        const TAG: &[u8] = b"TidecoinSighashV1_512";
444        let zero_hash = [0; 64];
445        let outputs_len = self.tx.borrow().outputs.len();
446
447        if sighash_type.is_single() && input_index >= outputs_len {
448            return Ok(Sighash512::from_byte_array(UINT512_ONE));
449        }
450
451        let tag_hash = sha512::Hash::hash(TAG);
452        let mut engine = Sighash512::engine();
453        engine.write_all(tag_hash.as_byte_array()).expect("hash engine does not fail");
454        engine.write_all(tag_hash.as_byte_array()).expect("hash engine does not fail");
455
456        let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
457        let prevouts = if !anyone_can_pay {
458            Some(*self.segwit_cache_512().prevouts.as_byte_array())
459        } else {
460            None
461        };
462        let sequences = if !anyone_can_pay
463            && sighash != TxSighashType::Single
464            && sighash != TxSighashType::None
465        {
466            Some(*self.segwit_cache_512().sequences.as_byte_array())
467        } else {
468            None
469        };
470        let outputs = if sighash != TxSighashType::Single && sighash != TxSighashType::None {
471            Some(*self.segwit_cache_512().outputs.as_byte_array())
472        } else {
473            None
474        };
475        let tx = self.tx.borrow();
476        io::encode_to_writer(&tx.version, &mut engine).expect("hash engine does not fail");
477
478        if let Some(prevouts) = prevouts {
479            engine.write_all(&prevouts).expect("hash engine does not fail");
480        } else {
481            engine.write_all(&zero_hash).expect("hash engine does not fail");
482        }
483
484        if let Some(sequences) = sequences {
485            engine.write_all(&sequences).expect("hash engine does not fail");
486        } else {
487            engine.write_all(&zero_hash).expect("hash engine does not fail");
488        }
489
490        let txin = self.input(input_index)?;
491        io::encode_to_writer(&txin.previous_output, &mut engine)
492            .expect("hash engine does not fail");
493        encode_script_bytes(witness_script_bytes, &mut engine).expect("hash engine does not fail");
494        io::encode_to_writer(&amount, &mut engine).expect("hash engine does not fail");
495        io::encode_to_writer(&txin.sequence, &mut engine).expect("hash engine does not fail");
496
497        if let Some(outputs) = outputs {
498            engine.write_all(&outputs).expect("hash engine does not fail");
499        } else if sighash == TxSighashType::Single {
500            let mut single_enc = sha512::Hash::engine();
501            io::encode_to_writer(&tx.outputs[input_index], &mut single_enc)
502                .expect("hash engine does not fail");
503            let hash = sha512::Hash::from_engine(single_enc);
504            engine.write_all(hash.as_byte_array()).expect("hash engine does not fail");
505        } else {
506            engine.write_all(&zero_hash).expect("hash engine does not fail");
507        }
508
509        io::encode_to_writer(&tx.lock_time, &mut engine).expect("hash engine does not fail");
510        engine.write_all(&sighash_type.to_u32().to_le_bytes()).expect("hash engine does not fail");
511        Ok(Sighash512::from_engine(engine))
512    }
513
514    fn common_cache_minimal_borrow<'a>(
515        common_cache: &'a mut Option<CommonCache>,
516        tx: &Transaction,
517    ) -> &'a CommonCache {
518        common_cache.get_or_insert_with(|| {
519            let mut enc_prevouts = sha256::Hash::engine();
520            let mut enc_sequences = sha256::Hash::engine();
521            for txin in &tx.inputs {
522                enc_prevouts = hashes::encode_to_engine(&txin.previous_output, enc_prevouts);
523                enc_sequences = hashes::encode_to_engine(&txin.sequence, enc_sequences);
524            }
525            CommonCache {
526                prevouts: sha256::Hash::from_engine(enc_prevouts),
527                sequences: sha256::Hash::from_engine(enc_sequences),
528                outputs: {
529                    let mut enc = sha256::Hash::engine();
530                    for txout in &tx.outputs {
531                        io::encode_to_writer(txout, &mut enc).expect("hash engine does not fail");
532                    }
533                    sha256::Hash::from_engine(enc)
534                },
535            }
536        })
537    }
538
539    fn segwit_cache(&mut self) -> &SegwitCache {
540        let common_cache = &mut self.common_cache;
541        let tx = self.tx.borrow();
542        self.segwit_cache.get_or_insert_with(|| {
543            let common_cache = Self::common_cache_minimal_borrow(common_cache, tx);
544            SegwitCache {
545                prevouts: common_cache.prevouts.hash_again(),
546                sequences: common_cache.sequences.hash_again(),
547                outputs: common_cache.outputs.hash_again(),
548            }
549        })
550    }
551
552    fn segwit_cache_512(&mut self) -> &SegwitV1512Cache {
553        let tx = self.tx.borrow();
554        self.segwit_cache_512.get_or_insert_with(|| {
555            let mut enc_prevouts = sha512::Hash::engine();
556            let mut enc_sequences = sha512::Hash::engine();
557            for txin in &tx.inputs {
558                enc_prevouts = hashes::encode_to_engine(&txin.previous_output, enc_prevouts);
559                enc_sequences = hashes::encode_to_engine(&txin.sequence, enc_sequences);
560            }
561            SegwitV1512Cache {
562                prevouts: sha512::Hash::from_engine(enc_prevouts),
563                sequences: sha512::Hash::from_engine(enc_sequences),
564                outputs: {
565                    let mut enc = sha512::Hash::engine();
566                    for txout in &tx.outputs {
567                        io::encode_to_writer(txout, &mut enc).expect("hash engine does not fail");
568                    }
569                    sha512::Hash::from_engine(enc)
570                },
571            }
572        })
573    }
574}
575
576impl<R: BorrowMut<Transaction>> SighashCache<R> {
577    /// Returns mutable access to the cached transaction.
578    ///
579    /// Callers must not mutate fields that participate in already-computed cache entries.
580    pub fn transaction_mut(&mut self) -> &mut Transaction {
581        self.tx.borrow_mut()
582    }
583}
584
585fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, outputs_len: usize) -> bool {
586    TxSighashType::from_consensus(sighash).is_single() && input_index >= outputs_len
587}
588
589fn encode_compact_size<W: Write>(len: usize, writer: &mut W) -> Result<(), io::Error> {
590    let mut encoder = CompactSizeEncoder::new(len);
591    io::flush_to_writer(&mut encoder, writer)
592}
593
594fn encode_script_bytes<W: Write>(bytes: &[u8], writer: &mut W) -> Result<(), io::Error> {
595    io::encode_to_writer(Script::<()>::from_bytes(bytes), writer)
596}