ed25519/
hex.rs

1//! Hexadecimal encoding support
2// TODO(tarcieri): use `base16ct`?
3
4use crate::{ComponentBytes, Error, Signature};
5use core::{fmt, str};
6
7/// Format a signature component as hex.
8pub(crate) struct ComponentFormatter<'a>(pub(crate) &'a ComponentBytes);
9
10impl fmt::Debug for ComponentFormatter<'_> {
11    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12        write!(f, "0x")?;
13
14        for byte in self.0 {
15            write!(f, "{:02x}", byte)?;
16        }
17
18        Ok(())
19    }
20}
21
22impl fmt::LowerHex for Signature {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        for component in [&self.R, &self.s] {
25            for byte in component {
26                write!(f, "{:02x}", byte)?;
27            }
28        }
29        Ok(())
30    }
31}
32
33impl fmt::UpperHex for Signature {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        for component in [&self.R, &self.s] {
36            for byte in component {
37                write!(f, "{:02X}", byte)?;
38            }
39        }
40        Ok(())
41    }
42}
43
44/// Decode a signature from hexadecimal.
45///
46/// Upper and lower case hexadecimal are both accepted, however mixed case is
47/// rejected.
48// TODO(tarcieri): use `base16ct`?
49impl str::FromStr for Signature {
50    type Err = Error;
51
52    fn from_str(hex: &str) -> signature::Result<Self> {
53        if hex.as_bytes().len() != Signature::BYTE_SIZE * 2 {
54            return Err(Error::new());
55        }
56
57        let mut upper_case = None;
58
59        // Ensure all characters are valid and case is not mixed
60        for &byte in hex.as_bytes() {
61            match byte {
62                b'0'..=b'9' => (),
63                b'a'..=b'z' => match upper_case {
64                    Some(true) => return Err(Error::new()),
65                    Some(false) => (),
66                    None => upper_case = Some(false),
67                },
68                b'A'..=b'Z' => match upper_case {
69                    Some(true) => (),
70                    Some(false) => return Err(Error::new()),
71                    None => upper_case = Some(true),
72                },
73                _ => return Err(Error::new()),
74            }
75        }
76
77        let mut result = [0u8; Self::BYTE_SIZE];
78        for (digit, byte) in hex.as_bytes().chunks_exact(2).zip(result.iter_mut()) {
79            *byte = str::from_utf8(digit)
80                .ok()
81                .and_then(|s| u8::from_str_radix(s, 16).ok())
82                .ok_or_else(Error::new)?;
83        }
84
85        Self::try_from(&result[..])
86    }
87}