1#![allow(unused_braces)] use std::borrow::Borrow;
25use std::fmt::{self, Formatter, LowerHex, UpperHex};
26use std::ops::BitXor;
27use std::str::FromStr;
28use std::{cmp, io, slice, vec};
29
30use amplify::confinement::Confined;
31use amplify::hex::FromHex;
32use amplify::{confinement, ByteArray, Bytes32, Wrapper};
33use commit_verify::{DigestExt, Sha256};
34use secp256k1::{Keypair, PublicKey, Scalar, XOnlyPublicKey};
35use strict_encoding::{
36 DecodeError, ReadTuple, StrictDecode, StrictEncode, StrictProduct, StrictTuple, StrictType,
37 TypeName, TypedRead, TypedWrite, WriteTuple,
38};
39
40use crate::opcodes::*;
41use crate::{
42 CompressedPk, ConsensusEncode, InvalidPubkey, PubkeyParseError, ScriptBytes, ScriptPubkey,
43 VarInt, VarIntBytes, WitnessVer, LIB_NAME_BITCOIN,
44};
45
46const MIDSTATE_TAPLEAF: [u8; 7] = *b"TapLeaf";
48const MIDSTATE_TAPBRANCH: [u8; 9] = *b"TapBranch";
52const MIDSTATE_TAPTWEAK: [u8; 8] = *b"TapTweak";
56pub const MIDSTATE_TAPSIGHASH: [u8; 10] = *b"TapSighash";
60impl<const LEN: usize> From<InvalidPubkey<LEN>> for DecodeError {
63 fn from(e: InvalidPubkey<LEN>) -> Self {
64 DecodeError::DataIntegrityError(format!("invalid x-only public key value '{e}'"))
65 }
66}
67
68#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
74#[wrapper(Deref, LowerHex, Display)]
75#[wrapper_mut(DerefMut)]
76#[derive(StrictType, StrictDumb)]
77#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self::dumb())]
78#[cfg_attr(
79 feature = "serde",
80 derive(Serialize, Deserialize),
81 serde(crate = "serde_crate", transparent)
82)]
83pub struct XOnlyPk(XOnlyPublicKey);
84
85impl XOnlyPk {
86 fn dumb() -> Self { Self(XOnlyPublicKey::from_slice(&[1u8; 32]).unwrap()) }
87
88 pub fn from_byte_array(data: [u8; 32]) -> Result<Self, InvalidPubkey<32>> {
89 XOnlyPublicKey::from_slice(data.as_ref())
90 .map(Self)
91 .map_err(|_| InvalidPubkey::Specified(data.into()))
92 }
93
94 pub fn to_byte_array(&self) -> [u8; 32] { self.0.serialize() }
95
96 pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, InvalidPubkey<33>> {
97 Ok(XOnlyPk(XOnlyPublicKey::from_slice(bytes.as_ref())?))
98 }
99}
100
101impl From<CompressedPk> for XOnlyPk {
102 fn from(pubkey: CompressedPk) -> Self { XOnlyPk(pubkey.x_only_public_key().0) }
103}
104
105impl From<PublicKey> for XOnlyPk {
106 fn from(pubkey: PublicKey) -> Self { XOnlyPk(pubkey.x_only_public_key().0) }
107}
108
109impl From<XOnlyPk> for [u8; 32] {
110 fn from(pk: XOnlyPk) -> [u8; 32] { pk.to_byte_array() }
111}
112
113impl StrictEncode for XOnlyPk {
114 fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
115 let bytes = Bytes32::from(self.0.serialize());
116 writer.write_newtype::<Self>(&bytes)
117 }
118}
119
120impl StrictDecode for XOnlyPk {
121 fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
122 reader.read_tuple(|r| {
123 let bytes: Bytes32 = r.read_field()?;
124 XOnlyPublicKey::from_slice(bytes.as_slice())
125 .map(Self)
126 .map_err(|_| InvalidPubkey::Specified(bytes).into())
127 })
128 }
129}
130
131impl FromStr for XOnlyPk {
132 type Err = PubkeyParseError<32>;
133
134 fn from_str(s: &str) -> Result<Self, Self::Err> {
135 let data = <[u8; 32]>::from_hex(s)?;
136 let pk = Self::from_byte_array(data)?;
137 Ok(pk)
138 }
139}
140
141#[derive(Eq, PartialEq, From)]
144pub struct InternalKeypair(#[from] Keypair);
145
146impl InternalKeypair {
147 pub fn to_output_keypair(&self, merkle_root: Option<TapNodeHash>) -> (Keypair, Parity) {
148 let internal_pk = self.0.x_only_public_key().0;
149 let mut engine = Sha256::from_tag(MIDSTATE_TAPTWEAK);
150 engine.input_raw(&internal_pk.serialize());
152 if let Some(merkle_root) = merkle_root {
153 engine.input_raw(merkle_root.into_tap_hash().as_ref());
154 }
155 let tweak =
156 Scalar::from_be_bytes(engine.finish()).expect("hash value greater than curve order");
157 let pair = self.0.add_xonly_tweak(secp256k1::SECP256K1, &tweak).expect("hash collision");
158 let (outpput_key, tweaked_parity) = pair.x_only_public_key();
159 debug_assert!(internal_pk.tweak_add_check(
160 secp256k1::SECP256K1,
161 &outpput_key,
162 tweaked_parity,
163 tweak
164 ));
165 (pair, tweaked_parity.into())
166 }
167}
168
169#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
172#[wrapper(Deref, LowerHex, Display, FromStr)]
173#[wrapper_mut(DerefMut)]
174#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
175#[strict_type(lib = LIB_NAME_BITCOIN)]
176#[cfg_attr(
177 feature = "serde",
178 derive(Serialize, Deserialize),
179 serde(crate = "serde_crate", transparent)
180)]
181pub struct InternalPk(
182 #[from]
183 #[from(XOnlyPublicKey)]
184 XOnlyPk,
185);
186
187impl InternalPk {
188 #[inline]
189 pub fn from_unchecked(pk: XOnlyPk) -> Self { Self(pk) }
190
191 #[inline]
192 pub fn from_byte_array(data: [u8; 32]) -> Result<Self, InvalidPubkey<32>> {
193 XOnlyPk::from_byte_array(data).map(Self)
194 }
195
196 #[inline]
197 pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, InvalidPubkey<33>> {
198 XOnlyPk::from_bytes(bytes).map(Self)
199 }
200
201 #[inline]
202 pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() }
203
204 #[inline]
205 pub fn to_xonly_pk(&self) -> XOnlyPk { self.0 }
206
207 pub fn to_output_pk(&self, merkle_root: Option<TapNodeHash>) -> (OutputPk, Parity) {
208 let mut engine = Sha256::from_tag(MIDSTATE_TAPTWEAK);
209 engine.input_raw(&self.0.serialize());
211 if let Some(merkle_root) = merkle_root {
212 engine.input_raw(merkle_root.into_tap_hash().as_ref());
213 }
214 let tweak =
215 Scalar::from_be_bytes(engine.finish()).expect("hash value greater than curve order");
216 let (output_key, tweaked_parity) =
217 self.0.add_tweak(secp256k1::SECP256K1, &tweak).expect("hash collision");
218 debug_assert!(self.tweak_add_check(
219 secp256k1::SECP256K1,
220 &output_key,
221 tweaked_parity,
222 tweak
223 ));
224 (OutputPk(XOnlyPk(output_key)), tweaked_parity.into())
225 }
226}
227
228impl From<InternalPk> for [u8; 32] {
229 fn from(pk: InternalPk) -> [u8; 32] { pk.to_byte_array() }
230}
231
232#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
236#[wrapper(Deref, LowerHex, Display, FromStr)]
237#[wrapper_mut(DerefMut)]
238#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
239#[strict_type(lib = LIB_NAME_BITCOIN)]
240#[cfg_attr(
241 feature = "serde",
242 derive(Serialize, Deserialize),
243 serde(crate = "serde_crate", transparent)
244)]
245pub struct OutputPk(XOnlyPk);
246
247impl OutputPk {
248 #[inline]
249 pub fn from_unchecked(pk: XOnlyPk) -> Self { Self(pk) }
250
251 #[inline]
252 pub fn from_byte_array(data: [u8; 32]) -> Result<Self, InvalidPubkey<32>> {
253 XOnlyPk::from_byte_array(data).map(Self)
254 }
255
256 #[inline]
257 pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, InvalidPubkey<33>> {
258 XOnlyPk::from_bytes(bytes).map(Self)
259 }
260
261 #[inline]
262 pub fn to_xonly_pk(&self) -> XOnlyPk { self.0 }
263
264 #[inline]
265 pub fn to_script_pubkey(&self) -> ScriptPubkey { ScriptPubkey::p2tr_tweaked(*self) }
266
267 #[inline]
268 pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() }
269}
270
271impl From<OutputPk> for [u8; 32] {
272 fn from(pk: OutputPk) -> [u8; 32] { pk.to_byte_array() }
273}
274
275pub trait IntoTapHash {
276 fn into_tap_hash(self) -> TapNodeHash;
277}
278
279#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
280#[wrapper(Index, RangeOps, AsSlice, BorrowSlice, Hex, Display, FromStr)]
281#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
282#[strict_type(lib = LIB_NAME_BITCOIN)]
283#[cfg_attr(
284 feature = "serde",
285 derive(Serialize, Deserialize),
286 serde(crate = "serde_crate", transparent)
287)]
288pub struct TapSighash(
289 #[from]
290 #[from([u8; 32])]
291 pub Bytes32,
292);
293
294impl From<TapSighash> for [u8; 32] {
295 fn from(value: TapSighash) -> Self { value.0.into_inner() }
296}
297
298impl From<TapSighash> for secp256k1::Message {
299 fn from(sighash: TapSighash) -> Self {
300 secp256k1::Message::from_digest(sighash.to_byte_array())
301 }
302}
303
304impl TapSighash {
305 pub fn engine() -> Sha256 { Sha256::from_tag(MIDSTATE_TAPSIGHASH) }
306
307 pub fn from_engine(engine: Sha256) -> Self { Self(engine.finish().into()) }
308}
309
310#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
311#[wrapper(Index, RangeOps, BorrowSlice, Hex, Display, FromStr)]
312#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
313#[strict_type(lib = LIB_NAME_BITCOIN)]
314#[cfg_attr(
315 feature = "serde",
316 derive(Serialize, Deserialize),
317 serde(crate = "serde_crate", transparent)
318)]
319pub struct TapLeafHash(
320 #[from]
321 #[from([u8; 32])]
322 Bytes32,
323);
324
325impl TapLeafHash {
326 pub fn with_leaf_script(leaf_script: &LeafScript) -> Self {
327 Self::with_raw_script(leaf_script.version, leaf_script.as_script_bytes())
328 }
329
330 pub fn with_tap_script(tap_script: &TapScript) -> Self {
331 Self::with_raw_script(LeafVer::TapScript, tap_script.as_script_bytes())
332 }
333
334 fn with_raw_script(version: LeafVer, script: &ScriptBytes) -> Self {
335 let mut engine = Sha256::from_tag(MIDSTATE_TAPLEAF);
336 engine.input_raw(&[version.to_consensus_u8()]);
337 script.len_var_int().consensus_encode(&mut engine).ok();
338 engine.input_raw(script.as_slice());
339 Self(engine.finish().into())
340 }
341}
342
343impl IntoTapHash for TapLeafHash {
344 fn into_tap_hash(self) -> TapNodeHash { TapNodeHash(self.0) }
345}
346
347#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
348#[wrapper(Index, RangeOps, BorrowSlice, Hex, Display, FromStr)]
349#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
350#[strict_type(lib = LIB_NAME_BITCOIN)]
351#[cfg_attr(
352 feature = "serde",
353 derive(Serialize, Deserialize),
354 serde(crate = "serde_crate", transparent)
355)]
356pub struct TapBranchHash(
357 #[from]
358 #[from([u8; 32])]
359 Bytes32,
360);
361
362impl TapBranchHash {
363 pub fn with_nodes(node1: TapNodeHash, node2: TapNodeHash) -> Self {
364 let mut engine = Sha256::from_tag(MIDSTATE_TAPBRANCH);
365 engine.input_raw(cmp::min(&node1, &node2).borrow());
366 engine.input_raw(cmp::max(&node1, &node2).borrow());
367 Self(engine.finish().into())
368 }
369}
370
371impl IntoTapHash for TapBranchHash {
372 fn into_tap_hash(self) -> TapNodeHash { TapNodeHash(self.0) }
373}
374
375#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
376#[wrapper(Index, RangeOps, AsSlice, BorrowSlice, Hex, Display, FromStr)]
377#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
378#[strict_type(lib = LIB_NAME_BITCOIN)]
379#[cfg_attr(
380 feature = "serde",
381 derive(Serialize, Deserialize),
382 serde(crate = "serde_crate", transparent)
383)]
384pub struct TapNodeHash(
385 #[from]
386 #[from([u8; 32])]
387 #[from(TapLeafHash)]
388 #[from(TapBranchHash)]
389 Bytes32,
390);
391
392impl IntoTapHash for TapNodeHash {
393 fn into_tap_hash(self) -> TapNodeHash { self }
394}
395
396#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)]
397#[wrapper(Deref)]
398#[wrapper_mut(DerefMut)]
399#[derive(StrictType, StrictEncode, StrictDecode)]
400#[strict_type(lib = LIB_NAME_BITCOIN)]
401#[cfg_attr(
402 feature = "serde",
403 derive(Serialize, Deserialize),
404 serde(crate = "serde_crate", transparent)
405)]
406pub struct TapMerklePath(Confined<Vec<TapBranchHash>, 0, 128>);
407
408impl IntoIterator for TapMerklePath {
409 type Item = TapBranchHash;
410 type IntoIter = vec::IntoIter<TapBranchHash>;
411
412 fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
413}
414
415impl<'a> IntoIterator for &'a TapMerklePath {
416 type Item = &'a TapBranchHash;
417 type IntoIter = slice::Iter<'a, TapBranchHash>;
418
419 fn into_iter(self) -> Self::IntoIter { self.0.iter() }
420}
421
422impl TapMerklePath {
423 #[inline]
428 pub fn try_from(path: Vec<TapBranchHash>) -> Result<Self, confinement::Error> {
429 Confined::try_from(path).map(Self::from_inner)
430 }
431
432 #[inline]
436 pub fn try_from_iter<I: IntoIterator<Item = TapBranchHash>>(
437 iter: I,
438 ) -> Result<Self, confinement::Error> {
439 Confined::try_from_iter(iter).map(Self::from_inner)
440 }
441}
442
443pub const TAPROOT_ANNEX_PREFIX: u8 = 0x50;
445
446pub const TAPROOT_LEAF_TAPSCRIPT: u8 = 0xc0;
449
450pub const TAPROOT_LEAF_MASK: u8 = 0xfe;
453
454#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Display, Error)]
455#[display(doc_comments)]
456pub struct InvalidLeafVer(u8);
458
459#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
461#[cfg_attr(
462 feature = "serde",
463 derive(Serialize, Deserialize),
464 serde(crate = "serde_crate", rename_all = "camelCase")
465)]
466pub enum LeafVer {
467 #[default]
469 TapScript,
470
471 Future(FutureLeafVer),
473}
474
475impl StrictType for LeafVer {
476 const STRICT_LIB_NAME: &'static str = LIB_NAME_BITCOIN;
477 fn strict_name() -> Option<TypeName> { Some(tn!("LeafVer")) }
478}
479impl StrictProduct for LeafVer {}
480impl StrictTuple for LeafVer {
481 const FIELD_COUNT: u8 = 1;
482}
483impl StrictEncode for LeafVer {
484 fn strict_encode<W: TypedWrite>(&self, writer: W) -> std::io::Result<W> {
485 writer.write_tuple::<Self>(|w| Ok(w.write_field(&self.to_consensus_u8())?.complete()))
486 }
487}
488impl StrictDecode for LeafVer {
489 fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
490 reader.read_tuple(|r| {
491 let version = r.read_field()?;
492 Self::from_consensus_u8(version)
493 .map_err(|err| DecodeError::DataIntegrityError(err.to_string()))
494 })
495 }
496}
497
498impl LeafVer {
499 #[doc(hidden)]
500 #[deprecated(since = "0.10.9", note = "use from_consensus_u8")]
501 pub fn from_consensus(version: u8) -> Result<Self, InvalidLeafVer> {
502 Self::from_consensus_u8(version)
503 }
504
505 pub fn from_consensus_u8(version: u8) -> Result<Self, InvalidLeafVer> {
512 match version {
513 TAPROOT_LEAF_TAPSCRIPT => Ok(LeafVer::TapScript),
514 TAPROOT_ANNEX_PREFIX => Err(InvalidLeafVer(TAPROOT_ANNEX_PREFIX)),
515 future => FutureLeafVer::from_consensus(future).map(LeafVer::Future),
516 }
517 }
518
519 #[doc(hidden)]
520 #[deprecated(since = "0.10.9", note = "use to_consensus_u8")]
521 pub fn to_consensus(self) -> u8 { self.to_consensus_u8() }
522
523 pub fn to_consensus_u8(self) -> u8 {
525 match self {
526 LeafVer::TapScript => TAPROOT_LEAF_TAPSCRIPT,
527 LeafVer::Future(version) => version.to_consensus(),
528 }
529 }
530}
531
532impl LowerHex for LeafVer {
533 fn fmt(&self, f: &mut Formatter) -> fmt::Result { LowerHex::fmt(&self.to_consensus_u8(), f) }
534}
535
536impl UpperHex for LeafVer {
537 fn fmt(&self, f: &mut Formatter) -> fmt::Result { UpperHex::fmt(&self.to_consensus_u8(), f) }
538}
539
540#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
547#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
548#[strict_type(lib = LIB_NAME_BITCOIN, dumb = { Self(0x51) })]
549#[cfg_attr(
550 feature = "serde",
551 derive(Serialize, Deserialize),
552 serde(crate = "serde_crate", transparent)
553)]
554pub struct FutureLeafVer(u8);
555
556impl FutureLeafVer {
557 pub(self) fn from_consensus(version: u8) -> Result<FutureLeafVer, InvalidLeafVer> {
558 match version {
559 TAPROOT_LEAF_TAPSCRIPT => unreachable!(
560 "FutureLeafVersion::from_consensus should be never called for 0xC0 value"
561 ),
562 TAPROOT_ANNEX_PREFIX => Err(InvalidLeafVer(TAPROOT_ANNEX_PREFIX)),
563 odd if odd & 0xFE != odd => Err(InvalidLeafVer(odd)),
564 even => Ok(FutureLeafVer(even)),
565 }
566 }
567
568 #[inline]
570 pub fn to_consensus(self) -> u8 { self.0 }
571}
572
573impl LowerHex for FutureLeafVer {
574 #[inline]
575 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { LowerHex::fmt(&self.0, f) }
576}
577
578impl UpperHex for FutureLeafVer {
579 #[inline]
580 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { UpperHex::fmt(&self.0, f) }
581}
582
583#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, Display)]
584#[derive(StrictType, StrictEncode, StrictDecode)]
585#[strict_type(lib = LIB_NAME_BITCOIN)]
586#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
587#[display("{version:04x} {script:x}")]
588pub struct LeafScript {
589 pub version: LeafVer,
590 pub script: ScriptBytes,
591}
592
593impl From<TapScript> for LeafScript {
596 fn from(tap_script: TapScript) -> Self {
597 LeafScript {
598 version: LeafVer::TapScript,
599 script: tap_script.into_inner(),
600 }
601 }
602}
603
604impl LeafScript {
605 #[inline]
606 pub fn new(version: LeafVer, script: ScriptBytes) -> Self { LeafScript { version, script } }
607 #[inline]
608 pub fn with_bytes(version: LeafVer, script: Vec<u8>) -> Result<Self, confinement::Error> {
609 Ok(LeafScript {
610 version,
611 script: ScriptBytes::try_from(script)?,
612 })
613 }
614 #[inline]
615 pub fn from_tap_script(tap_script: TapScript) -> Self { Self::from(tap_script) }
616
617 #[inline]
618 pub fn as_script_bytes(&self) -> &ScriptBytes { &self.script }
619
620 #[inline]
621 pub fn tap_leaf_hash(&self) -> TapLeafHash { TapLeafHash::with_leaf_script(self) }
622}
623
624#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)]
625#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
626#[strict_type(lib = LIB_NAME_BITCOIN, tags = repr, into_u8, try_from_u8)]
627#[repr(u8)]
628#[non_exhaustive]
629pub enum TapCode {
630 #[display("OP_PUSH_BYTES32")]
632 PushBytes32 = OP_PUSHBYTES_32,
633
634 Reserved = OP_RESERVED,
636
637 #[display("OP_RETURN")]
639 #[strict_type(dumb)]
640 Return = OP_RETURN,
641
642 #[display("OP_PUSH_DATA1")]
645 PushData1 = OP_PUSHDATA1,
646 #[display("OP_PUSH_DATA2")]
649 PushData2 = OP_PUSHDATA2,
650 #[display("OP_PUSH_DATA3")]
653 PushData4 = OP_PUSHDATA4,
654}
655
656#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)]
657#[wrapper(Deref, AsSlice, Hex)]
658#[wrapper_mut(DerefMut, AsSliceMut)]
659#[derive(StrictType, StrictEncode, StrictDecode)]
660#[strict_type(lib = LIB_NAME_BITCOIN)]
661#[cfg_attr(
662 feature = "serde",
663 derive(Serialize, Deserialize),
664 serde(crate = "serde_crate", transparent)
665)]
666pub struct TapScript(ScriptBytes);
667impl TryFrom<Vec<u8>> for TapScript {
670 type Error = confinement::Error;
671 fn try_from(script_bytes: Vec<u8>) -> Result<Self, Self::Error> {
672 ScriptBytes::try_from(script_bytes).map(Self)
673 }
674}
675
676impl TapScript {
677 #[inline]
678 pub fn new() -> Self { Self::default() }
679
680 #[inline]
681 pub fn with_capacity(capacity: usize) -> Self {
682 Self(ScriptBytes::from(Confined::with_capacity(capacity)))
683 }
684
685 #[inline]
688 pub fn from_unsafe(script_bytes: Vec<u8>) -> Self {
689 Self(ScriptBytes::from_unsafe(script_bytes))
690 }
691
692 #[inline]
693 pub fn tap_leaf_hash(&self) -> TapLeafHash { TapLeafHash::with_tap_script(self) }
694
695 #[inline]
697 pub fn push_opcode(&mut self, op_code: TapCode) { self.0.push(op_code as u8); }
698
699 #[inline]
700 pub fn as_script_bytes(&self) -> &ScriptBytes { &self.0 }
701}
702
703impl ScriptPubkey {
704 pub fn p2tr(internal_key: InternalPk, merkle_root: Option<TapNodeHash>) -> Self {
705 let (output_key, _) = internal_key.to_output_pk(merkle_root);
706 Self::p2tr_tweaked(output_key)
707 }
708
709 pub fn p2tr_key_only(internal_key: InternalPk) -> Self {
710 let (output_key, _) = internal_key.to_output_pk(None);
711 Self::p2tr_tweaked(output_key)
712 }
713
714 pub fn p2tr_scripted(internal_key: InternalPk, merkle_root: impl IntoTapHash) -> Self {
715 let (output_key, _) = internal_key.to_output_pk(Some(merkle_root.into_tap_hash()));
716 Self::p2tr_tweaked(output_key)
717 }
718
719 pub fn p2tr_tweaked(output_key: OutputPk) -> Self {
720 Self::with_witness_program_unchecked(WitnessVer::V1, &output_key.serialize())
723 }
724
725 pub fn is_p2tr(&self) -> bool {
726 self.len() == 34 && self[0] == WitnessVer::V1.op_code() as u8 && self[1] == OP_PUSHBYTES_32
727 }
728}
729
730#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, Error)]
732#[display(doc_comments)]
733pub struct InvalidParityValue(pub u8);
734
735#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
737#[display(lowercase)]
738#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
739#[strict_type(lib = LIB_NAME_BITCOIN, tags = repr, into_u8, try_from_u8)]
740#[cfg_attr(
741 feature = "serde",
742 derive(Serialize, Deserialize),
743 serde(crate = "serde_crate", rename_all = "camelCase")
744)]
745#[repr(u8)]
746pub enum Parity {
747 #[strict_type(dumb)]
749 Even = 0,
750 Odd = 1,
752}
753
754impl From<secp256k1::Parity> for Parity {
755 fn from(parity: secp256k1::Parity) -> Self {
756 match parity {
757 secp256k1::Parity::Even => Parity::Even,
758 secp256k1::Parity::Odd => Parity::Odd,
759 }
760 }
761}
762
763impl Parity {
764 pub fn to_consensus_u8(self) -> u8 { self as u8 }
768
769 pub fn from_consensus_u8(parity: u8) -> Result<Parity, InvalidParityValue> {
774 match parity {
775 0 => Ok(Parity::Even),
776 1 => Ok(Parity::Odd),
777 invalid => Err(InvalidParityValue(invalid)),
778 }
779 }
780}
781
782impl BitXor for Parity {
784 type Output = Parity;
785
786 fn bitxor(self, rhs: Parity) -> Self::Output {
787 if self == rhs {
790 Parity::Even } else {
792 Parity::Odd }
794 }
795}
796
797#[derive(Clone, Eq, PartialEq, Hash, Debug)]
798#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
799#[strict_type(lib = LIB_NAME_BITCOIN)]
800#[cfg_attr(
801 feature = "serde",
802 derive(Serialize, Deserialize),
803 serde(crate = "serde_crate", rename_all = "camelCase")
804)]
805pub struct ControlBlock {
806 pub leaf_version: LeafVer,
808 pub output_key_parity: Parity,
811 pub internal_pk: InternalPk,
813 pub merkle_branch: TapMerklePath,
815}
816
817impl ControlBlock {
818 #[inline]
819 pub fn with(
820 leaf_version: LeafVer,
821 internal_pk: InternalPk,
822 output_key_parity: Parity,
823 merkle_branch: TapMerklePath,
824 ) -> Self {
825 ControlBlock {
826 leaf_version,
827 output_key_parity,
828 internal_pk,
829 merkle_branch,
830 }
831 }
832}
833
834#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error, From)]
835#[display(doc_comments)]
836pub enum AnnexError {
837 WrongFirstByte(u8),
839
840 #[from]
841 #[display(inner)]
842 Size(confinement::Error),
843}
844
845#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
847#[wrapper(Deref, AsSlice, Hex)]
848#[wrapper_mut(DerefMut, AsSliceMut)]
849#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
850#[strict_type(lib = LIB_NAME_BITCOIN, dumb = { Self(VarIntBytes::with(0x50)) })]
851pub struct Annex(VarIntBytes<1>);
852
853impl TryFrom<Vec<u8>> for Annex {
854 type Error = confinement::Error;
855 fn try_from(script_bytes: Vec<u8>) -> Result<Self, Self::Error> {
856 Confined::try_from(script_bytes).map(Self)
857 }
858}
859
860impl Annex {
861 #[inline]
865 pub fn new(annex_bytes: Vec<u8>) -> Result<Self, AnnexError> {
866 let annex = Confined::try_from(annex_bytes).map(Self)?;
867 if annex[0] != TAPROOT_ANNEX_PREFIX {
868 return Err(AnnexError::WrongFirstByte(annex[0]));
869 }
870 Ok(annex)
871 }
872
873 pub fn len_var_int(&self) -> VarInt { VarInt(self.len() as u64) }
874
875 pub fn into_vec(self) -> Vec<u8> { self.0.release() }
876
877 pub fn as_slice(&self) -> &[u8] { self.0.as_slice() }
879
880 pub(crate) fn as_var_int_bytes(&self) -> &VarIntBytes<1> { &self.0 }
881}
882
883#[cfg(feature = "serde")]
884mod _serde {
885 use amplify::hex::{FromHex, ToHex};
886 use serde::{Deserialize, Serialize};
887 use serde_crate::de::Error;
888 use serde_crate::{Deserializer, Serializer};
889
890 use super::*;
891
892 impl Serialize for Annex {
893 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
894 where S: Serializer {
895 if serializer.is_human_readable() {
896 serializer.serialize_str(&self.to_hex())
897 } else {
898 serializer.serialize_bytes(self.as_slice())
899 }
900 }
901 }
902
903 impl<'de> Deserialize<'de> for Annex {
904 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
905 where D: Deserializer<'de> {
906 if deserializer.is_human_readable() {
907 String::deserialize(deserializer).and_then(|string| {
908 Self::from_hex(&string).map_err(|_| D::Error::custom("wrong hex data"))
909 })
910 } else {
911 let bytes = Vec::<u8>::deserialize(deserializer)?;
912 Self::new(bytes).map_err(|_| D::Error::custom("invalid annex data"))
913 }
914 }
915 }
916}