/ console / program / src / data / ciphertext / decrypt.rs
decrypt.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm 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<N: Network> Ciphertext<N> {
 19      /// Decrypts `self` into plaintext using the given account view key & nonce.
 20      pub fn decrypt(&self, view_key: ViewKey<N>, nonce: Group<N>) -> Result<Plaintext<N>> {
 21          // Compute the plaintext view key.
 22          let plaintext_view_key = (nonce * *view_key).to_x_coordinate();
 23          // Decrypt the record.
 24          self.decrypt_symmetric(plaintext_view_key)
 25      }
 26  
 27      /// Decrypts `self` into plaintext using the given plaintext view key.
 28      pub fn decrypt_symmetric(&self, plaintext_view_key: Field<N>) -> Result<Plaintext<N>> {
 29          // Determine the number of randomizers needed to encrypt the plaintext.
 30          let num_randomizers = self.num_randomizers()?;
 31          // Prepare a randomizer for each field element.
 32          let randomizers = N::hash_many_psd8(&[N::encryption_domain(), plaintext_view_key], num_randomizers);
 33          // Decrypt the plaintext.
 34          self.decrypt_with_randomizers(&randomizers)
 35      }
 36  
 37      /// Decrypts `self` into plaintext using the given randomizers.
 38      pub(crate) fn decrypt_with_randomizers(&self, randomizers: &[Field<N>]) -> Result<Plaintext<N>> {
 39          // Decrypt the ciphertext.
 40          Plaintext::from_fields(
 41              &self
 42                  .iter()
 43                  .zip_eq(randomizers)
 44                  .map(|(ciphertext, randomizer)| *ciphertext - randomizer)
 45                  .collect::<Vec<_>>(),
 46          )
 47      }
 48  }
 49  
 50  #[cfg(test)]
 51  mod tests {
 52      use super::*;
 53      use crate::Literal;
 54      use alphavm_console_account::{Address, PrivateKey};
 55      use alphavm_console_network::MainnetV0;
 56  
 57      type CurrentNetwork = MainnetV0;
 58  
 59      const ITERATIONS: u64 = 100;
 60  
 61      fn check_encrypt_and_decrypt<N: Network>(rng: &mut TestRng) -> Result<()> {
 62          // Prepare the plaintext.
 63          let plaintext_string = r"{
 64    foo: 5u8,
 65    bar: {
 66      baz: 10field,
 67      qux: {
 68        quux: {
 69          corge: {
 70            grault: {
 71              garply: {
 72                waldo: {
 73                  fred: {
 74                    plugh: {
 75                      xyzzy: {
 76                        thud: true
 77                      }
 78                    }
 79                  }
 80                }
 81              }
 82            }
 83          }
 84        }
 85      }
 86    }
 87  }";
 88          let plaintext = Plaintext::<N>::from_str(plaintext_string)?;
 89  
 90          // Sample a random address.
 91          let private_key = PrivateKey::<N>::new(rng)?;
 92          let view_key = ViewKey::<N>::try_from(private_key)?;
 93          let address = Address::<N>::try_from(view_key)?;
 94  
 95          // Encrypt the plaintext.
 96          let randomizer = Uniform::rand(rng);
 97          let ciphertext = plaintext.encrypt(&address, randomizer)?;
 98  
 99          // Decrypt the plaintext.
100          let nonce = N::g_scalar_multiply(&randomizer);
101          assert_eq!(plaintext, ciphertext.decrypt(view_key, nonce)?);
102          Ok(())
103      }
104  
105      fn check_encrypt_and_decrypt_symmetric<N: Network>(rng: &mut TestRng) -> Result<()> {
106          // Prepare the plaintext.
107          let plaintext = Plaintext::<N>::from(Literal::Field(Uniform::rand(rng)));
108  
109          // Encrypt the plaintext.
110          let plaintext_view_key = Uniform::rand(rng);
111          let ciphertext = plaintext.encrypt_symmetric(plaintext_view_key)?;
112          // Decrypt the plaintext.
113          assert_eq!(plaintext, ciphertext.decrypt_symmetric(plaintext_view_key)?);
114          Ok(())
115      }
116  
117      #[test]
118      fn test_encrypt_and_decrypt() -> Result<()> {
119          let mut rng = TestRng::default();
120  
121          for _ in 0..ITERATIONS {
122              check_encrypt_and_decrypt::<CurrentNetwork>(&mut rng)?;
123              check_encrypt_and_decrypt_symmetric::<CurrentNetwork>(&mut rng)?;
124          }
125          Ok(())
126      }
127  }