/ circuit / types / group / src / add.rs
add.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use super::*;
 17  
 18  impl<E: Environment> Add<Self> for Group<E> {
 19      type Output = Self;
 20  
 21      fn add(self, other: Self) -> Self::Output {
 22          self + &other
 23      }
 24  }
 25  
 26  impl<E: Environment> Add<&Self> for Group<E> {
 27      type Output = Self;
 28  
 29      fn add(self, other: &Self) -> Self::Output {
 30          // If `self` is constant *and* `self` is zero, then return `other`.
 31          if self.is_constant() && self.eject_value().is_zero() {
 32              other.clone()
 33          }
 34          // If `other` is constant *and* `other` is zero, then return `self`.
 35          else if other.is_constant() && other.eject_value().is_zero() {
 36              self
 37          }
 38          // Otherwise, compute the sum of `self` and `other`.
 39          else {
 40              // This swap reduces the number of constants by one.
 41              let (this, that) = match other.is_constant() {
 42                  true => (&self, other),
 43                  false => (other, &self),
 44              };
 45  
 46              let a = Field::constant(console::Field::new(E::EDWARDS_A));
 47              let d = Field::constant(console::Field::new(E::EDWARDS_D));
 48  
 49              // Compute U = (-A * x1 + y1) * (x2 + y2)
 50              let u1 = (&this.x * &-&a) + &this.y;
 51              let u2 = &that.x + &that.y;
 52              let u = u1 * u2;
 53  
 54              // Compute v0 = x1 * y2
 55              let v0 = &this.x * &that.y;
 56  
 57              // Compute v1 = x2 * y1
 58              let v1 = &that.x * &this.y;
 59  
 60              // Compute v2 = d * v0 * v1
 61              let v2 = (&v0 * &v1) * d;
 62  
 63              // Compute x3 and y3.
 64              let (x3, y3) = witness!(|a, u, v0, v1, v2| {
 65                  // Assign x3 = (v0 + v1) / (v2 + 1).
 66                  let x3 = (v0 + v1) / (v2 + console::Field::one());
 67                  // Assign y3 = (U + a * v0 - v1) / (1 - v2).
 68                  let y3 = (u + (v0 * a) - v1) / (console::Field::one() - v2);
 69                  // Return (x3, y3).
 70                  (x3, y3)
 71              });
 72  
 73              // Ensure x3 is well-formed.
 74              // x3 * (v2 + 1) = v0 + v1
 75              let v2_plus_one = &v2 + &Field::one();
 76              let v0_plus_v1 = &v0 + &v1;
 77              E::enforce(|| (&x3, v2_plus_one, v0_plus_v1));
 78  
 79              // Ensure y3 is well-formed.
 80              // y3 * (1 - v2) = u + (a * v0) - v1
 81              let one_minus_v2 = Field::one() - v2;
 82              let a_v0 = v0 * a;
 83              let u_plus_a_v0_minus_v1 = u + a_v0 - v1;
 84              E::enforce(|| (&y3, one_minus_v2, u_plus_a_v0_minus_v1));
 85  
 86              Self { x: x3, y: y3 }
 87          }
 88      }
 89  }
 90  
 91  impl<E: Environment> Add<&Group<E>> for &Group<E> {
 92      type Output = Group<E>;
 93  
 94      fn add(self, other: &Group<E>) -> Self::Output {
 95          (*self).clone() + other
 96      }
 97  }
 98  
 99  impl<E: Environment> AddAssign<Self> for Group<E> {
100      fn add_assign(&mut self, other: Self) {
101          *self += &other;
102      }
103  }
104  
105  impl<E: Environment> AddAssign<&Self> for Group<E> {
106      fn add_assign(&mut self, other: &Self) {
107          *self = self.clone() + other;
108      }
109  }
110  
111  impl<E: Environment> Metrics<dyn Add<Group<E>, Output = Group<E>>> for Group<E> {
112      type Case = (Mode, Mode);
113  
114      fn count(case: &Self::Case) -> Count {
115          match (case.0, case.1) {
116              (Mode::Constant, Mode::Constant) => Count::less_than(4, 0, 0, 0),
117              (Mode::Constant, _) | (_, Mode::Constant) => Count::is(2, 0, 3, 3),
118              (_, _) => Count::is(2, 0, 6, 6),
119          }
120      }
121  }
122  
123  impl<E: Environment> OutputMode<dyn Add<Group<E>, Output = Group<E>>> for Group<E> {
124      type Case = (Mode, Mode);
125  
126      // TODO: This implementation is incorrect. In the case where one operand is a constant and is equal to zero, then the output mode
127      //  is that of the other operand.
128      fn output_mode(case: &Self::Case) -> Mode {
129          match (case.0, case.1) {
130              (Mode::Constant, Mode::Constant) => Mode::Constant,
131              (_, _) => Mode::Private,
132          }
133      }
134  }
135  
136  #[cfg(test)]
137  mod tests {
138      use super::*;
139      use alphavm_circuit_environment::Circuit;
140  
141      const ITERATIONS: u64 = 100;
142  
143      fn check_add(
144          name: &str,
145          expected: &console::Group<<Circuit as Environment>::Network>,
146          a: &Group<Circuit>,
147          b: &Group<Circuit>,
148      ) {
149          Circuit::scope(name, || {
150              let candidate = a + b;
151              assert_eq!(*expected, candidate.eject_value(), "({} + {})", a.eject_value(), b.eject_value());
152              assert_count!(Add(Group, Group) => Group, &(a.eject_mode(), b.eject_mode()));
153              assert_output_mode!(Add(Group, Group) => Group, &(a.eject_mode(), b.eject_mode()), candidate);
154          });
155      }
156  
157      fn check_add_assign(
158          name: &str,
159          expected: &console::Group<<Circuit as Environment>::Network>,
160          a: &Group<Circuit>,
161          b: &Group<Circuit>,
162      ) {
163          Circuit::scope(name, || {
164              let mut candidate = a.clone();
165              candidate += b;
166              assert_eq!(*expected, candidate.eject_value(), "({} + {})", a.eject_value(), b.eject_value());
167              assert_count!(Add(Group, Group) => Group, &(a.eject_mode(), b.eject_mode()));
168              assert_output_mode!(Add(Group, Group) => Group, &(a.eject_mode(), b.eject_mode()), candidate);
169          });
170      }
171  
172      fn run_test(mode_a: Mode, mode_b: Mode) {
173          let mut rng = TestRng::default();
174  
175          for i in 0..ITERATIONS {
176              let first = Uniform::rand(&mut rng);
177              let second = Uniform::rand(&mut rng);
178  
179              let a = Group::<Circuit>::new(mode_a, first);
180              let b = Group::<Circuit>::new(mode_b, second);
181  
182              let expected = first + second;
183  
184              let name = format!("Add: a + b {i}");
185              check_add(&name, &expected, &a, &b);
186              let name = format!("AddAssign: a + b {i}");
187              check_add_assign(&name, &expected, &a, &b);
188          }
189      }
190  
191      #[test]
192      fn test_constant_plus_constant() {
193          run_test(Mode::Constant, Mode::Constant);
194      }
195  
196      #[test]
197      fn test_constant_plus_public() {
198          run_test(Mode::Constant, Mode::Public);
199      }
200  
201      #[test]
202      fn test_public_plus_constant() {
203          run_test(Mode::Public, Mode::Constant);
204      }
205  
206      #[test]
207      fn test_constant_plus_private() {
208          run_test(Mode::Constant, Mode::Private);
209      }
210  
211      #[test]
212      fn test_private_plus_constant() {
213          run_test(Mode::Private, Mode::Constant);
214      }
215  
216      #[test]
217      fn test_public_plus_public() {
218          run_test(Mode::Public, Mode::Public);
219      }
220  
221      #[test]
222      fn test_public_plus_private() {
223          run_test(Mode::Public, Mode::Private);
224      }
225  
226      #[test]
227      fn test_private_plus_public() {
228          run_test(Mode::Private, Mode::Public);
229      }
230  
231      #[test]
232      fn test_private_plus_private() {
233          run_test(Mode::Private, Mode::Private);
234      }
235  
236      #[test]
237      fn test_add_matches() {
238          let mut rng = TestRng::default();
239  
240          // Sample two random elements.
241          let a = Uniform::rand(&mut rng);
242          let b = Uniform::rand(&mut rng);
243          let expected = a + b;
244  
245          // Constant
246          let first = Group::<Circuit>::new(Mode::Constant, a);
247          let second = Group::<Circuit>::new(Mode::Constant, b);
248          let candidate_a = first + second;
249          assert_eq!(expected, candidate_a.eject_value());
250  
251          // Private
252          let first = Group::<Circuit>::new(Mode::Private, a);
253          let second = Group::<Circuit>::new(Mode::Private, b);
254          let candidate_b = first + second;
255          assert_eq!(expected, candidate_b.eject_value());
256      }
257  }