1use std::collections::BTreeMap;
2
3use anyhow::{Context, ensure};
4
5use crate::encoding::{Decodable, Encodable};
6use crate::module::registry::ModuleDecoderRegistry;
7
8const RFC4648: [u8; 32] = *b"0123456789abcdefghijklmnopqrstuv";
10
11pub const FEDIMINT_PREFIX: &str = "fedimint";
14
15pub fn encode(input: &[u8]) -> String {
17 let mut output = Vec::with_capacity(((8 * input.len()) / 5) + 1);
18
19 let mut buffer = 0;
20 let mut bits = 0;
21
22 for byte in input {
23 buffer |= (*byte as usize) << bits;
24 bits += 8;
25
26 while bits >= 5 {
27 output.push(RFC4648[buffer & 0b11111]);
28
29 buffer >>= 5;
30 bits -= 5;
31 }
32 }
33
34 if bits > 0 {
35 output.push(RFC4648[buffer & 0b11111]);
36 }
37
38 String::from_utf8(output).unwrap()
39}
40
41pub fn decode(input: &str) -> anyhow::Result<Vec<u8>> {
44 let decode_table = RFC4648
45 .iter()
46 .enumerate()
47 .map(|(i, c)| (*c, i))
48 .collect::<BTreeMap<u8, usize>>();
49
50 let mut output = Vec::with_capacity(((5 * input.len()) / 8) + 1);
51
52 let mut buffer = 0;
53 let mut bits = 0;
54
55 for byte in input.as_bytes() {
56 let value = decode_table
57 .get(byte)
58 .copied()
59 .context("Invalid character encountered")?;
60
61 buffer |= value << bits;
62 bits += 5;
63
64 while bits >= 8 {
65 output.push((buffer & 0xFF) as u8);
66
67 buffer >>= 8;
68 bits -= 8;
69 }
70 }
71
72 Ok(output)
73}
74
75pub fn encode_prefixed<T: Encodable>(prefix: &str, encodable: &T) -> String {
76 encode_prefixed_bytes(prefix, &encodable.consensus_encode_to_vec())
77}
78
79pub fn encode_prefixed_bytes(prefix: &str, bytes: &[u8]) -> String {
80 format!("{prefix}{}", encode(bytes))
81}
82
83pub fn decode_prefixed<T: Decodable>(prefix: &str, s: &str) -> anyhow::Result<T> {
84 Ok(T::consensus_decode_whole(
85 &decode_prefixed_bytes(prefix, s)?,
86 &ModuleDecoderRegistry::default(),
87 )?)
88}
89
90pub fn decode_prefixed_bytes(prefix: &str, s: &str) -> anyhow::Result<Vec<u8>> {
91 let s = s.to_lowercase();
92 ensure!(s.starts_with(prefix), "Invalid Prefix");
93 decode(&s[prefix.len()..])
94}
95
96#[test]
97fn test_base_32_roundtrip() {
98 const TEST_PREFIX: &str = "test";
99 let data: [u8; 10] = [0x50, 0xAB, 0x3F, 0x77, 0x01, 0xCD, 0x55, 0xFE, 0x10, 0x99];
100
101 for n in 1..10 {
102 let bytes = data[0..n].to_vec();
103
104 assert_eq!(decode(&encode(&bytes)).unwrap(), bytes);
105
106 assert_eq!(
107 decode_prefixed::<Vec<u8>>(TEST_PREFIX, &encode_prefixed(TEST_PREFIX, &bytes)).unwrap(),
108 bytes
109 );
110
111 assert_eq!(
112 decode_prefixed::<Vec<u8>>(
113 TEST_PREFIX,
114 &encode_prefixed(TEST_PREFIX, &bytes).to_ascii_uppercase()
115 )
116 .unwrap(),
117 bytes
118 );
119 }
120}