arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/uint/add/wrapping.rs
src/uint/add/wrapping.rsRaw
  1use ark_ff::PrimeField;
  2use ark_relations::r1cs::SynthesisError;
  3
  4use crate::uint::*;
  5use crate::R1CSVar;
  6
  7impl<const N: usize, T: PrimUInt, F: PrimeField> UInt<N, T, F> {
  8    /// Compute `*self = self.wrapping_add(other)`.
  9    pub fn wrapping_add_in_place(&mut self, other: &Self) {
 10        let result = Self::wrapping_add_many(&[self.clone(), other.clone()]).unwrap();
 11        *self = result;
 12    }
 13
 14    /// Compute `self.wrapping_add(other)`.
 15    pub fn wrapping_add(&self, other: &Self) -> Self {
 16        let mut result = self.clone();
 17        result.wrapping_add_in_place(other);
 18        result
 19    }
 20
 21    /// Perform wrapping addition of `operands`.
 22    /// Computes `operands[0].wrapping_add(operands[1]).wrapping_add(operands[2])...`.
 23    ///
 24    /// The user must ensure that overflow does not occur.
 25    #[tracing::instrument(target = "r1cs", skip(operands))]
 26    pub fn wrapping_add_many(operands: &[Self]) -> Result<Self, SynthesisError>
 27    where
 28        F: PrimeField,
 29    {
 30        let (mut sum_bits, value) = Self::add_many_helper(operands, |a, b| a.wrapping_add(&b))?;
 31        if operands.is_constant() {
 32            // If all operands are constant, then the result is also constant.
 33            // In this case, we can return early.
 34            Ok(UInt::constant(value.unwrap()))
 35        } else {
 36            sum_bits.truncate(N);
 37            Ok(UInt {
 38                bits: sum_bits.try_into().unwrap(),
 39                value,
 40            })
 41        }
 42    }
 43}
 44
 45#[cfg(test)]
 46mod tests {
 47    use super::*;
 48    use crate::{
 49        alloc::{AllocVar, AllocationMode},
 50        prelude::EqGadget,
 51        uint::test_utils::{run_binary_exhaustive, run_binary_random},
 52        R1CSVar,
 53    };
 54    use ark_ff::PrimeField;
 55    use ark_test_curves::bls12_381::Fr;
 56
 57    fn uint_wrapping_add<T: PrimUInt, const N: usize, F: PrimeField>(
 58        a: UInt<N, T, F>,
 59        b: UInt<N, T, F>,
 60    ) -> Result<(), SynthesisError> {
 61        let cs = a.cs().or(b.cs());
 62        let both_constant = a.is_constant() && b.is_constant();
 63        let computed = a.wrapping_add(&b);
 64        let expected_mode = if both_constant {
 65            AllocationMode::Constant
 66        } else {
 67            AllocationMode::Witness
 68        };
 69        let expected = UInt::new_variable(
 70            cs.clone(),
 71            || Ok(a.value()?.wrapping_add(&b.value()?)),
 72            expected_mode,
 73        )?;
 74        assert_eq!(expected.value(), computed.value());
 75        expected.enforce_equal(&computed)?;
 76        if !both_constant {
 77            assert!(cs.is_satisfied().unwrap());
 78        }
 79        Ok(())
 80    }
 81
 82    #[test]
 83    fn u8_wrapping_add() {
 84        run_binary_exhaustive(uint_wrapping_add::<u8, 8, Fr>).unwrap()
 85    }
 86
 87    #[test]
 88    fn u16_wrapping_add() {
 89        run_binary_random::<1000, 16, _, _>(uint_wrapping_add::<u16, 16, Fr>).unwrap()
 90    }
 91
 92    #[test]
 93    fn u32_wrapping_add() {
 94        run_binary_random::<1000, 32, _, _>(uint_wrapping_add::<u32, 32, Fr>).unwrap()
 95    }
 96
 97    #[test]
 98    fn u64_wrapping_add() {
 99        run_binary_random::<1000, 64, _, _>(uint_wrapping_add::<u64, 64, Fr>).unwrap()
100    }
101
102    #[test]
103    fn u128_wrapping_add() {
104        run_binary_random::<1000, 128, _, _>(uint_wrapping_add::<u128, 128, Fr>).unwrap()
105    }
106}