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