/ console / program / src / data / ciphertext / decrypt.rs
decrypt.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use super::*;
 20  
 21  impl<N: Network> Ciphertext<N> {
 22      /// Decrypts `self` into plaintext using the given account view key & nonce.
 23      pub fn decrypt(&self, view_key: ViewKey<N>, nonce: Group<N>) -> Result<Plaintext<N>> {
 24          // Compute the plaintext view key.
 25          let plaintext_view_key = (nonce * *view_key).to_x_coordinate();
 26          // Decrypt the record.
 27          self.decrypt_symmetric(plaintext_view_key)
 28      }
 29  
 30      /// Decrypts `self` into plaintext using the given plaintext view key.
 31      pub fn decrypt_symmetric(&self, plaintext_view_key: Field<N>) -> Result<Plaintext<N>> {
 32          // Determine the number of randomizers needed to encrypt the plaintext.
 33          let num_randomizers = self.num_randomizers()?;
 34          // Prepare a randomizer for each field element.
 35          let randomizers = N::hash_many_psd8(&[N::encryption_domain(), plaintext_view_key], num_randomizers);
 36          // Decrypt the plaintext.
 37          self.decrypt_with_randomizers(&randomizers)
 38      }
 39  
 40      /// Decrypts `self` into plaintext using the given randomizers.
 41      pub(crate) fn decrypt_with_randomizers(&self, randomizers: &[Field<N>]) -> Result<Plaintext<N>> {
 42          // Decrypt the ciphertext.
 43          Plaintext::from_fields(
 44              &self
 45                  .iter()
 46                  .zip_eq(randomizers)
 47                  .map(|(ciphertext, randomizer)| *ciphertext - randomizer)
 48                  .collect::<Vec<_>>(),
 49          )
 50      }
 51  }
 52  
 53  #[cfg(test)]
 54  mod tests {
 55      use super::*;
 56      use crate::Literal;
 57      use alphavm_console_account::{Address, PrivateKey};
 58      use alphavm_console_network::MainnetV0;
 59  
 60      type CurrentNetwork = MainnetV0;
 61  
 62      const ITERATIONS: u64 = 100;
 63  
 64      fn check_encrypt_and_decrypt<N: Network>(rng: &mut TestRng) -> Result<()> {
 65          // Prepare the plaintext.
 66          let plaintext_string = r"{
 67    foo: 5u8,
 68    bar: {
 69      baz: 10field,
 70      qux: {
 71        quux: {
 72          corge: {
 73            grault: {
 74              garply: {
 75                waldo: {
 76                  fred: {
 77                    plugh: {
 78                      xyzzy: {
 79                        thud: true
 80                      }
 81                    }
 82                  }
 83                }
 84              }
 85            }
 86          }
 87        }
 88      }
 89    }
 90  }";
 91          let plaintext = Plaintext::<N>::from_str(plaintext_string)?;
 92  
 93          // Sample a random address.
 94          let private_key = PrivateKey::<N>::new(rng)?;
 95          let view_key = ViewKey::<N>::try_from(private_key)?;
 96          let address = Address::<N>::try_from(view_key)?;
 97  
 98          // Encrypt the plaintext.
 99          let randomizer = Uniform::rand(rng);
100          let ciphertext = plaintext.encrypt(&address, randomizer)?;
101  
102          // Decrypt the plaintext.
103          let nonce = N::g_scalar_multiply(&randomizer);
104          assert_eq!(plaintext, ciphertext.decrypt(view_key, nonce)?);
105          Ok(())
106      }
107  
108      fn check_encrypt_and_decrypt_symmetric<N: Network>(rng: &mut TestRng) -> Result<()> {
109          // Prepare the plaintext.
110          let plaintext = Plaintext::<N>::from(Literal::Field(Uniform::rand(rng)));
111  
112          // Encrypt the plaintext.
113          let plaintext_view_key = Uniform::rand(rng);
114          let ciphertext = plaintext.encrypt_symmetric(plaintext_view_key)?;
115          // Decrypt the plaintext.
116          assert_eq!(plaintext, ciphertext.decrypt_symmetric(plaintext_view_key)?);
117          Ok(())
118      }
119  
120      #[test]
121      fn test_encrypt_and_decrypt() -> Result<()> {
122          let mut rng = TestRng::default();
123  
124          for _ in 0..ITERATIONS {
125              check_encrypt_and_decrypt::<CurrentNetwork>(&mut rng)?;
126              check_encrypt_and_decrypt_symmetric::<CurrentNetwork>(&mut rng)?;
127          }
128          Ok(())
129      }
130  }