mod bytes;
mod serialize;
mod string;
use crate::{Identifier, Plaintext, ProgramID, Record, Value};
use snarkvm_console_account::ViewKey;
use snarkvm_console_network::Network;
use snarkvm_console_types::prelude::*;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum InputID<N: Network> {
Constant(Field<N>),
Public(Field<N>),
Private(Field<N>),
Record(Field<N>, Group<N>, Field<N>, Field<N>, Field<N>),
ExternalRecord(Field<N>),
DynamicRecord(Field<N>),
}
impl<N: Network> InputID<N> {
pub const fn id(&self) -> &Field<N> {
match self {
InputID::Constant(id) => id,
InputID::Public(id) => id,
InputID::Private(id) => id,
InputID::Record(id, ..) => id,
InputID::ExternalRecord(id) => id,
InputID::DynamicRecord(id) => id,
}
}
pub fn constant(function_id: Field<N>, input: &Value<N>, tcm: Field<N>, index: u16) -> Result<Self> {
ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
let index = Field::from_u16(index);
let mut preimage = Vec::new();
preimage.push(function_id);
preimage.extend(input.to_fields()?);
preimage.push(tcm);
preimage.push(index);
let hash = N::hash_psd8(&preimage)?;
Ok(Self::Constant(hash))
}
pub fn public(function_id: Field<N>, input: &Value<N>, tcm: Field<N>, index: u16) -> Result<Self> {
ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
let index = Field::from_u16(index);
let mut preimage = Vec::new();
preimage.push(function_id);
preimage.extend(input.to_fields()?);
preimage.push(tcm);
preimage.push(index);
let hash = N::hash_psd8(&preimage)?;
Ok(Self::Public(hash))
}
pub fn private(function_id: Field<N>, input: &Value<N>, tvk: Field<N>, index: u16) -> Result<Self> {
ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
let index = Field::from_u16(index);
let input_view_key = N::hash_psd4(&[function_id, tvk, index])?;
let ciphertext = match &input {
Value::Plaintext(plaintext) => plaintext.encrypt_symmetric(input_view_key)?,
Value::Record(..) => bail!("Expected a plaintext input, found a record input"),
Value::Future(..) => bail!("Expected a plaintext input, found a future input"),
Value::DynamicRecord(..) => bail!("Expected a plaintext input, found a dynamic record input"),
Value::DynamicFuture(..) => bail!("Expected a plaintext input, found a dynamic future input"),
};
let hash = N::hash_psd8(&ciphertext.to_fields()?)?;
Ok(Self::Private(hash))
}
pub fn record(
program_id: &ProgramID<N>,
record_name: &Identifier<N>,
input: &Value<N>,
signer: &Address<N>,
view_key: &ViewKey<N>,
sk_sig: &Scalar<N>,
sk_tag: Field<N>,
) -> Result<Self> {
let record = match &input {
Value::Record(record) => record,
Value::Plaintext(..) => bail!("Expected a record input, found a plaintext input"),
Value::Future(..) => bail!("Expected a record input, found a future input"),
Value::DynamicRecord(..) => bail!("Expected a record input, found a dynamic record input"),
Value::DynamicFuture(..) => bail!("Expected a record input, found a dynamic future input"),
};
ensure!(**record.owner() == *signer, "Input record '{program_id}/{record_name}' must belong to the signer");
let record_view_key = (*record.nonce() * **view_key).to_x_coordinate();
let commitment = record.to_commitment(program_id, record_name, &record_view_key)?;
let h = N::hash_to_group_psd2(&[N::serial_number_domain(), commitment])?;
let gamma = h * sk_sig;
let serial_number = Record::<N, Plaintext<N>>::serial_number_from_gamma(&gamma, commitment)?;
let tag = Record::<N, Plaintext<N>>::tag(sk_tag, commitment)?;
Ok(InputID::Record(commitment, gamma, record_view_key, serial_number, tag))
}
pub fn external_record(function_id: Field<N>, input: &Value<N>, tvk: Field<N>, index: u16) -> Result<Self> {
ensure!(matches!(input, Value::Record(..)), "Expected a record input");
let index = Field::from_u16(index);
let mut preimage = Vec::new();
preimage.push(function_id);
preimage.extend(input.to_fields()?);
preimage.push(tvk);
preimage.push(index);
let hash = N::hash_psd8(&preimage)?;
Ok(Self::ExternalRecord(hash))
}
pub fn dynamic_record(function_id: Field<N>, input: &Value<N>, tvk: Field<N>, index: u16) -> Result<Self> {
ensure!(matches!(input, Value::DynamicRecord(..)), "Expected a dynamic record input");
let index = Field::from_u16(index);
let mut preimage = Vec::new();
preimage.push(function_id);
preimage.extend(input.to_fields()?);
preimage.push(tvk);
preimage.push(index);
let hash = N::hash_psd8(&preimage)?;
Ok(Self::DynamicRecord(hash))
}
}