commonware_utils/
lib.rs

1//! Leverage common functionality across multiple primitives.
2
3use bytes::{BufMut, BytesMut};
4use commonware_codec::{EncodeSize, Write};
5
6pub mod array;
7pub use array::Array;
8mod bitvec;
9pub use bitvec::{BitIterator, BitVec};
10mod time;
11pub use time::SystemTimeExt;
12mod priority_set;
13pub use priority_set::PrioritySet;
14pub mod futures;
15mod stable_buf;
16pub use stable_buf::StableBuf;
17mod stable_buf_mut;
18pub use stable_buf_mut::StableBufMut;
19
20/// Converts bytes to a hexadecimal string.
21pub fn hex(bytes: &[u8]) -> String {
22    let mut hex = String::new();
23    for byte in bytes.iter() {
24        hex.push_str(&format!("{:02x}", byte));
25    }
26    hex
27}
28
29/// Converts a hexadecimal string to bytes.
30pub fn from_hex(hex: &str) -> Option<Vec<u8>> {
31    if hex.len() % 2 != 0 {
32        return None;
33    }
34
35    (0..hex.len())
36        .step_by(2)
37        .map(|i| u8::from_str_radix(&hex[i..i + 2], 16).ok())
38        .collect()
39}
40
41/// Converts a hexadecimal string to bytes, stripping whitespace and/or a `0x` prefix. Commonly used
42/// in testing to encode external test vectors without modification.
43pub fn from_hex_formatted(hex: &str) -> Option<Vec<u8>> {
44    let hex = hex.replace(['\t', '\n', '\r', ' '], "");
45    let res = hex.strip_prefix("0x").unwrap_or(&hex);
46    from_hex(res)
47}
48
49/// Compute the maximum number of `f` (faults) that can be tolerated for a given set of `n`
50/// participants. This is the maximum integer `f` such that `n >= 3*f + 1`. `f` may be zero.
51pub fn max_faults(n: u32) -> u32 {
52    n.saturating_sub(1) / 3
53}
54
55/// Compute the quorum size for a given set of `n` participants. This is the minimum integer `q`
56/// such that `3*q >= 2*n + 1`. It is also equal to `n - f`, where `f` is the maximum number of
57/// faults.
58///
59/// # Panics
60///
61/// Panics if `n` is zero.
62pub fn quorum(n: u32) -> u32 {
63    assert!(n > 0, "n must not be zero");
64    n - max_faults(n)
65}
66
67/// Computes the union of two byte slices.
68pub fn union(a: &[u8], b: &[u8]) -> Vec<u8> {
69    let mut union = Vec::with_capacity(a.len() + b.len());
70    union.extend_from_slice(a);
71    union.extend_from_slice(b);
72    union
73}
74
75/// Concatenate a namespace and a message, prepended by a varint encoding of the namespace length.
76///
77/// This produces a unique byte sequence (i.e. no collisions) for each `(namespace, msg)` pair.
78pub fn union_unique(namespace: &[u8], msg: &[u8]) -> Vec<u8> {
79    let len_prefix = namespace.len();
80    let mut buf = BytesMut::with_capacity(len_prefix.encode_size() + namespace.len() + msg.len());
81    len_prefix.write(&mut buf);
82    BufMut::put_slice(&mut buf, namespace);
83    BufMut::put_slice(&mut buf, msg);
84    buf.into()
85}
86
87/// Compute the modulo of bytes interpreted as a big-endian integer.
88///
89/// This function is used to select a random entry from an array
90/// when the bytes are a random seed.
91pub fn modulo(bytes: &[u8], n: u64) -> u64 {
92    let mut result = 0;
93    for &byte in bytes {
94        result = (result << 8) | (byte as u64);
95        result %= n;
96    }
97    result
98}
99
100/// A macro to create a `NonZeroUsize` from a value, panicking if the value is zero.
101#[macro_export]
102macro_rules! NZUsize {
103    ($val:expr) => {
104        // This will panic at runtime if $val is zero.
105        // For literals, the compiler *might* optimize, but the check is still conceptually there.
106        std::num::NonZeroUsize::new($val).expect("value must be non-zero")
107    };
108}
109
110/// A macro to create a `NonZeroU32` from a value, panicking if the value is zero.
111#[macro_export]
112macro_rules! NZU32 {
113    ($val:expr) => {
114        // This will panic at runtime if $val is zero.
115        // For literals, the compiler *might* optimize, but the check is still conceptually there.
116        std::num::NonZeroU32::new($val).expect("value must be non-zero")
117    };
118}
119
120/// A macro to create a `NonZeroU64` from a value, panicking if the value is zero.
121#[macro_export]
122macro_rules! NZU64 {
123    ($val:expr) => {
124        // This will panic at runtime if $val is zero.
125        // For literals, the compiler *might* optimize, but the check is still conceptually there.
126        std::num::NonZeroU64::new($val).expect("value must be non-zero")
127    };
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133    use num_bigint::BigUint;
134    use rand::{rngs::StdRng, Rng, SeedableRng};
135
136    #[test]
137    fn test_hex() {
138        // Test case 0: empty bytes
139        let b = &[];
140        let h = hex(b);
141        assert_eq!(h, "");
142        assert_eq!(from_hex(&h).unwrap(), b.to_vec());
143
144        // Test case 1: single byte
145        let b = &[0x01];
146        let h = hex(b);
147        assert_eq!(h, "01");
148        assert_eq!(from_hex(&h).unwrap(), b.to_vec());
149
150        // Test case 2: multiple bytes
151        let b = &[0x01, 0x02, 0x03];
152        let h = hex(b);
153        assert_eq!(h, "010203");
154        assert_eq!(from_hex(&h).unwrap(), b.to_vec());
155
156        // Test case 3: odd number of bytes
157        let h = "0102030";
158        assert!(from_hex(h).is_none());
159
160        // Test case 4: invalid hexadecimal character
161        let h = "01g3";
162        assert!(from_hex(h).is_none());
163    }
164
165    #[test]
166    fn test_from_hex_formatted() {
167        // Test case 0: empty bytes
168        let b = &[];
169        let h = hex(b);
170        assert_eq!(h, "");
171        assert_eq!(from_hex_formatted(&h).unwrap(), b.to_vec());
172
173        // Test case 1: single byte
174        let b = &[0x01];
175        let h = hex(b);
176        assert_eq!(h, "01");
177        assert_eq!(from_hex_formatted(&h).unwrap(), b.to_vec());
178
179        // Test case 2: multiple bytes
180        let b = &[0x01, 0x02, 0x03];
181        let h = hex(b);
182        assert_eq!(h, "010203");
183        assert_eq!(from_hex_formatted(&h).unwrap(), b.to_vec());
184
185        // Test case 3: odd number of bytes
186        let h = "0102030";
187        assert!(from_hex_formatted(h).is_none());
188
189        // Test case 4: invalid hexadecimal character
190        let h = "01g3";
191        assert!(from_hex_formatted(h).is_none());
192
193        // Test case 5: whitespace
194        let h = "01 02 03";
195        assert_eq!(from_hex_formatted(h).unwrap(), b.to_vec());
196
197        // Test case 6: 0x prefix
198        let h = "0x010203";
199        assert_eq!(from_hex_formatted(h).unwrap(), b.to_vec());
200
201        // Test case 7: 0x prefix + different whitespace chars
202        let h = "    \n\n0x\r\n01
203                            02\t03\n";
204        assert_eq!(from_hex_formatted(h).unwrap(), b.to_vec());
205    }
206
207    #[test]
208    fn test_max_faults_zero() {
209        assert_eq!(max_faults(0), 0);
210    }
211
212    #[test]
213    #[should_panic]
214    fn test_quorum_zero() {
215        quorum(0);
216    }
217
218    #[test]
219    fn test_quorum_and_max_faults() {
220        // n, expected_f, expected_q
221        let test_cases = [
222            (1, 0, 1),
223            (2, 0, 2),
224            (3, 0, 3),
225            (4, 1, 3),
226            (5, 1, 4),
227            (6, 1, 5),
228            (7, 2, 5),
229            (8, 2, 6),
230            (9, 2, 7),
231            (10, 3, 7),
232            (11, 3, 8),
233            (12, 3, 9),
234            (13, 4, 9),
235            (14, 4, 10),
236            (15, 4, 11),
237            (16, 5, 11),
238            (17, 5, 12),
239            (18, 5, 13),
240            (19, 6, 13),
241            (20, 6, 14),
242            (21, 6, 15),
243        ];
244
245        for (n, ef, eq) in test_cases {
246            assert_eq!(max_faults(n), ef);
247            assert_eq!(quorum(n), eq);
248            assert_eq!(n, ef + eq);
249        }
250    }
251
252    #[test]
253    fn test_union() {
254        // Test case 0: empty slices
255        assert_eq!(union(&[], &[]), []);
256
257        // Test case 1: empty and non-empty slices
258        assert_eq!(union(&[], &[0x01, 0x02, 0x03]), [0x01, 0x02, 0x03]);
259
260        // Test case 2: non-empty and non-empty slices
261        assert_eq!(
262            union(&[0x01, 0x02, 0x03], &[0x04, 0x05, 0x06]),
263            [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]
264        );
265    }
266
267    #[test]
268    fn test_union_unique() {
269        let namespace = b"namespace";
270        let msg = b"message";
271
272        let length_encoding = vec![0b0000_1001];
273        let mut expected = Vec::with_capacity(length_encoding.len() + namespace.len() + msg.len());
274        expected.extend_from_slice(&length_encoding);
275        expected.extend_from_slice(namespace);
276        expected.extend_from_slice(msg);
277
278        let result = union_unique(namespace, msg);
279        assert_eq!(result, expected);
280        assert_eq!(result.len(), result.capacity());
281    }
282
283    #[test]
284    fn test_union_unique_zero_length() {
285        let namespace = b"";
286        let msg = b"message";
287
288        let length_encoding = vec![0];
289        let mut expected = Vec::with_capacity(length_encoding.len() + namespace.len() + msg.len());
290        expected.extend_from_slice(&length_encoding);
291        expected.extend_from_slice(msg);
292
293        let result = union_unique(namespace, msg);
294        assert_eq!(result, expected);
295        assert_eq!(result.len(), result.capacity());
296    }
297
298    #[test]
299    fn test_union_unique_long_length() {
300        // Use a namespace of over length 127.
301        let namespace = &b"n".repeat(256);
302        let msg = b"message";
303
304        let length_encoding = vec![0b1000_0000, 0b0000_0010];
305        let mut expected = Vec::with_capacity(length_encoding.len() + namespace.len() + msg.len());
306        expected.extend_from_slice(&length_encoding);
307        expected.extend_from_slice(namespace);
308        expected.extend_from_slice(msg);
309
310        let result = union_unique(namespace, msg);
311        assert_eq!(result, expected);
312        assert_eq!(result.len(), result.capacity());
313    }
314
315    #[test]
316    fn test_modulo() {
317        // Test case 0: empty bytes
318        assert_eq!(modulo(&[], 1), 0);
319
320        // Test case 1: single byte
321        assert_eq!(modulo(&[0x01], 1), 0);
322
323        // Test case 2: multiple bytes
324        assert_eq!(modulo(&[0x01, 0x02, 0x03], 10), 1);
325
326        // Test case 3: check equivalence with BigUint
327        let n = 11u64;
328        for i in 0..100 {
329            let mut rng = StdRng::seed_from_u64(i);
330            let bytes: [u8; 32] = rng.gen();
331            let big_modulo = BigUint::from_bytes_be(&bytes) % n;
332            let utils_modulo = modulo(&bytes, n);
333            assert_eq!(big_modulo, BigUint::from(utils_modulo));
334        }
335    }
336
337    #[test]
338    fn test_non_zero_macros() {
339        // Test case 0: zero value
340        assert!(std::panic::catch_unwind(|| NZUsize!(0)).is_err());
341        assert!(std::panic::catch_unwind(|| NZU32!(0)).is_err());
342        assert!(std::panic::catch_unwind(|| NZU64!(0)).is_err());
343
344        // Test case 1: non-zero value
345        assert_eq!(NZUsize!(1).get(), 1);
346        assert_eq!(NZU32!(2).get(), 2);
347        assert_eq!(NZU64!(3).get(), 3);
348    }
349}