ark_r1cs_std/uint/
convert.rs

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
174#[cfg(test)]
175mod tests {
176    use super::*;
177    use crate::{
178        prelude::EqGadget,
179        uint::test_utils::{run_unary_exhaustive, run_unary_random},
180        R1CSVar,
181    };
182    use ark_ff::PrimeField;
183    use ark_test_curves::bls12_381::Fr;
184
185    fn uint_to_bytes_le<T: PrimUInt, const N: usize, F: PrimeField>(
186        a: UInt<N, T, F>,
187    ) -> Result<(), SynthesisError> {
188        let cs = a.cs();
189        let computed = a.to_bytes_le()?;
190        let expected = UInt8::constant_vec(a.value()?.to_le_bytes().as_ref());
191        assert_eq!(expected.len(), computed.len());
192        assert_eq!(expected.value(), computed.value());
193        expected.enforce_equal(&computed)?;
194        if !a.is_constant() {
195            assert!(cs.is_satisfied().unwrap());
196        }
197        Ok(())
198    }
199
200    fn uint_to_bytes_be<T: PrimUInt, const N: usize, F: PrimeField>(
201        a: UInt<N, T, F>,
202    ) -> Result<(), SynthesisError> {
203        let cs = a.cs();
204        let computed = a.to_bytes_be()?;
205        let expected = UInt8::constant_vec(a.value()?.to_be_bytes().as_ref());
206        assert_eq!(expected.len(), computed.len());
207        assert_eq!(expected.value(), computed.value());
208        expected.enforce_equal(&computed)?;
209        if !a.is_constant() {
210            assert!(cs.is_satisfied().unwrap());
211        }
212        Ok(())
213    }
214
215    fn uint_from_bytes_le<T: PrimUInt, const N: usize, F: PrimeField>(
216        expected: UInt<N, T, F>,
217    ) -> Result<(), SynthesisError> {
218        let cs = expected.cs();
219        let mode = if expected.is_constant() {
220            AllocationMode::Constant
221        } else {
222            AllocationMode::Witness
223        };
224        let computed = {
225            let value = expected.value()?.to_le_bytes();
226            let a = Vec::<UInt8<F>>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?;
227            UInt::from_bytes_le(&a)?
228        };
229        assert_eq!(expected.value(), computed.value());
230        expected.enforce_equal(&computed)?;
231        if !expected.is_constant() {
232            assert!(cs.is_satisfied().unwrap());
233        }
234        Ok(())
235    }
236
237    fn uint_from_bytes_be<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_be_bytes();
248            let a = Vec::<UInt8<F>>::new_variable(cs.clone(), || Ok(value.as_ref()), mode)?;
249            UInt::from_bytes_be(&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    #[test]
260    fn u8_to_bytes_le() {
261        run_unary_exhaustive(uint_to_bytes_le::<u8, 8, Fr>).unwrap()
262    }
263
264    #[test]
265    fn u16_to_bytes_le() {
266        run_unary_random::<1000, 16, _, _>(uint_to_bytes_le::<u16, 16, Fr>).unwrap()
267    }
268
269    #[test]
270    fn u32_to_bytes_le() {
271        run_unary_random::<1000, 32, _, _>(uint_to_bytes_le::<u32, 32, Fr>).unwrap()
272    }
273
274    #[test]
275    fn u64_to_bytes_le() {
276        run_unary_random::<1000, 64, _, _>(uint_to_bytes_le::<u64, 64, Fr>).unwrap()
277    }
278
279    #[test]
280    fn u128_to_bytes_le() {
281        run_unary_random::<1000, 128, _, _>(uint_to_bytes_le::<u128, 128, Fr>).unwrap()
282    }
283
284    #[test]
285    fn u8_to_bytes_be() {
286        run_unary_exhaustive(uint_to_bytes_be::<u8, 8, Fr>).unwrap()
287    }
288
289    #[test]
290    fn u16_to_bytes_be() {
291        run_unary_random::<1000, 16, _, _>(uint_to_bytes_be::<u16, 16, Fr>).unwrap()
292    }
293
294    #[test]
295    fn u32_to_bytes_be() {
296        run_unary_random::<1000, 32, _, _>(uint_to_bytes_be::<u32, 32, Fr>).unwrap()
297    }
298
299    #[test]
300    fn u64_to_bytes_be() {
301        run_unary_random::<1000, 64, _, _>(uint_to_bytes_be::<u64, 64, Fr>).unwrap()
302    }
303
304    #[test]
305    fn u128_to_bytes_be() {
306        run_unary_random::<1000, 128, _, _>(uint_to_bytes_be::<u128, 128, Fr>).unwrap()
307    }
308
309    #[test]
310    fn u8_from_bytes_le() {
311        run_unary_exhaustive(uint_from_bytes_le::<u8, 8, Fr>).unwrap()
312    }
313
314    #[test]
315    fn u16_from_bytes_le() {
316        run_unary_random::<1000, 16, _, _>(uint_from_bytes_le::<u16, 16, Fr>).unwrap()
317    }
318
319    #[test]
320    fn u32_from_bytes_le() {
321        run_unary_random::<1000, 32, _, _>(uint_from_bytes_le::<u32, 32, Fr>).unwrap()
322    }
323
324    #[test]
325    fn u64_from_bytes_le() {
326        run_unary_random::<1000, 64, _, _>(uint_from_bytes_le::<u64, 64, Fr>).unwrap()
327    }
328
329    #[test]
330    fn u128_from_bytes_le() {
331        run_unary_random::<1000, 128, _, _>(uint_from_bytes_le::<u128, 128, Fr>).unwrap()
332    }
333
334    #[test]
335    fn u8_from_bytes_be() {
336        run_unary_exhaustive(uint_from_bytes_be::<u8, 8, Fr>).unwrap()
337    }
338
339    #[test]
340    fn u16_from_bytes_be() {
341        run_unary_random::<1000, 16, _, _>(uint_from_bytes_be::<u16, 16, Fr>).unwrap()
342    }
343
344    #[test]
345    fn u32_from_bytes_be() {
346        run_unary_random::<1000, 32, _, _>(uint_from_bytes_be::<u32, 32, Fr>).unwrap()
347    }
348
349    #[test]
350    fn u64_from_bytes_be() {
351        run_unary_random::<1000, 64, _, _>(uint_from_bytes_be::<u64, 64, Fr>).unwrap()
352    }
353
354    #[test]
355    fn u128_from_bytes_be() {
356        run_unary_random::<1000, 128, _, _>(uint_from_bytes_be::<u128, 128, Fr>).unwrap()
357    }
358}