dpp/util/
vec.rs

1use std::num::ParseIntError;
2
3use crate::InvalidVectorSizeError;
4
5fn byte_to_hex(byte: &u8) -> String {
6    format!("{:02x}", byte)
7}
8
9pub fn encode_hex<T: Clone + Into<Vec<u8>>>(bytes: &T) -> String {
10    let hex_vec: Vec<String> = bytes.clone().into().iter().map(byte_to_hex).collect();
11
12    hex_vec.join("")
13}
14
15pub fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
16    (0..s.len())
17        .step_by(2)
18        .map(|i| u8::from_str_radix(&s[i..i + 2], 16))
19        .collect()
20}
21
22#[derive(Debug)]
23pub enum DecodeError {
24    ParseIntError(ParseIntError),
25    InvalidVectorSizeError(InvalidVectorSizeError),
26}
27
28impl From<InvalidVectorSizeError> for DecodeError {
29    fn from(err: InvalidVectorSizeError) -> Self {
30        Self::InvalidVectorSizeError(err)
31    }
32}
33
34impl From<ParseIntError> for DecodeError {
35    fn from(err: ParseIntError) -> Self {
36        Self::ParseIntError(err)
37    }
38}
39
40pub fn decode_hex_bls_sig(s: &str) -> Result<[u8; 96], DecodeError> {
41    hex_to_array::<96>(s)
42}
43
44pub fn decode_hex_sha256(s: &str) -> Result<[u8; 32], DecodeError> {
45    hex_to_array::<32>(s)
46}
47
48pub fn hex_to_array<const N: usize>(s: &str) -> Result<[u8; N], DecodeError> {
49    let vec = decode_hex(s)?;
50    Ok(vec_to_array::<N>(&vec)?)
51}
52
53pub fn vec_to_array<const N: usize>(vec: &[u8]) -> Result<[u8; N], InvalidVectorSizeError> {
54    let mut v: [u8; N] = [0; N];
55    // let mut v: T = T::default();
56    if v.len() != vec.len() {
57        return Err(InvalidVectorSizeError::new(v.len(), vec.len()));
58    }
59    for i in 0..vec.len() {
60        if let Some(n) = vec.get(i) {
61            v[i] = *n;
62        } else {
63            return Err(InvalidVectorSizeError::new(v.len(), vec.len()));
64        }
65    }
66    Ok(v)
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    // -- encode_hex --
74
75    #[test]
76    fn test_encode_hex_empty() {
77        let bytes: Vec<u8> = vec![];
78        assert_eq!(encode_hex(&bytes), "");
79    }
80
81    #[test]
82    fn test_encode_hex_single_byte() {
83        let bytes: Vec<u8> = vec![0xff];
84        assert_eq!(encode_hex(&bytes), "ff");
85    }
86
87    #[test]
88    fn test_encode_hex_multiple_bytes() {
89        let bytes: Vec<u8> = vec![0xde, 0xad, 0xbe, 0xef];
90        assert_eq!(encode_hex(&bytes), "deadbeef");
91    }
92
93    #[test]
94    fn test_encode_hex_leading_zeros() {
95        let bytes: Vec<u8> = vec![0x00, 0x01, 0x0a];
96        assert_eq!(encode_hex(&bytes), "00010a");
97    }
98
99    #[test]
100    fn test_encode_hex_all_zeros() {
101        let bytes: Vec<u8> = vec![0x00, 0x00, 0x00];
102        assert_eq!(encode_hex(&bytes), "000000");
103    }
104
105    // -- decode_hex --
106
107    #[test]
108    fn test_decode_hex_empty() {
109        let result = decode_hex("").unwrap();
110        assert!(result.is_empty());
111    }
112
113    #[test]
114    fn test_decode_hex_valid() {
115        let result = decode_hex("deadbeef").unwrap();
116        assert_eq!(result, vec![0xde, 0xad, 0xbe, 0xef]);
117    }
118
119    #[test]
120    fn test_decode_hex_uppercase() {
121        let result = decode_hex("DEADBEEF").unwrap();
122        assert_eq!(result, vec![0xde, 0xad, 0xbe, 0xef]);
123    }
124
125    #[test]
126    fn test_decode_hex_mixed_case() {
127        let result = decode_hex("DeAdBeEf").unwrap();
128        assert_eq!(result, vec![0xde, 0xad, 0xbe, 0xef]);
129    }
130
131    #[test]
132    fn test_decode_hex_leading_zeros() {
133        let result = decode_hex("00010a").unwrap();
134        assert_eq!(result, vec![0x00, 0x01, 0x0a]);
135    }
136
137    #[test]
138    fn test_decode_hex_invalid_chars() {
139        let result = decode_hex("zzzz");
140        assert!(result.is_err());
141    }
142
143    #[test]
144    #[should_panic]
145    fn test_decode_hex_odd_length_panics() {
146        // Known issue: odd-length hex strings panic instead of returning Err
147        // because s[i..i+2] goes out of bounds on the last byte.
148        let _ = decode_hex("abc");
149    }
150
151    // -- round-trip encode/decode --
152
153    #[test]
154    fn test_hex_round_trip() {
155        let original: Vec<u8> = vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
156        let hex = encode_hex(&original);
157        let decoded = decode_hex(&hex).unwrap();
158        assert_eq!(original, decoded);
159    }
160
161    #[test]
162    fn test_hex_round_trip_empty() {
163        let original: Vec<u8> = vec![];
164        let hex = encode_hex(&original);
165        let decoded = decode_hex(&hex).unwrap();
166        assert_eq!(original, decoded);
167    }
168
169    #[test]
170    fn test_hex_round_trip_all_byte_values() {
171        let original: Vec<u8> = (0..=255).collect();
172        let hex = encode_hex(&original);
173        let decoded = decode_hex(&hex).unwrap();
174        assert_eq!(original, decoded);
175    }
176
177    // -- hex_to_array --
178
179    #[test]
180    fn test_hex_to_array_valid_4_bytes() {
181        let result = hex_to_array::<4>("deadbeef").unwrap();
182        assert_eq!(result, [0xde, 0xad, 0xbe, 0xef]);
183    }
184
185    #[test]
186    fn test_hex_to_array_valid_32_bytes() {
187        let hex = "a".repeat(64); // 32 bytes encoded as 64 hex chars
188        let result = hex_to_array::<32>(&hex).unwrap();
189        assert_eq!(result.len(), 32);
190        assert!(result.iter().all(|&b| b == 0xaa));
191    }
192
193    #[test]
194    fn test_hex_to_array_wrong_size() {
195        // Provide 4 bytes of hex (8 chars) but expect a 2-byte array
196        let result = hex_to_array::<2>("deadbeef");
197        assert!(result.is_err());
198    }
199
200    #[test]
201    fn test_hex_to_array_invalid_hex() {
202        let result = hex_to_array::<2>("zzzz");
203        assert!(result.is_err());
204    }
205
206    // -- vec_to_array --
207
208    #[test]
209    fn test_vec_to_array_valid() {
210        let vec = vec![1u8, 2, 3, 4];
211        let result = vec_to_array::<4>(&vec).unwrap();
212        assert_eq!(result, [1, 2, 3, 4]);
213    }
214
215    #[test]
216    fn test_vec_to_array_too_short() {
217        let vec = vec![1u8, 2];
218        let result = vec_to_array::<4>(&vec);
219        assert!(result.is_err());
220        let err = result.unwrap_err();
221        assert_eq!(err.expected_size(), 4);
222        assert_eq!(err.actual_size(), 2);
223    }
224
225    #[test]
226    fn test_vec_to_array_too_long() {
227        let vec = vec![1u8, 2, 3, 4, 5];
228        let result = vec_to_array::<4>(&vec);
229        assert!(result.is_err());
230        let err = result.unwrap_err();
231        assert_eq!(err.expected_size(), 4);
232        assert_eq!(err.actual_size(), 5);
233    }
234
235    #[test]
236    fn test_vec_to_array_empty_to_zero() {
237        let vec: Vec<u8> = vec![];
238        let result = vec_to_array::<0>(&vec).unwrap();
239        assert_eq!(result, [0u8; 0]);
240    }
241
242    #[test]
243    fn test_vec_to_array_single_element() {
244        let vec = vec![0xffu8];
245        let result = vec_to_array::<1>(&vec).unwrap();
246        assert_eq!(result, [0xff]);
247    }
248
249    // -- decode_hex_sha256 / decode_hex_bls_sig --
250
251    #[test]
252    fn test_decode_hex_sha256_valid() {
253        let hex = "ab".repeat(32); // 32 bytes
254        let result = decode_hex_sha256(&hex).unwrap();
255        assert_eq!(result.len(), 32);
256        assert!(result.iter().all(|&b| b == 0xab));
257    }
258
259    #[test]
260    fn test_decode_hex_sha256_wrong_length() {
261        let hex = "ab".repeat(16); // 16 bytes, not 32
262        let result = decode_hex_sha256(&hex);
263        assert!(result.is_err());
264    }
265
266    #[test]
267    fn test_decode_hex_bls_sig_valid() {
268        let hex = "cd".repeat(96); // 96 bytes
269        let result = decode_hex_bls_sig(&hex).unwrap();
270        assert_eq!(result.len(), 96);
271        assert!(result.iter().all(|&b| b == 0xcd));
272    }
273
274    #[test]
275    fn test_decode_hex_bls_sig_wrong_length() {
276        let hex = "cd".repeat(48); // 48 bytes, not 96
277        let result = decode_hex_bls_sig(&hex);
278        assert!(result.is_err());
279    }
280}