Improve docs in taproot module

As has been done in other places in the codebase; improve the docs in
the `taproot` module by doing:

- Use full sentences (capital letters + full stops)
- Use back ticks and links for types where appropriate
- Fix grammar
- Fix stale docs
- Use third person for describing functions
- Use 100 character line width
- Use markdown sections (`# Examples`, `# Returns`) where appropriate
- Separate brief heading from extended description when appropriate
- Use `///` for all functions/types (both private and public)

I also did:

- Build the docs and check all the links
- Read all the built docs, check for sanity and pretty-ness
This commit is contained in:
Tobin Harding 2022-03-28 14:07:07 +11:00
parent 730d35516c
commit 8631474f08
1 changed files with 195 additions and 171 deletions

View File

@ -53,7 +53,7 @@ const MIDSTATE_TAPTWEAK: [u8; 32] = [
];
// d129a2f3701c655d6583b6c3b941972795f4e23294fd54f4a2ae8d8547ca590b
/// The SHA-256 midstate value for the TapSigHash hash.
/// The SHA-256 midstate value for the [`TapSighashHash`].
const MIDSTATE_TAPSIGHASH: [u8; 32] = [
245, 4, 164, 37, 215, 248, 120, 59, 19, 99, 134, 138, 227, 229, 86, 88, 110, 238, 148, 93, 188,
120, 136, 221, 2, 166, 226, 195, 24, 115, 254, 159,
@ -99,8 +99,8 @@ sha256t_hash_newtype!(TapSighashHash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64,
);
impl TapTweakHash {
/// Create a new BIP341 [`TapTweakHash`] from key and tweak
/// Produces H_taptweak(P||R) where P is internal key and R is the merkle root
/// Creates a new BIP341 [`TapTweakHash`] from key and tweak. Produces `H_taptweak(P||R)` where
/// `P` is the internal key and `R` is the merkle root.
pub fn from_key_and_tweak(
internal_key: UntweakedPublicKey,
merkle_root: Option<TapBranchHash>,
@ -118,7 +118,7 @@ impl TapTweakHash {
}
impl TapLeafHash {
/// function to compute leaf hash from components
/// Computes the leaf hash from components.
pub fn from_script(script: &Script, ver: LeafVersion) -> TapLeafHash {
let mut eng = TapLeafHash::engine();
ver.to_consensus()
@ -131,24 +131,24 @@ impl TapLeafHash {
}
}
/// Maximum depth of a Taproot Tree Script spend path
/// Maximum depth of a taproot tree script spend path.
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L229
pub const TAPROOT_CONTROL_MAX_NODE_COUNT: usize = 128;
/// Size of a taproot control node
/// Size of a taproot control node.
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L228
pub const TAPROOT_CONTROL_NODE_SIZE: usize = 32;
/// Tapleaf mask for getting the leaf version from first byte of control block
/// Tapleaf mask for getting the leaf version from first byte of control block.
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L225
pub const TAPROOT_LEAF_MASK: u8 = 0xfe;
/// Tapscript leaf version
/// Tapscript leaf version.
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L226
pub const TAPROOT_LEAF_TAPSCRIPT: u8 = 0xc0;
/// Taproot annex prefix
/// Taproot annex prefix.
pub const TAPROOT_ANNEX_PREFIX: u8 = 0x50;
/// Tapscript control base size
/// Tapscript control base size.
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L227
pub const TAPROOT_CONTROL_BASE_SIZE: usize = 33;
/// Tapscript control max size
/// Tapscript control max size.
// https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L230
pub const TAPROOT_CONTROL_MAX_SIZE: usize =
TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;
@ -156,45 +156,48 @@ pub const TAPROOT_CONTROL_MAX_SIZE: usize =
// type alias for versioned tap script corresponding merkle proof
type ScriptMerkleProofMap = BTreeMap<(Script, LeafVersion), BTreeSet<TaprootMerkleBranch>>;
/// Data structure for representing Taproot spending information.
/// Taproot output corresponds to a combination of a
/// single public key condition (known the internal key), and zero or more
/// general conditions encoded in scripts organized in the form of a binary tree.
/// Represents taproot spending information.
///
/// Taproot can be spent be either:
/// - Spending using the key path i.e., with secret key corresponding to the output_key
/// - By satisfying any of the scripts in the script spent path. Each script can be satisfied by providing
/// a witness stack consisting of the script's inputs, plus the script itself and the control block.
/// Taproot output corresponds to a combination of a single public key condition (known as the
/// internal key), and zero or more general conditions encoded in scripts organized in the form of a
/// binary tree.
///
/// If one or more of the spending conditions consist of just a single key (after aggregation),
/// the most likely one should be made the internal key.
/// See [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) for more details
/// on choosing internal keys for a taproot application
/// Taproot can be spent by either:
/// - Spending using the key path i.e., with secret key corresponding to the tweaked `output_key`.
/// - By satisfying any of the scripts in the script spend path. Each script can be satisfied by
/// providing a witness stack consisting of the script's inputs, plus the script itself and the
/// control block.
///
/// Note: This library currently does not support [annex](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-5)
/// If one or more of the spending conditions consist of just a single key (after aggregation), the
/// most likely key should be made the internal key.
/// See [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) for more details on
/// choosing internal keys for a taproot application.
///
/// Note: This library currently does not support
/// [annex](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-5).
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaprootSpendInfo {
/// The BIP341 internal key.
internal_key: UntweakedPublicKey,
/// The Merkle root of the script tree (None if there are no scripts)
/// The merkle root of the script tree (None if there are no scripts).
merkle_root: Option<TapBranchHash>,
/// The sign final output pubkey as per BIP 341
/// The sign final output pubkey as per BIP 341.
output_key_parity: secp256k1::Parity,
/// The tweaked output key
/// The tweaked output key.
output_key: TweakedPublicKey,
/// Map from (script, leaf_version) to (sets of) [`TaprootMerkleBranch`].
/// More than one control block for a given script is only possible if it
/// appears in multiple branches of the tree. In all cases, keeping one should
/// be enough for spending funds, but we keep all of the paths so that
/// a full tree can be constructed again from spending data if required.
/// Map from (script, leaf_version) to (sets of) [`TaprootMerkleBranch`]. More than one control
/// block for a given script is only possible if it appears in multiple branches of the tree. In
/// all cases, keeping one should be enough for spending funds, but we keep all of the paths so
/// that a full tree can be constructed again from spending data if required.
script_map: ScriptMerkleProofMap,
}
impl TaprootSpendInfo {
/// Create a new [`TaprootSpendInfo`] from a list of script(with default script version).
/// Creates a new [`TaprootSpendInfo`] from a list of scripts (with default script version) and
/// weights of satisfaction for that script.
///
/// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation
/// See [`TaprootBuilder::with_huffman_tree`] for more detailed documentation.
pub fn with_huffman_tree<C, I>(
secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey,
@ -207,18 +210,17 @@ impl TaprootSpendInfo {
TaprootBuilder::with_huffman_tree(script_weights)?.finalize(secp, internal_key)
}
/// Create a new key spend with internal key and proided merkle root.
/// Provide [`None`] for merkle_root if there is no script path.
/// Creates a new key spend with `internal_key` and `merkle_root`. Provide [`None`] for
/// `merkle_root` if there is no script path.
///
/// *Note*: As per BIP341
///
/// When the merkle root is [`None`], the output key commits to an unspendable
/// script path instead of having no script path. This is achieved by computing
/// the output key point as Q = P + int(hashTapTweak(bytes(P)))G.
/// See also [`TaprootSpendInfo::tap_tweak`].
/// Refer to BIP 341 footnote (Why should the output key always have
/// a taproot commitment, even if there is no script path?) for more details
/// When the merkle root is [`None`], the output key commits to an unspendable script path
/// instead of having no script path. This is achieved by computing the output key point as
/// `Q = P + int(hashTapTweak(bytes(P)))G`. See also [`TaprootSpendInfo::tap_tweak`].
///
/// Refer to BIP 341 footnote ('Why should the output key always have a taproot commitment, even
/// if there is no script path?') for more details.
pub fn new_key_spend<C: secp256k1::Verification>(
secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey,
@ -234,35 +236,36 @@ impl TaprootSpendInfo {
}
}
/// Obtain the tweak and parity used to compute the output_key
/// Returns the `TapTweakHash` for this [`TaprootSpendInfo`] i.e., the tweak using `internal_key`
/// and `merkle_root`.
pub fn tap_tweak(&self) -> TapTweakHash {
TapTweakHash::from_key_and_tweak(self.internal_key, self.merkle_root)
}
/// Obtain the internal key
/// Returns the internal key for this [`TaprootSpendInfo`].
pub fn internal_key(&self) -> UntweakedPublicKey {
self.internal_key
}
/// Obtain the merkle root
/// Returns the merkle root for this [`TaprootSpendInfo`].
pub fn merkle_root(&self) -> Option<TapBranchHash> {
self.merkle_root
}
/// Output key(the key used in script pubkey) from Spend data. See also
/// [`TaprootSpendInfo::output_key_parity`]
/// Returns the output key (the key used in script pubkey) for this [`TaprootSpendInfo`].
pub fn output_key(&self) -> TweakedPublicKey {
self.output_key
}
/// Parity of the output key. See also [`TaprootSpendInfo::output_key`]
/// Returns the parity of the output key. See also [`TaprootSpendInfo::output_key`].
pub fn output_key_parity(&self) -> secp256k1::Parity {
self.output_key_parity
}
/// Compute [`TaprootSpendInfo`] from [`NodeInfo`], and internal key.
/// This is useful when you want to manually build a taproot tree wihtout
/// using [`TaprootBuilder`].
/// Computes the [`TaprootSpendInfo`] from `internal_key` and `node`.
///
/// This is useful when you want to manually build a taproot tree without using
/// [`TaprootBuilder`].
pub fn from_node_info<C: secp256k1::Verification>(
secp: &Secp256k1<C>,
internal_key: UntweakedPublicKey,
@ -288,14 +291,17 @@ impl TaprootSpendInfo {
info
}
/// Access the internal script map
/// Returns the internal script map.
pub fn as_script_map(&self) -> &ScriptMerkleProofMap {
&self.script_map
}
/// Obtain a [`ControlBlock`] for particular script with the given version.
/// Returns [`None`] if the script is not contained in the [`TaprootSpendInfo`]
/// If there are multiple ControlBlocks possible, this returns the shortest one.
/// Constructs a [`ControlBlock`] for particular script with the given version.
///
/// # Returns
///
/// - If there are multiple control blocks possible, returns the shortest one.
/// - If the script is not contained in the [`TaprootSpendInfo`], returns `None`.
pub fn control_block(&self, script_ver: &(Script, LeafVersion)) -> Option<ControlBlock> {
let merkle_branch_set = self.script_map.get(script_ver)?;
// Choose the smallest one amongst the multiple script maps
@ -312,22 +318,23 @@ impl TaprootSpendInfo {
}
}
/// Builder for building taproot iteratively. Users can specify tap leaf or omitted/hidden
/// branches in a DFS(Depth first search) walk to construct this tree.
// Similar to Taproot Builder in bitcoin core
/// Builder for building taproot iteratively. Users can specify tap leaf or omitted/hidden branches
/// in a depth-first search (DFS) walk order to construct this tree.
///
/// See Wikipedia for more details on [DFS](https://en.wikipedia.org/wiki/Depth-first_search).
// Similar to Taproot Builder in bitcoin core.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaprootBuilder {
// The following doc-comment is from bitcoin core, but modified for rust
// The comment below describes the current state of the builder for a given tree.
// The following doc-comment is from bitcoin core, but modified for Rust. It describes the
// current state of the builder for a given tree.
//
// For each level in the tree, one NodeInfo object may be present. branch at index 0
// is information about the root; further values are for deeper subtrees being
// explored.
// For each level in the tree, one NodeInfo object may be present. Branch at index 0 is
// information about the root; further values are for deeper subtrees being explored.
//
// During the construction of Taptree, for every right branch taken to
// reach the position we're currently working in, there will be a (Some(_))
// entry in branch corresponding to the left branch at that level.
// During the construction of Taptree, for every right branch taken to reach the position we're
// currently working on, there will be a `(Some(_))` entry in branch corresponding to the left
// branch at that level.
//
// For example, imagine this tree: - N0 -
// / \
@ -337,50 +344,50 @@ pub struct TaprootBuilder {
// / \
// D E
//
// Initially, branch is empty. After processing leaf A, it would become
// {None, None, A}. When processing leaf B, an entry at level 2 already
// exists, and it would thus be combined with it to produce a level 1 one,
// resulting in {None, N1}. Adding C and D takes us to {None, N1, C}
// and {None, N1, C, D} respectively. When E is processed, it is combined
// with D, and then C, and then N1, to produce the root, resulting in {N0}.
// Initially, branch is empty. After processing leaf A, it would become {None, None, A}. When
// processing leaf B, an entry at level 2 already exists, and it would thus be combined with it
// to produce a level 1 entry, resulting in {None, N1}. Adding C and D takes us to {None, N1, C}
// and {None, N1, C, D} respectively. When E is processed, it is combined with D, and then C,
// and then N1, to produce the root, resulting in {N0}.
//
// This structure allows processing with just O(log n) overhead if the leaves
// are computed on the fly.
//
// As an invariant, there can never be None entries at the end. There can
// also not be more than 128 entries (as that would mean more than 128 levels
// in the tree). The depth of newly added entries will always be at least
// equal to the current size of branch (otherwise it does not correspond
// to a depth-first traversal of a tree). branch is only empty if no entries
// have ever be processed. branch having length 1 corresponds to being done.
// This structure allows processing with just O(log n) overhead if the leaves are computed on
// the fly.
//
// As an invariant, there can never be None entries at the end. There can also not be more than
// 128 entries (as that would mean more than 128 levels in the tree). The depth of newly added
// entries will always be at least equal to the current size of branch (otherwise it does not
// correspond to a depth-first traversal of a tree). A branch is only empty if no entries have
// ever be processed. A branch having length 1 corresponds to being done.
branch: Vec<Option<NodeInfo>>,
}
impl TaprootBuilder {
/// Create a new instance of [`TaprootBuilder`]
/// Creates a new instance of [`TaprootBuilder`].
pub fn new() -> Self {
TaprootBuilder { branch: vec![] }
}
/// Create a new [`TaprootBuilder`] from a list of script(with default script version) and
/// weights of satisfaction for that script. The weights represent the probability of
/// each branch being taken. If probabilities/weights for each condition are known,
/// constructing the tree as a Huffman tree is the optimal way to minimize average
/// case satisfaction cost. This function takes an iterator of (`u32`, &[`Script`]) tuples
/// as an input, where `u32` represents the satisfaction weights of the script branch.
/// For example, [(3, S1), (2, S2), (5, S3)] would construct a TapTree that has optimal
/// Creates a new [`TaprootSpendInfo`] from a list of scripts (with default script version) and
/// weights of satisfaction for that script.
///
/// The weights represent the probability of each branch being taken. If probabilities/weights
/// for each condition are known, constructing the tree as a Huffman Tree is the optimal way to
/// minimize average case satisfaction cost. This function takes as input an iterator of
/// `tuple(u32, &Script)` where `u32` represents the satisfaction weights of the branch. For
/// example, [(3, S1), (2, S2), (5, S3)] would construct a [`TapTree`] that has optimal
/// satisfaction weight when probability for S1 is 30%, S2 is 20% and S3 is 50%.
///
/// # Errors:
///
/// - When the optimal huffman tree has a depth more than 128
/// - If the provided list of script weights is empty
/// - When the optimal Huffman Tree has a depth more than 128.
/// - If the provided list of script weights is empty.
///
/// # Edge Cases:
/// - If the script weight calculations overflow, a sub-optimal tree may be generated. This
/// should not happen unless you are dealing with billions of branches with weights close to
/// 2^32.
///
/// If the script weight calculations overflow, a sub-optimal tree may be generated. This should
/// not happen unless you are dealing with billions of branches with weights close to 2^32.
///
/// [`TapTree`]: ::util::psbt::TapTree
pub fn with_huffman_tree<I>(
script_weights: I,
) -> Result<Self, TaprootBuilderError>
@ -412,7 +419,8 @@ impl TaprootBuilder {
Ok(TaprootBuilder{branch: vec![Some(node)]})
}
/// Just like [`TaprootBuilder::add_leaf`] but allows to specify script version
/// Adds a leaf script at `depth` to the builder with script version `ver`. Errors if the leaves
/// are not provided in DFS walk order. The depth of the root node is 0.
pub fn add_leaf_with_ver(
self,
depth: usize,
@ -423,29 +431,27 @@ impl TaprootBuilder {
self.insert(leaf, depth)
}
/// Add a leaf script at a depth `depth` to the builder with default script version.
/// This will error if the leave are not provided in a DFS walk order. The depth of the
/// root node is 0 and it's immediate child would be at depth 1.
/// See [`TaprootBuilder::add_leaf_with_ver`] for adding a leaf with specific version
/// See [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search) for more details
/// Adds a leaf script at `depth` to the builder with default script version. Errors if the
/// leaves are not provided in DFS walk order. The depth of the root node is 0.
///
/// See [`TaprootBuilder::add_leaf_with_ver`] for adding a leaf with specific version.
pub fn add_leaf(self, depth: usize, script: Script) -> Result<Self, TaprootBuilderError> {
self.add_leaf_with_ver(depth, script, LeafVersion::TapScript)
}
/// Add a hidden/omitted node at a depth `depth` to the builder.
/// This will error if the node are not provided in a DFS walk order. The depth of the
/// root node is 0 and it's immediate child would be at depth 1.
/// Adds a hidden/omitted node at `depth` to the builder. Errors if the leaves are not provided
/// in DFS walk order. The depth of the root node is 0.
pub fn add_hidden(self, depth: usize, hash: sha256::Hash) -> Result<Self, TaprootBuilderError> {
let node = NodeInfo::new_hidden(hash);
self.insert(node, depth)
}
/// Check if the builder is a complete tree
/// Checks if the builder is a complete tree.
pub fn is_complete(&self) -> bool {
self.branch.len() == 1 && self.branch[0].is_some()
}
/// Create [`TaprootSpendInfo`] with the given internal key
/// Creates a [`TaprootSpendInfo`] with the given internal key.
pub fn finalize<C: secp256k1::Verification>(
mut self,
secp: &Secp256k1<C>,
@ -466,7 +472,7 @@ impl TaprootBuilder {
&self.branch
}
// Helper function to insert a leaf at a depth
/// Inserts a leaf at `depth`.
fn insert(mut self, mut node: NodeInfo, mut depth: usize) -> Result<Self, TaprootBuilderError> {
// early error on invalid depth. Though this will be checked later
// while constructing TaprootMerkelBranch
@ -513,15 +519,16 @@ impl TaprootBuilder {
}
}
/// Data structure used to represent node information in taproot tree.
/// Represents the node information in taproot tree.
///
/// You can use [`TaprootSpendInfo::from_node_info`] to a get [`TaprootSpendInfo`]
/// from the merkle root [`NodeInfo`].
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct NodeInfo {
/// Merkle Hash for this node
/// Merkle hash for this node.
pub(crate) hash: sha256::Hash,
/// information about leaves inside this node
/// Information about leaves inside this node.
pub(crate) leaves: Vec<LeafInfo>,
}
@ -569,20 +576,20 @@ impl NodeInfo {
}
}
// Internally used structure to store information about taproot leaf node
/// Store information about taproot leaf node.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub(crate) struct LeafInfo {
// The underlying script
/// The underlying script.
pub(crate) script: Script,
// The leaf version
/// The leaf version.
pub(crate) ver: LeafVersion,
// The merkle proof(hashing partners) to get this node
/// The merkle proof (hashing partners) to get this node.
pub(crate) merkle_branch: TaprootMerkleBranch,
}
impl LeafInfo {
// Create an instance of Self from Script with default version and no merkle branch
/// Creates an new [`LeafInfo`] from `script` and `ver` and no merkle branch.
fn new(script: Script, ver: LeafVersion) -> Self {
Self {
script: script,
@ -591,27 +598,27 @@ impl LeafInfo {
}
}
// Compute a leaf hash for the given leaf
/// Computes a leaf hash for this [`LeafInfo`].
fn hash(&self) -> sha256::Hash {
let leaf_hash = TapLeafHash::from_script(&self.script, self.ver);
sha256::Hash::from_inner(leaf_hash.into_inner())
}
}
/// The Merkle proof for inclusion of a tree in a taptree hash
// The type of hash is sha256::Hash because the vector might contain
// both TapBranchHash and TapLeafHash
/// The merkle proof for inclusion of a tree in a taptree hash.
// The type of hash is `sha256::Hash` because the vector might contain both `TapBranchHash` and
// `TapLeafHash`.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaprootMerkleBranch(Vec<sha256::Hash>);
impl TaprootMerkleBranch {
/// Obtain a reference to inner
/// Returns a reference to the inner vector of hashes.
pub fn as_inner(&self) -> &[sha256::Hash] {
&self.0
}
/// Create a merkle proof from slice
/// Creates a merkle proof from raw data representing a list of hashes.
pub fn from_slice(sl: &[u8]) -> Result<Self, TaprootError> {
if sl.len() % TAPROOT_CONTROL_NODE_SIZE != 0 {
Err(TaprootError::InvalidMerkleBranchSize(sl.len()))
@ -630,7 +637,11 @@ impl TaprootMerkleBranch {
}
}
/// Serialize to a writer. Returns the number of bytes written
/// Serializes to a writer.
///
/// # Returns
///
/// The number of bytes written to the writer.
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> {
for hash in self.0.iter() {
writer.write_all(hash)?;
@ -638,12 +649,12 @@ impl TaprootMerkleBranch {
Ok(self.0.len() * sha256::Hash::LEN)
}
/// Serialize self as bytes
/// Serializes `self` as bytes.
pub fn serialize(&self) -> Vec<u8> {
self.0.iter().map(|e| e.as_inner()).flatten().map(|x| *x).collect::<Vec<u8>>()
}
// Internal function to append elements to proof
/// Appends elements to proof.
fn push(&mut self, h: sha256::Hash) -> Result<(), TaprootBuilderError> {
if self.0.len() >= TAPROOT_CONTROL_MAX_NODE_COUNT {
Err(TaprootBuilderError::InvalidMerkleTreeDepth(self.0.len()))
@ -653,8 +664,11 @@ impl TaprootMerkleBranch {
}
}
/// Create a MerkleProof from Vec<[`sha256::Hash`]>. Returns an error when
/// inner proof len is more than TAPROOT_CONTROL_MAX_NODE_COUNT (128)
/// Creates a merkle proof from list of hashes.
///
/// # Errors
///
/// If inner proof length is more than [`TAPROOT_CONTROL_MAX_NODE_COUNT`] (128).
pub fn from_inner(inner: Vec<sha256::Hash>) -> Result<Self, TaprootError> {
if inner.len() > TAPROOT_CONTROL_MAX_NODE_COUNT {
Err(TaprootError::InvalidMerkleTreeDepth(inner.len()))
@ -663,35 +677,38 @@ impl TaprootMerkleBranch {
}
}
/// Consume Self to get Vec<[`sha256::Hash`]>
/// Returns the inner list of hashes.
pub fn into_inner(self) -> Vec<sha256::Hash> {
self.0
}
}
/// Control Block data structure used in Tapscript satisfaction
/// Control block data structure used in Tapscript satisfaction.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ControlBlock {
/// The tapleaf version,
/// The tapleaf version.
pub leaf_version: LeafVersion,
/// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY)
/// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY).
pub output_key_parity: secp256k1::Parity,
/// The internal key
/// The internal key.
pub internal_key: UntweakedPublicKey,
/// The merkle proof of a script associated with this leaf
/// The merkle proof of a script associated with this leaf.
pub merkle_branch: TaprootMerkleBranch,
}
impl ControlBlock {
/// Obtain a ControlBlock from slice. This is an extra witness element
/// that provides the proof that taproot script pubkey is correctly computed
/// with some specified leaf hash. This is the last element in
/// taproot witness when spending a output via script path.
/// Constructs a `ControlBlock` from slice. This is an extra witness element that provides the
/// proof that taproot script pubkey is correctly computed with some specified leaf hash. This
/// is the last element in taproot witness when spending a output via script path.
///
/// # Errors:
/// - If the control block size is not of the form 33 + 32m where
/// 0 <= m <= 128, InvalidControlBlock is returned
/// # Errors
///
/// - `TaprootError::InvalidControlBlockSize` if `sl` is not of size 1 + 32 + 32N for any N >= 0.
/// - `TaprootError::InvalidParity` if first byte of `sl` is not a valid output key parity.
/// - `TaprootError::InvalidTaprootLeafVersion` if first byte of `sl` is not a valid leaf version.
/// - `TaprootError::InvalidInternalKey` if internal key is invalid (first 32 bytes after the parity byte).
/// - `TaprootError::InvalidMerkleTreeDepth` if merkle tree is too deep (more than 128 levels).
pub fn from_slice(sl: &[u8]) -> Result<ControlBlock, TaprootError> {
if sl.len() < TAPROOT_CONTROL_BASE_SIZE
|| (sl.len() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE != 0
@ -712,13 +729,17 @@ impl ControlBlock {
})
}
/// Obtain the size of control block. Faster and more efficient than calling
/// serialize() followed by len(). Can be handy for fee estimation
/// Returns the size of control block. Faster and more efficient than calling
/// `Self::serialize().len()`. Can be handy for fee estimation.
pub fn size(&self) -> usize {
TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * self.merkle_branch.as_inner().len()
}
/// Serialize to a writer. Returns the number of bytes written
/// Serializes to a writer.
///
/// # Returns
///
/// The number of bytes written to the writer.
pub fn encode<Write: io::Write>(&self, mut writer: Write) -> io::Result<usize> {
let first_byte: u8 = i32::from(self.output_key_parity) as u8 | self.leaf_version.to_consensus();
writer.write_all(&[first_byte])?;
@ -727,19 +748,21 @@ impl ControlBlock {
Ok(self.size())
}
/// Serialize the control block. This would be required when
/// using ControlBlock as a witness element while spending an output via
/// script path. This serialization does not include the VarInt prefix that would be
/// applied when encoding this element as a witness.
/// Serializes the control block.
///
/// This would be required when using [`ControlBlock`] as a witness element while spending an
/// output via script path. This serialization does not include the [`::VarInt`] prefix that would
/// be applied when encoding this element as a witness.
pub fn serialize(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(self.size());
self.encode(&mut buf).expect("writers don't error");
buf
}
/// Verify that a control block is correct proof for a given output key and script
/// This only checks that script is contained inside the taptree described by
/// output key, full verification must also execute the script with witness data
/// Verifies that a control block is correct proof for a given output key and script.
///
/// Only checks that script is contained inside the taptree described by output key. Full
/// verification must also execute the script with witness data.
pub fn verify_taproot_commitment<C: secp256k1::Verification>(
&self,
secp: &Secp256k1<C>,
@ -791,7 +814,7 @@ impl FutureLeafVersion {
}
}
/// Get consensus representation of the future leaf version.
/// Returns the consensus representation of this [`FutureLeafVersion`].
#[inline]
pub fn to_consensus(self) -> u8 {
self.0
@ -819,20 +842,21 @@ impl fmt::UpperHex for FutureLeafVersion {
}
}
/// The leaf version for tapleafs
/// The leaf version for tapleafs.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum LeafVersion {
/// BIP-342 tapscript
/// BIP-342 tapscript.
TapScript,
/// Future leaf version
/// Future leaf version.
Future(FutureLeafVersion)
}
impl LeafVersion {
/// Obtain LeafVersion from consensus byte representation.
/// Creates a [`LeafVersion`] from consensus byte representation.
///
/// # Errors
///
/// - If the last bit of the `version` is odd.
/// - If the `version` is 0x50 ([`TAPROOT_ANNEX_PREFIX`]).
// Text from BIP341:
@ -852,7 +876,7 @@ impl LeafVersion {
}
}
/// Get consensus representation of the [`LeafVersion`].
/// Returns the consensus representation of this [`LeafVersion`].
pub fn to_consensus(self) -> u8 {
match self {
LeafVersion::TapScript => TAPROOT_LEAF_TAPSCRIPT,
@ -884,7 +908,7 @@ impl fmt::UpperHex for LeafVersion {
}
}
/// Serializes LeafVersion as u8 using consensus encoding
/// Serializes [`LeafVersion`] as a `u8` using consensus encoding.
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl ::serde::Serialize for LeafVersion {
@ -896,7 +920,7 @@ impl ::serde::Serialize for LeafVersion {
}
}
/// Deserializes LeafVersion as u8 using consensus encoding
/// Deserializes [`LeafVersion`] as a `u8` using consensus encoding.
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> ::serde::Deserialize<'de> for LeafVersion {
@ -926,20 +950,20 @@ impl<'de> ::serde::Deserialize<'de> for LeafVersion {
}
}
/// Detailed error type for taproot builder
/// Detailed error type for taproot builder.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TaprootBuilderError {
/// Merkle Tree depth must not be more than 128
/// Merkle tree depth must not be more than 128.
InvalidMerkleTreeDepth(usize),
/// Nodes must be added specified in DFS order
/// Nodes must be added specified in DFS walk order.
NodeNotInDfsOrder,
/// Two nodes at depth 0 are not allowed
/// Two nodes at depth 0 are not allowed.
OverCompleteTree,
/// Invalid taproot internal key
/// Invalid taproot internal key.
InvalidInternalKey(secp256k1::Error),
/// Called finalize on an incomplete tree
/// Called finalize on an incomplete tree.
IncompleteTree,
/// Called finalize on a empty tree
/// Called finalize on a empty tree.
EmptyTree,
}
@ -974,22 +998,22 @@ impl fmt::Display for TaprootBuilderError {
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl error::Error for TaprootBuilderError {}
/// Detailed error type for taproot utilities
/// Detailed error type for taproot utilities.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TaprootError {
/// Proof size must be a multiple of 32
/// Proof size must be a multiple of 32.
InvalidMerkleBranchSize(usize),
/// Merkle Tree depth must not be more than 128
/// Merkle tree depth must not be more than 128.
InvalidMerkleTreeDepth(usize),
/// The last bit of tapleaf version must be zero
/// The last bit of tapleaf version must be zero.
InvalidTaprootLeafVersion(u8),
/// Invalid Control Block Size
/// Invalid control block size.
InvalidControlBlockSize(usize),
/// Invalid taproot internal key
/// Invalid taproot internal key.
InvalidInternalKey(secp256k1::Error),
/// Invalid parity for internal key
/// Invalid parity for internal key.
InvalidParity(secp256k1::InvalidParityValue),
/// Empty TapTree
/// Empty tap tree.
EmptyTree,
}