use bacteria::Transcript;
use mohan::{
ser,
dalek::{
ristretto::RistrettoPoint,
scalar::Scalar,
constants::RISTRETTO_BASEPOINT_COMPRESSED
},
mohan_rand,
hash::hash_to_ristretto
};
use crate::ZeiError;
use serde::{ Serialize, Deserialize };
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
pub struct EqualityProof {
pub(crate) c: Scalar,
pub(crate) z: Scalar,
}
impl Default for EqualityProof {
fn default() -> EqualityProof {
EqualityProof {
c: Scalar::zero(),
z: Scalar::zero()
}
}
}
impl EqualityProof {
pub fn proove(
c1: &RistrettoPoint,
c1_blind: &Scalar,
c2: &RistrettoPoint,
c2_blind: &Scalar
) -> Result<EqualityProof, ZeiError> {
let mut transcript = Transcript::new(b"zei_equality_proof");
let base_h = hash_to_ristretto(RISTRETTO_BASEPOINT_COMPRESSED.as_bytes());
let mut rng = transcript
.build_rng()
.finalize(&mut mohan_rand());
let r = Scalar::random(&mut rng);
let rh = &r * &base_h;
let big_a = c1 - c2;
let c = {
transcript.commit_point(b"A", &big_a.compress());
transcript.commit_point(b"H", &base_h.compress());
transcript.commit_point(b"factor", &rh.compress());
transcript.challenge_scalar(b"c")
};
let a = c1_blind - c2_blind;
let z = (&a*&c) + r;
Ok(
EqualityProof {
c: c,
z: z
}
)
}
pub fn verify(&self, c1: &RistrettoPoint, c2: &RistrettoPoint) -> Result<(), ZeiError> {
let mut transcript = Transcript::new(b"zei_equality_proof");
let base_h = hash_to_ristretto(RISTRETTO_BASEPOINT_COMPRESSED.as_bytes());
let big_a = c1 - c2;
let factor = (&self.z * base_h) - (self.c * big_a);
let c = {
transcript.commit_point(b"A", &big_a.compress());
transcript.commit_point(b"H", &base_h.compress());
transcript.commit_point(b"factor", &factor.compress());
transcript.challenge_scalar(b"c")
};
if c == self.c {
Ok(())
} else {
Err(ZeiError::VerificationError)
}
}
}
impl ser::Writeable for EqualityProof {
fn write<W: ser::Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
self.c.write(writer)?;
self.z.write(writer)?;
Ok(())
}
}
impl ser::Readable for EqualityProof {
fn read(reader: &mut dyn ser::Reader) -> Result<EqualityProof, ser::Error> {
Ok(EqualityProof{
c: Scalar::read(reader)?,
z: Scalar::read(reader)?
})
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::PedersenGens;
#[test]
fn test_simple() {
let mut transcript = Transcript::new(b"zei_equality_proof_test");
let mut rng = transcript
.build_rng()
.finalize(&mut mohan_rand());
let value = Scalar::from(11111u64);
let input_blind = Scalar::random(&mut rng);
let output_blind = Scalar::random(&mut rng);
let pc_gens = PedersenGens::default();
let inputs_comm = pc_gens.commit(&value, &input_blind);
let outputs_comm = pc_gens.commit(&value, &output_blind);
let proof = EqualityProof::proove(&inputs_comm, &input_blind, &outputs_comm, &output_blind).unwrap();
assert!(proof.verify(&inputs_comm, &outputs_comm).is_ok());
}
#[test]
fn test_simple_2() {
let mut transcript = Transcript::new(b"zei_equality_proof_test");
let mut rng = transcript
.build_rng()
.finalize(&mut mohan_rand());
let input_blind = Scalar::random(&mut rng);
let output_blind = Scalar::random(&mut rng);
let input_blind2 = Scalar::random(&mut rng);
let output_blind2 = Scalar::random(&mut rng);
let pc_gens = PedersenGens::default();
let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
let inputs_comm2 = pc_gens.commit(&Scalar::from(12u64), &input_blind2);
let outputs_comm = pc_gens.commit(&Scalar::from(11u64), &output_blind);
let outputs_comm2 = pc_gens.commit(&Scalar::from(1u64), &output_blind2);
let total_in = inputs_comm + inputs_comm2;
let total_out = outputs_comm + outputs_comm2;
let total_in_r = input_blind + input_blind2;
let total_out_r = output_blind + output_blind2;
let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();
assert!(proof.verify(&total_in, &total_out).is_err());
}
#[test]
fn test_simple_3() {
let mut transcript = Transcript::new(b"zei_equality_proof_test");
let mut rng = transcript
.build_rng()
.finalize(&mut mohan_rand());
let input_blind = Scalar::random(&mut rng);
let output_blind = Scalar::random(&mut rng);
let input_blind2 = Scalar::random(&mut rng);
let output_blind2 = Scalar::random(&mut rng);
let pc_gens = PedersenGens::default();
let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
let inputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &input_blind2);
let outputs_comm = pc_gens.commit(&Scalar::from(11u64), &output_blind);
let outputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &output_blind2);
let total_in = inputs_comm + inputs_comm2;
let total_out = outputs_comm + outputs_comm2;
let total_in_r = input_blind + input_blind2;
let total_out_r = output_blind + output_blind2;
let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();
assert!(proof.verify(&total_in, &total_out).is_ok());
}
#[test]
fn test_simple_4() {
let mut transcript = Transcript::new(b"zei_equality_proof_test");
let mut rng = transcript
.build_rng()
.finalize(&mut mohan_rand());
let input_blind = Scalar::random(&mut rng);
let output_blind = Scalar::random(&mut rng);
let input_blind2 = Scalar::random(&mut rng);
let pc_gens = PedersenGens::default();
let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
let inputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &input_blind2);
let outputs_comm = pc_gens.commit(&Scalar::from(11u64), &output_blind);
let total_in = inputs_comm + inputs_comm2;
let total_out = outputs_comm;
let total_in_r = input_blind + input_blind2;
let total_out_r = output_blind;
let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();
assert!(proof.verify(&total_in, &total_out).is_err());
}
#[test]
fn test_simple_5() {
let mut transcript = Transcript::new(b"zei_equality_proof_test");
let mut rng = transcript
.build_rng()
.finalize(&mut mohan_rand());
let input_blind = Scalar::random(&mut rng);
let output_blind = Scalar::random(&mut rng);
let input_blind2 = Scalar::random(&mut rng);
let pc_gens = PedersenGens::default();
let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
let inputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &input_blind2);
let outputs_comm = pc_gens.commit(&Scalar::from(1000u64), &output_blind);
let total_in = inputs_comm + inputs_comm2;
let total_out = outputs_comm;
let total_in_r = input_blind + input_blind2;
let total_out_r = output_blind;
let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();
assert!(proof.verify(&total_in, &total_out).is_err());
}
#[test]
fn test_simple_not_equal() {
let mut transcript = Transcript::new(b"zei_equality_proof_test");
let mut rng = transcript
.build_rng()
.finalize(&mut mohan_rand());
let value = Scalar::from(11111u64);
let value2 = Scalar::from(111111u64);
let input_blind = Scalar::random(&mut rng);
let output_blind = Scalar::random(&mut rng);
let pc_gens = PedersenGens::default();
let inputs_comm = pc_gens.commit(&value, &input_blind);
let outputs_comm = pc_gens.commit(&value2, &output_blind);
let proof = EqualityProof::proove(&inputs_comm, &input_blind, &outputs_comm, &output_blind).unwrap();
assert!(proof.verify(&inputs_comm, &outputs_comm).is_err());
}
}