1#[macro_export]
39macro_rules! operation {
40 ($vis:vis struct $name:ident<$operator:path, $circuit_operator:path, $operate:ident, $opcode:tt> { $( $input:ident => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
42 $crate::operation!($vis struct $name<$operator, $circuit_operator, $operate, $opcode, 1> { $( ($input) => $output $( ( $($condition),+ ) )?, )+ });
43 };
44 ($vis:vis struct $name:ident<$operator:path, $circuit_operator:path, $operate:ident?, $opcode:tt> { $( $input:ident => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
46 $crate::operation!($vis struct $name<$operator, $circuit_operator, $operate?, $opcode, 1> { $( ($input) => $output $( ( $($condition),+ ) )?, )+ });
47 };
48 ($vis:vis struct $name:ident<$operator:path, $circuit_operator:path, $operate:ident, $opcode:tt> { $( ($input_a:ident, $input_b:ident) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
50 $crate::operation!($vis struct $name<$operator, $circuit_operator, $operate, $opcode, 2> { $( ($input_a, $input_b) => $output $( ( $($condition),+ ) )?, )+ });
51 };
52 ($vis:vis struct $name:ident<$operator:path, $circuit_operator:path, $operate:ident, $opcode:tt> { $( ($input_a:ident, $input_b:ident, $input_c:ident) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
54 $crate::operation!($vis struct $name<$operator, $circuit_operator, $operate, $opcode, 3> { $( ($input_a, $input_b, $input_c) => $output $( ( $($condition),+ ) )?, )+ });
55 };
56 ($vis:vis struct $name:ident<$operator:path, $circuit_operator:path, $operate:ident, $opcode:tt, $num_inputs:tt> { $( ( $($input:ident),+ ) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
58 #[derive(Clone, PartialEq, Eq, Hash)]
60 $vis struct $name<N: Network>(core::marker::PhantomData<N>);
61
62 impl<N: Network> $crate::Operation<N, console::program::Literal<N>, console::program::LiteralType, $num_inputs> for $name<N> {
63 const OPCODE: $crate::Opcode = Opcode::Literal($opcode);
65
66 #[inline]
68 fn evaluate(inputs: &[console::program::Literal<N>; $num_inputs]) -> Result<console::program::Literal<N>> {
69 use $operator as Operator;
71 Ok($crate::evaluate!(match Operator::$operate(inputs) { $( ( $($input),+ ) => $output, )+ }))
73 }
74
75 #[inline]
77 fn execute<A: circuit::Aleo<Network = N>>(inputs: &[circuit::Literal<A>; $num_inputs]) -> Result<circuit::Literal<A>> {
78 use $circuit_operator as Operator;
80 Ok($crate::execute!(match Operator::$operate(inputs) { $( ( $($input),+ ) => $output, )+ }))
82 }
83
84 #[inline]
86 fn output_type(inputs: &[console::program::LiteralType; $num_inputs]) -> Result<console::program::LiteralType> {
87 Ok($crate::output_type!(match inputs { $( ( $($input),+ ) => $output, )+ }))
89 }
90 }
91
92 paste::paste! {
93 #[cfg(test)]
94 mod [<test _ $operate>] {
95 use super::*;
96 use console::types::*;
97
98 type CurrentNetwork = console::network::MainnetV0;
100 type CurrentAleo = circuit::network::AleoV0;
101
102 use $operator as Operator;
104 type Operation = $name::<CurrentNetwork>;
106 $crate::test_execute!(Operator::$operate == Operation::execute { $( ( $($input),+ ) => $output $( ($($condition),+) )?, )+ });
108 }
109 }
110 };
111 ($vis:vis struct $name:ident<$operator:path, $circuit_operator:path, $operate:ident?, $opcode:tt, $num_inputs:tt> { $( ( $($input:ident),+ ) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
113 #[derive(Clone, PartialEq, Eq, Hash)]
115 $vis struct $name<N: Network>(core::marker::PhantomData<N>);
116
117 impl<N: Network> $crate::Operation<N, console::program::Literal<N>, console::program::LiteralType, $num_inputs> for $name<N> {
118 const OPCODE: $crate::Opcode = Opcode::Literal($opcode);
120
121 #[inline]
123 fn evaluate(inputs: &[console::program::Literal<N>; $num_inputs]) -> Result<console::program::Literal<N>> {
124 use $operator as Operator;
126 Ok($crate::evaluate!(match Operator::$operate(inputs)? { $( ( $($input),+ ) => $output, )+ }))
128 }
129
130 #[inline]
132 fn execute<A: circuit::Aleo<Network = N>>(inputs: &[circuit::Literal<A>; $num_inputs]) -> Result<circuit::Literal<A>> {
133 use $circuit_operator as Operator;
135 Ok($crate::execute!(match Operator::$operate(inputs) { $( ( $($input),+ ) => $output, )+ }))
137 }
138
139 #[inline]
141 fn output_type(inputs: &[console::program::LiteralType; $num_inputs]) -> Result<console::program::LiteralType> {
142 Ok($crate::output_type!(match inputs { $( ( $($input),+ ) => $output, )+ }))
144 }
145 }
146
147 paste::paste! {
148 #[cfg(test)]
149 mod [<test _ $operate>] {
150 use super::*;
151 use console::types::*;
152
153 type CurrentNetwork = console::network::MainnetV0;
155 type CurrentAleo = circuit::network::AleoV0;
156
157 use $operator as Operator;
159 type Operation = $name::<CurrentNetwork>;
161 $crate::test_execute!(Operator::$operate == Operation::execute? { $( ( $($input),+ ) => $output $( ($($condition),+) )?, )+ });
163 }
164 }
165 };
166}
167
168#[macro_export]
188macro_rules! evaluate {
189 (match $operator:tt::$operate:tt($inputs:expr) { $( ($input:ident) => $output:ident, )+ }) => {{
191 let [first] = $inputs;
193 match first {
195 $(console::program::Literal::$input(first) => console::program::Literal::$output(first.$operate()),)+
196 _ => bail!("Invalid operand for the '{}' instruction", Self::OPCODE),
197 }
198 }};
199 (match $operator:tt::$operate:tt($inputs:expr)? { $( ( $input:ident ) => $output:ident, )+ }) => {{
201 let [first] = $inputs;
203 match first {
205 $(console::program::Literal::$input(first) => console::program::Literal::$output(first.$operate()?),)+
206 _ => bail!("Invalid operand for the '{}' instruction", Self::OPCODE),
207 }
208 }};
209 (match $operator:tt::$operate:tt($inputs:expr) { $( ($input_a:ident, $input_b:ident) => $output:ident, )+ }) => {{
211 let [first, second] = $inputs;
213 match (first, second) {
215 $((console::program::Literal::$input_a(first), console::program::Literal::$input_b(second)) => console::program::Literal::$output(first.$operate(second)),)+
216 _ => bail!("Invalid operands for the '{}' instruction", Self::OPCODE),
217 }
218 }};
219 (match $operator:tt::$operate:tt($inputs:expr) { $( ($input_a:ident, $input_b:ident, $input_c:ident) => $output:ident, )+ }) => {{
221 let [first, second, third] = $inputs;
223 match (first, second, third) {
225 $((console::program::Literal::$input_a(first), console::program::Literal::$input_b(second), console::program::Literal::$input_c(third)) => console::program::Literal::$output($operator::$operate(first, second, third)),)+
226 _ => bail!("Invalid operands for the '{}' instruction", Self::OPCODE),
227 }
228 }};
229}
230
231#[macro_export]
251macro_rules! execute {
252 (match $operator:tt::$operate:tt($inputs:expr) { $( ($input:ident) => $output:ident, )+ }) => {{
254 let [first] = $inputs.to_owned();
256 match first {
258 $(circuit::Literal::$input(first) => circuit::Literal::$output(first.$operate()),)+
259 _ => bail!("Invalid operand for the '{}' instruction", Self::OPCODE),
260 }
261 }};
262 (match $operator:tt::$operate:tt($inputs:expr) { $( ($input_a:ident, $input_b:ident) => $output:ident, )+ }) => {{
264 let [first, second] = $inputs.to_owned();
266 match (first, second) {
268 $((circuit::Literal::$input_a(first), circuit::Literal::$input_b(second)) => circuit::Literal::$output(first.$operate(&second)),)+
269 _ => bail!("Invalid operands for the '{}' instruction", Self::OPCODE),
270 }
271 }};
272 (match $operator:tt::$operate:tt($inputs:expr) { $( ($input_a:ident, $input_b:ident, $input_c:ident) => $output:ident, )+ }) => {{
274 let [first, second, third] = $inputs.to_owned();
276 match (first, second, third) {
278 $((circuit::Literal::$input_a(first), circuit::Literal::$input_b(second), circuit::Literal::$input_c(third)) => circuit::Literal::$output($operator::$operate(&first, &second, &third)),)+
279 _ => bail!("Invalid operands for the '{}' instruction", Self::OPCODE),
280 }
281 }};
282}
283
284#[macro_export]
304macro_rules! output_type {
305 (match $inputs:ident { $( ($input:ident) => $output:ident, )+ }) => {{
307 let [first] = $inputs;
309 match first {
311 $(console::program::LiteralType::$input => console::program::LiteralType::$output,)+
312 _ => bail!("Invalid operand types for the '{}' instruction", Self::OPCODE),
313 }
314 }};
315 (match $inputs:ident { $( ($input_a:ident, $input_b:ident) => $output:ident, )+ }) => {{
317 let [first, second] = $inputs;
319 match (first, second) {
321 $((console::program::LiteralType::$input_a, console::program::LiteralType::$input_b) => console::program::LiteralType::$output,)+
322 _ => bail!("Invalid operand types for the '{}' instruction", Self::OPCODE),
323 }
324 }};
325 (match $inputs:ident { $( ($input_a:ident, $input_b:ident, $input_c:ident) => $output:ident, )+ }) => {{
327 let [first, second, third] = $inputs;
329 match (first, second, third) {
331 $((console::program::LiteralType::$input_a, console::program::LiteralType::$input_b, console::program::LiteralType::$input_c) => console::program::LiteralType::$output,)+
332 _ => bail!("Invalid operand types for the '{}' instruction", Self::OPCODE),
333 }
334 }};
335}
336
337#[cfg(test)]
338mod tests {
339 #[macro_export]
341 macro_rules! sample_literals {
342 ($network:ident, $rng:expr) => {
343 [
344 console::program::Literal::<$network>::Address(console::types::Address::rand($rng)),
345 console::program::Literal::Boolean(console::types::Boolean::rand($rng)),
346 console::program::Literal::Field(console::types::Field::rand($rng)),
347 console::program::Literal::Group(console::types::Group::rand($rng)),
348 console::program::Literal::I8(console::types::I8::rand($rng)),
349 console::program::Literal::I16(console::types::I16::rand($rng)),
350 console::program::Literal::I32(console::types::I32::rand($rng)),
351 console::program::Literal::I64(console::types::I64::rand($rng)),
352 console::program::Literal::I128(console::types::I128::rand($rng)),
353 console::program::Literal::U8(console::types::U8::rand($rng)),
354 console::program::Literal::U16(console::types::U16::rand($rng)),
355 console::program::Literal::U32(console::types::U32::rand($rng)),
356 console::program::Literal::U64(console::types::U64::rand($rng)),
357 console::program::Literal::U128(console::types::U128::rand($rng)),
358 console::program::Literal::Scalar(console::types::Scalar::rand($rng)),
359 console::program::Literal::sample(console::program::LiteralType::Signature, $rng),
360 console::program::Literal::String(console::types::StringType::rand($rng)),
361 ]
362 };
363 }
364
365 #[macro_export]
395 macro_rules! test_execute {
396 ($operator:tt::$operate:tt == $operation:tt::$execute:tt { $( ($input:ident) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
398 $( $crate::test_execute!{$operator::$operate == $operation::$execute for $input => $output $( ($($condition),+) )?} )+
400 paste::paste! {
402 #[test]
403 fn [<test _ $operate _ fails _ on _ invalid _ operands>]() -> Result<()> {
404 let mut rng = TestRng::default();
406
407 for i in 0..8 {
408 for literal_a in $crate::sample_literals!(CurrentNetwork, &mut rng).iter() {
409 for mode_a in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
410 $(if literal_a.to_type() == console::program::LiteralType::$input {
412 continue;
413 })+
414
415 let result_a = <$operation as $crate::Operation<_, _, _, 1>>::evaluate(&[literal_a.clone()]);
417 assert!(result_a.is_err(), "An invalid operand case (on iteration {i}) did not fail (console): {literal_a}");
419
420 let result_b = <$operation as $crate::Operation<_, _, _, 1>>::$execute::<CurrentAleo>(&[
422 circuit::program::Literal::from_str(&format!("{literal_a}.{mode_a}"))?,
423 ]);
424 assert!(result_b.is_err(), "An invalid operand case (on iteration {i}) did not fail (circuit): {literal_a}");
426 <CurrentAleo as circuit::Environment>::reset();
428 }
429 }
430 }
431 Ok(())
432 }
433 }
434 };
435
436 ($operator:tt::$operate:tt == $operation:tt::$execute:tt? { $( ($input:ident) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
438 $( $crate::test_execute!{$operator::$operate == $operation::$execute (.unwrap()) for $input => $output $( ($($condition),+) )?} )+
440 paste::paste! {
442 #[test]
443 fn [<test _ $operate _ fails _ on _ invalid _ operands>]() -> Result<()> {
444 let mut rng = TestRng::default();
446
447 for i in 0..8 {
448 for literal_a in $crate::sample_literals!(CurrentNetwork, &mut rng).iter() {
449 for mode_a in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
450 $(if literal_a.to_type() == console::program::LiteralType::$input {
452 continue;
453 })+
454
455 let result_a = <$operation as $crate::Operation<_, _, _, 1>>::evaluate(&[literal_a.clone()]);
457 assert!(result_a.is_err(), "An invalid operand case (on iteration {i}) did not fail (console): {literal_a}");
459
460 let result_b = <$operation as $crate::Operation<_, _, _, 1>>::$execute::<CurrentAleo>(&[
462 circuit::program::Literal::from_str(&format!("{literal_a}.{mode_a}"))?,
463 ]);
464 assert!(result_b.is_err(), "An invalid operand case (on iteration {i}) did not fail (circuit): {literal_a}");
466 <CurrentAleo as circuit::Environment>::reset();
468 }
469 }
470 }
471 Ok(())
472 }
473 }
474 };
475
476 ($operator:tt::$operate:tt == $operation:tt::$execute:tt { $( ($input_a:ident, $input_b:ident) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
478 $( $crate::test_execute!{$operator::$operate == $operation::$execute for ($input_a, $input_b) => $output $( ($($condition),+) )?} )+
480
481 paste::paste! {
483 #[test]
484 fn [<test _ $operate _ fails _ on _ invalid _ operands>]() -> Result<()> {
485 let mut rng = TestRng::default();
487
488 for i in 0..8 {
489 for literal_a in $crate::sample_literals!(CurrentNetwork, &mut rng).iter() {
490 for literal_b in $crate::sample_literals!(CurrentNetwork, &mut rng).iter() {
491 for mode_a in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
492 for mode_b in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
493 $(if literal_a.to_type() == console::program::LiteralType::$input_a
495 && literal_b.to_type() == console::program::LiteralType::$input_b {
496 continue;
497 })+
498
499 let result_a = <$operation as $crate::Operation<_, _, _, 2>>::evaluate(&[literal_a.clone(), literal_b.clone()]);
501 assert!(result_a.is_err(), "An invalid operands case (on iteration {i}) did not fail (console): {literal_a} {literal_b}");
503
504 let result_b = <$operation as $crate::Operation<_, _, _, 2>>::$execute::<CurrentAleo>(&[
506 circuit::program::Literal::from_str(&format!("{literal_a}.{mode_a}"))?,
507 circuit::program::Literal::from_str(&format!("{literal_b}.{mode_b}"))?,
508 ]);
509 assert!(result_b.is_err(), "An invalid operands case (on iteration {i}) did not fail (circuit): {literal_a} {literal_b}");
511 <CurrentAleo as circuit::Environment>::reset();
513 }
514 }
515 }
516 }
517 }
518 Ok(())
519 }
520 }
521 };
522
523 ($operator:tt::$operate:tt == $operation:tt::$execute:tt { $( ($input_a:ident, $input_b:ident, $input_c:ident) => $output:ident $( ($($condition:tt),+) )?, )+ }) => {
525 $( $crate::test_execute!{$operator::$operate == $operation::$execute for ($input_a, $input_b, $input_c) => $output $( ($($condition),+) )?} )+
527
528 paste::paste! {
530 #[test]
531 fn [<test _ $operate _ fails _ on _ invalid _ operands>]() -> Result<()> {
532 let mut rng = TestRng::default();
534
535 for literal_a in $crate::sample_literals!(CurrentNetwork, &mut rng).iter() {
536 for literal_b in $crate::sample_literals!(CurrentNetwork, &mut rng).iter() {
537 for literal_c in $crate::sample_literals!(CurrentNetwork, &mut rng).iter() {
538 for mode_a in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
539 for mode_b in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
540 for mode_c in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
541 $(if literal_a.to_type() == console::program::LiteralType::$input_a
543 && literal_b.to_type() == console::program::LiteralType::$input_b
544 && literal_c.to_type() == console::program::LiteralType::$input_c {
545 continue;
546 })+
547
548 let result_a = <$operation as $crate::Operation<_, _, _, 3>>::evaluate(&[literal_a.clone(), literal_b.clone(), literal_c.clone()]);
550 assert!(result_a.is_err(), "An invalid operands case did not fail (console): {literal_a} {literal_b}");
552
553 let result_b = <$operation as $crate::Operation<_, _, _, 3>>::$execute::<CurrentAleo>(&[
555 circuit::program::Literal::from_str(&format!("{literal_a}.{mode_a}"))?,
556 circuit::program::Literal::from_str(&format!("{literal_b}.{mode_b}"))?,
557 circuit::program::Literal::from_str(&format!("{literal_c}.{mode_c}"))?,
558 ]);
559 assert!(result_b.is_err(), "An invalid operands case did not fail (circuit): {literal_a} {literal_b} {literal_c}");
561 <CurrentAleo as circuit::Environment>::reset();
563 }
564 }
565 }
566 }
567 }
568 }
569 Ok(())
570 }
571 }
572 };
573
574 ($operator:tt::$operate:tt == $operation:tt::$execute:tt $((.$unwrap:tt()))? for $input:ident => $output:ident $( ($($condition:tt),+) )?) => {
584 paste::paste! {
585 #[test]
586 fn [<test _ $operate _ $input:lower _ into _ $output:lower>]() -> Result<()> {
587 let mut rng = TestRng::default();
589
590 assert_eq!(
592 console::program::LiteralType::$output,
593 <$operation as $crate::Operation<_, _, _, 1>>::output_type(&[console::program::LiteralType::$input.into()])?
594 );
595
596 for i in 0..150u64 {
598 #[allow(deprecated)]
600 let a = match i {
601 0 => $input::zero(),
602 1.. => $input::<CurrentNetwork>::rand(&mut rng)
603 };
604
605 #[allow(unused_mut)]
607 let mut should_succeed = true;
608 #[allow(unused_macros)]
610 macro_rules! check_condition {
611 ("ensure overflows halt") => {
612 match *<$operation as $crate::Operation<_, _, _, 1>>::OPCODE {
613 "abs" => should_succeed &= (*a).checked_abs().is_some(),
614 "neg" => should_succeed &= (*a).checked_neg().is_some(),
615 _ => panic!("Unsupported test enforcement for '{}'", <$operation as $crate::Operation<_, _, _, 1>>::OPCODE),
616 }
617 };
618 ("ensure inverse of zero halts") => {
619 should_succeed &= !(*a).is_zero()
620 };
621 ("ensure quadratic nonresidues halt") => {
622 should_succeed &= (*a).sqrt().is_some()
623 };
624 }
625 $( $( check_condition!($condition); )+ )?
627
628 let expected = match should_succeed {
630 true => Some(console::program::Literal::$output(a.$operate()$(.$unwrap())?)),
631 false => None
632 };
633
634 for mode_a in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
635 let a = console::program::Literal::from_str(&format!("{a}"))?;
637
638 let first = circuit::program::Literal::from_str(&format!("{a}.{mode_a}"))?;
640
641 if should_succeed {
643 let candidate_a = <$operation as $crate::Operation<_, _, _, 1>>::evaluate(&[a])?;
645 let candidate_b = <$operation as $crate::Operation<_, _, _, 1>>::$execute::<CurrentAleo>(&[first])?;
647
648 assert_eq!(expected, Some(candidate_a));
650 assert_eq!(expected, Some(circuit::Eject::eject_value(&candidate_b)));
652
653 }
654 else {
656 let result_a = std::panic::catch_unwind(|| <$operation as $crate::Operation<_, _, _, 1>>::evaluate(&[a.clone()]).unwrap());
658 assert!(result_a.is_err(), "Failure case (on iteration {i}) did not halt (console): {a}");
660
661 if mode_a.is_constant() {
663 let result_b = std::panic::catch_unwind(|| <$operation as $crate::Operation<_, _, _, 1>>::$execute::<CurrentAleo>(&[first]).unwrap());
665 assert!(result_b.is_err(), "Failure case (on iteration {i}) did not halt (circuit): {a}");
667 } else {
668 let _result_b = <$operation as $crate::Operation<_, _, _, 1>>::$execute::<CurrentAleo>(&[first])?;
670 assert!(!<CurrentAleo as circuit::Environment>::is_satisfied(), "Failure case (on iteration {i}) should not be satisfied (circuit): {a}");
672 }
673 }
674 <CurrentAleo as circuit::Environment>::reset();
676 }
677 }
678
679 Ok(())
680 }
681 }
682 };
683
684 ($operator:tt::$operate:tt == $operation:tt::$execute:tt for ($input_a:ident, $input_b:ident) => $output:ident $( ($($condition:tt),+) )?) => {
693 paste::paste! {
694 #[test]
695 fn [<test _ $operate _ $input_a:lower _ $input_b:lower _ into _ $output:lower>]() -> Result<()> {
696 let mut rng = TestRng::default();
698
699 assert_eq!(
701 console::program::LiteralType::$output,
702 <$operation as $crate::Operation<_, _, _, 2>>::output_type(&[console::program::LiteralType::$input_a.into(), console::program::LiteralType::$input_b.into()])?
703 );
704
705 let num_iterations: u64 = match *<$operation as $crate::Operation<_, _, _, 2>>::OPCODE {
707 "pow" | "pow.w" => 10,
708 _ => 100
709 };
710
711 for i in 0..num_iterations {
713 macro_rules! sample_value {
714 (I8, I8) => { sample_value!(I128, I128) };
715 (I16, I16) => { sample_value!(I128, I128) };
716 (I32, I32) => { sample_value!(I128, I128) };
717 (I64, I64) => { sample_value!(I128, I128) };
718 (I128, I128) => {
719 match i {
720 0 => ($input_a::zero(), $input_b::zero()),
721 1 => ($input_a::<CurrentNetwork>::rand(&mut rng), $input_b::zero()),
722 2 => ($input_a::zero(), $input_b::<CurrentNetwork>::rand(&mut rng)),
723 3 => ($input_a::MIN, $input_b::zero() - $input_b::one()),
724 4.. => ($input_b::<CurrentNetwork>::rand(&mut rng), $input_b::<CurrentNetwork>::rand(&mut rng))
725 }
726 };
727 ($lhs:ident, $rhs:ident) => {
728 match i {
729 0 => ($lhs::zero(), $rhs::zero()),
730 1 => ($lhs::<CurrentNetwork>::rand(&mut rng), $rhs::zero()),
731 2 => ($lhs::zero(), $rhs::<CurrentNetwork>::rand(&mut rng)),
732 3.. => ($lhs::<CurrentNetwork>::rand(&mut rng), $rhs::<CurrentNetwork>::rand(&mut rng))
733 }
734 }
735 }
736 #[allow(deprecated)]
738 let (a, b) = sample_value!($input_a, $input_b);
739
740 #[allow(deprecated)]
742 let is_rhs_zero = (*b) == *$input_b::<CurrentNetwork>::zero();
743
744 #[allow(unused_mut)]
746 let mut should_succeed = true;
747 #[allow(unused_mut)]
748 let mut is_shift_operator = false;
749 #[allow(unused_mut)]
750 let mut shift_exceeds_bitwidth = false;
751 #[allow(unused_mut)]
752 let mut is_division_operator = false;
753 #[allow(unused_macros)]
755 macro_rules! check_condition {
756 ("ensure overflows halt") => {
757 match *<$operation as $crate::Operation<_, _, _, 2>>::OPCODE {
758 "add" => should_succeed &= (*a).checked_add(*b).is_some(),
759 "div" => should_succeed &= (*a).checked_div(*b).is_some(),
760 "mul" => should_succeed &= (*a).checked_mul(*b).is_some(),
761 "rem" => should_succeed &= (*a).checked_rem(*b).is_some(),
762 "sub" => should_succeed &= (*a).checked_sub(*b).is_some(),
763 _ => panic!("Unsupported test enforcement for '{}'", <$operation as $crate::Operation<_, _, _, 2>>::OPCODE),
764 }
765 };
766 ("ensure exponentiation overflows halt") => {
767 should_succeed &= (*a).checked_pow((*b) as u32).is_some()
768 };
769 ("ensure shifting past boundary halts") => {
770 match *<$operation as $crate::Operation<_, _, _, 2>>::OPCODE {
771 "shl" => should_succeed &= console::prelude::CheckedShl::checked_shl(&*a, &(*b as u32)).is_some(),
773 "shr" => should_succeed &= (*a).checked_shr(*b as u32).is_some(),
774 _ => panic!("Unsupported test enforcement for '{}'", <$operation as $crate::Operation<_, _, _, 2>>::OPCODE),
775 }
776 is_shift_operator |= true;
778 let input_a_size_in_bits = u32::try_from($input_a::<CurrentNetwork>::size_in_bits()).expect("Input size in bits exceeded u32::MAX");
779 shift_exceeds_bitwidth |= ((*b as u32) >= input_a_size_in_bits);
780 };
781 ("ensure divide by zero halts") => {
782 should_succeed &= (*b) != *$input_b::<CurrentNetwork>::zero();
783 is_division_operator |= true;
785 };
786 }
787 $( $( check_condition!($condition); )+ )?
789
790 let expected = match should_succeed {
792 true => Some(console::program::Literal::$output(a.$operate(&b))),
793 false => None
794 };
795
796 for mode_a in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
797 for mode_b in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
798 let a = console::program::Literal::from_str(&format!("{a}"))?;
800 let b = console::program::Literal::from_str(&format!("{b}"))?;
801
802 let first = circuit::program::Literal::from_str(&format!("{a}.{mode_a}"))?;
804 let second = circuit::program::Literal::from_str(&format!("{b}.{mode_b}"))?;
805
806 let mut should_panic_on_halt = false;
809 should_panic_on_halt |= is_shift_operator && shift_exceeds_bitwidth && mode_b.is_constant();
811 should_panic_on_halt |= is_division_operator && (
813 mode_b.is_constant() && (mode_a.is_constant() || is_rhs_zero)
814 );
815
816 if should_succeed {
818 let candidate_a = <$operation as $crate::Operation<_, _, _, 2>>::evaluate(&[a, b])?;
820 let candidate_b = <$operation as $crate::Operation<_, _, _, 2>>::$execute::<CurrentAleo>(&[first, second])?;
822
823 assert_eq!(expected, Some(candidate_a));
825 assert_eq!(expected, Some(circuit::Eject::eject_value(&candidate_b)));
827
828 }
829 else {
831 let result_a = std::panic::catch_unwind(|| <$operation as $crate::Operation<_, _, _, 2>>::evaluate(&[a.clone(), b.clone()]).unwrap());
833 assert!(result_a.is_err(), "Failure case (on iteration {i}) did not halt (console): {a} {b}");
835
836 if (mode_a.is_constant() && mode_b.is_constant()) || should_panic_on_halt {
838 let result_b = std::panic::catch_unwind(|| <$operation as $crate::Operation<_, _, _, 2>>::$execute::<CurrentAleo>(&[first, second]).unwrap());
840 assert!(result_b.is_err(), "Failure case (on iteration {i}) did not halt (circuit): {a} {b}");
842 } else {
843 let _result_b = <$operation as $crate::Operation<_, _, _, 2>>::$execute::<CurrentAleo>(&[first, second])?;
845 assert!(!<CurrentAleo as circuit::Environment>::is_satisfied(), "Failure case (on iteration {i}) should not be satisfied (circuit): {a} {b}");
847 }
848 }
849 <CurrentAleo as circuit::Environment>::reset();
851 }
852 }
853 }
854
855 Ok(())
856 }
857 }
858 };
859
860 ($operator:tt::$operate:tt == $operation:tt::$execute:tt for ($input_a:ident, $input_b:ident, $input_c:ident) => $output:ident $( ($($condition:tt),+) )?) => {
869 paste::paste! {
870 #[test]
871 fn [<test _ $operate _ $input_a:lower _ $input_b:lower _ $input_c:lower _ into _ $output:lower>]() -> Result<()> {
872 let mut rng = TestRng::default();
874
875 assert_eq!(
877 console::program::LiteralType::$output,
878 <$operation as $crate::Operation<_, _, _, 3>>::output_type(&[console::program::LiteralType::$input_a.into(), console::program::LiteralType::$input_b.into(), console::program::LiteralType::$input_c.into()])?
879 );
880
881 let num_iterations: u64 = match *<$operation as $crate::Operation<_, _, _, 3>>::OPCODE {
883 _ => 100
884 };
885
886 for i in 0..num_iterations {
888 #[allow(deprecated)]
890 let (a, b, c) = match i {
891 0 => ($input_a::zero(), $input_b::zero(), $input_c::zero()),
892 1 => ($input_a::<CurrentNetwork>::rand(&mut rng), $input_b::<CurrentNetwork>::rand(&mut rng), $input_c::zero()),
893 2 => ($input_a::<CurrentNetwork>::rand(&mut rng), $input_b::zero(), $input_c::<CurrentNetwork>::rand(&mut rng)),
894 3 => ($input_a::<CurrentNetwork>::rand(&mut rng), $input_b::zero(), $input_c::zero()),
895 4 => ($input_a::zero(), $input_b::<CurrentNetwork>::rand(&mut rng), $input_c::<CurrentNetwork>::rand(&mut rng)),
896 5 => ($input_a::zero(), $input_b::<CurrentNetwork>::rand(&mut rng), $input_c::<CurrentNetwork>::zero()),
897 6 => ($input_a::zero(), $input_b::zero(), $input_c::<CurrentNetwork>::rand(&mut rng)),
898 7.. => ($input_a::<CurrentNetwork>::rand(&mut rng), $input_b::<CurrentNetwork>::rand(&mut rng), $input_c::<CurrentNetwork>::rand(&mut rng))
899 };
900
901 #[allow(unused_mut)]
903 let mut should_succeed = true;
904
905 let expected = match should_succeed {
907 true => Some(console::program::Literal::from_str(&format!("{}", $operator::$operate(&a, &b, &c)))?),
908 false => None
909 };
910
911 for mode_a in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
912 for mode_b in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
913 for mode_c in &[circuit::Mode::Constant, circuit::Mode::Public, circuit::Mode::Private] {
914 let a = console::program::Literal::from_str(&format!("{a}"))?;
916 let b = console::program::Literal::from_str(&format!("{b}"))?;
917 let c = console::program::Literal::from_str(&format!("{c}"))?;
918
919 let first = circuit::program::Literal::from_str(&format!("{a}.{mode_a}"))?;
921 let second = circuit::program::Literal::from_str(&format!("{b}.{mode_b}"))?;
922 let third = circuit::program::Literal::from_str(&format!("{c}.{mode_c}"))?;
923
924 if should_succeed {
926 let candidate_a = <$operation as $crate::Operation<_, _, _, 3>>::evaluate(&[a, b, c])?;
928 let candidate_b = <$operation as $crate::Operation<_, _, _, 3>>::$execute::<CurrentAleo>(&[first, second, third])?;
930
931 assert_eq!(expected, Some(candidate_a));
933 assert_eq!(expected, Some(circuit::Eject::eject_value(&candidate_b)));
935 }
936 else {
938 let result_a = std::panic::catch_unwind(|| <$operation as $crate::Operation<_, _, _, 3>>::evaluate(&[a.clone(), b.clone(), c.clone()]).unwrap());
940 assert!(result_a.is_err(), "Failure case (on iteration {i}) did not halt (console): {a} {b} {c}");
942
943 if (mode_a.is_constant() && mode_b.is_constant() && mode_c.is_constant()) {
945 let result_b = std::panic::catch_unwind(|| <$operation as $crate::Operation<_, _, _, 3>>::$execute::<CurrentAleo>(&[first, second, third]).unwrap());
947 assert!(result_b.is_err(), "Failure case (on iteration {i}) did not halt (circuit): {a} {b} {c}");
949 } else {
950 let _result_b = <$operation as $crate::Operation<_, _, _, 3>>::$execute::<CurrentAleo>(&[first, second, third])?;
952 assert!(!<CurrentAleo as circuit::Environment>::is_satisfied(), "Failure case (on iteration {i}) should not be satisfied (circuit): {a} {b} {c}");
954 }
955 }
956 <CurrentAleo as circuit::Environment>::reset();
958 }
959 }
960 }
961 }
962
963 Ok(())
964 }
965 }
966 };
967 }
968}