1use ark_ff::{Field, PrimeField, ToConstraintField};
2use ark_relations::gr1cs::{Namespace, SynthesisError};
3use ark_std::vec::Vec;
4
5use crate::{
6 convert::ToConstraintFieldGadget,
7 fields::fp::{AllocatedFp, FpVar},
8 prelude::*,
9};
10
11pub type UInt8<F> = super::uint::UInt<8, u8, F>;
14
15impl<F: Field> UInt8<F> {
16 pub fn new_input_vec(
42 cs: impl Into<Namespace<F>>,
43 values: &[u8],
44 ) -> Result<Vec<Self>, SynthesisError>
45 where
46 F: PrimeField,
47 {
48 let ns = cs.into();
49 let cs = ns.cs();
50 let values_len = values.len();
51 let field_elements: Vec<F> = ToConstraintField::<F>::to_field_elements(values).unwrap();
52
53 let max_size = 8 * ((F::MODULUS_BIT_SIZE - 1) / 8) as usize;
54 let mut allocated_bits = Vec::new();
55 for field_element in field_elements.into_iter() {
56 let fe = AllocatedFp::new_input(cs.clone(), || Ok(field_element))?;
57 let fe_bits = fe.to_bits_le()?;
58
59 allocated_bits.extend_from_slice(&fe_bits[0..max_size]);
65 }
66
67 Ok(allocated_bits[0..(8 * values_len)]
69 .chunks(8)
70 .map(Self::from_bits_le)
71 .collect())
72 }
73}
74
75impl<ConstraintF: PrimeField> ToConstraintFieldGadget<ConstraintF> for [UInt8<ConstraintF>] {
81 #[tracing::instrument(target = "gr1cs")]
82 fn to_constraint_field(&self) -> Result<Vec<FpVar<ConstraintF>>, SynthesisError> {
83 let max_size = ((ConstraintF::MODULUS_BIT_SIZE - 1) / 8) as usize;
84 self.chunks(max_size)
85 .map(|chunk| Boolean::le_bits_to_fp(chunk.to_bits_le()?.as_slice()))
86 .collect::<Result<Vec<_>, SynthesisError>>()
87 }
88}
89
90impl<ConstraintF: PrimeField> ToConstraintFieldGadget<ConstraintF> for Vec<UInt8<ConstraintF>> {
91 #[tracing::instrument(target = "gr1cs")]
92 fn to_constraint_field(&self) -> Result<Vec<FpVar<ConstraintF>>, SynthesisError> {
93 self.as_slice().to_constraint_field()
94 }
95}
96
97#[cfg(test)]
98mod test {
99 use crate::{
100 convert::ToConstraintFieldGadget,
101 fields::fp::FpVar,
102 prelude::{
103 AllocationMode::{Constant, Input, Witness},
104 *,
105 },
106 };
107 use ark_ff::{PrimeField, ToConstraintField};
108 use ark_relations::gr1cs::{ConstraintSystem, SynthesisError};
109 use ark_std::rand::{distributions::Uniform, Rng};
110 use ark_test_curves::bls12_381::Fr;
111
112 #[test]
113 fn test_uint8_from_bits_to_bits() -> Result<(), SynthesisError> {
114 let cs = ConstraintSystem::<Fr>::new_ref();
115 let byte_val = 0b01110001;
116 let byte =
117 UInt8::new_witness(ark_relations::ns!(cs, "alloc value"), || Ok(byte_val)).unwrap();
118 let bits = byte.to_bits_le()?;
119 for (i, bit) in bits.iter().enumerate() {
120 assert_eq!(bit.value()?, (byte_val >> i) & 1 == 1)
121 }
122 Ok(())
123 }
124
125 #[test]
126 fn test_uint8_new_input_vec() -> Result<(), SynthesisError> {
127 let cs = ConstraintSystem::<Fr>::new_ref();
128 let byte_vals = (64u8..128u8).collect::<Vec<_>>();
129 let bytes =
130 UInt8::new_input_vec(ark_relations::ns!(cs, "alloc value"), &byte_vals).unwrap();
131 for (native, variable) in byte_vals.into_iter().zip(bytes) {
132 let bits = variable.to_bits_le()?;
133 for (i, bit) in bits.iter().enumerate() {
134 assert_eq!(
135 bit.value()?,
136 (native >> i) & 1 == 1,
137 "native value {}: bit {:?}",
138 native,
139 i
140 )
141 }
142 }
143 Ok(())
144 }
145
146 #[test]
147 fn test_uint8_from_bits() -> Result<(), SynthesisError> {
148 let mut rng = ark_std::test_rng();
149
150 for _ in 0..1000 {
151 let v = (0..8)
152 .map(|_| Boolean::<Fr>::Constant(rng.gen()))
153 .collect::<Vec<_>>();
154
155 let val = UInt8::from_bits_le(&v);
156
157 let value = val.value()?;
158 for (i, bit) in val.bits.iter().enumerate() {
159 match bit {
160 Boolean::Constant(b) => assert_eq!(*b, ((value >> i) & 1 == 1)),
161 _ => unreachable!(),
162 }
163 }
164
165 let expected_to_be_same = val.to_bits_le()?;
166
167 for x in v.iter().zip(expected_to_be_same.iter()) {
168 match x {
169 (&Boolean::Constant(true), &Boolean::Constant(true)) => {},
170 (&Boolean::Constant(false), &Boolean::Constant(false)) => {},
171 _ => unreachable!(),
172 }
173 }
174 }
175 Ok(())
176 }
177
178 #[test]
179 fn test_uint8_xor() -> Result<(), SynthesisError> {
180 let mut rng = ark_std::test_rng();
181
182 for _ in 0..1000 {
183 let cs = ConstraintSystem::<Fr>::new_ref();
184
185 let a: u8 = rng.gen();
186 let b: u8 = rng.gen();
187 let c: u8 = rng.gen();
188
189 let mut expected = a ^ b ^ c;
190
191 let a_bit = UInt8::new_witness(ark_relations::ns!(cs, "a_bit"), || Ok(a)).unwrap();
192 let b_bit = UInt8::constant(b);
193 let c_bit = UInt8::new_witness(ark_relations::ns!(cs, "c_bit"), || Ok(c)).unwrap();
194
195 let mut r = a_bit ^ b_bit;
196 r ^= &c_bit;
197
198 assert!(cs.is_satisfied().unwrap());
199
200 assert_eq!(r.value, Some(expected));
201
202 for b in r.bits.iter() {
203 match b {
204 Boolean::Var(b) => assert!(b.value()? == (expected & 1 == 1)),
205 Boolean::Constant(b) => assert!(*b == (expected & 1 == 1)),
206 }
207
208 expected >>= 1;
209 }
210 }
211 Ok(())
212 }
213
214 #[test]
215 fn test_uint8_to_constraint_field() -> Result<(), SynthesisError> {
216 let mut rng = ark_std::test_rng();
217 let max_size = ((<Fr as PrimeField>::MODULUS_BIT_SIZE - 1) / 8) as usize;
218
219 let modes = [Input, Witness, Constant];
220 for mode in &modes {
221 for _ in 0..1000 {
222 let cs = ConstraintSystem::<Fr>::new_ref();
223
224 let bytes: Vec<u8> = (&mut rng)
225 .sample_iter(&Uniform::new_inclusive(0, u8::max_value()))
226 .take(max_size * 3 + 5)
227 .collect();
228
229 let bytes_var = bytes
230 .iter()
231 .map(|byte| UInt8::new_variable(cs.clone(), || Ok(*byte), *mode))
232 .collect::<Result<Vec<_>, SynthesisError>>()?;
233
234 let f_vec: Vec<Fr> = bytes.to_field_elements().unwrap();
235 let f_var_vec: Vec<FpVar<Fr>> = bytes_var.to_constraint_field()?;
236
237 assert!(cs.is_satisfied().unwrap());
238 assert_eq!(f_vec, f_var_vec.value()?);
239 }
240 }
241
242 Ok(())
243 }
244
245 #[test]
246 fn test_uint8_random_access() {
247 let mut rng = ark_std::test_rng();
248
249 for _ in 0..100 {
250 let cs = ConstraintSystem::<Fr>::new_ref();
251
252 let values: Vec<u8> = (0..128).map(|_| rng.gen()).collect();
254 let values_const: Vec<UInt8<Fr>> = values.iter().map(|x| UInt8::constant(*x)).collect();
255
256 let position: Vec<bool> = (0..7).map(|_| rng.gen()).collect();
258 let position_var: Vec<Boolean<Fr>> = position
259 .iter()
260 .map(|b| {
261 Boolean::new_witness(ark_relations::ns!(cs, "index_arr_element"), || Ok(*b))
262 .unwrap()
263 })
264 .collect();
265
266 let mut index = 0;
268 for x in position {
269 index *= 2;
270 index += if x { 1 } else { 0 };
271 }
272
273 assert_eq!(
274 UInt8::conditionally_select_power_of_two_vector(&position_var, &values_const)
275 .unwrap()
276 .value()
277 .unwrap(),
278 values[index]
279 )
280 }
281 }
282}