1use std::collections::HashMap;
4
5use crate::engine;
6use crate::error::Error;
7use crate::validate::{self, Operand, MAX_LEN};
8
9#[derive(Clone)]
18pub struct FF1 {
19 key: Vec<u8>,
20 radix: u32,
21 min_length: usize,
22 default_tweak: Vec<u8>,
23 min_tweak_len: Option<usize>,
24 max_tweak_len: Option<usize>,
25 alphabet: Option<Alphabet>,
26}
27
28impl std::fmt::Debug for FF1 {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 f.debug_struct("FF1")
32 .field("radix", &self.radix)
33 .field("min_length", &self.min_length)
34 .field("min_tweak_len", &self.min_tweak_len)
35 .field("max_tweak_len", &self.max_tweak_len)
36 .field("has_alphabet", &self.alphabet.is_some())
37 .finish_non_exhaustive()
38 }
39}
40
41#[derive(Clone)]
43struct Alphabet {
44 chars: Vec<char>,
45 index: HashMap<char, u16>,
46}
47
48#[derive(Clone)]
50#[must_use = "a builder does nothing until .build() is called"]
51pub struct Builder<'a> {
52 key: &'a [u8],
53 radix: u32,
54 alphabet: Option<&'a str>,
55 tweak: &'a [u8],
56 min_tweak_len: Option<usize>,
57 max_tweak_len: Option<usize>,
58}
59
60impl<'a> Builder<'a> {
61 pub fn alphabet(mut self, alphabet: &'a str) -> Self {
64 self.alphabet = Some(alphabet);
65 self
66 }
67
68 pub fn tweak(mut self, tweak: &'a [u8]) -> Self {
70 self.tweak = tweak;
71 self
72 }
73
74 pub fn min_tweak_len(mut self, len: usize) -> Self {
76 self.min_tweak_len = Some(len);
77 self
78 }
79
80 pub fn max_tweak_len(mut self, len: usize) -> Self {
83 self.max_tweak_len = Some(len);
84 self
85 }
86
87 pub fn build(self) -> Result<FF1, Error> {
93 validate::key(self.key)?;
94 validate::radix(self.radix)?;
95 validate::tweak_bounds(self.min_tweak_len, self.max_tweak_len)?;
96 validate::tweak(self.tweak.len(), self.min_tweak_len, self.max_tweak_len)?;
97 let alphabet = match self.alphabet {
98 None => None,
99 Some(text) => {
100 let chars = validate::alphabet(text, self.radix)?;
101 let index = chars
103 .iter()
104 .enumerate()
105 .map(|(i, &c)| (c, u16::try_from(i).expect("position < radix < 2**16")))
106 .collect();
107 Some(Alphabet { chars, index })
108 }
109 };
110 Ok(FF1 {
111 key: self.key.to_vec(),
112 radix: self.radix,
113 min_length: validate::min_length(self.radix),
114 default_tweak: self.tweak.to_vec(),
115 min_tweak_len: self.min_tweak_len,
116 max_tweak_len: self.max_tweak_len,
117 alphabet,
118 })
119 }
120}
121
122impl FF1 {
123 pub fn new(key: &[u8], radix: u32) -> Result<FF1, Error> {
129 FF1::builder(key, radix).build()
130 }
131
132 pub fn builder(key: &[u8], radix: u32) -> Builder<'_> {
135 Builder {
136 key,
137 radix,
138 alphabet: None,
139 tweak: &[],
140 min_tweak_len: None,
141 max_tweak_len: None,
142 }
143 }
144
145 pub fn encrypt_numerals(&self, x: &[u16], tweak: Option<&[u8]>) -> Result<Vec<u16>, Error> {
148 self.run(x, tweak, Operand::Plaintext)
149 }
150
151 pub fn decrypt_numerals(&self, x: &[u16], tweak: Option<&[u8]>) -> Result<Vec<u16>, Error> {
154 self.run(x, tweak, Operand::Ciphertext)
155 }
156
157 pub fn encrypt(&self, s: &str, tweak: Option<&[u8]>) -> Result<String, Error> {
159 let alphabet = self
160 .alphabet
161 .as_ref()
162 .ok_or_else(|| validate::alphabet_required("encrypt_numerals"))?;
163 let numerals = validate::decode(s, &alphabet.index)?;
164 let out = self.encrypt_numerals(&numerals, tweak)?;
165 Ok(alphabet.encode(&out))
166 }
167
168 pub fn decrypt(&self, s: &str, tweak: Option<&[u8]>) -> Result<String, Error> {
170 let alphabet = self
171 .alphabet
172 .as_ref()
173 .ok_or_else(|| validate::alphabet_required("decrypt_numerals"))?;
174 let numerals = validate::decode(s, &alphabet.index)?;
175 let out = self.decrypt_numerals(&numerals, tweak)?;
176 Ok(alphabet.encode(&out))
177 }
178
179 pub fn min_length(&self) -> usize {
182 self.min_length
183 }
184
185 pub fn max_length(&self) -> u64 {
188 MAX_LEN
189 }
190
191 fn run(&self, x: &[u16], tweak: Option<&[u8]>, operand: Operand) -> Result<Vec<u16>, Error> {
194 let tweak = tweak.unwrap_or(&self.default_tweak);
195 validate::length(x.len(), self.min_length, self.radix, operand)?;
196 validate::tweak(tweak.len(), self.min_tweak_len, self.max_tweak_len)?;
197 validate::numerals(x, self.radix, operand)?;
198 let encrypt = operand == Operand::Plaintext;
199 Ok(engine::ff1(&self.key, self.radix, x, tweak, encrypt)
204 .expect("inputs were validated; the FF1 core cannot fail on them"))
205 }
206}
207
208impl Alphabet {
209 fn encode(&self, numerals: &[u16]) -> String {
210 numerals
211 .iter()
212 .map(|&v| self.chars[usize::from(v)])
213 .collect()
214 }
215}