use crate::error::KVACError;
use ark_ec::{pairing::Pairing, AffineRepr};
use ark_ff::Zero;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{ops::Neg, rand::RngCore, vec, vec::Vec, UniformRand};
use digest::Digest;
use dock_crypto_utils::{affine_group_element_from_byte_slices, serde_utils::ArkObjectBytes};
use schnorr_pok::{
compute_random_oracle_challenge,
discrete_log::{PokDiscreteLog, PokDiscreteLogProtocol},
inequality::{UnknownDiscreteLogInequalityProof, UnknownDiscreteLogInequalityProtocol},
};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
#[serde_as]
#[derive(
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct KeyedProof<G: AffineRepr> {
#[serde_as(as = "ArkObjectBytes")]
pub B_0: G,
#[serde_as(as = "ArkObjectBytes")]
pub C: G,
}
#[serde_as]
#[derive(
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct PublicVerificationKey<E: Pairing>(
#[serde_as(as = "ArkObjectBytes")] pub E::G2Affine,
#[serde_as(as = "ArkObjectBytes")] pub E::G2Affine,
);
#[serde_as]
#[derive(
Clone, Debug, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct PreparedPublicVerificationKey<E: Pairing>(
#[serde_as(as = "ArkObjectBytes")] pub E::G2Prepared,
#[serde_as(as = "ArkObjectBytes")] pub E::G2Prepared,
);
#[serde_as]
#[derive(
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct ProofOfValidityOfKeyedProof<G: AffineRepr> {
pub sc_pk: PokDiscreteLog<G>,
pub sc_proof: PokDiscreteLog<G>,
}
#[serde_as]
#[derive(
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct ProofOfInvalidityOfKeyedProof<G: AffineRepr>(UnknownDiscreteLogInequalityProof<G>);
impl<E: Pairing> PublicVerificationKey<E> {
pub fn new<D: Digest>(label: &[u8], sk: &E::ScalarField) -> Self {
let P = affine_group_element_from_byte_slices!(label, b" : P");
let Q = P * sk;
Self(P, Q.into())
}
}
impl<E: Pairing> From<PublicVerificationKey<E>> for PreparedPublicVerificationKey<E> {
fn from(pk: PublicVerificationKey<E>) -> Self {
Self(E::G2Prepared::from(pk.0), E::G2Prepared::from(pk.1))
}
}
impl<G: AffineRepr> KeyedProof<G> {
pub fn verify(&self, secret_key: &G::ScalarField) -> Result<(), KVACError> {
if self.C != (self.B_0 * secret_key).into() {
return Err(KVACError::InvalidRandomizedMAC);
}
Ok(())
}
pub fn verify_with_public_verification_key<E: Pairing>(
&self,
pk: impl Into<PreparedPublicVerificationKey<E>>,
) -> Result<(), KVACError>
where
<E as Pairing>::G1Prepared: From<G>,
{
let pk = pk.into();
if !E::multi_pairing(
[
E::G1Prepared::from(self.B_0),
E::G1Prepared::from(self.C.into_group().neg().into()),
],
[pk.1, pk.0],
)
.is_zero()
{
return Err(KVACError::InvalidRandomizedMAC);
}
Ok(())
}
pub fn create_proof_of_validity<'a, R: RngCore, D: Digest>(
&self,
rng: &mut R,
secret_key: G::ScalarField,
pk: impl Into<&'a G>,
g_0: impl Into<&'a G>,
) -> ProofOfValidityOfKeyedProof<G> {
let g_0 = g_0.into();
let sk_blinding = G::ScalarField::rand(rng);
let sc_pk = PokDiscreteLogProtocol::init(secret_key, sk_blinding, g_0);
let sc_proof = PokDiscreteLogProtocol::init(secret_key, sk_blinding, &self.B_0);
let mut challenge_bytes = vec![];
sc_pk
.challenge_contribution(g_0, pk.into(), &mut challenge_bytes)
.unwrap();
sc_proof
.challenge_contribution(&self.B_0, &self.C, &mut challenge_bytes)
.unwrap();
let challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes);
let sc_pk = sc_pk.gen_proof(&challenge);
let sc_proof = sc_proof.gen_proof(&challenge);
ProofOfValidityOfKeyedProof { sc_pk, sc_proof }
}
pub fn create_proof_of_invalidity<'a, R: RngCore, D: Digest>(
&self,
rng: &mut R,
secret_key: G::ScalarField,
pk: impl Into<&'a G>,
g_0: impl Into<&'a G>,
) -> Result<ProofOfInvalidityOfKeyedProof<G>, KVACError> {
let pk = pk.into();
let g_0 = g_0.into();
let protocol = UnknownDiscreteLogInequalityProtocol::new(
rng, secret_key, g_0, &self.B_0, pk, &self.C,
)?;
let mut challenge_bytes = vec![];
protocol.challenge_contribution(g_0, &self.B_0, pk, &self.C, &mut challenge_bytes)?;
let challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes);
let proof = protocol.gen_proof(&challenge);
Ok(ProofOfInvalidityOfKeyedProof(proof))
}
}
impl<G: AffineRepr> ProofOfValidityOfKeyedProof<G> {
pub fn verify<'a, D: Digest>(
&self,
proof: &KeyedProof<G>,
pk: impl Into<&'a G>,
g_0: impl Into<&'a G>,
) -> Result<(), KVACError> {
if self.sc_proof.response != self.sc_pk.response {
return Err(KVACError::InvalidKeyedProof);
}
let pk = pk.into();
let g_0 = g_0.into();
let mut challenge_bytes = vec![];
self.sc_pk
.challenge_contribution(g_0, pk, &mut challenge_bytes)
.unwrap();
self.sc_proof
.challenge_contribution(&proof.B_0, &proof.C, &mut challenge_bytes)
.unwrap();
let challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes);
if !self.sc_pk.verify(pk, g_0, &challenge) {
return Err(KVACError::InvalidKeyedProof);
}
if !self.sc_proof.verify(&proof.C, &proof.B_0, &challenge) {
return Err(KVACError::InvalidKeyedProof);
}
Ok(())
}
}
impl<G: AffineRepr> ProofOfInvalidityOfKeyedProof<G> {
pub fn verify<'a, D: Digest>(
&self,
proof: &KeyedProof<G>,
pk: impl Into<&'a G>,
g_0: impl Into<&'a G>,
) -> Result<(), KVACError> {
let pk = pk.into();
let g_0 = g_0.into();
let mut challenge_bytes = vec![];
self.0
.challenge_contribution(g_0, &proof.B_0, pk, &proof.C, &mut challenge_bytes)
.unwrap();
let challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes);
self.0.verify(g_0, &proof.B_0, pk, &proof.C, &challenge)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bddt_2016::setup::{MACParams, PublicKey, SecretKey};
use ark_bls12_381::{Bls12_381, G1Affine};
use ark_ec::CurveGroup;
use ark_ff::Field;
use ark_std::{
rand::{prelude::StdRng, SeedableRng},
UniformRand,
};
use blake2::Blake2b512;
#[test]
fn keyed_proof_verification() {
let mut rng = StdRng::seed_from_u64(0u64);
let params = MACParams::<G1Affine>::new::<Blake2b512>(b"test", 5);
let sk = SecretKey::new(&mut rng);
let pk = PublicKey::new(&sk, ¶ms.g_0);
let pvk = PublicVerificationKey::<Bls12_381>::new::<Blake2b512>(b"test", sk.as_ref());
let B_0 = G1Affine::rand(&mut rng);
let C = (B_0 * sk.0).into_affine();
let kp = KeyedProof { B_0, C };
kp.verify(sk.as_ref()).unwrap();
kp.verify_with_public_verification_key(pvk).unwrap();
let invalid_C = (B_0 * sk.0.square()).into_affine();
let invalid_kp = KeyedProof { B_0, C: invalid_C };
let validity_proof =
kp.create_proof_of_validity::<_, Blake2b512>(&mut rng, sk.0, pk.as_ref(), ¶ms.g_0);
validity_proof
.verify::<Blake2b512>(&kp, pk.as_ref(), ¶ms.g_0)
.unwrap();
assert!(validity_proof
.verify::<Blake2b512>(&invalid_kp, pk.as_ref(), ¶ms.g_0)
.is_err());
let invalidity_proof = invalid_kp
.create_proof_of_invalidity::<_, Blake2b512>(&mut rng, sk.0, pk.as_ref(), ¶ms.g_0)
.unwrap();
invalidity_proof
.verify::<Blake2b512>(&invalid_kp, pk.as_ref(), ¶ms.g_0)
.unwrap();
assert!(invalidity_proof
.verify::<Blake2b512>(&kp, pk.as_ref(), ¶ms.g_0)
.is_err());
}
}