1use ark_ff::{Field, PrimeField};
2use core::{borrow::Borrow, convert::TryFrom, fmt::Debug};
3
4use ark_relations::r1cs::{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)]
30pub struct UInt<const N: usize, T: PrimUInt, F: Field> {
31 #[doc(hidden)]
32 pub bits: [Boolean<F>; N],
33 #[doc(hidden)]
34 pub value: Option<T>,
35}
36
37impl<const N: usize, T: PrimUInt, F: Field> R1CSVar<F> for UInt<N, T, F> {
38 type Value = T;
39
40 fn cs(&self) -> ConstraintSystemRef<F> {
41 self.bits.as_ref().cs()
42 }
43
44 fn value(&self) -> Result<Self::Value, SynthesisError> {
45 let mut value = T::zero();
46 for (i, bit) in self.bits.iter().enumerate() {
47 value = value + (T::from(bit.value()? as u8).unwrap() << i);
48 }
49 debug_assert_eq!(self.value, Some(value));
50 Ok(value)
51 }
52}
53
54impl<const N: usize, T: PrimUInt, F: Field> UInt<N, T, F> {
55 pub const MAX: Self = Self {
56 bits: [Boolean::TRUE; N],
57 value: Some(T::MAX),
58 };
59
60 pub fn constant(value: T) -> Self {
81 let mut bits = [Boolean::FALSE; N];
82 let mut bit_values = value;
83
84 for i in 0..N {
85 bits[i] = Boolean::constant((bit_values & T::one()) == T::one());
86 bit_values = bit_values >> 1u8;
87 }
88
89 Self {
90 bits,
91 value: Some(value),
92 }
93 }
94
95 pub fn constant_vec(values: &[T]) -> Vec<Self> {
115 values.iter().map(|v| Self::constant(*v)).collect()
116 }
117
118 pub fn new_witness_vec(
120 cs: impl Into<Namespace<F>>,
121 values: &[impl Into<Option<T>> + Copy],
122 ) -> Result<Vec<Self>, SynthesisError> {
123 let ns = cs.into();
124 let cs = ns.cs();
125 let mut output_vec = Vec::with_capacity(values.len());
126 for value in values {
127 let byte: Option<T> = Into::into(*value);
128 output_vec.push(Self::new_witness(cs.clone(), || byte.get())?);
129 }
130 Ok(output_vec)
131 }
132}
133
134impl<const N: usize, T: PrimUInt, ConstraintF: Field> AllocVar<T, ConstraintF>
135 for UInt<N, T, ConstraintF>
136{
137 fn new_variable<S: Borrow<T>>(
138 cs: impl Into<Namespace<ConstraintF>>,
139 f: impl FnOnce() -> Result<S, SynthesisError>,
140 mode: AllocationMode,
141 ) -> Result<Self, SynthesisError> {
142 let ns = cs.into();
143 let cs = ns.cs();
144 let value = f().map(|f| *f.borrow()).ok();
145
146 let mut values = [None; N];
147 if let Some(val) = value {
148 values
149 .iter_mut()
150 .enumerate()
151 .for_each(|(i, v)| *v = Some(((val >> i) & T::one()) == T::one()));
152 }
153
154 let mut bits = [Boolean::FALSE; N];
155 for (b, v) in bits.iter_mut().zip(&values) {
156 *b = Boolean::new_variable(cs.clone(), || v.get(), mode)?;
157 }
158 Ok(Self { bits, value })
159 }
160}