1use rand_core::{CryptoRng, RngCore};
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6use zeroize::{Zeroize, Zeroizing};
7
8use core::{fmt, marker::PhantomData, ops};
9
10#[cfg(feature = "serde")]
11use crate::serde::ElementHelper;
12use crate::{
13 alloc::{vec, HashMap, Vec},
14 group::{Group, ScalarOps},
15 PublicKey, SecretKey,
16};
17
18#[derive(Clone, Copy)]
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97pub struct Ciphertext<G: Group> {
98 #[cfg_attr(feature = "serde", serde(with = "ElementHelper::<G>"))]
99 pub(crate) random_element: G::Element,
100 #[cfg_attr(feature = "serde", serde(with = "ElementHelper::<G>"))]
101 pub(crate) blinded_element: G::Element,
102}
103
104impl<G: Group> fmt::Debug for Ciphertext<G> {
105 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
106 formatter
107 .debug_struct("Ciphertext")
108 .field("random_element", &self.random_element)
109 .field("blinded_element", &self.blinded_element)
110 .finish()
111 }
112}
113
114impl<G: Group> Ciphertext<G> {
115 pub fn zero() -> Self {
117 Self {
118 random_element: G::identity(),
119 blinded_element: G::identity(),
120 }
121 }
122
123 pub fn non_blinded<T>(value: T) -> Self
126 where
127 G::Scalar: From<T>,
128 {
129 let scalar = Zeroizing::new(G::Scalar::from(value));
130 Self {
131 random_element: G::identity(),
132 blinded_element: G::mul_generator(&scalar),
133 }
134 }
135
136 pub fn random_element(&self) -> &G::Element {
138 &self.random_element
139 }
140
141 pub fn blinded_element(&self) -> &G::Element {
143 &self.blinded_element
144 }
145
146 pub fn to_bytes(self) -> Vec<u8> {
149 let mut bytes = vec![0_u8; 2 * G::ELEMENT_SIZE];
150 G::serialize_element(&self.random_element, &mut bytes[..G::ELEMENT_SIZE]);
151 G::serialize_element(&self.blinded_element, &mut bytes[G::ELEMENT_SIZE..]);
152 bytes
153 }
154}
155
156impl<G: Group> ops::Add for Ciphertext<G> {
157 type Output = Self;
158
159 fn add(self, rhs: Self) -> Self {
160 Self {
161 random_element: self.random_element + rhs.random_element,
162 blinded_element: self.blinded_element + rhs.blinded_element,
163 }
164 }
165}
166
167impl<G: Group> ops::AddAssign for Ciphertext<G> {
168 fn add_assign(&mut self, rhs: Self) {
169 *self = *self + rhs;
170 }
171}
172
173impl<G: Group> ops::Sub for Ciphertext<G> {
174 type Output = Self;
175
176 fn sub(self, rhs: Self) -> Self {
177 Self {
178 random_element: self.random_element - rhs.random_element,
179 blinded_element: self.blinded_element - rhs.blinded_element,
180 }
181 }
182}
183
184impl<G: Group> ops::SubAssign for Ciphertext<G> {
185 fn sub_assign(&mut self, rhs: Self) {
186 *self = *self - rhs;
187 }
188}
189
190impl<G: Group> ops::Mul<&G::Scalar> for Ciphertext<G> {
191 type Output = Self;
192
193 fn mul(self, rhs: &G::Scalar) -> Self {
194 Self {
195 random_element: self.random_element * rhs,
196 blinded_element: self.blinded_element * rhs,
197 }
198 }
199}
200
201impl<G: Group> ops::Mul<u64> for Ciphertext<G> {
202 type Output = Self;
203
204 fn mul(self, rhs: u64) -> Self {
205 let scalar = G::Scalar::from(rhs);
206 self * &scalar
207 }
208}
209
210impl<G: Group> ops::Neg for Ciphertext<G> {
211 type Output = Self;
212
213 fn neg(self) -> Self::Output {
214 Self {
215 random_element: -self.random_element,
216 blinded_element: -self.blinded_element,
217 }
218 }
219}
220
221#[derive(Debug, Clone)]
254pub struct DiscreteLogTable<G: Group> {
255 inner: HashMap<Vec<u8>, u64>,
256 _t: PhantomData<G>,
257}
258
259impl<G: Group> DiscreteLogTable<G> {
260 pub fn new(values: impl IntoIterator<Item = u64>) -> Self {
262 let lookup_table = values
263 .into_iter()
264 .filter(|&value| value != 0)
265 .map(|i| {
266 let element = G::vartime_mul_generator(&G::Scalar::from(i));
267 let mut bytes = vec![0_u8; G::ELEMENT_SIZE];
268 G::serialize_element(&element, &mut bytes);
269 (bytes, i)
270 })
271 .collect();
272
273 Self {
274 inner: lookup_table,
275 _t: PhantomData,
276 }
277 }
278
279 pub fn get(&self, decrypted_element: &G::Element) -> Option<u64> {
282 if G::is_identity(decrypted_element) {
283 Some(0)
286 } else {
287 let mut bytes = vec![0_u8; G::ELEMENT_SIZE];
288 G::serialize_element(decrypted_element, &mut bytes);
289 self.inner.get(&bytes).copied()
290 }
291 }
292}
293
294#[derive(Debug, Clone)]
296#[doc(hidden)] pub struct ExtendedCiphertext<G: Group> {
298 pub(crate) inner: Ciphertext<G>,
299 pub(crate) random_scalar: SecretKey<G>,
300}
301
302impl<G: Group> ExtendedCiphertext<G> {
303 pub(crate) fn new<R: CryptoRng + RngCore>(
305 value: G::Element,
306 receiver: &PublicKey<G>,
307 rng: &mut R,
308 ) -> Self {
309 let random_scalar = SecretKey::<G>::generate(rng);
310 let random_element = G::mul_generator(random_scalar.expose_scalar());
311 let dh_element = receiver.as_element() * random_scalar.expose_scalar();
312 let blinded_element = value + dh_element;
313
314 Self {
315 inner: Ciphertext {
316 random_element,
317 blinded_element,
318 },
319 random_scalar,
320 }
321 }
322
323 pub(crate) fn zero() -> Self {
324 Self {
325 inner: Ciphertext::zero(),
326 random_scalar: SecretKey::new(G::Scalar::from(0_u64)),
327 }
328 }
329
330 pub(crate) fn with_value<V>(self, value: V) -> CiphertextWithValue<G, V>
331 where
332 V: Zeroize,
333 G::Scalar: From<V>,
334 {
335 CiphertextWithValue {
336 inner: self,
337 value: Zeroizing::new(value),
338 }
339 }
340}
341
342impl<G: Group> ops::Add for ExtendedCiphertext<G> {
343 type Output = Self;
344
345 fn add(self, rhs: Self) -> Self::Output {
346 Self {
347 inner: self.inner + rhs.inner,
348 random_scalar: self.random_scalar + rhs.random_scalar,
349 }
350 }
351}
352
353impl<G: Group> ops::AddAssign for ExtendedCiphertext<G> {
354 fn add_assign(&mut self, rhs: Self) {
355 self.inner += rhs.inner;
356 self.random_scalar += rhs.random_scalar;
357 }
358}
359
360impl<G: Group> ops::Sub for ExtendedCiphertext<G> {
361 type Output = Self;
362
363 fn sub(self, rhs: Self) -> Self::Output {
364 Self {
365 inner: self.inner - rhs.inner,
366 random_scalar: self.random_scalar - rhs.random_scalar,
367 }
368 }
369}
370
371#[derive(Debug)]
377pub struct CiphertextWithValue<G: Group, V: Zeroize = <G as ScalarOps>::Scalar> {
378 inner: ExtendedCiphertext<G>,
379 value: Zeroizing<V>,
380}
381
382impl<G: Group, V: Zeroize> From<CiphertextWithValue<G, V>> for Ciphertext<G> {
383 fn from(ciphertext: CiphertextWithValue<G, V>) -> Self {
384 ciphertext.inner.inner
385 }
386}
387
388impl<G: Group, V> CiphertextWithValue<G, V>
389where
390 V: Copy + Zeroize,
391 G::Scalar: From<V>,
392{
393 pub fn new<R: CryptoRng + RngCore>(value: V, receiver: &PublicKey<G>, rng: &mut R) -> Self {
398 let scalar = Zeroizing::new(G::Scalar::from(value));
399 let element = G::mul_generator(&scalar);
400 ExtendedCiphertext::new(element, receiver, rng).with_value(value)
401 }
402
403 pub fn generalize(self) -> CiphertextWithValue<G> {
405 CiphertextWithValue {
406 inner: self.inner,
407 value: Zeroizing::new(G::Scalar::from(*self.value)),
408 }
409 }
410}
411
412impl<G: Group, V> CiphertextWithValue<G, V>
413where
414 V: Zeroize,
415 G::Scalar: From<V>,
416{
417 pub fn inner(&self) -> &Ciphertext<G> {
419 &self.inner.inner
420 }
421
422 pub(crate) fn extended_ciphertext(&self) -> &ExtendedCiphertext<G> {
423 &self.inner
424 }
425
426 pub(crate) fn randomness(&self) -> &SecretKey<G> {
427 &self.inner.random_scalar
428 }
429
430 pub(crate) fn value(&self) -> &V {
431 &self.value
432 }
433}
434
435#[cfg(test)]
436mod tests {
437 use rand::{thread_rng, Rng};
438
439 use super::*;
440 use crate::{curve25519::scalar::Scalar as Curve25519Scalar, group::Ristretto, Keypair};
441
442 #[test]
443 fn ciphertext_addition() {
444 let mut rng = thread_rng();
445 let numbers: Vec<_> = (0..10).map(|_| u64::from(rng.gen::<u32>())).collect();
446 let sum = numbers.iter().copied().sum::<u64>();
447
448 let (pk, sk) = Keypair::<Ristretto>::generate(&mut rng).into_tuple();
449 let ciphertexts = numbers.into_iter().map(|x| pk.encrypt(x, &mut rng));
450 let sum_ciphertext = ciphertexts.reduce(ops::Add::add).unwrap();
451 let decrypted = sk.decrypt_to_element(sum_ciphertext);
452
453 assert_eq!(decrypted, Ristretto::vartime_mul_generator(&sum.into()));
454 }
455
456 #[test]
457 fn ciphertext_mul_by_u64() {
458 let mut rng = thread_rng();
459 let (pk, sk) = Keypair::<Ristretto>::generate(&mut rng).into_tuple();
460 for _ in 0..100 {
461 let x = rng.gen::<u64>();
462 let multiplier = rng.gen::<u64>();
463 let ciphertext = pk.encrypt(x, &mut rng);
464 let decrypted = sk.decrypt_to_element(ciphertext * multiplier);
465
466 let expected_decryption =
467 Curve25519Scalar::from(x) * Curve25519Scalar::from(multiplier);
468 assert_eq!(
469 decrypted,
470 Ristretto::vartime_mul_generator(&expected_decryption)
471 );
472 }
473 }
474
475 #[test]
476 fn ciphertext_negation() {
477 let mut rng = thread_rng();
478 let (pk, sk) = Keypair::<Ristretto>::generate(&mut rng).into_tuple();
479 for _ in 0..100 {
480 let x = rng.gen::<u64>();
481 let ciphertext = pk.encrypt(x, &mut rng);
482 let neg_ciphertext = -ciphertext;
483 let decrypted = sk.decrypt_to_element(neg_ciphertext);
484
485 assert_eq!(
486 decrypted,
487 Ristretto::vartime_mul_generator(&-Curve25519Scalar::from(x))
488 );
489 }
490 }
491
492 #[test]
493 fn non_blinded_ciphertext() {
494 let mut rng = thread_rng();
495 let (_, sk) = Keypair::<Ristretto>::generate(&mut rng).into_tuple();
496 for _ in 0..100 {
497 let x = rng.gen::<u64>();
498 let ciphertext = Ciphertext::non_blinded(x);
499 let decrypted = sk.decrypt_to_element(ciphertext);
500
501 assert_eq!(
502 decrypted,
503 Ristretto::vartime_mul_generator(&Curve25519Scalar::from(x))
504 );
505 }
506 }
507}