1use std::iter;
6
7use binius_core::{Word, consts::WORD_SIZE_BITS};
8
9use crate::compiler::{CircuitBuilder, Wire, circuit::WitnessFiller};
10
11pub fn pack_bytes_into_wires_le(w: &mut WitnessFiller, wires: &[Wire], bytes: &[u8]) {
21 let max_value_size = wires.len() * 8;
22 assert!(
23 bytes.len() <= max_value_size,
24 "bytes length {} exceeds maximum {}",
25 bytes.len(),
26 max_value_size
27 );
28
29 for (&wire, chunk) in iter::zip(wires, bytes.chunks(8)) {
31 let mut chunk_arr = [0u8; 8];
32 chunk_arr[..chunk.len()].copy_from_slice(chunk);
33 w[wire] = Word(u64::from_le_bytes(chunk_arr));
34 }
35
36 for &wire in &wires[bytes.len().div_ceil(8)..] {
38 w[wire] = Word::ZERO;
39 }
40}
41
42pub fn pack_bytes_into_const_wires_le(b: &CircuitBuilder, bytes: &[u8]) -> Vec<Wire> {
54 bytes
55 .chunks(8)
56 .map(|chunk| {
57 let mut chunk_arr = [0u8; 8];
58 chunk_arr[..chunk.len()].copy_from_slice(chunk);
59 let word = Word(u64::from_le_bytes(chunk_arr));
60 b.add_constant(word)
61 })
62 .collect()
63}
64
65pub fn num_biguint_from_u64_limbs<I>(limbs: I) -> num_bigint::BigUint
67where
68 I: IntoIterator,
69 I::Item: std::borrow::Borrow<u64>,
70 I::IntoIter: ExactSizeIterator,
71{
72 use std::borrow::Borrow;
73
74 use num_bigint::BigUint;
75
76 let iter = limbs.into_iter();
77 let mut digits = Vec::with_capacity(iter.len() * 2);
79 for item in iter {
80 let double_digit = *item.borrow();
81 digits.push(double_digit as u32);
85 digits.push((double_digit >> 32) as u32);
86 }
87 BigUint::new(digits)
88}
89
90pub fn all_true(b: &CircuitBuilder, booleans: impl IntoIterator<Item = Wire>) -> Wire {
92 booleans
93 .into_iter()
94 .fold(b.add_constant(Word::ALL_ONE), |lhs, rhs| b.band(lhs, rhs))
95}
96
97pub fn bool_to_mask(b: &CircuitBuilder, boolean: Wire) -> Wire {
99 b.sar(boolean, (WORD_SIZE_BITS - 1) as u32)
100}
101
102pub fn byteswap(b: &CircuitBuilder, word: Wire) -> Wire {
106 let bytes = (0..8).map(|j| {
107 let byte = b.extract_byte(word, j as u32);
108 b.shl(byte, (56 - 8 * j) as u32)
109 });
110 bytes
111 .reduce(|lhs, rhs| b.bxor(lhs, rhs))
112 .expect("WORD_SIZE_BITS > 0")
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 fn test_pack_bytes(bytes: &[u8], expected_words: &[u64]) {
121 let b = CircuitBuilder::new();
122 let wires = pack_bytes_into_const_wires_le(&b, bytes);
123
124 assert_eq!(wires.len(), expected_words.len());
125
126 let circuit = b.build();
127 let mut filler = circuit.new_witness_filler();
128 circuit.populate_wire_witness(&mut filler).unwrap();
129
130 for (wire, &expected) in wires.iter().zip(expected_words) {
131 assert_eq!(filler[*wire], Word(expected));
132 }
133 }
134
135 #[test]
136 fn test_pack_bytes_into_const_wires_le_aligned() {
137 let bytes = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
139 test_pack_bytes(&bytes, &[0x0807060504030201]);
140 }
141
142 #[test]
143 fn test_pack_bytes_into_const_wires_le_partial() {
144 test_pack_bytes(b"Hello", &[0x6f6c6c6548]);
148 }
149
150 #[test]
151 fn test_pack_bytes_into_const_wires_le_multiple_words() {
152 let bytes: Vec<u8> = (0..16).collect();
154 test_pack_bytes(&bytes, &[0x0706050403020100, 0x0f0e0d0c0b0a0908]);
155 }
156
157 #[test]
158 fn test_pack_bytes_into_const_wires_le_empty() {
159 test_pack_bytes(&[], &[]);
161 }
162
163 #[test]
164 fn test_pack_bytes_into_const_wires_le_unaligned_multi() {
165 let bytes: Vec<u8> = (0..11).collect();
167 test_pack_bytes(&bytes, &[0x0706050403020100, 0x0a0908]);
168 }
169}