1use bech32::{FromBase32, ToBase32};
6pub use bech32::{Variant, Variant::*};
9use serde::{Deserialize, Deserializer, Serializer};
10
11pub 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
39pub 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 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 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 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 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 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 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 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 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 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 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}