arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
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}