arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
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}