decrypt.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm library. 3 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at: 7 8 // http://www.apache.org/licenses/LICENSE-2.0 9 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 use super::*; 17 18 impl<A: Alpha> Record<A, Ciphertext<A>> { 19 /// Decrypts `self` into a plaintext record using the given view key & nonce. 20 pub fn decrypt(&self, view_key: &ViewKey<A>) -> Record<A, Plaintext<A>> { 21 // Compute the record view key. 22 let record_view_key = (&**view_key * &self.nonce).to_x_coordinate(); 23 // Decrypt the record. 24 let record = self.decrypt_symmetric_unchecked(record_view_key); 25 // Ensure the view key corresponds to the record owner. 26 A::assert_eq(view_key.to_address(), record.owner().deref()); 27 // Return the decrypted record. 28 record 29 } 30 31 /// Decrypts `self` into a plaintext record using the given record view key. 32 /// Note: This method does not check that the record view key corresponds to the record owner. 33 /// Use `Self::decrypt` for the checked variant. 34 pub fn decrypt_symmetric_unchecked(&self, record_view_key: Field<A>) -> Record<A, Plaintext<A>> { 35 // Determine the number of randomizers needed to encrypt the record. 36 let num_randomizers = self.num_randomizers(); 37 // Prepare a randomizer for each field element. 38 let randomizers = A::hash_many_psd8(&[A::encryption_domain(), record_view_key], num_randomizers); 39 // Decrypt the record. 40 self.decrypt_with_randomizers(&randomizers) 41 } 42 43 /// Decrypts `self` into a plaintext record using the given randomizers. 44 fn decrypt_with_randomizers(&self, randomizers: &[Field<A>]) -> Record<A, Plaintext<A>> { 45 // Initialize an index to keep track of the randomizer index. 46 let mut index: usize = 0; 47 48 // Decrypt the owner. 49 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 // Increment the index if the owner is private. 55 if owner.is_private().eject_value() { 56 index += 1; 57 } 58 59 // Decrypt the program data. 60 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 // Retrieve the randomizers for this entry. 63 let randomizers = &randomizers[index..index + num_randomizers as usize]; 64 // Decrypt the entry. 65 let entry = match entry { 66 // Constant entries do not need to be decrypted. 67 Entry::Constant(plaintext) => Entry::Constant(plaintext.clone()), 68 // Public entries do not need to be decrypted. 69 Entry::Public(plaintext) => Entry::Public(plaintext.clone()), 70 // Private entries are decrypted with the given randomizers. 71 Entry::Private(private) => Entry::Private(private.decrypt_with_randomizers(randomizers)), 72 }; 73 // Insert the decrypted entry. 74 if decrypted_data.insert(id.clone(), entry).is_some() { 75 A::halt(format!("Duplicate identifier in record: {id}")) 76 } 77 // Increment the index. 78 index += num_randomizers as usize; 79 } 80 81 // Return the decrypted record. 82 Record { owner, data: decrypted_data, nonce: self.nonce.clone(), version: self.version.clone() } 83 } 84 } 85 86 #[cfg(test)] 87 mod tests { 88 use super::*; 89 use crate::{Circuit, Literal}; 90 use deltavm_circuit_types::{Address, Field}; 91 use deltavm_utilities::{TestRng, Uniform}; 92 93 use anyhow::Result; 94 95 const ITERATIONS: u64 = 100; 96 97 fn check_encrypt_and_decrypt<A: Alpha>( 98 view_key: &ViewKey<A>, 99 owner: Owner<A, Plaintext<A>>, 100 rng: &mut TestRng, 101 ) -> Result<()> { 102 // Prepare the record. 103 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 // Encrypt the record. 121 let ciphertext = record.encrypt(&randomizer); 122 // Decrypt the record. 123 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 // Generate a private key, view key, and address. 133 let private_key = deltavm_console_account::PrivateKey::<<Circuit as Environment>::Network>::new(&mut rng)?; 134 let view_key = deltavm_console_account::ViewKey::try_from(private_key)?; 135 let address = deltavm_console_account::Address::try_from(private_key)?; 136 137 // Initialize a view key and address. 138 let view_key = ViewKey::<Circuit>::new(Mode::Private, view_key); 139 let owner = address; 140 141 // Public owner. 142 { 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 // Private owner. 148 { 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 }