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