taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

base32.rs (3691B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024, 2025, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::{borrow::Cow, fmt::Display, ops::Deref, str::FromStr};
     18 
     19 use rand::{TryRng, rngs::SysRng};
     20 use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
     21 
     22 use crate::encoding::base32::{self, Base32Error, decode_static};
     23 
     24 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
     25 pub struct Base32<const L: usize>([u8; L]);
     26 
     27 impl<const L: usize> Base32<L> {
     28     pub const ZEROED: Base32<L> = Self([0; L]);
     29 
     30     pub fn rand() -> Self {
     31         Self(rand::random())
     32     }
     33 
     34     pub fn secure_rand() -> Self {
     35         let mut array = [0; L];
     36         SysRng.try_fill_bytes(&mut array).unwrap();
     37         Self(array)
     38     }
     39 }
     40 
     41 impl<const L: usize> From<[u8; L]> for Base32<L> {
     42     fn from(array: [u8; L]) -> Self {
     43         Self(array)
     44     }
     45 }
     46 
     47 impl<const L: usize> Deref for Base32<L> {
     48     type Target = [u8; L];
     49 
     50     fn deref(&self) -> &Self::Target {
     51         &self.0
     52     }
     53 }
     54 
     55 impl<const L: usize> FromStr for Base32<L> {
     56     type Err = Base32Error<L>;
     57 
     58     fn from_str(s: &str) -> Result<Self, Self::Err> {
     59         Ok(Self(decode_static(s.as_bytes())?))
     60     }
     61 }
     62 
     63 impl<const L: usize> Display for Base32<L> {
     64     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     65         // TODO use a unique stack allocated buffer when supported
     66         f.write_fmt(format_args!("{}", base32::fmt(&self.0)))
     67     }
     68 }
     69 
     70 impl<const L: usize> std::fmt::Debug for Base32<L> {
     71     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     72         Display::fmt(&self, f)
     73     }
     74 }
     75 
     76 impl<const L: usize> Serialize for Base32<L> {
     77     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     78     where
     79         S: Serializer,
     80     {
     81         serializer.collect_str(&self)
     82     }
     83 }
     84 
     85 impl<'de, const L: usize> Deserialize<'de> for Base32<L> {
     86     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     87     where
     88         D: Deserializer<'de>,
     89     {
     90         let raw = Cow::<str>::deserialize(deserializer)?;
     91         Self::from_str(&raw).map_err(D::Error::custom)
     92     }
     93 }
     94 
     95 impl<'a, const L: usize> TryFrom<&'a [u8]> for Base32<L> {
     96     type Error = Base32Error<L>;
     97 
     98     fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
     99         Ok(Self(
    100             value
    101                 .try_into()
    102                 .map_err(|_| Base32Error::Length(value.len()))?,
    103         ))
    104     }
    105 }
    106 
    107 impl<const L: usize> sqlx::Type<sqlx::Postgres> for Base32<L> {
    108     fn type_info() -> sqlx::postgres::PgTypeInfo {
    109         <&[u8]>::type_info()
    110     }
    111 }
    112 
    113 impl<'q, const L: usize> sqlx::Encode<'q, sqlx::Postgres> for Base32<L> {
    114     fn encode_by_ref(
    115         &self,
    116         buf: &mut sqlx::postgres::PgArgumentBuffer,
    117     ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {
    118         self.0.encode_by_ref(buf)
    119     }
    120 }
    121 
    122 impl<'r, const L: usize> sqlx::Decode<'r, sqlx::Postgres> for Base32<L> {
    123     fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> {
    124         let array = <[u8; L]>::decode(value)?;
    125         Ok(Self(array))
    126     }
    127 }