/ console / network / src / helpers / id.rs
id.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use crate::prelude::*;
 17  
 18  use anyhow::Result;
 19  use bech32::{self, FromBase32, ToBase32};
 20  use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
 21  use std::borrow::Borrow;
 22  
 23  pub 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]
 51  macro_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  /// Converts a string of 2 characters into a `u16` for a human-readable prefix in Bech32.
 60  #[macro_export]
 61  macro_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)]
 70  pub struct AlphaID<F: FieldTrait, const PREFIX: u16>(F);
 71  
 72  impl<F: FieldTrait, const PREFIX: u16> Bech32ID<F> for AlphaID<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().div_ceil(8)
 81      }
 82  
 83      #[inline]
 84      fn number_of_data_characters() -> usize {
 85          (Self::size_in_bytes() * 8).div_ceil(5)
 86      }
 87  }
 88  
 89  impl<F: FieldTrait, const PREFIX: u16> From<F> for AlphaID<F, PREFIX> {
 90      #[inline]
 91      fn from(data: F) -> Self {
 92          Self(data)
 93      }
 94  }
 95  
 96  impl<F: FieldTrait, const PREFIX: u16> Default for AlphaID<F, PREFIX> {
 97      #[inline]
 98      fn default() -> Self {
 99          Self(F::zero())
100      }
101  }
102  
103  impl<F: FieldTrait, const PREFIX: u16> FromBytes for AlphaID<F, PREFIX> {
104      /// Reads data into a buffer.
105      #[inline]
106      fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
107          Ok(Self(F::read_le(&mut reader)?))
108      }
109  }
110  
111  impl<F: FieldTrait, const PREFIX: u16> ToBytes for AlphaID<F, PREFIX> {
112      /// Writes the data to a buffer.
113      #[inline]
114      fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
115          self.0.write_le(&mut writer)
116      }
117  }
118  
119  impl<F: FieldTrait, const PREFIX: u16> FromStr for AlphaID<F, PREFIX> {
120      type Err = Error;
121  
122      /// Reads in a bech32m string.
123      #[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  
144  impl<F: FieldTrait, const PREFIX: u16> Display for AlphaID<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  
157  impl<F: FieldTrait, const PREFIX: u16> Debug for AlphaID<F, PREFIX> {
158      #[inline]
159      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
160          write!(f, "AlphaLocator {{ hrp: {:?}, data: {:?} }}", &Self::prefix(), self.0)
161      }
162  }
163  
164  impl<F: FieldTrait, const PREFIX: u16> Serialize for AlphaID<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  
174  impl<'de, F: FieldTrait, const PREFIX: u16> Deserialize<'de> for AlphaID<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  
184  impl<F: FieldTrait, const PREFIX: u16> Deref for AlphaID<F, PREFIX> {
185      type Target = F;
186  
187      #[inline]
188      fn deref(&self) -> &Self::Target {
189          &self.0
190      }
191  }
192  
193  impl<F: FieldTrait, const PREFIX: u16> Borrow<F> for AlphaID<F, PREFIX> {
194      #[inline]
195      fn borrow(&self) -> &F {
196          &self.0
197      }
198  }
199  
200  #[allow(clippy::from_over_into)]
201  impl<F: FieldTrait, const PREFIX: u16> Into<Vec<F>> for AlphaID<F, PREFIX> {
202      #[inline]
203      fn into(self) -> Vec<F> {
204          vec![self.0]
205      }
206  }
207  
208  impl<F: FieldTrait, const PREFIX: u16> Distribution<AlphaID<F, PREFIX>> for Standard {
209      #[inline]
210      fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AlphaID<F, PREFIX> {
211          AlphaID::<F, PREFIX>(Uniform::rand(rng))
212      }
213  }