descriptors/
segwit.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::collections::{BTreeSet, HashMap};
24use std::fmt::{self, Display, Formatter};
25use std::iter;
26
27use derive::{
28    Derive, DeriveCompr, DerivedScript, KeyOrigin, Keychain, LegacyPk, NormalIndex, ScriptPubkey,
29    SigScript, TapDerivation, Terminal, WPubkeyHash, Witness, XOnlyPk, XpubAccount, XpubDerivable,
30};
31use indexmap::IndexMap;
32
33use crate::{Descriptor, LegacyKeySig, SpkClass, TaprootKeySig};
34
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[derive(Clone, Eq, PartialEq, Hash, Debug, From)]
37pub struct Wpkh<K: DeriveCompr = XpubDerivable>(K);
38
39impl<K: DeriveCompr> Wpkh<K> {
40    pub fn as_key(&self) -> &K { &self.0 }
41    pub fn into_key(self) -> K { self.0 }
42}
43
44impl<K: DeriveCompr> Derive<DerivedScript> for Wpkh<K> {
45    #[inline]
46    fn default_keychain(&self) -> Keychain { self.0.default_keychain() }
47
48    #[inline]
49    fn keychains(&self) -> BTreeSet<Keychain> { self.0.keychains() }
50
51    fn derive(
52        &self,
53        keychain: impl Into<Keychain>,
54        index: impl Into<NormalIndex>,
55    ) -> impl Iterator<Item = DerivedScript> {
56        self.0
57            .derive(keychain, index)
58            .map(|key| DerivedScript::Bare(ScriptPubkey::p2wpkh(WPubkeyHash::from(key))))
59    }
60}
61
62impl<K: DeriveCompr> Descriptor<K> for Wpkh<K> {
63    fn class(&self) -> SpkClass { SpkClass::P2wpkh }
64
65    fn keys<'a>(&'a self) -> impl Iterator<Item = &'a K>
66    where K: 'a {
67        iter::once(&self.0)
68    }
69    fn vars<'a>(&'a self) -> impl Iterator<Item = &'a ()>
70    where (): 'a {
71        iter::empty()
72    }
73    fn xpubs(&self) -> impl Iterator<Item = &XpubAccount> { iter::once(self.0.xpub_spec()) }
74
75    fn legacy_keyset(&self, terminal: Terminal) -> IndexMap<LegacyPk, KeyOrigin> {
76        self.0
77            .derive(terminal.keychain, terminal.index)
78            .map(|key| (key.into(), KeyOrigin::with(self.0.xpub_spec().origin().clone(), terminal)))
79            .collect()
80    }
81
82    fn xonly_keyset(&self, _terminal: Terminal) -> IndexMap<XOnlyPk, TapDerivation> {
83        IndexMap::new()
84    }
85
86    fn legacy_witness(
87        &self,
88        keysigs: HashMap<&KeyOrigin, LegacyKeySig>,
89    ) -> Option<(SigScript, Witness)> {
90        let our_origin = self.0.xpub_spec().origin();
91        let keysig =
92            keysigs.iter().find(|(origin, _)| our_origin.is_subset_of(origin)).map(|(_, ks)| ks)?;
93        let witness = Witness::from_consensus_stack([keysig.sig.to_vec(), keysig.key.to_vec()]);
94        Some((empty!(), witness))
95    }
96
97    fn taproot_witness(&self, _keysigs: HashMap<&KeyOrigin, TaprootKeySig>) -> Option<Witness> {
98        None
99    }
100}
101
102impl<K: DeriveCompr> Display for Wpkh<K> {
103    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "wpkh({})", self.0) }
104}