1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use snarkvm_fields::{FieldParameters, PrimeField};
use snarkvm_r1cs::{Assignment, ConstraintSystem, LinearCombination};
use crate::{
boolean::{AllocatedBit, Boolean},
errors::SignedIntegerError,
integers::int::*,
traits::{
alloc::AllocGadget,
bits::RippleCarryAdder,
integers::{Add, Integer},
},
};
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 Integer>::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 Integer>::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 Integer>::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);
Ok(Self {
bits: result_bits,
value: modular_value,
})
}
}
)*)
}
add_int_impl!(Int8 Int16 Int32 Int64 Int128);