w3f_bls/
double_pop.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
//! ## Implementation of ProofofPossion trait for Double BLS public keys using
//! the scheme described in [https://eprint.iacr.org/2022/1611] which also
//! complies with the proof of possession proposed in
//! [draft-irtf-cfrg-bls-signature-05](https://www.ietf.org/archive/id/draft-irtf-cfrg-bls-signature-05.html)

use crate::engine::EngineBLS;
use crate::{DoubleSignature, Message, ProofOfPossession, ProofOfPossessionGenerator};

use crate::double::{DoublePublicKey, DoublePublicKeyScheme};
use crate::serialize::SerializableToBytes;
use crate::single::{Keypair, PublicKey};

use alloc::vec::Vec;
use digest::DynDigest;

use ark_ec::Group;
use ark_ff::field_hashers::{DefaultFieldHasher, HashToField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};

/// Proof Of Possession of the secret key as the secret scaler genarting both public
/// keys in G1 and G2 by generating a BLS Signature of public key (in G2)
#[derive(CanonicalSerialize, CanonicalDeserialize)]
pub struct NuggetBLSPoP<E: EngineBLS>(pub E::SignatureGroup);

//The bls proof of possession for single or double public key schemes are the same
impl<E: EngineBLS, H: DynDigest + Default + Clone>
    ProofOfPossessionGenerator<E, H, DoublePublicKey<E>, NuggetBLSPoP<E>> for Keypair<E>
{
    fn generate_pok(&mut self) -> NuggetBLSPoP<E> {
        //We simply classicaly BLS sign public key in G2 based on https://eprint.iacr.org/2022/1611
        let sigma_pop = ProofOfPossessionGenerator::<E, H, DoublePublicKey<E>, NuggetBLSnCPPoP<E>>::generate_pok(self);
        NuggetBLSPoP::<E>(sigma_pop.0 .0)
    }
}

/// Serialization for DoublePublickey
impl<E: EngineBLS> SerializableToBytes for NuggetBLSPoP<E> {
    const SERIALIZED_BYTES_SIZE: usize = E::SIGNATURE_SERIALIZED_SIZE;
}

/// The verification process for verifying both possession of one secret key
/// for two public key is different.
impl<E: EngineBLS, H: DynDigest + Default + Clone> ProofOfPossession<E, H, DoublePublicKey<E>>
    for NuggetBLSPoP<E>
{
    /// verify the validity of PoP by performing the following Pairing
    /// e(H_pop(pk_2) + t.g_1, pk_2) = e(sign(H_pop(pk_2))+ t.pk_1, g_2)
    /// we verifying by calling the verify_prepared ⎈function from the
    /// engine.
    fn verify(&self, public_key_of_prover: &DoublePublicKey<E>) -> bool {
        //First we need to generate our randomness in a way that
        //prover is unable to predict. We assume g1 and g2 are fixed.

        let public_key_as_bytes =
            <E as EngineBLS>::public_key_point_to_byte(&public_key_of_prover.1);
        let public_key_in_signature_group = public_key_of_prover.0;
        let public_key_in_signature_group_as_bytes =
            E::signature_point_to_byte(&public_key_in_signature_group);

        let public_key_hashed_to_signature_group =
            Message::new_pop_message(b"", &public_key_as_bytes).hash_to_signature_curve::<E>();
        let public_key_hashed_to_signature_group_as_bytes =
            E::signature_point_to_byte(&public_key_hashed_to_signature_group);
        let random_oracle_seed = [
            public_key_hashed_to_signature_group_as_bytes,
            public_key_as_bytes,
            public_key_in_signature_group_as_bytes,
            E::signature_point_to_byte(&self.0),
        ]
        .concat();

        let hasher = <DefaultFieldHasher<H> as HashToField<
            <<E as EngineBLS>::PublicKeyGroup as Group>::ScalarField,
        >>::new(&[]);

        let randomization_coefficient: E::Scalar =
            hasher.hash_to_field(random_oracle_seed.as_slice(), 1)[0];

        let mut randomized_pub_in_g1 = public_key_in_signature_group;
        randomized_pub_in_g1 *= randomization_coefficient;
        let signature = E::prepare_signature(self.0 + randomized_pub_in_g1);
        let prepared_public_key = E::prepare_public_key(public_key_of_prover.1);
        let prepared = [
            (
                prepared_public_key.clone(),
                E::prepare_signature(public_key_hashed_to_signature_group),
            ),
            (
                prepared_public_key.clone(),
                E::prepare_signature(E::generator_of_signature_group() * randomization_coefficient),
            ),
        ];
        E::verify_prepared(signature, prepared.iter())
    }
}

/// Proof Of Possession of the secret key as the secret scaler genarting both public
/// keys in G1 and G2 by generating a BLS Signature of public key (in G2) plus proof
/// of knowledge of the secret key of the chaum-pedersen key (samae secret key)
#[derive(CanonicalSerialize, CanonicalDeserialize)]
pub struct NuggetBLSnCPPoP<E: EngineBLS>(pub DoubleSignature<E>);

//The implement the generation of bls proof of possession including  chaum-pederesno PoP for double public key schemes
impl<E: EngineBLS, H: DynDigest + Default + Clone>
    ProofOfPossessionGenerator<E, H, DoublePublicKey<E>, NuggetBLSnCPPoP<E>> for Keypair<E>
{
    fn generate_pok(&mut self) -> NuggetBLSnCPPoP<E> {
        //We simply classicaly BLS sign public key in G2 based on https://eprint.iacr.org/2022/1611
        let public_key_as_bytes = self.public.to_bytes();
        let sigma_pop = DoublePublicKeyScheme::<E>::sign(
            self,
            &Message::new_pop_message(b"", &public_key_as_bytes.as_slice()),
        );

        NuggetBLSnCPPoP::<E>(sigma_pop)
    }
}

/// Serialization for NuggetBLSnCPPoP
impl<E: EngineBLS> SerializableToBytes for NuggetBLSnCPPoP<E> {
    const SERIALIZED_BYTES_SIZE: usize =
        <DoubleSignature<E> as SerializableToBytes>::SERIALIZED_BYTES_SIZE;
}

/// The verification process for verifying both nugget BLS and CP
impl<E: EngineBLS, H: DynDigest + Default + Clone> ProofOfPossession<E, H, DoublePublicKey<E>>
    for NuggetBLSnCPPoP<E>
{
    /// verify the validity of PoP by verifying nugget PoP and the CP
    /// signature
    fn verify(&self, public_key_of_prover: &DoublePublicKey<E>) -> bool {
        let public_key_in_public_key_group_as_bytes =
            PublicKey::<E>(public_key_of_prover.1).to_bytes();
        //verify double pairing && verify cp
        <NuggetBLSPoP<E> as ProofOfPossession<E, H, DoublePublicKey<E>>>::verify(
            &NuggetBLSPoP::<E>(self.0 .0),
            public_key_of_prover,
        ) && public_key_of_prover.verify(
            &Message::new_pop_message(b"", &public_key_in_public_key_group_as_bytes.as_slice()),
            &self.0,
        )
    }
}

#[cfg(all(test, feature = "std"))]
mod tests {
    use crate::double::DoublePublicKeyScheme;
    use crate::engine::TinyBLS381;
    use crate::serialize::SerializableToBytes;
    use crate::single::Keypair;
    use crate::{double_pop::NuggetBLSPoP, DoublePublicKey};
    use crate::{ProofOfPossession, ProofOfPossessionGenerator};

    use rand::thread_rng;
    use sha2::Sha256;

    use super::NuggetBLSnCPPoP;

    fn double_bls_pop_sign<
        PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>>,
    >()
    where
        Keypair<TinyBLS381>:
            ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
    {
        let mut keypair = Keypair::<TinyBLS381>::generate(thread_rng());
        <Keypair<TinyBLS381> as ProofOfPossessionGenerator<
            TinyBLS381,
            Sha256,
            DoublePublicKey<TinyBLS381>,
            PoPFlavor,
        >>::generate_pok(&mut keypair);
    }

    #[test]
    fn nugget_bls_pop_sign() {
        double_bls_pop_sign::<NuggetBLSPoP<TinyBLS381>>();
    }

    #[test]
    fn nugget_bls_and_cp_pop_sign() {
        double_bls_pop_sign::<NuggetBLSnCPPoP<TinyBLS381>>();
    }

    fn double_bls_pop_sign_and_verify<
        PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>>,
    >()
    where
        Keypair<TinyBLS381>:
            ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
    {
        let mut keypair = Keypair::<TinyBLS381>::generate(thread_rng());
        let proof_pair = <dyn ProofOfPossessionGenerator<
            TinyBLS381,
            Sha256,
            DoublePublicKey<TinyBLS381>,
            PoPFlavor,
        >>::generate_pok(&mut keypair);
        assert!(
            ProofOfPossession::<TinyBLS381, Sha256, DoublePublicKey::<TinyBLS381>>::verify(
                &proof_pair,
                &DoublePublicKeyScheme::into_double_public_key(&keypair)
            ),
            "valid pok does not verify"
        );
    }

    #[test]
    fn nugget_bls_pop_sign_and_verify() {
        double_bls_pop_sign_and_verify::<NuggetBLSPoP<TinyBLS381>>();
    }

    #[test]
    fn nugget_bls_and_cp_pop_sign_and_verify() {
        double_bls_pop_sign_and_verify::<NuggetBLSnCPPoP<TinyBLS381>>();
    }

    fn double_bls_pop_of_random_public_key_should_fail<
        PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>>,
    >()
    where
        Keypair<TinyBLS381>:
            ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
    {
        let mut keypair_good = Keypair::<TinyBLS381>::generate(thread_rng());
        let proof_pair = <dyn ProofOfPossessionGenerator<
            TinyBLS381,
            Sha256,
            DoublePublicKey<TinyBLS381>,
            PoPFlavor,
        >>::generate_pok(&mut keypair_good);
        let keypair_bad = Keypair::<TinyBLS381>::generate(thread_rng());
        assert!(
            !ProofOfPossession::<TinyBLS381, Sha256, DoublePublicKey::<TinyBLS381>>::verify(
                &proof_pair,
                &DoublePublicKeyScheme::into_double_public_key(&keypair_bad)
            ),
            "invalid pok of unrelated public key should not verify"
        );
    }

    #[test]
    fn nugget_bls_pop_of_random_public_key_should_fail() {
        double_bls_pop_of_random_public_key_should_fail::<NuggetBLSPoP<TinyBLS381>>();
    }

    #[test]
    fn nugget_bls_and_cp_pop_of_random_public_key_should_fail() {
        double_bls_pop_of_random_public_key_should_fail::<NuggetBLSnCPPoP<TinyBLS381>>();
    }

    fn pop_of_a_double_public_key_should_serialize_and_deserialize_for_bls12_381<
        PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>> + SerializableToBytes,
    >()
    where
        Keypair<TinyBLS381>:
            ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
    {
        let mut keypair = Keypair::<TinyBLS381>::generate(thread_rng());

        let proof_pair = <dyn ProofOfPossessionGenerator<
            TinyBLS381,
            Sha256,
            DoublePublicKey<TinyBLS381>,
            PoPFlavor,
        >>::generate_pok(&mut keypair);

        let serialized_proof = proof_pair.to_bytes();
        let deserialized_proof = PoPFlavor::from_bytes(&serialized_proof).unwrap();

        assert!(
            ProofOfPossession::<TinyBLS381, Sha256, DoublePublicKey::<TinyBLS381>>::verify(
                &deserialized_proof,
                &DoublePublicKeyScheme::into_double_public_key(&keypair)
            ),
            "valid pok does not verify"
        );
    }

    #[test]
    fn nugget_bls_pop_should_serialize_and_deserialize_for_bls12_381() {
        pop_of_a_double_public_key_should_serialize_and_deserialize_for_bls12_381::<
            NuggetBLSPoP<TinyBLS381>,
        >();
    }

    #[test]
    fn nugget_bls_and_cp_pop_should_serialize_and_deserialize_for_bls12_381() {
        pop_of_a_double_public_key_should_serialize_and_deserialize_for_bls12_381::<
            NuggetBLSnCPPoP<TinyBLS381>,
        >();
    }
}