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 use bitcoin;
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 InvalidControlBlock,
76 InvalidSighash,
78 MissingSpentOutputs,
80 UnexpectedInput,
82}
83
84pub trait Verifier {
87 fn verify(
97 &self,
98 script_pubkeys: &HashMap<usize, ScriptBuf>,
99 tx_to: &Transaction,
100 spent_outputs: &[TxOut],
101 ) -> Result<(), Error>;
102}
103
104#[cfg(feature = "bitcoinkernel")]
106pub struct DefaultVerifier;
107
108#[cfg(feature = "bitcoinkernel")]
109impl Verifier for DefaultVerifier {
110 fn verify(
111 &self,
112 script_pubkeys: &HashMap<usize, ScriptBuf>,
113 tx_to: &Transaction,
114 spent_outputs: &[TxOut],
115 ) -> Result<(), Error> {
116 let mut amounts = Vec::new();
117 let mut outputs = Vec::new();
118 for txout in spent_outputs {
119 let amount = txout
120 .value
121 .to_signed()
122 .map_err(|_| Error::VerificationFailed("invalid amount".to_string()))?
123 .to_sat();
124 let script = bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes())
125 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
126
127 amounts.push(amount);
128 outputs.push(bitcoinkernel::TxOut::new(&script, amount));
129 }
130
131 let tx_bytes = bitcoin::consensus::serialize(tx_to);
132 let tx_to = &bitcoinkernel::Transaction::try_from(tx_bytes.as_slice())
133 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
134
135 for (&i, script_pubkey) in script_pubkeys {
136 let amount = amounts.get(i).cloned();
137 let script_pubkey = &bitcoinkernel::ScriptPubkey::try_from(script_pubkey.as_bytes())
138 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
139
140 bitcoinkernel::verify(script_pubkey, amount, tx_to, i, None, &outputs)
141 .map_err(|e| Error::VerificationFailed(e.to_string()))?;
142 }
143
144 Ok(())
145 }
146}
147
148pub fn verify_and_sign<V: Verifier>(
178 verifier: &V,
179 emulated_tx_to: &Transaction,
180 actual_spent_outputs: &[TxOut],
181 aux_rand: &[u8; 32],
182 parent_key: SecretKey,
183 backup_merkle_roots: HashMap<usize, TapNodeHash>,
184) -> Result<Transaction, Error> {
185 let mut emulated_script_pubkeys: HashMap<usize, ScriptBuf> = HashMap::new();
187
188 let mut child_keys_by_index: HashMap<usize, SecretKey> = HashMap::new();
190
191 if actual_spent_outputs.len() < emulated_tx_to.input.len() {
193 return Err(Error::MissingSpentOutputs);
194 }
195
196 let secp = Secp256k1::new();
198 for (i, input) in emulated_tx_to.input.clone().into_iter().enumerate() {
199 let (Some(true), Some(control_block), Some(tapleaf)) = (
201 actual_spent_outputs[i]
202 .script_pubkey
203 .is_p2tr()
204 .then_some(true),
205 input.witness.taproot_control_block(),
206 input.witness.taproot_leaf_script(),
207 ) else {
208 continue;
209 };
210
211 let Ok(control_block) = ControlBlock::decode(control_block) else {
213 return Err(Error::InvalidControlBlock);
214 };
215
216 let mut merkle_root = TapNodeHash::from_script(tapleaf.script, tapleaf.version);
218 for elem in &control_block.merkle_branch {
219 merkle_root = TapNodeHash::from_node_hashes(merkle_root, *elem);
220 }
221
222 let emulated_address = Address::p2tr(
224 &secp,
225 control_block.internal_key,
226 Some(merkle_root),
227 Network::Bitcoin,
228 );
229
230 if actual_spent_outputs[i].script_pubkey == emulated_address.script_pubkey() {
232 continue;
233 }
234
235 let child_key = derive_child_secret_key(parent_key, merkle_root.to_byte_array())?;
237 let (internal_key, _) = child_key.public_key(&secp).x_only_public_key();
238 child_keys_by_index.insert(i, child_key);
239
240 let backup_merkle_root = backup_merkle_roots.get(&i).cloned();
242 let actual_address =
243 Address::p2tr(&secp, internal_key, backup_merkle_root, Network::Bitcoin);
244 if actual_spent_outputs[i].script_pubkey != actual_address.script_pubkey() {
245 return Err(Error::UnexpectedInput);
246 }
247
248 emulated_script_pubkeys.insert(i, emulated_address.script_pubkey());
250 }
251
252 verifier.verify(
254 &emulated_script_pubkeys,
255 emulated_tx_to,
256 actual_spent_outputs,
257 )?;
258
259 let mut tx = emulated_tx_to.clone();
260 for &i in emulated_script_pubkeys.keys() {
261 let annex = tx.input[i]
263 .witness
264 .taproot_annex()
265 .filter(|bytes| bytes.len() > 1 && bytes[1] == TAPROOT_ANNEX_DATA_CARRYING_TAG)
266 .and_then(|bytes| Annex::new(bytes).ok());
267
268 let mut sighash_cache = SighashCache::new(&tx);
270 let sighash_bytes = sighash_cache
271 .taproot_signature_hash(
272 i,
273 &Prevouts::All(actual_spent_outputs),
274 annex.clone(),
275 None,
276 TapSighashType::Default,
277 )
278 .map_err(|_| Error::InvalidSighash)?;
279 let mut sighash = [0u8; 32];
280 sighash.copy_from_slice(sighash_bytes.as_byte_array());
281
282 let child_key = child_keys_by_index.get(&i).unwrap();
284 let (internal_key, parity) = child_key.public_key(&secp).x_only_public_key();
285 let child_key_for_tweak = if parity == secp256k1::Parity::Odd {
286 child_key.negate()
287 } else {
288 *child_key
289 };
290
291 let backup_merkle_root = backup_merkle_roots.get(&i).cloned();
293 let tweak = TapTweakHash::from_key_and_tweak(internal_key, backup_merkle_root);
294 let tweaked_secret_key = child_key_for_tweak.add_tweak(&tweak.to_scalar())?;
295 let tweaked_keypair = Keypair::from_secret_key(&secp, &tweaked_secret_key);
296
297 let mut hasher = Sha256::new();
299 hasher.update(aux_rand);
300 hasher.update((i as u64).to_le_bytes());
301 let aux_rand: [u8; 32] = hasher.finalize().into();
302
303 let message = Message::from_digest(sighash);
305 let signature = secp.sign_schnorr_with_aux_rand(&message, &tweaked_keypair, &aux_rand);
306
307 let tap_signature = Signature {
309 signature,
310 sighash_type: TapSighashType::Default,
311 };
312
313 let mut witness = Witness::new();
315 witness.push(tap_signature.to_vec());
316 if let Some(annex) = annex {
317 witness.push(annex.as_bytes());
318 }
319 tx.input[i].witness = witness;
320 }
321
322 Ok(tx)
323}
324
325pub fn generate_address(
337 parent_key: PublicKey,
338 emulated_merkle_root: TapNodeHash,
339 backup_merkle_root: Option<TapNodeHash>,
340 network: Network,
341) -> Result<Address, secp256k1::Error> {
342 let secp = Secp256k1::new();
343 let child_key = derive_child_public_key(parent_key, emulated_merkle_root.to_byte_array())?;
344 let internal_key = XOnlyPublicKey::from(child_key);
345 let address = Address::p2tr(&secp, internal_key, backup_merkle_root, network);
346
347 Ok(address)
348}
349
350fn derive_child_secret_key(
353 parent_key: SecretKey,
354 emulated_merkle_root: [u8; 32],
355) -> Result<SecretKey, secp256k1::Error> {
356 let secp = Secp256k1::new();
357
358 let parent_public = parent_key.public_key(&secp);
360
361 let mut mac = Hmac::<Sha512>::new_from_slice(&parent_public.serialize())
363 .expect("PublicKey serialization should always be non-empty");
364 mac.update(&emulated_merkle_root);
365 let hmac_result = mac.finalize().into_bytes();
366
367 let mut key_material = [0u8; 32];
369 key_material.copy_from_slice(&hmac_result[..32]);
370 let scalar = reduce_mod_order(&key_material);
371
372 parent_key.add_tweak(&scalar)
374}
375
376fn derive_child_public_key(
379 parent_public: PublicKey,
380 emulated_merkle_root: [u8; 32],
381) -> Result<PublicKey, secp256k1::Error> {
382 let secp = Secp256k1::new();
383
384 let mut mac = Hmac::<Sha512>::new_from_slice(&parent_public.serialize())
386 .expect("PublicKey serialization should always be non-empty");
387 mac.update(&emulated_merkle_root);
388 let hmac_result = mac.finalize().into_bytes();
389
390 let mut key_material = [0u8; 32];
392 key_material.copy_from_slice(&hmac_result[..32]);
393 let scalar = reduce_mod_order(&key_material);
394
395 parent_public.add_exp_tweak(&secp, &scalar)
397}
398
399fn reduce_mod_order(bytes: &[u8; 32]) -> Scalar {
401 let mut attempt = *bytes;
404 loop {
405 match Scalar::from_be_bytes(attempt) {
406 Ok(scalar) => return scalar,
407 Err(_) => {
408 attempt = subtract_curve_order(&attempt);
411 }
412 }
413 }
414}
415
416fn subtract_curve_order(bytes: &[u8; 32]) -> [u8; 32] {
418 let value = BigUint::from_bytes_be(bytes);
419 let order = BigUint::from_bytes_be(&CURVE_ORDER);
420 let reduced = value % order;
421
422 let mut result = [0u8; 32];
423 let reduced_bytes = reduced.to_bytes_be();
424 let offset = 32 - reduced_bytes.len();
425 result[offset..].copy_from_slice(&reduced_bytes);
426 result
427}
428
429impl fmt::Display for Error {
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 match self {
432 Error::VerificationFailed(e) => {
433 write!(f, "Verification failed: {e}")
434 }
435 Error::Secp256k1(e) => {
436 write!(f, "Secp256k1 cryptographic operation failed: {e}")
437 }
438 Error::InvalidControlBlock => {
439 write!(f, "Input has invalid control block")
440 }
441 Error::InvalidSighash => {
442 write!(f, "Unable to calculate sighash for input")
443 }
444 Error::MissingSpentOutputs => {
445 write!(f, "Missing spent outputs")
446 }
447 Error::UnexpectedInput => {
448 write!(f, "Unexpected input scriptPubKey")
449 }
450 }
451 }
452}
453
454impl From<secp256k1::Error> for Error {
455 fn from(error: secp256k1::Error) -> Self {
456 Error::Secp256k1(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_missing_spent_outputs() {
517 let result = verify_and_sign(
518 &DefaultVerifier,
519 &create_test_transaction_single_input(),
520 &[],
521 &[1u8; 32],
522 SecretKey::from_slice(&[1u8; 32]).unwrap(),
523 HashMap::new(),
524 );
525
526 assert!(matches!(result, Err(Error::MissingSpentOutputs)));
527 }
528
529 #[test]
530 fn test_unexpected_input_script_pubkey() {
531 let secp = Secp256k1::new();
532
533 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
535 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
536
537 let op_true_script = Script::builder()
539 .push_opcode(bitcoin::opcodes::OP_TRUE)
540 .into_script();
541
542 let taproot_builder = TaprootBuilder::new()
544 .add_leaf(0, op_true_script.clone())
545 .unwrap();
546 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
547
548 let control_block = taproot_spend_info
550 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
551 .unwrap();
552
553 let mut witness = Witness::new();
555 witness.push(op_true_script.as_bytes());
556 witness.push(control_block.serialize());
557
558 let mut emulated_tx = create_test_transaction_single_input();
560 emulated_tx.input[0].witness = witness;
561
562 let dummy_p2tr_address = Address::p2tr(&secp, internal_key, None, Network::Bitcoin);
564 let txout = TxOut {
565 value: Amount::from_sat(100000),
566 script_pubkey: dummy_p2tr_address.script_pubkey(),
567 };
568
569 let result = verify_and_sign(
570 &DefaultVerifier,
571 &emulated_tx,
572 std::slice::from_ref(&txout),
573 &[1u8; 32],
574 SecretKey::from_slice(&[1u8; 32]).unwrap(),
575 HashMap::new(),
576 );
577
578 assert!(matches!(result, Err(Error::UnexpectedInput)));
579 }
580
581 #[test]
582 fn test_verify_and_sign_single_input_single_leaf() {
583 let secp = Secp256k1::new();
584
585 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
587 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
588
589 let op_true_script = Script::builder()
591 .push_opcode(bitcoin::opcodes::OP_TRUE)
592 .into_script();
593
594 let taproot_builder = TaprootBuilder::new()
596 .add_leaf(0, op_true_script.clone())
597 .unwrap();
598 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
599
600 let control_block = taproot_spend_info
602 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
603 .unwrap();
604
605 let mut witness = Witness::new();
607 witness.push(op_true_script.as_bytes());
608 witness.push(control_block.serialize());
609
610 let mut emulated_tx = create_test_transaction_single_input();
612 emulated_tx.input[0].witness = witness;
613
614 let aux_rand = [1u8; 32];
616 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
617 let child_secret = derive_child_secret_key(
618 parent_secret,
619 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
620 )
621 .unwrap();
622
623 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
625 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
626 let actual_spent_outputs = [TxOut {
627 value: Amount::from_sat(100_000),
628 script_pubkey: actual_address.script_pubkey(),
629 }];
630
631 let actual_tx = verify_and_sign(
633 &DefaultVerifier,
634 &emulated_tx,
635 &actual_spent_outputs,
636 &aux_rand,
637 parent_secret,
638 HashMap::new(),
639 )
640 .unwrap();
641
642 let mut actual_outputs = Vec::new();
643 for txout in actual_spent_outputs {
644 let amount = txout.value.to_signed().unwrap().to_sat();
645 let script =
646 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
647 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
648 }
649
650 let verify_result = bitcoinkernel::verify(
652 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
653 .unwrap(),
654 Some(100_000),
655 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
656 0,
657 None,
658 &actual_outputs,
659 );
660
661 assert!(verify_result.is_ok());
662 assert_eq!(actual_tx.input[0].witness.len(), 1);
663 }
664
665 #[test]
666 fn test_verify_and_sign_single_input_multiple_leaves() {
667 let secp = Secp256k1::new();
668
669 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
671 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
672
673 let op_true_script = Script::builder()
675 .push_opcode(bitcoin::opcodes::OP_TRUE)
676 .into_script();
677 let op_false_script = Script::builder()
678 .push_opcode(bitcoin::opcodes::OP_FALSE)
679 .into_script();
680
681 let taproot_builder = TaprootBuilder::new()
683 .add_leaf(1, op_true_script.clone())
684 .unwrap()
685 .add_leaf(1, op_false_script.clone())
686 .unwrap();
687 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
688
689 let control_block = taproot_spend_info
691 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
692 .unwrap();
693
694 let mut witness = Witness::new();
696 witness.push(op_true_script.as_bytes());
697 witness.push(control_block.serialize());
698
699 let mut emulated_tx = create_test_transaction_single_input();
701 emulated_tx.input[0].witness = witness;
702
703 let aux_rand = [1u8; 32];
705 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
706 let child_secret = derive_child_secret_key(
707 parent_secret,
708 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
709 )
710 .unwrap();
711
712 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
714 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
715 let actual_spent_outputs = [TxOut {
716 value: Amount::from_sat(100_000),
717 script_pubkey: actual_address.script_pubkey(),
718 }];
719
720 let actual_tx = verify_and_sign(
722 &DefaultVerifier,
723 &emulated_tx,
724 &actual_spent_outputs,
725 &aux_rand,
726 parent_secret,
727 HashMap::new(),
728 )
729 .unwrap();
730
731 let mut actual_outputs = Vec::new();
732 for txout in actual_spent_outputs {
733 let amount = txout.value.to_signed().unwrap().to_sat();
734 let script =
735 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
736 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
737 }
738
739 let verify_result = bitcoinkernel::verify(
741 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
742 .unwrap(),
743 Some(100_000),
744 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
745 0,
746 None,
747 &actual_outputs,
748 );
749
750 assert!(verify_result.is_ok());
751 assert_eq!(actual_tx.input[0].witness.len(), 1);
752 }
753
754 #[test]
755 fn test_verify_and_sign_single_input_with_backup() {
756 let secp = Secp256k1::new();
757
758 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
760 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
761
762 let op_true_script = Script::builder()
764 .push_opcode(bitcoin::opcodes::OP_TRUE)
765 .into_script();
766
767 let taproot_builder = TaprootBuilder::new()
769 .add_leaf(0, op_true_script.clone())
770 .unwrap();
771 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
772
773 let control_block = taproot_spend_info
775 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
776 .unwrap();
777
778 let mut witness = Witness::new();
780 witness.push(op_true_script.as_bytes());
781 witness.push(control_block.serialize());
782
783 let mut emulated_tx = create_test_transaction_single_input();
785 emulated_tx.input[0].witness = witness;
786
787 let aux_rand = [1u8; 32];
789 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
790 let child_secret = derive_child_secret_key(
791 parent_secret,
792 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
793 )
794 .unwrap();
795
796 let actual_backup_merkle_root = taproot_spend_info.merkle_root();
798 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
799 let actual_address = Address::p2tr(
800 &secp,
801 actual_internal_key,
802 actual_backup_merkle_root,
803 Network::Bitcoin,
804 );
805 let actual_spent_outputs = [TxOut {
806 value: Amount::from_sat(100_000),
807 script_pubkey: actual_address.script_pubkey(),
808 }];
809
810 let actual_tx = verify_and_sign(
812 &DefaultVerifier,
813 &emulated_tx,
814 &actual_spent_outputs,
815 &aux_rand,
816 parent_secret,
817 HashMap::from([(0, actual_backup_merkle_root.unwrap())]),
818 )
819 .unwrap();
820
821 let mut actual_outputs = Vec::new();
822 for txout in actual_spent_outputs {
823 let amount = txout.value.to_signed().unwrap().to_sat();
824 let script =
825 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
826 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
827 }
828
829 let verify_result = bitcoinkernel::verify(
831 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
832 .unwrap(),
833 Some(100_000),
834 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
835 0,
836 None,
837 &actual_outputs,
838 );
839
840 assert!(verify_result.is_ok());
841 assert_eq!(actual_tx.input[0].witness.len(), 1);
842 }
843
844 #[test]
845 fn test_verify_and_sign_single_input_single_leaf_with_data_carrying_annex() {
846 let secp = Secp256k1::new();
847
848 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
850 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
851
852 let op_true_script = Script::builder()
854 .push_opcode(bitcoin::opcodes::OP_TRUE)
855 .into_script();
856
857 let taproot_builder = TaprootBuilder::new()
859 .add_leaf(0, op_true_script.clone())
860 .unwrap();
861 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
862
863 let control_block = taproot_spend_info
865 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
866 .unwrap();
867
868 let annex: &[u8] = &[0x50, TAPROOT_ANNEX_DATA_CARRYING_TAG, 0x01, 0x02, 0x03];
870
871 let mut witness = Witness::new();
873 witness.push(op_true_script.as_bytes());
874 witness.push(control_block.serialize());
875 witness.push(annex);
876
877 let mut emulated_tx = create_test_transaction_single_input();
879 emulated_tx.input[0].witness = witness;
880
881 let aux_rand = [1u8; 32];
883 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
884 let child_secret = derive_child_secret_key(
885 parent_secret,
886 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
887 )
888 .unwrap();
889
890 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
892 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
893 let actual_spent_outputs = [TxOut {
894 value: Amount::from_sat(100_000),
895 script_pubkey: actual_address.script_pubkey(),
896 }];
897
898 let actual_tx = verify_and_sign(
900 &DefaultVerifier,
901 &emulated_tx,
902 &actual_spent_outputs,
903 &aux_rand,
904 parent_secret,
905 HashMap::new(),
906 )
907 .unwrap();
908
909 let mut actual_outputs = Vec::new();
910 for txout in actual_spent_outputs {
911 let amount = txout.value.to_signed().unwrap().to_sat();
912 let script =
913 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
914 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
915 }
916
917 let verify_result = bitcoinkernel::verify(
919 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
920 .unwrap(),
921 Some(100_000),
922 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
923 0,
924 None,
925 &actual_outputs,
926 );
927
928 assert!(verify_result.is_ok());
929 assert_eq!(actual_tx.input[0].witness.len(), 2);
930 assert_eq!(&actual_tx.input[0].witness[1], annex);
931 }
932
933 #[test]
934 fn test_verify_and_sign_single_input_single_leaf_with_non_data_carrying_annex() {
935 let secp = Secp256k1::new();
936
937 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
939 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
940
941 let op_true_script = Script::builder()
943 .push_opcode(bitcoin::opcodes::OP_TRUE)
944 .into_script();
945
946 let taproot_builder = TaprootBuilder::new()
948 .add_leaf(0, op_true_script.clone())
949 .unwrap();
950 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
951
952 let control_block = taproot_spend_info
954 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
955 .unwrap();
956
957 let annex: &[u8] = &[0x50, 0x01, 0x02, 0x03];
959
960 let mut witness = Witness::new();
962 witness.push(op_true_script.as_bytes());
963 witness.push(control_block.serialize());
964 witness.push(annex);
965
966 let mut emulated_tx = create_test_transaction_single_input();
968 emulated_tx.input[0].witness = witness;
969
970 let aux_rand = [1u8; 32];
972 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
973 let child_secret = derive_child_secret_key(
974 parent_secret,
975 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
976 )
977 .unwrap();
978
979 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
981 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
982 let actual_spent_outputs = [TxOut {
983 value: Amount::from_sat(100_000),
984 script_pubkey: actual_address.script_pubkey(),
985 }];
986
987 let actual_tx = verify_and_sign(
989 &DefaultVerifier,
990 &emulated_tx,
991 &actual_spent_outputs,
992 &aux_rand,
993 parent_secret,
994 HashMap::new(),
995 )
996 .unwrap();
997
998 let mut actual_outputs = Vec::new();
999 for txout in actual_spent_outputs {
1000 let amount = txout.value.to_signed().unwrap().to_sat();
1001 let script =
1002 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
1003 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
1004 }
1005
1006 let verify_result = bitcoinkernel::verify(
1008 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
1009 .unwrap(),
1010 Some(100_000),
1011 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
1012 0,
1013 None,
1014 &actual_outputs,
1015 );
1016
1017 assert!(verify_result.is_ok());
1018 assert_eq!(actual_tx.input[0].witness.len(), 1);
1019 }
1020
1021 #[test]
1022 fn test_verify_and_sign_multi_input_tx() {
1023 let secp = Secp256k1::new();
1024
1025 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1027 let internal_key = UntweakedPublicKey::from(internal_secret.public_key(&secp));
1028
1029 let op_true_script = Script::builder()
1031 .push_opcode(bitcoin::opcodes::OP_TRUE)
1032 .into_script();
1033
1034 let taproot_builder = TaprootBuilder::new()
1036 .add_leaf(0, op_true_script.clone())
1037 .unwrap();
1038 let taproot_spend_info = taproot_builder.finalize(&secp, internal_key).unwrap();
1039
1040 let control_block = taproot_spend_info
1042 .control_block(&(op_true_script.clone(), LeafVersion::TapScript))
1043 .unwrap();
1044
1045 let mut witness = Witness::new();
1047 witness.push(op_true_script.as_bytes());
1048 witness.push(control_block.serialize());
1049
1050 let mut emulated_tx = create_test_transaction_multi_input();
1052 emulated_tx.input[1].witness = witness;
1053
1054 let aux_rand = [1u8; 32];
1056 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1057 let child_secret = derive_child_secret_key(
1058 parent_secret,
1059 taproot_spend_info.merkle_root().unwrap().to_byte_array(),
1060 )
1061 .unwrap();
1062
1063 let actual_internal_key = XOnlyPublicKey::from(child_secret.public_key(&secp));
1065 let actual_address = Address::p2tr(&secp, actual_internal_key, None, Network::Bitcoin);
1066 let actual_spent_outputs = [
1067 TxOut {
1068 value: Amount::from_sat(200_000),
1069 script_pubkey: actual_address.script_pubkey(),
1070 },
1071 TxOut {
1072 value: Amount::from_sat(100_000),
1073 script_pubkey: actual_address.script_pubkey(),
1074 },
1075 ];
1076
1077 let actual_tx = verify_and_sign(
1079 &DefaultVerifier,
1080 &emulated_tx,
1081 &actual_spent_outputs,
1082 &aux_rand,
1083 parent_secret,
1084 HashMap::new(),
1085 )
1086 .unwrap();
1087
1088 let mut actual_outputs = Vec::new();
1089 for txout in actual_spent_outputs {
1090 let amount = txout.value.to_signed().unwrap().to_sat();
1091 let script =
1092 bitcoinkernel::ScriptPubkey::try_from(txout.script_pubkey.as_bytes()).unwrap();
1093 actual_outputs.push(bitcoinkernel::TxOut::new(&script, amount));
1094 }
1095
1096 let verify_result = bitcoinkernel::verify(
1098 &bitcoinkernel::ScriptPubkey::try_from(actual_address.script_pubkey().as_bytes())
1099 .unwrap(),
1100 Some(100_000),
1101 &bitcoinkernel::Transaction::try_from(serialize(&actual_tx).as_slice()).unwrap(),
1102 1,
1103 None,
1104 &actual_outputs,
1105 );
1106
1107 assert!(verify_result.is_ok());
1108 assert_eq!(actual_tx.input[1].witness.len(), 1);
1109 }
1110}
1111
1112#[cfg(test)]
1113mod non_kernel_tests {
1114 use super::*;
1115 use bitcoin::{
1116 Script,
1117 key::{Secp256k1, UntweakedPublicKey},
1118 taproot::TaprootBuilder,
1119 };
1120
1121 #[test]
1122 fn test_generate_address() {
1123 let secp = Secp256k1::new();
1124
1125 let emulated_script = Script::builder()
1127 .push_opcode(bitcoin::opcodes::OP_TRUE)
1128 .into_script();
1129
1130 let taproot_builder = TaprootBuilder::new()
1132 .add_leaf(0, emulated_script.clone())
1133 .unwrap();
1134 let dummy_internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1135 let dummy_internal_key = UntweakedPublicKey::from(dummy_internal_secret.public_key(&secp));
1136 let taproot_spend_info = taproot_builder.finalize(&secp, dummy_internal_key).unwrap();
1137 let emulated_merkle_root = taproot_spend_info.merkle_root().unwrap();
1138
1139 let backup_merkle_root = emulated_merkle_root;
1141
1142 let internal_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1144 let master_public_key: PublicKey = internal_secret.public_key(&secp);
1145 let onchain_address = generate_address(
1146 master_public_key,
1147 emulated_merkle_root,
1148 Some(backup_merkle_root),
1149 Network::Bitcoin,
1150 );
1151
1152 assert!(onchain_address.is_ok());
1153 }
1154
1155 #[test]
1156 fn test_public_private_key_derivation_consistency() {
1157 let parent_secret = SecretKey::from_slice(&[1u8; 32]).unwrap();
1158 let parent_public = parent_secret.public_key(&Secp256k1::new());
1159 let merkle_root = [42u8; 32];
1160
1161 let child_secret = derive_child_secret_key(parent_secret, merkle_root).unwrap();
1162 let child_public_from_secret = child_secret.public_key(&Secp256k1::new());
1163 let child_public_direct = derive_child_public_key(parent_public, merkle_root).unwrap();
1164
1165 assert_eq!(child_public_from_secret, child_public_direct);
1166 }
1167
1168 #[test]
1169 fn test_curve_order_reduction() {
1170 let max_bytes = [0xFF; 32];
1171 let reduced = reduce_mod_order(&max_bytes);
1172 #[allow(clippy::useless_conversion)]
1174 let _ = Scalar::from(reduced);
1175 }
1176}