use super::common::*;
use crate::{
common::*,
curve_arithmetic::{multiexp, Curve, Field},
pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value},
random_oracle::RandomOracle,
};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, SerdeBase16Serialize)]
pub struct Response<T: Curve> {
pub response: (T::Scalar, T::Scalar),
}
#[derive(Debug, Serialize)]
pub struct CommittedMessages<C: Curve, D: Curve> {
pub u: C,
pub v: Commitment<D>,
}
pub struct ComEq<C: Curve, D: Curve<Scalar = C::Scalar>> {
pub commitment: Commitment<D>,
pub y: C,
pub cmm_key: CommitmentKey<D>,
pub g: C,
}
pub struct ComEqSecret<C: Curve> {
pub r: Randomness<C>,
pub a: Value<C>,
}
#[allow(non_snake_case)]
impl<C: Curve, D: Curve<Scalar = C::Scalar>> SigmaProtocol for ComEq<C, D> {
type CommitMessage = CommittedMessages<C, D>;
type ProtocolChallenge = C::Scalar;
type ProverState = (Value<D>, Randomness<D>);
type Response = Response<C>;
type SecretData = ComEqSecret<D>;
fn public(&self, ro: &mut RandomOracle) {
ro.append_message("commitment", &self.commitment);
ro.append_message("y", &self.y);
ro.append_message("cmm_key", &self.cmm_key);
ro.append_message("g", &self.g)
}
fn compute_commit_message<R: rand::Rng>(
&self,
csprng: &mut R,
) -> Option<(Self::CommitMessage, Self::ProverState)> {
let mut u = C::zero_point();
let alpha = Value::<D>::generate_non_zero(csprng);
let (v, cR) = self.cmm_key.commit(&alpha, csprng);
u = u.plus_point(&self.g.mul_by_scalar(&alpha));
Some((CommittedMessages { u, v }, (alpha, cR)))
}
fn get_challenge(
&self,
challenge: &crate::random_oracle::Challenge,
) -> Self::ProtocolChallenge {
C::scalar_from_bytes(challenge)
}
fn compute_response(
&self,
secret: Self::SecretData,
state: Self::ProverState,
challenge: &Self::ProtocolChallenge,
) -> Option<Self::Response> {
let (ref alpha, ref cR) = state;
let mut s = *challenge;
s.mul_assign(&secret.a);
s.negate();
s.add_assign(alpha);
let mut t: C::Scalar = *challenge;
t.mul_assign(&secret.r);
t.negate();
t.add_assign(cR);
Some(Response { response: (s, t) })
}
fn extract_commit_message(
&self,
challenge: &Self::ProtocolChallenge,
response: &Self::Response,
) -> Option<Self::CommitMessage> {
let u = multiexp(&[self.y, self.g], &[*challenge, response.response.0]);
let v = self.commitment.mul_by_scalar(challenge).plus_point(
&self
.cmm_key
.hide_worker(&response.response.0, &response.response.1),
);
Some(CommittedMessages {
u,
v: Commitment(v),
})
}
#[cfg(test)]
#[allow(clippy::many_single_char_names)]
fn with_valid_data<R: rand::Rng>(
_data_size: usize,
csprng: &mut R,
f: impl FnOnce(Self, Self::SecretData, &mut R),
) {
let comm_key = CommitmentKey::generate(csprng);
let a = Value::<D>::generate_non_zero(csprng);
let (c, randomness) = comm_key.commit(&a, csprng);
let g = C::generate(csprng);
let mut y = C::zero_point();
y = y.plus_point(&g.mul_by_scalar(&a));
let com_eq = ComEq {
commitment: c,
y,
cmm_key: comm_key,
g,
};
let secret = ComEqSecret { r: randomness, a };
f(com_eq, secret, csprng)
}
}
#[cfg(test)]
mod test {
use crate::curve_arithmetic::arkworks_instances::ArkGroup;
use super::*;
use ark_bls12_381::{G1Projective, G2Projective};
type G1 = ArkGroup<G1Projective>;
type G2 = ArkGroup<G2Projective>;
#[test]
pub fn test_com_eq_correctness() {
let mut csprng = rand::thread_rng();
for _i in 1..20 {
ComEq::<G1, G2>::with_valid_data(0, &mut csprng, |com_eq, secret, csprng| {
let challenge_prefix = generate_challenge_prefix(csprng);
let mut ro = RandomOracle::domain(challenge_prefix);
let proof = prove(&mut ro.split(), &com_eq, secret, csprng)
.expect("Proving should succeed.");
let res = verify(&mut ro, &com_eq, &proof);
assert!(res, "Verification of produced proof.");
})
}
}
#[test]
pub fn test_com_eq_soundness() {
let mut csprng = rand::thread_rng();
for i in 1..20 {
ComEq::<G1, G2>::with_valid_data(i, &mut csprng, |com_eq, secret, csprng| {
let challenge_prefix = generate_challenge_prefix(csprng);
let ro = RandomOracle::domain(challenge_prefix);
let proof = prove(&mut ro.split(), &com_eq, secret, csprng)
.expect("Proving should succeed.");
let mut wrong_ro = RandomOracle::domain(generate_challenge_prefix(csprng));
if verify(&mut wrong_ro, &com_eq, &proof) {
assert_eq!(wrong_ro, ro);
}
let mut wrong_com_eq = com_eq;
{
let tmp = wrong_com_eq.commitment;
let v = Value::<G1>::generate(csprng);
wrong_com_eq.commitment = wrong_com_eq.cmm_key.commit(&v, csprng).0;
assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
wrong_com_eq.commitment = tmp;
}
{
let tmp = wrong_com_eq.y;
wrong_com_eq.y = G1::generate(csprng);
assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
wrong_com_eq.y = tmp;
}
{
let tmp = wrong_com_eq.cmm_key;
wrong_com_eq.cmm_key = CommitmentKey::generate(csprng);
assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
wrong_com_eq.cmm_key = tmp;
}
{
let tmp = wrong_com_eq.g;
wrong_com_eq.g = G1::generate(csprng);
assert!(!verify(&mut ro.split(), &wrong_com_eq, &proof));
wrong_com_eq.g = tmp;
}
})
}
}
}