rust_elgamal/encrypt.rs
1// Encryption 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::{Formatter, Debug};
17
18use curve25519_dalek::constants::{RISTRETTO_BASEPOINT_TABLE, RISTRETTO_BASEPOINT_POINT};
19use curve25519_dalek::ristretto::RistrettoPoint;
20use curve25519_dalek::scalar::Scalar;
21use curve25519_dalek::traits::MultiscalarMul;
22use rand_core::{RngCore, CryptoRng};
23
24#[cfg(feature = "enable-serde")]
25use serde::{Serialize, Deserialize};
26
27use crate::{Ciphertext, DecryptionKey};
28
29/// An ElGamal encryption key (also called a public key in other implementations).
30/// To create a new encryption key, see [DecryptionKey](crate::decrypt::DecryptionKey).
31#[derive(Copy, Clone, Eq, PartialEq)]
32#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
33pub struct EncryptionKey(pub(crate) RistrettoPoint);
34
35impl EncryptionKey {
36 /// Encrypt `mG` with a randomly-generated blinding factor, where `G` is the group generator.
37 ///
38 /// This is computationally intensive to decrypt to the original scalar, and not relevant to
39 /// the majority of users. This function takes advantage of a fast implementation for multiple
40 /// multiplications in `curve25519-dalek`.
41 ///
42 /// # Example
43 ///
44 /// ```rust
45 /// use rand::rngs::StdRng;
46 /// use rand::SeedableRng;
47 /// use rust_elgamal::{DecryptionKey, GENERATOR_TABLE, Scalar};
48 ///
49 /// let mut rng = StdRng::from_entropy();
50 /// let dec_key = DecryptionKey::new(&mut rng);
51 /// let enc_key = dec_key.encryption_key();
52 ///
53 /// let m = Scalar::from(5u32);
54 /// let encrypted = enc_key.exp_encrypt(m, &mut rng);
55 /// ```
56 pub fn exp_encrypt<R: RngCore + CryptoRng>(&self, m: Scalar, rng: &mut R) -> Ciphertext {
57 self.exp_encrypt_with(m, Scalar::random(rng))
58 }
59
60 /// Encrypt `mG` with the blinding factor `r`, where `G` is the group generator.
61 ///
62 /// This is computationally intensive to decrypt to the original scalar, and not relevant to
63 /// the majority of users. This function takes advantage of a fast implementation for multiple
64 /// multiplications in `curve25519-dalek`.
65 ///
66 /// # Example
67 ///
68 /// ```rust
69 /// use rand::rngs::StdRng;
70 /// use rand::SeedableRng;
71 /// use rust_elgamal::{DecryptionKey, GENERATOR_TABLE, Scalar};
72 ///
73 /// let mut rng = StdRng::from_entropy();
74 /// let dec_key = DecryptionKey::new(&mut rng);
75 /// let enc_key = dec_key.encryption_key();
76 ///
77 /// let m = Scalar::from(5u32);
78 /// let r = Scalar::from(10u32);
79 /// let encrypted = enc_key.exp_encrypt_with(m, r);
80 /// ```
81 pub fn exp_encrypt_with(&self, m: Scalar, r: Scalar) -> Ciphertext {
82 let c1 = &r * &RISTRETTO_BASEPOINT_TABLE;
83 // mG + rY
84 let c2 = RistrettoPoint::multiscalar_mul(&[m, r], &[RISTRETTO_BASEPOINT_POINT, self.0]);
85 Ciphertext(c1, c2)
86 }
87
88 /// Encrypt the curve point `m` with a randomly-generated blinding factor.
89 ///
90 /// # Example
91 ///
92 /// ```rust
93 /// use rand::rngs::StdRng;
94 /// use rand::SeedableRng;
95 /// use rust_elgamal::{DecryptionKey, GENERATOR_TABLE, Scalar};
96 ///
97 /// let mut rng = StdRng::from_entropy();
98 /// let dec_key = DecryptionKey::new(&mut rng);
99 /// let enc_key = dec_key.encryption_key();
100 ///
101 /// let m = &Scalar::from(5u32) * &GENERATOR_TABLE;
102 /// let encrypted = enc_key.encrypt(m, &mut rng);
103 /// ```
104 pub fn encrypt<R: RngCore + CryptoRng>(&self, m: RistrettoPoint, rng: &mut R) -> Ciphertext {
105 self.encrypt_with(m, Scalar::random(rng))
106 }
107
108 /// Encrypt the curve point `m` with the blinding factor `r`.
109 ///
110 /// # Example
111 ///
112 /// ```rust
113 /// use rand::rngs::StdRng;
114 /// use rand::SeedableRng;
115 /// use rust_elgamal::{DecryptionKey, GENERATOR_TABLE, Scalar};
116 ///
117 /// let mut rng = StdRng::from_entropy();
118 /// let dec_key = DecryptionKey::new(&mut rng);
119 /// let enc_key = dec_key.encryption_key();
120 ///
121 /// let m = &Scalar::from(5u32) * &GENERATOR_TABLE;
122 /// let r = Scalar::from(10u32);
123 /// let encrypted = enc_key.encrypt_with(m, r);
124 /// ```
125 pub fn encrypt_with(&self, m: RistrettoPoint, r: Scalar) -> Ciphertext {
126 let c1 = &r * &RISTRETTO_BASEPOINT_TABLE;
127 let c2 = m + r * &self.0;
128 Ciphertext(c1, c2)
129 }
130
131 /// Re-randomise the ciphertext `ct` with a randomly-generated blinding factor.
132 /// This will generate a new encryption of the same curve point.
133 ///
134 /// # Example
135 ///
136 /// ```rust
137 /// use rand::rngs::StdRng;
138 /// use rand::SeedableRng;
139 /// use rust_elgamal::{DecryptionKey, GENERATOR_TABLE, Scalar};
140 ///
141 /// let mut rng = StdRng::from_entropy();
142 /// let dec_key = DecryptionKey::new(&mut rng);
143 /// let enc_key = dec_key.encryption_key();
144 ///
145 /// let m = &Scalar::from(5u32) * &GENERATOR_TABLE;
146 /// let ct1 = enc_key.encrypt(m, &mut rng);
147 /// let ct2 = enc_key.rerandomise(ct1, &mut rng);
148 /// assert_eq!(dec_key.decrypt(ct1), dec_key.decrypt(ct2));
149 /// ```
150 pub fn rerandomise<R: RngCore + CryptoRng>(&self, ct: Ciphertext, rng: &mut R) -> Ciphertext {
151 self.rerandomise_with(ct, Scalar::random(rng))
152 }
153
154
155 /// Re-randomise the ciphertext `ct` with the provided blinding factor.
156 /// This will generate a new encryption of the same curve point.
157 ///
158 /// # Example
159 ///
160 /// ```rust
161 /// use rand::rngs::StdRng;
162 /// use rand::SeedableRng;
163 /// use rust_elgamal::{DecryptionKey, GENERATOR_TABLE, Scalar};
164 ///
165 /// let mut rng = StdRng::from_entropy();
166 /// let dec_key = DecryptionKey::new(&mut rng);
167 /// let enc_key = dec_key.encryption_key();
168 ///
169 /// let m = &Scalar::from(5u32) * &GENERATOR_TABLE;
170 /// let ct1 = enc_key.encrypt(m, &mut rng);
171 ///
172 /// let r = Scalar::from(10u32);
173 /// let ct2 = enc_key.rerandomise_with(ct1, r);
174 ///
175 /// assert_eq!(dec_key.decrypt(ct1), dec_key.decrypt(ct2));
176 /// ```
177 pub fn rerandomise_with(&self, ct: Ciphertext, r: Scalar) -> Ciphertext {
178 let c1 = ct.0 + &r * &RISTRETTO_BASEPOINT_TABLE;
179 let c2 = ct.1 + &self.0 * r;
180 Ciphertext(c1, c2)
181 }
182}
183
184impl Debug for EncryptionKey {
185 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
186 write!(f, "EncryptionKey({:?})", self.0.compress())
187 }
188}
189
190// Conversion traits
191
192impl From<DecryptionKey> for EncryptionKey {
193 fn from(dk: DecryptionKey) -> Self {
194 dk.ek
195 }
196}
197
198impl From<RistrettoPoint> for EncryptionKey {
199 fn from(y: RistrettoPoint) -> Self {
200 Self(y)
201 }
202}
203
204impl AsRef<RistrettoPoint> for EncryptionKey {
205 fn as_ref(&self) -> &RistrettoPoint {
206 &self.0
207 }
208}