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#[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 pub const MAX: Self = Self {
58 bits: [Boolean::TRUE; N],
59 value: Some(T::MAX),
60 };
61
62 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 pub fn constant_vec(values: &[T]) -> Vec<Self> {
117 values.iter().map(|v| Self::constant(*v)).collect()
118 }
119
120 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}