#[cfg(test)]
use snarkvm_circuit_types::environment::assert_scope;
mod to_tpk;
mod verify;
use crate::{Identifier, Plaintext, ProgramID, Record, Value};
use snarkvm_circuit_account::Signature;
use snarkvm_circuit_network::Aleo;
use snarkvm_circuit_types::{environment::prelude::*, Address, Boolean, Equal, Field, Group, Scalar, U16};
pub enum InputID<A: Aleo> {
Constant(Field<A>),
Public(Field<A>),
Private(Field<A>),
Record(Field<A>, Box<Group<A>>, Field<A>, Field<A>),
ExternalRecord(Field<A>),
}
#[cfg(console)]
impl<A: Aleo> Inject for InputID<A> {
type Primitive = console::InputID<A::Network>;
fn new(_: Mode, input: Self::Primitive) -> Self {
match input {
console::InputID::Constant(field) => Self::Constant(Field::new(Mode::Public, field)),
console::InputID::Public(field) => Self::Public(Field::new(Mode::Public, field)),
console::InputID::Private(field) => Self::Private(Field::new(Mode::Public, field)),
console::InputID::Record(commitment, gamma, serial_number, tag) => Self::Record(
Field::new(Mode::Private, commitment),
Box::new(Group::new(Mode::Private, gamma)),
Field::new(Mode::Public, serial_number),
Field::new(Mode::Public, tag),
),
console::InputID::ExternalRecord(field) => Self::ExternalRecord(Field::new(Mode::Public, field)),
}
}
}
#[cfg(console)]
impl<A: Aleo> Eject for InputID<A> {
type Primitive = console::InputID<A::Network>;
fn eject_mode(&self) -> Mode {
match self {
Self::Constant(field) => field.eject_mode(),
Self::Public(field) => field.eject_mode(),
Self::Private(field) => field.eject_mode(),
Self::Record(commitment, gamma, serial_number, tag) => Mode::combine(commitment.eject_mode(), [
gamma.eject_mode(),
serial_number.eject_mode(),
tag.eject_mode(),
]),
Self::ExternalRecord(field) => field.eject_mode(),
}
}
fn eject_value(&self) -> Self::Primitive {
match self {
Self::Constant(field) => console::InputID::Constant(field.eject_value()),
Self::Public(field) => console::InputID::Public(field.eject_value()),
Self::Private(field) => console::InputID::Private(field.eject_value()),
Self::Record(commitment, gamma, serial_number, tag) => console::InputID::Record(
commitment.eject_value(),
gamma.eject_value(),
serial_number.eject_value(),
tag.eject_value(),
),
Self::ExternalRecord(field) => console::InputID::ExternalRecord(field.eject_value()),
}
}
}
impl<A: Aleo> ToFields for InputID<A> {
type Field = Field<A>;
fn to_fields(&self) -> Vec<Self::Field> {
match self {
InputID::Constant(field) => vec![field.clone()],
InputID::Public(field) => vec![field.clone()],
InputID::Private(field) => vec![field.clone()],
InputID::Record(commitment, gamma, serial_number, tag) => {
vec![commitment.clone(), gamma.to_x_coordinate(), serial_number.clone(), tag.clone()]
}
InputID::ExternalRecord(field) => vec![field.clone()],
}
}
}
pub struct Request<A: Aleo> {
caller: Address<A>,
network_id: U16<A>,
program_id: ProgramID<A>,
function_name: Identifier<A>,
input_ids: Vec<InputID<A>>,
inputs: Vec<Value<A>>,
signature: Signature<A>,
sk_tag: Field<A>,
tvk: Field<A>,
tsk: Scalar<A>,
tcm: Field<A>,
}
#[cfg(console)]
impl<A: Aleo> Inject for Request<A> {
type Primitive = console::Request<A::Network>;
fn new(mode: Mode, request: Self::Primitive) -> Self {
let tcm = Field::new(Mode::Public, *request.tcm());
let inputs = match request
.input_ids()
.iter()
.zip_eq(request.inputs())
.map(|(input_id, input)| {
match input_id {
console::InputID::Constant(..) => {
let input = Value::new(Mode::Constant, input.clone());
ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
Ok(input)
}
console::InputID::Public(..) => {
let input = Value::new(Mode::Private, input.clone());
ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
Ok(input)
}
console::InputID::Private(..) => {
let input = Value::new(Mode::Private, input.clone());
ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
Ok(input)
}
console::InputID::Record(..) => {
let input = Value::new(Mode::Private, input.clone());
ensure!(matches!(input, Value::Record(..)), "Expected a record input");
Ok(input)
}
console::InputID::ExternalRecord(..) => {
let input = Value::new(Mode::Private, input.clone());
ensure!(matches!(input, Value::Record(..)), "Expected an external record input");
Ok(input)
}
}
})
.collect::<Result<Vec<_>, _>>()
{
Ok(inputs) => inputs,
Err(error) => A::halt(format!("{error}")),
};
Self {
caller: Address::new(mode, *request.caller()),
network_id: U16::new(Mode::Constant, *request.network_id()),
program_id: ProgramID::new(Mode::Constant, *request.program_id()),
function_name: Identifier::new(Mode::Constant, *request.function_name()),
input_ids: request.input_ids().iter().map(|input_id| InputID::new(Mode::Public, *input_id)).collect(),
inputs,
signature: Signature::new(mode, *request.signature()),
sk_tag: Field::new(mode, *request.sk_tag()),
tvk: Field::new(mode, *request.tvk()),
tsk: Scalar::new(mode, *request.tsk()),
tcm,
}
}
}
impl<A: Aleo> Request<A> {
pub const fn caller(&self) -> &Address<A> {
&self.caller
}
pub const fn network_id(&self) -> &U16<A> {
&self.network_id
}
pub const fn program_id(&self) -> &ProgramID<A> {
&self.program_id
}
pub const fn function_name(&self) -> &Identifier<A> {
&self.function_name
}
pub fn input_ids(&self) -> &[InputID<A>] {
&self.input_ids
}
pub fn inputs(&self) -> &[Value<A>] {
&self.inputs
}
pub const fn signature(&self) -> &Signature<A> {
&self.signature
}
pub const fn sk_tag(&self) -> &Field<A> {
&self.sk_tag
}
pub const fn tvk(&self) -> &Field<A> {
&self.tvk
}
pub const fn tsk(&self) -> &Scalar<A> {
&self.tsk
}
pub const fn tcm(&self) -> &Field<A> {
&self.tcm
}
}
#[cfg(console)]
impl<A: Aleo> Eject for Request<A> {
type Primitive = console::Request<A::Network>;
fn eject_mode(&self) -> Mode {
Mode::combine(self.caller.eject_mode(), [
self.network_id.eject_mode(),
self.program_id.eject_mode(),
self.function_name.eject_mode(),
self.input_ids.eject_mode(),
self.inputs.eject_mode(),
self.signature.eject_mode(),
self.sk_tag.eject_mode(),
self.tvk.eject_mode(),
self.tsk.eject_mode(),
self.tcm.eject_mode(),
])
}
fn eject_value(&self) -> Self::Primitive {
Self::Primitive::from((
self.caller.eject_value(),
self.network_id.eject_value(),
self.program_id.eject_value(),
self.function_name.eject_value(),
self.input_ids.iter().map(|input_id| input_id.eject_value()).collect(),
self.inputs.eject_value(),
self.signature.eject_value(),
self.sk_tag.eject_value(),
self.tvk.eject_value(),
self.tsk.eject_value(),
self.tcm.eject_value(),
))
}
}