Skip to main content

ark_r1cs_std/uint/
mod.rs

1use ark_ff::{Field, PrimeField};
2use core::{borrow::Borrow, convert::TryFrom, fmt::Debug};
3
4use ark_relations::gr1cs::{ConstraintSystemRef, Namespace, SynthesisError};
5
6use crate::{boolean::Boolean, prelude::*, Assignment, Vec};
7
8mod add;
9mod and;
10mod cmp;
11mod convert;
12mod eq;
13mod not;
14mod or;
15mod rotate;
16mod select;
17mod shl;
18mod shr;
19mod xor;
20
21#[doc(hidden)]
22pub mod prim_uint;
23pub use prim_uint::*;
24
25#[cfg(test)]
26pub(crate) mod test_utils;
27
28/// This struct represent an unsigned `N` bit integer as a sequence of `N`
29/// [`Boolean`]s.
30#[derive(Clone, Debug)]
31pub struct UInt<const N: usize, T: PrimUInt, F: Field> {
32    #[doc(hidden)]
33    pub bits: [Boolean<F>; N],
34    #[doc(hidden)]
35    pub value: Option<T>,
36}
37
38impl<const N: usize, T: PrimUInt, F: Field> GR1CSVar<F> for UInt<N, T, F> {
39    type Value = T;
40
41    fn cs(&self) -> ConstraintSystemRef<F> {
42        self.bits.as_ref().cs()
43    }
44
45    fn value(&self) -> Result<Self::Value, SynthesisError> {
46        let mut value = T::zero();
47        for (i, bit) in self.bits.iter().enumerate() {
48            value = value + (T::from(bit.value()? as u8).unwrap() << i);
49        }
50        debug_assert_eq!(self.value, Some(value));
51        Ok(value)
52    }
53}
54
55impl<const N: usize, T: PrimUInt, F: Field> UInt<N, T, F> {
56    /// The maximum value of the unsigned integer type.
57    pub const MAX: Self = Self {
58        bits: [Boolean::TRUE; N],
59        value: Some(T::MAX),
60    };
61
62    /// Construct a constant [`UInt`] from the native unsigned integer type.
63    ///
64    /// This *does not* create new variables or constraints.
65    ///
66    /// ```
67    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
68    /// // We'll use the BLS12-381 scalar field for our constraints.
69    /// use ark_test_curves::bls12_381::Fr;
70    /// use ark_relations::gr1cs::*;
71    /// use ark_r1cs_std::prelude::*;
72    ///
73    /// let cs = ConstraintSystem::<Fr>::new_ref();
74    /// let var = UInt8::new_witness(cs.clone(), || Ok(2))?;
75    ///
76    /// let constant = UInt8::constant(2);
77    /// var.enforce_equal(&constant)?;
78    /// assert!(cs.is_satisfied().unwrap());
79    /// # Ok(())
80    /// # }
81    /// ```
82    pub fn constant(value: T) -> Self {
83        let mut bits = [Boolean::FALSE; N];
84        let mut bit_values = value;
85
86        for bit in &mut bits {
87            *bit = Boolean::constant((bit_values & T::one()) == T::one());
88            bit_values >>= 1u8;
89        }
90
91        Self {
92            bits,
93            value: Some(value),
94        }
95    }
96
97    /// Construct a constant vector of [`UInt`] from a vector of the native type
98    ///
99    /// This *does not* create any new variables or constraints.
100    /// ```
101    /// # fn main() -> Result<(), ark_relations::gr1cs::SynthesisError> {
102    /// // We'll use the BLS12-381 scalar field for our constraints.
103    /// use ark_test_curves::bls12_381::Fr;
104    /// use ark_relations::gr1cs::*;
105    /// use ark_r1cs_std::prelude::*;
106    ///
107    /// let cs = ConstraintSystem::<Fr>::new_ref();
108    /// let var = vec![UInt8::new_witness(cs.clone(), || Ok(2))?];
109    ///
110    /// let constant = UInt8::constant_vec(&[2]);
111    /// var.enforce_equal(&constant)?;
112    /// assert!(cs.is_satisfied().unwrap());
113    /// # Ok(())
114    /// # }
115    /// ```
116    pub fn constant_vec(values: &[T]) -> Vec<Self> {
117        values.iter().map(|v| Self::constant(*v)).collect()
118    }
119
120    /// Allocates a slice of `uN`'s as private witnesses.
121    pub fn new_witness_vec(
122        cs: impl Into<Namespace<F>>,
123        values: &[impl Into<Option<T>> + Copy],
124    ) -> Result<Vec<Self>, SynthesisError> {
125        let ns = cs.into();
126        let cs = ns.cs();
127        let mut output_vec = Vec::with_capacity(values.len());
128        for value in values {
129            let byte: Option<T> = Into::into(*value);
130            output_vec.push(Self::new_witness(cs.clone(), || byte.get())?);
131        }
132        Ok(output_vec)
133    }
134}
135
136impl<const N: usize, T: PrimUInt, ConstraintF: Field> AllocVar<T, ConstraintF>
137    for UInt<N, T, ConstraintF>
138{
139    fn new_variable<S: Borrow<T>>(
140        cs: impl Into<Namespace<ConstraintF>>,
141        f: impl FnOnce() -> Result<S, SynthesisError>,
142        mode: AllocationMode,
143    ) -> Result<Self, SynthesisError> {
144        let ns = cs.into();
145        let cs = ns.cs();
146        let value = f().map(|f| *f.borrow()).ok();
147
148        let mut values = [None; N];
149        if let Some(val) = value {
150            values
151                .iter_mut()
152                .enumerate()
153                .for_each(|(i, v)| *v = Some(((val >> i) & T::one()) == T::one()));
154        }
155
156        let mut bits = [Boolean::FALSE; N];
157        for (b, v) in bits.iter_mut().zip(&values) {
158            *b = Boolean::new_variable(cs.clone(), || v.get(), mode)?;
159        }
160        Ok(Self { bits, value })
161    }
162}