1use std::ops::Mul;
2
3use ark_ec::{pairing::Pairing, CurveGroup, Group};
4use ark_ff::Field;
5use ferveo_common::serialization;
6use itertools::izip;
7use serde::{de::DeserializeOwned, Deserialize, Serialize};
8use serde_with::serde_as;
9
10use crate::{
11 Ciphertext, CiphertextHeader, PrivateKeyShare,
12 PublicDecryptionContextSimple, Result,
13};
14
15#[serde_as]
16#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
17pub struct ValidatorShareChecksum<E: Pairing> {
18 #[serde_as(as = "serialization::SerdeAs")]
19 pub checksum: E::G1Affine,
20}
21
22impl<E: Pairing> ValidatorShareChecksum<E> {
23 pub fn new(
24 validator_decryption_key: &E::ScalarField,
25 ciphertext_header: &CiphertextHeader<E>,
26 ) -> Result<Self> {
27 let checksum = ciphertext_header
29 .commitment
30 .mul(
31 validator_decryption_key
32 .inverse()
33 .expect("Inverse of this key doesn't exist"),
34 )
35 .into_affine();
36 Ok(Self { checksum })
37 }
38
39 pub fn verify(
40 &self,
41 decryption_share: &E::TargetField,
42 share_aggregate: &E::G2Affine,
43 validator_public_key: &E::G2Affine,
44 ciphertext: &Ciphertext<E>,
45 ) -> bool {
46 if *decryption_share != E::pairing(self.checksum, *share_aggregate).0 {
49 return false;
50 }
51
52 if E::pairing(self.checksum, *validator_public_key)
55 != E::pairing(ciphertext.commitment, E::G2::generator())
56 {
57 return false;
58 }
59
60 true
61 }
62}
63
64#[serde_as]
68#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
69pub struct DecryptionShareSimple<E: Pairing> {
70 #[serde_as(as = "serialization::SerdeAs")]
71 pub decryption_share: E::TargetField,
72 #[serde(bound(
73 serialize = "ValidatorShareChecksum<E>: Serialize",
74 deserialize = "ValidatorShareChecksum<E>: DeserializeOwned"
75 ))]
76 pub validator_checksum: ValidatorShareChecksum<E>,
77}
78
79impl<E: Pairing> DecryptionShareSimple<E> {
80 pub fn create(
83 validator_decryption_key: &E::ScalarField,
84 private_key_share: &PrivateKeyShare<E>,
85 ciphertext_header: &CiphertextHeader<E>,
86 aad: &[u8],
87 ) -> Result<Self> {
88 ciphertext_header.check(aad)?;
89 Self::create_unchecked(
90 validator_decryption_key,
91 private_key_share,
92 ciphertext_header,
93 )
94 }
95
96 pub fn create_unchecked(
99 validator_decryption_key: &E::ScalarField,
100 private_key_share: &PrivateKeyShare<E>,
101 ciphertext_header: &CiphertextHeader<E>,
102 ) -> Result<Self> {
103 let decryption_share =
105 E::pairing(ciphertext_header.commitment, private_key_share.0).0;
106
107 let validator_checksum = ValidatorShareChecksum::new(
108 validator_decryption_key,
109 ciphertext_header,
110 )?;
111
112 Ok(Self {
113 decryption_share,
114 validator_checksum,
115 })
116 }
117 pub fn verify(
119 &self,
120 share_aggregate: &E::G2Affine,
121 validator_public_key: &E::G2Affine,
122 ciphertext: &Ciphertext<E>,
123 ) -> bool {
124 self.validator_checksum.verify(
125 &self.decryption_share,
126 share_aggregate,
127 validator_public_key,
128 ciphertext,
129 )
130 }
131}
132
133#[serde_as]
139#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
140pub struct DecryptionSharePrecomputed<E: Pairing> {
141 pub decrypter_index: usize,
142 #[serde_as(as = "serialization::SerdeAs")]
143 pub decryption_share: E::TargetField,
144 #[serde(bound(
145 serialize = "ValidatorShareChecksum<E>: Serialize",
146 deserialize = "ValidatorShareChecksum<E>: DeserializeOwned"
147 ))]
148 pub validator_checksum: ValidatorShareChecksum<E>,
149}
150
151impl<E: Pairing> DecryptionSharePrecomputed<E> {
152 pub fn create(
155 validator_index: usize,
156 validator_decryption_key: &E::ScalarField,
157 private_key_share: &PrivateKeyShare<E>,
158 ciphertext_header: &CiphertextHeader<E>,
159 aad: &[u8],
160 lagrange_coeff: &E::ScalarField,
161 ) -> Result<Self> {
162 ciphertext_header.check(aad)?;
163 Self::create_unchecked(
164 validator_index,
165 validator_decryption_key,
166 private_key_share,
167 ciphertext_header,
168 lagrange_coeff,
169 )
170 }
171
172 pub fn create_unchecked(
175 validator_index: usize,
176 validator_decryption_key: &E::ScalarField,
177 private_key_share: &PrivateKeyShare<E>,
178 ciphertext_header: &CiphertextHeader<E>,
179 lagrange_coeff: &E::ScalarField,
180 ) -> Result<Self> {
181 let u_to_lagrange_coeff =
183 ciphertext_header.commitment.mul(lagrange_coeff);
184 let decryption_share =
186 E::pairing(u_to_lagrange_coeff, private_key_share.0).0;
187
188 let validator_checksum = ValidatorShareChecksum::new(
189 validator_decryption_key,
190 ciphertext_header,
191 )?;
192
193 Ok(Self {
194 decrypter_index: validator_index,
195 decryption_share,
196 validator_checksum,
197 })
198 }
199
200 pub fn verify(
202 &self,
203 share_aggregate: &E::G2Affine,
204 validator_public_key: &E::G2Affine,
205 ciphertext: &Ciphertext<E>,
206 ) -> bool {
207 self.validator_checksum.verify(
208 &self.decryption_share,
209 share_aggregate,
210 validator_public_key,
211 ciphertext,
212 )
213 }
214}
215
216pub fn verify_decryption_shares_simple<E: Pairing>(
217 pub_contexts: &Vec<PublicDecryptionContextSimple<E>>,
218 ciphertext: &Ciphertext<E>,
219 decryption_shares: &Vec<DecryptionShareSimple<E>>,
220) -> bool {
221 let blinded_key_shares = &pub_contexts
222 .iter()
223 .map(|c| &c.blinded_key_share.blinded_key_share)
224 .collect::<Vec<_>>();
225 for (decryption_share, y_i, pub_context) in
226 izip!(decryption_shares, blinded_key_shares, pub_contexts)
227 {
228 let is_valid = decryption_share.verify(
229 y_i,
230 &pub_context.validator_public_key.encryption_key,
231 ciphertext,
232 );
233 if !is_valid {
234 return false;
235 }
236 }
237 true
238}