1use crate::crypto::OptimizedSha256;
10use crate::error::Result;
11use crate::types::*;
12use blvm_spec_lock::spec_locked;
13
14#[inline]
16fn write_varint_to_vec(vec: &mut Vec<u8>, value: u64) {
17 if value < 0xfd {
18 vec.push(value as u8);
19 } else if value <= 0xffff {
20 vec.push(0xfd);
21 vec.extend_from_slice(&(value as u16).to_le_bytes());
22 } else if value <= 0xffffffff {
23 vec.push(0xfe);
24 vec.extend_from_slice(&(value as u32).to_le_bytes());
25 } else {
26 vec.push(0xff);
27 vec.extend_from_slice(&value.to_le_bytes());
28 }
29}
30
31#[cfg(feature = "production")]
32use hashbrown::HashMap as HashBrownMap;
33#[cfg(feature = "production")]
34use lru::LruCache;
35#[cfg(feature = "production")]
36use rustc_hash::{FxBuildHasher, FxHasher};
37#[cfg(feature = "production")]
38use std::cell::RefCell;
39#[cfg(feature = "production")]
40use std::hash::{Hash as StdHash, Hasher};
41
42#[cfg(feature = "production")]
45#[derive(Clone, Copy, PartialEq, Eq, Debug)]
46pub struct SighashCacheKey {
47 prevout: crate::types::OutPoint,
48 code_hash: u64,
49 sighash_byte: u8,
50}
51
52#[cfg(feature = "production")]
53impl std::hash::Hash for SighashCacheKey {
54 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55 state.write_u64(self.code_hash);
56 }
57}
58
59#[cfg(feature = "production")]
60pub type SighashMidstateCache =
61 std::sync::Arc<std::sync::Mutex<HashBrownMap<SighashCacheKey, [u8; 32], FxBuildHasher>>>;
62
63#[cfg(feature = "production")]
66thread_local! {
67 static SIGHASH_MIDSTATE_CACHE: RefCell<HashBrownMap<SighashCacheKey, [u8; 32], FxBuildHasher>> =
68 const { RefCell::new(HashBrownMap::with_hasher(FxBuildHasher)) };
69}
70
71#[cfg(feature = "production")]
72fn insert_midstate_cache(
73 sighash_cache: Option<&SighashMidstateCache>,
74 prevout: crate::types::OutPoint,
75 code: &[u8],
76 sighash_byte: u8,
77 hash: [u8; 32],
78) {
79 let key_hash = sighash_cache_hash(&prevout, code, sighash_byte);
80 let key = SighashCacheKey {
81 prevout,
82 code_hash: key_hash,
83 sighash_byte,
84 };
85 if let Some(c) = sighash_cache {
86 let _ = c.lock().map(|mut g| g.insert(key, hash));
87 } else {
88 SIGHASH_MIDSTATE_CACHE.with(|cell| {
89 cell.borrow_mut().insert(key, hash);
90 });
91 }
92}
93
94#[cfg(feature = "production")]
96#[inline]
97fn sighash_cache_hash(prevout: &crate::types::OutPoint, code: &[u8], sighash_byte: u8) -> u64 {
98 let mut hasher = FxHasher::default();
99 prevout.hash(&mut hasher);
100 code.hash(&mut hasher);
101 sighash_byte.hash(&mut hasher);
102 hasher.finish()
103}
104
105#[cfg(feature = "production")]
110thread_local! {
111 static SIGHASH_CACHE: RefCell<LruCache<[u8; 32], [u8; 32]>> = RefCell::new({
112 let cap = std::env::var("BLVM_SIGHASH_CACHE_SIZE")
113 .ok()
114 .and_then(|s| s.parse().ok())
115 .unwrap_or(262_144)
116 .clamp(65_536, 2_097_152);
117 LruCache::new(std::num::NonZeroUsize::new(cap).unwrap())
118 });
119}
120
121#[cfg(feature = "production")]
123thread_local! {
124 static SIGHASH_PREIMAGE_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(4096));
125}
126
127#[cfg(feature = "production")]
130thread_local! {
131 static BIP143_SERIALIZE_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(131_072)); }
133
134#[cfg(feature = "production")]
136thread_local! {
137 static BIP143_PREIMAGE_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(1024));
138}
139
140#[cfg(feature = "production")]
142thread_local! {
143 static BIP143_SINGLE_OUTPUT_BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(256));
144}
145
146#[cfg(feature = "production")]
149thread_local! {
150 static LEGACY_BATCH_PREIMAGES: std::cell::RefCell<Vec<Vec<u8>>> =
151 const { std::cell::RefCell::new(Vec::new()) };
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
163pub struct SighashType(pub u8);
164
165impl SighashType {
166 pub const ALL_LEGACY: Self = SighashType(0x00);
168 pub const ALL: Self = SighashType(0x01);
169 pub const NONE: Self = SighashType(0x02);
170 pub const SINGLE: Self = SighashType(0x03);
171 pub const ALL_ANYONECANPAY: Self = SighashType(0x81);
172 pub const NONE_ANYONECANPAY: Self = SighashType(0x82);
173 pub const SINGLE_ANYONECANPAY: Self = SighashType(0x83);
174
175 pub fn from_byte(byte: u8) -> Self {
178 SighashType(byte)
179 }
180
181 pub fn as_u32(&self) -> u32 {
183 self.0 as u32
184 }
185
186 pub fn base_type(&self) -> u8 {
188 self.0 & 0x1f
189 }
190
191 pub fn is_anyonecanpay(&self) -> bool {
193 self.0 & 0x80 != 0
194 }
195
196 pub fn is_all(&self) -> bool {
198 let base = self.base_type();
199 base != 0x02 && base != 0x03
200 }
201
202 pub fn is_none(&self) -> bool {
204 self.base_type() == 0x02
205 }
206
207 pub fn is_single(&self) -> bool {
209 self.base_type() == 0x03
210 }
211}
212
213#[cfg(feature = "production")]
215#[allow(dead_code)]
216#[inline]
217fn is_cacheable_sighash_pattern(
218 tx: &Transaction,
219 input_index: usize,
220 sighash_type: SighashType,
221) -> bool {
222 if sighash_type.is_anyonecanpay() {
223 return false;
224 }
225 let base = sighash_type.base_type();
227 if base == 0x01 || base == 0x00 {
228 let ni = tx.inputs.len();
229 let no = tx.outputs.len();
230 (ni == 1 && (1..=4).contains(&no))
231 || ((1..=4).contains(&ni) && no == 1)
232 || (ni == 2 && no == 2)
233 || (ni == 1 && no == 1)
234 } else if base == 0x02 {
235 !tx.inputs.is_empty() && tx.inputs.len() <= 4
237 } else if base == 0x03 {
238 input_index < tx.outputs.len() && tx.inputs.len() <= 4
240 } else {
241 false
242 }
243}
244
245#[cfg(feature = "production")]
250fn sighash_with_cache(preimage: &[u8]) -> Hash {
251 let hasher = OptimizedSha256::new();
252 let first_hash: [u8; 32] = hasher.hash(preimage);
253 SIGHASH_CACHE.with(|cell| {
254 let mut cache = cell.borrow_mut();
255 if let Some(cached) = cache.get(&first_hash) {
256 return *cached;
257 }
258 let second_hash = hasher.hash(&first_hash);
259 let mut result = [0u8; 32];
260 result.copy_from_slice(&second_hash);
261 cache.put(first_hash, result);
262 result
263 })
264}
265
266#[cfg(feature = "production")]
270#[spec_locked("5.1.1")]
271#[inline]
272pub fn compute_legacy_sighash_nocache(
273 tx: &Transaction,
274 input_index: usize,
275 script_code: &[u8],
276 sighash_byte: u8,
277) -> [u8; 32] {
278 use sha2::{Digest, Sha256};
279
280 let sighash_u32 = sighash_byte as u32;
281 let base_type = sighash_u32 & 0x1f;
282 let anyone_can_pay = (sighash_u32 & 0x80) != 0;
283 let hash_none = base_type == 0x02;
284 let hash_single = base_type == 0x03;
285
286 if hash_single && input_index >= tx.outputs.len() {
287 let mut result = [0u8; 32];
288 result[0] = 1;
289 return result;
290 }
291
292 let mut h = Sha256::new();
293 h.update((tx.version as u32).to_le_bytes());
294
295 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
296 update_varint(&mut h, n_inputs as u64);
297
298 for i in 0..n_inputs {
299 let actual_i = if anyone_can_pay { input_index } else { i };
300 let input = &tx.inputs[actual_i];
301 h.update(input.prevout.hash);
302 h.update(input.prevout.index.to_le_bytes());
303
304 if actual_i == input_index {
305 update_varint(&mut h, script_code.len() as u64);
306 h.update(script_code);
307 } else {
308 h.update([0u8]);
309 }
310
311 if actual_i != input_index && (hash_single || hash_none) {
312 h.update(0u32.to_le_bytes());
313 } else {
314 h.update((input.sequence as u32).to_le_bytes());
315 }
316 }
317
318 let n_outputs = if hash_none {
319 0
320 } else if hash_single {
321 input_index + 1
322 } else {
323 tx.outputs.len()
324 };
325 update_varint(&mut h, n_outputs as u64);
326
327 for i in 0..n_outputs {
328 if hash_single && i != input_index {
329 h.update((-1i64).to_le_bytes());
330 h.update([0u8]);
331 } else {
332 let output = &tx.outputs[i];
333 h.update(output.value.to_le_bytes());
334 update_varint(&mut h, output.script_pubkey.len() as u64);
335 h.update(output.script_pubkey.as_slice());
336 }
337 }
338
339 h.update((tx.lock_time as u32).to_le_bytes());
340 h.update(sighash_u32.to_le_bytes());
341
342 let first_hash = h.finalize();
343 let second_hash = Sha256::digest(first_hash);
344 let mut result = [0u8; 32];
345 result.copy_from_slice(&second_hash);
346 result
347}
348
349#[cfg(feature = "production")]
351#[inline]
352fn update_varint(hasher: &mut sha2::Sha256, value: u64) {
353 use sha2::Digest;
354 if value < 0xfd {
355 hasher.update([value as u8]);
356 } else if value <= 0xffff {
357 hasher.update([0xfd]);
358 hasher.update((value as u16).to_le_bytes());
359 } else if value <= 0xffffffff {
360 hasher.update([0xfe]);
361 hasher.update((value as u32).to_le_bytes());
362 } else {
363 hasher.update([0xff]);
364 hasher.update(value.to_le_bytes());
365 }
366}
367
368#[cfg(feature = "production")]
370#[inline]
371fn push_varint(buf: &mut Vec<u8>, value: u64) {
372 if value < 0xfd {
373 buf.push(value as u8);
374 } else if value <= 0xffff {
375 buf.push(0xfd);
376 buf.extend_from_slice(&(value as u16).to_le_bytes());
377 } else if value <= 0xffffffff {
378 buf.push(0xfe);
379 buf.extend_from_slice(&(value as u32).to_le_bytes());
380 } else {
381 buf.push(0xff);
382 buf.extend_from_slice(&value.to_le_bytes());
383 }
384}
385
386#[cfg(feature = "production")]
389#[spec_locked("5.1.1")]
390#[inline]
391pub fn compute_legacy_sighash_buffered(
392 tx: &Transaction,
393 input_index: usize,
394 script_code: &[u8],
395 sighash_byte: u8,
396) -> [u8; 32] {
397 use sha2::{Digest, Sha256};
398
399 let sighash_u32 = sighash_byte as u32;
400 let base_type = sighash_u32 & 0x1f;
401 let anyone_can_pay = (sighash_u32 & 0x80) != 0;
402 let hash_none = base_type == 0x02;
403 let hash_single = base_type == 0x03;
404
405 if hash_single && input_index >= tx.outputs.len() {
406 let mut result = [0u8; 32];
407 result[0] = 1;
408 return result;
409 }
410
411 thread_local! {
412 static BUF: std::cell::RefCell<Vec<u8>> = std::cell::RefCell::new(Vec::with_capacity(4096));
413 }
414
415 BUF.with(|cell| {
416 let mut buf = cell.borrow_mut();
417 buf.clear();
418
419 buf.extend_from_slice(&(tx.version as u32).to_le_bytes());
420
421 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
422 push_varint(&mut buf, n_inputs as u64);
423
424 for i in 0..n_inputs {
425 let actual_i = if anyone_can_pay { input_index } else { i };
426 let input = &tx.inputs[actual_i];
427 buf.extend_from_slice(&input.prevout.hash);
428 buf.extend_from_slice(&input.prevout.index.to_le_bytes());
429
430 if actual_i == input_index {
431 push_varint(&mut buf, script_code.len() as u64);
432 buf.extend_from_slice(script_code);
433 } else {
434 buf.push(0u8);
435 }
436
437 if actual_i != input_index && (hash_single || hash_none) {
438 buf.extend_from_slice(&0u32.to_le_bytes());
439 } else {
440 buf.extend_from_slice(&(input.sequence as u32).to_le_bytes());
441 }
442 }
443
444 let n_outputs = if hash_none {
445 0
446 } else if hash_single {
447 input_index + 1
448 } else {
449 tx.outputs.len()
450 };
451 push_varint(&mut buf, n_outputs as u64);
452
453 for i in 0..n_outputs {
454 if hash_single && i != input_index {
455 buf.extend_from_slice(&(-1i64).to_le_bytes());
456 buf.push(0u8);
457 } else {
458 let output = &tx.outputs[i];
459 buf.extend_from_slice(&output.value.to_le_bytes());
460 push_varint(&mut buf, output.script_pubkey.len() as u64);
461 buf.extend_from_slice(&output.script_pubkey);
462 }
463 }
464
465 buf.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
466 buf.extend_from_slice(&sighash_u32.to_le_bytes());
467
468 let first_hash = Sha256::digest(buf.as_slice());
469 let second_hash = Sha256::digest(first_hash);
470 let mut result = [0u8; 32];
471 result.copy_from_slice(&second_hash);
472 result
473 })
474}
475
476#[cfg(feature = "production")]
483#[spec_locked("5.1.1")]
484pub fn compute_sighashes_batch(
485 tx: &Transaction,
486 script_codes: &[&[u8]],
487 sighash_bytes: &[u8],
488) -> Vec<[u8; 32]> {
489 use sha2::{Digest, Sha256};
490 let n = tx.inputs.len();
491 debug_assert_eq!(script_codes.len(), n);
492 debug_assert_eq!(sighash_bytes.len(), n);
493
494 let mut results = Vec::with_capacity(n);
495
496 let all_sighash_all = sighash_bytes.iter().all(|&b| {
497 let base = (b as u32) & 0x1f;
498 let acp = (b as u32) & 0x80;
499 base == 0x01 && acp == 0
500 });
501
502 if !all_sighash_all || n <= 1 {
503 for i in 0..n {
504 results.push(compute_legacy_sighash_nocache(
505 tx,
506 i,
507 script_codes[i],
508 sighash_bytes[i],
509 ));
510 }
511 return results;
512 }
513
514 let mut outputs_buf: Vec<u8> = Vec::with_capacity(tx.outputs.len() * 40 + 16);
516 write_varint_to_vec(&mut outputs_buf, tx.outputs.len() as u64);
517 for output in tx.outputs.iter() {
518 outputs_buf.extend_from_slice(&output.value.to_le_bytes());
519 write_varint_to_vec(&mut outputs_buf, output.script_pubkey.len() as u64);
520 outputs_buf.extend_from_slice(&output.script_pubkey);
521 }
522 outputs_buf.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
523
524 let mut running = Sha256::new();
526 running.update((tx.version as u32).to_le_bytes());
527 update_varint(&mut running, n as u64);
528
529 let mut midstates: Vec<Sha256> = Vec::with_capacity(n);
530 for j in 0..n {
531 midstates.push(running.clone());
532 running.update(tx.inputs[j].prevout.hash);
533 running.update(tx.inputs[j].prevout.index.to_le_bytes());
534 running.update([0u8]);
535 running.update((tx.inputs[j].sequence as u32).to_le_bytes());
536 }
537
538 let sighash_u32_le = 0x01u32.to_le_bytes();
539
540 for i in 0..n {
541 let mut h = midstates[i].clone();
542
543 h.update(tx.inputs[i].prevout.hash);
545 h.update(tx.inputs[i].prevout.index.to_le_bytes());
546 update_varint(&mut h, script_codes[i].len() as u64);
547 h.update(script_codes[i]);
548 h.update((tx.inputs[i].sequence as u32).to_le_bytes());
549
550 for j in (i + 1)..n {
552 h.update(tx.inputs[j].prevout.hash);
553 h.update(tx.inputs[j].prevout.index.to_le_bytes());
554 h.update([0u8]);
555 h.update((tx.inputs[j].sequence as u32).to_le_bytes());
556 }
557
558 h.update(outputs_buf.as_slice());
560 h.update(sighash_u32_le);
561
562 let first_hash = h.finalize();
563 let second_hash = Sha256::digest(first_hash);
564 let mut result = [0u8; 32];
565 result.copy_from_slice(&second_hash);
566 results.push(result);
567 }
568
569 results
570}
571
572#[spec_locked("5.1")]
590pub fn calculate_transaction_sighash(
591 tx: &Transaction,
592 input_index: usize,
593 prevouts: &[TransactionOutput],
594 sighash_type: SighashType,
595) -> Result<Hash> {
596 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
598 let prevout_script_pubkeys: Vec<&[u8]> =
599 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
600 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
602 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
603 prevout_values.len(),
604 tx.inputs.len(),
605 ));
606 }
607 calculate_transaction_sighash_with_script_code(
608 tx,
609 input_index,
610 &prevout_values,
611 &prevout_script_pubkeys,
612 sighash_type,
613 None,
614 #[cfg(feature = "production")]
615 None,
616 )
617}
618
619#[spec_locked("5.1")]
624pub fn calculate_transaction_sighash_single_input(
625 tx: &Transaction,
626 input_index: usize,
627 script_for_signing: &[u8],
628 prevout_value: i64,
629 sighash_type: SighashType,
630 #[cfg(feature = "production")] sighash_cache: Option<&SighashMidstateCache>,
631) -> Result<Hash> {
632 if input_index >= tx.inputs.len() {
633 return Err(crate::error::ConsensusError::InvalidInputIndex(input_index));
634 }
635 #[cfg(feature = "production")]
639 return calculate_transaction_sighash_with_script_code(
640 tx,
641 input_index,
642 &[],
643 &[],
644 sighash_type,
645 Some(script_for_signing),
646 sighash_cache,
647 );
648 #[cfg(not(feature = "production"))]
649 {
650 let mut prevout_values = vec![0i64; tx.inputs.len()];
651 prevout_values[input_index] = prevout_value;
652 let prevout_script_pubkeys: Vec<&[u8]> = (0..tx.inputs.len())
653 .map(|i| {
654 if i == input_index {
655 script_for_signing
656 } else {
657 &[]
658 }
659 })
660 .collect();
661 calculate_transaction_sighash_with_script_code(
662 tx,
663 input_index,
664 &prevout_values,
665 &prevout_script_pubkeys,
666 sighash_type,
667 Some(script_for_signing),
668 )
669 }
670}
671
672#[spec_locked("5.1")]
678pub fn calculate_transaction_sighash_with_script_code(
679 tx: &Transaction,
680 input_index: usize,
681 prevout_values: &[i64],
682 prevout_script_pubkeys: &[&[u8]],
683 sighash_type: SighashType,
684 script_code: Option<&[u8]>,
685 #[cfg(feature = "production")] sighash_cache: Option<&SighashMidstateCache>,
686) -> Result<Hash> {
687 #[cfg(all(feature = "production", feature = "profile"))]
688 let _t0 = std::time::Instant::now();
689
690 if input_index >= tx.inputs.len() {
692 return Err(crate::error::ConsensusError::InvalidInputIndex(input_index));
693 }
694
695 if script_code.is_none()
699 && (prevout_values.len() != tx.inputs.len()
700 || prevout_script_pubkeys.len() != tx.inputs.len())
701 {
702 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
703 prevout_values.len(),
704 tx.inputs.len(),
705 ));
706 }
707
708 let sighash_byte = sighash_type.as_u32();
709 let base_type = sighash_byte & 0x1f;
710 let anyone_can_pay = (sighash_byte & 0x80) != 0;
711 let hash_none = base_type == 0x02; let hash_single = base_type == 0x03; if hash_single && input_index >= tx.outputs.len() {
717 let mut result = [0u8; 32];
718 result[0] = 1; return Ok(result);
720 }
721
722 #[cfg(feature = "production")]
725 {
726 let prevout = &tx.inputs[input_index].prevout;
727 let code = script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]);
728 let sighash_byte_u8 = sighash_byte as u8;
729 let hash = sighash_cache_hash(prevout, code, sighash_byte_u8);
730 let cached = if let Some(cache) = sighash_cache {
731 cache.lock().ok().and_then(|guard| {
732 (*guard)
733 .raw_entry()
734 .from_hash(hash, |k: &SighashCacheKey| {
735 k.prevout == *prevout
736 && k.code_hash == hash
737 && k.sighash_byte == sighash_byte_u8
738 })
739 .map(|(_, v)| *v)
740 })
741 } else {
742 SIGHASH_MIDSTATE_CACHE.with(|cell| {
743 let map = cell.borrow();
744 map.raw_entry()
745 .from_hash(hash, |k: &SighashCacheKey| {
746 k.prevout == *prevout
747 && k.code_hash == hash
748 && k.sighash_byte == sighash_byte_u8
749 })
750 .map(|(_, v)| *v)
751 })
752 };
753 if let Some(cached) = cached {
754 return Ok(cached);
755 }
756 }
757
758 #[cfg(feature = "production")]
760 if tx.inputs.len() == 1 && input_index == 0 && !anyone_can_pay && !hash_none && !hash_single {
761 let base_type = sighash_byte & 0x1f;
762 if base_type == 0x01 || base_type == 0x00 {
763 let n_out = tx.outputs.len();
764 if n_out == 1 {
765 if let Ok(h) = build_preimage_1in1out_sighash_all(
766 tx,
767 prevout_values,
768 prevout_script_pubkeys,
769 script_code,
770 sighash_byte,
771 ) {
772 #[cfg(all(feature = "production", feature = "profile"))]
773 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
774 #[cfg(feature = "production")]
775 insert_midstate_cache(
776 sighash_cache,
777 tx.inputs[0].prevout,
778 script_code.unwrap_or_else(|| prevout_script_pubkeys[0]),
779 sighash_byte as u8,
780 h,
781 );
782 return Ok(h);
783 }
784 } else if (2..=16).contains(&n_out) {
785 if let Ok(h) = build_preimage_1in_nout_sighash_all(
786 tx,
787 prevout_script_pubkeys,
788 script_code,
789 sighash_byte,
790 ) {
791 #[cfg(all(feature = "production", feature = "profile"))]
792 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
793 #[cfg(feature = "production")]
794 insert_midstate_cache(
795 sighash_cache,
796 tx.inputs[0].prevout,
797 script_code.unwrap_or_else(|| prevout_script_pubkeys[0]),
798 sighash_byte as u8,
799 h,
800 );
801 return Ok(h);
802 }
803 }
804 }
805 }
806
807 #[cfg(feature = "production")]
809 if tx.inputs.len() == 2 && input_index < 2 && !anyone_can_pay && !hash_none && !hash_single {
810 let base_type = sighash_byte & 0x1f;
811 if base_type == 0x01 || base_type == 0x00 {
812 let n_out = tx.outputs.len();
813 if n_out == 1 {
814 if let Ok(h) = build_preimage_2in1out_sighash_all(
815 tx,
816 input_index,
817 prevout_values,
818 prevout_script_pubkeys,
819 script_code,
820 sighash_byte,
821 ) {
822 #[cfg(all(feature = "production", feature = "profile"))]
823 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
824 #[cfg(feature = "production")]
825 insert_midstate_cache(
826 sighash_cache,
827 tx.inputs[input_index].prevout,
828 script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]),
829 sighash_byte as u8,
830 h,
831 );
832 return Ok(h);
833 }
834 } else if n_out == 2 {
835 if let Ok(h) = build_preimage_2in2out_sighash_all(
836 tx,
837 input_index,
838 prevout_script_pubkeys,
839 script_code,
840 sighash_byte,
841 ) {
842 #[cfg(all(feature = "production", feature = "profile"))]
843 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
844 #[cfg(feature = "production")]
845 insert_midstate_cache(
846 sighash_cache,
847 tx.inputs[input_index].prevout,
848 script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]),
849 sighash_byte as u8,
850 h,
851 );
852 return Ok(h);
853 }
854 }
855 }
856 }
857
858 let estimated_size = 4 + 2 + (tx.inputs.len() * 50) + 2 + (tx.outputs.len() * 30) + 4 + 4;
860 let capacity = estimated_size.min(4096);
861
862 #[cfg(feature = "production")]
863 let (result, preimage_vec) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
864 let mut preimage = buf_cell.borrow_mut();
865 preimage.clear();
866 if preimage.capacity() < capacity {
867 preimage.reserve(capacity);
868 }
869 build_preimage_and_hash(
870 tx,
871 input_index,
872 prevout_values,
873 prevout_script_pubkeys,
874 script_code,
875 sighash_byte,
876 anyone_can_pay,
877 hash_none,
878 hash_single,
879 &mut preimage,
880 )
881 });
882
883 #[cfg(not(feature = "production"))]
884 let (result, preimage_vec) = {
885 let mut preimage = Vec::with_capacity(capacity);
886 build_preimage_and_hash(
887 tx,
888 input_index,
889 prevout_values,
890 prevout_script_pubkeys,
891 script_code,
892 sighash_byte,
893 anyone_can_pay,
894 hash_none,
895 hash_single,
896 &mut preimage,
897 )
898 };
899
900 #[cfg(all(feature = "production", feature = "profile"))]
901 crate::script_profile::add_sighash_ns(_t0.elapsed().as_nanos() as u64);
902
903 #[cfg(feature = "production")]
904 if let Ok(ref h) = result {
905 insert_midstate_cache(
906 sighash_cache,
907 tx.inputs[input_index].prevout,
908 script_code.unwrap_or_else(|| prevout_script_pubkeys[input_index]),
909 sighash_byte as u8,
910 *h,
911 );
912 }
913 result
914}
915
916#[cfg(feature = "production")]
918#[inline]
919fn build_preimage_1in1out_sighash_all(
920 tx: &crate::types::Transaction,
921 prevout_values: &[i64],
922 prevout_script_pubkeys: &[&[u8]],
923 script_code: Option<&[u8]>,
924 sighash_byte: u32,
925) -> Result<Hash> {
926 let input = &tx.inputs[0];
927 let output = &tx.outputs[0];
928 let code = script_code.unwrap_or_else(|| prevout_script_pubkeys[0]);
929
930 let capacity = 4 + 2 + 36 + 2 + code.len() + 4 + 2 + 8 + 2 + output.script_pubkey.len() + 4 + 4;
931 let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
932 let mut preimage = buf_cell.borrow_mut();
933 preimage.clear();
934 if preimage.capacity() < capacity {
935 preimage.reserve(capacity);
936 }
937 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
938 preimage.push(1); preimage.extend_from_slice(&input.prevout.hash);
940 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
941 write_varint_to_vec(&mut preimage, code.len() as u64);
942 preimage.extend_from_slice(code);
943 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
944 preimage.push(1); preimage.extend_from_slice(&output.value.to_le_bytes());
946 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
947 preimage.extend_from_slice(&output.script_pubkey);
948 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
949 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
950 let r = sighash_with_cache(&preimage);
951 (Ok(r), ())
952 });
953 result
954}
955
956#[cfg(feature = "production")]
958#[inline]
959fn build_preimage_1in_nout_sighash_all(
960 tx: &crate::types::Transaction,
961 prevout_script_pubkeys: &[&[u8]],
962 script_code: Option<&[u8]>,
963 sighash_byte: u32,
964) -> Result<Hash> {
965 let input = &tx.inputs[0];
966 let code = script_code.unwrap_or_else(|| prevout_script_pubkeys[0]);
967 let mut capacity = 4 + 2 + 36 + 2 + code.len() + 4 + 2; for out in &tx.outputs {
969 capacity += 8 + 2 + out.script_pubkey.len();
970 }
971 capacity += 4 + 4; let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
974 let mut preimage = buf_cell.borrow_mut();
975 preimage.clear();
976 if preimage.capacity() < capacity {
977 preimage.reserve(capacity);
978 }
979 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
980 preimage.push(1); preimage.extend_from_slice(&input.prevout.hash);
982 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
983 write_varint_to_vec(&mut preimage, code.len() as u64);
984 preimage.extend_from_slice(code);
985 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
986 write_varint_to_vec(&mut preimage, tx.outputs.len() as u64);
987 for output in &tx.outputs {
988 preimage.extend_from_slice(&output.value.to_le_bytes());
989 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
990 preimage.extend_from_slice(&output.script_pubkey);
991 }
992 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
993 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
994 let r = sighash_with_cache(&preimage);
995 (Ok(r), ())
996 });
997 result
998}
999
1000#[cfg(feature = "production")]
1003#[inline]
1004fn build_preimage_2in1out_sighash_all(
1005 tx: &crate::types::Transaction,
1006 input_index: usize,
1007 _prevout_values: &[i64],
1008 prevout_script_pubkeys: &[&[u8]],
1009 script_code: Option<&[u8]>,
1010 sighash_byte: u32,
1011) -> Result<Hash> {
1012 let output = &tx.outputs[0];
1013 let code_len = script_code
1014 .map(|s| s.len())
1015 .unwrap_or_else(|| prevout_script_pubkeys[input_index].len());
1016 let capacity =
1017 4 + 2 + 36 + 2 + code_len + 4 + 36 + 2 + 4 + 8 + 2 + output.script_pubkey.len() + 4 + 4;
1018
1019 let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
1020 let mut preimage = buf_cell.borrow_mut();
1021 preimage.clear();
1022 if preimage.capacity() < capacity {
1023 preimage.reserve(capacity);
1024 }
1025 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1026 preimage.push(2);
1027 for (i, inp) in tx.inputs.iter().enumerate().take(2) {
1028 let (script_len, script_slice): (usize, &[u8]) = if i == input_index {
1029 let c = script_code.unwrap_or_else(|| prevout_script_pubkeys[i]);
1030 (c.len(), c)
1031 } else {
1032 (0, &[][..]) };
1034 preimage.extend_from_slice(&inp.prevout.hash);
1035 preimage.extend_from_slice(&inp.prevout.index.to_le_bytes());
1036 write_varint_to_vec(&mut preimage, script_len as u64);
1037 preimage.extend_from_slice(script_slice);
1038 preimage.extend_from_slice(&(inp.sequence as u32).to_le_bytes());
1039 }
1040 preimage.push(1);
1041 preimage.extend_from_slice(&output.value.to_le_bytes());
1042 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
1043 preimage.extend_from_slice(&output.script_pubkey);
1044 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1045 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1046 let r = sighash_with_cache(&preimage);
1047 (Ok(r), ())
1048 });
1049 result
1050}
1051
1052#[cfg(feature = "production")]
1055#[inline]
1056fn build_preimage_2in2out_sighash_all(
1057 tx: &crate::types::Transaction,
1058 input_index: usize,
1059 prevout_script_pubkeys: &[&[u8]],
1060 script_code: Option<&[u8]>,
1061 sighash_byte: u32,
1062) -> Result<Hash> {
1063 let code_len = script_code
1064 .map(|s| s.len())
1065 .unwrap_or_else(|| prevout_script_pubkeys[input_index].len());
1066 let mut capacity = 4 + 2 + 36 + 2 + code_len + 4 + 36 + 2 + 4;
1067 for out in &tx.outputs {
1068 capacity += 8 + 2 + out.script_pubkey.len();
1069 }
1070 capacity += 4 + 4;
1071
1072 let (result, _) = SIGHASH_PREIMAGE_BUF.with(|buf_cell| {
1073 let mut preimage = buf_cell.borrow_mut();
1074 preimage.clear();
1075 if preimage.capacity() < capacity {
1076 preimage.reserve(capacity);
1077 }
1078 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1079 preimage.push(2);
1080 for (i, inp) in tx.inputs.iter().enumerate().take(2) {
1081 let (script_len, script_slice): (usize, &[u8]) = if i == input_index {
1082 let c = script_code.unwrap_or_else(|| prevout_script_pubkeys[i]);
1083 (c.len(), c)
1084 } else {
1085 (0, &[][..])
1086 };
1087 preimage.extend_from_slice(&inp.prevout.hash);
1088 preimage.extend_from_slice(&inp.prevout.index.to_le_bytes());
1089 write_varint_to_vec(&mut preimage, script_len as u64);
1090 preimage.extend_from_slice(script_slice);
1091 preimage.extend_from_slice(&(inp.sequence as u32).to_le_bytes());
1092 }
1093 write_varint_to_vec(&mut preimage, 2);
1094 for output in &tx.outputs {
1095 preimage.extend_from_slice(&output.value.to_le_bytes());
1096 write_varint_to_vec(&mut preimage, output.script_pubkey.len() as u64);
1097 preimage.extend_from_slice(&output.script_pubkey);
1098 }
1099 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1100 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1101 let r = sighash_with_cache(&preimage);
1102 (Ok(r), ())
1103 });
1104 result
1105}
1106
1107#[inline]
1108fn build_preimage_and_hash(
1109 tx: &crate::types::Transaction,
1110 input_index: usize,
1111 prevout_values: &[i64],
1112 prevout_script_pubkeys: &[&[u8]],
1113 script_code: Option<&[u8]>,
1114 sighash_byte: u32,
1115 anyone_can_pay: bool,
1116 hash_none: bool,
1117 hash_single: bool,
1118 preimage: &mut Vec<u8>,
1119) -> (Result<Hash>, ()) {
1120 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1122
1123 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
1125 write_varint_to_vec(preimage, n_inputs as u64);
1126
1127 for i in 0..n_inputs {
1129 let actual_i = if anyone_can_pay { input_index } else { i };
1131 let input = &tx.inputs[actual_i];
1132
1133 preimage.extend_from_slice(&input.prevout.hash);
1135 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1136
1137 if actual_i == input_index {
1139 let code = match script_code {
1140 Some(s) => s,
1141 None => prevout_script_pubkeys[actual_i],
1142 };
1143 write_varint_to_vec(preimage, code.len() as u64);
1144 preimage.extend_from_slice(code);
1145 } else {
1146 preimage.push(0); }
1148
1149 if actual_i != input_index && (hash_single || hash_none) {
1151 preimage.extend_from_slice(&0u32.to_le_bytes());
1152 } else {
1153 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1154 }
1155 }
1156
1157 let n_outputs = if hash_none {
1159 0
1160 } else if hash_single {
1161 input_index + 1
1162 } else {
1163 tx.outputs.len()
1164 };
1165 write_varint_to_vec(preimage, n_outputs as u64);
1166
1167 for i in 0..n_outputs {
1169 if hash_single && i != input_index {
1170 preimage.extend_from_slice(&(-1i64).to_le_bytes()); preimage.push(0); } else {
1174 let output = &tx.outputs[i];
1175 preimage.extend_from_slice(&output.value.to_le_bytes());
1176 write_varint_to_vec(preimage, output.script_pubkey.len() as u64);
1177 preimage.extend_from_slice(&output.script_pubkey);
1178 }
1179 }
1180
1181 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1183
1184 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1186
1187 #[cfg(feature = "production")]
1189 let result = sighash_with_cache(preimage);
1190 #[cfg(not(feature = "production"))]
1191 let result = {
1192 let hasher = OptimizedSha256::new();
1193 let first_hash = hasher.hash(&preimage);
1194 let second_hash = hasher.hash(&first_hash);
1195 let mut r = [0u8; 32];
1196 r.copy_from_slice(&second_hash);
1197 r
1198 };
1199 (Ok(result), ())
1200}
1201
1202#[spec_locked("5.1.1")]
1216pub fn batch_compute_sighashes(
1217 tx: &Transaction,
1218 prevouts: &[TransactionOutput],
1219 sighash_type: SighashType,
1220) -> Result<Vec<Hash>> {
1221 if prevouts.len() != tx.inputs.len() {
1223 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
1224 prevouts.len(),
1225 tx.inputs.len(),
1226 ));
1227 }
1228
1229 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
1231 let prevout_script_pubkeys: Vec<&[u8]> =
1232 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
1233
1234 #[cfg(feature = "production")]
1235 {
1236 let sighash_byte = sighash_type.as_u32() as u8;
1239 let specs: Vec<(usize, u8, &[u8])> = (0..tx.inputs.len())
1240 .map(|i| (i, sighash_byte, prevout_script_pubkeys[i]))
1241 .collect();
1242 let hashes =
1243 batch_compute_legacy_sighashes(tx, &prevout_values, &prevout_script_pubkeys, &specs)?;
1244 Ok(hashes)
1245 }
1246
1247 #[cfg(not(feature = "production"))]
1248 {
1249 let mut results = Vec::with_capacity(tx.inputs.len());
1251 for i in 0..tx.inputs.len() {
1252 results.push(calculate_transaction_sighash_with_script_code(
1253 tx,
1254 i,
1255 &prevout_values,
1256 &prevout_script_pubkeys,
1257 sighash_type,
1258 None,
1259 )?);
1260 }
1261 Ok(results)
1262 }
1263}
1264
1265#[cfg(feature = "production")]
1267fn build_legacy_sighash_preimage_into(
1268 preimage: &mut Vec<u8>,
1269 tx: &Transaction,
1270 input_index: usize,
1271 prevout_values: &[i64],
1272 prevout_script_pubkeys: &[&[u8]],
1273 script_code: &[u8],
1274 sighash_byte: u32,
1275) {
1276 let anyone_can_pay = (sighash_byte & 0x80) != 0;
1277 let hash_none = (sighash_byte & 0x1f) == 0x02;
1278 let hash_single = (sighash_byte & 0x1f) == 0x03;
1279 let n_inputs = if anyone_can_pay { 1 } else { tx.inputs.len() };
1280 let n_outputs = if hash_none {
1281 0
1282 } else if hash_single {
1283 input_index + 1
1284 } else {
1285 tx.outputs.len()
1286 };
1287 preimage.clear();
1288 preimage.reserve(512);
1289 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1290 write_varint_to_vec(preimage, n_inputs as u64);
1291 for i in 0..n_inputs {
1292 let actual_i = if anyone_can_pay { input_index } else { i };
1293 let input = &tx.inputs[actual_i];
1294 preimage.extend_from_slice(&input.prevout.hash);
1295 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1296 if actual_i == input_index {
1297 write_varint_to_vec(preimage, script_code.len() as u64);
1298 preimage.extend_from_slice(script_code);
1299 } else {
1300 preimage.push(0);
1301 }
1302 if actual_i != input_index && (hash_single || hash_none) {
1303 preimage.extend_from_slice(&0u32.to_le_bytes());
1304 } else {
1305 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1306 }
1307 }
1308 write_varint_to_vec(preimage, n_outputs as u64);
1309 for i in 0..n_outputs {
1310 let use_missing_output =
1312 hash_single && (i != input_index || input_index >= tx.outputs.len());
1313 if use_missing_output {
1314 preimage.extend_from_slice(&(-1i64).to_le_bytes());
1315 preimage.push(0);
1316 } else {
1317 let output = &tx.outputs[i];
1318 preimage.extend_from_slice(&output.value.to_le_bytes());
1319 write_varint_to_vec(preimage, output.script_pubkey.len() as u64);
1320 preimage.extend_from_slice(&output.script_pubkey);
1321 }
1322 }
1323 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1324 preimage.extend_from_slice(&sighash_byte.to_le_bytes());
1325}
1326
1327#[cfg(feature = "production")]
1332#[spec_locked("5.1.1")]
1333pub fn batch_compute_legacy_sighashes(
1334 tx: &Transaction,
1335 prevout_values: &[i64],
1336 prevout_script_pubkeys: &[&[u8]],
1337 specs: &[(usize, u8, &[u8])],
1338) -> Result<Vec<[u8; 32]>> {
1339 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
1340 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
1341 prevout_values.len(),
1342 tx.inputs.len(),
1343 ));
1344 }
1345 const SIGHASH_SINGLE_INVALID: [u8; 32] = {
1347 let mut h = [0u8; 32];
1348 h[0] = 1;
1349 h
1350 };
1351
1352 LEGACY_BATCH_PREIMAGES.with(|cell| {
1353 let mut storage = cell.borrow_mut();
1354 storage.resize_with(specs.len(), || Vec::with_capacity(512));
1355 let mut fixed_indices: Vec<usize> = Vec::new();
1356 for (i, &(input_index, sighash_byte, script_code)) in specs.iter().enumerate() {
1357 let hash_single = (sighash_byte & 0x1f) == 0x03;
1358 if hash_single && input_index >= tx.outputs.len() {
1359 fixed_indices.push(i);
1360 continue;
1361 }
1362 build_legacy_sighash_preimage_into(
1363 &mut storage[i],
1364 tx,
1365 input_index,
1366 prevout_values,
1367 prevout_script_pubkeys,
1368 script_code,
1369 sighash_byte as u32,
1370 );
1371 }
1372 let preimage_refs: Vec<&[u8]> = storage
1374 .iter()
1375 .enumerate()
1376 .filter(|(i, _)| !fixed_indices.contains(i))
1377 .map(|(_, v)| v.as_slice())
1378 .collect();
1379 let batch_hashes =
1380 crate::optimizations::simd_vectorization::batch_double_sha256(&preimage_refs);
1381 let mut result = vec![[0u8; 32]; specs.len()];
1383 let mut batch_idx = 0;
1384 for (i, slot) in result.iter_mut().enumerate() {
1385 if fixed_indices.contains(&i) {
1386 *slot = SIGHASH_SINGLE_INVALID;
1387 } else {
1388 *slot = batch_hashes[batch_idx];
1389 batch_idx += 1;
1390 }
1391 }
1392 Ok(result)
1393 })
1394}
1395
1396#[cfg(all(feature = "production", feature = "benchmarking"))]
1399pub fn clear_sighash_templates() {
1400 SIGHASH_CACHE.with(|cell| {
1401 cell.borrow_mut().clear();
1402 });
1403}
1404
1405fn encode_varint(value: u64) -> Vec<u8> {
1406 if value < 0xfd {
1407 vec![value as u8]
1408 } else if value <= 0xffff {
1409 let mut result = vec![0xfd];
1410 result.extend_from_slice(&(value as u16).to_le_bytes());
1411 result
1412 } else if value <= 0xffffffff {
1413 let mut result = vec![0xfe];
1414 result.extend_from_slice(&(value as u32).to_le_bytes());
1415 result
1416 } else {
1417 let mut result = vec![0xff];
1418 result.extend_from_slice(&value.to_le_bytes());
1419 result
1420 }
1421}
1422
1423#[derive(Clone, Debug)]
1436pub struct Bip143PrecomputedHashes {
1437 pub hash_prevouts: [u8; 32],
1439 pub hash_sequence: [u8; 32],
1441 pub hash_outputs: [u8; 32],
1443}
1444
1445impl Bip143PrecomputedHashes {
1446 #[inline]
1450 pub fn compute(
1451 tx: &Transaction,
1452 _prevout_values: &[i64],
1453 _prevout_script_pubkeys: &[&[u8]],
1454 ) -> Self {
1455 #[cfg(feature = "production")]
1456 {
1457 let hash_prevouts = BIP143_SERIALIZE_BUF.with(|cell| {
1458 let mut data = cell.borrow_mut();
1459 data.clear();
1460 data.reserve(tx.inputs.len() * 36);
1461 for input in tx.inputs.iter() {
1462 data.extend_from_slice(&input.prevout.hash);
1463 data.extend_from_slice(&input.prevout.index.to_le_bytes());
1464 }
1465 double_sha256(&data)
1466 });
1467
1468 let hash_sequence = BIP143_SERIALIZE_BUF.with(|cell| {
1469 let mut data = cell.borrow_mut();
1470 data.clear();
1471 data.reserve(tx.inputs.len() * 4);
1472 for input in tx.inputs.iter() {
1473 data.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1474 }
1475 double_sha256(&data)
1476 });
1477
1478 let hash_outputs = BIP143_SERIALIZE_BUF.with(|cell| {
1479 let mut data = cell.borrow_mut();
1480 data.clear();
1481 let cap = tx
1482 .outputs
1483 .iter()
1484 .map(|o| 8 + 5 + o.script_pubkey.len())
1485 .sum::<usize>();
1486 data.reserve(cap);
1487 for output in tx.outputs.iter() {
1488 data.extend_from_slice(&output.value.to_le_bytes());
1489 write_varint_to_vec(&mut data, output.script_pubkey.len() as u64);
1490 data.extend_from_slice(&output.script_pubkey);
1491 }
1492 double_sha256(&data)
1493 });
1494
1495 Self {
1496 hash_prevouts,
1497 hash_sequence,
1498 hash_outputs,
1499 }
1500 }
1501
1502 #[cfg(not(feature = "production"))]
1503 {
1504 let hash_prevouts = {
1506 let mut data = Vec::with_capacity(tx.inputs.len() * 36);
1507 for input in tx.inputs.iter() {
1508 data.extend_from_slice(&input.prevout.hash);
1509 data.extend_from_slice(&input.prevout.index.to_le_bytes());
1510 }
1511 double_sha256(&data)
1512 };
1513
1514 let hash_sequence = {
1515 let mut data = Vec::with_capacity(tx.inputs.len() * 4);
1516 for input in tx.inputs.iter() {
1517 data.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1518 }
1519 double_sha256(&data)
1520 };
1521
1522 let hash_outputs = {
1523 let mut data = Vec::with_capacity(tx.outputs.len() * 34);
1524 for output in tx.outputs.iter() {
1525 data.extend_from_slice(&output.value.to_le_bytes());
1526 write_varint_to_vec(&mut data, output.script_pubkey.len() as u64);
1527 data.extend_from_slice(&output.script_pubkey);
1528 }
1529 double_sha256(&data)
1530 };
1531
1532 Self {
1533 hash_prevouts,
1534 hash_sequence,
1535 hash_outputs,
1536 }
1537 }
1538 }
1539}
1540
1541#[inline(always)]
1543fn double_sha256(data: &[u8]) -> [u8; 32] {
1544 let hasher = OptimizedSha256::new();
1545 hasher.hash256(data)
1546}
1547
1548#[spec_locked("11.1.9")]
1565pub fn calculate_bip143_sighash(
1566 tx: &Transaction,
1567 input_index: usize,
1568 script_code: &[u8],
1569 amount: i64,
1570 sighash_type: u8,
1571 precomputed: Option<&Bip143PrecomputedHashes>,
1572) -> Result<Hash> {
1573 if input_index >= tx.inputs.len() {
1574 return Err(crate::error::ConsensusError::InvalidInputIndex(input_index));
1575 }
1576
1577 let anyone_can_pay = (sighash_type & 0x80) != 0;
1579 let base_type = sighash_type & 0x1f;
1580 let is_none = base_type == 0x02;
1581 let is_single = base_type == 0x03;
1582
1583 let computed;
1585 let hashes = match precomputed {
1586 Some(h) => h,
1587 None => {
1588 computed = Bip143PrecomputedHashes::compute(tx, &[], &[]);
1589 &computed
1590 }
1591 };
1592
1593 #[cfg(feature = "production")]
1596 let preimage_result = BIP143_PREIMAGE_BUF.with(|buf_cell| {
1597 let mut preimage = buf_cell.borrow_mut();
1598 preimage.clear();
1599 let cap = 160 + script_code.len();
1600 if preimage.capacity() < cap {
1601 preimage.reserve(cap);
1602 }
1603 build_bip143_preimage(
1604 tx,
1605 input_index,
1606 script_code,
1607 amount,
1608 sighash_type,
1609 anyone_can_pay,
1610 is_none,
1611 is_single,
1612 hashes,
1613 &mut preimage,
1614 )
1615 });
1616 #[cfg(not(feature = "production"))]
1617 let preimage_result = {
1618 let mut preimage = Vec::with_capacity(160 + script_code.len());
1619 build_bip143_preimage(
1620 tx,
1621 input_index,
1622 script_code,
1623 amount,
1624 sighash_type,
1625 anyone_can_pay,
1626 is_none,
1627 is_single,
1628 hashes,
1629 &mut preimage,
1630 )
1631 };
1632 preimage_result
1633}
1634
1635#[inline]
1636fn build_bip143_preimage(
1637 tx: &Transaction,
1638 input_index: usize,
1639 script_code: &[u8],
1640 amount: i64,
1641 sighash_type: u8,
1642 anyone_can_pay: bool,
1643 is_none: bool,
1644 is_single: bool,
1645 hashes: &Bip143PrecomputedHashes,
1646 preimage: &mut Vec<u8>,
1647) -> Result<Hash> {
1648 preimage.extend_from_slice(&(tx.version as u32).to_le_bytes());
1650
1651 if anyone_can_pay {
1653 preimage.extend_from_slice(&[0u8; 32]);
1654 } else {
1655 preimage.extend_from_slice(&hashes.hash_prevouts);
1656 }
1657
1658 if anyone_can_pay || is_none || is_single {
1660 preimage.extend_from_slice(&[0u8; 32]);
1661 } else {
1662 preimage.extend_from_slice(&hashes.hash_sequence);
1663 }
1664
1665 let input = &tx.inputs[input_index];
1667 preimage.extend_from_slice(&input.prevout.hash);
1668 preimage.extend_from_slice(&input.prevout.index.to_le_bytes());
1669
1670 write_varint_to_vec(preimage, script_code.len() as u64);
1672 preimage.extend_from_slice(script_code);
1673
1674 preimage.extend_from_slice(&amount.to_le_bytes());
1676
1677 preimage.extend_from_slice(&(input.sequence as u32).to_le_bytes());
1679
1680 if is_none {
1682 preimage.extend_from_slice(&[0u8; 32]);
1683 } else if is_single {
1684 if input_index < tx.outputs.len() {
1685 let output = &tx.outputs[input_index];
1687 #[cfg(feature = "production")]
1688 let hash_outputs = BIP143_SINGLE_OUTPUT_BUF.with(|buf_cell| {
1689 let mut output_data = buf_cell.borrow_mut();
1690 output_data.clear();
1691 let cap = 8 + 9 + output.script_pubkey.len(); if output_data.capacity() < cap {
1693 output_data.reserve(cap);
1694 }
1695 output_data.extend_from_slice(&output.value.to_le_bytes());
1696 write_varint_to_vec(&mut output_data, output.script_pubkey.len() as u64);
1697 output_data.extend_from_slice(&output.script_pubkey);
1698 double_sha256(&output_data)
1699 });
1700 #[cfg(not(feature = "production"))]
1701 let hash_outputs = {
1702 let mut output_data = Vec::with_capacity(8 + 9 + output.script_pubkey.len());
1703 output_data.extend_from_slice(&output.value.to_le_bytes());
1704 write_varint_to_vec(&mut output_data, output.script_pubkey.len() as u64);
1705 output_data.extend_from_slice(&output.script_pubkey);
1706 double_sha256(&output_data)
1707 };
1708 preimage.extend_from_slice(&hash_outputs);
1709 } else {
1710 preimage.extend_from_slice(&[0u8; 32]);
1712 }
1713 } else {
1714 preimage.extend_from_slice(&hashes.hash_outputs);
1715 }
1716
1717 preimage.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
1719
1720 preimage.extend_from_slice(&(sighash_type as u32).to_le_bytes());
1722
1723 Ok(double_sha256(preimage))
1725}
1726
1727#[spec_locked("11.1.9")]
1731pub fn batch_compute_bip143_sighashes(
1732 tx: &Transaction,
1733 prevout_values: &[i64],
1734 prevout_script_pubkeys: &[&[u8]],
1735 script_codes: &[&[u8]],
1736 sighash_type: u8,
1737) -> Result<Vec<Hash>> {
1738 if prevout_values.len() != tx.inputs.len()
1739 || prevout_script_pubkeys.len() != tx.inputs.len()
1740 || script_codes.len() != tx.inputs.len()
1741 {
1742 return Err(crate::error::ConsensusError::InvalidPrevoutsCount(
1743 prevout_values.len(),
1744 tx.inputs.len(),
1745 ));
1746 }
1747
1748 let precomputed = Bip143PrecomputedHashes::compute(tx, prevout_values, prevout_script_pubkeys);
1750
1751 let mut results = Vec::with_capacity(tx.inputs.len());
1753 for (i, (value, script_code)) in prevout_values.iter().zip(script_codes.iter()).enumerate() {
1754 let sighash =
1755 calculate_bip143_sighash(tx, i, script_code, *value, sighash_type, Some(&precomputed))?;
1756 results.push(sighash);
1757 }
1758 Ok(results)
1759}
1760
1761#[cfg(test)]
1762mod tests {
1763 use super::*;
1764 use crate::opcodes::*;
1765
1766 #[test]
1767 fn test_sighash_type_parsing() {
1768 assert_eq!(SighashType::from_byte(0x01), SighashType::ALL);
1770 assert_eq!(SighashType::from_byte(0x02), SighashType::NONE);
1771 assert_eq!(SighashType::from_byte(0x03), SighashType::SINGLE);
1772 assert_eq!(SighashType::from_byte(0x00), SighashType::ALL_LEGACY);
1773 assert_eq!(SighashType::from_byte(0x81), SighashType::ALL_ANYONECANPAY);
1774 assert_eq!(SighashType::from_byte(0x82), SighashType::NONE_ANYONECANPAY);
1775 assert_eq!(
1776 SighashType::from_byte(0x83),
1777 SighashType::SINGLE_ANYONECANPAY
1778 );
1779 assert_eq!(SighashType::ALL_ANYONECANPAY.as_u32(), 0x81);
1781 assert_eq!(SighashType::NONE_ANYONECANPAY.as_u32(), 0x82);
1782 assert_eq!(SighashType::SINGLE_ANYONECANPAY.as_u32(), 0x83);
1783 let st = SighashType::from_byte(0x04);
1785 assert!(st.is_all()); assert_eq!(st.as_u32(), 0x04); let st84 = SighashType::from_byte(0x84);
1788 assert!(st84.is_all());
1789 assert!(st84.is_anyonecanpay());
1790 assert_eq!(st84.as_u32(), 0x84);
1791 }
1792
1793 #[test]
1794 fn test_varint_encoding() {
1795 assert_eq!(encode_varint(0), vec![0]);
1796 assert_eq!(encode_varint(252), vec![252]);
1797 assert_eq!(encode_varint(253), vec![0xfd, 253, 0]);
1798 assert_eq!(encode_varint(65535), vec![0xfd, 255, 255]);
1799 assert_eq!(encode_varint(65536), vec![0xfe, 0, 0, 1, 0]);
1800 }
1801
1802 #[test]
1803 fn test_sighash_calculation() {
1804 let tx = Transaction {
1806 version: 1,
1807 inputs: vec![TransactionInput {
1808 prevout: OutPoint {
1809 hash: [1u8; 32].into(),
1810 index: 0,
1811 },
1812 script_sig: vec![OP_1],
1813 sequence: 0xffffffff,
1814 }]
1815 .into(),
1816 outputs: vec![TransactionOutput {
1817 value: 5000000000,
1818 script_pubkey: vec![
1819 OP_DUP,
1820 OP_HASH160,
1821 PUSH_20_BYTES,
1822 0x89,
1823 0xab,
1824 0xcd,
1825 0xef,
1826 0x12,
1827 0x34,
1828 0x56,
1829 0x78,
1830 0x9a,
1831 0xbc,
1832 0xde,
1833 0xf0,
1834 0x12,
1835 0x34,
1836 0x56,
1837 0x78,
1838 0x9a,
1839 OP_EQUALVERIFY,
1840 OP_CHECKSIG,
1841 ]
1842 .into(), }]
1844 .into(),
1845 lock_time: 0,
1846 };
1847
1848 let prevouts = vec![TransactionOutput {
1849 value: 10000000000,
1850 script_pubkey: vec![
1851 OP_DUP,
1852 OP_HASH160,
1853 PUSH_20_BYTES,
1854 0x89,
1855 0xab,
1856 0xcd,
1857 0xef,
1858 0x12,
1859 0x34,
1860 0x56,
1861 0x78,
1862 0x9a,
1863 0xbc,
1864 0xde,
1865 0xf0,
1866 0x12,
1867 0x34,
1868 0x56,
1869 0x78,
1870 0x9a,
1871 OP_EQUALVERIFY,
1872 OP_CHECKSIG,
1873 ],
1874 }];
1875
1876 let sighash = calculate_transaction_sighash(&tx, 0, &prevouts, SighashType::ALL).unwrap();
1878 assert_eq!(sighash.len(), 32);
1879
1880 let sighash_none =
1882 calculate_transaction_sighash(&tx, 0, &prevouts, SighashType::NONE).unwrap();
1883 assert_ne!(sighash, sighash_none);
1884
1885 let sighash_single =
1887 calculate_transaction_sighash(&tx, 0, &prevouts, SighashType::SINGLE).unwrap();
1888 assert_ne!(sighash, sighash_single);
1889 }
1890
1891 #[test]
1892 fn test_sighash_invalid_input_index() {
1893 let tx = Transaction {
1894 version: 1,
1895 inputs: vec![].into(),
1896 outputs: vec![].into(),
1897 lock_time: 0,
1898 };
1899
1900 let result = calculate_transaction_sighash(&tx, 0, &[], SighashType::ALL);
1901 assert!(result.is_err());
1902 }
1903
1904 #[test]
1905 fn test_bip143_sighash() {
1906 let tx = Transaction {
1908 version: 1,
1909 inputs: vec![
1910 TransactionInput {
1911 prevout: OutPoint {
1912 hash: [1u8; 32].into(),
1913 index: 0,
1914 },
1915 script_sig: vec![], sequence: 0xffffffff,
1917 },
1918 TransactionInput {
1919 prevout: OutPoint {
1920 hash: [2u8; 32].into(),
1921 index: 1,
1922 },
1923 script_sig: vec![],
1924 sequence: 0xfffffffe,
1925 },
1926 ]
1927 .into(),
1928 outputs: vec![TransactionOutput {
1929 value: 5000000000,
1930 script_pubkey: vec![
1931 OP_0,
1932 PUSH_20_BYTES,
1933 0x89,
1934 0xab,
1935 0xcd,
1936 0xef,
1937 0x12,
1938 0x34,
1939 0x56,
1940 0x78,
1941 0x9a,
1942 0xbc,
1943 0xde,
1944 0xf0,
1945 0x12,
1946 0x34,
1947 0x56,
1948 0x78,
1949 0x9a,
1950 0xbc,
1951 0xde,
1952 0xf0,
1953 ]
1954 .into(),
1955 }]
1956 .into(),
1957 lock_time: 0,
1958 };
1959
1960 let prevouts = vec![
1961 TransactionOutput {
1962 value: 10000000000,
1963 script_pubkey: vec![
1964 OP_0,
1965 PUSH_20_BYTES,
1966 0x11,
1967 0x22,
1968 0x33,
1969 0x44,
1970 0x55,
1971 0x66,
1972 0x77,
1973 0x88,
1974 0x99,
1975 0xaa,
1976 0xbb,
1977 0xcc,
1978 0xdd,
1979 0xee,
1980 0xff,
1981 0x00,
1982 0x11,
1983 0x22,
1984 0x33,
1985 0x44,
1986 ],
1987 },
1988 TransactionOutput {
1989 value: 8000000000,
1990 script_pubkey: vec![
1991 OP_0,
1992 PUSH_20_BYTES,
1993 0xaa,
1994 0xbb,
1995 0xcc,
1996 0xdd,
1997 0xee,
1998 0xff,
1999 0x00,
2000 0x11,
2001 0x22,
2002 0x33,
2003 0x44,
2004 0x55,
2005 0x66,
2006 0x77,
2007 0x88,
2008 0x99,
2009 0xaa,
2010 0xbb,
2011 0xcc,
2012 0xdd,
2013 ],
2014 },
2015 ];
2016
2017 let script_code = vec![
2019 OP_DUP,
2020 OP_HASH160,
2021 PUSH_20_BYTES,
2022 0x11,
2023 0x22,
2024 0x33,
2025 0x44,
2026 0x55,
2027 0x66,
2028 0x77,
2029 0x88,
2030 0x99,
2031 0xaa,
2032 0xbb,
2033 0xcc,
2034 0xdd,
2035 0xee,
2036 0xff,
2037 0x00,
2038 0x11,
2039 0x22,
2040 0x33,
2041 OP_EQUALVERIFY,
2042 OP_CHECKSIG,
2043 ];
2044
2045 let sighash0 =
2047 calculate_bip143_sighash(&tx, 0, &script_code, prevouts[0].value, 0x01, None).unwrap();
2048 assert_eq!(sighash0.len(), 32);
2049
2050 let sighash1 =
2052 calculate_bip143_sighash(&tx, 1, &script_code, prevouts[1].value, 0x01, None).unwrap();
2053 assert_ne!(sighash0, sighash1);
2054
2055 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
2057 let prevout_script_pubkeys: Vec<&[u8]> =
2058 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
2059 let precomputed =
2060 Bip143PrecomputedHashes::compute(&tx, &prevout_values, &prevout_script_pubkeys);
2061 let sighash0_precomputed = calculate_bip143_sighash(
2062 &tx,
2063 0,
2064 &script_code,
2065 prevout_values[0],
2066 0x01,
2067 Some(&precomputed),
2068 )
2069 .unwrap();
2070 assert_eq!(sighash0, sighash0_precomputed);
2071 }
2072
2073 #[test]
2074 fn test_bip143_anyonecanpay() {
2075 let tx = Transaction {
2076 version: 1,
2077 inputs: vec![TransactionInput {
2078 prevout: OutPoint {
2079 hash: [1u8; 32].into(),
2080 index: 0,
2081 },
2082 script_sig: vec![],
2083 sequence: 0xffffffff,
2084 }]
2085 .into(),
2086 outputs: vec![TransactionOutput {
2087 value: 5000000000,
2088 script_pubkey: vec![OP_0, PUSH_20_BYTES].into(),
2089 }]
2090 .into(),
2091 lock_time: 0,
2092 };
2093
2094 let script_code = {
2095 let mut s = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
2096 s.extend_from_slice(&[0u8; 20]); s.push(OP_EQUALVERIFY);
2098 s.push(OP_CHECKSIG);
2099 s };
2101 let amount = 10000000000i64;
2102
2103 let sighash_all =
2105 calculate_bip143_sighash(&tx, 0, &script_code, amount, 0x01, None).unwrap();
2106
2107 let sighash_anyonecanpay =
2109 calculate_bip143_sighash(&tx, 0, &script_code, amount, 0x81, None).unwrap();
2110
2111 assert_ne!(sighash_all, sighash_anyonecanpay);
2113 }
2114
2115 #[test]
2119 fn test_2input_legacy_sighash_non_signing_empty_script() {
2120 let script_a = vec![
2122 PUSH_33_BYTES,
2123 0x02,
2124 0x00,
2125 0x00,
2126 0x00,
2127 0x00,
2128 0x00,
2129 0x00,
2130 0x00,
2131 0x00,
2132 0x00,
2133 0x00,
2134 0x00,
2135 0x00,
2136 0x00,
2137 0x00,
2138 0x00,
2139 0x00,
2140 0x00,
2141 0x00,
2142 0x00,
2143 0x00,
2144 0x00,
2145 0x00,
2146 0x00,
2147 0x00,
2148 0x00,
2149 0x00,
2150 0x00,
2151 0x00,
2152 0x00,
2153 0x00,
2154 OP_CHECKSIG,
2155 ]; let script_b = vec![
2157 PUSH_33_BYTES,
2158 0x03,
2159 0x11,
2160 0x11,
2161 0x11,
2162 0x11,
2163 0x11,
2164 0x11,
2165 0x11,
2166 0x11,
2167 0x11,
2168 0x11,
2169 0x11,
2170 0x11,
2171 0x11,
2172 0x11,
2173 0x11,
2174 0x11,
2175 0x11,
2176 0x11,
2177 0x11,
2178 0x11,
2179 0x11,
2180 0x11,
2181 0x11,
2182 0x11,
2183 0x11,
2184 0x11,
2185 0x11,
2186 0x11,
2187 0x11,
2188 0x11,
2189 OP_CHECKSIG,
2190 ]; let tx = Transaction {
2192 version: 1,
2193 inputs: vec![
2194 TransactionInput {
2195 prevout: OutPoint {
2196 hash: [1u8; 32].into(),
2197 index: 0,
2198 },
2199 script_sig: vec![].into(),
2200 sequence: 0xffffffff,
2201 },
2202 TransactionInput {
2203 prevout: OutPoint {
2204 hash: [2u8; 32].into(),
2205 index: 1,
2206 },
2207 script_sig: vec![].into(),
2208 sequence: 0xffffffff,
2209 },
2210 ]
2211 .into(),
2212 outputs: vec![TransactionOutput {
2213 value: 5000000000,
2214 script_pubkey: vec![OP_DUP, OP_HASH160, PUSH_20_BYTES].into(),
2215 }]
2216 .into(),
2217 lock_time: 0,
2218 };
2219 let pv: Vec<i64> = vec![10_000_000_000, 8_000_000_000];
2220 let psp_ab: Vec<&[u8]> = vec![script_a.as_slice(), script_b.as_slice()];
2221 let psp_aa: Vec<&[u8]> = vec![script_a.as_slice(), script_a.as_slice()];
2222
2223 let sighash_ab = calculate_transaction_sighash_with_script_code(
2226 &tx,
2227 0,
2228 &pv,
2229 &psp_ab,
2230 SighashType::ALL,
2231 None,
2232 #[cfg(feature = "production")]
2233 None,
2234 )
2235 .unwrap();
2236 let sighash_aa = calculate_transaction_sighash_with_script_code(
2237 &tx,
2238 0,
2239 &pv,
2240 &psp_aa,
2241 SighashType::ALL,
2242 None,
2243 #[cfg(feature = "production")]
2244 None,
2245 )
2246 .unwrap();
2247 assert_eq!(sighash_ab, sighash_aa,
2248 "2-input legacy: signing input 0 — input 1 script must be empty; changing input 1 scriptPubKey must not change sighash");
2249 }
2250
2251 #[cfg(feature = "production")]
2252 #[test]
2253 fn test_batch_sighash_single_input_index_ge_outputs() {
2254 let tx = Transaction {
2257 version: 1,
2258 inputs: vec![
2259 TransactionInput {
2260 prevout: OutPoint {
2261 hash: [1u8; 32].into(),
2262 index: 0,
2263 },
2264 script_sig: vec![].into(),
2265 sequence: 0xffffffff,
2266 },
2267 TransactionInput {
2268 prevout: OutPoint {
2269 hash: [2u8; 32].into(),
2270 index: 1,
2271 },
2272 script_sig: vec![].into(),
2273 sequence: 0xffffffff,
2274 },
2275 ]
2276 .into(),
2277 outputs: vec![TransactionOutput {
2278 value: 5000000000,
2279 script_pubkey: vec![OP_DUP, OP_HASH160, PUSH_20_BYTES].into(),
2280 }]
2281 .into(),
2282 lock_time: 0,
2283 };
2284 let prevout_values = vec![10_000_000_000i64, 8_000_000_000i64];
2285 let script = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
2286 let prevout_script_pubkeys: Vec<&[u8]> = vec![script.as_slice(), script.as_slice()];
2287 let specs = vec![(1usize, 0x03u8, script.as_slice() as &[u8])]; let hashes = super::batch_compute_legacy_sighashes(
2289 &tx,
2290 &prevout_values,
2291 &prevout_script_pubkeys,
2292 &specs,
2293 )
2294 .unwrap();
2295 assert_eq!(hashes.len(), 1);
2296 let mut expected = [0u8; 32];
2297 expected[0] = 1;
2298 assert_eq!(
2299 hashes[0], expected,
2300 "SIGHASH_SINGLE with input_index>=outputs.len() must return 0x0000...0001"
2301 );
2302 }
2303}