Skip to main content

psbt_v2/v2/
dleq.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! BIP-375: Support for silent payments in PSBTs.
4//!
5//! This module provides type-safe wrapper for BIP-374 dleq proof field.
6
7use core::fmt;
8
9use crate::prelude::*;
10use crate::serialize::{Deserialize, Serialize};
11
12/// A 64-byte DLEQ proof (BIP-374).
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct DleqProof(pub [u8; 64]);
15
16#[cfg(feature = "serde")]
17impl serde::Serialize for DleqProof {
18    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
19    where
20        S: serde::Serializer,
21    {
22        if serializer.is_human_readable() {
23            serializer.serialize_str(&bitcoin::hex::DisplayHex::to_lower_hex_string(&self.0[..]))
24        } else {
25            serializer.serialize_bytes(&self.0[..])
26        }
27    }
28}
29
30#[cfg(feature = "serde")]
31impl<'de> serde::Deserialize<'de> for DleqProof {
32    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
33    where
34        D: serde::Deserializer<'de>,
35    {
36        if deserializer.is_human_readable() {
37            struct HexVisitor;
38            impl serde::de::Visitor<'_> for HexVisitor {
39                type Value = DleqProof;
40
41                fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
42                    f.write_str("a 64-byte hex string")
43                }
44
45                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
46                where
47                    E: serde::de::Error,
48                {
49                    use bitcoin::hex::FromHex;
50                    let vec = Vec::<u8>::from_hex(s).map_err(E::custom)?;
51                    DleqProof::try_from(vec).map_err(|e| {
52                        E::custom(format!("expected {} bytes, got {}", e.expected, e.got))
53                    })
54                }
55            }
56            deserializer.deserialize_str(HexVisitor)
57        } else {
58            struct BytesVisitor;
59            impl serde::de::Visitor<'_> for BytesVisitor {
60                type Value = DleqProof;
61
62                fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
63                    f.write_str("64 bytes")
64                }
65
66                fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
67                where
68                    E: serde::de::Error,
69                {
70                    DleqProof::try_from(v).map_err(|e| {
71                        E::custom(format!("expected {} bytes, got {}", e.expected, e.got))
72                    })
73                }
74            }
75            deserializer.deserialize_bytes(BytesVisitor)
76        }
77    }
78}
79
80impl DleqProof {
81    /// Returns the inner 64-byte array.
82    pub fn as_bytes(&self) -> &[u8; 64] { &self.0 }
83}
84
85impl From<[u8; 64]> for DleqProof {
86    fn from(bytes: [u8; 64]) -> Self { DleqProof(bytes) }
87}
88
89impl AsRef<[u8]> for DleqProof {
90    fn as_ref(&self) -> &[u8] { &self.0 }
91}
92
93impl TryFrom<&[u8]> for DleqProof {
94    type Error = InvalidLengthError;
95
96    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
97        <[u8; 64]>::try_from(slice)
98            .map(DleqProof)
99            .map_err(|_| InvalidLengthError { got: slice.len(), expected: 64 })
100    }
101}
102
103impl TryFrom<Vec<u8>> for DleqProof {
104    type Error = InvalidLengthError;
105
106    fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> { Self::try_from(v.as_slice()) }
107}
108
109impl Serialize for DleqProof {
110    fn serialize(&self) -> Vec<u8> { self.0.to_vec() }
111}
112
113impl Deserialize for DleqProof {
114    fn deserialize(bytes: &[u8]) -> Result<Self, crate::serialize::Error> {
115        DleqProof::try_from(bytes).map_err(|e| {
116            crate::serialize::Error::InvalidDleqProof(InvalidLengthError {
117                got: e.got,
118                expected: e.expected,
119            })
120        })
121    }
122}
123
124/// Error returned when a byte array has an invalid length for a dleq proof.
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub struct InvalidLengthError {
127    /// The length that was provided.
128    pub got: usize,
129    /// The expected length.
130    pub expected: usize,
131}
132
133impl fmt::Display for InvalidLengthError {
134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135        write!(f, "invalid length for BIP-375 type: got {}, expected {}", self.got, self.expected)
136    }
137}
138
139#[cfg(feature = "std")]
140impl std::error::Error for InvalidLengthError {}