use ark_ff::field_hashers::{DefaultFieldHasher, HashToField};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use crate::engine::EngineBLS;
use crate::{ProofOfPossession, ProofOfPossessionGenerator};
use crate::serialize::SerializableToBytes;
use crate::single::{Keypair, PublicKey};
use alloc::vec::Vec;
use digest::DynDigest;
use ark_ec::Group;
pub type SchnorrProof<E> = (<E as EngineBLS>::Scalar, <E as EngineBLS>::Scalar);
#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
pub struct SchnorrPoP<E: EngineBLS>(SchnorrProof<E>);
impl<E: EngineBLS> Clone for SchnorrPoP<E> {
fn clone(&self) -> Self {
SchnorrPoP(self.0)
}
}
trait BLSSchnorrPoPGenerator<E: EngineBLS, H: DynDigest + Default + Clone>:
ProofOfPossessionGenerator<E, H, PublicKey<E>, SchnorrPoP<E>>
{
fn witness_scalar(&self) -> <<E as EngineBLS>::PublicKeyGroup as Group>::ScalarField;
}
impl<E: EngineBLS, H: DynDigest + Default + Clone> BLSSchnorrPoPGenerator<E, H> for Keypair<E> {
fn witness_scalar(&self) -> <<E as EngineBLS>::PublicKeyGroup as Group>::ScalarField {
let secret_key_as_bytes = self.secret.to_bytes();
let public_key_as_bytes = <E as EngineBLS>::public_key_point_to_byte(&self.public.0);
let mut secret_key_hasher = H::default();
secret_key_hasher.update(secret_key_as_bytes.as_slice());
let hashed_secret_key = secret_key_hasher.finalize_reset().to_vec();
let hasher = <DefaultFieldHasher<H> as HashToField<
<<E as EngineBLS>::PublicKeyGroup as Group>::ScalarField,
>>::new(&[]);
let scalar_seed = [hashed_secret_key, public_key_as_bytes].concat();
hasher.hash_to_field(scalar_seed.as_slice(), 1)[0]
}
}
impl<E: EngineBLS, H: DynDigest + Default + Clone>
ProofOfPossessionGenerator<E, H, PublicKey<E>, SchnorrPoP<E>> for Keypair<E>
{
fn generate_pok(&mut self) -> SchnorrPoP<E> {
let mut r = <dyn BLSSchnorrPoPGenerator<E, H>>::witness_scalar(self);
let mut r_point = <<E as EngineBLS>::PublicKeyGroup as Group>::generator();
r_point *= r; let r_point_as_bytes = <E as EngineBLS>::public_key_point_to_byte(&r_point);
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();
let hasher = <DefaultFieldHasher<H> as HashToField<
<<E as EngineBLS>::PublicKeyGroup as Group>::ScalarField,
>>::new(&[]);
let k = hasher.hash_to_field(proof_basis.as_slice(), 1)[0];
let s = (k * self.secret.into_vartime().0) + r;
::zeroize::Zeroize::zeroize(&mut r); SchnorrPoP::<E>((s, k))
}
}
impl<E: EngineBLS, H: DynDigest + Default + Clone> ProofOfPossession<E, H, PublicKey<E>>
for SchnorrPoP<E>
{
fn verify(&self, public_key_of_prover: &PublicKey<E>) -> bool {
let mut schnorr_point = <<E as EngineBLS>::PublicKeyGroup as Group>::generator();
schnorr_point *= self.0 .0;
let mut k_public_key = public_key_of_prover.0;
k_public_key *= -self.0 .1;
schnorr_point += k_public_key;
let schnorr_point_as_bytes = <E as EngineBLS>::public_key_point_to_byte(&schnorr_point);
let public_key_as_bytes =
<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();
let hasher = <DefaultFieldHasher<H> as HashToField<
<<E as EngineBLS>::PublicKeyGroup as Group>::ScalarField,
>>::new(&[]);
let random_scalar: E::Scalar = hasher.hash_to_field(resulting_proof_basis.as_slice(), 1)[0];
random_scalar == self.0 .1
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::SchnorrPoP;
use crate::engine::ZBLS;
use crate::single::{Keypair, PublicKey};
use crate::ProofOfPossessionGenerator;
use rand::thread_rng;
use sha2::Sha512;
#[test]
fn schnorr_bls_pop_sign() {
let mut keypair = Keypair::<ZBLS>::generate(thread_rng());
<Keypair<ZBLS> as ProofOfPossessionGenerator<
ZBLS,
Sha512,
PublicKey<ZBLS>,
SchnorrPoP<ZBLS>,
>>::generate_pok(&mut keypair);
}
#[test]
fn schnorr_bls_pop_sign_and_verify() {
use crate::{ProofOfPossession, ProofOfPossessionGenerator};
let mut keypair = Keypair::<ZBLS>::generate(thread_rng());
let proof_pair = <dyn ProofOfPossessionGenerator<
ZBLS,
Sha512,
PublicKey<ZBLS>,
SchnorrPoP<ZBLS>,
>>::generate_pok(&mut keypair);
assert!(
ProofOfPossession::<ZBLS, Sha512, PublicKey::<ZBLS>>::verify(
&proof_pair,
&keypair.public
),
"valid pok does not verify"
);
}
#[test]
fn schnorr_bls_pop_of_random_public_key_should_fail() {
use crate::{ProofOfPossession, ProofOfPossessionGenerator};
let mut keypair_good = Keypair::<ZBLS>::generate(thread_rng());
let proof_pair = <dyn ProofOfPossessionGenerator<
ZBLS,
Sha512,
PublicKey<ZBLS>,
SchnorrPoP<ZBLS>,
>>::generate_pok(&mut keypair_good);
let keypair_bad = Keypair::<ZBLS>::generate(thread_rng());
assert!(
!ProofOfPossession::<ZBLS, Sha512, PublicKey::<ZBLS>>::verify(
&proof_pair,
&keypair_bad.public
),
"invalid pok of unrelated public key should not verify"
);
}
}