base32.rs (3708B)
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::{Base32Error, decode_static, encode_static, encoded_buf_len}; 23 24 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] 25 pub struct Base32<const L: usize>([u8; L]); 26 27 impl<const L: usize> Base32<L> { 28 pub fn rand() -> Self { 29 Self(rand::random()) 30 } 31 32 pub fn secure_rand() -> Self { 33 let mut array = [0; L]; 34 SysRng.try_fill_bytes(&mut array).unwrap(); 35 Self(array) 36 } 37 } 38 39 impl<const L: usize> From<[u8; L]> for Base32<L> { 40 fn from(array: [u8; L]) -> Self { 41 Self(array) 42 } 43 } 44 45 impl<const L: usize> Deref for Base32<L> { 46 type Target = [u8; L]; 47 48 fn deref(&self) -> &Self::Target { 49 &self.0 50 } 51 } 52 53 impl<const L: usize> FromStr for Base32<L> { 54 type Err = Base32Error<L>; 55 56 fn from_str(s: &str) -> Result<Self, Self::Err> { 57 Ok(Self(decode_static(s.as_bytes())?)) 58 } 59 } 60 61 impl<const L: usize> Display for Base32<L> { 62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 63 let mut buff = vec![0u8; encoded_buf_len(L)]; // TODO use a stack allocated buffer when supported 64 f.write_str(encode_static(&self.0, &mut buff)) 65 } 66 } 67 68 impl<const L: usize> std::fmt::Debug for Base32<L> { 69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 70 Display::fmt(&self, f) 71 } 72 } 73 74 impl<const L: usize> Serialize for Base32<L> { 75 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 76 where 77 S: Serializer, 78 { 79 serializer.serialize_str(&self.to_string()) 80 } 81 } 82 83 impl<'de, const L: usize> Deserialize<'de> for Base32<L> { 84 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 85 where 86 D: Deserializer<'de>, 87 { 88 let raw = Cow::<str>::deserialize(deserializer)?; 89 Self::from_str(&raw).map_err(D::Error::custom) 90 } 91 } 92 93 impl<'a, const L: usize> TryFrom<&'a [u8]> for Base32<L> { 94 type Error = Base32Error<L>; 95 96 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> { 97 Ok(Self( 98 value 99 .try_into() 100 .map_err(|_| Base32Error::Length(value.len()))?, 101 )) 102 } 103 } 104 105 impl<const L: usize> sqlx::Type<sqlx::Postgres> for Base32<L> { 106 fn type_info() -> sqlx::postgres::PgTypeInfo { 107 <&[u8]>::type_info() 108 } 109 } 110 111 impl<'q, const L: usize> sqlx::Encode<'q, sqlx::Postgres> for Base32<L> { 112 fn encode_by_ref( 113 &self, 114 buf: &mut sqlx::postgres::PgArgumentBuffer, 115 ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> { 116 self.0.encode_by_ref(buf) 117 } 118 } 119 120 impl<'r, const L: usize> sqlx::Decode<'r, sqlx::Postgres> for Base32<L> { 121 fn decode(value: sqlx::postgres::PgValueRef<'r>) -> Result<Self, sqlx::error::BoxDynError> { 122 let array = <[u8; L]>::decode(value)?; 123 Ok(Self(array)) 124 } 125 }