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 }