use alloc::vec::Vec;
use core::{iter::once, marker::PhantomData};
use ark_ec::{AffineRepr, CurveGroup, PrimeGroup};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use digest::FixedOutputReset;
use sha2::Sha256;
use crate::broken_derives;
use crate::chaum_pedersen_signature::{ChaumPedersenSigner, ChaumPedersenVerifier};
use crate::dual_scalar_mul::DualScalarMultiplication;
use crate::chaum_pedersen_signature::DLEQProof;
use crate::serialize::SerializableToBytes;
use crate::single::{Keypair, KeypairVT, PublicKey, SecretKeyVT, Signature};
use crate::{EngineBLS, Message, Signed};
#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
pub struct PublicKeyInSignatureGroup<E: EngineBLS>(pub E::SignatureGroup);
broken_derives!(PublicKeyInSignatureGroup);
#[derive(Debug, Clone, Copy, PartialEq, Eq, CanonicalDeserialize)]
pub struct PublicKeyInSisterGroup<S: CurveGroup>(pub S);
pub trait NuggetPublicKey<
E: EngineBLS,
S: CurveGroup + PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
>
{
fn into_public_key_in_signature_group(&self) -> PublicKeyInSignatureGroup<E>;
fn into_bls_public_key(&self) -> PublicKey<E>;
fn into_public_key_in_sister_group(&self) -> PublicKeyInSisterGroup<S>;
fn straus_sister_group_precomputed_points(&self) -> &[S];
fn verify(&self, message: &Message, signature: &NuggetSignature<E>) -> bool;
}
pub trait NuggetBLS<E: EngineBLS, S: CurveGroup>
where
S: PrimeGroup<ScalarField = E::Scalar>,
{
fn into_public_key_in_signature_group(&self) -> PublicKeyInSignatureGroup<E>;
fn into_public_key_in_sister_group(&self) -> PublicKeyInSisterGroup<S>;
fn sign(&mut self, message: &Message) -> NuggetSignature<E>;
}
impl<E: EngineBLS, S: CurveGroup> NuggetBLS<E, S> for SecretKeyVT<E>
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
{
fn into_public_key_in_signature_group(&self) -> PublicKeyInSignatureGroup<E> {
PublicKeyInSignatureGroup(
<E::SignatureGroup as CurveGroup>::Affine::generator().into_group() * self.0,
)
}
fn into_public_key_in_sister_group(&self) -> PublicKeyInSisterGroup<S> {
PublicKeyInSisterGroup(S::Affine::generator().into_group() * self.0)
}
fn sign(&mut self, message: &Message) -> NuggetSignature<E> {
ChaumPedersenSigner::<E, S, Sha256>::generate_cp_signature(self, &message)
}
}
impl<E: EngineBLS, S: CurveGroup> NuggetBLS<E, S> for KeypairVT<E>
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
{
fn into_public_key_in_signature_group(&self) -> PublicKeyInSignatureGroup<E> {
NuggetBLS::<E, S>::into_public_key_in_signature_group(&self.secret)
}
fn into_public_key_in_sister_group(&self) -> PublicKeyInSisterGroup<S> {
self.secret.into_public_key_in_sister_group()
}
fn sign(&mut self, message: &Message) -> NuggetSignature<E> {
NuggetBLS::<E, S>::sign(&mut self.secret, message)
}
}
impl<E: EngineBLS, S: CurveGroup> NuggetBLS<E, S> for Keypair<E>
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
{
fn into_public_key_in_signature_group(&self) -> PublicKeyInSignatureGroup<E> {
NuggetBLS::<E, S>::into_public_key_in_signature_group(&self.into_vartime())
}
fn into_public_key_in_sister_group(&self) -> PublicKeyInSisterGroup<S> {
self.into_vartime().into_public_key_in_sister_group()
}
fn sign(&mut self, message: &Message) -> NuggetSignature<E> {
NuggetBLS::<E, S>::sign(&mut self.into_vartime(), message)
}
}
#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)]
pub struct NuggetSignature<E: EngineBLS>(pub E::SignatureGroup, pub DLEQProof<E>);
impl<E: EngineBLS> NuggetSignature<E> {
pub fn verify<
S: CurveGroup + DualScalarMultiplication,
H: FixedOutputReset + Default + Clone,
P: ChaumPedersenVerifier<E, S, H>,
>(
&self,
message: &Message,
publickey: &P,
) -> bool
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
E::SignatureGroup: DualScalarMultiplication,
{
publickey.verify_cp_signature(message, self)
}
}
#[derive(Debug, Clone)]
pub struct NuggetSignedMessage<E: EngineBLS, S: CurveGroup, P: NuggetPublicKey<E, S>>
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
P: Sized,
{
pub message: Message,
pub publickey: P,
pub signature: NuggetSignature<E>,
pub _phantom: PhantomData<S>,
}
impl<E: EngineBLS, S: CurveGroup, P: NuggetPublicKey<E, S>> NuggetSignedMessage<E, S, P>
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
P: Sized,
{
pub fn new(message: Message, publickey: P, signature: NuggetSignature<E>) -> Self {
NuggetSignedMessage {
message,
publickey,
signature,
_phantom: PhantomData,
}
}
}
impl<E: EngineBLS, S: CurveGroup, P: NuggetPublicKey<E, S>> PartialEq<Self>
for NuggetSignedMessage<E, S, P>
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
{
fn eq(&self, other: &Self) -> bool {
self.message.eq(&other.message)
&& self
.publickey
.into_bls_public_key()
.eq(&other.publickey.into_bls_public_key())
&& self
.publickey
.into_public_key_in_signature_group()
.eq(&other.publickey.into_public_key_in_signature_group())
&& self
.publickey
.into_public_key_in_sister_group()
.eq(&other.publickey.into_public_key_in_sister_group())
&& self.signature.0.eq(&other.signature.0)
}
}
impl<
'a,
E: EngineBLS,
S: CurveGroup + DualScalarMultiplication,
P: ChaumPedersenVerifier<E, S, Sha256>,
> Signed for &'a NuggetSignedMessage<E, S, P>
where
S: PrimeGroup<ScalarField = E::Scalar> + SerializableToBytes,
E::SignatureGroup: DualScalarMultiplication,
{
type E = E;
type M = Message;
type PKG = PublicKey<E>;
type PKnM = ::core::iter::Once<(Message, PublicKey<E>)>;
fn messages_and_publickeys(self) -> Self::PKnM {
once((self.message.clone(), self.publickey.into_bls_public_key())) }
fn signature(&self) -> Signature<E> {
Signature(self.signature.0)
}
fn verify(self) -> bool {
ChaumPedersenVerifier::<E, S, Sha256>::verify_cp_signature(
&self.publickey,
&self.message,
&self.signature,
)
}
}
impl<E: EngineBLS> SerializableToBytes for NuggetSignature<E> {
const SERIALIZED_BYTES_SIZE: usize = E::SIGNATURE_SERIALIZED_SIZE + 2 * E::SECRET_KEY_SIZE;
}