use crate::{
curves::{fp_parameters::FpParameters, PrimeField},
gadgets::{
r1cs::{Assignment, ConstraintSystem, LinearCombination},
utilities::{
alloc::AllocGadget,
arithmetic::Add,
bits::RippleCarryAdder,
boolean::{AllocatedBit, Boolean},
int::{Int, Int64},
},
},
};
use snarkvm_errors::gadgets::SignedIntegerError;
macro_rules! add_int_impl {
($($gadget: ident)*) => ($(
impl<F: PrimeField> Add<F> for $gadget {
type ErrorType = SignedIntegerError;
fn add<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Self, Self::ErrorType> {
let max_bits = <$gadget as Int>::SIZE;
assert!(F::Parameters::MODULUS_BITS >= max_bits as u32);
let result_value = match (self.value, other.value) {
(Some(a), Some(b)) => {
let val = match a.checked_add(b) {
Some(val) => val,
None => return Err(SignedIntegerError::Overflow)
};
Some(val)
},
_ => {
None
}
};
let mut lc = LinearCombination::zero();
let mut all_constants = true;
let mut bits = self.add_bits(cs.ns(|| format!("bits")), other)?;
let _carry = bits.pop();
let mut coeff = F::one();
for bit in bits {
match bit {
Boolean::Is(ref bit) => {
all_constants = false;
lc += (coeff, bit.get_variable());
}
Boolean::Not(ref bit) => {
all_constants = false;
lc = lc + (coeff, CS::one()) - (coeff, bit.get_variable());
}
Boolean::Constant(bit) => {
if bit {
lc += (coeff, CS::one());
}
}
}
coeff.double_in_place();
}
let modular_value = result_value.map(|v| v as <$gadget as Int>::IntegerType);
if all_constants && modular_value.is_some() {
return Ok(Self::constant(modular_value.unwrap()));
}
let mut result_bits = Vec::with_capacity(max_bits);
let mut coeff = F::one();
for i in 0..max_bits {
let mask = 1 << i as <$gadget as Int>::IntegerType;
let b = AllocatedBit::alloc(cs.ns(|| format!("result bit_gadget {}", i)), || {
result_value.map(|v| (v & mask) == mask).get()
})?;
lc = lc - (coeff, b.get_variable());
result_bits.push(b.into());
coeff.double_in_place();
}
cs.enforce(|| "modular addition", |lc| lc, |lc| lc, |_| lc);
result_bits.truncate(<$gadget as Int>::SIZE);
Ok(Self {
bits: result_bits,
value: modular_value,
})
}
}
)*)
}
add_int_impl!(Int64);