fpr_ff1/error.rs
1//! The crate's error type (plan 00009 STEP-05).
2
3use core::fmt;
4
5/// What kind of input was rejected.
6///
7/// One variant per exception class in the `fpr-ff1` Python package, so code
8/// ported between the two maps each exception to exactly one kind:
9///
10/// | Kind | Python exception |
11/// |---|---|
12/// | [`KeyLength`](ErrorKind::KeyLength) | `KeyLengthError` |
13/// | [`Radix`](ErrorKind::Radix) | `RadixError` |
14/// | [`Length`](ErrorKind::Length) | `LengthError` |
15/// | [`ValueRange`](ErrorKind::ValueRange) | `ValueRangeError` |
16/// | [`TweakLength`](ErrorKind::TweakLength) | `TweakLengthError` |
17/// | [`Alphabet`](ErrorKind::Alphabet) | `AlphabetError` |
18/// | [`AlphabetRequired`](ErrorKind::AlphabetRequired) | `FF1Error` (the base class) |
19///
20/// Python's `BackendError` has no counterpart: backend selection is a
21/// Python-side concern.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23#[non_exhaustive]
24pub enum ErrorKind {
25 /// The key is not 16, 24 or 32 bytes.
26 KeyLength,
27 /// The radix is outside `2 <= radix < 2**16`.
28 Radix,
29 /// The input length is below the minimum domain for the radix, or above
30 /// `2**32 - 1`.
31 Length,
32 /// A numeral is not less than the radix, or a character is not in the
33 /// alphabet.
34 ValueRange,
35 /// A tweak or a tweak-length bound is outside the configured bounds or
36 /// above the four-byte encodable maximum.
37 TweakLength,
38 /// The alphabet's length does not equal the radix, or a character repeats.
39 Alphabet,
40 /// The string interface was used without an alphabet.
41 AlphabetRequired,
42}
43
44/// A rejected input.
45///
46/// The message matches the Python package's for the same rejection. It never
47/// contains key material, a numeral value or a character from the input:
48/// validation errors are routinely logged, and those are secrets or
49/// plaintext. It names the offending position or length instead.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct Error {
52 kind: ErrorKind,
53 message: String,
54}
55
56impl Error {
57 pub(crate) fn new(kind: ErrorKind, message: impl Into<String>) -> Self {
58 Self {
59 kind,
60 message: message.into(),
61 }
62 }
63
64 /// The kind of rejection.
65 pub fn kind(&self) -> ErrorKind {
66 self.kind
67 }
68}
69
70impl fmt::Display for Error {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.write_str(&self.message)
73 }
74}
75
76impl core::error::Error for Error {}