group_threshold_cryptography_pre_release/
decryption.rs1use std::ops::Mul;
2
3use ark_ec::{pairing::Pairing, CurveGroup};
4use ark_ff::{Field, One, Zero};
5use ferveo_common::serialization;
6use itertools::{izip, zip_eq};
7use rand_core::RngCore;
8use serde::{de::DeserializeOwned, Deserialize, Serialize};
9use serde_with::serde_as;
10
11use crate::{
12 generate_random, Ciphertext, CiphertextHeader, PrivateKeyShare,
13 PublicDecryptionContextFast, PublicDecryptionContextSimple, Result,
14};
15
16#[serde_as]
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct DecryptionShareFast<E: Pairing> {
19 pub decrypter_index: usize,
20 #[serde_as(as = "serialization::SerdeAs")]
21 pub decryption_share: E::G1Affine,
22}
23
24#[serde_as]
25#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
26pub struct ValidatorShareChecksum<E: Pairing> {
27 #[serde_as(as = "serialization::SerdeAs")]
28 pub checksum: E::G1Affine,
29}
30
31impl<E: Pairing> ValidatorShareChecksum<E> {
32 pub fn new(
33 validator_decryption_key: &E::ScalarField,
34 ciphertext_header: &CiphertextHeader<E>,
35 ) -> Result<Self> {
36 let checksum = ciphertext_header
38 .commitment
39 .mul(
43 validator_decryption_key
44 .inverse()
45 .expect("Inverse of this key doesn't exist"),
46 )
47 .into_affine();
48 Ok(Self { checksum })
49 }
50
51 pub fn verify(
52 &self,
53 decryption_share: &E::TargetField,
54 share_aggregate: &E::G2Affine,
55 validator_public_key: &E::G2Affine,
56 h: &E::G2,
57 ciphertext: &Ciphertext<E>,
58 ) -> bool {
59 if *decryption_share != E::pairing(self.checksum, *share_aggregate).0 {
61 return false;
62 }
63
64 if E::pairing(self.checksum, *validator_public_key)
66 != E::pairing(ciphertext.commitment, *h)
67 {
68 return false;
69 }
70
71 true
72 }
73}
74
75#[serde_as]
76#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(bound(
78 serialize = "ValidatorShareChecksum<E>: Serialize",
79 deserialize = "ValidatorShareChecksum<E>: DeserializeOwned"
80))]
81pub struct DecryptionShareSimple<E: Pairing> {
82 #[serde_as(as = "serialization::SerdeAs")]
83 pub decryption_share: E::TargetField,
84 pub validator_checksum: ValidatorShareChecksum<E>,
85}
86
87impl<E: Pairing> DecryptionShareSimple<E> {
88 pub fn create(
91 validator_decryption_key: &E::ScalarField,
92 private_key_share: &PrivateKeyShare<E>,
93 ciphertext_header: &CiphertextHeader<E>,
94 aad: &[u8],
95 g_inv: &E::G1Prepared,
96 ) -> Result<Self> {
97 ciphertext_header.check(aad, g_inv)?;
98 Self::create_unchecked(
99 validator_decryption_key,
100 private_key_share,
101 ciphertext_header,
102 )
103 }
104
105 pub fn create_unchecked(
108 validator_decryption_key: &E::ScalarField,
109 private_key_share: &PrivateKeyShare<E>,
110 ciphertext_header: &CiphertextHeader<E>,
111 ) -> Result<Self> {
112 let decryption_share = E::pairing(
114 ciphertext_header.commitment,
115 private_key_share.private_key_share,
116 )
117 .0;
118
119 let validator_checksum = ValidatorShareChecksum::new(
120 validator_decryption_key,
121 ciphertext_header,
122 )?;
123
124 Ok(Self {
125 decryption_share,
126 validator_checksum,
127 })
128 }
129 pub fn verify(
131 &self,
132 share_aggregate: &E::G2Affine,
133 validator_public_key: &E::G2Affine,
134 h: &E::G2,
135 ciphertext: &Ciphertext<E>,
136 ) -> bool {
137 self.validator_checksum.verify(
138 &self.decryption_share,
139 share_aggregate,
140 validator_public_key,
141 h,
142 ciphertext,
143 )
144 }
145}
146
147#[serde_as]
148#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
149#[serde(bound(
150 serialize = "ValidatorShareChecksum<E>: Serialize",
151 deserialize = "ValidatorShareChecksum<E>: DeserializeOwned"
152))]
153pub struct DecryptionSharePrecomputed<E: Pairing> {
154 pub decrypter_index: usize,
155 #[serde_as(as = "serialization::SerdeAs")]
156 pub decryption_share: E::TargetField,
157 pub validator_checksum: ValidatorShareChecksum<E>,
158}
159
160impl<E: Pairing> DecryptionSharePrecomputed<E> {
161 pub fn new(
162 validator_index: usize,
163 validator_decryption_key: &E::ScalarField,
164 private_key_share: &PrivateKeyShare<E>,
165 ciphertext_header: &CiphertextHeader<E>,
166 aad: &[u8],
167 lagrange_coeff: &E::ScalarField,
168 g_inv: &E::G1Prepared,
169 ) -> Result<Self> {
170 ciphertext_header.check(aad, g_inv)?;
171 Self::create_unchecked(
172 validator_index,
173 validator_decryption_key,
174 private_key_share,
175 ciphertext_header,
176 lagrange_coeff,
177 )
178 }
179
180 pub fn create_unchecked(
181 validator_index: usize,
182 validator_decryption_key: &E::ScalarField,
183 private_key_share: &PrivateKeyShare<E>,
184 ciphertext_header: &CiphertextHeader<E>,
185 lagrange_coeff: &E::ScalarField,
186 ) -> Result<Self> {
187 let u_to_lagrange_coeff =
189 ciphertext_header.commitment.mul(lagrange_coeff);
190 let decryption_share = E::pairing(
192 u_to_lagrange_coeff,
193 private_key_share.private_key_share,
194 )
195 .0;
196
197 let validator_checksum = ValidatorShareChecksum::new(
198 validator_decryption_key,
199 ciphertext_header,
200 )?;
201
202 Ok(Self {
203 decrypter_index: validator_index,
204 decryption_share,
205 validator_checksum,
206 })
207 }
208
209 pub fn verify(
211 &self,
212 share_aggregate: &E::G2Affine,
213 validator_public_key: &E::G2Affine,
214 h: &E::G2,
215 ciphertext: &Ciphertext<E>,
216 ) -> bool {
217 self.validator_checksum.verify(
218 &self.decryption_share,
219 share_aggregate,
220 validator_public_key,
221 h,
222 ciphertext,
223 )
224 }
225}
226
227pub fn batch_verify_decryption_shares<R: RngCore, E: Pairing>(
229 pub_contexts: &[PublicDecryptionContextFast<E>],
230 ciphertexts: &[Ciphertext<E>],
231 decryption_shares: &[Vec<DecryptionShareFast<E>>],
232 rng: &mut R,
233) -> bool {
234 let num_ciphertexts = ciphertexts.len();
235 let num_shares = decryption_shares[0].len();
236
237 let blinding_keys = decryption_shares[0]
239 .iter()
240 .map(|d| {
241 pub_contexts[d.decrypter_index]
242 .blinded_key_share
243 .blinding_key_prepared
244 .clone()
245 })
246 .collect::<Vec<_>>();
247
248 let alpha_ij = (0..num_ciphertexts)
250 .map(|_| generate_random::<_, E>(num_shares, rng))
251 .collect::<Vec<_>>();
252
253 let mut pairings_a = Vec::with_capacity(num_shares + 1);
254 let mut pairings_b = Vec::with_capacity(num_shares + 1);
255
256 let sum_alpha_i = alpha_ij
258 .iter()
259 .map(|alpha_j| alpha_j.iter().sum::<E::ScalarField>())
260 .collect::<Vec<_>>();
261
262 let sum_u_i = E::G1Prepared::from(
264 izip!(ciphertexts.iter(), sum_alpha_i.iter())
265 .map(|(c, alpha_j)| c.commitment.mul(*alpha_j))
266 .sum::<E::G1>()
267 .into_affine(),
268 );
269
270 pairings_a.push(sum_u_i);
272 pairings_b.push(pub_contexts[0].h_inv.clone());
273
274 let mut sum_d_i = vec![E::G1::zero(); num_shares];
275
276 for (d, alpha_j) in izip!(decryption_shares.iter(), alpha_ij.iter()) {
278 for (sum_alpha_d_i, d_ij, alpha) in
279 izip!(sum_d_i.iter_mut(), d.iter(), alpha_j.iter())
280 {
281 *sum_alpha_d_i += d_ij.decryption_share.mul(*alpha);
282 }
283 }
284
285 for (d_i, b_i) in izip!(sum_d_i.iter(), blinding_keys.iter()) {
287 pairings_a.push(E::G1Prepared::from(d_i.into_affine()));
288 pairings_b.push(b_i.clone());
289 }
290
291 E::multi_pairing(pairings_a, pairings_b).0 == E::TargetField::one()
292}
293
294pub fn verify_decryption_shares_fast<E: Pairing>(
295 pub_contexts: &[PublicDecryptionContextFast<E>],
296 ciphertext: &Ciphertext<E>,
297 decryption_shares: &[DecryptionShareFast<E>],
298) -> bool {
299 let blinding_keys = decryption_shares
301 .iter()
302 .map(|d| {
303 pub_contexts[d.decrypter_index]
304 .blinded_key_share
305 .blinding_key_prepared
306 .clone()
307 })
308 .collect::<Vec<_>>();
309
310 let mut pairing_a: Vec<E::G1Prepared> = vec![];
311 let mut pairing_b = vec![];
312
313 pairing_a.push(ciphertext.commitment.into());
315 pairing_b.push(pub_contexts[0].h_inv.clone());
316
317 for (d_i, p_i) in zip_eq(decryption_shares, blinding_keys) {
318 let mut pairing_a_i = pairing_a.clone();
319 let mut pairing_b_i = pairing_b.clone();
320 pairing_a_i.push(d_i.decryption_share.into());
322 pairing_b_i.push(p_i.clone());
323 if E::multi_pairing(pairing_a_i, pairing_b_i).0 != E::TargetField::one()
324 {
325 return false;
326 }
327 }
328
329 true
330}
331
332pub fn verify_decryption_shares_simple<E: Pairing>(
333 pub_contexts: &Vec<PublicDecryptionContextSimple<E>>,
334 ciphertext: &Ciphertext<E>,
335 decryption_shares: &Vec<DecryptionShareSimple<E>>,
336) -> bool {
337 let blinded_key_shares = &pub_contexts
338 .iter()
339 .map(|c| &c.blinded_key_share.blinded_key_share)
340 .collect::<Vec<_>>();
341 for (decryption_share, y_i, pub_context) in
342 izip!(decryption_shares, blinded_key_shares, pub_contexts)
343 {
344 let is_valid = decryption_share.verify(
345 y_i,
346 &pub_context.validator_public_key.into_affine(),
347 &pub_context.h.into(),
348 ciphertext,
349 );
350 if !is_valid {
351 return false;
352 }
353 }
354 true
355}
356
357#[cfg(test)]
358mod tests {
359 use ark_ec::AffineRepr;
360 use ferveo_common::{FromBytes, ToBytes};
361
362 use crate::*;
363
364 type E = ark_bls12_381::Bls12_381;
365
366 #[test]
367 fn decryption_share_serialization() {
368 let decryption_share = DecryptionShareFast::<E> {
369 decrypter_index: 1,
370 decryption_share: ark_bls12_381::G1Affine::generator(),
371 };
372
373 let serialized = decryption_share.to_bytes().unwrap();
374 let deserialized: DecryptionShareFast<E> =
375 DecryptionShareFast::from_bytes(&serialized).unwrap();
376 assert_eq!(serialized, deserialized.to_bytes().unwrap())
377 }
378}