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 }