/ circuit / types / group / src / ternary.rs
ternary.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> Ternary for Group<E> {
 19      type Boolean = Boolean<E>;
 20      type Output = Group<E>;
 21  
 22      /// Returns `first` if `condition` is `true`, otherwise returns `second`.
 23      fn ternary(condition: &Self::Boolean, first: &Self, second: &Self) -> Self::Output {
 24          let x = Ternary::ternary(condition, &first.x, &second.x);
 25          let y = Ternary::ternary(condition, &first.y, &second.y);
 26          Group { x, y }
 27      }
 28  }
 29  
 30  impl<E: Environment> Metrics<dyn Ternary<Boolean = Boolean<E>, Output = Group<E>>> for Group<E> {
 31      type Case = (Mode, Mode, Mode);
 32  
 33      fn count(case: &Self::Case) -> Count {
 34          match case {
 35              (Mode::Constant, _, _)
 36              | (Mode::Public, Mode::Constant, Mode::Constant)
 37              | (Mode::Private, Mode::Constant, Mode::Constant) => Count::is(0, 0, 0, 0),
 38              _ => Count::is(0, 0, 2, 2),
 39          }
 40      }
 41  }
 42  
 43  impl<E: Environment> OutputMode<dyn Ternary<Boolean = Boolean<E>, Output = Self>> for Group<E> {
 44      type Case = (CircuitType<Boolean<E>>, Mode, Mode);
 45  
 46      fn output_mode(parameter: &Self::Case) -> Mode {
 47          match parameter.0.mode().is_constant() {
 48              true => match &parameter.0 {
 49                  CircuitType::Constant(constant) => match constant.eject_value() {
 50                      true => parameter.1,
 51                      false => parameter.2,
 52                  },
 53                  _ => E::halt("The constant condition is required to determine output mode."),
 54              },
 55              false => Mode::Private,
 56          }
 57      }
 58  }
 59  
 60  #[cfg(test)]
 61  mod tests {
 62      use super::*;
 63      use alphavm_circuit_environment::Circuit;
 64  
 65      fn check_ternary(
 66          name: &str,
 67          expected: console::Group<<Circuit as Environment>::Network>,
 68          condition: Boolean<Circuit>,
 69          a: Group<Circuit>,
 70          b: Group<Circuit>,
 71      ) {
 72          Circuit::scope(name, || {
 73              let case = format!("({} ? {} : {})", condition.eject_value(), a.eject_value(), b.eject_value());
 74              let candidate = Group::ternary(&condition, &a, &b);
 75              assert_eq!(expected, candidate.eject_value(), "{case}");
 76              assert_count!(Ternary(Boolean, Group, Group) => Group, &(condition.eject_mode(), a.eject_mode(), b.eject_mode()));
 77              assert_output_mode!(Ternary(Boolean, Group, Group) => Group, &(CircuitType::from(&condition), a.eject_mode(), b.eject_mode()), candidate);
 78          });
 79      }
 80  
 81      #[test]
 82      fn test_constant_condition() {
 83          let mut rng = TestRng::default();
 84  
 85          let first = Uniform::rand(&mut rng);
 86          let second = Uniform::rand(&mut rng);
 87  
 88          // false ? Constant : Constant
 89          let expected = second;
 90          let condition = Boolean::<Circuit>::new(Mode::Constant, false);
 91          let a = Group::<Circuit>::new(Mode::Constant, first);
 92          let b = Group::<Circuit>::new(Mode::Constant, second);
 93          check_ternary("false ? Constant : Constant", expected, condition, a, b);
 94  
 95          // false ? Constant : Public
 96          let expected = second;
 97          let condition = Boolean::<Circuit>::new(Mode::Constant, false);
 98          let a = Group::<Circuit>::new(Mode::Constant, first);
 99          let b = Group::<Circuit>::new(Mode::Public, second);
100          check_ternary("false ? Constant : Public", expected, condition, a, b);
101  
102          // false ? Public : Constant
103          let expected = second;
104          let condition = Boolean::<Circuit>::new(Mode::Constant, false);
105          let a = Group::<Circuit>::new(Mode::Public, first);
106          let b = Group::<Circuit>::new(Mode::Constant, second);
107          check_ternary("false ? Public : Constant", expected, condition, a, b);
108  
109          // false ? Public : Public
110          let expected = second;
111          let condition = Boolean::<Circuit>::new(Mode::Constant, false);
112          let a = Group::<Circuit>::new(Mode::Public, first);
113          let b = Group::<Circuit>::new(Mode::Public, second);
114          check_ternary("false ? Public : Public", expected, condition, a, b);
115  
116          // false ? Public : Private
117          let expected = second;
118          let condition = Boolean::<Circuit>::new(Mode::Constant, false);
119          let a = Group::<Circuit>::new(Mode::Public, first);
120          let b = Group::<Circuit>::new(Mode::Private, second);
121          check_ternary("false ? Public : Private", expected, condition, a, b);
122  
123          // false ? Private : Private
124          let expected = second;
125          let condition = Boolean::<Circuit>::new(Mode::Constant, false);
126          let a = Group::<Circuit>::new(Mode::Private, first);
127          let b = Group::<Circuit>::new(Mode::Private, second);
128          check_ternary("false ? Private : Private", expected, condition, a, b);
129  
130          // true ? Constant : Constant
131          let expected = first;
132          let condition = Boolean::<Circuit>::new(Mode::Constant, true);
133          let a = Group::<Circuit>::new(Mode::Constant, first);
134          let b = Group::<Circuit>::new(Mode::Constant, second);
135          check_ternary("true ? Constant : Constant", expected, condition, a, b);
136  
137          // true ? Constant : Public
138          let expected = first;
139          let condition = Boolean::<Circuit>::new(Mode::Constant, true);
140          let a = Group::<Circuit>::new(Mode::Constant, first);
141          let b = Group::<Circuit>::new(Mode::Public, second);
142          check_ternary("true ? Constant : Public", expected, condition, a, b);
143  
144          // true ? Public : Constant
145          let expected = first;
146          let condition = Boolean::<Circuit>::new(Mode::Constant, true);
147          let a = Group::<Circuit>::new(Mode::Public, first);
148          let b = Group::<Circuit>::new(Mode::Constant, second);
149          check_ternary("true ? Public : Constant", expected, condition, a, b);
150  
151          // true ? Public : Public
152          let expected = first;
153          let condition = Boolean::<Circuit>::new(Mode::Constant, true);
154          let a = Group::<Circuit>::new(Mode::Public, first);
155          let b = Group::<Circuit>::new(Mode::Public, second);
156          check_ternary("true ? Public : Public", expected, condition, a, b);
157  
158          // true ? Public : Private
159          let expected = first;
160          let condition = Boolean::<Circuit>::new(Mode::Constant, true);
161          let a = Group::<Circuit>::new(Mode::Public, first);
162          let b = Group::<Circuit>::new(Mode::Private, second);
163          check_ternary("true ? Public : Private", expected, condition, a, b);
164  
165          // true ? Private : Private
166          let expected = first;
167          let condition = Boolean::<Circuit>::new(Mode::Constant, true);
168          let a = Group::<Circuit>::new(Mode::Private, first);
169          let b = Group::<Circuit>::new(Mode::Private, second);
170          check_ternary("true ? Private : Private", expected, condition, a, b);
171      }
172  
173      #[test]
174      fn test_public_condition_and_constant_inputs() {
175          let mut rng = TestRng::default();
176  
177          let first = Uniform::rand(&mut rng);
178          let second = Uniform::rand(&mut rng);
179  
180          // false ? Constant : Constant
181          let expected = second;
182          let condition = Boolean::<Circuit>::new(Mode::Public, false);
183          let a = Group::<Circuit>::new(Mode::Constant, first);
184          let b = Group::<Circuit>::new(Mode::Constant, second);
185          check_ternary("false ? Constant : Constant", expected, condition, a, b);
186  
187          // true ? Constant : Constant
188          let expected = first;
189          let condition = Boolean::<Circuit>::new(Mode::Public, true);
190          let a = Group::<Circuit>::new(Mode::Constant, first);
191          let b = Group::<Circuit>::new(Mode::Constant, second);
192          check_ternary("true ? Constant : Constant", expected, condition, a, b);
193      }
194  
195      #[test]
196      fn test_public_condition_and_mixed_inputs() {
197          let mut rng = TestRng::default();
198  
199          let first = Uniform::rand(&mut rng);
200          let second = Uniform::rand(&mut rng);
201  
202          // false ? Constant : Public
203          let expected = second;
204          let condition = Boolean::<Circuit>::new(Mode::Public, false);
205          let a = Group::<Circuit>::new(Mode::Constant, first);
206          let b = Group::<Circuit>::new(Mode::Public, second);
207          check_ternary("false ? Constant : Public", expected, condition, a, b);
208  
209          // false ? Public : Constant
210          let expected = second;
211          let condition = Boolean::<Circuit>::new(Mode::Public, false);
212          let a = Group::<Circuit>::new(Mode::Public, first);
213          let b = Group::<Circuit>::new(Mode::Constant, second);
214          check_ternary("false ? Public : Constant", expected, condition, a, b);
215  
216          // true ? Constant : Public
217          let expected = first;
218          let condition = Boolean::<Circuit>::new(Mode::Public, true);
219          let a = Group::<Circuit>::new(Mode::Constant, first);
220          let b = Group::<Circuit>::new(Mode::Public, second);
221          check_ternary("true ? Constant : Public", expected, condition, a, b);
222  
223          // true ? Public : Constant
224          let expected = first;
225          let condition = Boolean::<Circuit>::new(Mode::Public, true);
226          let a = Group::<Circuit>::new(Mode::Public, first);
227          let b = Group::<Circuit>::new(Mode::Constant, second);
228          check_ternary("true ? Public : Constant", expected, condition, a, b);
229      }
230  
231      #[test]
232      fn test_private_condition_and_constant_inputs() {
233          let mut rng = TestRng::default();
234  
235          let first = Uniform::rand(&mut rng);
236          let second = Uniform::rand(&mut rng);
237  
238          // false ? Constant : Constant
239          let expected = second;
240          let condition = Boolean::<Circuit>::new(Mode::Private, false);
241          let a = Group::<Circuit>::new(Mode::Constant, first);
242          let b = Group::<Circuit>::new(Mode::Constant, second);
243          check_ternary("false ? Constant : Constant", expected, condition, a, b);
244  
245          // true ? Constant : Constant
246          let expected = first;
247          let condition = Boolean::<Circuit>::new(Mode::Private, true);
248          let a = Group::<Circuit>::new(Mode::Constant, first);
249          let b = Group::<Circuit>::new(Mode::Constant, second);
250          check_ternary("true ? Constant : Constant", expected, condition, a, b);
251      }
252  
253      #[test]
254      fn test_private_condition_and_mixed_inputs() {
255          let mut rng = TestRng::default();
256  
257          let first = Uniform::rand(&mut rng);
258          let second = Uniform::rand(&mut rng);
259  
260          // false ? Constant : Public
261          let expected = second;
262          let condition = Boolean::<Circuit>::new(Mode::Private, false);
263          let a = Group::<Circuit>::new(Mode::Constant, first);
264          let b = Group::<Circuit>::new(Mode::Public, second);
265          check_ternary("false ? Constant : Public", expected, condition, a, b);
266  
267          // false ? Public : Constant
268          let expected = second;
269          let condition = Boolean::<Circuit>::new(Mode::Private, false);
270          let a = Group::<Circuit>::new(Mode::Public, first);
271          let b = Group::<Circuit>::new(Mode::Constant, second);
272          check_ternary("false ? Public : Constant", expected, condition, a, b);
273  
274          // true ? Constant : Public
275          let expected = first;
276          let condition = Boolean::<Circuit>::new(Mode::Private, true);
277          let a = Group::<Circuit>::new(Mode::Constant, first);
278          let b = Group::<Circuit>::new(Mode::Public, second);
279          check_ternary("true ? Constant : Public", expected, condition, a, b);
280  
281          // true ? Public : Constant
282          let expected = first;
283          let condition = Boolean::<Circuit>::new(Mode::Private, true);
284          let a = Group::<Circuit>::new(Mode::Public, first);
285          let b = Group::<Circuit>::new(Mode::Constant, second);
286          check_ternary("true ? Public : Constant", expected, condition, a, b);
287      }
288  
289      #[test]
290      fn test_public_condition_and_variable_inputs() {
291          let mut rng = TestRng::default();
292  
293          let first = Uniform::rand(&mut rng);
294          let second = Uniform::rand(&mut rng);
295  
296          // false ? Public : Public
297          let expected = second;
298          let condition = Boolean::<Circuit>::new(Mode::Public, false);
299          let a = Group::<Circuit>::new(Mode::Public, first);
300          let b = Group::<Circuit>::new(Mode::Public, second);
301          check_ternary("false ? Public : Public", expected, condition, a, b);
302  
303          // false ? Public : Private
304          let expected = second;
305          let condition = Boolean::<Circuit>::new(Mode::Public, false);
306          let a = Group::<Circuit>::new(Mode::Public, first);
307          let b = Group::<Circuit>::new(Mode::Private, second);
308          check_ternary("false ? Public : Private", expected, condition, a, b);
309  
310          // false ? Private : Public
311          let expected = second;
312          let condition = Boolean::<Circuit>::new(Mode::Public, false);
313          let a = Group::<Circuit>::new(Mode::Private, first);
314          let b = Group::<Circuit>::new(Mode::Public, second);
315          check_ternary("false ? Private : Public", expected, condition, a, b);
316  
317          // false ? Private : Private
318          let expected = second;
319          let condition = Boolean::<Circuit>::new(Mode::Public, false);
320          let a = Group::<Circuit>::new(Mode::Private, first);
321          let b = Group::<Circuit>::new(Mode::Private, second);
322          check_ternary("false ? Private : Private", expected, condition, a, b);
323  
324          // true ? Public : Public
325          let expected = first;
326          let condition = Boolean::<Circuit>::new(Mode::Public, true);
327          let a = Group::<Circuit>::new(Mode::Public, first);
328          let b = Group::<Circuit>::new(Mode::Public, second);
329          check_ternary("true ? Public : Public", expected, condition, a, b);
330  
331          // true ? Public : Private
332          let expected = first;
333          let condition = Boolean::<Circuit>::new(Mode::Public, true);
334          let a = Group::<Circuit>::new(Mode::Public, first);
335          let b = Group::<Circuit>::new(Mode::Private, second);
336          check_ternary("true ? Public : Private", expected, condition, a, b);
337  
338          // true ? Private : Public
339          let expected = first;
340          let condition = Boolean::<Circuit>::new(Mode::Public, true);
341          let a = Group::<Circuit>::new(Mode::Private, first);
342          let b = Group::<Circuit>::new(Mode::Public, second);
343          check_ternary("true ? Private : Public", expected, condition, a, b);
344  
345          // true ? Private : Private
346          let expected = first;
347          let condition = Boolean::<Circuit>::new(Mode::Public, true);
348          let a = Group::<Circuit>::new(Mode::Private, first);
349          let b = Group::<Circuit>::new(Mode::Private, second);
350          check_ternary("true ? Private : Private", expected, condition, a, b);
351      }
352  
353      #[test]
354      fn test_private_condition_and_variable_inputs() {
355          let mut rng = TestRng::default();
356  
357          let first = Uniform::rand(&mut rng);
358          let second = Uniform::rand(&mut rng);
359  
360          // false ? Public : Public
361          let expected = second;
362          let condition = Boolean::<Circuit>::new(Mode::Private, false);
363          let a = Group::<Circuit>::new(Mode::Public, first);
364          let b = Group::<Circuit>::new(Mode::Public, second);
365          check_ternary("false ? Public : Public", expected, condition, a, b);
366  
367          // false ? Public : Private
368          let expected = second;
369          let condition = Boolean::<Circuit>::new(Mode::Private, false);
370          let a = Group::<Circuit>::new(Mode::Public, first);
371          let b = Group::<Circuit>::new(Mode::Private, second);
372          check_ternary("false ? Public : Private", expected, condition, a, b);
373  
374          // false ? Private : Public
375          let expected = second;
376          let condition = Boolean::<Circuit>::new(Mode::Private, false);
377          let a = Group::<Circuit>::new(Mode::Private, first);
378          let b = Group::<Circuit>::new(Mode::Public, second);
379          check_ternary("false ? Private : Public", expected, condition, a, b);
380  
381          // false ? Private : Private
382          let expected = second;
383          let condition = Boolean::<Circuit>::new(Mode::Private, false);
384          let a = Group::<Circuit>::new(Mode::Private, first);
385          let b = Group::<Circuit>::new(Mode::Private, second);
386          check_ternary("false ? Private : Private", expected, condition, a, b);
387  
388          // true ? Public : Public
389          let expected = first;
390          let condition = Boolean::<Circuit>::new(Mode::Private, true);
391          let a = Group::<Circuit>::new(Mode::Public, first);
392          let b = Group::<Circuit>::new(Mode::Public, second);
393          check_ternary("true ? Public : Public", expected, condition, a, b);
394  
395          // true ? Public : Private
396          let expected = first;
397          let condition = Boolean::<Circuit>::new(Mode::Private, true);
398          let a = Group::<Circuit>::new(Mode::Public, first);
399          let b = Group::<Circuit>::new(Mode::Private, second);
400          check_ternary("true ? Public : Private", expected, condition, a, b);
401  
402          // true ? Private : Public
403          let expected = first;
404          let condition = Boolean::<Circuit>::new(Mode::Private, true);
405          let a = Group::<Circuit>::new(Mode::Private, first);
406          let b = Group::<Circuit>::new(Mode::Public, second);
407          check_ternary("true ? Private : Public", expected, condition, a, b);
408  
409          // true ? Private : Private
410          let expected = first;
411          let condition = Boolean::<Circuit>::new(Mode::Private, true);
412          let a = Group::<Circuit>::new(Mode::Private, first);
413          let b = Group::<Circuit>::new(Mode::Private, second);
414          check_ternary("true ? Private : Private", expected, condition, a, b);
415      }
416  }