1use crate::engine::EngineBLS;
7use crate::{DoubleSignature, Message, ProofOfPossession, ProofOfPossessionGenerator};
8
9use crate::double::{DoublePublicKey, DoublePublicKeyScheme};
10use crate::serialize::SerializableToBytes;
11use crate::single::{Keypair, PublicKey};
12
13use alloc::vec::Vec;
14use digest::DynDigest;
15
16use ark_ec::Group;
17use ark_ff::field_hashers::{DefaultFieldHasher, HashToField};
18use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
19
20#[derive(CanonicalSerialize, CanonicalDeserialize)]
23pub struct NuggetBLSPoP<E: EngineBLS>(pub E::SignatureGroup);
24
25impl<E: EngineBLS, H: DynDigest + Default + Clone>
27 ProofOfPossessionGenerator<E, H, DoublePublicKey<E>, NuggetBLSPoP<E>> for Keypair<E>
28{
29 fn generate_pok(&mut self) -> NuggetBLSPoP<E> {
30 let sigma_pop = ProofOfPossessionGenerator::<E, H, DoublePublicKey<E>, NuggetBLSnCPPoP<E>>::generate_pok(self);
32 NuggetBLSPoP::<E>(sigma_pop.0 .0)
33 }
34}
35
36impl<E: EngineBLS> SerializableToBytes for NuggetBLSPoP<E> {
38 const SERIALIZED_BYTES_SIZE: usize = E::SIGNATURE_SERIALIZED_SIZE;
39}
40
41impl<E: EngineBLS, H: DynDigest + Default + Clone> ProofOfPossession<E, H, DoublePublicKey<E>>
44 for NuggetBLSPoP<E>
45{
46 fn verify(&self, public_key_of_prover: &DoublePublicKey<E>) -> bool {
51 let public_key_as_bytes =
55 <E as EngineBLS>::public_key_point_to_byte(&public_key_of_prover.1);
56 let public_key_in_signature_group = public_key_of_prover.0;
57 let public_key_in_signature_group_as_bytes =
58 E::signature_point_to_byte(&public_key_in_signature_group);
59
60 let public_key_hashed_to_signature_group =
61 Message::new_pop_message(b"", &public_key_as_bytes).hash_to_signature_curve::<E>();
62 let public_key_hashed_to_signature_group_as_bytes =
63 E::signature_point_to_byte(&public_key_hashed_to_signature_group);
64 let random_oracle_seed = [
65 public_key_hashed_to_signature_group_as_bytes,
66 public_key_as_bytes,
67 public_key_in_signature_group_as_bytes,
68 E::signature_point_to_byte(&self.0),
69 ]
70 .concat();
71
72 let hasher = <DefaultFieldHasher<H> as HashToField<
73 <<E as EngineBLS>::PublicKeyGroup as Group>::ScalarField,
74 >>::new(&[]);
75
76 let randomization_coefficient: E::Scalar =
77 hasher.hash_to_field(random_oracle_seed.as_slice(), 1)[0];
78
79 let mut randomized_pub_in_g1 = public_key_in_signature_group;
80 randomized_pub_in_g1 *= randomization_coefficient;
81 let signature = E::prepare_signature(self.0 + randomized_pub_in_g1);
82 let prepared_public_key = E::prepare_public_key(public_key_of_prover.1);
83 let prepared = [
84 (
85 prepared_public_key.clone(),
86 E::prepare_signature(public_key_hashed_to_signature_group),
87 ),
88 (
89 prepared_public_key.clone(),
90 E::prepare_signature(E::generator_of_signature_group() * randomization_coefficient),
91 ),
92 ];
93 E::verify_prepared(signature, prepared.iter())
94 }
95}
96
97#[derive(CanonicalSerialize, CanonicalDeserialize)]
101pub struct NuggetBLSnCPPoP<E: EngineBLS>(pub DoubleSignature<E>);
102
103impl<E: EngineBLS, H: DynDigest + Default + Clone>
105 ProofOfPossessionGenerator<E, H, DoublePublicKey<E>, NuggetBLSnCPPoP<E>> for Keypair<E>
106{
107 fn generate_pok(&mut self) -> NuggetBLSnCPPoP<E> {
108 let public_key_as_bytes = self.public.to_bytes();
110 let sigma_pop = DoublePublicKeyScheme::<E>::sign(
111 self,
112 &Message::new_pop_message(b"", &public_key_as_bytes.as_slice()),
113 );
114
115 NuggetBLSnCPPoP::<E>(sigma_pop)
116 }
117}
118
119impl<E: EngineBLS> SerializableToBytes for NuggetBLSnCPPoP<E> {
121 const SERIALIZED_BYTES_SIZE: usize =
122 <DoubleSignature<E> as SerializableToBytes>::SERIALIZED_BYTES_SIZE;
123}
124
125impl<E: EngineBLS, H: DynDigest + Default + Clone> ProofOfPossession<E, H, DoublePublicKey<E>>
127 for NuggetBLSnCPPoP<E>
128{
129 fn verify(&self, public_key_of_prover: &DoublePublicKey<E>) -> bool {
132 let public_key_in_public_key_group_as_bytes =
133 PublicKey::<E>(public_key_of_prover.1).to_bytes();
134 <NuggetBLSPoP<E> as ProofOfPossession<E, H, DoublePublicKey<E>>>::verify(
136 &NuggetBLSPoP::<E>(self.0 .0),
137 public_key_of_prover,
138 ) && public_key_of_prover.verify(
139 &Message::new_pop_message(b"", &public_key_in_public_key_group_as_bytes.as_slice()),
140 &self.0,
141 )
142 }
143}
144
145#[cfg(all(test, feature = "std"))]
146mod tests {
147 use crate::double::DoublePublicKeyScheme;
148 use crate::engine::TinyBLS381;
149 use crate::serialize::SerializableToBytes;
150 use crate::single::Keypair;
151 use crate::{double_pop::NuggetBLSPoP, DoublePublicKey};
152 use crate::{ProofOfPossession, ProofOfPossessionGenerator};
153
154 use rand::thread_rng;
155 use sha2::Sha256;
156
157 use super::NuggetBLSnCPPoP;
158
159 fn double_bls_pop_sign<
160 PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>>,
161 >()
162 where
163 Keypair<TinyBLS381>:
164 ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
165 {
166 let mut keypair = Keypair::<TinyBLS381>::generate(thread_rng());
167 <Keypair<TinyBLS381> as ProofOfPossessionGenerator<
168 TinyBLS381,
169 Sha256,
170 DoublePublicKey<TinyBLS381>,
171 PoPFlavor,
172 >>::generate_pok(&mut keypair);
173 }
174
175 #[test]
176 fn nugget_bls_pop_sign() {
177 double_bls_pop_sign::<NuggetBLSPoP<TinyBLS381>>();
178 }
179
180 #[test]
181 fn nugget_bls_and_cp_pop_sign() {
182 double_bls_pop_sign::<NuggetBLSnCPPoP<TinyBLS381>>();
183 }
184
185 fn double_bls_pop_sign_and_verify<
186 PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>>,
187 >()
188 where
189 Keypair<TinyBLS381>:
190 ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
191 {
192 let mut keypair = Keypair::<TinyBLS381>::generate(thread_rng());
193 let proof_pair = <dyn ProofOfPossessionGenerator<
194 TinyBLS381,
195 Sha256,
196 DoublePublicKey<TinyBLS381>,
197 PoPFlavor,
198 >>::generate_pok(&mut keypair);
199 assert!(
200 ProofOfPossession::<TinyBLS381, Sha256, DoublePublicKey::<TinyBLS381>>::verify(
201 &proof_pair,
202 &DoublePublicKeyScheme::into_double_public_key(&keypair)
203 ),
204 "valid pok does not verify"
205 );
206 }
207
208 #[test]
209 fn nugget_bls_pop_sign_and_verify() {
210 double_bls_pop_sign_and_verify::<NuggetBLSPoP<TinyBLS381>>();
211 }
212
213 #[test]
214 fn nugget_bls_and_cp_pop_sign_and_verify() {
215 double_bls_pop_sign_and_verify::<NuggetBLSnCPPoP<TinyBLS381>>();
216 }
217
218 fn double_bls_pop_of_random_public_key_should_fail<
219 PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>>,
220 >()
221 where
222 Keypair<TinyBLS381>:
223 ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
224 {
225 let mut keypair_good = Keypair::<TinyBLS381>::generate(thread_rng());
226 let proof_pair = <dyn ProofOfPossessionGenerator<
227 TinyBLS381,
228 Sha256,
229 DoublePublicKey<TinyBLS381>,
230 PoPFlavor,
231 >>::generate_pok(&mut keypair_good);
232 let keypair_bad = Keypair::<TinyBLS381>::generate(thread_rng());
233 assert!(
234 !ProofOfPossession::<TinyBLS381, Sha256, DoublePublicKey::<TinyBLS381>>::verify(
235 &proof_pair,
236 &DoublePublicKeyScheme::into_double_public_key(&keypair_bad)
237 ),
238 "invalid pok of unrelated public key should not verify"
239 );
240 }
241
242 #[test]
243 fn nugget_bls_pop_of_random_public_key_should_fail() {
244 double_bls_pop_of_random_public_key_should_fail::<NuggetBLSPoP<TinyBLS381>>();
245 }
246
247 #[test]
248 fn nugget_bls_and_cp_pop_of_random_public_key_should_fail() {
249 double_bls_pop_of_random_public_key_should_fail::<NuggetBLSnCPPoP<TinyBLS381>>();
250 }
251
252 fn pop_of_a_double_public_key_should_serialize_and_deserialize_for_bls12_381<
253 PoPFlavor: ProofOfPossession<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>> + SerializableToBytes,
254 >()
255 where
256 Keypair<TinyBLS381>:
257 ProofOfPossessionGenerator<TinyBLS381, Sha256, DoublePublicKey<TinyBLS381>, PoPFlavor>,
258 {
259 let mut keypair = Keypair::<TinyBLS381>::generate(thread_rng());
260
261 let proof_pair = <dyn ProofOfPossessionGenerator<
262 TinyBLS381,
263 Sha256,
264 DoublePublicKey<TinyBLS381>,
265 PoPFlavor,
266 >>::generate_pok(&mut keypair);
267
268 let serialized_proof = proof_pair.to_bytes();
269 let deserialized_proof = PoPFlavor::from_bytes(&serialized_proof).unwrap();
270
271 assert!(
272 ProofOfPossession::<TinyBLS381, Sha256, DoublePublicKey::<TinyBLS381>>::verify(
273 &deserialized_proof,
274 &DoublePublicKeyScheme::into_double_public_key(&keypair)
275 ),
276 "valid pok does not verify"
277 );
278 }
279
280 #[test]
281 fn nugget_bls_pop_should_serialize_and_deserialize_for_bls12_381() {
282 pop_of_a_double_public_key_should_serialize_and_deserialize_for_bls12_381::<
283 NuggetBLSPoP<TinyBLS381>,
284 >();
285 }
286
287 #[test]
288 fn nugget_bls_and_cp_pop_should_serialize_and_deserialize_for_bls12_381() {
289 pop_of_a_double_public_key_should_serialize_and_deserialize_for_bls12_381::<
290 NuggetBLSnCPPoP<TinyBLS381>,
291 >();
292 }
293}