ark-r1cs-std/src/uint/convert.rs
src/uint/convert.rsRaw
1use crate::convert::*;
2use crate::fields::fp::FpVar;
3
4use super::*;
5
6impl<const N: usize, F: Field, T: PrimUInt> UInt<N, T, F> {
7 /// Converts `self` into a field element. The elements comprising `self` are
8 /// interpreted as a little-endian bit order representation of a field element.
9 ///
10 /// # Panics
11 /// Assumes that `N` is equal to at most the number of bits in `F::MODULUS_BIT_SIZE - 1`, and panics otherwise.
12 pub fn to_fp(&self) -> Result<FpVar<F>, SynthesisError>
13 where
14 F: PrimeField,
15 {
16 assert!(N <= F::MODULUS_BIT_SIZE as usize - 1);
17
18 Boolean::le_bits_to_fp(&self.bits)
19 }
20
21 /// Converts a field element into its little-endian bit order representation.
22 ///
23 /// # Panics
24 ///
25 /// Assumes that `N` is at most the number of bits in `F::MODULUS_BIT_SIZE - 1`, and panics otherwise.
26 pub fn from_fp(other: &FpVar<F>) -> Result<(Self, FpVar<F>), SynthesisError>
27 where
28 F: PrimeField,
29 {
30 let (bits, rest) = other.to_bits_le_with_top_bits_zero(N)?;
31 let result = Self::from_bits_le(&bits);
32 Ok((result, rest))
33 }
34
35 /// Converts a little-endian byte order representation of bits into a
36 /// `UInt`.
37 ///
38 /// ```
39 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
40 /// // We'll use the BLS12-381 scalar field for our constraints.
41 /// use ark_test_curves::bls12_381::Fr;
42 /// use ark_relations::r1cs::*;
43 /// use ark_r1cs_std::prelude::*;
44 ///
45 /// let cs = ConstraintSystem::<Fr>::new_ref();
46 /// let var = UInt8::new_witness(cs.clone(), || Ok(128))?;
47 ///
48 /// let f = Boolean::FALSE;
49 /// let t = Boolean::TRUE;
50 ///
51 /// // Construct [0, 0, 0, 0, 0, 0, 0, 1]
52 /// let mut bits = vec![f.clone(); 7];
53 /// bits.push(t);
54 ///
55 /// let mut c = UInt8::from_bits_le(&bits);
56 /// var.enforce_equal(&c)?;
57 /// assert!(cs.is_satisfied().unwrap());
58 /// # Ok(())
59 /// # }
60 /// ```
61 #[tracing::instrument(target = "r1cs")]
62 pub fn from_bits_le(bits: &[Boolean<F>]) -> Self {
63 assert_eq!(bits.len(), N);
64 let bits = <&[Boolean<F>; N]>::try_from(bits).unwrap().clone();
65 let value_exists = bits.iter().all(|b| b.value().is_ok());
66 let mut value = T::zero();
67 for (i, b) in bits.iter().enumerate() {
68 if let Ok(b) = b.value() {
69 value = value + (T::from(b as u8).unwrap() << i);
70 }
71 }
72 let value = value_exists.then_some(value);
73 Self { bits, value }
74 }
75
76 /// Converts a big-endian list of bytes into a `UInt`.
77 ///
78 /// ```
79 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
80 /// // We'll use the BLS12-381 scalar field for our constraints.
81 /// use ark_test_curves::bls12_381::Fr;
82 /// use ark_relations::r1cs::*;
83 /// use ark_r1cs_std::prelude::*;
84 ///
85 /// let cs = ConstraintSystem::<Fr>::new_ref();
86 /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?;
87 ///
88 /// // Construct u8::MAX * 2
89 /// let bytes = UInt8::constant_vec(&(2 * (u8::MAX as u16)).to_be_bytes());
90 ///
91 /// let c = UInt16::from_bytes_be(&bytes)?;
92 /// var.enforce_equal(&c)?;
93 /// assert!(cs.is_satisfied().unwrap());
94 /// # Ok(())
95 /// # }
96 /// ```
97 pub fn from_bytes_be(bytes: &[UInt8<F>]) -> Result<Self, SynthesisError> {
98 let bits = bytes
99 .iter()
100 .rev()
101 .flat_map(|b| b.to_bits_le().unwrap())
102 .collect::<Vec<_>>();
103 Ok(Self::from_bits_le(&bits))
104 }
105
106 /// Converts a little-endian byte order list of bytes into a `UInt`.
107 ///
108 /// ```
109 /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
110 /// // We'll use the BLS12-381 scalar field for our constraints.
111 /// use ark_test_curves::bls12_381::Fr;
112 /// use ark_relations::r1cs::*;
113 /// use ark_r1cs_std::prelude::*;
114 ///
115 /// let cs = ConstraintSystem::<Fr>::new_ref();
116 /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?;
117 ///
118 /// // Construct u8::MAX * 2
119 /// let bytes = UInt8::constant_vec(&(2 * (u8::MAX as u16)).to_le_bytes());
120 ///
121 /// let c = UInt16::from_bytes_le(&bytes)?;
122 /// var.enforce_equal(&c)?;
123 /// assert!(cs.is_satisfied().unwrap());
124 /// # Ok(())
125 /// # }
126 /// ```
127 pub fn from_bytes_le(bytes: &[UInt8<F>]) -> Result<Self, SynthesisError> {
128 let bits = bytes
129 .iter()
130 .flat_map(|b| b.to_bits_le().unwrap())
131 .collect::<Vec<_>>();
132 Ok(Self::from_bits_le(&bits))
133 }
134
135 pub fn to_bytes_be(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
136 let mut bytes = self.to_bytes_le()?;
137 bytes.reverse();
138 Ok(bytes)
139 }
140}
141
142impl<const N: usize, T: PrimUInt, F: Field> ToBitsGadget<F> for UInt<N, T, F> {
143 fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
144 Ok(self.bits.to_vec())
145 }
146}
147
148impl<const N: usize, T: PrimUInt, F: Field> ToBitsGadget<F> for [UInt<N, T, F>] {
149 /// Interprets `self` as an integer, and outputs the little-endian
150 /// bit-wise decomposition of that integer.
151 fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
152 let bits = self.iter().flat_map(|b| &b.bits).cloned().collect();
153 Ok(bits)
154 }
155}
156
157/*****************************************************************************************/
158/********************************* Conversions to bytes. *********************************/
159/*****************************************************************************************/
160
161impl<const N: usize, T: PrimUInt, ConstraintF: Field> ToBytesGadget<ConstraintF>
162 for UInt<N, T, ConstraintF>
163{
164 #[tracing::instrument(target = "r1cs", skip(self))]
165 fn to_bytes_le(&self) -> Result<Vec<UInt8<ConstraintF>>, SynthesisError> {
166 Ok(self
167 .to_bits_le()?
168 .chunks(8)
169 .map(UInt8::from_bits_le)
170 .collect())
171 }
172}
173
174impl<const N: usize, T: PrimUInt, F: Field> ToBytesGadget<F> for [UInt<N, T, F>] {
175 fn to_bytes_le(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
176 let mut bytes = Vec::with_capacity(self.len() * (N / 8));
177 for elem in self {
178 bytes.extend_from_slice(&elem.to_bytes_le()?);
179 }
180 Ok(bytes)
181 }
182}
183
184impl<const N: usize, T: PrimUInt, F: Field> ToBytesGadget<F> for Vec<UInt<N, T, F>> {
185 fn to_bytes_le(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
186 self.as_slice().to_bytes_le()
187 }
188}
189
190impl<'a, const N: usize, T: PrimUInt, F: Field> ToBytesGadget<F> for &'a [UInt<N, T, F>] {
191 fn to_bytes_le(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
192 (*self).to_bytes_le()
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199 use crate::{
200 prelude::EqGadget,
201 uint::test_utils::{run_unary_exhaustive, run_unary_random},
202 R1CSVar,
203 };
204 use ark_ff::PrimeField;
205 use ark_test_curves::bls12_381::Fr;
206
207 fn uint_to_bytes_le<T: PrimUInt, const N: usize, F: PrimeField>(
208 a: UInt<N, T, F>,
209 ) -> Result<(), SynthesisError> {
210 let cs = a.cs();
211 let computed = a.to_bytes_le()?;
212 let expected = UInt8::constant_vec(a.value()?.to_le_bytes().as_ref());
213 assert_eq!(expected.len(), computed.len());
214 assert_eq!(expected.value(), computed.value());
215 expected.enforce_equal(&computed)?;
216 if !a.is_constant() {
217 assert!(cs.is_satisfied().unwrap());
218 }
219 Ok(())
220 }
221
222 fn uint_to_bytes_be<T: PrimUInt, const N: usize, F: PrimeField>(
223 a: UInt<N, T, F>,
224 ) -> Result<(), SynthesisError> {
225 let cs = a.cs();
226 let computed = a.to_bytes_be()?;
227 let expected = UInt8::constant_vec(a.value()?.to_be_bytes().as_ref());
228 assert_eq!(expected.len(), computed.len());
229 assert_eq!(expected.value(), computed.value());
230 expected.enforce_equal(&computed)?;
231 if !a.is_constant() {
232 assert!(cs.is_satisfied().unwrap());
233 }
234 Ok(())
235 }
236
237 fn uint_from_bytes_le<T: PrimUInt, const N: usize, F: PrimeField>(
238 expected: UInt<N, T, F>,
239 ) -> Result<(), SynthesisError> {
240 let cs = expected.cs();
241 let mode = if expected.is_constant() {
242 AllocationMode::Constant
243 } else {
244 AllocationMode::Witness
245 };
246 let computed = {
247 let value = expected.value()?.to_le_bytes();
248 let a = Vec::<UInt8<F>>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?;
249 UInt::from_bytes_le(&a)?
250 };
251 assert_eq!(expected.value(), computed.value());
252 expected.enforce_equal(&computed)?;
253 if !expected.is_constant() {
254 assert!(cs.is_satisfied().unwrap());
255 }
256 Ok(())
257 }
258
259 fn uint_from_bytes_be<T: PrimUInt, const N: usize, F: PrimeField>(
260 expected: UInt<N, T, F>,
261 ) -> Result<(), SynthesisError> {
262 let cs = expected.cs();
263 let mode = if expected.is_constant() {
264 AllocationMode::Constant
265 } else {
266 AllocationMode::Witness
267 };
268 let computed = {
269 let value = expected.value()?.to_be_bytes();
270 let a = Vec::<UInt8<F>>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?;
271 UInt::from_bytes_be(&a)?
272 };
273 assert_eq!(expected.value(), computed.value());
274 expected.enforce_equal(&computed)?;
275 if !expected.is_constant() {
276 assert!(cs.is_satisfied().unwrap());
277 }
278 Ok(())
279 }
280
281 #[test]
282 fn u8_to_bytes_le() {
283 run_unary_exhaustive(uint_to_bytes_le::<u8, 8, Fr>).unwrap()
284 }
285
286 #[test]
287 fn u16_to_bytes_le() {
288 run_unary_random::<1000, 16, _, _>(uint_to_bytes_le::<u16, 16, Fr>).unwrap()
289 }
290
291 #[test]
292 fn u32_to_bytes_le() {
293 run_unary_random::<1000, 32, _, _>(uint_to_bytes_le::<u32, 32, Fr>).unwrap()
294 }
295
296 #[test]
297 fn u64_to_bytes_le() {
298 run_unary_random::<1000, 64, _, _>(uint_to_bytes_le::<u64, 64, Fr>).unwrap()
299 }
300
301 #[test]
302 fn u128_to_bytes_le() {
303 run_unary_random::<1000, 128, _, _>(uint_to_bytes_le::<u128, 128, Fr>).unwrap()
304 }
305
306 #[test]
307 fn u8_to_bytes_be() {
308 run_unary_exhaustive(uint_to_bytes_be::<u8, 8, Fr>).unwrap()
309 }
310
311 #[test]
312 fn u16_to_bytes_be() {
313 run_unary_random::<1000, 16, _, _>(uint_to_bytes_be::<u16, 16, Fr>).unwrap()
314 }
315
316 #[test]
317 fn u32_to_bytes_be() {
318 run_unary_random::<1000, 32, _, _>(uint_to_bytes_be::<u32, 32, Fr>).unwrap()
319 }
320
321 #[test]
322 fn u64_to_bytes_be() {
323 run_unary_random::<1000, 64, _, _>(uint_to_bytes_be::<u64, 64, Fr>).unwrap()
324 }
325
326 #[test]
327 fn u128_to_bytes_be() {
328 run_unary_random::<1000, 128, _, _>(uint_to_bytes_be::<u128, 128, Fr>).unwrap()
329 }
330
331 #[test]
332 fn u8_from_bytes_le() {
333 run_unary_exhaustive(uint_from_bytes_le::<u8, 8, Fr>).unwrap()
334 }
335
336 #[test]
337 fn u16_from_bytes_le() {
338 run_unary_random::<1000, 16, _, _>(uint_from_bytes_le::<u16, 16, Fr>).unwrap()
339 }
340
341 #[test]
342 fn u32_from_bytes_le() {
343 run_unary_random::<1000, 32, _, _>(uint_from_bytes_le::<u32, 32, Fr>).unwrap()
344 }
345
346 #[test]
347 fn u64_from_bytes_le() {
348 run_unary_random::<1000, 64, _, _>(uint_from_bytes_le::<u64, 64, Fr>).unwrap()
349 }
350
351 #[test]
352 fn u128_from_bytes_le() {
353 run_unary_random::<1000, 128, _, _>(uint_from_bytes_le::<u128, 128, Fr>).unwrap()
354 }
355
356 #[test]
357 fn u8_from_bytes_be() {
358 run_unary_exhaustive(uint_from_bytes_be::<u8, 8, Fr>).unwrap()
359 }
360
361 #[test]
362 fn u16_from_bytes_be() {
363 run_unary_random::<1000, 16, _, _>(uint_from_bytes_be::<u16, 16, Fr>).unwrap()
364 }
365
366 #[test]
367 fn u32_from_bytes_be() {
368 run_unary_random::<1000, 32, _, _>(uint_from_bytes_be::<u32, 32, Fr>).unwrap()
369 }
370
371 #[test]
372 fn u64_from_bytes_be() {
373 run_unary_random::<1000, 64, _, _>(uint_from_bytes_be::<u64, 64, Fr>).unwrap()
374 }
375
376 #[test]
377 fn u128_from_bytes_be() {
378 run_unary_random::<1000, 128, _, _>(uint_from_bytes_be::<u128, 128, Fr>).unwrap()
379 }
380}