use super::{
com_mult::{ComMult, ComMultSecret, Response as ComMultResponse},
common::{prove as sigma_prove, verify as sigma_verify, SigmaProof},
};
use crate::{
common::*,
curve_arithmetic::{Curve, Field},
pedersen_commitment::{Commitment, CommitmentKey, Randomness, Value},
random_oracle::RandomOracle,
};
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
pub struct Response<C: Curve> {
com_mult_response: SigmaProof<ComMultResponse<C>>,
aux_com: Commitment<C>,
}
pub fn prove_com_ineq<R: rand::Rng, C: Curve>(
com_key: &CommitmentKey<C>,
value: &Value<C>,
value_tilde: &Randomness<C>,
pub_value: C::Scalar,
csprng: &mut R,
) -> Option<Response<C>> {
let mut transcript = RandomOracle::domain(b"InequalityProof");
let c = com_key.hide(&value, value_tilde);
transcript.append_message(b"commitmentKey", &com_key);
transcript.append_message(b"public commitment", &c);
transcript.append_message(b"public value", &pub_value);
let mut diff = pub_value;
diff.negate();
diff.add_assign(value);
let diff_inv = diff.inverse()?;
let diff_val = Value::new(diff);
let diff_inv_val = Value::new(diff_inv);
let cmm_1 = com_key.hide(&diff_val, value_tilde);
let (cmm_2, r_2) = com_key.commit(&diff_inv_val, csprng);
let cmm_3 = Commitment(com_key.g);
let prover = ComMult {
cmms: [cmm_1, cmm_2, cmm_3],
cmm_key: *com_key,
};
let secret = ComMultSecret {
values: [diff_val, diff_inv_val],
rands: [value_tilde.clone(), r_2, Randomness::<C>::zero()],
};
let partial_proof = sigma_prove(&mut transcript, &prover, secret, csprng)?;
Some(Response {
com_mult_response: partial_proof,
aux_com: cmm_2,
})
}
pub fn verify_com_ineq<C: Curve>(
com_key: &CommitmentKey<C>,
c: &Commitment<C>,
pub_value: C::Scalar,
proof: &Response<C>,
) -> bool {
let Response {
com_mult_response,
aux_com,
} = proof;
let mut transcript = RandomOracle::domain(b"InequalityProof");
transcript.append_message(b"commitmentKey", &com_key);
transcript.append_message(b"public commitment", &c);
transcript.append_message(b"public value", &pub_value);
let mut minus_pub_value = pub_value;
minus_pub_value.negate();
let g_minus_pub_value = com_key.g.mul_by_scalar(&minus_pub_value);
let cmm_1: C = c.plus_point(&g_minus_pub_value);
let cmm_3 = Commitment(com_key.g);
let com_mult = ComMult {
cmms: [Commitment(cmm_1), *aux_com, cmm_3],
cmm_key: *com_key,
};
sigma_verify(&mut transcript, &com_mult, com_mult_response)
}
#[cfg(test)]
mod tests {
use crate::id::constants::{ArCurve, BaseField};
use super::*;
use std::str::FromStr;
type G1 = ArCurve;
type Fr = BaseField;
#[test]
fn test_com_ineq_correctness() {
let mut csprng = rand::thread_rng();
let com_key: CommitmentKey<_> = CommitmentKey::<G1>::generate(&mut csprng);
let value = Value::<G1>::new(Fr::from_str("20000102").unwrap());
let pub_value = Fr::from_str("20000103").unwrap();
let (cmm_1, value_tilde) = com_key.commit(&value, &mut csprng);
let proof = prove_com_ineq(&com_key, &value, &value_tilde, pub_value, &mut csprng)
.expect("Proving should succeed.");
assert!(
verify_com_ineq(&com_key, &cmm_1, pub_value, &proof),
"Incorrect inequality proof."
);
}
#[test]
fn test_com_ineq_soundness() {
let mut csprng = rand::thread_rng();
let com_key: CommitmentKey<_> = CommitmentKey::<G1>::generate(&mut csprng);
let value = Value::<G1>::new(Fr::from_str("20000102").unwrap());
let pub_value = Fr::from_str("20000103").unwrap();
let (cmm_1, value_tilde) = com_key.commit(&value, &mut csprng);
let proof = prove_com_ineq(&com_key, &value, &value_tilde, pub_value, &mut csprng)
.expect("Proving should succeed.");
let wrong_com_key = CommitmentKey::<G1>::generate(&mut csprng);
let wrong_pub_value = Fr::from_str("20000102").unwrap();
let wrong_proof = Response {
aux_com: Commitment(G1::generate(&mut csprng)),
com_mult_response: proof.com_mult_response.clone(),
};
assert!(!verify_com_ineq(&wrong_com_key, &cmm_1, pub_value, &proof));
assert!(!verify_com_ineq(&com_key, &cmm_1, wrong_pub_value, &proof));
assert!(!verify_com_ineq(&com_key, &cmm_1, pub_value, &wrong_proof));
assert_eq!(
prove_com_ineq(&com_key, &value, &value_tilde, wrong_pub_value, &mut csprng),
None
);
}
}