1use ark_ff::field_hashers::{DefaultFieldHasher, HashToField};
4use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
5
6use crate::engine::EngineBLS;
7use crate::{ProofOfPossession, ProofOfPossessionGenerator};
8
9use crate::serialize::SerializableToBytes;
10use crate::single::{Keypair, PublicKey};
11
12use alloc::vec::Vec;
13use ark_ec::PrimeGroup;
14use digest::DynDigest;
15use digest::FixedOutputReset;
16
17pub type SchnorrProof<E> = (<E as EngineBLS>::Scalar, <E as EngineBLS>::Scalar);
18
19#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
20pub struct SchnorrPoP<E: EngineBLS>(SchnorrProof<E>);
21
22impl<E: EngineBLS> Clone for SchnorrPoP<E> {
23 fn clone(&self) -> Self {
24 SchnorrPoP(self.0)
25 }
26}
27
28trait BLSSchnorrPoPGenerator<E: EngineBLS, H: DynDigest + FixedOutputReset + Default + Clone>:
30 ProofOfPossessionGenerator<E, H, PublicKey<E>, SchnorrPoP<E>>
31{
32 fn witness_scalar(&self) -> <<E as EngineBLS>::PublicKeyGroup as PrimeGroup>::ScalarField;
36}
37
38impl<E: EngineBLS, H: DynDigest + FixedOutputReset + Default + Clone> BLSSchnorrPoPGenerator<E, H>
39 for Keypair<E>
40{
41 fn witness_scalar(&self) -> <<E as EngineBLS>::PublicKeyGroup as PrimeGroup>::ScalarField {
44 let secret_key_as_bytes = self.secret.to_bytes();
45 let public_key_as_bytes = <E as EngineBLS>::public_key_point_to_byte(&self.public.0);
46
47 let mut secret_key_hasher = H::default();
48 DynDigest::update(&mut secret_key_hasher, secret_key_as_bytes.as_slice());
49 let hashed_secret_key = secret_key_hasher.finalize_reset().to_vec();
50
51 let hasher = <DefaultFieldHasher<H> as HashToField<
52 <<E as EngineBLS>::PublicKeyGroup as PrimeGroup>::ScalarField,
53 >>::new(&[]);
54
55 let scalar_seed = [hashed_secret_key, public_key_as_bytes].concat();
56 hasher.hash_to_field::<1>(scalar_seed.as_slice())[0]
57 }
58}
59
60impl<E: EngineBLS, H: DynDigest + FixedOutputReset + Default + Clone>
61 ProofOfPossessionGenerator<E, H, PublicKey<E>, SchnorrPoP<E>> for Keypair<E>
62{
63 fn generate_pok(&mut self) -> SchnorrPoP<E> {
65 let mut r = <dyn BLSSchnorrPoPGenerator<E, H>>::witness_scalar(self);
81
82 let mut r_point = <<E as EngineBLS>::PublicKeyGroup as PrimeGroup>::generator();
83 r_point *= r; let r_point_as_bytes = <E as EngineBLS>::public_key_point_to_byte(&r_point);
86 let public_key_as_bytes = <E as EngineBLS>::public_key_point_to_byte(&self.public.0); let proof_basis = [r_point_as_bytes, public_key_as_bytes].concat();
89 let hasher = <DefaultFieldHasher<H> as HashToField<
90 <<E as EngineBLS>::PublicKeyGroup as PrimeGroup>::ScalarField,
91 >>::new(&[]);
92 let k = hasher.hash_to_field::<1>(proof_basis.as_slice())[0];
93
94 let s = (k * self.secret.into_vartime().0) + r;
95
96 ::zeroize::Zeroize::zeroize(&mut r); SchnorrPoP::<E>((s, k))
99 }
100}
101
102impl<E: EngineBLS, H: DynDigest + FixedOutputReset + Default + Clone>
103 ProofOfPossession<E, H, PublicKey<E>> for SchnorrPoP<E>
104{
105 fn verify(&self, public_key_of_prover: &PublicKey<E>) -> bool {
109 let mut schnorr_point = <<E as EngineBLS>::PublicKeyGroup as PrimeGroup>::generator();
110 schnorr_point *= self.0 .0;
111 let mut k_public_key = public_key_of_prover.0;
112 k_public_key *= -self.0 .1;
113 schnorr_point += k_public_key;
114
115 let schnorr_point_as_bytes = <E as EngineBLS>::public_key_point_to_byte(&schnorr_point);
116 let public_key_as_bytes =
117 <E as EngineBLS>::public_key_point_to_byte(&public_key_of_prover.0); let resulting_proof_basis = [schnorr_point_as_bytes, public_key_as_bytes].concat();
120
121 let hasher = <DefaultFieldHasher<H> as HashToField<
122 <<E as EngineBLS>::PublicKeyGroup as PrimeGroup>::ScalarField,
123 >>::new(&[]);
124 let random_scalar: E::Scalar =
125 hasher.hash_to_field::<1>(resulting_proof_basis.as_slice())[0];
126 random_scalar == self.0 .1
127 }
128}
129
130#[cfg(all(test, feature = "std"))]
131mod tests {
132 use super::SchnorrPoP;
133 use crate::engine::ZBLS;
134 use crate::single::{Keypair, PublicKey};
135 use crate::ProofOfPossessionGenerator;
136 use rand::thread_rng;
137 use sha2::Sha512;
138
139 #[test]
140 fn schnorr_bls_pop_sign() {
141 let mut keypair = Keypair::<ZBLS>::generate(thread_rng());
142 <Keypair<ZBLS> as ProofOfPossessionGenerator<
143 ZBLS,
144 Sha512,
145 PublicKey<ZBLS>,
146 SchnorrPoP<ZBLS>,
147 >>::generate_pok(&mut keypair);
148 }
149
150 #[test]
151 fn schnorr_bls_pop_sign_and_verify() {
152 use crate::{ProofOfPossession, ProofOfPossessionGenerator};
153
154 let mut keypair = Keypair::<ZBLS>::generate(thread_rng());
155 let proof_pair = <dyn ProofOfPossessionGenerator<
156 ZBLS,
157 Sha512,
158 PublicKey<ZBLS>,
159 SchnorrPoP<ZBLS>,
160 >>::generate_pok(&mut keypair);
161 assert!(
162 ProofOfPossession::<ZBLS, Sha512, PublicKey::<ZBLS>>::verify(
163 &proof_pair,
164 &keypair.public
165 ),
166 "valid pok does not verify"
167 );
168 }
169
170 #[test]
171 fn schnorr_bls_pop_of_random_public_key_should_fail() {
172 use crate::{ProofOfPossession, ProofOfPossessionGenerator};
173
174 let mut keypair_good = Keypair::<ZBLS>::generate(thread_rng());
175 let proof_pair = <dyn ProofOfPossessionGenerator<
176 ZBLS,
177 Sha512,
178 PublicKey<ZBLS>,
179 SchnorrPoP<ZBLS>,
180 >>::generate_pok(&mut keypair_good);
181 let keypair_bad = Keypair::<ZBLS>::generate(thread_rng());
182 assert!(
183 !ProofOfPossession::<ZBLS, Sha512, PublicKey::<ZBLS>>::verify(
184 &proof_pair,
185 &keypair_bad.public
186 ),
187 "invalid pok of unrelated public key should not verify"
188 );
189 }
190}