rust_elgamal/
ciphertext.rs1use core::fmt::{Debug, Formatter};
17use core::ops::{Add, Neg, Mul, Sub};
18
19use curve25519_dalek::ristretto::RistrettoPoint;
20use curve25519_dalek::traits::Identity;
21use curve25519_dalek::scalar::Scalar;
22
23#[cfg(feature = "enable-serde")]
24use serde::{Serialize, Deserialize};
25
26#[derive(Copy, Clone, PartialEq, Eq)]
31#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
32pub struct Ciphertext(pub(crate) RistrettoPoint, pub(crate) RistrettoPoint);
33
34impl Ciphertext {
35 pub fn inner(&self) -> (RistrettoPoint, RistrettoPoint) {
37 (self.0, self.1)
38 }
39}
40
41impl Debug for Ciphertext {
42 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
43 write!(f, "Ciphertext({:?}, {:?})", self.0.compress(), self.1.compress())
44 }
45}
46
47impl From<(RistrettoPoint, RistrettoPoint)> for Ciphertext {
50 fn from(pair: (RistrettoPoint, RistrettoPoint)) -> Self {
51 Self(pair.0, pair.1)
52 }
53}
54
55impl Identity for Ciphertext {
58 fn identity() -> Self {
59 Self(RistrettoPoint::identity(), RistrettoPoint::identity())
60 }
61}
62
63impl Add for Ciphertext {
64 type Output = Self;
65
66 fn add(self, rhs: Self) -> Self::Output {
67 Ciphertext(self.0 + rhs.0, self.1 + rhs.1)
68 }
69}
70
71impl Add for &Ciphertext {
72 type Output = Ciphertext;
73
74 fn add(self, rhs: Self) -> Self::Output {
75 Ciphertext(&self.0 + &rhs.0, &self.1 + &rhs.1)
76 }
77}
78
79impl Add<&Ciphertext> for Ciphertext {
80 type Output = Ciphertext;
81
82 fn add(self, rhs: &Ciphertext) -> Self::Output {
83 Ciphertext(self.0 + &rhs.0, self.1 + &rhs.1)
84 }
85}
86
87impl Add<Ciphertext> for &Ciphertext {
88 type Output = Ciphertext;
89
90 fn add(self, rhs: Ciphertext) -> Self::Output {
91 Ciphertext(&self.0 + rhs.0, &self.1 + rhs.1)
92 }
93}
94
95impl Sub for Ciphertext {
96 type Output = Self;
97
98 fn sub(self, rhs: Self) -> Self::Output {
99 Ciphertext(self.0 - rhs.0, self.1 - rhs.1)
100 }
101}
102
103impl Sub for &Ciphertext {
104 type Output = Ciphertext;
105
106 fn sub(self, rhs: Self) -> Self::Output {
107 Ciphertext(&self.0 - &rhs.0, &self.1 - &rhs.1)
108 }
109}
110
111impl Sub<&Ciphertext> for Ciphertext {
112 type Output = Ciphertext;
113
114 fn sub(self, rhs: &Ciphertext) -> Self::Output {
115 Ciphertext(self.0 - &rhs.0, self.1 - &rhs.1)
116 }
117}
118
119impl Sub<Ciphertext> for &Ciphertext {
120 type Output = Ciphertext;
121
122 fn sub(self, rhs: Ciphertext) -> Self::Output {
123 Ciphertext(&self.0 - rhs.0, &self.1 - rhs.1)
124 }
125}
126
127impl Neg for Ciphertext {
128 type Output = Ciphertext;
129
130 fn neg(self) -> Self::Output {
131 Ciphertext(-self.0, -self.1)
132 }
133}
134
135impl Neg for &Ciphertext {
136 type Output = Ciphertext;
137
138 fn neg(self) -> Self::Output {
139 Ciphertext(-self.0, -self.1)
140 }
141}
142
143impl Mul<Scalar> for Ciphertext {
144 type Output = Ciphertext;
145
146 fn mul(self, rhs: Scalar) -> Self::Output {
147 Ciphertext(self.0 * rhs, self.1 * rhs)
148 }
149}
150
151impl Mul<Scalar> for &Ciphertext {
152 type Output = Ciphertext;
153
154 fn mul(self, rhs: Scalar) -> Self::Output {
155 Ciphertext(self.0 * rhs, self.1 * rhs)
156 }
157}
158
159impl Mul<&Scalar> for Ciphertext {
160 type Output = Ciphertext;
161
162 fn mul(self, rhs: &Scalar) -> Self::Output {
163 Ciphertext(self.0 * rhs, self.1 * rhs)
164 }
165}
166
167impl Mul<&Scalar> for &Ciphertext {
168 type Output = Ciphertext;
169
170 fn mul(self, rhs: &Scalar) -> Self::Output {
171 Ciphertext(self.0 * rhs, self.1 * rhs)
172 }
173}
174
175#[cfg(feature = "enable-serde")]
176#[cfg(test)]
177mod tests {
178 use rand::prelude::StdRng;
179 use rand_core::SeedableRng;
180
181 use crate::{DecryptionKey, RistrettoPoint};
182
183 #[test]
184 fn serde_ciphertext() {
185 const N: usize = 100;
186
187 let mut rng = StdRng::from_entropy();
188 let dk = DecryptionKey::new(&mut rng);
189
190 for _ in 0..N {
191 let ct = dk.encryption_key().encrypt(RistrettoPoint::random(&mut rng), &mut rng);
192 let encoded = bincode::serialize(&ct).unwrap();
193 assert_eq!(encoded.len(), 64);
194
195 let decoded = bincode::deserialize(&encoded).unwrap();
196 assert_eq!(ct, decoded);
197 }
198 }
199}