use crate::convert::*; use crate::fields::fp::FpVar; use super::*; impl UInt { /// Converts `self` into a field element. The elements comprising `self` are /// interpreted as a little-endian bit order representation of a field element. /// /// # Panics /// Assumes that `N` is equal to at most the number of bits in `F::MODULUS_BIT_SIZE - 1`, and panics otherwise. pub fn to_fp(&self) -> Result, SynthesisError> where F: PrimeField, { assert!(N <= F::MODULUS_BIT_SIZE as usize - 1); Boolean::le_bits_to_fp(&self.bits) } /// Converts a field element into its little-endian bit order representation. /// /// # Panics /// /// Assumes that `N` is at most the number of bits in `F::MODULUS_BIT_SIZE - 1`, and panics otherwise. pub fn from_fp(other: &FpVar) -> Result<(Self, FpVar), SynthesisError> where F: PrimeField, { let (bits, rest) = other.to_bits_le_with_top_bits_zero(N)?; let result = Self::from_bits_le(&bits); Ok((result, rest)) } /// Converts a little-endian byte order representation of bits into a /// `UInt`. /// /// ``` /// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> { /// // We'll use the BLS12-381 scalar field for our constraints. /// use ark_test_curves::bls12_381::Fr; /// use ark_relations::r1cs::*; /// use ark_r1cs_std::prelude::*; /// /// let cs = ConstraintSystem::::new_ref(); /// let var = UInt8::new_witness(cs.clone(), || Ok(128))?; /// /// let f = Boolean::FALSE; /// let t = Boolean::TRUE; /// /// // Construct [0, 0, 0, 0, 0, 0, 0, 1] /// let mut bits = vec![f.clone(); 7]; /// bits.push(t); /// /// let mut c = UInt8::from_bits_le(&bits); /// var.enforce_equal(&c)?; /// assert!(cs.is_satisfied().unwrap()); /// # Ok(()) /// # } /// ``` #[tracing::instrument(target = "r1cs")] pub fn from_bits_le(bits: &[Boolean]) -> Self { assert_eq!(bits.len(), N); let bits = <&[Boolean; N]>::try_from(bits).unwrap().clone(); let value_exists = bits.iter().all(|b| b.value().is_ok()); let mut value = T::zero(); for (i, b) in bits.iter().enumerate() { if let Ok(b) = b.value() { value = value + (T::from(b as u8).unwrap() << i); } } let value = value_exists.then_some(value); Self { bits, value } } } impl ToBitsGadget for UInt { fn to_bits_le(&self) -> Result>, SynthesisError> { Ok(self.bits.to_vec()) } } impl ToBitsGadget for [UInt] { /// Interprets `self` as an integer, and outputs the little-endian /// bit-wise decomposition of that integer. fn to_bits_le(&self) -> Result>, SynthesisError> { let bits = self.iter().flat_map(|b| &b.bits).cloned().collect(); Ok(bits) } } /*****************************************************************************************/ /********************************* Conversions to bytes. *********************************/ /*****************************************************************************************/ impl ToBytesGadget for UInt { #[tracing::instrument(target = "r1cs", skip(self))] fn to_bytes(&self) -> Result>, SynthesisError> { Ok(self .to_bits_le()? .chunks(8) .map(UInt8::from_bits_le) .collect()) } } impl ToBytesGadget for [UInt] { fn to_bytes(&self) -> Result>, SynthesisError> { let mut bytes = Vec::with_capacity(self.len() * (N / 8)); for elem in self { bytes.extend_from_slice(&elem.to_bytes()?); } Ok(bytes) } } impl ToBytesGadget for Vec> { fn to_bytes(&self) -> Result>, SynthesisError> { self.as_slice().to_bytes() } } impl<'a, const N: usize, T: PrimUInt, F: Field> ToBytesGadget for &'a [UInt] { fn to_bytes(&self) -> Result>, SynthesisError> { (*self).to_bytes() } }