snarkvm_console_network/helpers/
id.rs1use crate::prelude::*;
17
18use anyhow::Result;
19use bech32::{self, FromBase32, ToBase32};
20use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
21use std::borrow::Borrow;
22
23pub trait Bech32ID<F: FieldTrait>:
24 From<F>
25 + Deref<Target = F>
26 + Into<Vec<F>>
27 + Uniform
28 + Copy
29 + Clone
30 + Default
31 + Debug
32 + Display
33 + FromStr
34 + ToBytes
35 + FromBytes
36 + Serialize
37 + DeserializeOwned
38 + PartialEq
39 + Eq
40 + core::hash::Hash
41 + Sync
42 + Send
43{
44 fn prefix() -> String;
45 fn size_in_bytes() -> usize;
46 fn number_of_data_characters() -> usize;
47}
48
49#[rustfmt::skip]
50#[macro_export]
51macro_rules! const_assert {
52 ($x:expr $(,)*) => {
53 pub const ASSERT: [(); 1] = [()];
54 pub const fn bool_assert(x: bool) -> bool { x }
55 let _ = ASSERT[!bool_assert($x) as usize];
56 };
57}
58
59#[macro_export]
61macro_rules! hrp2 {
62 ( $persona: expr ) => {{
63 const_assert!($persona.len() == 2);
64 let p = $persona.as_bytes();
65 u16::from_le_bytes([p[0], p[1]])
66 }};
67}
68
69#[derive(Copy, Clone, PartialEq, Eq, Hash)]
70pub struct AleoID<F: FieldTrait, const PREFIX: u16>(F);
71
72impl<F: FieldTrait, const PREFIX: u16> Bech32ID<F> for AleoID<F, PREFIX> {
73 #[inline]
74 fn prefix() -> String {
75 String::from_utf8(PREFIX.to_le_bytes().to_vec()).expect("Failed to convert prefix to string")
76 }
77
78 #[inline]
79 fn size_in_bytes() -> usize {
80 (F::size_in_bits() + 7) / 8
81 }
82
83 #[inline]
84 fn number_of_data_characters() -> usize {
85 ((Self::size_in_bytes() * 8) + 4) / 5
86 }
87}
88
89impl<F: FieldTrait, const PREFIX: u16> From<F> for AleoID<F, PREFIX> {
90 #[inline]
91 fn from(data: F) -> Self {
92 Self(data)
93 }
94}
95
96impl<F: FieldTrait, const PREFIX: u16> Default for AleoID<F, PREFIX> {
97 #[inline]
98 fn default() -> Self {
99 Self(F::zero())
100 }
101}
102
103impl<F: FieldTrait, const PREFIX: u16> FromBytes for AleoID<F, PREFIX> {
104 #[inline]
106 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
107 Ok(Self(F::read_le(&mut reader)?))
108 }
109}
110
111impl<F: FieldTrait, const PREFIX: u16> ToBytes for AleoID<F, PREFIX> {
112 #[inline]
114 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
115 self.0.write_le(&mut writer)
116 }
117}
118
119impl<F: FieldTrait, const PREFIX: u16> FromStr for AleoID<F, PREFIX> {
120 type Err = Error;
121
122 #[inline]
124 fn from_str(string: &str) -> Result<Self, Self::Err> {
125 const CHECKSUM_STRING_LENGTH: usize = 6;
126 if string.len() != 3 + Self::number_of_data_characters() + CHECKSUM_STRING_LENGTH {
127 bail!("Invalid byte size for a bech32m hash: {} bytes", string.len())
128 }
129
130 let (hrp, data, variant) = bech32::decode(string)?;
131 if hrp.as_bytes() != PREFIX.to_le_bytes() {
132 bail!("Invalid prefix for a bech32m hash: {hrp}")
133 };
134 if data.is_empty() {
135 bail!("Bech32m hash data is empty")
136 }
137 if variant != bech32::Variant::Bech32m {
138 bail!("Hash is not a bech32m hash")
139 }
140 Ok(Self::read_le(&*Vec::from_base32(&data)?)?)
141 }
142}
143
144impl<F: FieldTrait, const PREFIX: u16> Display for AleoID<F, PREFIX> {
145 #[inline]
146 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
147 bech32::encode_to_fmt(
148 f,
149 &Self::prefix(),
150 self.0.to_bytes_le().expect("Failed to write data as bytes").to_base32(),
151 bech32::Variant::Bech32m,
152 )
153 .expect("Failed to encode in bech32m")
154 }
155}
156
157impl<F: FieldTrait, const PREFIX: u16> Debug for AleoID<F, PREFIX> {
158 #[inline]
159 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
160 write!(f, "AleoLocator {{ hrp: {:?}, data: {:?} }}", &Self::prefix(), self.0)
161 }
162}
163
164impl<F: FieldTrait, const PREFIX: u16> Serialize for AleoID<F, PREFIX> {
165 #[inline]
166 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
167 match serializer.is_human_readable() {
168 true => serializer.collect_str(self),
169 false => ToBytesSerializer::serialize(self, serializer),
170 }
171 }
172}
173
174impl<'de, F: FieldTrait, const PREFIX: u16> Deserialize<'de> for AleoID<F, PREFIX> {
175 #[inline]
176 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
177 match deserializer.is_human_readable() {
178 true => FromStr::from_str(&String::deserialize(deserializer)?).map_err(de::Error::custom),
179 false => FromBytesDeserializer::<Self>::deserialize(deserializer, &Self::prefix(), Self::size_in_bytes()),
180 }
181 }
182}
183
184impl<F: FieldTrait, const PREFIX: u16> Deref for AleoID<F, PREFIX> {
185 type Target = F;
186
187 #[inline]
188 fn deref(&self) -> &Self::Target {
189 &self.0
190 }
191}
192
193impl<F: FieldTrait, const PREFIX: u16> Borrow<F> for AleoID<F, PREFIX> {
194 #[inline]
195 fn borrow(&self) -> &F {
196 &self.0
197 }
198}
199
200#[allow(clippy::from_over_into)]
201impl<F: FieldTrait, const PREFIX: u16> Into<Vec<F>> for AleoID<F, PREFIX> {
202 #[inline]
203 fn into(self) -> Vec<F> {
204 vec![self.0]
205 }
206}
207
208impl<F: FieldTrait, const PREFIX: u16> Distribution<AleoID<F, PREFIX>> for Standard {
209 #[inline]
210 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AleoID<F, PREFIX> {
211 AleoID::<F, PREFIX>(Uniform::rand(rng))
212 }
213}