ark-r1cs-std/src/uint/add/mod.rs
src/uint/add/mod.rsRaw
1use crate::fields::fp::FpVar;
2
3use super::*;
4
5mod saturating;
6mod wrapping;
7
8impl<const N: usize, T: PrimUInt, F: PrimeField> UInt<N, T, F> {
9 /// Adds up `operands`, returning the bit decomposition of the result, along with
10 /// the value of the result. If all the operands are constant, then the bit decomposition
11 /// is empty, and the value is the constant value of the result.
12 ///
13 /// # Panics
14 ///
15 /// This method panics if the result of addition could possibly exceed the field size.
16 #[tracing::instrument(target = "r1cs", skip(operands, adder))]
17 fn add_many_helper(
18 operands: &[Self],
19 adder: impl Fn(T, T) -> T,
20 ) -> Result<(Vec<Boolean<F>>, Option<T>), SynthesisError> {
21 // Bounds on `N` to avoid overflows
22
23 assert!(operands.len() >= 1);
24 let max_value_size = N as u32 + ark_std::log2(operands.len());
25 assert!(max_value_size <= F::MODULUS_BIT_SIZE);
26
27 if operands.len() == 1 {
28 return Ok((operands[0].bits.to_vec(), operands[0].value));
29 }
30
31 // Compute the value of the result.
32 let mut value = Some(T::zero());
33 for op in operands {
34 value = value.and_then(|v| Some(adder(v, op.value?)));
35 }
36 if operands.is_constant() {
37 // If all operands are constant, then the result is also constant.
38 // In this case, we can return early.
39 return Ok((Vec::new(), value));
40 }
41
42 // Compute the full (non-wrapped) sum of the operands.
43 let result = operands
44 .iter()
45 .map(|op| Boolean::le_bits_to_fp(&op.bits).unwrap())
46 .sum::<FpVar<_>>();
47 let (result, _) = result.to_bits_le_with_top_bits_zero(max_value_size as usize)?;
48 Ok((result, value))
49 }
50}