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
// Copyright (C) 2019-2023 Aleo Systems Inc.
// This file is part of the snarkVM library.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// The `witness!` macro is a closure that takes in a list of circuits,
/// eject the value of each circuit, and uses it in the subsequent code block.
///
/// This macro requires `Inject` to be implemented on the return type,
/// and `Eject` to be implemented on all inputs.
#[macro_export]
macro_rules! witness {
(| $($circuit:ident),* | $block:block) => {{
// Determine the witness mode, by checking if all given circuits are constant.
let mode = witness_mode!($( $circuit ),*);
E::new_witness(mode, || {
// Reassign each circuit to its primitive type.
$( let rename_selfs!($circuit) = $circuit.eject_value(); )*
// Execute the code block, returning the primitive to be injected.
rename_selfs!($block)
})
}};
(| $($circuit:ident),* | $logic:expr) => {{
witness!(| $($circuit),* | { $logic })
}};
}
/// The `witness_mode!` macro returns the expected mode given a list of circuits.
#[macro_export]
macro_rules! witness_mode {
($($circuit:ident),*) => {{
// Determine the witness mode, by checking if all given circuits are constant.
match $( $circuit.is_constant() & )* true {
true => Mode::Constant,
false => Mode::Private
}
}}
}
#[cfg(test)]
mod tests {
use crate::*;
/// A dummy struct for testing `witness!`.
pub struct Foo(Mode, u8);
impl Inject for Foo {
type Primitive = u8;
fn new(mode: Mode, value: Self::Primitive) -> Self {
Self(mode, value)
}
}
impl Eject for Foo {
type Primitive = u8;
fn eject_mode(&self) -> Mode {
self.0
}
fn eject_value(&self) -> Self::Primitive {
self.1
}
}
fn check_witness<E: Environment>(expected_mode: Mode, mode_a: Mode, mode_b: Mode) {
let x = Foo::new(mode_a, 3);
let y = Foo::new(mode_b, 5);
let z: Foo = witness!(|x, y| { x + y });
assert_eq!(expected_mode, z.eject_mode());
assert_eq!(8, z.eject_value());
}
#[test]
fn test_witness_constant() {
check_witness::<Circuit>(Mode::Constant, Mode::Constant, Mode::Constant);
}
#[test]
fn test_witness_private() {
check_witness::<Circuit>(Mode::Private, Mode::Constant, Mode::Private);
}
}