1use crate::crypto::OptimizedSha256;
10use crate::error::Result;
11use crate::types::*;
12#[cfg(feature = "spec-lock")]
13use blvm_spec_lock::spec_locked;
14
15#[inline]
17fn write_varint_to_vec(vec: &mut Vec<u8>, value: u64) {
18 if value < 0xfd {
19 vec.push(value as u8);
20 } else if value <= 0xffff {
21 vec.push(0xfd);
22 vec.extend_from_slice(&(value as u16).to_le_bytes());
23 } else if value <= 0xffffffff {
24 vec.push(0xfe);
25 vec.extend_from_slice(&(value as u32).to_le_bytes());
26 } else {
27 vec.push(0xff);
28 vec.extend_from_slice(&value.to_le_bytes());
29 }
30}
31
32#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "SerializeScriptCode"))]
37pub fn serialize_script_code_for_legacy_sighash(script: &[u8]) -> Vec<u8> {
38 let mut out = Vec::with_capacity(script.len());
39 append_stripped_codeseparators(&mut out, script);
40 out
41}
42
43#[cfg_attr(
45 feature = "spec-lock",
46 spec_locked("11.1.9.1", "DeriveWitnessScriptCode")
47)]
48pub fn derive_bip143_script_code_p2wpkh(pubkey_hash: &[u8; 20]) -> [u8; 25] {
49 use crate::opcodes::{OP_CHECKSIG, OP_DUP, OP_EQUALVERIFY, OP_HASH160, PUSH_20_BYTES};
50 let mut script_code = [0u8; 25];
51 script_code[0] = OP_DUP;
52 script_code[1] = OP_HASH160;
53 script_code[2] = PUSH_20_BYTES;
54 script_code[3..23].copy_from_slice(pubkey_hash);
55 script_code[23] = OP_EQUALVERIFY;
56 script_code[24] = OP_CHECKSIG;
57 script_code
58}
59
60#[cfg_attr(
65 feature = "spec-lock",
66 spec_locked("11.1.9.1", "DeriveWitnessScriptCode")
67)]
68pub fn derive_bip143_script_code(
69 witness_program: &[u8],
70 witness_script: Option<&[u8]>,
71) -> Option<Vec<u8>> {
72 use crate::opcodes::{OP_0, PUSH_20_BYTES, PUSH_32_BYTES};
73 if witness_program.len() == 22
74 && witness_program[0] == OP_0
75 && witness_program[1] == PUSH_20_BYTES
76 {
77 let mut hash = [0u8; 20];
78 hash.copy_from_slice(&witness_program[2..22]);
79 return Some(derive_bip143_script_code_p2wpkh(&hash).to_vec());
80 }
81 if witness_program.len() == 34
82 && witness_program[0] == OP_0
83 && witness_program[1] == PUSH_32_BYTES
84 {
85 return witness_script.map(|s| s.to_vec());
86 }
87 None
88}
89
90#[inline]
96fn write_script_code_for_sighash(preimage: &mut Vec<u8>, code: &[u8]) {
97 if !code.contains(&0xab) {
100 write_varint_to_vec(preimage, code.len() as u64);
101 preimage.extend_from_slice(code);
102 return;
103 }
104 if code.len() < 0xfd {
107 let len_at = preimage.len();
108 preimage.push(0);
109 let body = preimage.len();
110 append_stripped_codeseparators(preimage, code);
111 preimage[len_at] = (preimage.len() - body) as u8;
112 return;
113 }
114 if code.len() <= 0xffff {
117 let start = preimage.len();
118 preimage.resize(start + 3, 0);
119 append_stripped_codeseparators(preimage, code);
120 let body_len = preimage.len() - (start + 3);
121 if body_len < 0xfd {
122 preimage.copy_within(start + 3.., start + 1);
123 preimage.truncate(start + 1 + body_len);
124 preimage[start] = body_len as u8;
125 } else {
126 preimage[start] = 0xfd;
127 let len_bytes = (body_len as u16).to_le_bytes();
128 preimage[start + 1] = len_bytes[0];
129 preimage[start + 2] = len_bytes[1];
130 }
131 return;
132 }
133 let n_codeseps = count_opcode_codeseparators(code);
134 write_varint_to_vec(preimage, (code.len() - n_codeseps) as u64);
135 if n_codeseps == 0 {
136 preimage.extend_from_slice(code);
137 } else {
138 append_stripped_codeseparators(preimage, code);
139 }
140}
141
142#[inline]
144fn count_opcode_codeseparators(script: &[u8]) -> usize {
145 let mut count = 0usize;
146 let mut i = 0usize;
147 while i < script.len() {
148 let op = script[i];
149 let advance = if (0x01..=0x4b).contains(&op) {
150 1 + op as usize
151 } else if op == 0x4c {
152 if i + 1 >= script.len() {
153 break;
154 }
155 2 + script[i + 1] as usize
156 } else if op == 0x4d {
157 if i + 2 >= script.len() {
158 break;
159 }
160 3 + u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize
161 } else if op == 0x4e {
162 if i + 4 >= script.len() {
163 break;
164 }
165 5 + u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
166 as usize
167 } else {
168 if op == 0xab {
169 count += 1;
170 }
171 1
172 };
173 i += advance.min(script.len() - i);
174 }
175 count
176}
177
178fn append_stripped_codeseparators(out: &mut Vec<u8>, code: &[u8]) {
180 let mut i = 0usize;
181 while i < code.len() {
182 let op = code[i];
183 if (0x01..=0x4b).contains(&op) {
184 let end = (i + 1 + op as usize).min(code.len());
185 out.extend_from_slice(&code[i..end]);
186 i = end;
187 } else if op == 0x4c {
188 if i + 1 >= code.len() {
189 out.push(op);
190 break;
191 }
192 let len = code[i + 1] as usize;
193 let end = (i + 2 + len).min(code.len());
194 out.extend_from_slice(&code[i..end]);
195 i = end;
196 } else if op == 0x4d {
197 if i + 2 >= code.len() {
198 out.extend_from_slice(&code[i..]);
199 break;
200 }
201 let len = u16::from_le_bytes([code[i + 1], code[i + 2]]) as usize;
202 let end = (i + 3 + len).min(code.len());
203 out.extend_from_slice(&code[i..end]);
204 i = end;
205 } else if op == 0x4e {
206 if i + 4 >= code.len() {
207 out.extend_from_slice(&code[i..]);
208 break;
209 }
210 let len =
211 u32::from_le_bytes([code[i + 1], code[i + 2], code[i + 3], code[i + 4]]) as usize;
212 let end = (i + 5 + len).min(code.len());
213 out.extend_from_slice(&code[i..end]);
214 i = end;
215 } else if op == 0xab {
216 i += 1; } else {
218 out.push(op);
219 i += 1;
220 }
221 }
222}
223
224#[cfg(feature = "production")]
225use lru::LruCache;
226#[cfg(feature = "production")]
227use rustc_hash::FxHashMap;
228#[cfg(feature = "production")]
229use std::cell::RefCell;
230
231#[cfg(feature = "production")]
239#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
240pub struct SighashCacheKey {
241 prevout: crate::types::OutPoint,
242 code_id: [u8; 32],
243 sighash_byte: u8,
244 tx_id: [u8; 32],
245}
246
247#[cfg(feature = "production")]
248pub type SighashMidstateCache =
249 std::sync::Arc<std::sync::Mutex<FxHashMap<SighashCacheKey, [u8; 32]>>>;
250
251#[cfg(feature = "production")]
255thread_local! {
256 static SIGHASH_MIDSTATE_CACHE: RefCell<LruCache<SighashCacheKey, [u8; 32]>> = RefCell::new({
257 let cap = std::env::var("BLVM_SIGHASH_MIDSTATE_CACHE_SIZE")
259 .ok()
260 .and_then(|s| s.parse().ok())
261 .unwrap_or(1_048_576)
262 .clamp(65_536, 2_097_152);
263 LruCache::new(std::num::NonZeroUsize::new(cap).unwrap())
264 });
265}
266
267#[cfg(feature = "production")]
268fn insert_midstate_cache(
269 sighash_cache: Option<&SighashMidstateCache>,
270 prevout: crate::types::OutPoint,
271 code: &[u8],
272 sighash_byte: u8,
273 tx_id: [u8; 32],
274 hash: [u8; 32],
275) {
276 let key = SighashCacheKey {
277 prevout,
278 code_id: script_code_id(code),
279 sighash_byte,
280 tx_id,
281 };
282 if let Some(c) = sighash_cache {
283 let _ = c.lock().map(|mut g| g.insert(key, hash));
284 } else {
285 SIGHASH_MIDSTATE_CACHE.with(|cell| {
286 cell.borrow_mut().put(key, hash);
287 });
288 }
289}
290
291#[cfg(feature = "production")]
293#[inline]
294fn script_code_id(code: &[u8]) -> [u8; 32] {
295 use sha2::{Digest, Sha256};
296 Sha256::digest(code).into()
297}
298
299#[inline]
303fn legacy_sighash_tx_id(tx: &Transaction) -> [u8; 32] {
304 use sha2::{Digest, Sha256};
305 let mut hasher = Sha256::new();
306 hasher.update(tx.version.to_le_bytes());
307 hasher.update(tx.lock_time.to_le_bytes());
308 hasher.update((tx.inputs.len() as u64).to_le_bytes());
309 for input in &tx.inputs {
310 hasher.update(input.prevout.hash);
311 hasher.update(input.prevout.index.to_le_bytes());
312 hasher.update(input.sequence.to_le_bytes());
313 }
314 hasher.update((tx.outputs.len() as u64).to_le_bytes());
315 for output in &tx.outputs {
316 hasher.update(output.value.to_le_bytes());
317 hasher.update((output.script_pubkey.len() as u64).to_le_bytes());
318 hasher.update(output.script_pubkey.as_slice());
319 }
320 hasher.finalize().into()
321}
322
323#[cfg(feature = "production")]
328thread_local! {
329 static SIGHASH_CACHE: RefCell<LruCache<[u8; 32], [u8; 32]>> = RefCell::new({
330 let cap = std::env::var("BLVM_SIGHASH_CACHE_SIZE")
331 .ok()
332 .and_then(|s| s.parse().ok())
333 .unwrap_or(262_144)
334 .clamp(65_536, 2_097_152);
335 LruCache::new(std::num::NonZeroUsize::new(cap).unwrap())
336 });
337}
338
339#[cfg(feature = "production")]
341thread_local! {
342 static SIGHASH_PREIMAGE_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(4096));
343}
344
345#[cfg(feature = "production")]
348thread_local! {
349 static BIP143_SERIALIZE_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(131_072)); }
351
352#[cfg(feature = "production")]
354thread_local! {
355 static BIP143_PREIMAGE_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(1024));
356}
357
358#[cfg(feature = "production")]
360thread_local! {
361 static BIP143_SINGLE_OUTPUT_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(256));
362}
363
364#[cfg(feature = "production")]
367thread_local! {
368 static LEGACY_BATCH_PREIMAGES: std::cell::RefCell<Vec<Vec<u8>>> =
369 const { std::cell::RefCell::new(Vec::new()) };
370}
371
372#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
381pub struct SighashType(pub u8);
382
383impl SighashType {
384 pub const ALL_LEGACY: Self = SighashType(0x00);
386 pub const ALL: Self = SighashType(0x01);
387 pub const NONE: Self = SighashType(0x02);
388 pub const SINGLE: Self = SighashType(0x03);
389 pub const ALL_ANYONECANPAY: Self = SighashType(0x81);
390 pub const NONE_ANYONECANPAY: Self = SighashType(0x82);
391 pub const SINGLE_ANYONECANPAY: Self = SighashType(0x83);
392
393 pub fn from_byte(byte: u8) -> Self {
396 SighashType(byte)
397 }
398
399 pub fn as_u32(&self) -> u32 {
401 self.0 as u32
402 }
403
404 pub fn base_type(&self) -> u8 {
406 self.0 & 0x1f
407 }
408
409 pub fn is_anyonecanpay(&self) -> bool {
411 self.0 & 0x80 != 0
412 }
413
414 pub fn is_all(&self) -> bool {
416 let base = self.base_type();
417 base != 0x02 && base != 0x03
418 }
419
420 pub fn is_none(&self) -> bool {
422 self.base_type() == 0x02
423 }
424
425 pub fn is_single(&self) -> bool {
427 self.base_type() == 0x03
428 }
429}
430
431#[cfg(feature = "production")]
436fn sighash_with_cache(preimage: &[u8]) -> Hash {
437 let hasher = OptimizedSha256::new();
438 let first_hash: [u8; 32] = hasher.hash(preimage);
439 SIGHASH_CACHE.with(|cell| {
440 let mut cache = cell.borrow_mut();
441 if let Some(cached) = cache.get(&first_hash) {
442 return *cached;
443 }
444 let second_hash = hasher.hash(&first_hash);
445 let mut result = [0u8; 32];
446 result.copy_from_slice(&second_hash);
447 cache.put(first_hash, result);
448 result
449 })
450}
451
452#[cfg(feature = "production")]
459#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
460#[inline]
461pub fn compute_legacy_sighash_nocache(
462 tx: &Transaction,
463 input_index: usize,
464 script_code: &[u8],
465 sighash_byte: u8,
466) -> [u8; 32] {
467 use sha2::{Digest, Sha256};
468
469 let sighash_u32 = sighash_byte as u32;
470 let base_type = sighash_u32 & 0x1f;
471 let anyone_can_pay = (sighash_u32 & 0x80) != 0;
472 let hash_none = base_type == 0x02;
473 let hash_single = base_type == 0x03;
474
475 if hash_single && input_index >= tx.outputs.len() {
476 let mut result = [0u8; 32];
477 result[0] = 1;
478 return result;
479 }
480
481 let mut h = Sha256::new();
482 h.update((tx.version as u32).to_le_bytes());
483
484 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
485 update_varint(&mut h, n_inputs as u64);
486
487 for i in 0..n_inputs {
488 let actual_i = if anyone_can_pay { input_index } else { i };
489 let input = &tx.inputs[actual_i];
490 h.update(input.prevout.hash);
491 h.update(input.prevout.index.to_le_bytes());
492
493 if actual_i == input_index {
494 update_varint(&mut h, script_code.len() as u64);
495 h.update(script_code);
496 } else {
497 h.update([0u8]);
498 }
499
500 if actual_i != input_index && (hash_single || hash_none) {
501 h.update(0u32.to_le_bytes());
502 } else {
503 h.update((input.sequence as u32).to_le_bytes());
504 }
505 }
506
507 let n_outputs = if hash_none {
508 0
509 } else if hash_single {
510 input_index + 1
511 } else {
512 tx.outputs.len()
513 };
514 update_varint(&mut h, n_outputs as u64);
515
516 for i in 0..n_outputs {
517 if hash_single && i != input_index {
518 h.update((-1i64).to_le_bytes());
519 h.update([0u8]);
520 } else {
521 let output = &tx.outputs[i];
522 h.update(output.value.to_le_bytes());
523 update_varint(&mut h, output.script_pubkey.len() as u64);
524 h.update(output.script_pubkey.as_slice());
525 }
526 }
527
528 h.update((tx.lock_time as u32).to_le_bytes());
529 h.update(sighash_u32.to_le_bytes());
530
531 let first_hash = h.finalize();
532 let second_hash = Sha256::digest(first_hash);
533 let mut result = [0u8; 32];
534 result.copy_from_slice(&second_hash);
535 result
536}
537
538#[inline]
540fn update_varint(hasher: &mut sha2::Sha256, value: u64) {
541 use sha2::Digest;
542 if value < 0xfd {
543 hasher.update([value as u8]);
544 } else if value <= 0xffff {
545 hasher.update([0xfd]);
546 hasher.update((value as u16).to_le_bytes());
547 } else if value <= 0xffffffff {
548 hasher.update([0xfe]);
549 hasher.update((value as u32).to_le_bytes());
550 } else {
551 hasher.update([0xff]);
552 hasher.update(value.to_le_bytes());
553 }
554}
555
556#[cfg(feature = "production")]
559#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
560#[inline]
561pub fn compute_legacy_sighash_buffered(
562 tx: &Transaction,
563 input_index: usize,
564 script_code: &[u8],
565 sighash_byte: u8,
566) -> [u8; 32] {
567 use sha2::{Digest, Sha256};
568
569 let sighash_u32 = sighash_byte as u32;
570 let base_type = sighash_u32 & 0x1f;
571 let anyone_can_pay = (sighash_u32 & 0x80) != 0;
572 let hash_none = base_type == 0x02;
573 let hash_single = base_type == 0x03;
574
575 if hash_single && input_index >= tx.outputs.len() {
576 let mut result = [0u8; 32];
577 result[0] = 1;
578 return result;
579 }
580
581 thread_local! {
582 static BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(4096));
583 }
584
585 BUF.with(|cell| {
586 let mut buf = cell.borrow_mut();
587 buf.clear();
588
589 buf.extend_from_slice(&(tx.version as u32).to_le_bytes());
590
591 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
592 write_varint_to_vec(&mut buf, n_inputs as u64);
593
594 for i in 0..n_inputs {
595 let actual_i = if anyone_can_pay { input_index } else { i };
596 let input = &tx.inputs[actual_i];
597 buf.extend_from_slice(&input.prevout.hash);
598 buf.extend_from_slice(&input.prevout.index.to_le_bytes());
599
600 if actual_i == input_index {
601 write_varint_to_vec(&mut buf, script_code.len() as u64);
602 buf.extend_from_slice(script_code);
603 } else {
604 buf.push(0u8);
605 }
606
607 if actual_i != input_index && (hash_single || hash_none) {
608 buf.extend_from_slice(&0u32.to_le_bytes());
609 } else {
610 buf.extend_from_slice(&(input.sequence as u32).to_le_bytes());
611 }
612 }
613
614 let n_outputs = if hash_none {
615 0
616 } else if hash_single {
617 input_index + 1
618 } else {
619 tx.outputs.len()
620 };
621 write_varint_to_vec(&mut buf, n_outputs as u64);
622
623 for i in 0..n_outputs {
624 if hash_single && i != input_index {
625 buf.extend_from_slice(&(-1i64).to_le_bytes());
626 buf.push(0u8);
627 } else {
628 let output = &tx.outputs[i];
629 buf.extend_from_slice(&output.value.to_le_bytes());
630 write_varint_to_vec(&mut buf, output.script_pubkey.len() as u64);
631 buf.extend_from_slice(&output.script_pubkey);
632 }
633 }
634
635 buf.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
636 buf.extend_from_slice(&sighash_u32.to_le_bytes());
637
638 let first_hash = Sha256::digest(buf.as_slice());
639 let second_hash = Sha256::digest(first_hash);
640 let mut result = [0u8; 32];
641 result.copy_from_slice(&second_hash);
642 result
643 })
644}
645
646#[cfg(feature = "production")]
653#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
654pub fn compute_sighashes_batch(
655 tx: &Transaction,
656 script_codes: &[&[u8]],
657 sighash_bytes: &[u8],
658) -> Vec<[u8; 32]> {
659 use sha2::{Digest, Sha256};
660 let n = tx.inputs.len();
661 debug_assert_eq!(script_codes.len(), n);
662 debug_assert_eq!(sighash_bytes.len(), n);
663
664 let mut results = Vec::with_capacity(n);
665
666 let all_sighash_all = sighash_bytes.iter().all(|&b| {
668 let base = (b as u32) & 0x1f;
669 let acp = (b as u32) & 0x80;
670 acp == 0 && (base == 0x01 || base == 0x00)
671 });
672
673 if !all_sighash_all || n <= 1 {
674 for i in 0..n {
675 results.push(compute_legacy_sighash_nocache(
676 tx,
677 i,
678 script_codes[i],
679 sighash_bytes[i],
680 ));
681 }
682 return results;
683 }
684
685 let mut outputs_buf: Vec<u8> = Vec::with_capacity(tx.outputs.len() * 40 + 16);
687 write_varint_to_vec(&mut outputs_buf, tx.outputs.len() as u64);
688 for output in tx.outputs.iter() {
689 outputs_buf.extend_from_slice(&output.value.to_le_bytes());
690 write_varint_to_vec(&mut outputs_buf, output.script_pubkey.len() as u64);
691 outputs_buf.extend_from_slice(&output.script_pubkey);
692 }
693 outputs_buf.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
694
695 let mut running = Sha256::new();
698 running.update((tx.version as u32).to_le_bytes());
699 update_varint(&mut running, n as u64);
700
701 for i in 0..n {
702 let mut h = running.clone();
703
704 h.update(tx.inputs[i].prevout.hash);
706 h.update(tx.inputs[i].prevout.index.to_le_bytes());
707 update_varint(&mut h, script_codes[i].len() as u64);
708 h.update(script_codes[i]);
709 h.update((tx.inputs[i].sequence as u32).to_le_bytes());
710
711 for j in (i + 1)..n {
713 h.update(tx.inputs[j].prevout.hash);
714 h.update(tx.inputs[j].prevout.index.to_le_bytes());
715 h.update([0u8]);
716 h.update((tx.inputs[j].sequence as u32).to_le_bytes());
717 }
718
719 h.update(outputs_buf.as_slice());
721 h.update((sighash_bytes[i] as u32).to_le_bytes());
722
723 let first_hash = h.finalize();
724 let second_hash = Sha256::digest(first_hash);
725 let mut result = [0u8; 32];
726 result.copy_from_slice(&second_hash);
727 results.push(result);
728
729 running.update(tx.inputs[i].prevout.hash);
731 running.update(tx.inputs[i].prevout.index.to_le_bytes());
732 running.update([0u8]);
733 running.update((tx.inputs[i].sequence as u32).to_le_bytes());
734 }
735
736 results
737}
738
739#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
757pub fn calculate_transaction_sighash(
758 tx: &Transaction,
759 input_index: usize,
760 prevouts: &[TransactionOutput],
761 sighash_type: SighashType,
762) -> Result<Hash> {
763 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
765 let prevout_script_pubkeys: Vec<&[u8]> =
766 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
767 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
769 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
770 prevout_values.len(),
771 tx.inputs.len(),
772 ));
773 }
774 calculate_transaction_sighash_with_script_code(
775 tx,
776 input_index,
777 &prevout_values,
778 &prevout_script_pubkeys,
779 sighash_type,
780 None,
781 #[cfg(feature = "production")]
782 None,
783 )
784}
785
786#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
791pub fn calculate_transaction_sighash_single_input(
792 tx: &Transaction,
793 input_index: usize,
794 script_for_signing: &[u8],
795 prevout_value: i64,
796 sighash_type: SighashType,
797 #[cfg(feature = "production")] sighash_cache: Option<&SighashMidstateCache>,
798) -> Result<Hash> {
799 if input_index >= tx.inputs.len() {
800 return Err(crate::error::ConsensusError::InvalidInputIndex(input_index));
801 }
802 #[cfg(feature = "production")]
806 return calculate_transaction_sighash_with_script_code(
807 tx,
808 input_index,
809 &[],
810 &[],
811 sighash_type,
812 Some(script_for_signing),
813 sighash_cache,
814 );
815 #[cfg(not(feature = "production"))]
816 {
817 let mut prevout_values = vec![0i64; tx.inputs.len()];
818 prevout_values[input_index] = prevout_value;
819 let prevout_script_pubkeys: Vec<&[u8]> = (0..tx.inputs.len())
820 .map(|i| {
821 if i == input_index {
822 script_for_signing
823 } else {
824 &[]
825 }
826 })
827 .collect();
828 calculate_transaction_sighash_with_script_code(
829 tx,
830 input_index,
831 &prevout_values,
832 &prevout_script_pubkeys,
833 sighash_type,
834 Some(script_for_signing),
835 )
836 }
837}
838
839#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
845pub fn calculate_transaction_sighash_with_script_code(
846 tx: &Transaction,
847 input_index: usize,
848 prevout_values: &[i64],
849 prevout_script_pubkeys: &[&[u8]],
850 sighash_type: SighashType,
851 script_code: Option<&[u8]>,
852 #[cfg(feature = "production")] sighash_cache: Option<&SighashMidstateCache>,
853) -> Result<Hash> {
854 #[cfg(all(feature = "production", feature = "profile"))]
855 let _t0 = std::time::Instant::now();
856
857 if input_index >= tx.inputs.len() {
859 return Err(crate::error::ConsensusError::InvalidInputIndex(input_index));
860 }
861
862 if script_code.is_none()
866 && (prevout_values.len() != tx.inputs.len()
867 || prevout_script_pubkeys.len() != tx.inputs.len())
868 {
869 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
870 prevout_values.len(),
871 tx.inputs.len(),
872 ));
873 }
874
875 let sighash_byte = sighash_type.as_u32();
876 let base_type = sighash_byte & 0x1f;
877 let anyone_can_pay = (sighash_byte & 0x80) != 0;
878 let hash_none = base_type == 0x02; let hash_single = base_type == 0x03; if hash_single && input_index >= tx.outputs.len() {
884 let mut result = [0u8; 32];
885 result[0] = 1; return Ok(result);
887 }
888
889 #[cfg(feature = "production")]
892 let tx_id = legacy_sighash_tx_id(tx);
893 #[cfg(feature = "production")]
894 {
895 let prevout = &tx.inputs[input_index].prevout;
896 let code = script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]);
897 let sighash_byte_u8 = sighash_byte as u8;
898 let lookup_key = SighashCacheKey {
899 prevout: *prevout,
900 code_id: script_code_id(code),
901 sighash_byte: sighash_byte_u8,
902 tx_id,
903 };
904 let cached = if let Some(cache) = sighash_cache {
905 cache
906 .lock()
907 .ok()
908 .and_then(|guard| guard.get(&lookup_key).copied())
909 } else {
910 SIGHASH_MIDSTATE_CACHE.with(|cell| cell.borrow_mut().get(&lookup_key).copied())
911 };
912 if let Some(cached) = cached {
913 return Ok(cached);
914 }
915 }
916
917 #[cfg(feature = "production")]
919 if tx.inputs.len() == 1 && input_index == 0 && !anyone_can_pay && !hash_none && !hash_single {
920 let base_type = sighash_byte & 0x1f;
921 if base_type == 0x01 || base_type == 0x00 {
922 let n_out = tx.outputs.len();
923 if n_out == 1 {
924 if let Ok(h) = build_preimage_1in1out_sighash_all(
925 tx,
926 prevout_values,
927 prevout_script_pubkeys,
928 script_code,
929 sighash_byte,
930 ) {
931 #[cfg(all(feature = "production", feature = "profile"))]
932 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
933 #[cfg(feature = "production")]
934 insert_midstate_cache(
935 sighash_cache,
936 tx.inputs[0].prevout,
937 script_code.unwrap_or_else(|| prevout_script_pubkeys[0]),
938 sighash_byte as u8,
939 tx_id,
940 h,
941 );
942 return Ok(h);
943 }
944 } else if (2..=16).contains(&n_out) {
945 if let Ok(h) = build_preimage_1in_nout_sighash_all(
946 tx,
947 prevout_script_pubkeys,
948 script_code,
949 sighash_byte,
950 ) {
951 #[cfg(all(feature = "production", feature = "profile"))]
952 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
953 #[cfg(feature = "production")]
954 insert_midstate_cache(
955 sighash_cache,
956 tx.inputs[0].prevout,
957 script_code.unwrap_or_else(|| prevout_script_pubkeys[0]),
958 sighash_byte as u8,
959 tx_id,
960 h,
961 );
962 return Ok(h);
963 }
964 }
965 }
966 }
967
968 #[cfg(feature = "production")]
970 if tx.inputs.len() == 2 && input_index < 2 && !anyone_can_pay && !hash_none && !hash_single {
971 let base_type = sighash_byte & 0x1f;
972 if base_type == 0x01 || base_type == 0x00 {
973 let n_out = tx.outputs.len();
974 if n_out == 1 {
975 if let Ok(h) = build_preimage_2in1out_sighash_all(
976 tx,
977 input_index,
978 prevout_values,
979 prevout_script_pubkeys,
980 script_code,
981 sighash_byte,
982 ) {
983 #[cfg(all(feature = "production", feature = "profile"))]
984 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
985 #[cfg(feature = "production")]
986 insert_midstate_cache(
987 sighash_cache,
988 tx.inputs[input_index].prevout,
989 script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]),
990 sighash_byte as u8,
991 tx_id,
992 h,
993 );
994 return Ok(h);
995 }
996 } else if n_out == 2 {
997 if let Ok(h) = build_preimage_2in2out_sighash_all(
998 tx,
999 input_index,
1000 prevout_script_pubkeys,
1001 script_code,
1002 sighash_byte,
1003 ) {
1004 #[cfg(all(feature = "production", feature = "profile"))]
1005 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
1006 #[cfg(feature = "production")]
1007 insert_midstate_cache(
1008 sighash_cache,
1009 tx.inputs[input_index].prevout,
1010 script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]),
1011 sighash_byte as u8,
1012 tx_id,
1013 h,
1014 );
1015 return Ok(h);
1016 }
1017 }
1018 }
1019 }
1020
1021 let estimated_size = 4 + 2 + (tx.inputs.len() * 50) + 2 + (tx.outputs.len() * 30) + 4 + 4;
1023 let capacity = estimated_size.min(4096);
1024
1025 #[cfg(feature = "production")]
1026 let (result, preimage_vec) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
1027 let mut preimage = buf_cell.borrow_mut();
1028 preimage.clear();
1029 if preimage.capacity() < capacity {
1030 preimage.reserve(capacity);
1031 }
1032 build_preimage_and_hash(
1033 tx,
1034 input_index,
1035 prevout_values,
1036 prevout_script_pubkeys,
1037 script_code,
1038 sighash_byte,
1039 anyone_can_pay,
1040 hash_none,
1041 hash_single,
1042 &mut preimage,
1043 )
1044 });
1045
1046 #[cfg(not(feature = "production"))]
1047 let (result, preimage_vec) = {
1048 let mut preimage = Vec::with_capacity(capacity);
1049 build_preimage_and_hash(
1050 tx,
1051 input_index,
1052 prevout_values,
1053 prevout_script_pubkeys,
1054 script_code,
1055 sighash_byte,
1056 anyone_can_pay,
1057 hash_none,
1058 hash_single,
1059 &mut preimage,
1060 )
1061 };
1062
1063 #[cfg(all(feature = "production", feature = "profile"))]
1064 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
1065
1066 #[cfg(feature = "production")]
1067 if let Ok(ref h) = result {
1068 insert_midstate_cache(
1069 sighash_cache,
1070 tx.inputs[input_index].prevout,
1071 script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]),
1072 sighash_byte as u8,
1073 tx_id,
1074 *h,
1075 );
1076 }
1077 result
1078}
1079
1080#[cfg(feature = "production")]
1082#[inline]
1083fn build_preimage_1in1out_sighash_all(
1084 tx: &crate::types::Transaction,
1085 prevout_values: &[i64],
1086 prevout_script_pubkeys: &[&[u8]],
1087 script_code: Option<&[u8]>,
1088 sighash_byte: u32,
1089) -> Result<Hash> {
1090 let input = &tx.inputs[0];
1091 let output = &tx.outputs[0];
1092 let code = script_code.unwrap_or_else(|| prevout_script_pubkeys[0]);
1093
1094 let capacity = 4 + 2 + 36 + 2 + code.len() + 4 + 2 + 8 + 2 + output.script_pubkey.len() + 4 + 4;
1095 let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
1096 let mut preimage = buf_cell.borrow_mut();
1097 preimage.clear();
1098 if preimage.capacity() < capacity {
1099 preimage.reserve(capacity);
1100 }
1101 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1102 preimage.push(1); preimage.extend_from_slice(&input.prevout.hash);
1104 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1105 write_script_code_for_sighash(&mut preimage, code);
1106 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1107 preimage.push(1); preimage.extend_from_slice(&output.value.to_le_bytes());
1109 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
1110 preimage.extend_from_slice(&output.script_pubkey);
1111 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1112 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1113 let r = sighash_with_cache(&preimage);
1114 (Ok(r), ())
1115 });
1116 result
1117}
1118
1119#[cfg(feature = "production")]
1121#[inline]
1122fn build_preimage_1in_nout_sighash_all(
1123 tx: &crate::types::Transaction,
1124 prevout_script_pubkeys: &[&[u8]],
1125 script_code: Option<&[u8]>,
1126 sighash_byte: u32,
1127) -> Result<Hash> {
1128 let input = &tx.inputs[0];
1129 let code = script_code.unwrap_or_else(|| prevout_script_pubkeys[0]);
1130 let mut capacity = 4 + 2 + 36 + 2 + code.len() + 4 + 2; for out in &tx.outputs {
1132 capacity += 8 + 2 + out.script_pubkey.len();
1133 }
1134 capacity += 4 + 4; let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
1137 let mut preimage = buf_cell.borrow_mut();
1138 preimage.clear();
1139 if preimage.capacity() < capacity {
1140 preimage.reserve(capacity);
1141 }
1142 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1143 preimage.push(1); preimage.extend_from_slice(&input.prevout.hash);
1145 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1146 write_script_code_for_sighash(&mut preimage, code);
1147 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1148 write_varint_to_vec(&mut preimage, tx.outputs.len() as u64);
1149 for output in &tx.outputs {
1150 preimage.extend_from_slice(&output.value.to_le_bytes());
1151 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
1152 preimage.extend_from_slice(&output.script_pubkey);
1153 }
1154 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1155 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1156 let r = sighash_with_cache(&preimage);
1157 (Ok(r), ())
1158 });
1159 result
1160}
1161
1162#[cfg(feature = "production")]
1165#[inline]
1166fn build_preimage_2in1out_sighash_all(
1167 tx: &crate::types::Transaction,
1168 input_index: usize,
1169 _prevout_values: &[i64],
1170 prevout_script_pubkeys: &[&[u8]],
1171 script_code: Option<&[u8]>,
1172 sighash_byte: u32,
1173) -> Result<Hash> {
1174 let output = &tx.outputs[0];
1175 let code_len = script_code
1176 .map(|s| s.len())
1177 .unwrap_or_else(|| prevout_script_pubkeys[input_index].len());
1178 let capacity =
1179 4 + 2 + 36 + 2 + code_len + 4 + 36 + 2 + 4 + 8 + 2 + output.script_pubkey.len() + 4 + 4;
1180
1181 let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
1182 let mut preimage = buf_cell.borrow_mut();
1183 preimage.clear();
1184 if preimage.capacity() < capacity {
1185 preimage.reserve(capacity);
1186 }
1187 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1188 preimage.push(2);
1189 for (i, inp) in tx.inputs.iter().enumerate().take(2) {
1190 preimage.extend_from_slice(&inp.prevout.hash);
1191 preimage.extend_from_slice(&inp.prevout.index.to_le_bytes());
1192 if i == input_index {
1193 let c = script_code.unwrap_or_else(|| prevout_script_pubkeys[i]);
1194 write_script_code_for_sighash(&mut preimage, c);
1195 } else {
1196 preimage.push(0);
1197 }
1198 preimage.extend_from_slice(&(inp.sequence as u32).to_le_bytes());
1199 }
1200 preimage.push(1);
1201 preimage.extend_from_slice(&output.value.to_le_bytes());
1202 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
1203 preimage.extend_from_slice(&output.script_pubkey);
1204 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1205 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1206 let r = sighash_with_cache(&preimage);
1207 (Ok(r), ())
1208 });
1209 result
1210}
1211
1212#[cfg(feature = "production")]
1215#[inline]
1216fn build_preimage_2in2out_sighash_all(
1217 tx: &crate::types::Transaction,
1218 input_index: usize,
1219 prevout_script_pubkeys: &[&[u8]],
1220 script_code: Option<&[u8]>,
1221 sighash_byte: u32,
1222) -> Result<Hash> {
1223 let code_len = script_code
1224 .map(|s| s.len())
1225 .unwrap_or_else(|| prevout_script_pubkeys[input_index].len());
1226 let mut capacity = 4 + 2 + 36 + 2 + code_len + 4 + 36 + 2 + 4;
1227 for out in &tx.outputs {
1228 capacity += 8 + 2 + out.script_pubkey.len();
1229 }
1230 capacity += 4 + 4;
1231
1232 let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
1233 let mut preimage = buf_cell.borrow_mut();
1234 preimage.clear();
1235 if preimage.capacity() < capacity {
1236 preimage.reserve(capacity);
1237 }
1238 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1239 preimage.push(2);
1240 for (i, inp) in tx.inputs.iter().enumerate().take(2) {
1241 preimage.extend_from_slice(&inp.prevout.hash);
1242 preimage.extend_from_slice(&inp.prevout.index.to_le_bytes());
1243 if i == input_index {
1244 let c = script_code.unwrap_or_else(|| prevout_script_pubkeys[i]);
1245 write_script_code_for_sighash(&mut preimage, c);
1246 } else {
1247 preimage.push(0);
1248 }
1249 preimage.extend_from_slice(&(inp.sequence as u32).to_le_bytes());
1250 }
1251 write_varint_to_vec(&mut preimage, 2);
1252 for output in &tx.outputs {
1253 preimage.extend_from_slice(&output.value.to_le_bytes());
1254 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
1255 preimage.extend_from_slice(&output.script_pubkey);
1256 }
1257 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1258 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1259 let r = sighash_with_cache(&preimage);
1260 (Ok(r), ())
1261 });
1262 result
1263}
1264
1265#[inline]
1266fn blank_input_prefixes(tx: &crate::types::Transaction) -> Vec<sha2::Sha256> {
1268 use sha2::{Digest, Sha256};
1269 let n = tx.inputs.len();
1270 let mut running = Sha256::new();
1271 let mut tmp = Vec::new();
1272 tmp.extend_from_slice(&(tx.version as u32).to_le_bytes());
1273 write_varint_to_vec(&mut tmp, n as u64);
1274 running.update(&tmp);
1275 let mut boundaries = Vec::with_capacity(n);
1276 for input in &tx.inputs {
1277 boundaries.push(running.clone());
1278 tmp.clear();
1279 tmp.extend_from_slice(&input.prevout.hash);
1280 tmp.extend_from_slice(&input.prevout.index.to_le_bytes());
1281 tmp.push(0);
1282 tmp.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1283 running.update(&tmp);
1284 }
1285 boundaries
1286}
1287
1288fn legacy_all_from_prefix_midstate(
1289 tx: &crate::types::Transaction,
1290 input_index: usize,
1291 prevout_script_pubkeys: &[&[u8]],
1292 script_code: Option<&[u8]>,
1293 sighash_byte: u32,
1294) -> Hash {
1295 use sha2::{Digest, Sha256};
1296 use std::cell::RefCell;
1297 thread_local! {
1298 static PREFIX: RefCell<Option<([u8; 32], Vec<Sha256>)>> = const { RefCell::new(None) };
1299 }
1300 let tx_id = legacy_sighash_tx_id(tx);
1301 let mut hasher = PREFIX.with(|cell| {
1302 let mut slot = cell.borrow_mut();
1303 let stale = match slot.as_ref() {
1304 Some((id, bounds)) => *id != tx_id || bounds.len() != tx.inputs.len(),
1305 None => true,
1306 };
1307 if stale {
1308 *slot = Some((tx_id, blank_input_prefixes(tx)));
1309 }
1310 slot.as_ref().unwrap().1[input_index].clone()
1311 });
1312 let mut tmp = Vec::new();
1313 let input = &tx.inputs[input_index];
1314 tmp.extend_from_slice(&input.prevout.hash);
1315 tmp.extend_from_slice(&input.prevout.index.to_le_bytes());
1316 let code = match script_code {
1317 Some(code) => code,
1318 None => prevout_script_pubkeys[input_index],
1319 };
1320 write_script_code_for_sighash(&mut tmp, code);
1321 tmp.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1322 for later in &tx.inputs[input_index + 1..] {
1323 tmp.extend_from_slice(&later.prevout.hash);
1324 tmp.extend_from_slice(&later.prevout.index.to_le_bytes());
1325 tmp.push(0);
1326 tmp.extend_from_slice(&(later.sequence as u32).to_le_bytes());
1327 }
1328 write_varint_to_vec(&mut tmp, tx.outputs.len() as u64);
1329 for output in &tx.outputs {
1330 tmp.extend_from_slice(&output.value.to_le_bytes());
1331 write_varint_to_vec(&mut tmp, output.script_pubkey.len() as u64);
1332 tmp.extend_from_slice(&output.script_pubkey);
1333 }
1334 tmp.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1335 tmp.extend_from_slice(&sighash_byte.to_le_bytes());
1336 hasher.update(&tmp);
1337 let first = hasher.finalize();
1338 let second = Sha256::digest(first);
1339 let mut out = [0u8; 32];
1340 out.copy_from_slice(&second);
1341 out
1342}
1343
1344fn build_preimage_and_hash(
1345 tx: &crate::types::Transaction,
1346 input_index: usize,
1347 prevout_values: &[i64],
1348 prevout_script_pubkeys: &[&[u8]],
1349 script_code: Option<&[u8]>,
1350 sighash_byte: u32,
1351 anyone_can_pay: bool,
1352 hash_none: bool,
1353 hash_single: bool,
1354 preimage: &mut Vec<u8>,
1355) -> (Result<Hash>, ()) {
1356 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1358
1359 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
1361 write_varint_to_vec(preimage, n_inputs as u64);
1362
1363 for i in 0..n_inputs {
1365 let actual_i = if anyone_can_pay { input_index } else { i };
1367 let input = &tx.inputs[actual_i];
1368
1369 preimage.extend_from_slice(&input.prevout.hash);
1371 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1372
1373 if actual_i == input_index {
1375 let code = match script_code {
1376 Some(s) => s,
1377 None => prevout_script_pubkeys[actual_i],
1378 };
1379 write_script_code_for_sighash(preimage, code);
1380 } else {
1381 preimage.push(0); }
1383
1384 if actual_i != input_index && (hash_single || hash_none) {
1386 preimage.extend_from_slice(&0u32.to_le_bytes());
1387 } else {
1388 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1389 }
1390 }
1391
1392 let n_outputs = if hash_none {
1394 0
1395 } else if hash_single {
1396 input_index + 1
1397 } else {
1398 tx.outputs.len()
1399 };
1400 write_varint_to_vec(preimage, n_outputs as u64);
1401
1402 for i in 0..n_outputs {
1404 if hash_single && i != input_index {
1405 preimage.extend_from_slice(&(-1i64).to_le_bytes()); preimage.push(0); } else {
1409 let output = &tx.outputs[i];
1410 preimage.extend_from_slice(&output.value.to_le_bytes());
1411 write_varint_to_vec(preimage, output.script_pubkey.len() as u64);
1412 preimage.extend_from_slice(&output.script_pubkey);
1413 }
1414 }
1415
1416 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1418
1419 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1421
1422 #[cfg(not(feature = "production"))]
1424 let mut result = {
1425 let hasher = OptimizedSha256::new();
1426 let first_hash = hasher.hash(&preimage);
1427 let second_hash = hasher.hash(&first_hash);
1428 let mut r = [0u8; 32];
1429 r.copy_from_slice(&second_hash);
1430 r
1431 };
1432 #[cfg(feature = "production")]
1433 let mut result = sighash_with_cache(preimage);
1434 if !anyone_can_pay && !hash_none && !hash_single && !tx.inputs.is_empty() {
1435 let prefixed = legacy_all_from_prefix_midstate(
1436 tx,
1437 input_index,
1438 prevout_script_pubkeys,
1439 script_code,
1440 sighash_byte,
1441 );
1442 #[cfg(test)]
1443 assert_eq!(
1444 prefixed, result,
1445 "prefix midstate diverged from the preimage hash"
1446 );
1447 result = prefixed;
1448 }
1449 (Ok(result), ())
1450}
1451
1452pub fn legacy_sighash_for_vector(
1454 tx: &Transaction,
1455 input_index: usize,
1456 script_code: &[u8],
1457 hash_type: i32,
1458) -> Result<Hash> {
1459 let hash_type = hash_type as u32;
1460 let base = hash_type & 0x1f;
1461 let values = vec![0i64; tx.inputs.len()];
1462 let empty: &[u8] = &[];
1463 let scripts = vec![empty; tx.inputs.len()];
1464 let mut preimage = Vec::new();
1465 let (result, _) = build_preimage_and_hash(
1466 tx,
1467 input_index,
1468 &values,
1469 &scripts,
1470 Some(script_code),
1471 hash_type,
1472 (hash_type & 0x80) != 0,
1473 base == 0x02,
1474 base == 0x03,
1475 &mut preimage,
1476 );
1477 result
1478}
1479
1480#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
1494pub fn batch_compute_sighashes(
1495 tx: &Transaction,
1496 prevouts: &[TransactionOutput],
1497 sighash_type: SighashType,
1498) -> Result<Vec<Hash>> {
1499 if prevouts.len() != tx.inputs.len() {
1501 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
1502 prevouts.len(),
1503 tx.inputs.len(),
1504 ));
1505 }
1506
1507 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
1509 let prevout_script_pubkeys: Vec<&[u8]> =
1510 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
1511
1512 #[cfg(feature = "production")]
1513 {
1514 let sighash_byte = sighash_type.as_u32() as u8;
1517 let specs: Vec<(usize, u8, &[u8])> = (0..tx.inputs.len())
1518 .map(|i| (i, sighash_byte, prevout_script_pubkeys[i]))
1519 .collect();
1520 let hashes =
1521 batch_compute_legacy_sighashes(tx, &prevout_values, &prevout_script_pubkeys, &specs)?;
1522 Ok(hashes)
1523 }
1524
1525 #[cfg(not(feature = "production"))]
1526 {
1527 let mut results = Vec::with_capacity(tx.inputs.len());
1529 for i in 0..tx.inputs.len() {
1530 results.push(calculate_transaction_sighash_with_script_code(
1531 tx,
1532 i,
1533 &prevout_values,
1534 &prevout_script_pubkeys,
1535 sighash_type,
1536 None,
1537 )?);
1538 }
1539 Ok(results)
1540 }
1541}
1542
1543#[cfg(feature = "production")]
1545fn build_legacy_sighash_preimage_into(
1546 preimage: &mut Vec<u8>,
1547 tx: &Transaction,
1548 input_index: usize,
1549 prevout_values: &[i64],
1550 prevout_script_pubkeys: &[&[u8]],
1551 script_code: &[u8],
1552 sighash_byte: u32,
1553) {
1554 let anyone_can_pay = (sighash_byte & 0x80) != 0;
1555 let hash_none = (sighash_byte & 0x1f) == 0x02;
1556 let hash_single = (sighash_byte & 0x1f) == 0x03;
1557 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
1558 let n_outputs = if hash_none {
1559 0
1560 } else if hash_single {
1561 input_index + 1
1562 } else {
1563 tx.outputs.len()
1564 };
1565 preimage.clear();
1566 preimage.reserve(512);
1567 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1568 write_varint_to_vec(preimage, n_inputs as u64);
1569 for i in 0..n_inputs {
1570 let actual_i = if anyone_can_pay { input_index } else { i };
1571 let input = &tx.inputs[actual_i];
1572 preimage.extend_from_slice(&input.prevout.hash);
1573 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1574 if actual_i == input_index {
1575 write_script_code_for_sighash(preimage, script_code);
1576 } else {
1577 preimage.push(0);
1578 }
1579 if actual_i != input_index && (hash_single || hash_none) {
1580 preimage.extend_from_slice(&0u32.to_le_bytes());
1581 } else {
1582 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1583 }
1584 }
1585 write_varint_to_vec(preimage, n_outputs as u64);
1586 for i in 0..n_outputs {
1587 let use_missing_output =
1589 hash_single && (i != input_index || input_index >= tx.outputs.len());
1590 if use_missing_output {
1591 preimage.extend_from_slice(&(-1i64).to_le_bytes());
1592 preimage.push(0);
1593 } else {
1594 let output = &tx.outputs[i];
1595 preimage.extend_from_slice(&output.value.to_le_bytes());
1596 write_varint_to_vec(preimage, output.script_pubkey.len() as u64);
1597 preimage.extend_from_slice(&output.script_pubkey);
1598 }
1599 }
1600 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1601 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1602}
1603
1604#[cfg(feature = "production")]
1609#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "CalculateSighash"))]
1610pub fn batch_compute_legacy_sighashes(
1611 tx: &Transaction,
1612 prevout_values: &[i64],
1613 prevout_script_pubkeys: &[&[u8]],
1614 specs: &[(usize, u8, &[u8])],
1615) -> Result<Vec<[u8; 32]>> {
1616 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
1617 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
1618 prevout_values.len(),
1619 tx.inputs.len(),
1620 ));
1621 }
1622 const SIGHASH_SINGLE_INVALID: [u8; 32] = {
1624 let mut h = [0u8; 32];
1625 h[0] = 1;
1626 h
1627 };
1628
1629 LEGACY_BATCH_PREIMAGES.with(|cell| {
1630 let mut storage = cell.borrow_mut();
1631 storage.resize_with(specs.len(), || Vec::with_capacity(512));
1632 let mut fixed_indices: Vec<usize> = Vec::new();
1633 for (i, &(input_index, sighash_byte, script_code)) in specs.iter().enumerate() {
1634 let hash_single = (sighash_byte & 0x1f) == 0x03;
1635 if hash_single && input_index >= tx.outputs.len() {
1636 fixed_indices.push(i);
1637 continue;
1638 }
1639 build_legacy_sighash_preimage_into(
1640 &mut storage[i],
1641 tx,
1642 input_index,
1643 prevout_values,
1644 prevout_script_pubkeys,
1645 script_code,
1646 sighash_byte as u32,
1647 );
1648 }
1649 let preimage_refs: Vec<&[u8]> = storage
1651 .iter()
1652 .enumerate()
1653 .filter(|(i, _)| !fixed_indices.contains(i))
1654 .map(|(_, v)| v.as_slice())
1655 .collect();
1656 let batch_hashes =
1657 crate::optimizations::simd_vectorization::batch_double_sha256(&preimage_refs);
1658 let mut result = vec![[0u8; 32]; specs.len()];
1660 let mut batch_idx = 0;
1661 for (i, slot) in result.iter_mut().enumerate() {
1662 if fixed_indices.contains(&i) {
1663 *slot = SIGHASH_SINGLE_INVALID;
1664 } else {
1665 *slot = batch_hashes[batch_idx];
1666 batch_idx += 1;
1667 }
1668 }
1669 Ok(result)
1670 })
1671}
1672
1673#[cfg(all(feature = "production", feature = "benchmarking"))]
1676pub fn clear_sighash_templates() {
1677 SIGHASH_CACHE.with(|cell| {
1678 cell.borrow_mut().clear();
1679 });
1680}
1681
1682#[derive(Clone, Debug)]
1695pub struct Bip143PrecomputedHashes {
1696 pub hash_prevouts: [u8; 32],
1698 pub hash_sequence: [u8; 32],
1700 pub hash_outputs: [u8; 32],
1702}
1703
1704impl Bip143PrecomputedHashes {
1705 #[inline]
1709 pub fn compute(
1710 tx: &Transaction,
1711 _prevout_values: &[i64],
1712 _prevout_script_pubkeys: &[&[u8]],
1713 ) -> Self {
1714 #[cfg(feature = "production")]
1715 {
1716 let hash_prevouts = BIP143_SERIALIZE_BUF.with(|cell| {
1717 let mut data = cell.borrow_mut();
1718 data.clear();
1719 data.reserve(tx.inputs.len() * 36);
1720 for input in tx.inputs.iter() {
1721 data.extend_from_slice(&input.prevout.hash);
1722 data.extend_from_slice(&input.prevout.index.to_le_bytes());
1723 }
1724 double_sha256(&data)
1725 });
1726
1727 let hash_sequence = BIP143_SERIALIZE_BUF.with(|cell| {
1728 let mut data = cell.borrow_mut();
1729 data.clear();
1730 data.reserve(tx.inputs.len() * 4);
1731 for input in tx.inputs.iter() {
1732 data.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1733 }
1734 double_sha256(&data)
1735 });
1736
1737 let hash_outputs = BIP143_SERIALIZE_BUF.with(|cell| {
1738 let mut data = cell.borrow_mut();
1739 data.clear();
1740 let cap = tx
1741 .outputs
1742 .iter()
1743 .map(|o| 8 + 5 + o.script_pubkey.len())
1744 .sum::<usize>();
1745 data.reserve(cap);
1746 for output in tx.outputs.iter() {
1747 data.extend_from_slice(&output.value.to_le_bytes());
1748 write_varint_to_vec(&mut data, output.script_pubkey.len() as u64);
1749 data.extend_from_slice(&output.script_pubkey);
1750 }
1751 double_sha256(&data)
1752 });
1753
1754 Self {
1755 hash_prevouts,
1756 hash_sequence,
1757 hash_outputs,
1758 }
1759 }
1760
1761 #[cfg(not(feature = "production"))]
1762 {
1763 let hash_prevouts = {
1765 let mut data = Vec::with_capacity(tx.inputs.len() * 36);
1766 for input in tx.inputs.iter() {
1767 data.extend_from_slice(&input.prevout.hash);
1768 data.extend_from_slice(&input.prevout.index.to_le_bytes());
1769 }
1770 double_sha256(&data)
1771 };
1772
1773 let hash_sequence = {
1774 let mut data = Vec::with_capacity(tx.inputs.len() * 4);
1775 for input in tx.inputs.iter() {
1776 data.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1777 }
1778 double_sha256(&data)
1779 };
1780
1781 let hash_outputs = {
1782 let mut data = Vec::with_capacity(tx.outputs.len() * 34);
1783 for output in tx.outputs.iter() {
1784 data.extend_from_slice(&output.value.to_le_bytes());
1785 write_varint_to_vec(&mut data, output.script_pubkey.len() as u64);
1786 data.extend_from_slice(&output.script_pubkey);
1787 }
1788 double_sha256(&data)
1789 };
1790
1791 Self {
1792 hash_prevouts,
1793 hash_sequence,
1794 hash_outputs,
1795 }
1796 }
1797 }
1798}
1799
1800#[inline(always)]
1802fn double_sha256(data: &[u8]) -> [u8; 32] {
1803 let hasher = OptimizedSha256::new();
1804 hasher.hash256(data)
1805}
1806
1807#[cfg_attr(
1824 feature = "spec-lock",
1825 spec_locked("11.1.9", "ComputeWitnessSignatureHash")
1826)]
1827pub fn calculate_bip143_sighash(
1828 tx: &Transaction,
1829 input_index: usize,
1830 script_code: &[u8],
1831 amount: i64,
1832 sighash_type: u8,
1833 precomputed: Option<&Bip143PrecomputedHashes>,
1834) -> Result<Hash> {
1835 if input_index >= tx.inputs.len() {
1836 return Err(crate::error::ConsensusError::InvalidInputIndex(input_index));
1837 }
1838
1839 let anyone_can_pay = (sighash_type & 0x80) != 0;
1841 let base_type = sighash_type & 0x1f;
1842 let is_none = base_type == 0x02;
1843 let is_single = base_type == 0x03;
1844
1845 let computed;
1847 let hashes = match precomputed {
1848 Some(h) => h,
1849 None => {
1850 computed = Bip143PrecomputedHashes::compute(tx, &[], &[]);
1851 &computed
1852 }
1853 };
1854
1855 #[cfg(feature = "production")]
1858 let preimage_result = BIP143_PREIMAGE_BUF.with(|buf_cell| {
1859 let mut preimage = buf_cell.borrow_mut();
1860 preimage.clear();
1861 let cap = 160 + script_code.len();
1862 if preimage.capacity() < cap {
1863 preimage.reserve(cap);
1864 }
1865 build_bip143_preimage(
1866 tx,
1867 input_index,
1868 script_code,
1869 amount,
1870 sighash_type,
1871 anyone_can_pay,
1872 is_none,
1873 is_single,
1874 hashes,
1875 &mut preimage,
1876 )
1877 });
1878 #[cfg(not(feature = "production"))]
1879 let preimage_result = {
1880 let mut preimage = Vec::with_capacity(160 + script_code.len());
1881 build_bip143_preimage(
1882 tx,
1883 input_index,
1884 script_code,
1885 amount,
1886 sighash_type,
1887 anyone_can_pay,
1888 is_none,
1889 is_single,
1890 hashes,
1891 &mut preimage,
1892 )
1893 };
1894 preimage_result
1895}
1896
1897#[inline]
1898fn build_bip143_preimage(
1899 tx: &Transaction,
1900 input_index: usize,
1901 script_code: &[u8],
1902 amount: i64,
1903 sighash_type: u8,
1904 anyone_can_pay: bool,
1905 is_none: bool,
1906 is_single: bool,
1907 hashes: &Bip143PrecomputedHashes,
1908 preimage: &mut Vec<u8>,
1909) -> Result<Hash> {
1910 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1912
1913 if anyone_can_pay {
1915 preimage.extend_from_slice(&[0u8; 32]);
1916 } else {
1917 preimage.extend_from_slice(&hashes.hash_prevouts);
1918 }
1919
1920 if anyone_can_pay || is_none || is_single {
1922 preimage.extend_from_slice(&[0u8; 32]);
1923 } else {
1924 preimage.extend_from_slice(&hashes.hash_sequence);
1925 }
1926
1927 let input = &tx.inputs[input_index];
1929 preimage.extend_from_slice(&input.prevout.hash);
1930 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1931
1932 write_varint_to_vec(preimage, script_code.len() as u64);
1934 preimage.extend_from_slice(script_code);
1935
1936 preimage.extend_from_slice(&amount.to_le_bytes());
1938
1939 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1941
1942 if is_none {
1944 preimage.extend_from_slice(&[0u8; 32]);
1945 } else if is_single {
1946 if input_index < tx.outputs.len() {
1947 let output = &tx.outputs[input_index];
1949 #[cfg(feature = "production")]
1950 let hash_outputs = BIP143_SINGLE_OUTPUT_BUF.with(|buf_cell| {
1951 let mut output_data = buf_cell.borrow_mut();
1952 output_data.clear();
1953 let cap = 8 + 9 + output.script_pubkey.len(); if output_data.capacity() < cap {
1955 output_data.reserve(cap);
1956 }
1957 output_data.extend_from_slice(&output.value.to_le_bytes());
1958 write_varint_to_vec(&mut output_data, output.script_pubkey.len() as u64);
1959 output_data.extend_from_slice(&output.script_pubkey);
1960 double_sha256(&output_data)
1961 });
1962 #[cfg(not(feature = "production"))]
1963 let hash_outputs = {
1964 let mut output_data = Vec::with_capacity(8 + 9 + output.script_pubkey.len());
1965 output_data.extend_from_slice(&output.value.to_le_bytes());
1966 write_varint_to_vec(&mut output_data, output.script_pubkey.len() as u64);
1967 output_data.extend_from_slice(&output.script_pubkey);
1968 double_sha256(&output_data)
1969 };
1970 preimage.extend_from_slice(&hash_outputs);
1971 } else {
1972 preimage.extend_from_slice(&[0u8; 32]);
1974 }
1975 } else {
1976 preimage.extend_from_slice(&hashes.hash_outputs);
1977 }
1978
1979 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1981
1982 preimage.extend_from_slice(&(sighash_type as u32).to_le_bytes());
1984
1985 Ok(double_sha256(preimage))
1987}
1988
1989#[cfg_attr(
1996 feature = "spec-lock",
1997 spec_locked("11.1.9", "ComputeWitnessSignatureHash")
1998)]
1999pub fn batch_compute_bip143_sighashes(
2000 tx: &Transaction,
2001 prevout_values: &[i64],
2002 prevout_script_pubkeys: &[&[u8]],
2003 script_codes: &[&[u8]],
2004 sighash_type: u8,
2005) -> Result<Vec<Hash>> {
2006 if prevout_values.len() != tx.inputs.len()
2007 || prevout_script_pubkeys.len() != tx.inputs.len()
2008 || script_codes.len() != tx.inputs.len()
2009 {
2010 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
2011 prevout_values.len(),
2012 tx.inputs.len(),
2013 ));
2014 }
2015
2016 let precomputed = Bip143PrecomputedHashes::compute(tx, prevout_values, prevout_script_pubkeys);
2018
2019 let base = sighash_type & 0x1f;
2020 let acp = sighash_type & 0x80;
2021 if base == 0x01 && acp == 0 && tx.inputs.len() >= 2 {
2022 return Ok(batch_bip143_sighash_all_midstate(
2023 tx,
2024 prevout_values,
2025 script_codes,
2026 &precomputed,
2027 ));
2028 }
2029
2030 let mut results = Vec::with_capacity(tx.inputs.len());
2032 for (i, (value, script_code)) in prevout_values.iter().zip(script_codes.iter()).enumerate() {
2033 let sighash =
2034 calculate_bip143_sighash(tx, i, script_code, *value, sighash_type, Some(&precomputed))?;
2035 results.push(sighash);
2036 }
2037 Ok(results)
2038}
2039
2040fn batch_bip143_sighash_all_midstate(
2042 tx: &Transaction,
2043 prevout_values: &[i64],
2044 script_codes: &[&[u8]],
2045 hashes: &Bip143PrecomputedHashes,
2046) -> Vec<Hash> {
2047 use sha2::{Digest, Sha256};
2048 let n = tx.inputs.len();
2049 let mut prefix = Sha256::new();
2050 prefix.update((tx.version as u32).to_le_bytes());
2051 prefix.update(hashes.hash_prevouts);
2052 prefix.update(hashes.hash_sequence);
2053
2054 let mut suffix = [0u8; 40];
2055 suffix[..32].copy_from_slice(&hashes.hash_outputs);
2056 suffix[32..36].copy_from_slice(&(tx.lock_time as u32).to_le_bytes());
2057 suffix[36..40].copy_from_slice(&0x01u32.to_le_bytes());
2058
2059 let mut results = Vec::with_capacity(n);
2060 for i in 0..n {
2061 let mut h = prefix.clone();
2062 let input = &tx.inputs[i];
2063 h.update(input.prevout.hash);
2064 h.update(input.prevout.index.to_le_bytes());
2065 update_varint(&mut h, script_codes[i].len() as u64);
2066 h.update(script_codes[i]);
2067 h.update(prevout_values[i].to_le_bytes());
2068 h.update((input.sequence as u32).to_le_bytes());
2069 h.update(suffix);
2070 let first = h.finalize();
2071 let second = Sha256::digest(first);
2072 let mut out = [0u8; 32];
2073 out.copy_from_slice(&second);
2074 results.push(out);
2075 }
2076 results
2077}
2078
2079#[cfg(test)]
2080mod tests {
2081 use super::*;
2082 use crate::opcodes::*;
2083
2084 #[test]
2085 fn test_sighash_type_parsing() {
2086 assert_eq!(SighashType::from_byte(0x01), SighashType::ALL);
2088 assert_eq!(SighashType::from_byte(0x02), SighashType::NONE);
2089 assert_eq!(SighashType::from_byte(0x03), SighashType::SINGLE);
2090 assert_eq!(SighashType::from_byte(0x00), SighashType::ALL_LEGACY);
2091 assert_eq!(SighashType::from_byte(0x81), SighashType::ALL_ANYONECANPAY);
2092 assert_eq!(SighashType::from_byte(0x82), SighashType::NONE_ANYONECANPAY);
2093 assert_eq!(
2094 SighashType::from_byte(0x83),
2095 SighashType::SINGLE_ANYONECANPAY
2096 );
2097 assert_eq!(SighashType::ALL_ANYONECANPAY.as_u32(), 0x81);
2099 assert_eq!(SighashType::NONE_ANYONECANPAY.as_u32(), 0x82);
2100 assert_eq!(SighashType::SINGLE_ANYONECANPAY.as_u32(), 0x83);
2101 let st = SighashType::from_byte(0x04);
2103 assert!(st.is_all()); assert_eq!(st.as_u32(), 0x04); let st84 = SighashType::from_byte(0x84);
2106 assert!(st84.is_all());
2107 assert!(st84.is_anyonecanpay());
2108 assert_eq!(st84.as_u32(), 0x84);
2109 }
2110
2111 #[test]
2112 fn legacy_sighash_cache_is_bound_to_the_transaction() {
2113 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
2114
2115 let prevout = OutPoint {
2116 hash: [9u8; 32],
2117 index: 0,
2118 };
2119 let script = [0x51u8];
2120 let tx_paying = |value: i64| Transaction {
2121 version: 1,
2122 inputs: vec![TransactionInput {
2123 prevout,
2124 sequence: 0xffff_ffff,
2125 script_sig: vec![0x01],
2126 }]
2127 .into(),
2128 outputs: vec![TransactionOutput {
2129 value,
2130 script_pubkey: vec![0x51],
2131 }]
2132 .into(),
2133 lock_time: 0,
2134 };
2135 let sighash = |value: i64| {
2136 calculate_transaction_sighash_single_input(
2137 &tx_paying(value),
2138 0,
2139 &script,
2140 value,
2141 SighashType::ALL,
2142 #[cfg(feature = "production")]
2143 None,
2144 )
2145 .unwrap()
2146 };
2147
2148 let first = sighash(1_000);
2149 for value in [2_000i64, 3, 50_000_000, i64::MAX / 4] {
2150 assert_ne!(first, sighash(value), "output {value}");
2151 }
2152 assert_eq!(first, sighash(1_000));
2154
2155 let mut later_locktime = tx_paying(1_000);
2156 later_locktime.lock_time = 50;
2157 let locktime_hash = calculate_transaction_sighash_single_input(
2158 &later_locktime,
2159 0,
2160 &script,
2161 1_000,
2162 SighashType::ALL,
2163 #[cfg(feature = "production")]
2164 None,
2165 )
2166 .unwrap();
2167 assert_ne!(first, locktime_hash);
2168
2169 let mut extra_input = tx_paying(1_000);
2170 extra_input.inputs.push(TransactionInput {
2171 prevout: OutPoint {
2172 hash: [8u8; 32],
2173 index: 1,
2174 },
2175 sequence: 0xffff_ffff,
2176 script_sig: vec![],
2177 });
2178 let extra_hash = calculate_transaction_sighash_single_input(
2179 &extra_input,
2180 0,
2181 &script,
2182 1_000,
2183 SighashType::ALL,
2184 #[cfg(feature = "production")]
2185 None,
2186 )
2187 .unwrap();
2188 assert_ne!(first, extra_hash);
2189
2190 let mut other_script_sig = tx_paying(1_000);
2192 other_script_sig.inputs[0].script_sig = vec![0x02, 0x03];
2193 let script_sig_hash = calculate_transaction_sighash_single_input(
2194 &other_script_sig,
2195 0,
2196 &script,
2197 1_000,
2198 SighashType::ALL,
2199 #[cfg(feature = "production")]
2200 None,
2201 )
2202 .unwrap();
2203 assert_eq!(first, script_sig_hash);
2204 }
2205
2206 fn fxhash_colliding_tail() -> [u8; 8] {
2209 0x1319_8a2e_0370_7344u64.to_le_bytes()
2210 }
2211
2212 fn fxhash_colliding_scripts() -> ([u8; 16], [u8; 16]) {
2213 let tail = fxhash_colliding_tail();
2214 let mut first = [0u8; 16];
2215 let mut second = [0u8; 16];
2216 let mut head_a = [0u8; 8];
2217 head_a[0] = OP_1;
2218 head_a[1] = OP_CHECKSIG;
2219 head_a[3] = 1;
2220 head_a[4] = 2;
2221 head_a[5] = 3;
2222 head_a[6] = 4;
2223 head_a[7] = 5;
2224 let mut head_b = [0u8; 8];
2225 head_b[0] = OP_2;
2226 head_b[1] = OP_CHECKSIG;
2227 head_b[2] = 9;
2228 head_b[3] = 8;
2229 head_b[4] = 7;
2230 head_b[5] = 6;
2231 head_b[6] = 5;
2232 head_b[7] = 4;
2233 first[..8].copy_from_slice(&head_a);
2234 second[..8].copy_from_slice(&head_b);
2235 first[8..].copy_from_slice(&tail);
2236 second[8..].copy_from_slice(&tail);
2237 (first, second)
2238 }
2239
2240 #[test]
2241 fn legacy_sighash_cache_does_not_reuse_an_fxhash_script_collision() {
2242 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
2243
2244 let (script_a, script_b) = fxhash_colliding_scripts();
2245 let tx = Transaction {
2246 version: 1,
2247 inputs: vec![TransactionInput {
2248 prevout: OutPoint {
2249 hash: [9u8; 32],
2250 index: 0,
2251 },
2252 sequence: 0xffff_ffff,
2253 script_sig: vec![],
2254 }]
2255 .into(),
2256 outputs: vec![TransactionOutput {
2257 value: 1_000,
2258 script_pubkey: vec![OP_1],
2259 }]
2260 .into(),
2261 lock_time: 0,
2262 };
2263 let sighash = |script: &[u8]| {
2264 calculate_transaction_sighash_single_input(
2265 &tx,
2266 0,
2267 script,
2268 1_000,
2269 SighashType::ALL,
2270 #[cfg(feature = "production")]
2271 None,
2272 )
2273 .unwrap()
2274 };
2275 let first = sighash(&script_a);
2276 let other = sighash(&script_b);
2277 assert_ne!(first, other);
2278 assert_eq!(first, sighash(&script_a));
2279 }
2280
2281 #[test]
2282 fn legacy_sighash_cache_does_not_reuse_an_fxhash_output_collision() {
2283 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
2284
2285 let (script_a, script_b) = fxhash_colliding_scripts();
2286 let signing = [OP_1, OP_CHECKSIG];
2287 let tx_paying = |spk: &[u8]| Transaction {
2288 version: 1,
2289 inputs: vec![TransactionInput {
2290 prevout: OutPoint {
2291 hash: [9u8; 32],
2292 index: 0,
2293 },
2294 sequence: 0xffff_ffff,
2295 script_sig: vec![],
2296 }]
2297 .into(),
2298 outputs: vec![TransactionOutput {
2299 value: 1_000,
2300 script_pubkey: spk.to_vec(),
2301 }]
2302 .into(),
2303 lock_time: 0,
2304 };
2305 let sighash = |spk: &[u8]| {
2306 calculate_transaction_sighash_single_input(
2307 &tx_paying(spk),
2308 0,
2309 &signing,
2310 1_000,
2311 SighashType::ALL,
2312 #[cfg(feature = "production")]
2313 None,
2314 )
2315 .unwrap()
2316 };
2317 let first = sighash(&script_a);
2318 assert_ne!(first, sighash(&script_b));
2319 assert_eq!(first, sighash(&script_a));
2320 }
2321
2322 #[test]
2323 fn test_varint_encoding() {
2324 use crate::serialization::varint::encode_varint;
2325 assert_eq!(encode_varint(0), vec![0]);
2326 assert_eq!(encode_varint(252), vec![252]);
2327 assert_eq!(encode_varint(253), vec![0xfd, 253, 0]);
2328 assert_eq!(encode_varint(65535), vec![0xfd, 255, 255]);
2329 assert_eq!(encode_varint(65536), vec![0xfe, 0, 0, 1, 0]);
2330 }
2331
2332 #[test]
2333 fn test_sighash_calculation() {
2334 let tx = Transaction {
2336 version: 1,
2337 inputs: vec![TransactionInput {
2338 prevout: OutPoint {
2339 hash: [1u8; 32],
2340 index: 0,
2341 },
2342 script_sig: vec![OP_1],
2343 sequence: 0xffffffff,
2344 }]
2345 .into(),
2346 outputs: vec![TransactionOutput {
2347 value: 5000000000,
2348 script_pubkey: vec![
2349 OP_DUP,
2350 OP_HASH160,
2351 PUSH_20_BYTES,
2352 0x89,
2353 0xab,
2354 0xcd,
2355 0xef,
2356 0x12,
2357 0x34,
2358 0x56,
2359 0x78,
2360 0x9a,
2361 0xbc,
2362 0xde,
2363 0xf0,
2364 0x12,
2365 0x34,
2366 0x56,
2367 0x78,
2368 0x9a,
2369 OP_EQUALVERIFY,
2370 OP_CHECKSIG,
2371 ], }]
2373 .into(),
2374 lock_time: 0,
2375 };
2376
2377 let prevouts = vec![TransactionOutput {
2378 value: 10000000000,
2379 script_pubkey: vec![
2380 OP_DUP,
2381 OP_HASH160,
2382 PUSH_20_BYTES,
2383 0x89,
2384 0xab,
2385 0xcd,
2386 0xef,
2387 0x12,
2388 0x34,
2389 0x56,
2390 0x78,
2391 0x9a,
2392 0xbc,
2393 0xde,
2394 0xf0,
2395 0x12,
2396 0x34,
2397 0x56,
2398 0x78,
2399 0x9a,
2400 OP_EQUALVERIFY,
2401 OP_CHECKSIG,
2402 ],
2403 }];
2404
2405 let sighash = calculate_transaction_sighash(&tx, 0, &prevouts, SighashType::ALL).unwrap();
2407 assert_eq!(sighash.len(), 32);
2408
2409 let sighash_none =
2411 calculate_transaction_sighash(&tx, 0, &prevouts, SighashType::NONE).unwrap();
2412 assert_ne!(sighash, sighash_none);
2413
2414 let sighash_single =
2416 calculate_transaction_sighash(&tx, 0, &prevouts, SighashType::SINGLE).unwrap();
2417 assert_ne!(sighash, sighash_single);
2418 }
2419
2420 #[test]
2421 fn test_sighash_invalid_input_index() {
2422 let tx = Transaction {
2423 version: 1,
2424 inputs: vec![].into(),
2425 outputs: vec![].into(),
2426 lock_time: 0,
2427 };
2428
2429 let result = calculate_transaction_sighash(&tx, 0, &[], SighashType::ALL);
2430 assert!(result.is_err());
2431 }
2432
2433 #[test]
2434 fn test_bip143_sighash() {
2435 let tx = Transaction {
2437 version: 1,
2438 inputs: vec![
2439 TransactionInput {
2440 prevout: OutPoint {
2441 hash: [1u8; 32],
2442 index: 0,
2443 },
2444 script_sig: vec![], sequence: 0xffffffff,
2446 },
2447 TransactionInput {
2448 prevout: OutPoint {
2449 hash: [2u8; 32],
2450 index: 1,
2451 },
2452 script_sig: vec![],
2453 sequence: 0xfffffffe,
2454 },
2455 ]
2456 .into(),
2457 outputs: vec![TransactionOutput {
2458 value: 5000000000,
2459 script_pubkey: vec![
2460 OP_0,
2461 PUSH_20_BYTES,
2462 0x89,
2463 0xab,
2464 0xcd,
2465 0xef,
2466 0x12,
2467 0x34,
2468 0x56,
2469 0x78,
2470 0x9a,
2471 0xbc,
2472 0xde,
2473 0xf0,
2474 0x12,
2475 0x34,
2476 0x56,
2477 0x78,
2478 0x9a,
2479 0xbc,
2480 0xde,
2481 0xf0,
2482 ],
2483 }]
2484 .into(),
2485 lock_time: 0,
2486 };
2487
2488 let prevouts = [
2489 TransactionOutput {
2490 value: 10000000000,
2491 script_pubkey: vec![
2492 OP_0,
2493 PUSH_20_BYTES,
2494 0x11,
2495 0x22,
2496 0x33,
2497 0x44,
2498 0x55,
2499 0x66,
2500 0x77,
2501 0x88,
2502 0x99,
2503 0xaa,
2504 0xbb,
2505 0xcc,
2506 0xdd,
2507 0xee,
2508 0xff,
2509 0x00,
2510 0x11,
2511 0x22,
2512 0x33,
2513 0x44,
2514 ],
2515 },
2516 TransactionOutput {
2517 value: 8000000000,
2518 script_pubkey: vec![
2519 OP_0,
2520 PUSH_20_BYTES,
2521 0xaa,
2522 0xbb,
2523 0xcc,
2524 0xdd,
2525 0xee,
2526 0xff,
2527 0x00,
2528 0x11,
2529 0x22,
2530 0x33,
2531 0x44,
2532 0x55,
2533 0x66,
2534 0x77,
2535 0x88,
2536 0x99,
2537 0xaa,
2538 0xbb,
2539 0xcc,
2540 0xdd,
2541 ],
2542 },
2543 ];
2544
2545 let script_code = vec![
2547 OP_DUP,
2548 OP_HASH160,
2549 PUSH_20_BYTES,
2550 0x11,
2551 0x22,
2552 0x33,
2553 0x44,
2554 0x55,
2555 0x66,
2556 0x77,
2557 0x88,
2558 0x99,
2559 0xaa,
2560 0xbb,
2561 0xcc,
2562 0xdd,
2563 0xee,
2564 0xff,
2565 0x00,
2566 0x11,
2567 0x22,
2568 0x33,
2569 OP_EQUALVERIFY,
2570 OP_CHECKSIG,
2571 ];
2572
2573 let sighash0 =
2575 calculate_bip143_sighash(&tx, 0, &script_code, prevouts[0].value, 0x01, None).unwrap();
2576 assert_eq!(sighash0.len(), 32);
2577
2578 let sighash1 =
2580 calculate_bip143_sighash(&tx, 1, &script_code, prevouts[1].value, 0x01, None).unwrap();
2581 assert_ne!(sighash0, sighash1);
2582
2583 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
2585 let prevout_script_pubkeys: Vec<&[u8]> =
2586 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
2587 let precomputed =
2588 Bip143PrecomputedHashes::compute(&tx, &prevout_values, &prevout_script_pubkeys);
2589 let sighash0_precomputed = calculate_bip143_sighash(
2590 &tx,
2591 0,
2592 &script_code,
2593 prevout_values[0],
2594 0x01,
2595 Some(&precomputed),
2596 )
2597 .unwrap();
2598 assert_eq!(sighash0, sighash0_precomputed);
2599
2600 let script_codes = [script_code.as_slice(), script_code.as_slice()];
2602 let batched = batch_compute_bip143_sighashes(
2603 &tx,
2604 &prevout_values,
2605 &prevout_script_pubkeys,
2606 &script_codes,
2607 0x01,
2608 )
2609 .unwrap();
2610 assert_eq!(batched[0], sighash0);
2611 assert_eq!(batched[1], sighash1);
2612 }
2613
2614 #[test]
2615 fn test_bip143_anyonecanpay() {
2616 let tx = Transaction {
2617 version: 1,
2618 inputs: vec![TransactionInput {
2619 prevout: OutPoint {
2620 hash: [1u8; 32],
2621 index: 0,
2622 },
2623 script_sig: vec![],
2624 sequence: 0xffffffff,
2625 }]
2626 .into(),
2627 outputs: vec![TransactionOutput {
2628 value: 5000000000,
2629 script_pubkey: vec![OP_0, PUSH_20_BYTES],
2630 }]
2631 .into(),
2632 lock_time: 0,
2633 };
2634
2635 let script_code = {
2636 let mut s = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
2637 s.extend_from_slice(&[0u8; 20]); s.push(OP_EQUALVERIFY);
2639 s.push(OP_CHECKSIG);
2640 s };
2642 let amount = 10000000000i64;
2643
2644 let sighash_all =
2646 calculate_bip143_sighash(&tx, 0, &script_code, amount, 0x01, None).unwrap();
2647
2648 let sighash_anyonecanpay =
2650 calculate_bip143_sighash(&tx, 0, &script_code, amount, 0x81, None).unwrap();
2651
2652 assert_ne!(sighash_all, sighash_anyonecanpay);
2654 }
2655
2656 #[test]
2660 fn test_2input_legacy_sighash_non_signing_empty_script() {
2661 let script_a = vec![
2663 PUSH_33_BYTES,
2664 0x02,
2665 0x00,
2666 0x00,
2667 0x00,
2668 0x00,
2669 0x00,
2670 0x00,
2671 0x00,
2672 0x00,
2673 0x00,
2674 0x00,
2675 0x00,
2676 0x00,
2677 0x00,
2678 0x00,
2679 0x00,
2680 0x00,
2681 0x00,
2682 0x00,
2683 0x00,
2684 0x00,
2685 0x00,
2686 0x00,
2687 0x00,
2688 0x00,
2689 0x00,
2690 0x00,
2691 0x00,
2692 0x00,
2693 0x00,
2694 0x00,
2695 OP_CHECKSIG,
2696 ]; let script_b = vec![
2698 PUSH_33_BYTES,
2699 0x03,
2700 0x11,
2701 0x11,
2702 0x11,
2703 0x11,
2704 0x11,
2705 0x11,
2706 0x11,
2707 0x11,
2708 0x11,
2709 0x11,
2710 0x11,
2711 0x11,
2712 0x11,
2713 0x11,
2714 0x11,
2715 0x11,
2716 0x11,
2717 0x11,
2718 0x11,
2719 0x11,
2720 0x11,
2721 0x11,
2722 0x11,
2723 0x11,
2724 0x11,
2725 0x11,
2726 0x11,
2727 0x11,
2728 0x11,
2729 0x11,
2730 OP_CHECKSIG,
2731 ]; let tx = Transaction {
2733 version: 1,
2734 inputs: vec![
2735 TransactionInput {
2736 prevout: OutPoint {
2737 hash: [1u8; 32],
2738 index: 0,
2739 },
2740 script_sig: vec![],
2741 sequence: 0xffffffff,
2742 },
2743 TransactionInput {
2744 prevout: OutPoint {
2745 hash: [2u8; 32],
2746 index: 1,
2747 },
2748 script_sig: vec![],
2749 sequence: 0xffffffff,
2750 },
2751 ]
2752 .into(),
2753 outputs: vec![TransactionOutput {
2754 value: 5000000000,
2755 script_pubkey: vec![OP_DUP, OP_HASH160, PUSH_20_BYTES],
2756 }]
2757 .into(),
2758 lock_time: 0,
2759 };
2760 let pv: Vec<i64> = vec![10_000_000_000, 8_000_000_000];
2761 let psp_ab: Vec<&[u8]> = vec![script_a.as_slice(), script_b.as_slice()];
2762 let psp_aa: Vec<&[u8]> = vec![script_a.as_slice(), script_a.as_slice()];
2763
2764 let sighash_ab = calculate_transaction_sighash_with_script_code(
2767 &tx,
2768 0,
2769 &pv,
2770 &psp_ab,
2771 SighashType::ALL,
2772 None,
2773 #[cfg(feature = "production")]
2774 None,
2775 )
2776 .unwrap();
2777 let sighash_aa = calculate_transaction_sighash_with_script_code(
2778 &tx,
2779 0,
2780 &pv,
2781 &psp_aa,
2782 SighashType::ALL,
2783 None,
2784 #[cfg(feature = "production")]
2785 None,
2786 )
2787 .unwrap();
2788 assert_eq!(
2789 sighash_ab, sighash_aa,
2790 "2-input legacy: signing input 0 — input 1 script must be empty; changing input 1 scriptPubKey must not change sighash"
2791 );
2792 }
2793
2794 #[cfg(feature = "production")]
2795 #[test]
2796 fn test_batch_sighash_single_input_index_ge_outputs() {
2797 let tx = Transaction {
2800 version: 1,
2801 inputs: vec![
2802 TransactionInput {
2803 prevout: OutPoint {
2804 hash: [1u8; 32],
2805 index: 0,
2806 },
2807 script_sig: vec![],
2808 sequence: 0xffffffff,
2809 },
2810 TransactionInput {
2811 prevout: OutPoint {
2812 hash: [2u8; 32],
2813 index: 1,
2814 },
2815 script_sig: vec![],
2816 sequence: 0xffffffff,
2817 },
2818 ]
2819 .into(),
2820 outputs: vec![TransactionOutput {
2821 value: 5000000000,
2822 script_pubkey: vec![OP_DUP, OP_HASH160, PUSH_20_BYTES],
2823 }]
2824 .into(),
2825 lock_time: 0,
2826 };
2827 let prevout_values = vec![10_000_000_000i64, 8_000_000_000i64];
2828 let script = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
2829 let prevout_script_pubkeys: Vec<&[u8]> = vec![script.as_slice(), script.as_slice()];
2830 let specs = vec![(1usize, 0x03u8, script.as_slice() as &[u8])]; let hashes = super::batch_compute_legacy_sighashes(
2832 &tx,
2833 &prevout_values,
2834 &prevout_script_pubkeys,
2835 &specs,
2836 )
2837 .unwrap();
2838 assert_eq!(hashes.len(), 1);
2839 let mut expected = [0u8; 32];
2840 expected[0] = 1;
2841 assert_eq!(
2842 hashes[0], expected,
2843 "SIGHASH_SINGLE with input_index>=outputs.len() must return 0x0000...0001"
2844 );
2845 }
2846}