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