use super::*;
impl<N: Network> Ciphertext<N> {
pub fn decrypt(&self, view_key: ViewKey<N>, nonce: Group<N>) -> Result<Plaintext<N>> {
let plaintext_view_key = (nonce * *view_key).to_x_coordinate();
self.decrypt_symmetric(plaintext_view_key)
}
pub fn decrypt_symmetric(&self, plaintext_view_key: Field<N>) -> Result<Plaintext<N>> {
let num_randomizers = self.num_randomizers()?;
let randomizers = N::hash_many_psd8(&[N::encryption_domain(), plaintext_view_key], num_randomizers);
self.decrypt_with_randomizers(&randomizers)
}
pub(crate) fn decrypt_with_randomizers(&self, randomizers: &[Field<N>]) -> Result<Plaintext<N>> {
Plaintext::from_fields(
&self
.iter()
.zip_eq(randomizers)
.map(|(ciphertext, randomizer)| *ciphertext - randomizer)
.collect::<Vec<_>>(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Literal;
use snarkvm_console_account::{Address, PrivateKey};
use snarkvm_console_network::MainnetV0;
type CurrentNetwork = MainnetV0;
const ITERATIONS: u64 = 100;
fn check_encrypt_and_decrypt<N: Network>(rng: &mut TestRng) -> Result<()> {
let plaintext_string = r"{
foo: 5u8,
bar: {
baz: 10field,
qux: {
quux: {
corge: {
grault: {
garply: {
waldo: {
fred: {
plugh: {
xyzzy: {
thud: true
}
}
}
}
}
}
}
}
}
}
}";
let plaintext = Plaintext::<N>::from_str(plaintext_string)?;
let private_key = PrivateKey::<N>::new(rng)?;
let view_key = ViewKey::<N>::try_from(private_key)?;
let address = Address::<N>::try_from(view_key)?;
let randomizer = Uniform::rand(rng);
let ciphertext = plaintext.encrypt(&address, randomizer)?;
let nonce = N::g_scalar_multiply(&randomizer);
assert_eq!(plaintext, ciphertext.decrypt(view_key, nonce)?);
Ok(())
}
fn check_encrypt_and_decrypt_symmetric<N: Network>(rng: &mut TestRng) -> Result<()> {
let plaintext = Plaintext::<N>::from(Literal::Field(Uniform::rand(rng)));
let plaintext_view_key = Uniform::rand(rng);
let ciphertext = plaintext.encrypt_symmetric(plaintext_view_key)?;
assert_eq!(plaintext, ciphertext.decrypt_symmetric(plaintext_view_key)?);
Ok(())
}
#[test]
fn test_encrypt_and_decrypt() -> Result<()> {
let mut rng = TestRng::default();
for _ in 0..ITERATIONS {
check_encrypt_and_decrypt::<CurrentNetwork>(&mut rng)?;
check_encrypt_and_decrypt_symmetric::<CurrentNetwork>(&mut rng)?;
}
Ok(())
}
}