1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// SPDX-License-Identifier: MIT

//! Segregated Witness functionality - useful for enforcing parts of [`BIP-173`] and [`BIP-350`].
//!
//! [BIP-173]: <https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki>
//! [BIP-350]: <https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki>

use core::fmt;

use crate::primitives::gf32::Fe32;

/// The field element representing segwit version 0.
pub const VERSION_0: Fe32 = Fe32::Q;
/// The field element representing segwit version 1 (taproot).
pub const VERSION_1: Fe32 = Fe32::P;

/// Returns true if given field element represents a valid segwit version.
pub fn is_valid_witness_version(witness_version: Fe32) -> bool {
    validate_witness_version(witness_version).is_ok()
}

/// Returns true if `length` represents a valid witness program length for `witness_version`.
pub fn is_valid_witness_program_length(length: usize, witness_version: Fe32) -> bool {
    validate_witness_program_length(length, witness_version).is_ok()
}

/// Checks that the given field element represents a valid segwit witness version.
pub fn validate_witness_version(witness_version: Fe32) -> Result<(), InvalidWitnessVersionError> {
    if witness_version.to_u8() > 16 {
        Err(InvalidWitnessVersionError(witness_version))
    } else {
        Ok(())
    }
}

/// Validates the segwit witness program `length` rules for witness `version`.
pub fn validate_witness_program_length(
    length: usize,
    version: Fe32,
) -> Result<(), WitnessLengthError> {
    use WitnessLengthError::*;

    if length < 2 {
        return Err(TooShort);
    }
    if length > 40 {
        return Err(TooLong);
    }
    if version == VERSION_0 && length != 20 && length != 32 {
        return Err(InvalidSegwitV0);
    }
    Ok(())
}

/// Field element does not represent a valid witness version.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct InvalidWitnessVersionError(Fe32);

impl fmt::Display for InvalidWitnessVersionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "field element does not represent a valid witness version")
    }
}

#[cfg(feature = "std")]
impl std::error::Error for InvalidWitnessVersionError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}

/// Witness program invalid because of incorrect length.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum WitnessLengthError {
    /// The witness data is too short.
    TooShort,
    /// The witness data is too long.
    TooLong,
    /// The segwit v0 witness is not 20 or 32 bytes long.
    InvalidSegwitV0,
}

impl fmt::Display for WitnessLengthError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use WitnessLengthError::*;

        match *self {
            TooShort => write!(f, "witness program is less than 2 bytes long"),
            TooLong => write!(f, "witness program is more than 40 bytes long"),
            InvalidSegwitV0 => write!(f, "the segwit v0 witness is not 20 or 32 bytes long"),
        }
    }
}

#[cfg(feature = "std")]
impl std::error::Error for WitnessLengthError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use WitnessLengthError::*;

        match *self {
            TooShort | TooLong | InvalidSegwitV0 => None,
        }
    }
}