snarkvm_circuit_program/data/record/
decrypt.rs1use super::*;
17
18impl<A: Aleo> Record<A, Ciphertext<A>> {
19 pub fn decrypt(&self, view_key: &ViewKey<A>) -> Record<A, Plaintext<A>> {
21 let record_view_key = (&**view_key * &self.nonce).to_x_coordinate();
23 let record = self.decrypt_symmetric_unchecked(record_view_key);
25 A::assert_eq(view_key.to_address(), record.owner().deref());
27 record
29 }
30
31 pub fn decrypt_symmetric_unchecked(&self, record_view_key: Field<A>) -> Record<A, Plaintext<A>> {
35 let num_randomizers = self.num_randomizers();
37 let randomizers = A::hash_many_psd8(&[A::encryption_domain(), record_view_key], num_randomizers);
39 self.decrypt_with_randomizers(&randomizers)
41 }
42
43 fn decrypt_with_randomizers(&self, randomizers: &[Field<A>]) -> Record<A, Plaintext<A>> {
45 let mut index: usize = 0;
47
48 let owner = match self.owner.is_public().eject_value() {
50 true => self.owner.decrypt(&[]),
51 false => self.owner.decrypt(&[randomizers[index].clone()]),
52 };
53
54 if owner.is_private().eject_value() {
56 index += 1;
57 }
58
59 let mut decrypted_data = IndexMap::with_capacity(self.data.len());
61 for (id, entry, num_randomizers) in self.data.iter().map(|(id, entry)| (id, entry, entry.num_randomizers())) {
62 let randomizers = &randomizers[index..index + num_randomizers as usize];
64 let entry = match entry {
66 Entry::Constant(plaintext) => Entry::Constant(plaintext.clone()),
68 Entry::Public(plaintext) => Entry::Public(plaintext.clone()),
70 Entry::Private(private) => Entry::Private(private.decrypt_with_randomizers(randomizers)),
72 };
73 if decrypted_data.insert(id.clone(), entry).is_some() {
75 A::halt(format!("Duplicate identifier in record: {id}"))
76 }
77 index += num_randomizers as usize;
79 }
80
81 Record { owner, data: decrypted_data, nonce: self.nonce.clone(), version: self.version.clone() }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::{Circuit, Literal};
90 use snarkvm_circuit_types::{Address, Field};
91 use snarkvm_utilities::{TestRng, Uniform};
92
93 use anyhow::Result;
94
95 const ITERATIONS: u64 = 100;
96
97 fn check_encrypt_and_decrypt<A: Aleo>(
98 view_key: &ViewKey<A>,
99 owner: Owner<A, Plaintext<A>>,
100 rng: &mut TestRng,
101 ) -> Result<()> {
102 let randomizer = Scalar::new(Mode::Private, Uniform::rand(rng));
104 let record = Record {
105 owner,
106 data: IndexMap::from_iter(vec![
107 (
108 Identifier::from_str("a")?,
109 Entry::Private(Plaintext::from(Literal::Field(Field::new(Mode::Private, Uniform::rand(rng))))),
110 ),
111 (
112 Identifier::from_str("b")?,
113 Entry::Private(Plaintext::from(Literal::Scalar(Scalar::new(Mode::Private, Uniform::rand(rng))))),
114 ),
115 ]),
116 nonce: A::g_scalar_multiply(&randomizer),
117 version: U8::new(Mode::Private, Uniform::rand(rng)),
118 };
119
120 let ciphertext = record.encrypt(&randomizer);
122 assert_eq!(record.eject(), ciphertext.decrypt(view_key).eject());
124 Ok(())
125 }
126
127 #[test]
128 fn test_encrypt_and_decrypt() -> Result<()> {
129 let mut rng = TestRng::default();
130
131 for _ in 0..ITERATIONS {
132 let private_key = snarkvm_console_account::PrivateKey::<<Circuit as Environment>::Network>::new(&mut rng)?;
134 let view_key = snarkvm_console_account::ViewKey::try_from(private_key)?;
135 let address = snarkvm_console_account::Address::try_from(private_key)?;
136
137 let view_key = ViewKey::<Circuit>::new(Mode::Private, view_key);
139 let owner = address;
140
141 {
143 let owner = Owner::Public(Address::<Circuit>::new(Mode::Public, owner));
144 check_encrypt_and_decrypt::<Circuit>(&view_key, owner, &mut rng)?;
145 }
146
147 {
149 let owner =
150 Owner::Private(Plaintext::from(Literal::Address(Address::<Circuit>::new(Mode::Private, owner))));
151 check_encrypt_and_decrypt::<Circuit>(&view_key, owner, &mut rng)?;
152 }
153 }
154 Ok(())
155 }
156}