fastcrypto_tbls/
ecies_v1.rs1use crate::ecies::{PrivateKey, PublicKey, RecoveryPackage};
5use crate::nizk::DdhTupleNizk;
6use crate::random_oracle::RandomOracle;
7use fastcrypto::aes::{Aes256Ctr, AesKey, Cipher, InitializationVector};
8use fastcrypto::error::{FastCryptoError, FastCryptoResult};
9use fastcrypto::groups::{FiatShamirChallenge, GroupElement, HashToGroupElement, Scalar};
10use fastcrypto::traits::{AllowedRng, ToFromBytes};
11use serde::{Deserialize, Serialize};
12use typenum::consts::{U16, U32};
13use typenum::Unsigned;
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28pub struct MultiRecipientEncryption<G: GroupElement> {
29 c: G,
30 c_hat: G,
31 encs: Vec<Vec<u8>>,
32 pub proof: DdhTupleNizk<G>,
33}
34
35impl<G: GroupElement + Serialize> MultiRecipientEncryption<G>
36where
37 <G as GroupElement>::ScalarType: FiatShamirChallenge,
38 G: HashToGroupElement,
39{
40 pub fn encrypt<R: AllowedRng>(
41 pk_and_msgs: &[(PublicKey<G>, Vec<u8>)],
42 encryption_random_oracle: &RandomOracle,
43 rng: &mut R,
44 ) -> MultiRecipientEncryption<G> {
45 let r = G::ScalarType::rand(rng);
46 let c = G::generator() * r;
47 let g_hat = G::hash_to_group_element(
48 &Self::g_hat_random_oracle(encryption_random_oracle).evaluate(&c),
49 );
50 let c_hat = g_hat * r;
51 let proof = DdhTupleNizk::<G>::create(
52 &r,
53 &g_hat,
54 &c,
55 &c_hat,
56 &Self::zk_random_oracle(encryption_random_oracle),
57 rng,
58 );
59
60 let encs_ro = Self::encs_random_oracle(encryption_random_oracle);
61 let encs = pk_and_msgs
62 .iter()
63 .enumerate()
64 .map(|(receiver_index, (receiver_pk, msg))| {
65 let pk_r = receiver_pk.0 * r;
66 let k = encs_ro.evaluate(&(receiver_index, pk_r));
67 let cipher = sym_cipher(&k);
68 cipher.encrypt(&fixed_zero_nonce(), msg)
70 })
71 .collect::<Vec<_>>();
72
73 MultiRecipientEncryption {
74 c,
75 c_hat,
76 encs,
77 proof,
78 }
79 }
80
81 pub fn verify(&self, encryption_random_oracle: &RandomOracle) -> FastCryptoResult<()> {
82 let g_hat = G::hash_to_group_element(
83 &Self::g_hat_random_oracle(encryption_random_oracle).evaluate(&self.c),
84 );
85 self.proof.verify(
86 &g_hat,
87 &self.c,
88 &self.c_hat,
89 &Self::zk_random_oracle(encryption_random_oracle),
90 )?;
91 self.encs
93 .iter()
94 .all(|e| !e.is_empty())
95 .then_some(())
96 .ok_or(FastCryptoError::InvalidInput)
97 }
98
99 pub fn decrypt(
102 &self,
103 sk: &PrivateKey<G>,
104 encryption_random_oracle: &RandomOracle,
105 receiver_index: usize,
106 ) -> Vec<u8> {
107 let enc_ro = Self::encs_random_oracle(encryption_random_oracle);
108 let ephemeral_key = self.c * sk.0;
109 let k = enc_ro.evaluate(&(receiver_index, ephemeral_key));
110 let cipher = sym_cipher(&k);
111 cipher
112 .decrypt(&fixed_zero_nonce(), &self.encs[receiver_index])
113 .expect("Decrypt should never fail for CTR mode")
114 }
115
116 pub fn create_recovery_package<R: AllowedRng>(
119 &self,
120 sk: &PrivateKey<G>,
121 recovery_random_oracle: &RandomOracle,
122 rng: &mut R,
123 ) -> RecoveryPackage<G> {
124 let pk = G::generator() * sk.0;
125 let ephemeral_key = self.c * sk.0;
126
127 let proof = DdhTupleNizk::<G>::create(
128 &sk.0,
129 &self.c,
130 &pk,
131 &ephemeral_key,
132 recovery_random_oracle,
133 rng,
134 );
135
136 RecoveryPackage {
137 ephemeral_key,
138 proof,
139 }
140 }
141
142 pub fn decrypt_with_recovery_package(
143 &self,
144 pkg: &RecoveryPackage<G>,
145 recovery_random_oracle: &RandomOracle,
146 encryption_random_oracle: &RandomOracle,
147 receiver_pk: &PublicKey<G>,
148 receiver_index: usize,
149 ) -> FastCryptoResult<Vec<u8>> {
150 assert!(receiver_index < self.encs.len());
151 pkg.proof.verify(
152 &self.c,
153 &receiver_pk.0,
154 &pkg.ephemeral_key,
155 recovery_random_oracle,
156 )?;
157 let encs_ro = Self::encs_random_oracle(encryption_random_oracle);
158 let k = encs_ro.evaluate(&(receiver_index, pkg.ephemeral_key));
159 let cipher = sym_cipher(&k);
160 Ok(cipher
161 .decrypt(&fixed_zero_nonce(), &self.encs[receiver_index])
162 .expect("Decrypt should never fail for CTR mode"))
163 }
164
165 pub fn len(&self) -> usize {
166 self.encs.len()
167 }
168 pub fn is_empty(&self) -> bool {
169 self.encs.is_empty()
170 }
171
172 pub fn ephemeral_key(&self) -> &G {
174 &self.c
175 }
176
177 pub fn proof(&self) -> &DdhTupleNizk<G> {
179 &self.proof
180 }
181
182 fn encs_random_oracle(encryption_random_oracle: &RandomOracle) -> RandomOracle {
183 encryption_random_oracle.extend("encs")
184 }
185
186 fn zk_random_oracle(encryption_random_oracle: &RandomOracle) -> RandomOracle {
187 encryption_random_oracle.extend("zk")
188 }
189
190 fn g_hat_random_oracle(encryption_random_oracle: &RandomOracle) -> RandomOracle {
191 encryption_random_oracle.extend("g_hat")
192 }
193
194 #[cfg(test)]
195 pub fn modify_c_hat_for_testing(&mut self, c_hat: G) {
196 self.c_hat = c_hat;
197 }
198
199 #[cfg(test)]
200 pub fn copy_for_testing(&mut self, src: usize, dst: usize) {
201 self.encs[dst] = self.encs[src].clone();
202 }
203}
204
205fn fixed_zero_nonce() -> InitializationVector<U16> {
206 InitializationVector::<U16>::from_bytes(&[0u8; 16])
207 .expect("U16 could always be set from a 16 bytes array of zeros")
208}
209
210fn sym_cipher(k: &[u8; 64]) -> Aes256Ctr {
211 Aes256Ctr::new(
212 AesKey::<U32>::from_bytes(&k[0..U32::USIZE])
213 .expect("New shouldn't fail as use fixed size key is used"),
214 )
215}