rust_elgamal/
decrypt.rs

1// Decryption logic for rust-elgamal.
2// Copyright 2021 Eleanor McMurtry
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 core::fmt::{Debug, Formatter};
17
18use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE;
19use curve25519_dalek::ristretto::RistrettoPoint;
20use curve25519_dalek::scalar::Scalar;
21use rand_core::{CryptoRng, RngCore};
22
23#[cfg(feature = "enable-serde")]
24use serde::{Deserialize, Deserializer, Serialize, de::Visitor};
25
26use crate::{Ciphertext, EncryptionKey};
27
28/// An ElGamal decryption key (also called a private key in other implementations).
29#[derive(Copy, Clone, Eq, PartialEq)]
30#[cfg_attr(feature = "enable-serde", derive(Serialize))]
31pub struct DecryptionKey {
32    pub(crate) secret: Scalar,
33    #[cfg_attr(feature = "enable-serde", serde(skip_serializing))]
34    pub(crate) ek: EncryptionKey,
35}
36
37impl DecryptionKey {
38    /// Generate a new ElGamal decryption key using the randomness source `rng`, together with
39    /// its corresponding encryption key.
40    ///
41    /// # Example
42    ///
43    /// ```rust
44    /// use rand::rngs::StdRng;
45    /// use rand::SeedableRng;
46    /// use rust_elgamal::DecryptionKey;
47    ///
48    /// let mut rng = StdRng::from_entropy();
49    /// let dec_key = DecryptionKey::new(&mut rng);
50    /// ```
51    pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
52        let secret = Scalar::random(rng);
53        let ek = EncryptionKey(&secret * &RISTRETTO_BASEPOINT_TABLE);
54        Self { secret, ek }
55    }
56
57    /// Decrypt the ciphertext `ct`.
58    ///
59    /// # Example
60    ///
61    /// ```rust
62    /// use rand::rngs::StdRng;
63    /// use rand::SeedableRng;
64    /// use rust_elgamal::{DecryptionKey, GENERATOR_TABLE, Scalar};
65    ///
66    /// let mut rng = StdRng::from_entropy();
67    /// let dec_key = DecryptionKey::new(&mut rng);
68    ///
69    /// let m = &Scalar::from(5u32) * &GENERATOR_TABLE;
70    /// let ct = dec_key.encryption_key().encrypt(m, &mut rng);
71    /// let decrypted = dec_key.decrypt(ct);
72    /// assert_eq!(m, decrypted);
73    /// ```
74    pub fn decrypt(&self, ct: Ciphertext) -> RistrettoPoint {
75        ct.1 - ct.0 * &self.secret
76    }
77
78    /// Retrieve the encryption key corresponding to this decryption key.
79    pub fn encryption_key(&self) -> &EncryptionKey {
80        &self.ek
81    }
82}
83
84impl Debug for DecryptionKey {
85    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
86        write!(f, "DecryptionKey({:?})", self.secret)
87    }
88}
89
90// Conversion traits
91
92impl From<Scalar> for DecryptionKey {
93    fn from(secret: Scalar) -> Self {
94        let ek = EncryptionKey(&secret * &RISTRETTO_BASEPOINT_TABLE);
95        Self { secret, ek }
96    }
97}
98
99impl AsRef<Scalar> for DecryptionKey {
100    fn as_ref(&self) -> &Scalar {
101        &self.secret
102    }
103}
104
105// serde traits
106
107// Here we want to deserialise the decryption key, then create its corresponding encryption key.
108#[cfg(feature = "enable-serde")]
109impl<'de> Deserialize<'de> for DecryptionKey {
110    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
111        where D: Deserializer<'de>
112    {
113        struct DecryptionKeyVisitor;
114
115        impl<'de> Visitor<'de> for DecryptionKeyVisitor {
116            type Value = DecryptionKey;
117
118            fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
119                formatter.write_str("a valid ElGamal decryption key")
120            }
121
122            fn visit_seq<A>(self, mut seq: A) -> Result<DecryptionKey, A::Error>
123                where A: serde::de::SeqAccess<'de>
124            {
125                let secret = seq.next_element()?
126                    .ok_or(serde::de::Error::invalid_length(0, &"expected decryption key (32 bytes)"))?;
127                let ek = EncryptionKey(&secret * &RISTRETTO_BASEPOINT_TABLE);
128                Ok(DecryptionKey { secret, ek })
129            }
130        }
131
132        deserializer.deserialize_tuple(32, DecryptionKeyVisitor)
133    }
134}
135
136#[cfg(feature = "enable-serde")]
137#[cfg(test)]
138mod tests {
139    use rand::prelude::StdRng;
140    use rand_core::SeedableRng;
141
142    use crate::DecryptionKey;
143
144    // Test that serialising and deserialising a decryption key produces an unchanged result.
145    #[test]
146    fn serde_decryption_key() {
147        const N: usize = 100;
148
149        let mut rng = StdRng::from_entropy();
150
151        for _ in 0..N {
152            let dk = DecryptionKey::new(&mut rng);
153            let encoded = bincode::serialize(&dk).unwrap();
154
155            // Check we aren't accidentally encoding the encryption key as well
156            assert_eq!(encoded.len(), 32);
157
158            let decoded = bincode::deserialize(&encoded).unwrap();
159            assert_eq!(dk, decoded);
160        }
161    }
162}