ferveo_tdec_temp5/
decryption.rs

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        // C_i = dk_i^{-1} * U
28        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        // See https://github.com/nucypher/ferveo/issues/42#issuecomment-1398953777
47        // D_i == e(C_i, Y_i)
48        if *decryption_share != E::pairing(self.checksum, *share_aggregate).0 {
49            return false;
50        }
51
52        // TODO: use multipairing here (h_inv) - Issue #192
53        // e(C_i, ek_i) == e(U, H)
54        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/// A decryption share for a simple variant of the threshold decryption scheme.
65/// In this variant, the decryption share require additional computation on the
66/// client side int order to be combined.
67#[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    /// Create a decryption share from the given parameters.
81    /// This function checks that the ciphertext is valid.
82    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    /// Create a decryption share from the given parameters.
97    /// This function does not check that the ciphertext is valid.
98    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        // D_i = e(U, Z_i)
104        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    /// Verify that the decryption share is valid.
118    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/// A decryption share for a precomputed variant of the threshold decryption scheme.
134/// In this variant, the decryption share is precomputed and can be combined
135/// without additional computation on the client side.
136/// The downside is that the threshold of decryption shares required to decrypt
137/// is equal to the number of private key shares in the scheme.
138#[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    /// Create a decryption share from the given parameters.
153    /// This function checks that the ciphertext is valid.
154    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    /// Create a decryption share from the given parameters.
173    /// This function does not check that the ciphertext is valid.
174    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        // U_{λ_i} = [λ_{i}(0)] U
182        let u_to_lagrange_coeff =
183            ciphertext_header.commitment.mul(lagrange_coeff);
184        // C_{λ_i} = e(U_{λ_i}, Z_i)
185        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    /// Verify that the decryption share is valid.
201    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}