tnt_bls/
schnorr_pop.rs

1//! ## Implementation of ProofofPossion trait for BLS keys using schnorr sginature
2//! ## TODO: I assume this can also moved to pop.rs but for now I put it separately to help reviews
3use 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
28/// Generate Schnorr Signature for an arbitrary message using a key ment to use in BLS scheme
29trait BLSSchnorrPoPGenerator<E: EngineBLS, H: DynDigest + FixedOutputReset + Default + Clone>:
30    ProofOfPossessionGenerator<E, H, PublicKey<E>, SchnorrPoP<E>>
31{
32    /// Produce a secret witness scalar `k`, aka nonce, from hash of
33    /// H( H(s) | H(public_key)) because our key does not have the
34    /// randomness redundacy exists in EdDSA secret key.
35    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    //The pseudo random witness is generated similar to eddsa witness
42    //hash(secret_key|publick_key)
43    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    //TODO: Message must be equal to public key.
64    fn generate_pok(&mut self) -> SchnorrPoP<E> {
65        //First we should figure out the base point in E, I think the secret key trait/struct knows about it.
66
67        //choose random scaler k
68        //For now we don't we just use a trick similar to Ed25519
69        //we use hash of concatination of hash the secret key and the public key
70
71        //schnorr equations
72
73        //R = rG.
74        //k = H(R|M)
75        //s = k*private_key + r
76        // publishing (s, R) verifying that (s*G = H(R|M)*Publickey + R => H(R|M)*Publickey + R - s*G = 0)
77        // so either we need to two into_affine and one curve addition or or two curve additions.
78        // instead we actually doing H(s*G - H(R|M)*Publickey|M) == H(R|M) == k
79        // avoiding one curve addition (or two field divisions) in expense of a hash.
80        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; //todo perhaps we need to mandate E to have  a hard coded point
84
85        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); //it *must* be the public key (fixed) otherwise secret key can be recovered from the two different proves
87
88        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); //clear secret witness from memory
97
98        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    /// verify the validity of schnoor proof for a given publick key by
106    /// making sure this is equal to zero
107    /// H(+s*G - k*Publkey|M) ==  k  
108    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); //it *must* be the public key (fixed) otherwise secret key can be recovered from the two different proves
118
119        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}