1use 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 InvalidWitnessVersion(u8),
37 MalformedWitnessVersion,
40 InvalidWitnessProgramLength(usize),
42 InvalidSegwitV0ProgramLength(usize),
44 UncompressedPubkey,
46}
47
48#[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 #[strict_type(dumb)]
59 #[display("segwit0")]
60 V0 = OP_PUSHBYTES_0,
61
62 #[display("segwit1")]
64 V1 = OP_PUSHNUM_1,
65
66 #[display("segwit2")]
68 V2 = OP_PUSHNUM_2,
69
70 #[display("segwit3")]
72 V3 = OP_PUSHNUM_3,
73
74 #[display("segwit4")]
76 V4 = OP_PUSHNUM_4,
77
78 #[display("segwit5")]
80 V5 = OP_PUSHNUM_5,
81
82 #[display("segwit6")]
84 V6 = OP_PUSHNUM_6,
85
86 #[display("segwit7")]
88 V7 = OP_PUSHNUM_7,
89
90 #[display("segwit8")]
92 V8 = OP_PUSHNUM_8,
93
94 #[display("segwit9")]
96 V9 = OP_PUSHNUM_9,
97
98 #[display("segwit10")]
100 V10 = OP_PUSHNUM_10,
101
102 #[display("segwit11")]
104 V11 = OP_PUSHNUM_11,
105
106 #[display("segwit12")]
108 V12 = OP_PUSHNUM_12,
109
110 #[display("segwit13")]
112 V13 = OP_PUSHNUM_13,
113
114 #[display("segwit14")]
116 V14 = OP_PUSHNUM_14,
117
118 #[display("segwit15")]
120 V15 = OP_PUSHNUM_15,
121
122 #[display("segwit16")]
124 V16 = OP_PUSHNUM_16,
125}
126
127impl WitnessVer {
128 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 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 pub fn op_code(self) -> OpCode {
188 OpCode::try_from(self as u8).expect("full range of u8 is covered")
189 }
190
191 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#[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 version: WitnessVer,
222 program: Confined<Vec<u8>, 2, 40>,
224}
225
226impl WitnessProgram {
227 fn dumb() -> Self { Self::new(strict_dumb!(), vec![0; 32]).unwrap() }
228
229 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 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 pub fn version(&self) -> WitnessVer { self.version }
246
247 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 pub fn from_witness_program(witness_program: &WitnessProgram) -> Self {
270 Self::with_witness_program_unchecked(witness_program.version, witness_program.program())
271 }
272
273 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 #[inline]
284 pub fn is_witness_program(&self) -> bool {
285 let script_len = self.len();
291 if !(4..=42).contains(&script_len) {
292 return false;
293 }
294 let Ok(ver_opcode) = OpCode::try_from(self[0]) else {
296 return false;
297 };
298 let push_opbyte = self[1]; WitnessVer::from_op_code(ver_opcode).is_ok()
300 && (OP_PUSHBYTES_2..=OP_PUSHBYTES_40).contains(&push_opbyte)
301 && 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(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
312pub struct WitnessScript(ScriptBytes);
313
314impl TryFrom<Vec<u8>> for WitnessScript {
315 type Error = confinement::Error;
316 fn try_from(script_bytes: Vec<u8>) -> Result<Self, Self::Error> {
317 ScriptBytes::try_from(script_bytes).map(Self)
318 }
319}
320
321impl WitnessScript {
322 #[inline]
323 pub fn new() -> Self { Self::default() }
324
325 #[inline]
326 pub fn with_capacity(capacity: usize) -> Self {
327 Self(ScriptBytes::from(Confined::with_capacity(capacity)))
328 }
329
330 #[inline]
333 pub fn from_checked(script_bytes: Vec<u8>) -> Self {
334 Self(ScriptBytes::from_checked(script_bytes))
335 }
336
337 #[inline]
339 pub fn push_opcode(&mut self, op_code: OpCode) { self.0.push(op_code as u8); }
340
341 pub fn to_redeem_script(&self) -> RedeemScript {
342 let script = ScriptPubkey::p2wsh(WScriptHash::from(self));
343 RedeemScript::from_inner(script.into_inner())
344 }
345
346 pub fn to_script_pubkey(&self) -> ScriptPubkey { ScriptPubkey::p2wsh(WScriptHash::from(self)) }
347
348 #[inline]
349 pub fn as_script_bytes(&self) -> &ScriptBytes { &self.0 }
350}
351
352#[derive(Wrapper, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)]
353#[wrapper(BorrowSlice, Index, RangeOps, Debug, Hex, Display, FromStr)]
354#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
355#[strict_type(lib = LIB_NAME_BITCOIN)]
356#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
357pub struct Wtxid(
358 #[from]
359 #[from([u8; 32])]
360 Bytes32StrRev,
361);
362
363#[derive(Wrapper, Clone, Eq, PartialEq, Hash, Debug, From, Default)]
364#[wrapper(Deref, Index, RangeOps)]
365#[derive(StrictType, StrictEncode, StrictDecode)]
366#[strict_type(lib = LIB_NAME_BITCOIN)]
367pub struct Witness(VarIntArray<ByteStr>);
368
369impl IntoIterator for Witness {
370 type Item = ByteStr;
371 type IntoIter = vec::IntoIter<ByteStr>;
372
373 fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
374}
375
376impl Witness {
377 #[inline]
378 pub fn new() -> Self { default!() }
379
380 #[inline]
381 pub fn elements(&self) -> impl Iterator<Item = &'_ [u8]> {
382 self.0.iter().map(|el| el.as_slice())
383 }
384
385 pub fn from_consensus_stack(witness: impl IntoIterator<Item = Vec<u8>>) -> Witness {
386 let iter = witness.into_iter().map(ByteStr::from);
387 let stack =
388 VarIntArray::try_from_iter(iter).expect("witness stack size exceeds 2^32 elements");
389 Witness(stack)
390 }
391
392 #[inline]
393 pub(crate) fn as_var_int_array(&self) -> &VarIntArray<ByteStr> { &self.0 }
394}
395
396#[cfg(feature = "serde")]
397mod _serde {
398 use serde::ser::SerializeSeq;
399 use serde::{Deserialize, Deserializer, Serialize, Serializer};
400
401 use super::*;
402
403 impl Serialize for Witness {
404 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
405 where S: Serializer {
406 let mut ser = serializer.serialize_seq(Some(self.len()))?;
407 for el in &self.0 {
408 ser.serialize_element(&el)?;
409 }
410 ser.end()
411 }
412 }
413
414 impl<'de> Deserialize<'de> for Witness {
415 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
416 where D: Deserializer<'de> {
417 let data = Vec::<ByteStr>::deserialize(deserializer)?;
418 Ok(Witness::from_consensus_stack(data.into_iter().map(ByteStr::into_vec)))
419 }
420 }
421}