mod to_tpk;
mod verify;
use crate::{Identifier, Plaintext, ProgramID, Record, Value, compute_function_id};
use snarkvm_circuit_account::Signature;
use snarkvm_circuit_network::Aleo;
use snarkvm_circuit_types::{Address, Boolean, Field, Group, U16, environment::prelude::*};
pub enum InputID<A: Aleo> {
Constant(Field<A>),
Public(Field<A>),
Private(Field<A>),
Record(Field<A>, Box<Group<A>>, Field<A>, Field<A>, Field<A>),
ExternalRecord(Field<A>),
DynamicRecord(Field<A>),
}
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, record_view_key, serial_number, tag) => Self::Record(
Field::new(Mode::Private, commitment),
Box::new(Group::new(Mode::Private, gamma)),
Field::new(Mode::Private, record_view_key),
Field::new(Mode::Public, serial_number),
Field::new(Mode::Public, tag),
),
console::InputID::ExternalRecord(field) => Self::ExternalRecord(Field::new(Mode::Public, field)),
console::InputID::DynamicRecord(field) => Self::DynamicRecord(Field::new(Mode::Public, field)),
}
}
}
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, record_view_key, serial_number, tag) => {
Mode::combine(commitment.eject_mode(), [
gamma.eject_mode(),
record_view_key.eject_mode(),
serial_number.eject_mode(),
tag.eject_mode(),
])
}
Self::ExternalRecord(field) => field.eject_mode(),
Self::DynamicRecord(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, record_view_key, serial_number, tag) => console::InputID::Record(
commitment.eject_value(),
gamma.eject_value(),
record_view_key.eject_value(),
serial_number.eject_value(),
tag.eject_value(),
),
Self::ExternalRecord(field) => console::InputID::ExternalRecord(field.eject_value()),
Self::DynamicRecord(field) => console::InputID::DynamicRecord(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, record_view_key, serial_number, tag) => {
vec![
commitment.clone(),
gamma.to_x_coordinate(),
record_view_key.clone(),
serial_number.clone(),
tag.clone(),
]
}
InputID::ExternalRecord(field) => vec![field.clone()],
InputID::DynamicRecord(field) => vec![field.clone()],
}
}
}
pub struct Request<A: Aleo> {
signer: 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>,
tcm: Field<A>,
scm: Field<A>,
is_dynamic: bool,
}
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 scm = Field::new(Mode::Public, *request.scm());
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)
}
console::InputID::DynamicRecord(..) => {
let input = Value::new(Mode::Private, input.clone());
ensure!(matches!(input, Value::DynamicRecord(..)), "Expected a dynamic record input");
Ok(input)
}
}
})
.collect::<Result<Vec<_>, _>>()
{
Ok(inputs) => inputs,
Err(error) => A::halt(format!("{error}")),
};
Self {
signer: Address::new(mode, *request.signer()),
network_id: U16::new(Mode::Constant, *request.network_id()),
program_id: ProgramID::constant(*request.program_id()),
function_name: Identifier::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()),
tcm,
scm,
is_dynamic: request.is_dynamic(),
}
}
}
impl<A: Aleo> Request<A> {
pub const fn signer(&self) -> &Address<A> {
&self.signer
}
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 tcm(&self) -> &Field<A> {
&self.tcm
}
pub const fn scm(&self) -> &Field<A> {
&self.scm
}
pub fn is_dynamic(&self) -> bool {
self.is_dynamic
}
}
impl<A: Aleo> Eject for Request<A> {
type Primitive = console::Request<A::Network>;
fn eject_mode(&self) -> Mode {
Mode::combine(self.signer.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.tcm.eject_mode(),
self.scm.eject_mode(),
])
}
fn eject_value(&self) -> Self::Primitive {
Self::Primitive::from((
self.signer.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.tcm.eject_value(),
self.scm.eject_value(),
self.is_dynamic,
))
}
}