1use crate::{convert::*, fields::fp::FpVar};
2
3use super::*;
4
5impl<const N: usize, F: Field, T: PrimUInt> UInt<N, T, F> {
6 pub fn to_fp(&self) -> Result<FpVar<F>, SynthesisError>
14 where
15 F: PrimeField,
16 {
17 assert!(N < F::MODULUS_BIT_SIZE as usize);
18
19 Boolean::le_bits_to_fp(&self.bits)
20 }
21
22 pub fn from_fp(other: &FpVar<F>) -> Result<(Self, FpVar<F>), SynthesisError>
30 where
31 F: PrimeField,
32 {
33 let (bits, rest) = other.to_bits_le_with_top_bits_zero(N)?;
34 let result = Self::from_bits_le(&bits);
35 Ok((result, rest))
36 }
37
38 #[tracing::instrument(target = "gr1cs")]
65 pub fn from_bits_le(bits: &[Boolean<F>]) -> Self {
66 assert_eq!(bits.len(), N);
67 let bits = <&[Boolean<F>; N]>::try_from(bits).unwrap().clone();
68 let value_exists = bits.iter().all(|b| b.value().is_ok());
69 let mut value = T::zero();
70 for (i, b) in bits.iter().enumerate() {
71 if let Ok(b) = b.value() {
72 value = value + (T::from(b as u8).unwrap() << i);
73 }
74 }
75 let value = value_exists.then_some(value);
76 Self { bits, value }
77 }
78
79 pub fn from_bytes_be(bytes: &[UInt8<F>]) -> Result<Self, SynthesisError> {
101 let bits = bytes
102 .iter()
103 .rev()
104 .flat_map(|b| b.to_bits_le().unwrap())
105 .collect::<Vec<_>>();
106 Ok(Self::from_bits_le(&bits))
107 }
108
109 pub fn from_bytes_le(bytes: &[UInt8<F>]) -> Result<Self, SynthesisError> {
131 let bits = bytes
132 .iter()
133 .flat_map(|b| b.to_bits_le().unwrap())
134 .collect::<Vec<_>>();
135 Ok(Self::from_bits_le(&bits))
136 }
137
138 pub fn to_bytes_be(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
162 let mut bytes = self.to_bytes_le()?;
163 bytes.reverse();
164 Ok(bytes)
165 }
166}
167
168impl<const N: usize, T: PrimUInt, F: Field> ToBitsGadget<F> for UInt<N, T, F> {
169 fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
170 Ok(self.bits.to_vec())
171 }
172}
173
174impl<const N: usize, T: PrimUInt, F: Field> ToBitsGadget<F> for [UInt<N, T, F>] {
175 fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
178 let bits = self.iter().flat_map(|b| &b.bits).cloned().collect();
179 Ok(bits)
180 }
181}
182
183impl<const N: usize, T: PrimUInt, ConstraintF: Field> ToBytesGadget<ConstraintF>
191 for UInt<N, T, ConstraintF>
192{
193 #[tracing::instrument(target = "gr1cs", skip(self))]
194 fn to_bytes_le(&self) -> Result<Vec<UInt8<ConstraintF>>, SynthesisError> {
195 Ok(self
196 .to_bits_le()?
197 .chunks(8)
198 .map(UInt8::from_bits_le)
199 .collect())
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::{
207 prelude::EqGadget,
208 uint::test_utils::{run_unary_exhaustive, run_unary_random},
209 GR1CSVar,
210 };
211 use ark_ff::PrimeField;
212 use ark_test_curves::bls12_381::Fr;
213
214 fn uint_to_bytes_le<T: PrimUInt, const N: usize, F: PrimeField>(
215 a: UInt<N, T, F>,
216 ) -> Result<(), SynthesisError> {
217 let cs = a.cs();
218 let computed = a.to_bytes_le()?;
219 let expected = UInt8::constant_vec(a.value()?.to_le_bytes().as_ref());
220 assert_eq!(expected.len(), computed.len());
221 assert_eq!(expected.value(), computed.value());
222 expected.enforce_equal(&computed)?;
223 if !a.is_constant() {
224 assert!(cs.is_satisfied().unwrap());
225 }
226 Ok(())
227 }
228
229 fn uint_to_bytes_be<T: PrimUInt, const N: usize, F: PrimeField>(
230 a: UInt<N, T, F>,
231 ) -> Result<(), SynthesisError> {
232 let cs = a.cs();
233 let computed = a.to_bytes_be()?;
234 let expected = UInt8::constant_vec(a.value()?.to_be_bytes().as_ref());
235 assert_eq!(expected.len(), computed.len());
236 assert_eq!(expected.value(), computed.value());
237 expected.enforce_equal(&computed)?;
238 if !a.is_constant() {
239 assert!(cs.is_satisfied().unwrap());
240 }
241 Ok(())
242 }
243
244 fn uint_from_bytes_le<T: PrimUInt, const N: usize, F: PrimeField>(
245 expected: UInt<N, T, F>,
246 ) -> Result<(), SynthesisError> {
247 let cs = expected.cs();
248 let mode = if expected.is_constant() {
249 AllocationMode::Constant
250 } else {
251 AllocationMode::Witness
252 };
253 let computed = {
254 let value = expected.value()?.to_le_bytes();
255 let a = Vec::<UInt8<F>>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?;
256 UInt::from_bytes_le(&a)?
257 };
258 assert_eq!(expected.value(), computed.value());
259 expected.enforce_equal(&computed)?;
260 if !expected.is_constant() {
261 assert!(cs.is_satisfied().unwrap());
262 }
263 Ok(())
264 }
265
266 fn uint_from_bytes_be<T: PrimUInt, const N: usize, F: PrimeField>(
267 expected: UInt<N, T, F>,
268 ) -> Result<(), SynthesisError> {
269 let cs = expected.cs();
270 let mode = if expected.is_constant() {
271 AllocationMode::Constant
272 } else {
273 AllocationMode::Witness
274 };
275 let computed = {
276 let value = expected.value()?.to_be_bytes();
277 let a = Vec::<UInt8<F>>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?;
278 UInt::from_bytes_be(&a)?
279 };
280 assert_eq!(expected.value(), computed.value());
281 expected.enforce_equal(&computed)?;
282 if !expected.is_constant() {
283 assert!(cs.is_satisfied().unwrap());
284 }
285 Ok(())
286 }
287
288 #[test]
289 fn u8_to_bytes_le() {
290 run_unary_exhaustive(uint_to_bytes_le::<u8, 8, Fr>).unwrap()
291 }
292
293 #[test]
294 fn u16_to_bytes_le() {
295 run_unary_random::<1000, 16, _, _>(uint_to_bytes_le::<u16, 16, Fr>).unwrap()
296 }
297
298 #[test]
299 fn u32_to_bytes_le() {
300 run_unary_random::<1000, 32, _, _>(uint_to_bytes_le::<u32, 32, Fr>).unwrap()
301 }
302
303 #[test]
304 fn u64_to_bytes_le() {
305 run_unary_random::<1000, 64, _, _>(uint_to_bytes_le::<u64, 64, Fr>).unwrap()
306 }
307
308 #[test]
309 fn u128_to_bytes_le() {
310 run_unary_random::<1000, 128, _, _>(uint_to_bytes_le::<u128, 128, Fr>).unwrap()
311 }
312
313 #[test]
314 fn u8_to_bytes_be() {
315 run_unary_exhaustive(uint_to_bytes_be::<u8, 8, Fr>).unwrap()
316 }
317
318 #[test]
319 fn u16_to_bytes_be() {
320 run_unary_random::<1000, 16, _, _>(uint_to_bytes_be::<u16, 16, Fr>).unwrap()
321 }
322
323 #[test]
324 fn u32_to_bytes_be() {
325 run_unary_random::<1000, 32, _, _>(uint_to_bytes_be::<u32, 32, Fr>).unwrap()
326 }
327
328 #[test]
329 fn u64_to_bytes_be() {
330 run_unary_random::<1000, 64, _, _>(uint_to_bytes_be::<u64, 64, Fr>).unwrap()
331 }
332
333 #[test]
334 fn u128_to_bytes_be() {
335 run_unary_random::<1000, 128, _, _>(uint_to_bytes_be::<u128, 128, Fr>).unwrap()
336 }
337
338 #[test]
339 fn u8_from_bytes_le() {
340 run_unary_exhaustive(uint_from_bytes_le::<u8, 8, Fr>).unwrap()
341 }
342
343 #[test]
344 fn u16_from_bytes_le() {
345 run_unary_random::<1000, 16, _, _>(uint_from_bytes_le::<u16, 16, Fr>).unwrap()
346 }
347
348 #[test]
349 fn u32_from_bytes_le() {
350 run_unary_random::<1000, 32, _, _>(uint_from_bytes_le::<u32, 32, Fr>).unwrap()
351 }
352
353 #[test]
354 fn u64_from_bytes_le() {
355 run_unary_random::<1000, 64, _, _>(uint_from_bytes_le::<u64, 64, Fr>).unwrap()
356 }
357
358 #[test]
359 fn u128_from_bytes_le() {
360 run_unary_random::<1000, 128, _, _>(uint_from_bytes_le::<u128, 128, Fr>).unwrap()
361 }
362
363 #[test]
364 fn u8_from_bytes_be() {
365 run_unary_exhaustive(uint_from_bytes_be::<u8, 8, Fr>).unwrap()
366 }
367
368 #[test]
369 fn u16_from_bytes_be() {
370 run_unary_random::<1000, 16, _, _>(uint_from_bytes_be::<u16, 16, Fr>).unwrap()
371 }
372
373 #[test]
374 fn u32_from_bytes_be() {
375 run_unary_random::<1000, 32, _, _>(uint_from_bytes_be::<u32, 32, Fr>).unwrap()
376 }
377
378 #[test]
379 fn u64_from_bytes_be() {
380 run_unary_random::<1000, 64, _, _>(uint_from_bytes_be::<u64, 64, Fr>).unwrap()
381 }
382
383 #[test]
384 fn u128_from_bytes_be() {
385 run_unary_random::<1000, 128, _, _>(uint_from_bytes_be::<u128, 128, Fr>).unwrap()
386 }
387}