snarkvm_utilities/
bits.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use anyhow::{Result, ensure};
17
18/// Takes as input a sequence of objects, and converts them to a series of little-endian bits.
19/// All traits that implement `ToBits` can be automatically converted to bits in this manner.
20#[macro_export]
21macro_rules! to_bits_le {
22    ($($x:expr),*) => ({
23        let mut buffer = vec![];
24        $($x.write_bits_le(&mut buffer);)*
25        buffer
26    });
27    ($($x:expr),*; $size:expr) => ({
28        let mut buffer = Vec::with_capacity($size);
29        $($x.write_bits_le(&mut buffer);)*
30        buffer
31    });
32}
33
34/// Takes as input a sequence of objects, and converts them to a series of little-endian bits.
35/// All traits that implement `ToBitsRaw` can be automatically converted to bits in this manner.
36#[macro_export]
37macro_rules! to_bits_raw_le {
38    ($($x:expr),*) => ({
39        let mut buffer = vec![];
40        $($x.write_bits_raw_le(&mut buffer);)*
41        buffer
42    });
43    ($($x:expr),*; $size:expr) => ({
44        let mut buffer = Vec::with_capacity($size);
45        $($x.write_bits_raw_le(&mut buffer);)*
46        buffer
47    });
48}
49
50pub trait ToBits: Sized {
51    /// Writes `self` into the given vector as a boolean array in little-endian order.
52    fn write_bits_le(&self, vec: &mut Vec<bool>);
53
54    /// Writes `self` into the given vector as a boolean array in big-endian order.
55    fn write_bits_be(&self, vec: &mut Vec<bool>);
56
57    /// Returns `self` as a boolean array in little-endian order.
58    fn to_bits_le(&self) -> Vec<bool> {
59        let mut bits = Vec::new();
60        self.write_bits_le(&mut bits);
61        bits
62    }
63
64    /// Returns `self` as a boolean array in big-endian order.
65    fn to_bits_be(&self) -> Vec<bool> {
66        let mut bits = Vec::new();
67        self.write_bits_be(&mut bits);
68        bits
69    }
70
71    /// An optional indication of how many bits an object can be represented with.
72    fn num_bits() -> Option<usize> {
73        None
74    }
75}
76
77pub trait ToBitsRaw: ToBits + Sized {
78    /// Writes `self` into the given vector as a raw boolean array in little-endian order.
79    fn write_bits_raw_le(&self, vec: &mut Vec<bool>);
80
81    /// Writes `self` into the given vector as a boolean array in big-endian order.
82    fn write_bits_raw_be(&self, vec: &mut Vec<bool>);
83
84    /// Returns `self` as a boolean array in little-endian order.
85    fn to_bits_raw_le(&self) -> Vec<bool> {
86        let mut bits = Vec::new();
87        self.write_bits_raw_le(&mut bits);
88        bits
89    }
90
91    /// Returns `self` as a boolean array in big-endian order.
92    fn to_bits_raw_be(&self) -> Vec<bool> {
93        let mut bits = Vec::new();
94        self.write_bits_raw_be(&mut bits);
95        bits
96    }
97}
98
99pub trait FromBits: Sized {
100    /// Reads `Self` from a boolean array in little-endian order.
101    fn from_bits_le(bits: &[bool]) -> Result<Self>;
102
103    /// Reads `Self` from a boolean array in big-endian order.
104    fn from_bits_be(bits: &[bool]) -> Result<Self>;
105}
106
107/********************/
108/****** Tuples ******/
109/********************/
110
111/// A helper macro to implement `ToBits` for a tuple of `ToBits` circuits.
112macro_rules! to_bits_tuple {
113    (($t0:ident, $i0:tt), $(($ty:ident, $idx:tt)),+) => {
114        impl<$t0: ToBits, $($ty: ToBits),+> ToBits for ($t0, $($ty),+) {
115            /// A helper method to return a concatenated list of little-endian bits from the circuits.
116            #[inline]
117            fn write_bits_le(&self, vec: &mut Vec<bool>) {
118                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
119                (&self).write_bits_le(vec);
120            }
121
122            /// A helper method to return a concatenated list of big-endian bits from the circuits.
123            #[inline]
124            fn write_bits_be(&self, vec: &mut Vec<bool>) {
125                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
126                (&self).write_bits_be(vec);
127            }
128        }
129
130        impl<'a, $t0: ToBits, $($ty: ToBits),+> ToBits for &'a ($t0, $($ty),+) {
131            /// A helper method to return a concatenated list of little-endian bits from the circuits.
132            #[inline]
133            fn write_bits_le(&self, vec: &mut Vec<bool>) {
134                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
135                self.$i0.write_bits_le(vec);
136                $(self.$idx.write_bits_le(vec);)+
137            }
138
139            /// A helper method to return a concatenated list of big-endian bits from the circuits.
140            #[inline]
141            fn write_bits_be(&self, vec: &mut Vec<bool>) {
142                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
143                self.$i0.write_bits_be(vec);
144                $(self.$idx.write_bits_be(vec);)+
145            }
146        }
147
148        impl<$t0: ToBitsRaw, $($ty: ToBitsRaw),+> ToBitsRaw for ($t0, $($ty),+) {
149            /// A helper method to return a concatenated list of little-endian bits without variant or identifier bits from the circuits.
150            #[inline]
151            fn write_bits_raw_le(&self, vec: &mut Vec<bool>) {
152                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
153                (&self).write_bits_raw_le(vec);
154            }
155
156            /// A helper method to return a concatenated list of bits-endian bits without variant or identifier bits from the circuits.
157            #[inline]
158            fn write_bits_raw_be(&self, vec: &mut Vec<bool>) {
159                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
160                (&self).write_bits_raw_be(vec);
161            }
162        }
163
164        impl<'a, $t0: ToBitsRaw, $($ty: ToBitsRaw),+> ToBitsRaw for &'a ($t0, $($ty),+) {
165            /// A helper method to return a concatenated list of little-endian bits without variant or identifier bits from the circuits.
166            #[inline]
167            fn write_bits_raw_le(&self, vec: &mut Vec<bool>) {
168                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
169                self.$i0.write_bits_raw_le(vec);
170                $(self.$idx.write_bits_raw_le(vec);)+
171            }
172
173            /// A helper method to return a concatenated list of bits-endian bits without variant or identifier bits from the circuits.
174            #[inline]
175            fn write_bits_raw_be(&self, vec: &mut Vec<bool>) {
176                // The tuple is order-preserving, meaning the first circuit in is the first circuit bits out.
177                self.$i0.write_bits_raw_be(vec);
178                $(self.$idx.write_bits_raw_be(vec);)+
179            }
180        }
181    }
182}
183
184to_bits_tuple!((C0, 0), (C1, 1));
185to_bits_tuple!((C0, 0), (C1, 1), (C2, 2));
186to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3));
187to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4));
188to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5));
189to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6));
190to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7));
191to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8));
192to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8), (C9, 9));
193to_bits_tuple!((C0, 0), (C1, 1), (C2, 2), (C3, 3), (C4, 4), (C5, 5), (C6, 6), (C7, 7), (C8, 8), (C9, 9), (C10, 10));
194
195/********************/
196/****** Boolean *****/
197/********************/
198
199impl ToBits for bool {
200    /// A helper method to return a concatenated list of little-endian bits.
201    #[inline]
202    fn write_bits_le(&self, vec: &mut Vec<bool>) {
203        vec.push(*self);
204    }
205
206    /// A helper method to return a concatenated list of big-endian bits.
207    #[inline]
208    fn write_bits_be(&self, vec: &mut Vec<bool>) {
209        vec.push(*self);
210    }
211}
212
213/********************/
214/***** Integers *****/
215/********************/
216
217macro_rules! impl_bits_for_integer {
218    ($int:ty) => {
219        impl ToBits for $int {
220            /// Returns `self` as a boolean array in little-endian order.
221            #[inline]
222            fn write_bits_le(&self, vec: &mut Vec<bool>) {
223                let mut value = *self;
224                for _ in 0..<$int>::BITS {
225                    vec.push(value & 1 == 1);
226                    value = value.wrapping_shr(1u32);
227                }
228            }
229
230            /// Returns `self` as a boolean array in big-endian order.
231            #[inline]
232            fn write_bits_be(&self, vec: &mut Vec<bool>) {
233                let reversed = self.reverse_bits();
234                reversed.write_bits_le(vec);
235            }
236
237            fn num_bits() -> Option<usize> {
238                Some(<$int>::BITS as usize)
239            }
240        }
241
242        impl FromBits for $int {
243            /// Reads `Self` from a boolean array in little-endian order.
244            #[inline]
245            fn from_bits_le(bits: &[bool]) -> Result<Self> {
246                // If the number of bits exceeds the size of the integer, ensure that the upper bits are all zero.
247                // Note that because the input bits are little-endian, these are the bits at the end of slice.
248                for bit in bits.iter().skip(<$int>::BITS as usize) {
249                    ensure!(!bit, "upper bits are not zero");
250                }
251                // Construct the integer from the bits.
252                Ok(bits.iter().take(<$int>::BITS as usize).rev().fold(0, |value, bit| match bit {
253                    true => (value.wrapping_shl(1)) ^ 1,
254                    false => (value.wrapping_shl(1)) ^ 0,
255                }))
256            }
257
258            /// Reads `Self` from a boolean array in big-endian order.
259            #[inline]
260            fn from_bits_be(bits: &[bool]) -> Result<Self> {
261                // If the number of bits exceeds the size of the integer, ensure that the upper bits are all zero.
262                // Note that because the input bits are big-endian, these are the bits at the beginning of slice.
263                for bit in bits.iter().take(bits.len().saturating_sub(<$int>::BITS as usize)) {
264                    ensure!(!bit, "upper bits are not zero");
265                }
266                // Construct the integer from the bits.
267                Ok(bits.iter().skip(bits.len().saturating_sub(<$int>::BITS as usize)).fold(0, |value, bit| match bit {
268                    true => (value.wrapping_shl(1)) ^ 1,
269                    false => (value.wrapping_shl(1)) ^ 0,
270                }))
271            }
272        }
273    };
274}
275
276impl_bits_for_integer!(u8);
277impl_bits_for_integer!(u16);
278impl_bits_for_integer!(u32);
279impl_bits_for_integer!(u64);
280impl_bits_for_integer!(u128);
281
282impl_bits_for_integer!(i8);
283impl_bits_for_integer!(i16);
284impl_bits_for_integer!(i32);
285impl_bits_for_integer!(i64);
286impl_bits_for_integer!(i128);
287
288/********************/
289/****** String ******/
290/********************/
291
292impl ToBits for String {
293    /// A helper method to return a concatenated list of little-endian bits.
294    #[inline]
295    fn write_bits_le(&self, vec: &mut Vec<bool>) {
296        // The vector is order-preserving, meaning the first byte in is the first byte bits out.
297        self.as_bytes().write_bits_le(vec);
298    }
299
300    /// A helper method to return a concatenated list of big-endian bits.
301    #[inline]
302    fn write_bits_be(&self, vec: &mut Vec<bool>) {
303        // The vector is order-preserving, meaning the first byte in is the first byte bits out.
304        self.as_bytes().write_bits_be(vec);
305    }
306}
307
308/********************/
309/****** Arrays ******/
310/********************/
311
312impl<C: ToBits> ToBits for Vec<C> {
313    /// A helper method to return a concatenated list of little-endian bits.
314    #[inline]
315    fn write_bits_le(&self, vec: &mut Vec<bool>) {
316        // The vector is order-preserving, meaning the first variable in is the first variable bits out.
317        self.as_slice().write_bits_le(vec);
318    }
319
320    /// A helper method to return a concatenated list of big-endian bits.
321    #[inline]
322    fn write_bits_be(&self, vec: &mut Vec<bool>) {
323        // The vector is order-preserving, meaning the first variable in is the first variable bits out.
324        self.as_slice().write_bits_be(vec);
325    }
326}
327
328impl<C: ToBits, const N: usize> ToBits for [C; N] {
329    /// A helper method to return a concatenated list of little-endian bits.
330    #[inline]
331    fn write_bits_le(&self, vec: &mut Vec<bool>) {
332        // The slice is order-preserving, meaning the first variable in is the first variable bits out.
333        self.as_slice().write_bits_le(vec)
334    }
335
336    /// A helper method to return a concatenated list of big-endian bits.
337    #[inline]
338    fn write_bits_be(&self, vec: &mut Vec<bool>) {
339        // The slice is order-preserving, meaning the first variable in is the first variable bits out.
340        self.as_slice().write_bits_be(vec)
341    }
342}
343
344impl<C: ToBits> ToBits for &[C] {
345    /// A helper method to return a concatenated list of little-endian bits.
346    #[inline]
347    fn write_bits_le(&self, vec: &mut Vec<bool>) {
348        if let Some(num_bits) = C::num_bits() {
349            vec.reserve(num_bits * self.len());
350        }
351
352        for elem in self.iter() {
353            elem.write_bits_le(vec);
354        }
355    }
356
357    /// A helper method to return a concatenated list of big-endian bits.
358    #[inline]
359    fn write_bits_be(&self, vec: &mut Vec<bool>) {
360        if let Some(num_bits) = C::num_bits() {
361            vec.reserve(num_bits * self.len());
362        }
363
364        for elem in self.iter() {
365            elem.write_bits_be(vec);
366        }
367    }
368}
369
370impl<C: ToBitsRaw> ToBitsRaw for Vec<C> {
371    /// A helper method to return a concatenated list of little-endian bits.
372    #[inline]
373    fn write_bits_raw_le(&self, vec: &mut Vec<bool>) {
374        // The vector is order-preserving, meaning the first variable in is the first variable bits out.
375        self.as_slice().write_bits_raw_le(vec);
376    }
377
378    /// A helper method to return a concatenated list of big-endian bits.
379    #[inline]
380    fn write_bits_raw_be(&self, vec: &mut Vec<bool>) {
381        // The vector is order-preserving, meaning the first variable in is the first variable bits out.
382        self.as_slice().write_bits_raw_be(vec);
383    }
384}
385
386impl<C: ToBitsRaw, const N: usize> ToBitsRaw for [C; N] {
387    /// A helper method to return a concatenated list of little-endian bits.
388    #[inline]
389    fn write_bits_raw_le(&self, vec: &mut Vec<bool>) {
390        // The slice is order-preserving, meaning the first variable in is the first variable bits out.
391        self.as_slice().write_bits_raw_le(vec)
392    }
393
394    /// A helper method to return a concatenated list of big-endian bits.
395    #[inline]
396    fn write_bits_raw_be(&self, vec: &mut Vec<bool>) {
397        // The slice is order-preserving, meaning the first variable in is the first variable bits out.
398        self.as_slice().write_bits_raw_be(vec)
399    }
400}
401
402impl<C: ToBitsRaw> ToBitsRaw for &[C] {
403    /// A helper method to return a concatenated list of little-endian bits.
404    #[inline]
405    fn write_bits_raw_le(&self, vec: &mut Vec<bool>) {
406        if let Some(num_bits) = C::num_bits() {
407            vec.reserve(num_bits * self.len());
408        }
409
410        for elem in self.iter() {
411            elem.write_bits_raw_le(vec);
412        }
413    }
414
415    /// A helper method to return a concatenated list of big-endian bits.
416    #[inline]
417    fn write_bits_raw_be(&self, vec: &mut Vec<bool>) {
418        if let Some(num_bits) = C::num_bits() {
419            vec.reserve(num_bits * self.len());
420        }
421
422        for elem in self.iter() {
423            elem.write_bits_raw_be(vec);
424        }
425    }
426}
427
428impl FromBits for Vec<u8> {
429    /// A helper method to return `Self` from a concatenated list of little-endian bits.
430    #[inline]
431    fn from_bits_le(bits: &[bool]) -> Result<Self> {
432        // The vector is order-preserving, meaning the first variable in is the first variable bits out.
433        bits.chunks(8).map(u8::from_bits_le).collect::<Result<Vec<_>>>()
434    }
435
436    /// A helper method to return `Self` from a concatenated list of big-endian bits.
437    #[inline]
438    fn from_bits_be(bits: &[bool]) -> Result<Self> {
439        // The vector is order-preserving, meaning the first variable in is the first variable bits out.
440        bits.chunks(8).map(u8::from_bits_be).collect::<Result<Vec<_>>>()
441    }
442}
443
444#[cfg(test)]
445mod tests {
446    use super::*;
447    use crate::{TestRng, Uniform};
448
449    use anyhow::Result;
450    use rand::{Rng, distributions::Alphanumeric};
451
452    const ITERATIONS: u64 = 10000;
453
454    fn random_string(len: u16, rng: &mut TestRng) -> String {
455        rng.sample_iter(&Alphanumeric).take(len as usize).map(char::from).collect()
456    }
457
458    #[test]
459    fn test_to_bits_le_macro() {
460        let rng = &mut TestRng::default();
461
462        // The checker.
463        macro_rules! check {
464            ($given:expr) => {{
465                let given = $given;
466
467                let mut expected = Vec::new();
468                given.iter().for_each(|elem| elem.write_bits_le(&mut expected));
469
470                let candidate = to_bits_le!(given);
471                assert_eq!(candidate, expected);
472            }};
473        }
474
475        // U8
476        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<u8>>());
477        // U16
478        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<u16>>());
479        // U32
480        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<u32>>());
481        // U64
482        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<u64>>());
483        // U128
484        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<u128>>());
485        // I8
486        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<i8>>());
487        // I16
488        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<i16>>());
489        // I32
490        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<i32>>());
491        // I64
492        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<i64>>());
493        // I128
494        check!((0..100).map(|_| Uniform::rand(rng)).collect::<Vec<i128>>());
495        // String
496        check!((0..100).map(|_| random_string(rng.r#gen(), rng)).collect::<Vec<String>>());
497        // Vec<Vec<u8>>
498        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<u8>>()).collect::<Vec<_>>());
499        // Vec<Vec<u16>>
500        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<u16>>()).collect::<Vec<_>>());
501        // Vec<Vec<u32>>
502        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<u32>>()).collect::<Vec<_>>());
503        // Vec<Vec<u64>>
504        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<u64>>()).collect::<Vec<_>>());
505        // Vec<Vec<u128>>
506        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<u128>>()).collect::<Vec<_>>());
507        // Vec<Vec<i8>>
508        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<i8>>()).collect::<Vec<_>>());
509        // Vec<Vec<i16>>
510        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<i16>>()).collect::<Vec<_>>());
511        // Vec<Vec<i32>>
512        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<i32>>()).collect::<Vec<_>>());
513        // Vec<Vec<i64>>
514        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<i64>>()).collect::<Vec<_>>());
515        // Vec<Vec<i128>>
516        check!((0..100).map(|_| (0..128).map(|_| Uniform::rand(rng)).collect::<Vec<i128>>()).collect::<Vec<_>>());
517        // Vec<Vec<String>>
518        check!(
519            (0..100)
520                .map(|_| (0..128).map(|_| random_string(rng.r#gen(), rng)).collect::<Vec<String>>())
521                .collect::<Vec<_>>()
522        );
523    }
524
525    #[test]
526    fn test_to_bits_le_macro_with_capacity() {
527        let mut expected = Vec::new();
528        1u8.write_bits_le(&mut expected);
529        2u16.write_bits_le(&mut expected);
530        3u32.write_bits_le(&mut expected);
531        4u64.write_bits_le(&mut expected);
532        5u128.write_bits_le(&mut expected);
533        6i8.write_bits_le(&mut expected);
534        7i16.write_bits_le(&mut expected);
535        8i32.write_bits_le(&mut expected);
536        9i64.write_bits_le(&mut expected);
537        10i128.write_bits_le(&mut expected);
538
539        let capacity = expected.len();
540
541        let candidate = to_bits_le![1u8, 2u16, 3u32, 4u64, 5u128, 6i8, 7i16, 8i32, 9i64, 10i128; capacity];
542        assert_eq!(candidate, expected);
543    }
544
545    #[test]
546    fn test_integers() -> Result<()> {
547        macro_rules! check_integer {
548            ($integer:tt, $rng:expr) => {{
549                for _ in 0..ITERATIONS {
550                    let expected: $integer = Uniform::rand($rng);
551
552                    let bits_le = expected.to_bits_le();
553                    assert_eq!(expected, $integer::from_bits_le(&bits_le)?);
554
555                    let bits_be = expected.to_bits_be();
556                    assert_eq!(expected, $integer::from_bits_be(&bits_be)?);
557                }
558            }};
559        }
560
561        let mut rng = TestRng::default();
562
563        check_integer!(u8, &mut rng);
564        check_integer!(u16, &mut rng);
565        check_integer!(u32, &mut rng);
566        check_integer!(u64, &mut rng);
567        check_integer!(u128, &mut rng);
568
569        check_integer!(i8, &mut rng);
570        check_integer!(i16, &mut rng);
571        check_integer!(i32, &mut rng);
572        check_integer!(i64, &mut rng);
573        check_integer!(i128, &mut rng);
574
575        Ok(())
576    }
577}