semaphore_rs_utils/
lib.rs

1use core::{
2    fmt::{Formatter, Result as FmtResult},
3    str,
4};
5use serde::{
6    de::{Error as DeError, Visitor},
7    Deserializer, Serializer,
8};
9use tiny_keccak::{Hasher as _, Keccak};
10
11pub fn keccak256(bytes: &[u8]) -> [u8; 32] {
12    let mut output = [0; 32];
13    let mut hasher = Keccak::v256();
14    hasher.update(bytes);
15    hasher.finalize(&mut output);
16    output
17}
18
19pub fn bytes_to_hex<const N: usize, const M: usize>(bytes: &[u8; N]) -> [u8; M] {
20    // TODO: Replace `M` with a const expression once it's stable.
21    debug_assert_eq!(M, 2 * N + 2);
22    let mut result = [0u8; M];
23    result[0] = b'0';
24    result[1] = b'x';
25    hex::encode_to_slice(&bytes[..], &mut result[2..]).expect("the buffer is correctly sized");
26    result
27}
28
29/// Helper to serialize byte arrays
30pub fn serialize_bytes<const N: usize, const M: usize, S: Serializer>(
31    serializer: S,
32    bytes: &[u8; N],
33) -> Result<S::Ok, S::Error> {
34    // TODO: Replace `M` with a const expression once it's stable.
35    debug_assert_eq!(M, 2 * N + 2);
36    if serializer.is_human_readable() {
37        // Write as a 0x prefixed lower-case hex string
38        let buffer = bytes_to_hex::<N, M>(bytes);
39        let string = str::from_utf8(&buffer).expect("the buffer is valid UTF-8");
40        serializer.serialize_str(string)
41    } else {
42        // Write as bytes directly
43        serializer.serialize_bytes(&bytes[..])
44    }
45}
46
47/// Helper to deserialize byte arrays from hex strings
48///
49/// TODO: How does it handle strings that are to short?
50pub fn bytes_from_hex<const N: usize>(s: &str) -> Result<[u8; N], hex::FromHexError> {
51    let str = trim_hex_prefix(s);
52    let mut result = [0_u8; N];
53    hex::decode_to_slice(str, &mut result)?;
54    Ok(result)
55}
56
57/// Helper function to remove  optionally `0x` prefix from hex strings.
58fn trim_hex_prefix(str: &str) -> &str {
59    str.trim_start_matches("0x").trim_start_matches("0X")
60}
61
62/// Helper to deserialize byte arrays.
63pub fn deserialize_bytes<'de, const N: usize, D: Deserializer<'de>>(
64    deserializer: D,
65) -> Result<[u8; N], D::Error> {
66    if deserializer.is_human_readable() {
67        struct StrVisitor<const N: usize>;
68        impl<const N: usize> Visitor<'_> for StrVisitor<N> {
69            type Value = [u8; N];
70
71            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
72                write!(formatter, "a {N} byte hex string")
73            }
74
75            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
76            where
77                E: DeError,
78            {
79                bytes_from_hex(value).map_err(|e| E::custom(format!("Error in hex: {e}")))
80            }
81        }
82        deserializer.deserialize_str(StrVisitor)
83    } else {
84        struct ByteVisitor<const N: usize>;
85        impl<const N: usize> Visitor<'_> for ByteVisitor<N> {
86            type Value = [u8; N];
87
88            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
89                write!(formatter, "{N} bytes of binary data")
90            }
91
92            fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
93            where
94                E: DeError,
95            {
96                if value.len() != N {
97                    return Err(E::invalid_length(value.len(), &self));
98                }
99                let mut result = [0_u8; N];
100                result.copy_from_slice(value);
101                Ok(result)
102            }
103        }
104        deserializer.deserialize_bytes(ByteVisitor)
105    }
106}
107
108#[cfg(test)]
109mod test {
110    use super::*;
111
112    #[test]
113    fn test_serialize_bytes_hex() {
114        let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
115        let mut ser = serde_json::Serializer::new(Vec::new());
116        serialize_bytes::<16, 34, _>(&mut ser, &bytes).unwrap();
117        let json = ser.into_inner();
118        assert_eq!(json, b"\"0x0102030405060708090a0b0c0d0e0f10\"");
119    }
120
121    #[test]
122    fn test_serialize_bytes_bin() {
123        let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
124        let mut bin: Vec<u8> = Vec::new();
125        {
126            let mut ser = bincode::Serializer::new(&mut bin, bincode::options());
127            serialize_bytes::<16, 34, _>(&mut ser, &bytes).unwrap();
128        }
129        // Bincode appears to prefix with a length.
130        assert_eq!(
131            bin,
132            [16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
133        );
134    }
135}