snarkvm_console_program/data/ciphertext/
decrypt.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM 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
16use super::*;
17
18impl<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)]
51mod tests {
52    use super::*;
53    use crate::Literal;
54    use snarkvm_console_account::{Address, PrivateKey};
55    use snarkvm_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}