Skip to main content

ark_r1cs_std/uint/
convert.rs

1use crate::{convert::*, fields::fp::FpVar};
2
3use super::*;
4
5impl<const N: usize, F: Field, T: PrimUInt> UInt<N, T, F> {
6    /// Converts `self` into a field element. The elements comprising `self` are
7    /// interpreted as a little-endian bit order representation of a field
8    /// element.
9    ///
10    /// # Panics
11    /// Assumes that `N` is equal to at most the number of bits in
12    /// `F::MODULUS_BIT_SIZE - 1`, and panics otherwise.
13    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    /// Converts a field element into its little-endian bit order
23    /// representation.
24    ///
25    /// # Panics
26    ///
27    /// Assumes that `N` is at most the number of bits in `F::MODULUS_BIT_SIZE -
28    /// 1`, and panics otherwise.
29    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    /// Converts a little-endian byte order representation of bits into a
39    /// `UInt`.
40    ///
41    /// ```
42    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
43    /// // We'll use the BLS12-381 scalar field for our constraints.
44    /// use ark_test_curves::bls12_381::Fr;
45    /// use ark_relations::gr1cs::*;
46    /// use ark_r1cs_std::prelude::*;
47    ///
48    /// let cs = ConstraintSystem::<Fr>::new_ref();
49    /// let var = UInt8::new_witness(cs.clone(), || Ok(128))?;
50    ///
51    /// let f = Boolean::FALSE;
52    /// let t = Boolean::TRUE;
53    ///
54    /// // Construct [0, 0, 0, 0, 0, 0, 0, 1]
55    /// let mut bits = vec![f.clone(); 7];
56    /// bits.push(t);
57    ///
58    /// let mut c = UInt8::from_bits_le(&bits);
59    /// var.enforce_equal(&c)?;
60    /// assert!(cs.is_satisfied().unwrap());
61    /// # Ok(())
62    /// # }
63    /// ```
64    #[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    /// Converts a big-endian list of bytes into a `UInt`.
80    ///
81    /// ```
82    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
83    /// // We'll use the BLS12-381 scalar field for our constraints.
84    /// use ark_test_curves::bls12_381::Fr;
85    /// use ark_relations::gr1cs::*;
86    /// use ark_r1cs_std::prelude::*;
87    ///
88    /// let cs = ConstraintSystem::<Fr>::new_ref();
89    /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?;
90    ///
91    /// // Construct u8::MAX * 2
92    /// let bytes = UInt8::constant_vec(&(2 * (u8::MAX as u16)).to_be_bytes());
93    ///
94    /// let c = UInt16::from_bytes_be(&bytes)?;
95    /// var.enforce_equal(&c)?;
96    /// assert!(cs.is_satisfied().unwrap());
97    /// # Ok(())
98    /// # }
99    /// ```
100    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    /// Converts a little-endian byte order list of bytes into a `UInt`.
110    ///
111    /// ```
112    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
113    /// // We'll use the BLS12-381 scalar field for our constraints.
114    /// use ark_test_curves::bls12_381::Fr;
115    /// use ark_relations::gr1cs::*;
116    /// use ark_r1cs_std::prelude::*;
117    ///
118    /// let cs = ConstraintSystem::<Fr>::new_ref();
119    /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?;
120    ///
121    /// // Construct u8::MAX * 2
122    /// let bytes = UInt8::constant_vec(&(2 * (u8::MAX as u16)).to_le_bytes());
123    ///
124    /// let c = UInt16::from_bytes_le(&bytes)?;
125    /// var.enforce_equal(&c)?;
126    /// assert!(cs.is_satisfied().unwrap());
127    /// # Ok(())
128    /// # }
129    /// ```
130    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    /// Converts a `UInt` into a big-endian byte order list of bytes.
139    ///
140    /// ```
141    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
142    /// // We'll use the BLS12-381 scalar field for our constraints.
143    /// use ark_test_curves::bls12_381::Fr;
144    /// use ark_relations::gr1cs::*;
145    /// use ark_r1cs_std::prelude::*;
146    ///
147    /// let cs = ConstraintSystem::<Fr>::new_ref();
148    /// let var = UInt16::new_witness(cs.clone(), || Ok(2 * (u8::MAX as u16)))?;
149    ///
150    /// // Construct u8::MAX * 2
151    /// let bytes = UInt8::constant_vec(&(2 * (u8::MAX as u16)).to_be_bytes());
152    /// let var_bytes = var.to_bytes_be()?;
153    /// for (b1, b2) in var_bytes.iter().zip(bytes) {
154    ///     b1.enforce_equal(&b2)?;
155    /// }
156    ///
157    /// assert!(cs.is_satisfied().unwrap());
158    /// # Ok(())
159    /// # }
160    /// ```
161    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    /// Interprets `self` as an integer, and outputs the little-endian
176    /// bit-wise decomposition of that integer.
177    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
183/// ****************************************************************************
184/// **********
185/// ******************************* Conversions to bytes.
186/// ********************************
187/// ****************************************************************************
188/// **********
189
190impl<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}