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:
parent
730d35516c
commit
8631474f08
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue