use console::{
network::Network,
types::{Field, Group},
};
pub struct Input<N: Network> {
serial_number: Field<N>,
bcm: Group<N>,
}
impl<N: Network> Input<N> {
pub const fn new(serial_number: Field<N>, bcm: Group<N>) -> Self {
Self { serial_number, bcm }
}
pub const fn serial_number(&self) -> Field<N> {
self.serial_number
}
pub const fn bcm(&self) -> Group<N> {
self.bcm
}
}
pub mod circuit {
use circuit::{
merkle_tree::MerklePath,
transition::Record,
Aleo,
Eject,
Field,
Group,
Inject,
Mode,
Scalar,
SerialNumber,
ToBits,
ToGroup,
Zero,
U64,
};
use anyhow::{ensure, Result};
pub struct Public<A: Aleo> {
root: Field<A>,
serial_number: Field<A>,
bcm: Group<A>,
fcm: Group<A>,
tcm: Field<A>,
tpk: Group<A>,
}
impl<A: Aleo> Public<A> {
pub fn from(
root: console::types::Field<A::Network>,
serial_number: console::types::Field<A::Network>,
bcm: console::types::Group<A::Network>,
fcm: console::types::Group<A::Network>,
tcm: console::types::Field<A::Network>,
tpk: console::types::Group<A::Network>,
) -> Self {
Self {
root: Field::new(Mode::Public, root),
serial_number: Field::new(Mode::Public, serial_number),
bcm: Group::new(Mode::Public, bcm),
fcm: Group::new(Mode::Public, fcm),
tcm: Field::new(Mode::Public, tcm),
tpk: Group::new(Mode::Public, tpk),
}
}
}
pub struct Private<A: Aleo> {
record_view_key: Field<A>,
record: Record<A>,
merkle_path: MerklePath<A, 32>,
serial_number: SerialNumber<A>,
r_fcm: Scalar<A>,
r_tcm: Field<A>,
}
impl<A: Aleo> Private<A> {
pub fn from(
record_view_key: console::types::Field<A::Network>,
record: console::transition::Record<A::Network>,
merkle_path: console::collections::merkle_tree::MerklePath<A::Network, 32>,
serial_number: console::transition::SerialNumber<A::Network>,
r_fcm: console::types::Scalar<A::Network>,
r_tcm: console::types::Field<A::Network>,
) -> Self {
Self {
record_view_key: Field::new(Mode::Private, record_view_key),
record: Record::new(Mode::Private, record),
merkle_path: MerklePath::new(Mode::Private, merkle_path),
serial_number: SerialNumber::new(Mode::Private, serial_number),
r_fcm: Scalar::new(Mode::Private, r_fcm),
r_tcm: Field::new(Mode::Private, r_tcm),
}
}
}
pub struct InputCircuit<A: Aleo>(Public<A>, Private<A>);
impl<A: Aleo> InputCircuit<A> {
pub fn from(public: Public<A>, private: Private<A>) -> Result<Self> {
let Public { root, serial_number, bcm, fcm, tcm, tpk } = &public;
ensure!(root.eject_mode().is_public(), "Input root must be public");
ensure!(serial_number.eject_mode().is_public(), "Input serial number must be public");
ensure!(bcm.eject_mode().is_public(), "Balance commitment must be public");
ensure!(fcm.eject_mode().is_public(), "Fee commitment must be public");
ensure!(tcm.eject_mode().is_public(), "Transition view key commitment must be public");
ensure!(tpk.eject_mode().is_public(), "Transition public key must be public");
let Private { record_view_key, record, merkle_path, serial_number, r_fcm, r_tcm } = &private;
ensure!(record_view_key.eject_mode().is_private(), "Input record view key must be private");
ensure!(record.eject_mode().is_private(), "Input record must be private");
ensure!(merkle_path.eject_mode().is_private(), "Input commitment Merkle path must be private");
ensure!(serial_number.eject_mode().is_private(), "Input serial number proof must be private");
ensure!(r_fcm.eject_mode().is_private(), "Fee randomizer must be private");
ensure!(r_tcm.eject_mode().is_private(), "Transition view key commitment randomizer must be private");
Ok(Self(public, private))
}
pub fn execute(&self) {
let (public, private) = (&self.0, &self.1);
let state = private.record.decrypt_symmetric(&private.record_view_key);
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
let tsk = A::hash_to_scalar_psd2(&[private.r_tcm.clone()]);
A::assert_eq(&public.tpk, &A::g_scalar_multiply(&tsk));
let tvk = state.owner().to_group() * tsk;
let preimage = [&state.owner().to_group(), &public.tpk, &tvk].map(|c| c.to_x_coordinate());
A::assert_eq(&public.tcm, &A::hash_psd4(&preimage));
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
let r_bcm = A::hash_to_scalar_psd2(&[A::r_bcm_domain(), private.record_view_key.clone()]);
A::assert_eq(&public.bcm, private.record.bcm() + &A::commit_ped64(&U64::zero().to_bits_le(), &r_bcm));
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
A::assert_eq(&public.fcm, A::commit_ped64(&U64::zero().to_bits_le(), &private.r_fcm));
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
let commitment = private.record.to_commitment();
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
A::assert(A::verify_merkle_path_bhp(&private.merkle_path, &public.root, &commitment.to_bits_le()));
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
A::assert(private.serial_number.verify(state.owner(), &[], &commitment));
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
A::assert_eq(&public.serial_number, private.serial_number.value());
println!("Is satisfied? {} ({} constraints)", A::is_satisfied(), A::num_constraints());
}
}
}