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, ScriptBuf, TapNodeHash, TapSighashType, TapTweakHash, Transaction, TxOut,
48 Witness, XOnlyPublicKey,
49 hashes::Hash,
50 key::Secp256k1,
51 secp256k1,
52 secp256k1::{Keypair, Message, PublicKey, Scalar, SecretKey, constants::CURVE_ORDER},
53 sighash::{Annex, Prevouts, SighashCache},
54 taproot::{ControlBlock, Signature},
55};
56use hmac::{Hmac, Mac};
57use num_bigint::BigUint;
58use sha2::{Digest, Sha256, Sha512};
59use std::collections::HashMap;
60use std::fmt;
61
62pub const TAPROOT_ANNEX_DATA_CARRYING_TAG: u8 = 0;
64
65#[derive(Debug)]
67pub enum Error {
68 VerificationFailed(String),
70 Secp256k1(secp256k1::Error),
72 InvalidControlBlock,
74 InvalidSighash,
76 MissingSpentOutputs,
78 UnexpectedInput,
80}
81
82pub trait Verifier {
85 fn verify(
95 &self,
96 script_pubkeys: &HashMap<usize, ScriptBuf>,
97 tx_to: &Transaction,
98 spent_outputs: &[TxOut],
99 ) -> Result<(), Error>;
100}
101
102#[cfg(feature = "bitcoinkernel")]
104pub struct DefaultVerifier;
105
106#[cfg(feature = "bitcoinkernel")]
107impl Verifier for DefaultVerifier {
108 fn verify(
109 &self,
110 script_pubkeys: &HashMap<usize, ScriptBuf>,
111 tx_to: &Transaction,
112 spent_outputs: &[TxOut],
113 ) -> Result<(), Error> {
114 let mut amounts = Vec::new();
115 let mut outputs = Vec::new();
116 for txout in spent_outputs {
117 let amount = txout
118 .value
119 .to_signed()
120 .map_err(|_| Error::VerificationFailed("invalid amount".to_string()))?
121 .to_sat();
122 let script = bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes())
123 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
124
125 amounts.push(amount);
126 outputs.push(bitcoinkernel::TxOut::new(&script, amount));
127 }
128
129 let tx_bytes = bitcoin::consensus::serialize(tx_to);
130 let tx_to = &bitcoinkernel::Transaction::try_from(tx_bytes.as_slice())
131 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
132
133 for (&i, script_pubkey) in script_pubkeys {
134 let amount = amounts.get(i).cloned();
135 let script_pubkey = &bitcoinkernel::ScriptPubkey::try_from(script_pubkey.as_bytes())
136 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
137
138 bitcoinkernel::verify(script_pubkey, amount, tx_to, i, None, &outputs)
139 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
140 }
141
142 Ok(())
143 }
144}
145
146pub fn verify_and_sign<V: Verifier>(
176 verifier: &V,
177 emulated_tx_to: &Transaction,
178 actual_spent_outputs: &[TxOut],
179 aux_rand: &[u8; 32],
180 parent_key: SecretKey,
181 backup_merkle_roots: HashMap<usize, TapNodeHash>,
182) -> Result<Transaction, Error> {
183 let mut emulated_script_pubkeys: HashMap<usize, ScriptBuf> = HashMap::new();
185
186 let mut child_keys_by_index: HashMap<usize, SecretKey> = HashMap::new();
188
189 if actual_spent_outputs.len() < emulated_tx_to.input.len() {
191 return Err(Error::MissingSpentOutputs);
192 }
193
194 let secp = Secp256k1::new();
196 for (i, input) in emulated_tx_to.input.clone().into_iter().enumerate() {
197 let (Some(true), Some(control_block), Some(tapleaf)) = (
199 actual_spent_outputs[i]
200 .script_pubkey
201 .is_p2tr()
202 .then_some(true),
203 input.witness.taproot_control_block(),
204 input.witness.taproot_leaf_script(),
205 ) else {
206 continue;
207 };
208
209 let Ok(control_block) = ControlBlock::decode(control_block) else {
211 return Err(Error::InvalidControlBlock);
212 };
213
214 let mut merkle_root = TapNodeHash::from_script(tapleaf.script, tapleaf.version);
216 for elem in &control_block.merkle_branch {
217 merkle_root = TapNodeHash::from_node_hashes(merkle_root, *elem);
218 }
219
220 let emulated_address = Address::p2tr(
222 &secp,
223 control_block.internal_key,
224 Some(merkle_root),
225 Network::Bitcoin,
226 );
227
228 if actual_spent_outputs[i].script_pubkey == emulated_address.script_pubkey() {
230 continue;
231 }
232
233 let child_key = derive_child_secret_key(parent_key, merkle_root.to_byte_array())?;
235 let (internal_key, _) = child_key.public_key(&secp).x_only_public_key();
236 child_keys_by_index.insert(i, child_key);
237
238 let backup_merkle_root = backup_merkle_roots.get(&i).cloned();
240 let actual_address =
241 Address::p2tr(&secp, internal_key, backup_merkle_root, Network::Bitcoin);
242 if actual_spent_outputs[i].script_pubkey != actual_address.script_pubkey() {
243 return Err(Error::UnexpectedInput);
244 }
245
246 emulated_script_pubkeys.insert(i, emulated_address.script_pubkey());
248 }
249
250 verifier.verify(
252 &emulated_script_pubkeys,
253 emulated_tx_to,
254 actual_spent_outputs,
255 )?;
256
257 let mut tx = emulated_tx_to.clone();
258 for &i in emulated_script_pubkeys.keys() {
259 let annex = tx.input[i]
261 .witness
262 .taproot_annex()
263 .filter(|bytes| bytes.len() > 1 && bytes[1] == TAPROOT_ANNEX_DATA_CARRYING_TAG)
264 .and_then(|bytes| Annex::new(bytes).ok());
265
266 let mut sighash_cache = SighashCache::new(&tx);
268 let sighash_bytes = sighash_cache
269 .taproot_signature_hash(
270 i,
271 &Prevouts::All(actual_spent_outputs),
272 annex.clone(),
273 None,
274 TapSighashType::Default,
275 )
276 .map_err(|_| Error::InvalidSighash)?;
277 let mut sighash = [0u8; 32];
278 sighash.copy_from_slice(sighash_bytes.as_byte_array());
279
280 let child_key = child_keys_by_index.get(&i).unwrap();
282 let (internal_key, parity) = child_key.public_key(&secp).x_only_public_key();
283 let child_key_for_tweak = if parity == secp256k1::Parity::Odd {
284 child_key.negate()
285 } else {
286 *child_key
287 };
288
289 let backup_merkle_root = backup_merkle_roots.get(&i).cloned();
291 let tweak = TapTweakHash::from_key_and_tweak(internal_key, backup_merkle_root);
292 let tweaked_secret_key = child_key_for_tweak.add_tweak(&tweak.to_scalar())?;
293 let tweaked_keypair = Keypair::from_secret_key(&secp, &tweaked_secret_key);
294
295 let mut hasher = Sha256::new();
297 hasher.update(aux_rand);
298 hasher.update((i as u64).to_le_bytes());
299 let aux_rand: [u8; 32] = hasher.finalize().into();
300
301 let message = Message::from_digest(sighash);
303 let signature = secp.sign_schnorr_with_aux_rand(&message, &tweaked_keypair, &aux_rand);
304
305 let tap_signature = Signature {
307 signature,
308 sighash_type: TapSighashType::Default,
309 };
310
311 let mut witness = Witness::new();
313 witness.push(tap_signature.to_vec());
314 if let Some(annex) = annex {
315 witness.push(annex.as_bytes());
316 }
317 tx.input[i].witness = witness;
318 }
319
320 Ok(tx)
321}
322
323pub fn generate_address(
335 parent_key: PublicKey,
336 emulated_merkle_root: TapNodeHash,
337 backup_merkle_root: Option<TapNodeHash>,
338 network: Network,
339) -> Result<Address, secp256k1::Error> {
340 let secp = Secp256k1::new();
341 let child_key = derive_child_public_key(parent_key, emulated_merkle_root.to_byte_array())?;
342 let internal_key = XOnlyPublicKey::from(child_key);
343 let address = Address::p2tr(&secp, internal_key, backup_merkle_root, network);
344
345 Ok(address)
346}
347
348fn derive_child_secret_key(
351 parent_key: SecretKey,
352 emulated_merkle_root: [u8; 32],
353) -> Result<SecretKey, secp256k1::Error> {
354 let secp = Secp256k1::new();
355
356 let parent_public = parent_key.public_key(&secp);
358
359 let mut mac = Hmac::<Sha512>::new_from_slice(&parent_public.serialize())
361 .expect("PublicKey serialization should always be non-empty");
362 mac.update(&emulated_merkle_root);
363 let hmac_result = mac.finalize().into_bytes();
364
365 let mut key_material = [0u8; 32];
367 key_material.copy_from_slice(&hmac_result[..32]);
368 let scalar = reduce_mod_order(&key_material);
369
370 parent_key.add_tweak(&scalar)
372}
373
374fn derive_child_public_key(
377 parent_public: PublicKey,
378 emulated_merkle_root: [u8; 32],
379) -> Result<PublicKey, secp256k1::Error> {
380 let secp = Secp256k1::new();
381
382 let mut mac = Hmac::<Sha512>::new_from_slice(&parent_public.serialize())
384 .expect("PublicKey serialization should always be non-empty");
385 mac.update(&emulated_merkle_root);
386 let hmac_result = mac.finalize().into_bytes();
387
388 let mut key_material = [0u8; 32];
390 key_material.copy_from_slice(&hmac_result[..32]);
391 let scalar = reduce_mod_order(&key_material);
392
393 parent_public.add_exp_tweak(&secp, &scalar)
395}
396
397fn reduce_mod_order(bytes: &[u8; 32]) -> Scalar {
399 let mut attempt = *bytes;
402 loop {
403 match Scalar::from_be_bytes(attempt) {
404 Ok(scalar) => return scalar,
405 Err(_) => {
406 attempt = subtract_curve_order(&attempt);
409 }
410 }
411 }
412}
413
414fn subtract_curve_order(bytes: &[u8; 32]) -> [u8; 32] {
416 let value = BigUint::from_bytes_be(bytes);
417 let order = BigUint::from_bytes_be(&CURVE_ORDER);
418 let reduced = value % order;
419
420 let mut result = [0u8; 32];
421 let reduced_bytes = reduced.to_bytes_be();
422 let offset = 32 - reduced_bytes.len();
423 result[offset..].copy_from_slice(&reduced_bytes);
424 result
425}
426
427impl fmt::Display for Error {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 match self {
430 Error::VerificationFailed(e) => {
431 write!(f, "Verification failed: {e}")
432 }
433 Error::Secp256k1(e) => {
434 write!(f, "Secp256k1 cryptographic operation failed: {e}")
435 }
436 Error::InvalidControlBlock => {
437 write!(f, "Input has invalid control block")
438 }
439 Error::InvalidSighash => {
440 write!(f, "Unable to calculate sighash for input")
441 }
442 Error::MissingSpentOutputs => {
443 write!(f, "Missing spent outputs")
444 }
445 Error::UnexpectedInput => {
446 write!(f, "Unexpected input scriptPubKey")
447 }
448 }
449 }
450}
451
452impl From<secp256k1::Error> for Error {
453 fn from(error: secp256k1::Error) -> Self {
454 Error::Secp256k1(error)
455 }
456}
457
458#[cfg(test)]
459#[cfg(feature = "bitcoinkernel")]
460mod kernel_tests {
461 use super::*;
462 use bitcoin::{
463 Address, Amount, Network, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut, Txid,
464 Witness,
465 consensus::encode::serialize,
466 hashes::Hash,
467 key::UntweakedPublicKey,
468 taproot::{LeafVersion, TaprootBuilder},
469 };
470
471 fn create_test_transaction_single_input() -> Transaction {
472 Transaction {
473 version: bitcoin::transaction::Version::TWO,
474 lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
475 input: vec![TxIn {
476 previous_output: OutPoint::null(),
477 script_sig: ScriptBuf::new(),
478 sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
479 witness: Witness::new(),
480 }],
481 output: vec![TxOut {
482 value: Amount::from_sat(100000),
483 script_pubkey: ScriptBuf::new_op_return([]),
484 }],
485 }
486 }
487
488 fn create_test_transaction_multi_input() -> Transaction {
489 Transaction {
490 version: bitcoin::transaction::Version::TWO,
491 lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
492 input: vec![
493 TxIn {
494 previous_output: OutPoint::null(),
495 script_sig: ScriptBuf::new(),
496 sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
497 witness: Witness::new(),
498 },
499 TxIn {
500 previous_output: OutPoint::new(Txid::all_zeros(), 1),
501 script_sig: ScriptBuf::new(),
502 sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME,
503 witness: Witness::new(),
504 },
505 ],
506 output: vec![TxOut {
507 value: Amount::from_sat(100000),
508 script_pubkey: ScriptBuf::new_op_return([]),
509 }],
510 }
511 }
512
513 #[test]
514 fn test_missing_spent_outputs() {
515 let result = verify_and_sign(
516 &DefaultVerifier,
517 &create_test_transaction_single_input(),
518 &[],
519 &[1u8; 32],
520 SecretKey::from_slice(&[1u8; 32]).unwrap(),
521 HashMap::new(),
522 );
523
524 assert!(matches!(result, Err(Error::MissingSpentOutputs)));
525 }
526
527 #[test]
528 fn test_unexpected_input_script_pubkey() {
529 let secp = Secp256k1::new();
530
531 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
533 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
534
535 let op_true_script = Script::builder()
537 .push_opcode(bitcoin::opcodes::OP_TRUE)
538 .into_script();
539
540 let taproot_builder = TaprootBuilder::new()
542 .add_leaf(0, op_true_script.clone())
543 .unwrap();
544 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
545
546 let control_block = taproot_spend_info
548 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
549 .unwrap();
550
551 let mut witness = Witness::new();
553 witness.push(op_true_script.as_bytes());
554 witness.push(control_block.serialize());
555
556 let mut emulated_tx = create_test_transaction_single_input();
558 emulated_tx.input[0].witness = witness;
559
560 let dummy_p2tr_address = Address::p2tr(&secp, internal_key, None, Network::Bitcoin);
562 let txout = TxOut {
563 value: Amount::from_sat(100000),
564 script_pubkey: dummy_p2tr_address.script_pubkey(),
565 };
566
567 let result = verify_and_sign(
568 &DefaultVerifier,
569 &emulated_tx,
570 std::slice::from_ref(&txout),
571 &[1u8; 32],
572 SecretKey::from_slice(&[1u8; 32]).unwrap(),
573 HashMap::new(),
574 );
575
576 assert!(matches!(result, Err(Error::UnexpectedInput)));
577 }
578
579 #[test]
580 fn test_verify_and_sign_single_input_single_leaf() {
581 let secp = Secp256k1::new();
582
583 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
585 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
586
587 let op_true_script = Script::builder()
589 .push_opcode(bitcoin::opcodes::OP_TRUE)
590 .into_script();
591
592 let taproot_builder = TaprootBuilder::new()
594 .add_leaf(0, op_true_script.clone())
595 .unwrap();
596 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
597
598 let control_block = taproot_spend_info
600 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
601 .unwrap();
602
603 let mut witness = Witness::new();
605 witness.push(op_true_script.as_bytes());
606 witness.push(control_block.serialize());
607
608 let mut emulated_tx = create_test_transaction_single_input();
610 emulated_tx.input[0].witness = witness;
611
612 let aux_rand = [1u8; 32];
614 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
615 let child_secret = derive_child_secret_key(
616 parent_secret,
617 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
618 )
619 .unwrap();
620
621 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
623 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
624 let actual_spent_outputs = [TxOut {
625 value: Amount::from_sat(100_000),
626 script_pubkey: actual_address.script_pubkey(),
627 }];
628
629 let actual_tx = verify_and_sign(
631 &DefaultVerifier,
632 &emulated_tx,
633 &actual_spent_outputs,
634 &aux_rand,
635 parent_secret,
636 HashMap::new(),
637 )
638 .unwrap();
639
640 let mut actual_outputs = Vec::new();
641 for txout in actual_spent_outputs {
642 let amount = txout.value.to_signed().unwrap().to_sat();
643 let script =
644 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
645 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
646 }
647
648 let verify_result = bitcoinkernel::verify(
650 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
651 .unwrap(),
652 Some(100_000),
653 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
654 0,
655 None,
656 &actual_outputs,
657 );
658
659 assert!(verify_result.is_ok());
660 assert_eq!(actual_tx.input[0].witness.len(), 1);
661 }
662
663 #[test]
664 fn test_verify_and_sign_single_input_multiple_leaves() {
665 let secp = Secp256k1::new();
666
667 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
669 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
670
671 let op_true_script = Script::builder()
673 .push_opcode(bitcoin::opcodes::OP_TRUE)
674 .into_script();
675 let op_false_script = Script::builder()
676 .push_opcode(bitcoin::opcodes::OP_FALSE)
677 .into_script();
678
679 let taproot_builder = TaprootBuilder::new()
681 .add_leaf(1, op_true_script.clone())
682 .unwrap()
683 .add_leaf(1, op_false_script.clone())
684 .unwrap();
685 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
686
687 let control_block = taproot_spend_info
689 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
690 .unwrap();
691
692 let mut witness = Witness::new();
694 witness.push(op_true_script.as_bytes());
695 witness.push(control_block.serialize());
696
697 let mut emulated_tx = create_test_transaction_single_input();
699 emulated_tx.input[0].witness = witness;
700
701 let aux_rand = [1u8; 32];
703 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
704 let child_secret = derive_child_secret_key(
705 parent_secret,
706 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
707 )
708 .unwrap();
709
710 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
712 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
713 let actual_spent_outputs = [TxOut {
714 value: Amount::from_sat(100_000),
715 script_pubkey: actual_address.script_pubkey(),
716 }];
717
718 let actual_tx = verify_and_sign(
720 &DefaultVerifier,
721 &emulated_tx,
722 &actual_spent_outputs,
723 &aux_rand,
724 parent_secret,
725 HashMap::new(),
726 )
727 .unwrap();
728
729 let mut actual_outputs = Vec::new();
730 for txout in actual_spent_outputs {
731 let amount = txout.value.to_signed().unwrap().to_sat();
732 let script =
733 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
734 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
735 }
736
737 let verify_result = bitcoinkernel::verify(
739 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
740 .unwrap(),
741 Some(100_000),
742 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
743 0,
744 None,
745 &actual_outputs,
746 );
747
748 assert!(verify_result.is_ok());
749 assert_eq!(actual_tx.input[0].witness.len(), 1);
750 }
751
752 #[test]
753 fn test_verify_and_sign_single_input_with_backup() {
754 let secp = Secp256k1::new();
755
756 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
758 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
759
760 let op_true_script = Script::builder()
762 .push_opcode(bitcoin::opcodes::OP_TRUE)
763 .into_script();
764
765 let taproot_builder = TaprootBuilder::new()
767 .add_leaf(0, op_true_script.clone())
768 .unwrap();
769 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
770
771 let control_block = taproot_spend_info
773 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
774 .unwrap();
775
776 let mut witness = Witness::new();
778 witness.push(op_true_script.as_bytes());
779 witness.push(control_block.serialize());
780
781 let mut emulated_tx = create_test_transaction_single_input();
783 emulated_tx.input[0].witness = witness;
784
785 let aux_rand = [1u8; 32];
787 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
788 let child_secret = derive_child_secret_key(
789 parent_secret,
790 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
791 )
792 .unwrap();
793
794 let actual_backup_merkle_root = taproot_spend_info.merkle_root();
796 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
797 let actual_address = Address::p2tr(
798 &secp,
799 actual_internal_key,
800 actual_backup_merkle_root,
801 Network::Bitcoin,
802 );
803 let actual_spent_outputs = [TxOut {
804 value: Amount::from_sat(100_000),
805 script_pubkey: actual_address.script_pubkey(),
806 }];
807
808 let actual_tx = verify_and_sign(
810 &DefaultVerifier,
811 &emulated_tx,
812 &actual_spent_outputs,
813 &aux_rand,
814 parent_secret,
815 HashMap::from([(0, actual_backup_merkle_root.unwrap())]),
816 )
817 .unwrap();
818
819 let mut actual_outputs = Vec::new();
820 for txout in actual_spent_outputs {
821 let amount = txout.value.to_signed().unwrap().to_sat();
822 let script =
823 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
824 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
825 }
826
827 let verify_result = bitcoinkernel::verify(
829 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
830 .unwrap(),
831 Some(100_000),
832 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
833 0,
834 None,
835 &actual_outputs,
836 );
837
838 assert!(verify_result.is_ok());
839 assert_eq!(actual_tx.input[0].witness.len(), 1);
840 }
841
842 #[test]
843 fn test_verify_and_sign_single_input_single_leaf_with_data_carrying_annex() {
844 let secp = Secp256k1::new();
845
846 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
848 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
849
850 let op_true_script = Script::builder()
852 .push_opcode(bitcoin::opcodes::OP_TRUE)
853 .into_script();
854
855 let taproot_builder = TaprootBuilder::new()
857 .add_leaf(0, op_true_script.clone())
858 .unwrap();
859 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
860
861 let control_block = taproot_spend_info
863 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
864 .unwrap();
865
866 let annex: &[u8] = &[0x50, TAPROOT_ANNEX_DATA_CARRYING_TAG, 0x01, 0x02, 0x03];
868
869 let mut witness = Witness::new();
871 witness.push(op_true_script.as_bytes());
872 witness.push(control_block.serialize());
873 witness.push(annex);
874
875 let mut emulated_tx = create_test_transaction_single_input();
877 emulated_tx.input[0].witness = witness;
878
879 let aux_rand = [1u8; 32];
881 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
882 let child_secret = derive_child_secret_key(
883 parent_secret,
884 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
885 )
886 .unwrap();
887
888 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
890 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
891 let actual_spent_outputs = [TxOut {
892 value: Amount::from_sat(100_000),
893 script_pubkey: actual_address.script_pubkey(),
894 }];
895
896 let actual_tx = verify_and_sign(
898 &DefaultVerifier,
899 &emulated_tx,
900 &actual_spent_outputs,
901 &aux_rand,
902 parent_secret,
903 HashMap::new(),
904 )
905 .unwrap();
906
907 let mut actual_outputs = Vec::new();
908 for txout in actual_spent_outputs {
909 let amount = txout.value.to_signed().unwrap().to_sat();
910 let script =
911 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
912 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
913 }
914
915 let verify_result = bitcoinkernel::verify(
917 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
918 .unwrap(),
919 Some(100_000),
920 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
921 0,
922 None,
923 &actual_outputs,
924 );
925
926 assert!(verify_result.is_ok());
927 assert_eq!(actual_tx.input[0].witness.len(), 2);
928 assert_eq!(&actual_tx.input[0].witness[1], annex);
929 }
930
931 #[test]
932 fn test_verify_and_sign_single_input_single_leaf_with_non_data_carrying_annex() {
933 let secp = Secp256k1::new();
934
935 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
937 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
938
939 let op_true_script = Script::builder()
941 .push_opcode(bitcoin::opcodes::OP_TRUE)
942 .into_script();
943
944 let taproot_builder = TaprootBuilder::new()
946 .add_leaf(0, op_true_script.clone())
947 .unwrap();
948 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
949
950 let control_block = taproot_spend_info
952 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
953 .unwrap();
954
955 let annex: &[u8] = &[0x50, 0x01, 0x02, 0x03];
957
958 let mut witness = Witness::new();
960 witness.push(op_true_script.as_bytes());
961 witness.push(control_block.serialize());
962 witness.push(annex);
963
964 let mut emulated_tx = create_test_transaction_single_input();
966 emulated_tx.input[0].witness = witness;
967
968 let aux_rand = [1u8; 32];
970 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
971 let child_secret = derive_child_secret_key(
972 parent_secret,
973 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
974 )
975 .unwrap();
976
977 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
979 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
980 let actual_spent_outputs = [TxOut {
981 value: Amount::from_sat(100_000),
982 script_pubkey: actual_address.script_pubkey(),
983 }];
984
985 let actual_tx = verify_and_sign(
987 &DefaultVerifier,
988 &emulated_tx,
989 &actual_spent_outputs,
990 &aux_rand,
991 parent_secret,
992 HashMap::new(),
993 )
994 .unwrap();
995
996 let mut actual_outputs = Vec::new();
997 for txout in actual_spent_outputs {
998 let amount = txout.value.to_signed().unwrap().to_sat();
999 let script =
1000 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
1001 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
1002 }
1003
1004 let verify_result = bitcoinkernel::verify(
1006 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
1007 .unwrap(),
1008 Some(100_000),
1009 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
1010 0,
1011 None,
1012 &actual_outputs,
1013 );
1014
1015 assert!(verify_result.is_ok());
1016 assert_eq!(actual_tx.input[0].witness.len(), 1);
1017 }
1018
1019 #[test]
1020 fn test_verify_and_sign_multi_input_tx() {
1021 let secp = Secp256k1::new();
1022
1023 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1025 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
1026
1027 let op_true_script = Script::builder()
1029 .push_opcode(bitcoin::opcodes::OP_TRUE)
1030 .into_script();
1031
1032 let taproot_builder = TaprootBuilder::new()
1034 .add_leaf(0, op_true_script.clone())
1035 .unwrap();
1036 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
1037
1038 let control_block = taproot_spend_info
1040 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
1041 .unwrap();
1042
1043 let mut witness = Witness::new();
1045 witness.push(op_true_script.as_bytes());
1046 witness.push(control_block.serialize());
1047
1048 let mut emulated_tx = create_test_transaction_multi_input();
1050 emulated_tx.input[1].witness = witness;
1051
1052 let aux_rand = [1u8; 32];
1054 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1055 let child_secret = derive_child_secret_key(
1056 parent_secret,
1057 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
1058 )
1059 .unwrap();
1060
1061 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
1063 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
1064 let actual_spent_outputs = [
1065 TxOut {
1066 value: Amount::from_sat(200_000),
1067 script_pubkey: actual_address.script_pubkey(),
1068 },
1069 TxOut {
1070 value: Amount::from_sat(100_000),
1071 script_pubkey: actual_address.script_pubkey(),
1072 },
1073 ];
1074
1075 let actual_tx = verify_and_sign(
1077 &DefaultVerifier,
1078 &emulated_tx,
1079 &actual_spent_outputs,
1080 &aux_rand,
1081 parent_secret,
1082 HashMap::new(),
1083 )
1084 .unwrap();
1085
1086 let mut actual_outputs = Vec::new();
1087 for txout in actual_spent_outputs {
1088 let amount = txout.value.to_signed().unwrap().to_sat();
1089 let script =
1090 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
1091 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
1092 }
1093
1094 let verify_result = bitcoinkernel::verify(
1096 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
1097 .unwrap(),
1098 Some(100_000),
1099 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
1100 1,
1101 None,
1102 &actual_outputs,
1103 );
1104
1105 assert!(verify_result.is_ok());
1106 assert_eq!(actual_tx.input[1].witness.len(), 1);
1107 }
1108}
1109
1110#[cfg(test)]
1111mod non_kernel_tests {
1112 use super::*;
1113 use bitcoin::{
1114 Script,
1115 key::{Secp256k1, UntweakedPublicKey},
1116 taproot::TaprootBuilder,
1117 };
1118
1119 #[test]
1120 fn test_generate_address() {
1121 let secp = Secp256k1::new();
1122
1123 let emulated_script = Script::builder()
1125 .push_opcode(bitcoin::opcodes::OP_TRUE)
1126 .into_script();
1127
1128 let taproot_builder = TaprootBuilder::new()
1130 .add_leaf(0, emulated_script.clone())
1131 .unwrap();
1132 let dummy_internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1133 let dummy_internal_key = UntweakedPublicKey::from(dummy_internal_secret.public_key(&secp));
1134 let taproot_spend_info = taproot_builder.finalize(&secp, dummy_internal_key).unwrap();
1135 let emulated_merkle_root = taproot_spend_info.merkle_root().unwrap();
1136
1137 let backup_merkle_root = emulated_merkle_root;
1139
1140 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1142 let master_public_key: PublicKey = internal_secret.public_key(&secp);
1143 let onchain_address = generate_address(
1144 master_public_key,
1145 emulated_merkle_root,
1146 Some(backup_merkle_root),
1147 Network::Bitcoin,
1148 );
1149
1150 assert!(onchain_address.is_ok());
1151 }
1152
1153 #[test]
1154 fn test_public_private_key_derivation_consistency() {
1155 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1156 let parent_public = parent_secret.public_key(&Secp256k1::new());
1157 let merkle_root = [42u8; 32];
1158
1159 let child_secret = derive_child_secret_key(parent_secret, merkle_root).unwrap();
1160 let child_public_from_secret = child_secret.public_key(&Secp256k1::new());
1161 let child_public_direct = derive_child_public_key(parent_public, merkle_root).unwrap();
1162
1163 assert_eq!(child_public_from_secret, child_public_direct);
1164 }
1165
1166 #[test]
1167 fn test_curve_order_reduction() {
1168 let max_bytes = [0xFF; 32];
1169 let reduced = reduce_mod_order(&max_bytes);
1170 #[allow(clippy::useless_conversion)]
1172 let _ = Scalar::from(reduced);
1173 }
1174}