use super::*;
impl<A: Aleo> Record<A, Ciphertext<A>> {
pub fn decrypt(&self, view_key: &ViewKey<A>) -> Record<A, Plaintext<A>> {
let record_view_key = (&**view_key * &self.nonce).to_x_coordinate();
self.decrypt_symmetric(record_view_key)
}
pub fn decrypt_symmetric(&self, record_view_key: Field<A>) -> Record<A, Plaintext<A>> {
let num_randomizers = self.num_randomizers();
let randomizers = A::hash_many_psd8(&[A::encryption_domain(), record_view_key], num_randomizers);
self.decrypt_with_randomizers(&randomizers)
}
fn decrypt_with_randomizers(&self, randomizers: &[Field<A>]) -> Record<A, Plaintext<A>> {
let mut index: usize = 0;
let owner = match self.owner.is_public().eject_value() {
true => self.owner.decrypt(&[]),
false => self.owner.decrypt(&[randomizers[index].clone()]),
};
if owner.is_private().eject_value() {
index += 1;
}
let gates = match self.gates.is_public().eject_value() {
true => self.gates.decrypt(&[]),
false => self.gates.decrypt(&[randomizers[index].clone()]),
};
if gates.is_private().eject_value() {
index += 1;
}
let mut decrypted_data = IndexMap::with_capacity(self.data.len());
for (id, entry, num_randomizers) in self.data.iter().map(|(id, entry)| (id, entry, entry.num_randomizers())) {
let randomizers = &randomizers[index..index + num_randomizers as usize];
let entry = match entry {
Entry::Constant(plaintext) => Entry::Constant(plaintext.clone()),
Entry::Public(plaintext) => Entry::Public(plaintext.clone()),
Entry::Private(private) => Entry::Private(private.decrypt_with_randomizers(randomizers)),
};
if decrypted_data.insert(id.clone(), entry).is_some() {
A::halt(format!("Duplicate identifier in record: {id}"))
}
index += num_randomizers as usize;
}
Record { owner, gates, data: decrypted_data, nonce: self.nonce.clone() }
}
}
#[cfg(all(test, console))]
mod tests {
use super::*;
use crate::{Circuit, Literal};
use snarkvm_circuit_types::{Address, Field, U64};
use snarkvm_utilities::{TestRng, Uniform};
use anyhow::Result;
const ITERATIONS: u64 = 100;
fn check_encrypt_and_decrypt<A: Aleo>(
view_key: &ViewKey<A>,
owner: Owner<A, Plaintext<A>>,
gates: Balance<A, Plaintext<A>>,
rng: &mut TestRng,
) -> Result<()> {
let randomizer = Scalar::new(Mode::Private, Uniform::rand(rng));
let record = Record {
owner,
gates,
data: IndexMap::from_iter(
vec![
(
Identifier::from_str("a")?,
Entry::Private(Plaintext::from(Literal::Field(Field::new(Mode::Private, Uniform::rand(rng))))),
),
(
Identifier::from_str("b")?,
Entry::Private(Plaintext::from(Literal::Scalar(Scalar::new(
Mode::Private,
Uniform::rand(rng),
)))),
),
]
.into_iter(),
),
nonce: A::g_scalar_multiply(&randomizer),
};
let ciphertext = record.encrypt(&randomizer);
assert_eq!(record.eject(), ciphertext.decrypt(view_key).eject());
Ok(())
}
#[test]
fn test_encrypt_and_decrypt() -> Result<()> {
let mut rng = TestRng::default();
for _ in 0..ITERATIONS {
let private_key = snarkvm_console_account::PrivateKey::<<Circuit as Environment>::Network>::new(&mut rng)?;
let view_key = snarkvm_console_account::ViewKey::try_from(private_key)?;
let address = snarkvm_console_account::Address::try_from(private_key)?;
let view_key = ViewKey::<Circuit>::new(Mode::Private, view_key);
let owner = address;
{
let owner = Owner::Public(Address::<Circuit>::new(Mode::Public, owner));
let gates = Balance::Public(U64::new(Mode::Public, console::U64::new(u64::rand(&mut rng) >> 12)));
check_encrypt_and_decrypt::<Circuit>(&view_key, owner, gates, &mut rng)?;
}
{
let owner =
Owner::Private(Plaintext::from(Literal::Address(Address::<Circuit>::new(Mode::Private, owner))));
let gates = Balance::Public(U64::new(Mode::Public, console::U64::new(u64::rand(&mut rng) >> 12)));
check_encrypt_and_decrypt::<Circuit>(&view_key, owner, gates, &mut rng)?;
}
{
let owner = Owner::Public(Address::<Circuit>::new(Mode::Public, owner));
let gates = Balance::Private(Plaintext::from(Literal::U64(U64::new(
Mode::Private,
console::U64::new(u64::rand(&mut rng) >> 12),
))));
check_encrypt_and_decrypt::<Circuit>(&view_key, owner, gates, &mut rng)?;
}
{
let owner =
Owner::Private(Plaintext::from(Literal::Address(Address::<Circuit>::new(Mode::Private, owner))));
let gates = Balance::Private(Plaintext::from(Literal::U64(U64::new(
Mode::Private,
console::U64::new(u64::rand(&mut rng) >> 12),
))));
check_encrypt_and_decrypt::<Circuit>(&view_key, owner, gates, &mut rng)?;
}
}
Ok(())
}
}