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};
#[derive(CanonicalSerialize, CanonicalDeserialize)]
pub struct NuggetBLSPoP<E: EngineBLS>(pub E::SignatureGroup);
impl<E: EngineBLS, H: DynDigest + Default + Clone>
ProofOfPossessionGenerator<E, H, DoublePublicKey<E>, NuggetBLSPoP<E>> for Keypair<E>
{
fn generate_pok(&mut self) -> NuggetBLSPoP<E> {
let sigma_pop = ProofOfPossessionGenerator::<E, H, DoublePublicKey<E>, NuggetBLSnCPPoP<E>>::generate_pok(self);
NuggetBLSPoP::<E>(sigma_pop.0 .0)
}
}
impl<E: EngineBLS> SerializableToBytes for NuggetBLSPoP<E> {
const SERIALIZED_BYTES_SIZE: usize = E::SIGNATURE_SERIALIZED_SIZE;
}
impl<E: EngineBLS, H: DynDigest + Default + Clone> ProofOfPossession<E, H, DoublePublicKey<E>>
for NuggetBLSPoP<E>
{
fn verify(&self, public_key_of_prover: &DoublePublicKey<E>) -> bool {
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())
}
}
#[derive(CanonicalSerialize, CanonicalDeserialize)]
pub struct NuggetBLSnCPPoP<E: EngineBLS>(pub DoubleSignature<E>);
impl<E: EngineBLS, H: DynDigest + Default + Clone>
ProofOfPossessionGenerator<E, H, DoublePublicKey<E>, NuggetBLSnCPPoP<E>> for Keypair<E>
{
fn generate_pok(&mut self) -> NuggetBLSnCPPoP<E> {
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)
}
}
impl<E: EngineBLS> SerializableToBytes for NuggetBLSnCPPoP<E> {
const SERIALIZED_BYTES_SIZE: usize =
<DoubleSignature<E> as SerializableToBytes>::SERIALIZED_BYTES_SIZE;
}
impl<E: EngineBLS, H: DynDigest + Default + Clone> ProofOfPossession<E, H, DoublePublicKey<E>>
for NuggetBLSnCPPoP<E>
{
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();
<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>,
>();
}
}