use crate::{
bbs_sharp::setup::{
DesignatedVerifierPoKOfPublicKey, MACParams, SecretKey, SignerPublicKey, UserPublicKey,
},
error::KVACError,
};
use ark_ec::{AffineRepr, CurveGroup};
use ark_ff::{Field, Zero};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{ops::Neg, rand::RngCore, vec, vec::Vec, UniformRand};
use digest::Digest;
use dock_crypto_utils::{
expect_equality, serde_utils::ArkObjectBytes, signature::MultiMessageSignatureParams,
};
use schnorr_pok::{
compute_random_oracle_challenge,
discrete_log::{PokDiscreteLog, PokDiscreteLogProtocol},
};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use zeroize::{Zeroize, ZeroizeOnDrop};
#[serde_as]
#[derive(
Clone,
PartialEq,
Eq,
Debug,
CanonicalSerialize,
CanonicalDeserialize,
Serialize,
Deserialize,
Zeroize,
ZeroizeOnDrop,
)]
pub struct MAC<G: AffineRepr> {
#[serde_as(as = "ArkObjectBytes")]
pub A: G,
#[serde_as(as = "ArkObjectBytes")]
pub e: G::ScalarField,
}
#[serde_as]
#[derive(
Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
)]
pub struct ProofOfValidityOfMAC<G: AffineRepr> {
pub sc_B: PokDiscreteLog<G>,
pub sc_pk: PokDiscreteLog<G>,
pub designated_verifier_pk_proof: Option<DesignatedVerifierPoKOfPublicKey<G>>,
}
impl<G: AffineRepr> MAC<G> {
pub fn new<R: RngCore>(
rng: &mut R,
messages: &[G::ScalarField],
user_public_key: &UserPublicKey<G>,
signer_secret_key: &SecretKey<G::ScalarField>,
params: impl AsRef<MACParams<G>>,
) -> Result<Self, KVACError> {
if messages.is_empty() {
return Err(KVACError::NoMessageGiven);
}
let params = params.as_ref();
expect_equality!(
messages.len(),
params.supported_message_count(),
KVACError::MessageCountIncompatibleWithMACParams
);
let mut e = G::ScalarField::rand(rng);
while (e + signer_secret_key.0).is_zero() {
e = G::ScalarField::rand(rng)
}
let e_plus_x_inv = (e + signer_secret_key.0).inverse().unwrap();
let A = params.b(messages.iter().enumerate(), user_public_key)? * e_plus_x_inv;
Ok(Self {
A: A.into_affine(),
e,
})
}
pub fn verify(
&self,
messages: &[G::ScalarField],
user_public_key: &UserPublicKey<G>,
sk: impl AsRef<G::ScalarField>,
params: impl AsRef<MACParams<G>>,
) -> Result<(), KVACError> {
if messages.is_empty() {
return Err(KVACError::NoMessageGiven);
}
let params = params.as_ref();
expect_equality!(
messages.len(),
params.supported_message_count(),
KVACError::MessageCountIncompatibleWithMACParams
);
let b = params.b(messages.iter().enumerate(), user_public_key)?;
let e_plus_x_inv = (self.e + sk.as_ref())
.inverse()
.ok_or(KVACError::CannotInvert0)?;
if (b * e_plus_x_inv).into_affine() != self.A {
return Err(KVACError::InvalidMAC);
}
Ok(())
}
}
impl<G: AffineRepr> ProofOfValidityOfMAC<G> {
pub fn new<R: RngCore, D: Digest>(
rng: &mut R,
mac: &MAC<G>,
secret_key: &SecretKey<G::ScalarField>,
public_key: &SignerPublicKey<G>,
params: impl AsRef<MACParams<G>>,
user_public_key: Option<&UserPublicKey<G>>,
) -> Self {
let witness = secret_key.0;
let blinding = G::ScalarField::rand(rng);
let B = (mac.A * witness).into_affine();
let params = params.as_ref();
let mut challenge_bytes = vec![];
let p1 = PokDiscreteLogProtocol::init(witness, blinding, &mac.A);
let p2 = PokDiscreteLogProtocol::init(witness, blinding, ¶ms.g_tilde);
p1.challenge_contribution(&mac.A, &B, &mut challenge_bytes)
.unwrap();
p2.challenge_contribution(¶ms.g_tilde, &public_key.0, &mut challenge_bytes)
.unwrap();
let mut challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes);
let designated_verifier_pk_proof =
user_public_key.map(|pk| DesignatedVerifierPoKOfPublicKey::new(rng, &pk.0, ¶ms.g));
if let Some(dvp) = &designated_verifier_pk_proof {
challenge = challenge - dvp.challenge;
}
Self {
sc_B: p1.gen_proof(&challenge),
sc_pk: p2.gen_proof(&challenge),
designated_verifier_pk_proof,
}
}
pub fn verify<D: Digest>(
&self,
mac: &MAC<G>,
messages: &[G::ScalarField],
user_public_key: &UserPublicKey<G>,
signer_public_key: &SignerPublicKey<G>,
params: impl AsRef<MACParams<G>>,
) -> Result<(), KVACError> {
if self.sc_B.response != self.sc_pk.response {
return Err(KVACError::InvalidMACProof);
}
let params = params.as_ref();
let B = (params.b(messages.iter().enumerate(), user_public_key)? + mac.A * mac.e.neg())
.into_affine();
let mut challenge_bytes = vec![];
self.sc_B
.challenge_contribution(&mac.A, &B, &mut challenge_bytes)
.unwrap();
self.sc_pk
.challenge_contribution(¶ms.g_tilde, &signer_public_key.0, &mut challenge_bytes)
.unwrap();
let mut challenge = compute_random_oracle_challenge::<G::ScalarField, D>(&challenge_bytes);
if let Some(dvp) = &self.designated_verifier_pk_proof {
dvp.verify(&user_public_key.0, ¶ms.g)?;
challenge = challenge - dvp.challenge
}
if !self.sc_B.verify(&B, &mac.A, &challenge) {
return Err(KVACError::InvalidMACProof);
}
if !self
.sc_pk
.verify(&signer_public_key.0, ¶ms.g_tilde, &challenge)
{
return Err(KVACError::InvalidMACProof);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use ark_secp256r1::{Affine, Fr};
use ark_std::rand::{prelude::StdRng, SeedableRng};
use sha2::Sha256;
#[test]
fn mac_verification() {
let mut rng = StdRng::seed_from_u64(0u64);
let message_count = 10;
let messages = (0..message_count)
.map(|_| Fr::rand(&mut rng))
.collect::<Vec<_>>();
let params = MACParams::<Affine>::new::<Sha256>(b"test", message_count);
let signer_sk = SecretKey::new(&mut rng);
let signer_pk = SignerPublicKey::new_from_params(&signer_sk, ¶ms);
let user_sk = SecretKey::new(&mut rng);
let user_pk = UserPublicKey::new_from_params(&user_sk, ¶ms);
let mac = MAC::new(&mut rng, &messages, &user_pk, &signer_sk, ¶ms).unwrap();
let proof = ProofOfValidityOfMAC::new::<_, Sha256>(
&mut rng, &mac, &signer_sk, &signer_pk, ¶ms, None,
);
assert!(proof.designated_verifier_pk_proof.is_none());
mac.verify(&messages, &user_pk, &signer_sk, ¶ms)
.unwrap();
proof
.verify::<Sha256>(&mac, &messages, &user_pk, &signer_pk, params)
.unwrap();
}
#[test]
fn mac_verification_with_designated_verifier_proof_of_validity() {
let mut rng = StdRng::seed_from_u64(0u64);
let message_count = 10;
let messages = (0..message_count)
.map(|_| Fr::rand(&mut rng))
.collect::<Vec<_>>();
let params = MACParams::<Affine>::new::<Sha256>(b"test", message_count);
let signer_sk = SecretKey::new(&mut rng);
let signer_pk = SignerPublicKey::new_from_params(&signer_sk, ¶ms);
let user_sk = SecretKey::new(&mut rng);
let user_pk = UserPublicKey::new_from_params(&user_sk, ¶ms);
let mac = MAC::new(&mut rng, &messages, &user_pk, &signer_sk, ¶ms).unwrap();
let proof = ProofOfValidityOfMAC::new::<_, Sha256>(
&mut rng,
&mac,
&signer_sk,
&signer_pk,
¶ms,
Some(&user_pk),
);
assert!(proof.designated_verifier_pk_proof.is_some());
mac.verify(&messages, &user_pk, &signer_sk, ¶ms)
.unwrap();
proof
.verify::<Sha256>(&mac, &messages, &user_pk, &signer_pk, params)
.unwrap();
}
}