1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Descriptor wallet library extending bitcoin & miniscript functionality
// by LNP/BP Association (https://lnp-bp.org)
// Written in 2020-2022 by
//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the Apache-2.0 License
// along with this software.
// If not, see <https://opensource.org/licenses/Apache-2.0>.

// In the future this mod will probably become part of bitcoin library

// Coding conventions
#![recursion_limit = "256"]
#![deny(dead_code, missing_docs, warnings)]

//! # Bitcoin script types
//!
//! Bitcoin doesn't make a distinction between Bitcoin script coming from
//! different sources, like *scriptPubKey* in transaction output or *witness*
//! and *scriptSig* in transaction input. There are many other possible script
//! containers for Bitcoin script: redeem script, witness script, taproot leaf
//! scripts of different versions. In fact, any "script" of [`bitcoin::Script`]
//! type can be used for inputs and outputs. What is a valid script for in one
//! context will not be a valid script for some other. That would mean that in
//! principle with existing [`bitcoin::Script`] type every input script can be
//! used as an output script, leading to potentially harmful code coming from an
//! unaware developer.
//!
//! While all [`bitcoin::Script`]s have the same parsing rules converting byte
//! string into a set of instructions (i.e. the same **syntax**), there are
//! multiple ways how the consensus meaning of these instructions will be
//! interpreted under different contexts (different **semantics**). Moreover,
//! the scripts may be nested - or to be committed into some other Bitcoin
//! script – in a nested structures like in several layers, like *redeemScript*
//! inside of *scriptSig* used for P2SH, or *tapScript* within *witnessScript*
//! coming from *witness* field for Taproot. These nested layers do distinguish
//! on the information they contain, since some of them only commit to the
//! hashes of the nested scripts ([`bitcoin::ScriptHash`], [`WitnessProgram`])
//! or public keys ([`bitcoin::PubkeyHash`], [`bitcoin::WPubkeyHash`]), while
//! other contain the full source of the script.
//!
//! The present type system represents a solution to the problem: it distinguish
//! different logical types by introducing `Script` wrapper types. It defines
//! [`LockScript`] as bottom layer of a script, containing no other script
//! commitments (in form of their hashes). It also defines types above on it:
//! [`PubkeyScript`] (for whatever is there in `scriptPubkey` field
//! of a [`bitcoin::TxOut`]), [`SigScript`] (for whatever comes from `scriptSig`
//! field of [`bitcoin::TxIn`]), [`RedeemScript`] and [`WitnessScript`].
//! For taproot, we define [`LeafScript`] as a top level of specific script
//! branch (see [`bitcoin::util::psbt::TapTree`]) and [`crate::TapScript`] as a
//! type specific for the current `0xC0` tapleaf version semantics, defined in
//! BIP-342.
//!
//! There are conversion functions, which, for instance, can analyse
//! [`PubkeyScript`] and if it is a custom script or P2PK return a
//! [`LockScript`] type - or otherwise fail with error. These conversions
//! functions reside in [`convert`] module. So with this type system one is
//! always sure which semantic information it does contain.
//!
//! ## Type conversion
//!
//! ```text
//! LockScript -+-> (PubkeyScript + RedeemScript) -+-> SigScript
//!             |                                  +-> WitnessScript
//!             +-> PubkeyScript
//!             |
//! TapScript ----> LeafScript
//!
//! PubkeyScript --?--> LockScript
//! ```

#[macro_use]
extern crate amplify;
#[macro_use]
extern crate strict_encoding;
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde_crate as serde;

pub mod address;
pub mod convert;
pub mod hlc;
#[cfg(feature = "miniscript")]
mod parser;
pub mod taproot;
mod types;

pub use convert::ConvertInfo;
#[cfg(feature = "miniscript")]
pub use parser::PubkeyParseError;
pub use types::{
    LeafScript, LockScript, PubkeyScript, RedeemScript, ScriptCode, ScriptSet, SigScript,
    TapScript, WitnessProgram, WitnessScript,
};