mod equal;
mod to_bits;
mod to_fields;
use snarkvm_circuit_network::Aleo;
use snarkvm_circuit_types::{Boolean, Field, environment::prelude::*};
#[derive(Clone)]
pub struct DynamicFuture<A: Aleo> {
program_name: Field<A>,
program_network: Field<A>,
function_name: Field<A>,
checksum: Field<A>,
arguments: Option<Vec<console::Argument<A::Network>>>,
}
impl<A: Aleo> Inject for DynamicFuture<A> {
type Primitive = console::DynamicFuture<A::Network>;
fn new(mode: Mode, value: Self::Primitive) -> Self {
DynamicFuture {
program_name: Inject::new(mode, *value.program_name()),
program_network: Inject::new(mode, *value.program_network()),
function_name: Inject::new(mode, *value.function_name()),
checksum: Inject::new(mode, *value.checksum()),
arguments: value.arguments().clone(),
}
}
}
impl<A: Aleo> DynamicFuture<A> {
pub const fn program_name(&self) -> &Field<A> {
&self.program_name
}
pub const fn program_network(&self) -> &Field<A> {
&self.program_network
}
pub const fn function_name(&self) -> &Field<A> {
&self.function_name
}
pub const fn checksum(&self) -> &Field<A> {
&self.checksum
}
pub const fn arguments(&self) -> &Option<Vec<console::Argument<A::Network>>> {
&self.arguments
}
}
impl<A: Aleo> Eject for DynamicFuture<A> {
type Primitive = console::DynamicFuture<A::Network>;
fn eject_mode(&self) -> Mode {
let program_name_mode = Eject::eject_mode(self.program_name());
let program_network_mode = Eject::eject_mode(self.program_network());
let function_name_mode = Eject::eject_mode(self.function_name());
let checksum_mode = Eject::eject_mode(self.checksum());
Mode::combine(program_name_mode, [program_network_mode, function_name_mode, checksum_mode])
}
fn eject_value(&self) -> Self::Primitive {
Self::Primitive::new_unchecked(
Eject::eject_value(self.program_name()),
Eject::eject_value(self.program_network()),
Eject::eject_value(self.function_name()),
Eject::eject_value(self.checksum()),
self.arguments.clone(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Circuit, console::ToFields as ConsoleToFields};
use snarkvm_circuit_types::environment::Inject;
use core::str::FromStr;
type CurrentNetwork = <Circuit as Environment>::Network;
type ConsoleFuture = console::Future<CurrentNetwork>;
type ConsoleDynamicFuture = console::DynamicFuture<CurrentNetwork>;
fn create_test_future(args: Vec<console::Argument<CurrentNetwork>>) -> ConsoleFuture {
ConsoleFuture::new(
console::ProgramID::from_str("test.aleo").unwrap(),
console::Identifier::from_str("foo").unwrap(),
args,
)
}
fn check_inject_eject(console_dynamic: &ConsoleDynamicFuture) {
let circuit_dynamic = DynamicFuture::<Circuit>::new(Mode::Private, console_dynamic.clone());
assert_eq!(circuit_dynamic.program_name().eject_value(), *console_dynamic.program_name());
assert_eq!(circuit_dynamic.program_network().eject_value(), *console_dynamic.program_network());
assert_eq!(circuit_dynamic.function_name().eject_value(), *console_dynamic.function_name());
assert_eq!(circuit_dynamic.checksum().eject_value(), *console_dynamic.checksum());
let ejected = circuit_dynamic.eject_value();
assert_eq!(ejected.program_name(), console_dynamic.program_name());
assert_eq!(ejected.program_network(), console_dynamic.program_network());
assert_eq!(ejected.function_name(), console_dynamic.function_name());
assert_eq!(ejected.checksum(), console_dynamic.checksum());
Circuit::reset();
}
fn check_to_bits_le(console_dynamic: &ConsoleDynamicFuture) {
let circuit_dynamic = DynamicFuture::<Circuit>::new(Mode::Private, console_dynamic.clone());
Circuit::scope("to_bits_le", || {
let circuit_bits = circuit_dynamic.to_bits_le();
let console_bits = console_dynamic.to_bits_le();
for (circuit_bit, console_bit) in circuit_bits.iter().zip_eq(console_bits.iter()) {
assert_eq!(circuit_bit.eject_value(), *console_bit, "Circuit and console bits must match");
}
});
Circuit::reset();
}
fn check_to_fields(console_dynamic: &ConsoleDynamicFuture) {
let circuit_dynamic = DynamicFuture::<Circuit>::new(Mode::Private, console_dynamic.clone());
Circuit::scope("to_fields", || {
let circuit_fields = circuit_dynamic.to_fields();
let console_fields = console_dynamic.to_fields().unwrap();
for (circuit_field, console_field) in circuit_fields.iter().zip_eq(console_fields.iter()) {
assert_eq!(circuit_field.eject_value(), *console_field, "Circuit and console fields must match");
}
});
Circuit::reset();
}
#[test]
fn test_inject_eject_no_arguments() {
let future = create_test_future(vec![]);
let dynamic = ConsoleDynamicFuture::from_future(&future).unwrap();
check_inject_eject(&dynamic);
}
#[test]
fn test_inject_eject_with_arguments() {
let args = vec![
console::Argument::Plaintext(console::Plaintext::from_str("100u64").unwrap()),
console::Argument::Plaintext(console::Plaintext::from_str("true").unwrap()),
];
let future = create_test_future(args);
let dynamic = ConsoleDynamicFuture::from_future(&future).unwrap();
check_inject_eject(&dynamic);
}
#[test]
fn test_to_bits_le_console_circuit_equivalence() {
let args = vec![console::Argument::Plaintext(console::Plaintext::from_str("42u64").unwrap())];
let future = create_test_future(args);
let dynamic = ConsoleDynamicFuture::from_future(&future).unwrap();
check_to_bits_le(&dynamic);
}
#[test]
fn test_to_fields_console_circuit_equivalence() {
let args = vec![console::Argument::Plaintext(console::Plaintext::from_str("42u64").unwrap())];
let future = create_test_future(args);
let dynamic = ConsoleDynamicFuture::from_future(&future).unwrap();
check_to_fields(&dynamic);
}
#[test]
fn test_to_fields_no_arguments() {
let future = create_test_future(vec![]);
let dynamic = ConsoleDynamicFuture::from_future(&future).unwrap();
check_to_fields(&dynamic);
}
}