bc/
segwit.rs

1// Bitcoin protocol consensus library.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2019-2024 by
6//     Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved.
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21
22use std::vec;
23
24use amplify::confinement::Confined;
25use amplify::{confinement, Bytes32StrRev, Wrapper};
26
27use crate::opcodes::*;
28use crate::{
29    ByteStr, RedeemScript, ScriptBytes, ScriptPubkey, VarIntArray, WScriptHash, LIB_NAME_BITCOIN,
30};
31
32#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)]
33#[display(doc_comments)]
34pub enum SegwitError {
35    /// Script version must be 0 to 16 inclusive.
36    InvalidWitnessVersion(u8),
37    /// Bitcoin script opcode does not match any known witness version, the
38    /// script is malformed.
39    MalformedWitnessVersion,
40    /// The witness program must be between 2 and 40 bytes in length.
41    InvalidWitnessProgramLength(usize),
42    /// A v0 witness program must be either of length 20 or 32.
43    InvalidSegwitV0ProgramLength(usize),
44    /// An uncompressed pubkey was used where it is not allowed.
45    UncompressedPubkey,
46}
47
48/// Version of the witness program.
49///
50/// First byte of `scriptPubkey` in transaction output for transactions starting
51/// with 0 and 0x51-0x60 (inclusive).
52#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
53#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
54#[strict_type(lib = LIB_NAME_BITCOIN, tags = repr, into_u8, try_from_u8)]
55#[repr(u8)]
56pub enum WitnessVer {
57    /// Initial version of witness program. Used for P2WPKH and P2WPK outputs
58    #[strict_type(dumb)]
59    #[display("segwit0")]
60    V0 = OP_PUSHBYTES_0,
61
62    /// Version of witness program used for Taproot P2TR outputs.
63    #[display("segwit1")]
64    V1 = OP_PUSHNUM_1,
65
66    /// Future (unsupported) version of witness program.
67    #[display("segwit2")]
68    V2 = OP_PUSHNUM_2,
69
70    /// Future (unsupported) version of witness program.
71    #[display("segwit3")]
72    V3 = OP_PUSHNUM_3,
73
74    /// Future (unsupported) version of witness program.
75    #[display("segwit4")]
76    V4 = OP_PUSHNUM_4,
77
78    /// Future (unsupported) version of witness program.
79    #[display("segwit5")]
80    V5 = OP_PUSHNUM_5,
81
82    /// Future (unsupported) version of witness program.
83    #[display("segwit6")]
84    V6 = OP_PUSHNUM_6,
85
86    /// Future (unsupported) version of witness program.
87    #[display("segwit7")]
88    V7 = OP_PUSHNUM_7,
89
90    /// Future (unsupported) version of witness program.
91    #[display("segwit8")]
92    V8 = OP_PUSHNUM_8,
93
94    /// Future (unsupported) version of witness program.
95    #[display("segwit9")]
96    V9 = OP_PUSHNUM_9,
97
98    /// Future (unsupported) version of witness program.
99    #[display("segwit10")]
100    V10 = OP_PUSHNUM_10,
101
102    /// Future (unsupported) version of witness program.
103    #[display("segwit11")]
104    V11 = OP_PUSHNUM_11,
105
106    /// Future (unsupported) version of witness program.
107    #[display("segwit12")]
108    V12 = OP_PUSHNUM_12,
109
110    /// Future (unsupported) version of witness program.
111    #[display("segwit13")]
112    V13 = OP_PUSHNUM_13,
113
114    /// Future (unsupported) version of witness program.
115    #[display("segwit14")]
116    V14 = OP_PUSHNUM_14,
117
118    /// Future (unsupported) version of witness program.
119    #[display("segwit15")]
120    V15 = OP_PUSHNUM_15,
121
122    /// Future (unsupported) version of witness program.
123    #[display("segwit16")]
124    V16 = OP_PUSHNUM_16,
125}
126
127impl WitnessVer {
128    /// Converts bitcoin script opcode into [`WitnessVer`] variant.
129    ///
130    /// # Errors
131    /// If the opcode does not correspond to any witness version, errors with
132    /// [`SegwitError::MalformedWitnessVersion`].
133    pub fn from_op_code(op_code: OpCode) -> Result<Self, SegwitError> {
134        match op_code as u8 {
135            0 => Ok(WitnessVer::V0),
136            OP_PUSHNUM_1 => Ok(WitnessVer::V1),
137            OP_PUSHNUM_2 => Ok(WitnessVer::V2),
138            OP_PUSHNUM_3 => Ok(WitnessVer::V3),
139            OP_PUSHNUM_4 => Ok(WitnessVer::V4),
140            OP_PUSHNUM_5 => Ok(WitnessVer::V5),
141            OP_PUSHNUM_6 => Ok(WitnessVer::V6),
142            OP_PUSHNUM_7 => Ok(WitnessVer::V7),
143            OP_PUSHNUM_8 => Ok(WitnessVer::V8),
144            OP_PUSHNUM_9 => Ok(WitnessVer::V9),
145            OP_PUSHNUM_10 => Ok(WitnessVer::V10),
146            OP_PUSHNUM_11 => Ok(WitnessVer::V11),
147            OP_PUSHNUM_12 => Ok(WitnessVer::V12),
148            OP_PUSHNUM_13 => Ok(WitnessVer::V13),
149            OP_PUSHNUM_14 => Ok(WitnessVer::V14),
150            OP_PUSHNUM_15 => Ok(WitnessVer::V15),
151            OP_PUSHNUM_16 => Ok(WitnessVer::V16),
152            _ => Err(SegwitError::MalformedWitnessVersion),
153        }
154    }
155
156    /// Converts witness version ordinal number into [`WitnessVer`] variant.
157    ///
158    /// # Errors
159    /// If the witness version number exceeds 16, errors with
160    /// [`SegwitError::MalformedWitnessVersion`].
161    pub fn from_version_no(no: u8) -> Result<Self, SegwitError> {
162        Ok(match no {
163            v if v == Self::V0.version_no() => Self::V0,
164            v if v == Self::V1.version_no() => Self::V1,
165            v if v == Self::V2.version_no() => Self::V2,
166            v if v == Self::V3.version_no() => Self::V3,
167            v if v == Self::V4.version_no() => Self::V4,
168            v if v == Self::V5.version_no() => Self::V5,
169            v if v == Self::V6.version_no() => Self::V6,
170            v if v == Self::V7.version_no() => Self::V7,
171            v if v == Self::V8.version_no() => Self::V8,
172            v if v == Self::V9.version_no() => Self::V9,
173            v if v == Self::V10.version_no() => Self::V10,
174            v if v == Self::V11.version_no() => Self::V11,
175            v if v == Self::V12.version_no() => Self::V12,
176            v if v == Self::V13.version_no() => Self::V13,
177            v if v == Self::V14.version_no() => Self::V14,
178            v if v == Self::V15.version_no() => Self::V15,
179            v if v == Self::V16.version_no() => Self::V16,
180            _ => return Err(SegwitError::InvalidWitnessVersion(no)),
181        })
182    }
183
184    /// Converts [`WitnessVer`] instance into corresponding Bitcoin op-code.
185    // TODO: Replace `try_from` with `from` since opcodes cover whole range of
186    //       u8
187    pub fn op_code(self) -> OpCode {
188        OpCode::try_from(self as u8).expect("full range of u8 is covered")
189    }
190
191    /// Converts [`WitnessVer`] into ordinal version number.
192    pub fn version_no(self) -> u8 {
193        match self {
194            WitnessVer::V0 => 0,
195            WitnessVer::V1 => 1,
196            WitnessVer::V2 => 2,
197            WitnessVer::V3 => 3,
198            WitnessVer::V4 => 4,
199            WitnessVer::V5 => 5,
200            WitnessVer::V6 => 6,
201            WitnessVer::V7 => 7,
202            WitnessVer::V8 => 8,
203            WitnessVer::V9 => 9,
204            WitnessVer::V10 => 10,
205            WitnessVer::V11 => 11,
206            WitnessVer::V12 => 12,
207            WitnessVer::V13 => 13,
208            WitnessVer::V14 => 14,
209            WitnessVer::V15 => 15,
210            WitnessVer::V16 => 16,
211        }
212    }
213}
214
215/// Witness program as defined in BIP141.
216#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
217#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)]
218#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self::dumb())]
219pub struct WitnessProgram {
220    /// The witness program version.
221    version: WitnessVer,
222    /// The witness program. (Between 2 and 40 bytes)
223    program: Confined<Vec<u8>, 2, 40>,
224}
225
226impl WitnessProgram {
227    fn dumb() -> Self { Self::new(strict_dumb!(), vec![0; 32]).unwrap() }
228
229    /// Creates a new witness program.
230    pub fn new(version: WitnessVer, program: Vec<u8>) -> Result<Self, SegwitError> {
231        let len = program.len();
232        let program = Confined::try_from(program)
233            .map_err(|_| SegwitError::InvalidWitnessProgramLength(len))?;
234
235        // Specific segwit v0 check. These addresses can never spend funds sent
236        // to them.
237        if version == WitnessVer::V0 && (program.len() != 20 && program.len() != 32) {
238            return Err(SegwitError::InvalidSegwitV0ProgramLength(program.len()));
239        }
240
241        Ok(WitnessProgram { version, program })
242    }
243
244    /// Returns the witness program version.
245    pub fn version(&self) -> WitnessVer { self.version }
246
247    /// Returns the witness program.
248    pub fn program(&self) -> &[u8] { &self.program }
249}
250
251impl ScriptPubkey {
252    pub fn p2wpkh(hash: impl Into<[u8; 20]>) -> Self {
253        Self::with_witness_program_unchecked(WitnessVer::V0, &hash.into())
254    }
255
256    pub fn p2wsh(hash: impl Into<[u8; 32]>) -> Self {
257        Self::with_witness_program_unchecked(WitnessVer::V0, &hash.into())
258    }
259
260    pub fn is_p2wpkh(&self) -> bool {
261        self.len() == 22 && self[0] == WitnessVer::V0.op_code() as u8 && self[1] == OP_PUSHBYTES_20
262    }
263
264    pub fn is_p2wsh(&self) -> bool {
265        self.len() == 34 && self[0] == WitnessVer::V0.op_code() as u8 && self[1] == OP_PUSHBYTES_32
266    }
267
268    /// Generates P2WSH-type of scriptPubkey with a given [`WitnessProgram`].
269    pub fn from_witness_program(witness_program: &WitnessProgram) -> Self {
270        Self::with_witness_program_unchecked(witness_program.version, witness_program.program())
271    }
272
273    /// Generates P2WSH-type of scriptPubkey with a given [`WitnessVer`] and
274    /// the program bytes. Does not do any checks on version or program length.
275    pub(crate) fn with_witness_program_unchecked(ver: WitnessVer, prog: &[u8]) -> Self {
276        let mut script = Self::with_capacity(ScriptBytes::len_for_slice(prog.len()) + 2);
277        script.push_opcode(ver.op_code());
278        script.push_slice(prog);
279        script
280    }
281
282    /// Checks whether a script pubkey is a Segregated Witness (segwit) program.
283    #[inline]
284    pub fn is_witness_program(&self) -> bool {
285        // A scriptPubKey (or redeemScript as defined in BIP16/P2SH) that consists of a
286        // 1-byte push opcode (for 0 to 16) followed by a data push between 2
287        // and 40 bytes gets a new special meaning. The value of the first push
288        // is called the "version byte". The following byte vector pushed is
289        // called the "witness program".
290        let script_len = self.len();
291        if !(4..=42).contains(&script_len) {
292            return false;
293        }
294        // Version 0 or PUSHNUM_1-PUSHNUM_16
295        let Ok(ver_opcode) = OpCode::try_from(self[0]) else {
296            return false;
297        };
298        let push_opbyte = self[1]; // Second byte push opcode 2-40 bytes
299        WitnessVer::from_op_code(ver_opcode).is_ok()
300            && (OP_PUSHBYTES_2..=OP_PUSHBYTES_40).contains(&push_opbyte)
301            // Check that the rest of the script has the correct size
302            && script_len - 2 == push_opbyte as usize
303    }
304}
305
306#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)]
307#[wrapper(Deref, AsSlice, Hex)]
308#[wrapper_mut(DerefMut, AsSliceMut)]
309#[derive(StrictType, StrictEncode, StrictDecode)]
310#[strict_type(lib = LIB_NAME_BITCOIN)]
311#[cfg_attr(
312    feature = "serde",
313    derive(Serialize, Deserialize),
314    serde(crate = "serde_crate", transparent)
315)]
316pub struct WitnessScript(ScriptBytes);
317
318impl TryFrom<Vec<u8>> for WitnessScript {
319    type Error = confinement::Error;
320    fn try_from(script_bytes: Vec<u8>) -> Result<Self, Self::Error> {
321        ScriptBytes::try_from(script_bytes).map(Self)
322    }
323}
324
325impl WitnessScript {
326    #[inline]
327    pub fn new() -> Self { Self::default() }
328
329    #[inline]
330    pub fn with_capacity(capacity: usize) -> Self {
331        Self(ScriptBytes::from(Confined::with_capacity(capacity)))
332    }
333
334    /// Constructs script object assuming the script length is less than 4GB.
335    /// Panics otherwise.
336    #[inline]
337    pub fn from_unsafe(script_bytes: Vec<u8>) -> Self {
338        Self(ScriptBytes::from_unsafe(script_bytes))
339    }
340
341    /// Adds a single opcode to the script.
342    #[inline]
343    pub fn push_opcode(&mut self, op_code: OpCode) { self.0.push(op_code as u8); }
344
345    pub fn to_redeem_script(&self) -> RedeemScript {
346        let script = ScriptPubkey::p2wsh(WScriptHash::from(self));
347        RedeemScript::from_inner(script.into_inner())
348    }
349
350    pub fn to_script_pubkey(&self) -> ScriptPubkey { ScriptPubkey::p2wsh(WScriptHash::from(self)) }
351
352    #[inline]
353    pub fn as_script_bytes(&self) -> &ScriptBytes { &self.0 }
354}
355
356#[derive(Wrapper, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)]
357#[wrapper(BorrowSlice, Index, RangeOps, Debug, Hex, Display, FromStr)]
358#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
359#[strict_type(lib = LIB_NAME_BITCOIN)]
360#[cfg_attr(
361    feature = "serde",
362    derive(Serialize, Deserialize),
363    serde(crate = "serde_crate", transparent)
364)]
365pub struct Wtxid(
366    #[from]
367    #[from([u8; 32])]
368    Bytes32StrRev,
369);
370
371#[derive(Wrapper, Clone, Eq, PartialEq, Hash, Debug, From, Default)]
372#[wrapper(Deref, Index, RangeOps)]
373#[derive(StrictType, StrictEncode, StrictDecode)]
374#[strict_type(lib = LIB_NAME_BITCOIN)]
375pub struct Witness(VarIntArray<ByteStr>);
376
377impl IntoIterator for Witness {
378    type Item = ByteStr;
379    type IntoIter = vec::IntoIter<ByteStr>;
380
381    fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
382}
383
384impl Witness {
385    #[inline]
386    pub fn new() -> Self { default!() }
387
388    #[inline]
389    pub fn elements(&self) -> impl Iterator<Item = &'_ [u8]> {
390        self.0.iter().map(|el| el.as_slice())
391    }
392
393    pub fn from_consensus_stack(witness: impl IntoIterator<Item = Vec<u8>>) -> Witness {
394        let iter = witness.into_iter().map(ByteStr::from);
395        let stack =
396            VarIntArray::try_from_iter(iter).expect("witness stack size exceeds 2^32 elements");
397        Witness(stack)
398    }
399
400    #[inline]
401    pub(crate) fn as_var_int_array(&self) -> &VarIntArray<ByteStr> { &self.0 }
402}
403
404#[cfg(feature = "serde")]
405mod _serde {
406    use serde::{Deserialize, Serialize};
407    use serde_crate::ser::SerializeSeq;
408    use serde_crate::{Deserializer, Serializer};
409
410    use super::*;
411
412    impl Serialize for Witness {
413        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
414        where S: Serializer {
415            let mut ser = serializer.serialize_seq(Some(self.len()))?;
416            for el in &self.0 {
417                ser.serialize_element(&el)?;
418            }
419            ser.end()
420        }
421    }
422
423    impl<'de> Deserialize<'de> for Witness {
424        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
425        where D: Deserializer<'de> {
426            let data = Vec::<ByteStr>::deserialize(deserializer)?;
427            Ok(Witness::from_consensus_stack(data.into_iter().map(ByteStr::into_vec)))
428        }
429    }
430}