1#![deny(unsafe_code)]
35#![deny(non_upper_case_globals)]
36#![deny(non_camel_case_types)]
37#![deny(non_snake_case)]
38#![deny(unused_mut)]
39#![deny(dead_code)]
40#![deny(unused_imports)]
41#![deny(missing_docs)]
42
43#[cfg(not(any(feature = "std")))]
44compile_error!("`std` must be enabled");
45
46use bitcoin::{
47 Address, Network, TapNodeHash, TapSighashType, TapTweakHash, Transaction, TxOut, Witness,
48 XOnlyPublicKey,
49 consensus::deserialize,
50 hashes::Hash,
51 key::Secp256k1,
52 secp256k1,
53 secp256k1::{Keypair, Message, PublicKey, Scalar, SecretKey, constants::CURVE_ORDER},
54 sighash::{Annex, Prevouts, SighashCache},
55 taproot::{ControlBlock, Signature},
56};
57#[cfg(feature = "bitcoinkernel")]
58use bitcoinkernel::{KernelError, verify};
59use hmac::{Hmac, Mac};
60use num_bigint::BigUint;
61use sha2::Sha512;
62use std::fmt;
63
64pub const TAPROOT_ANNEX_DATA_CARRYING_TAG: u8 = 0;
66
67#[derive(Debug)]
69pub enum Error {
70 VerificationFailed(String),
72 Secp256k1(secp256k1::Error),
74 NotScriptPathSpend,
76 InvalidControlBlock,
78 InvalidAmount(bitcoin_units::amount::OutOfRangeError),
80 DeserializationFailed(bitcoin::consensus::encode::Error),
82 InvalidSighash,
84 InputIndexOutOfBounds,
86 UnexpectedInput,
88}
89
90pub trait Verifier {
93 fn verify(
106 &self,
107 script_pubkey: &[u8],
108 amount: Option<i64>,
109 tx_to: &[u8],
110 input_index: u32,
111 flags: Option<u32>,
112 spent_outputs: &[TxOut],
113 ) -> Result<(), Error>;
114}
115
116#[cfg(feature = "bitcoinkernel")]
118pub struct DefaultVerifier;
119
120#[cfg(feature = "bitcoinkernel")]
121impl Verifier for DefaultVerifier {
122 fn verify(
123 &self,
124 script_pubkey: &[u8],
125 amount: Option<i64>,
126 tx_to: &[u8],
127 input_index: u32,
128 flags: Option<u32>,
129 spent_outputs: &[TxOut],
130 ) -> Result<(), Error> {
131 let mut outputs = Vec::new();
132 for txout in spent_outputs {
133 let amount = txout.value.to_signed()?.to_sat();
134 let script = bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes())?;
135 outputs.push(bitcoinkernel::TxOut::new(&script, amount));
136 }
137
138 verify(
139 &bitcoinkernel::ScriptPubkey::try_from(script_pubkey)?,
140 amount,
141 &bitcoinkernel::Transaction::try_from(tx_to)?,
142 input_index,
143 flags,
144 &outputs,
145 )?;
146
147 Ok(())
148 }
149}
150
151pub fn verify_and_sign<V: Verifier>(
175 verifier: &V,
176 input_index: u32,
177 emulated_tx_to: &[u8],
178 actual_spent_outputs: &[TxOut],
179 aux_rand: &[u8; 32],
180 parent_key: SecretKey,
181 backup_merkle_root: Option<TapNodeHash>,
182) -> Result<Transaction, Error> {
183 let mut tx: Transaction = deserialize(emulated_tx_to)?;
185
186 if input_index as usize >= tx.input.len() {
188 return Err(Error::InputIndexOutOfBounds);
189 }
190
191 let amount = actual_spent_outputs[input_index as usize]
193 .value
194 .to_signed()?
195 .to_sat();
196
197 let input = tx.input[input_index as usize].clone();
199 let (Some(control_block), Some(tapleaf)) = (
200 input.witness.taproot_control_block(),
201 input.witness.taproot_leaf_script(),
202 ) else {
203 return Err(Error::NotScriptPathSpend);
204 };
205 let Ok(control_block) = ControlBlock::decode(control_block) else {
206 return Err(Error::NotScriptPathSpend);
207 };
208
209 let mut merkle_root = TapNodeHash::from_script(tapleaf.script, tapleaf.version);
211 for elem in &control_block.merkle_branch {
212 merkle_root = TapNodeHash::from_node_hashes(merkle_root, *elem);
213 }
214
215 let secp = Secp256k1::new();
217 let emulated_address = Address::p2tr(
218 &secp,
219 control_block.internal_key,
220 Some(merkle_root),
221 Network::Bitcoin,
222 );
223
224 let child_key = derive_child_secret_key(parent_key, merkle_root.to_byte_array())?;
226 let (internal_key, parity) = child_key.public_key(&secp).x_only_public_key();
227 let child_key_for_tweak = if parity == secp256k1::Parity::Odd {
228 child_key.negate()
229 } else {
230 child_key
231 };
232
233 let actual_address = Address::p2tr(&secp, internal_key, backup_merkle_root, Network::Bitcoin);
235 if actual_spent_outputs[input_index as usize].script_pubkey != actual_address.script_pubkey() {
236 return Err(Error::UnexpectedInput);
237 }
238
239 verifier.verify(
241 emulated_address.script_pubkey().as_bytes(),
242 Some(amount),
243 emulated_tx_to,
244 input_index,
245 None,
246 actual_spent_outputs,
247 )?;
248
249 let annex = input
251 .witness
252 .taproot_annex()
253 .filter(|bytes| bytes.len() > 1 && bytes[1] == TAPROOT_ANNEX_DATA_CARRYING_TAG)
254 .and_then(|bytes| Annex::new(bytes).ok());
255
256 let mut sighash_cache = SighashCache::new(&tx);
258 let sighash_bytes = sighash_cache
259 .taproot_signature_hash(
260 input_index as usize,
261 &Prevouts::All(actual_spent_outputs),
262 annex.clone(),
263 None,
264 TapSighashType::Default,
265 )
266 .map_err(|_| Error::InvalidSighash)?;
267 let mut sighash = [0u8; 32];
268 sighash.copy_from_slice(sighash_bytes.as_byte_array());
269
270 let tweak = TapTweakHash::from_key_and_tweak(internal_key, backup_merkle_root);
272 let tweaked_secret_key = child_key_for_tweak.add_tweak(&tweak.to_scalar())?;
273 let tweaked_keypair = Keypair::from_secret_key(&secp, &tweaked_secret_key);
274
275 let message = Message::from_digest(sighash);
277 let signature = secp.sign_schnorr_with_aux_rand(&message, &tweaked_keypair, aux_rand);
278
279 let tap_signature = Signature {
281 signature,
282 sighash_type: TapSighashType::Default,
283 };
284
285 let mut witness = Witness::new();
287 witness.push(tap_signature.to_vec());
288 if let Some(annex) = annex {
289 witness.push(annex.as_bytes());
290 }
291 tx.input[input_index as usize].witness = witness;
292
293 Ok(tx)
294}
295
296pub fn generate_address(
308 parent_key: PublicKey,
309 emulated_merkle_root: TapNodeHash,
310 backup_merkle_root: Option<TapNodeHash>,
311 network: Network,
312) -> Result<Address, secp256k1::Error> {
313 let secp = Secp256k1::new();
314 let child_key = derive_child_public_key(parent_key, emulated_merkle_root.to_byte_array())?;
315 let internal_key = XOnlyPublicKey::from(child_key);
316 let address = Address::p2tr(&secp, internal_key, backup_merkle_root, network);
317
318 Ok(address)
319}
320
321fn derive_child_secret_key(
324 parent_key: SecretKey,
325 emulated_merkle_root: [u8; 32],
326) -> Result<SecretKey, secp256k1::Error> {
327 let secp = Secp256k1::new();
328
329 let parent_public = parent_key.public_key(&secp);
331
332 let mut mac = Hmac::<Sha512>::new_from_slice(&parent_public.serialize())
334 .expect("PublicKey serialization should always be non-empty");
335 mac.update(&emulated_merkle_root);
336 let hmac_result = mac.finalize().into_bytes();
337
338 let mut key_material = [0u8; 32];
340 key_material.copy_from_slice(&hmac_result[..32]);
341 let scalar = reduce_mod_order(&key_material);
342
343 parent_key.add_tweak(&scalar)
345}
346
347fn derive_child_public_key(
350 parent_public: PublicKey,
351 emulated_merkle_root: [u8; 32],
352) -> Result<PublicKey, secp256k1::Error> {
353 let secp = Secp256k1::new();
354
355 let mut mac = Hmac::<Sha512>::new_from_slice(&parent_public.serialize())
357 .expect("PublicKey serialization should always be non-empty");
358 mac.update(&emulated_merkle_root);
359 let hmac_result = mac.finalize().into_bytes();
360
361 let mut key_material = [0u8; 32];
363 key_material.copy_from_slice(&hmac_result[..32]);
364 let scalar = reduce_mod_order(&key_material);
365
366 parent_public.add_exp_tweak(&secp, &scalar)
368}
369
370fn reduce_mod_order(bytes: &[u8; 32]) -> Scalar {
372 let mut attempt = *bytes;
375 loop {
376 match Scalar::from_be_bytes(attempt) {
377 Ok(scalar) => return scalar,
378 Err(_) => {
379 attempt = subtract_curve_order(&attempt);
382 }
383 }
384 }
385}
386
387fn subtract_curve_order(bytes: &[u8; 32]) -> [u8; 32] {
389 let value = BigUint::from_bytes_be(bytes);
390 let order = BigUint::from_bytes_be(&CURVE_ORDER);
391 let reduced = value % order;
392
393 let mut result = [0u8; 32];
394 let reduced_bytes = reduced.to_bytes_be();
395 let offset = 32 - reduced_bytes.len();
396 result[offset..].copy_from_slice(&reduced_bytes);
397 result
398}
399
400impl fmt::Display for Error {
401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 match self {
403 Error::VerificationFailed(e) => {
404 write!(f, "Verification failed: {e}")
405 }
406 Error::Secp256k1(e) => {
407 write!(f, "Secp256k1 cryptographic operation failed: {e}")
408 }
409 Error::NotScriptPathSpend => {
410 write!(
411 f,
412 "Input is not a script path spend (missing taproot control block)"
413 )
414 }
415 Error::InvalidAmount(e) => {
416 write!(f, "Invalid amount: {e}")
417 }
418 Error::InvalidControlBlock => {
419 write!(f, "Input has invalid control block")
420 }
421 Error::DeserializationFailed(e) => {
422 write!(f, "Failed to deserialize: {e}")
423 }
424 Error::InvalidSighash => {
425 write!(f, "Unable to calculate sighash for input")
426 }
427 Error::InputIndexOutOfBounds => {
428 write!(f, "Input index out of bounds")
429 }
430 Error::UnexpectedInput => {
431 write!(f, "Unexpected input scriptPubKey")
432 }
433 }
434 }
435}
436
437#[cfg(feature = "bitcoinkernel")]
438impl From<KernelError> for Error {
439 fn from(error: KernelError) -> Self {
440 Error::VerificationFailed(error.to_string())
441 }
442}
443
444impl From<secp256k1::Error> for Error {
445 fn from(error: secp256k1::Error) -> Self {
446 Error::Secp256k1(error)
447 }
448}
449
450impl From<bitcoin::consensus::encode::Error> for Error {
451 fn from(error: bitcoin::consensus::encode::Error) -> Self {
452 Error::DeserializationFailed(error)
453 }
454}
455
456impl From<bitcoin_units::amount::OutOfRangeError> for Error {
457 fn from(error: bitcoin_units::amount::OutOfRangeError) -> Self {
458 Error::InvalidAmount(error)
459 }
460}
461
462#[cfg(test)]
463#[cfg(feature = "bitcoinkernel")]
464mod kernel_tests {
465 use super::*;
466 use bitcoin::{
467 Address, Amount, Network, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut, Txid,
468 Witness,
469 consensus::encode::serialize,
470 hashes::Hash,
471 key::UntweakedPublicKey,
472 taproot::{LeafVersion, TaprootBuilder},
473 };
474
475 fn create_test_transaction_single_input() -> Transaction {
476 Transaction {
477 version: bitcoin::transaction::Version::TWO,
478 lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
479 input: vec![TxIn {
480 previous_output: OutPoint::null(),
481 script_sig: ScriptBuf::new(),
482 sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
483 witness: Witness::new(),
484 }],
485 output: vec![TxOut {
486 value: Amount::from_sat(100000),
487 script_pubkey: ScriptBuf::new_op_return([]),
488 }],
489 }
490 }
491
492 fn create_test_transaction_multi_input() -> Transaction {
493 Transaction {
494 version: bitcoin::transaction::Version::TWO,
495 lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
496 input: vec![
497 TxIn {
498 previous_output: OutPoint::null(),
499 script_sig: ScriptBuf::new(),
500 sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
501 witness: Witness::new(),
502 },
503 TxIn {
504 previous_output: OutPoint::new(Txid::all_zeros(), 1),
505 script_sig: ScriptBuf::new(),
506 sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
507 witness: Witness::new(),
508 },
509 ],
510 output: vec![TxOut {
511 value: Amount::from_sat(100000),
512 script_pubkey: ScriptBuf::new_op_return([]),
513 }],
514 }
515 }
516
517 #[test]
518 fn test_unable_to_deserialize_tx() {
519 let result = verify_and_sign(
520 &DefaultVerifier,
521 0,
522 &[],
523 &[],
524 &[1u8; 32],
525 SecretKey::from_slice(&[1u8; 32]).unwrap(),
526 None,
527 );
528
529 assert!(matches!(result, Err(Error::DeserializationFailed(_))));
530 }
531
532 #[test]
533 fn test_input_index_out_of_bounds() {
534 let txout = TxOut {
535 value: Amount::from_sat(100000),
536 script_pubkey: ScriptBuf::new_op_return([]),
537 };
538 let result = verify_and_sign(
539 &DefaultVerifier,
540 1,
541 &serialize(&create_test_transaction_single_input()),
542 std::slice::from_ref(&txout),
543 &[1u8; 32],
544 SecretKey::from_slice(&[1u8; 32]).unwrap(),
545 None,
546 );
547
548 assert!(matches!(result, Err(Error::InputIndexOutOfBounds)));
549 }
550
551 #[test]
552 fn test_not_script_path_spend() {
553 let txout = TxOut {
554 value: Amount::from_sat(100000),
555 script_pubkey: ScriptBuf::new_op_return([]),
556 };
557 let result = verify_and_sign(
558 &DefaultVerifier,
559 0,
560 &serialize(&create_test_transaction_single_input()),
561 std::slice::from_ref(&txout),
562 &[1u8; 32],
563 SecretKey::from_slice(&[1u8; 32]).unwrap(),
564 None,
565 );
566
567 assert!(matches!(result, Err(Error::NotScriptPathSpend)));
568 }
569
570 #[test]
571 fn test_unexpected_input_script_pubkey() {
572 let secp = Secp256k1::new();
573
574 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
576 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
577
578 let op_true_script = Script::builder()
580 .push_opcode(bitcoin::opcodes::OP_TRUE)
581 .into_script();
582
583 let taproot_builder = TaprootBuilder::new()
585 .add_leaf(0, op_true_script.clone())
586 .unwrap();
587 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
588
589 let control_block = taproot_spend_info
591 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
592 .unwrap();
593
594 let mut witness = Witness::new();
596 witness.push(op_true_script.as_bytes());
597 witness.push(control_block.serialize());
598
599 let mut emulated_tx = create_test_transaction_single_input();
601 emulated_tx.input[0].witness = witness;
602
603 let txout = TxOut {
605 value: Amount::from_sat(100000),
606 script_pubkey: ScriptBuf::new_op_return([]),
607 };
608
609 let result = verify_and_sign(
610 &DefaultVerifier,
611 0,
612 &serialize(&emulated_tx),
613 std::slice::from_ref(&txout),
614 &[1u8; 32],
615 SecretKey::from_slice(&[1u8; 32]).unwrap(),
616 None,
617 );
618
619 assert!(matches!(result, Err(Error::UnexpectedInput)));
620 }
621
622 #[test]
623 fn test_verify_and_sign_single_input_single_leaf() {
624 let secp = Secp256k1::new();
625
626 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
628 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
629
630 let op_true_script = Script::builder()
632 .push_opcode(bitcoin::opcodes::OP_TRUE)
633 .into_script();
634
635 let taproot_builder = TaprootBuilder::new()
637 .add_leaf(0, op_true_script.clone())
638 .unwrap();
639 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
640
641 let control_block = taproot_spend_info
643 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
644 .unwrap();
645
646 let mut witness = Witness::new();
648 witness.push(op_true_script.as_bytes());
649 witness.push(control_block.serialize());
650
651 let mut emulated_tx = create_test_transaction_single_input();
653 emulated_tx.input[0].witness = witness;
654
655 let aux_rand = [1u8; 32];
657 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
658 let child_secret = derive_child_secret_key(
659 parent_secret,
660 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
661 )
662 .unwrap();
663
664 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
666 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
667 let actual_spent_outputs = [TxOut {
668 value: Amount::from_sat(100_000),
669 script_pubkey: actual_address.script_pubkey(),
670 }];
671
672 let actual_tx = verify_and_sign(
674 &DefaultVerifier,
675 0,
676 &serialize(&emulated_tx),
677 &actual_spent_outputs,
678 &aux_rand,
679 parent_secret,
680 None,
681 )
682 .unwrap();
683
684 let mut actual_outputs = Vec::new();
685 for txout in actual_spent_outputs {
686 let amount = txout.value.to_signed().unwrap().to_sat();
687 let script =
688 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
689 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
690 }
691
692 let verify_result = bitcoinkernel::verify(
694 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
695 .unwrap(),
696 Some(100_000),
697 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
698 0,
699 None,
700 &actual_outputs,
701 );
702
703 assert!(verify_result.is_ok());
704 assert_eq!(actual_tx.input[0].witness.len(), 1);
705 }
706
707 #[test]
708 fn test_verify_and_sign_single_input_multiple_leaves() {
709 let secp = Secp256k1::new();
710
711 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
713 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
714
715 let op_true_script = Script::builder()
717 .push_opcode(bitcoin::opcodes::OP_TRUE)
718 .into_script();
719 let op_false_script = Script::builder()
720 .push_opcode(bitcoin::opcodes::OP_FALSE)
721 .into_script();
722
723 let taproot_builder = TaprootBuilder::new()
725 .add_leaf(1, op_true_script.clone())
726 .unwrap()
727 .add_leaf(1, op_false_script.clone())
728 .unwrap();
729 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
730
731 let control_block = taproot_spend_info
733 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
734 .unwrap();
735
736 let mut witness = Witness::new();
738 witness.push(op_true_script.as_bytes());
739 witness.push(control_block.serialize());
740
741 let mut emulated_tx = create_test_transaction_single_input();
743 emulated_tx.input[0].witness = witness;
744
745 let aux_rand = [1u8; 32];
747 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
748 let child_secret = derive_child_secret_key(
749 parent_secret,
750 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
751 )
752 .unwrap();
753
754 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
756 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
757 let actual_spent_outputs = [TxOut {
758 value: Amount::from_sat(100_000),
759 script_pubkey: actual_address.script_pubkey(),
760 }];
761
762 let actual_tx = verify_and_sign(
764 &DefaultVerifier,
765 0,
766 &serialize(&emulated_tx),
767 &actual_spent_outputs,
768 &aux_rand,
769 parent_secret,
770 None,
771 )
772 .unwrap();
773
774 let mut actual_outputs = Vec::new();
775 for txout in actual_spent_outputs {
776 let amount = txout.value.to_signed().unwrap().to_sat();
777 let script =
778 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
779 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
780 }
781
782 let verify_result = bitcoinkernel::verify(
784 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
785 .unwrap(),
786 Some(100_000),
787 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
788 0,
789 None,
790 &actual_outputs,
791 );
792
793 assert!(verify_result.is_ok());
794 assert_eq!(actual_tx.input[0].witness.len(), 1);
795 }
796
797 #[test]
798 fn test_verify_and_sign_single_input_with_backup() {
799 let secp = Secp256k1::new();
800
801 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
803 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
804
805 let op_true_script = Script::builder()
807 .push_opcode(bitcoin::opcodes::OP_TRUE)
808 .into_script();
809
810 let taproot_builder = TaprootBuilder::new()
812 .add_leaf(0, op_true_script.clone())
813 .unwrap();
814 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
815
816 let control_block = taproot_spend_info
818 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
819 .unwrap();
820
821 let mut witness = Witness::new();
823 witness.push(op_true_script.as_bytes());
824 witness.push(control_block.serialize());
825
826 let mut emulated_tx = create_test_transaction_single_input();
828 emulated_tx.input[0].witness = witness;
829
830 let aux_rand = [1u8; 32];
832 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
833 let child_secret = derive_child_secret_key(
834 parent_secret,
835 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
836 )
837 .unwrap();
838
839 let actual_backup_merkle_root = taproot_spend_info.merkle_root();
841 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
842 let actual_address = Address::p2tr(
843 &secp,
844 actual_internal_key,
845 actual_backup_merkle_root,
846 Network::Bitcoin,
847 );
848 let actual_spent_outputs = [TxOut {
849 value: Amount::from_sat(100_000),
850 script_pubkey: actual_address.script_pubkey(),
851 }];
852
853 let actual_tx = verify_and_sign(
855 &DefaultVerifier,
856 0,
857 &serialize(&emulated_tx),
858 &actual_spent_outputs,
859 &aux_rand,
860 parent_secret,
861 actual_backup_merkle_root,
862 )
863 .unwrap();
864
865 let mut actual_outputs = Vec::new();
866 for txout in actual_spent_outputs {
867 let amount = txout.value.to_signed().unwrap().to_sat();
868 let script =
869 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
870 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
871 }
872
873 let verify_result = bitcoinkernel::verify(
875 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
876 .unwrap(),
877 Some(100_000),
878 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
879 0,
880 None,
881 &actual_outputs,
882 );
883
884 assert!(verify_result.is_ok());
885 assert_eq!(actual_tx.input[0].witness.len(), 1);
886 }
887
888 #[test]
889 fn test_verify_and_sign_single_input_single_leaf_with_data_carrying_annex() {
890 let secp = Secp256k1::new();
891
892 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
894 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
895
896 let op_true_script = Script::builder()
898 .push_opcode(bitcoin::opcodes::OP_TRUE)
899 .into_script();
900
901 let taproot_builder = TaprootBuilder::new()
903 .add_leaf(0, op_true_script.clone())
904 .unwrap();
905 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
906
907 let control_block = taproot_spend_info
909 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
910 .unwrap();
911
912 let annex: &[u8] = &[0x50, TAPROOT_ANNEX_DATA_CARRYING_TAG, 0x01, 0x02, 0x03];
914
915 let mut witness = Witness::new();
917 witness.push(op_true_script.as_bytes());
918 witness.push(control_block.serialize());
919 witness.push(annex);
920
921 let mut emulated_tx = create_test_transaction_single_input();
923 emulated_tx.input[0].witness = witness;
924
925 let aux_rand = [1u8; 32];
927 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
928 let child_secret = derive_child_secret_key(
929 parent_secret,
930 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
931 )
932 .unwrap();
933
934 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
936 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
937 let actual_spent_outputs = [TxOut {
938 value: Amount::from_sat(100_000),
939 script_pubkey: actual_address.script_pubkey(),
940 }];
941
942 let actual_tx = verify_and_sign(
944 &DefaultVerifier,
945 0,
946 &serialize(&emulated_tx),
947 &actual_spent_outputs,
948 &aux_rand,
949 parent_secret,
950 None,
951 )
952 .unwrap();
953
954 let mut actual_outputs = Vec::new();
955 for txout in actual_spent_outputs {
956 let amount = txout.value.to_signed().unwrap().to_sat();
957 let script =
958 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
959 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
960 }
961
962 let verify_result = bitcoinkernel::verify(
964 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
965 .unwrap(),
966 Some(100_000),
967 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
968 0,
969 None,
970 &actual_outputs,
971 );
972
973 assert!(verify_result.is_ok());
974 assert_eq!(actual_tx.input[0].witness.len(), 2);
975 assert_eq!(&actual_tx.input[0].witness[1], annex);
976 }
977
978 #[test]
979 fn test_verify_and_sign_single_input_single_leaf_with_non_data_carrying_annex() {
980 let secp = Secp256k1::new();
981
982 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
984 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
985
986 let op_true_script = Script::builder()
988 .push_opcode(bitcoin::opcodes::OP_TRUE)
989 .into_script();
990
991 let taproot_builder = TaprootBuilder::new()
993 .add_leaf(0, op_true_script.clone())
994 .unwrap();
995 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
996
997 let control_block = taproot_spend_info
999 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
1000 .unwrap();
1001
1002 let annex: &[u8] = &[0x50, 0x01, 0x02, 0x03];
1004
1005 let mut witness = Witness::new();
1007 witness.push(op_true_script.as_bytes());
1008 witness.push(control_block.serialize());
1009 witness.push(annex);
1010
1011 let mut emulated_tx = create_test_transaction_single_input();
1013 emulated_tx.input[0].witness = witness;
1014
1015 let aux_rand = [1u8; 32];
1017 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1018 let child_secret = derive_child_secret_key(
1019 parent_secret,
1020 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
1021 )
1022 .unwrap();
1023
1024 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
1026 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
1027 let actual_spent_outputs = [TxOut {
1028 value: Amount::from_sat(100_000),
1029 script_pubkey: actual_address.script_pubkey(),
1030 }];
1031
1032 let actual_tx = verify_and_sign(
1034 &DefaultVerifier,
1035 0,
1036 &serialize(&emulated_tx),
1037 &actual_spent_outputs,
1038 &aux_rand,
1039 parent_secret,
1040 None,
1041 )
1042 .unwrap();
1043
1044 let mut actual_outputs = Vec::new();
1045 for txout in actual_spent_outputs {
1046 let amount = txout.value.to_signed().unwrap().to_sat();
1047 let script =
1048 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
1049 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
1050 }
1051
1052 let verify_result = bitcoinkernel::verify(
1054 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
1055 .unwrap(),
1056 Some(100_000),
1057 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
1058 0,
1059 None,
1060 &actual_outputs,
1061 );
1062
1063 assert!(verify_result.is_ok());
1064 assert_eq!(actual_tx.input[0].witness.len(), 1);
1065 }
1066
1067 #[test]
1068 fn test_verify_and_sign_multi_input_tx() {
1069 let secp = Secp256k1::new();
1070
1071 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1073 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
1074
1075 let op_true_script = Script::builder()
1077 .push_opcode(bitcoin::opcodes::OP_TRUE)
1078 .into_script();
1079
1080 let taproot_builder = TaprootBuilder::new()
1082 .add_leaf(0, op_true_script.clone())
1083 .unwrap();
1084 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
1085
1086 let control_block = taproot_spend_info
1088 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
1089 .unwrap();
1090
1091 let mut witness = Witness::new();
1093 witness.push(op_true_script.as_bytes());
1094 witness.push(control_block.serialize());
1095
1096 let mut emulated_tx = create_test_transaction_multi_input();
1098 emulated_tx.input[1].witness = witness;
1099
1100 let aux_rand = [1u8; 32];
1102 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1103 let child_secret = derive_child_secret_key(
1104 parent_secret,
1105 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
1106 )
1107 .unwrap();
1108
1109 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
1111 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
1112 let actual_spent_outputs = [
1113 TxOut {
1114 value: Amount::from_sat(200_000),
1115 script_pubkey: actual_address.script_pubkey(),
1116 },
1117 TxOut {
1118 value: Amount::from_sat(100_000),
1119 script_pubkey: actual_address.script_pubkey(),
1120 },
1121 ];
1122
1123 let actual_tx = verify_and_sign(
1125 &DefaultVerifier,
1126 1,
1127 &serialize(&emulated_tx),
1128 &actual_spent_outputs,
1129 &aux_rand,
1130 parent_secret,
1131 None,
1132 )
1133 .unwrap();
1134
1135 let mut actual_outputs = Vec::new();
1136 for txout in actual_spent_outputs {
1137 let amount = txout.value.to_signed().unwrap().to_sat();
1138 let script =
1139 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
1140 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
1141 }
1142
1143 let verify_result = bitcoinkernel::verify(
1145 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
1146 .unwrap(),
1147 Some(100_000),
1148 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
1149 1,
1150 None,
1151 &actual_outputs,
1152 );
1153
1154 assert!(verify_result.is_ok());
1155 assert_eq!(actual_tx.input[1].witness.len(), 1);
1156 }
1157}
1158
1159#[cfg(test)]
1160mod non_kernel_tests {
1161 use super::*;
1162 use bitcoin::{
1163 Script,
1164 key::{Secp256k1, UntweakedPublicKey},
1165 taproot::TaprootBuilder,
1166 };
1167
1168 #[test]
1169 fn test_generate_address() {
1170 let secp = Secp256k1::new();
1171
1172 let emulated_script = Script::builder()
1174 .push_opcode(bitcoin::opcodes::OP_TRUE)
1175 .into_script();
1176
1177 let taproot_builder = TaprootBuilder::new()
1179 .add_leaf(0, emulated_script.clone())
1180 .unwrap();
1181 let dummy_internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1182 let dummy_internal_key = UntweakedPublicKey::from(dummy_internal_secret.public_key(&secp));
1183 let taproot_spend_info = taproot_builder.finalize(&secp, dummy_internal_key).unwrap();
1184 let emulated_merkle_root = taproot_spend_info.merkle_root().unwrap();
1185
1186 let backup_merkle_root = emulated_merkle_root;
1188
1189 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1191 let master_public_key: PublicKey = internal_secret.public_key(&secp);
1192 let onchain_address = generate_address(
1193 master_public_key,
1194 emulated_merkle_root,
1195 Some(backup_merkle_root),
1196 Network::Bitcoin,
1197 );
1198
1199 assert!(onchain_address.is_ok());
1200 }
1201
1202 #[test]
1203 fn test_public_private_key_derivation_consistency() {
1204 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1205 let parent_public = parent_secret.public_key(&Secp256k1::new());
1206 let merkle_root = [42u8; 32];
1207
1208 let child_secret = derive_child_secret_key(parent_secret, merkle_root).unwrap();
1209 let child_public_from_secret = child_secret.public_key(&Secp256k1::new());
1210 let child_public_direct = derive_child_public_key(parent_public, merkle_root).unwrap();
1211
1212 assert_eq!(child_public_from_secret, child_public_direct);
1213 }
1214
1215 #[test]
1216 fn test_curve_order_reduction() {
1217 let max_bytes = [0xFF; 32];
1218 let reduced = reduce_mod_order(&max_bytes);
1219 #[allow(clippy::useless_conversion)]
1221 let _ = Scalar::from(reduced);
1222 }
1223}