penumbra_sdk_proto/serializers/
bech32str.rs

1//! Bech32 serializers. Because Bech32 is parameterized by the HRP, this module
2//! implements (internal) helper functions that are used in submodules that fill
3//! in parameters for various key types.
4
5use bech32::{FromBase32, ToBase32};
6// re-exporting allows the convenience methods to be used without referencing
7// the underlying bech32 crate.
8pub use bech32::{Variant, Variant::*};
9use serde::{Deserialize, Deserializer, Serializer};
10
11/// Convenience method for (general-purpose) Bech32 decoding.
12///
13/// Works around a bit of awkwardness in the [`bech32`] API.
14pub fn decode(
15    string: &str,
16    expected_hrp: &str,
17    expected_variant: Variant,
18) -> anyhow::Result<Vec<u8>> {
19    let (hrp, data, variant) = bech32::decode(string)?;
20
21    if variant != expected_variant {
22        anyhow::bail!(
23            "wrong bech32 variant {:?}, expected {:?}",
24            variant,
25            expected_variant
26        );
27    }
28    if hrp != expected_hrp {
29        anyhow::bail!(
30            "wrong bech32 human readable part {}, expected {}",
31            hrp,
32            expected_hrp
33        );
34    }
35
36    Ok(Vec::from_base32(&data).expect("bech32 decoding produces valid base32"))
37}
38
39/// Convenience method for (general-purpose) Bech32 encoding.
40///
41/// Works around a bit of awkwardness in the [`bech32`] API.
42/// Panics if the HRP is invalid.
43pub fn encode(data: &[u8], hrp: &str, variant: Variant) -> String {
44    bech32::encode(hrp, data.to_base32(), variant).expect("HRP should be valid")
45}
46
47fn deserialize_bech32<'de, D>(
48    deserializer: D,
49    expected_hrp: &str,
50    expected_variant: Variant,
51) -> Result<Vec<u8>, D::Error>
52where
53    D: Deserializer<'de>,
54{
55    decode(
56        &Option::<String>::deserialize(deserializer)?.unwrap_or_default(),
57        expected_hrp,
58        expected_variant,
59    )
60    .map_err(serde::de::Error::custom)
61}
62
63fn serialize_bech32<S, T>(
64    value: &T,
65    serializer: S,
66    hrp: &str,
67    variant: Variant,
68) -> Result<S::Ok, S::Error>
69where
70    S: Serializer,
71    T: AsRef<[u8]>,
72{
73    serializer.serialize_str(&encode(value.as_ref(), hrp, variant))
74}
75
76pub mod validator_identity_key {
77    use super::*;
78
79    /// The Bech32 prefix used for validator identity keys.
80    pub const BECH32_PREFIX: &str = "penumbravalid";
81
82    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
83    where
84        D: Deserializer<'de>,
85    {
86        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
87    }
88
89    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
90    where
91        S: Serializer,
92        T: AsRef<[u8]>,
93    {
94        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
95    }
96}
97
98pub mod validator_governance_key {
99    use super::*;
100
101    /// The Bech32 prefix used for validator governance keys.
102    pub const BECH32_PREFIX: &str = "penumbragovern";
103
104    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
105    where
106        D: Deserializer<'de>,
107    {
108        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
109    }
110
111    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
112    where
113        S: Serializer,
114        T: AsRef<[u8]>,
115    {
116        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
117    }
118}
119
120pub mod address {
121    use super::*;
122
123    /// The Bech32 prefix used for addresses.
124    pub const BECH32_PREFIX: &str = "penumbra";
125
126    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
127    where
128        D: Deserializer<'de>,
129    {
130        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
131    }
132
133    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
134    where
135        S: Serializer,
136        T: AsRef<[u8]>,
137    {
138        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
139    }
140}
141
142pub mod compat_address {
143    use super::*;
144
145    /// The Bech32 prefix used for compat addresses (Bech32, not Bech32m, addresses).
146    pub const BECH32_PREFIX: &str = "penumbracompat1";
147
148    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
149    where
150        D: Deserializer<'de>,
151    {
152        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32)
153    }
154
155    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
156    where
157        S: Serializer,
158        T: AsRef<[u8]>,
159    {
160        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32)
161    }
162}
163
164pub mod asset_id {
165    use super::*;
166
167    /// The Bech32 prefix used for asset IDs.
168    pub const BECH32_PREFIX: &str = "passet";
169
170    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
171    where
172        D: Deserializer<'de>,
173    {
174        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
175    }
176
177    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
178    where
179        S: Serializer,
180        T: AsRef<[u8]>,
181    {
182        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
183    }
184}
185
186pub mod full_viewing_key {
187    use super::*;
188
189    /// The Bech32 prefix used for full viewing keys.
190    pub const BECH32_PREFIX: &str = "penumbrafullviewingkey";
191
192    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
193    where
194        D: Deserializer<'de>,
195    {
196        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
197    }
198
199    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
200    where
201        S: Serializer,
202        T: AsRef<[u8]>,
203    {
204        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
205    }
206}
207
208pub mod wallet_id {
209    use super::*;
210
211    /// The Bech32 prefix used for wallet ids.
212    pub const BECH32_PREFIX: &str = "penumbrawalletid";
213
214    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
215    where
216        D: Deserializer<'de>,
217    {
218        deserialize_bech32(deserializer, BECH32_PREFIX, Bech32m)
219    }
220
221    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
222    where
223        S: Serializer,
224        T: AsRef<[u8]>,
225    {
226        serialize_bech32(value, serializer, BECH32_PREFIX, Bech32m)
227    }
228}
229
230pub mod spend_key {
231    use super::*;
232
233    /// The Bech32 prefix used for spend keys.
234    pub const BECH32_PREFIX: &str = "penumbraspendkey";
235
236    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
237    where
238        D: Deserializer<'de>,
239    {
240        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
241    }
242
243    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
244    where
245        S: Serializer,
246        T: AsRef<[u8]>,
247    {
248        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
249    }
250}
251
252pub mod lp_id {
253    use super::*;
254
255    /// The Bech32 prefix used for LP IDs.
256    pub const BECH32_PREFIX: &str = "plpid";
257
258    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
259    where
260        D: Deserializer<'de>,
261    {
262        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
263    }
264
265    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
266    where
267        S: Serializer,
268        T: AsRef<[u8]>,
269    {
270        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
271    }
272}
273
274pub mod auction_id {
275    use super::*;
276
277    /// The Bech32 prefix used for Auction IDs.
278    pub const BECH32_PREFIX: &str = "pauctid";
279
280    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
281    where
282        D: Deserializer<'de>,
283    {
284        deserialize_bech32(deserializer, BECH32_PREFIX, Variant::Bech32m)
285    }
286
287    pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
288    where
289        S: Serializer,
290        T: AsRef<[u8]>,
291    {
292        serialize_bech32(value, serializer, BECH32_PREFIX, Variant::Bech32m)
293    }
294}