derive/
taptree.rs

1// Modern, minimalistic & standard-compliant cold wallet library.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2020-2024 by
6//     Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2020-2024 LNP/BP Standards Association. All rights reserved.
9// Copyright (C) 2020-2024 Dr Maxim Orlovsky. All rights reserved.
10//
11// Licensed under the Apache License, Version 2.0 (the "License");
12// you may not use this file except in compliance with the License.
13// You may obtain a copy of the License at
14//
15//     http://www.apache.org/licenses/LICENSE-2.0
16//
17// Unless required by applicable law or agreed to in writing, software
18// distributed under the License is distributed on an "AS IS" BASIS,
19// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20// See the License for the specific language governing permissions and
21// limitations under the License.
22
23use std::ops::Deref;
24use std::{slice, vec};
25
26use amplify::num::u7;
27use bc::{
28    ControlBlock, InternalPk, LeafScript, OutputPk, Parity, TapLeafHash, TapMerklePath,
29    TapNodeHash, TapScript,
30};
31use commit_verify::merkle::MerkleBuoy;
32
33use crate::{KeyOrigin, Terminal, XkeyOrigin};
34
35#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error, From)]
36pub enum InvalidTree {
37    #[from]
38    #[display(doc_comments)]
39    Unfinalized(UnfinalizedTree),
40
41    #[from(FinalizedTree)]
42    #[display("tap tree contains too many script leaves which doesn't fit a single Merkle tree")]
43    MountainRange,
44}
45
46#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)]
47#[display("can't add more leaves to an already finalized tap tree")]
48pub struct FinalizedTree;
49
50#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)]
51#[display(
52    "unfinalized tap tree containing leaves at level {0} which can't commit into a single Merkle \
53     root"
54)]
55pub struct UnfinalizedTree(pub u7);
56
57#[derive(Clone, Eq, PartialEq, Debug, Default)]
58pub struct TapTreeBuilder {
59    leaves: Vec<LeafInfo>,
60    buoy: MerkleBuoy<u7>,
61    finalized: bool,
62}
63
64impl TapTreeBuilder {
65    pub fn new() -> Self { Self::default() }
66
67    pub fn with_capacity(capacity: usize) -> Self {
68        Self {
69            leaves: Vec::with_capacity(capacity),
70            buoy: zero!(),
71            finalized: false,
72        }
73    }
74
75    pub fn is_finalized(&self) -> bool { self.finalized }
76
77    pub fn push_leaf(&mut self, leaf: LeafInfo) -> Result<bool, FinalizedTree> {
78        if self.finalized {
79            return Err(FinalizedTree);
80        }
81        let depth = leaf.depth;
82        self.leaves.push(leaf);
83        self.buoy.push(depth);
84        if self.buoy.level() == u7::ZERO {
85            self.finalized = true
86        }
87        Ok(self.finalized)
88    }
89
90    pub fn finish(self) -> Result<TapTree, UnfinalizedTree> {
91        if !self.finalized {
92            return Err(UnfinalizedTree(self.buoy.level()));
93        }
94        Ok(TapTree(self.leaves))
95    }
96}
97
98/// Non-empty taproot script tree.
99#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
100#[cfg_attr(
101    feature = "serde",
102    derive(Serialize, Deserialize),
103    serde(crate = "serde_crate", transparent)
104)]
105pub struct TapTree(Vec<LeafInfo>);
106
107impl Deref for TapTree {
108    type Target = Vec<LeafInfo>;
109    fn deref(&self) -> &Self::Target { &self.0 }
110}
111
112impl IntoIterator for TapTree {
113    type Item = LeafInfo;
114    type IntoIter = vec::IntoIter<LeafInfo>;
115
116    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
117}
118
119impl<'a> IntoIterator for &'a TapTree {
120    type Item = &'a LeafInfo;
121    type IntoIter = slice::Iter<'a, LeafInfo>;
122
123    fn into_iter(self) -> Self::IntoIter { self.0.iter() }
124}
125
126impl TapTree {
127    pub fn with_single_leaf(leaf: impl Into<LeafScript>) -> TapTree {
128        Self(vec![LeafInfo {
129            depth: u7::ZERO,
130            script: leaf.into(),
131        }])
132    }
133
134    pub fn from_leaves(leaves: impl IntoIterator<Item = LeafInfo>) -> Result<Self, InvalidTree> {
135        let mut builder = TapTreeBuilder::new();
136        for leaf in leaves {
137            builder.push_leaf(leaf)?;
138        }
139        builder.finish().map_err(InvalidTree::from)
140    }
141
142    pub fn from_builder(builder: TapTreeBuilder) -> Result<Self, UnfinalizedTree> {
143        builder.finish()
144    }
145
146    pub fn merkle_root(&self) -> TapNodeHash {
147        if self.0.len() == 1 {
148            TapLeafHash::with_leaf_script(&self.0[0].script).into()
149        } else {
150            todo!("#10 implement TapTree::merkle_root for trees with more than one leaf")
151        }
152    }
153
154    pub fn into_vec(self) -> Vec<LeafInfo> { self.0 }
155}
156
157#[derive(Clone, Eq, PartialEq, Hash, Debug)]
158#[cfg_attr(
159    feature = "serde",
160    derive(Serialize, Deserialize),
161    serde(crate = "serde_crate", rename_all = "camelCase")
162)]
163pub struct LeafInfo {
164    pub depth: u7,
165    pub script: LeafScript,
166}
167
168impl LeafInfo {
169    pub fn tap_script(depth: u7, script: TapScript) -> Self {
170        LeafInfo {
171            depth,
172            script: LeafScript::from_tap_script(script),
173        }
174    }
175}
176
177#[derive(Getters, Clone, Eq, PartialEq, Debug)]
178#[getter(as_copy)]
179pub struct ControlBlockFactory {
180    internal_pk: InternalPk,
181    output_pk: OutputPk,
182    parity: Parity,
183    merkle_root: TapNodeHash,
184
185    #[getter(skip)]
186    merkle_path: TapMerklePath,
187    #[getter(skip)]
188    remaining_leaves: Vec<LeafInfo>,
189}
190
191impl ControlBlockFactory {
192    #[inline]
193    pub fn with(internal_pk: InternalPk, tap_tree: TapTree) -> Self {
194        let merkle_root = tap_tree.merkle_root();
195        let (output_pk, parity) = internal_pk.to_output_pk(Some(merkle_root));
196        ControlBlockFactory {
197            internal_pk,
198            output_pk,
199            parity,
200            merkle_root,
201            merkle_path: empty!(),
202            remaining_leaves: tap_tree.into_vec(),
203        }
204    }
205
206    #[inline]
207    pub fn into_remaining_leaves(self) -> Vec<LeafInfo> { self.remaining_leaves }
208}
209
210impl Iterator for ControlBlockFactory {
211    type Item = (ControlBlock, LeafScript);
212
213    fn next(&mut self) -> Option<Self::Item> {
214        let leaf = self.remaining_leaves.pop()?;
215        let leaf_script = leaf.script;
216        let control_block = ControlBlock::with(
217            leaf_script.version,
218            self.internal_pk,
219            self.parity,
220            self.merkle_path.clone(),
221        );
222        Some((control_block, leaf_script))
223    }
224}
225
226/// A compact size unsigned integer representing the number of leaf hashes, followed by a list
227/// of leaf hashes, followed by the 4 byte master key fingerprint concatenated with the
228/// derivation path of the public key. The derivation path is represented as 32-bit little
229/// endian unsigned integer indexes concatenated with each other. Public keys are those needed
230/// to spend this output. The leaf hashes are of the leaves which involve this public key. The
231/// internal key does not have leaf hashes, so can be indicated with a hashes len of 0.
232/// Finalizers should remove this field after `PSBT_IN_FINAL_SCRIPTWITNESS` is constructed.
233#[derive(Clone, Eq, PartialEq, Hash, Debug)]
234#[cfg_attr(
235    feature = "serde",
236    derive(Serialize, Deserialize),
237    serde(crate = "serde_crate", rename_all = "camelCase")
238)]
239pub struct TapDerivation {
240    pub leaf_hashes: Vec<TapLeafHash>,
241    pub origin: KeyOrigin,
242}
243
244impl TapDerivation {
245    pub fn with_internal_pk(xpub_origin: XkeyOrigin, terminal: Terminal) -> Self {
246        let origin = KeyOrigin::with(xpub_origin, terminal);
247        TapDerivation {
248            leaf_hashes: empty!(),
249            origin,
250        }
251    }
252}