#[macro_export]
macro_rules! impl_PoK_VC {
( $ProverCommitting:ident, $ProverCommitted:ident, $Proof:ident, $group_element:ident, $group_element_vec:ident ) => {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct $ProverCommitting {
gens: $group_element_vec,
blindings: FieldElementVector,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct $ProverCommitted {
gens: $group_element_vec,
blindings: FieldElementVector,
commitment: $group_element,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct $Proof {
pub commitment: $group_element,
pub responses: FieldElementVector,
}
impl $ProverCommitting {
pub fn new() -> Self {
Self {
gens: $group_element_vec::new(0),
blindings: FieldElementVector::new(0),
}
}
pub fn commit(
&mut self,
gen: &$group_element,
blinding: Option<&FieldElement>,
) -> usize {
let blinding = match blinding {
Some(b) => b.clone(),
None => FieldElement::random(),
};
let idx = self.gens.len();
self.gens.push(gen.clone());
self.blindings.push(blinding);
idx
}
pub fn finish(self) -> $ProverCommitted {
let commitment = self
.gens
.multi_scalar_mul_const_time(&self.blindings)
.unwrap();
$ProverCommitted {
gens: self.gens,
blindings: self.blindings,
commitment,
}
}
pub fn get_index(
&self,
idx: usize,
) -> Result<(&$group_element, &FieldElement), PSError> {
if idx >= self.gens.len() {
return Err(PSError::GeneralError {
msg: format!("index {} greater than size {}", idx, self.gens.len()),
});
}
Ok((&self.gens[idx], &self.blindings[idx]))
}
}
impl $ProverCommitted {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = vec![];
for b in self.gens.as_slice() {
bytes.append(&mut b.to_bytes());
}
bytes.append(&mut self.commitment.to_bytes());
bytes
}
pub fn gen_challenge(&self, mut extra: Vec<u8>) -> FieldElement {
let mut bytes = self.to_bytes();
bytes.append(&mut extra);
FieldElement::from_msg_hash(&bytes)
}
pub fn gen_proof(
self,
challenge: &FieldElement,
secrets: &[FieldElement],
) -> Result<$Proof, PSError> {
if secrets.len() != self.gens.len() {
return Err(PSError::UnequalNoOfBasesExponents {
bases: self.gens.len(),
exponents: secrets.len(),
});
}
let mut responses = FieldElementVector::with_capacity(self.gens.len());
for i in 0..self.gens.len() {
responses.push(&self.blindings[i] - (challenge * &secrets[i]));
}
Ok($Proof {
commitment: self.commitment,
responses,
})
}
}
impl $Proof {
pub fn verify(
&self,
bases: &[$group_element],
commitment: &$group_element,
challenge: &FieldElement,
) -> Result<bool, PSError> {
if bases.len() != self.responses.len() {
return Err(PSError::UnequalNoOfBasesExponents {
bases: bases.len(),
exponents: self.responses.len(),
});
}
let mut points = $group_element_vec::from(bases);
let mut scalars = self.responses.clone();
points.push(commitment.clone());
scalars.push(challenge.clone());
let pr = points.multi_scalar_mul_var_time(&scalars).unwrap() - &self.commitment;
Ok(pr.is_identity())
}
}
};
}
#[cfg(test)]
#[macro_export]
macro_rules! test_PoK_VC {
( $n:ident, $ProverCommitting:ident, $ProverCommitted:ident, $Proof:ident, $group_element:ident, $group_element_vec:ident ) => {
let mut gens = $group_element_vec::with_capacity($n);
let mut secrets = FieldElementVector::with_capacity($n);
let mut commiting = $ProverCommitting::new();
for _ in 0..$n - 1 {
let g = $group_element::random();
commiting.commit(&g, None);
gens.push(g);
secrets.push(FieldElement::random());
}
let g = $group_element::random();
let r = FieldElement::random();
commiting.commit(&g, Some(&r));
let (g_, r_) = commiting.get_index($n - 1).unwrap();
assert_eq!(g, *g_);
assert_eq!(r, *r_);
gens.push(g);
secrets.push(FieldElement::random());
let committed = commiting.finish();
let commitment = gens.multi_scalar_mul_const_time(&secrets).unwrap();
let challenge = committed.gen_challenge(commitment.to_bytes());
let proof = committed.gen_proof(&challenge, secrets.as_slice()).unwrap();
assert!(proof
.verify(gens.as_slice(), &commitment, &challenge)
.unwrap());
assert!(!proof
.verify(gens.as_slice(), &$group_element::random(), &challenge)
.unwrap());
assert!(!proof
.verify(gens.as_slice(), &commitment, &FieldElement::random())
.unwrap());
};
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::errors::PSError;
use amcl_wrapper::field_elem::{FieldElement, FieldElementVector};
use amcl_wrapper::group_elem::{GroupElement, GroupElementVector};
use amcl_wrapper::group_elem_g1::{G1Vector, G1};
use amcl_wrapper::group_elem_g2::{G2Vector, G2};
#[test]
fn test_PoK_VC_G1() {
impl_PoK_VC!(ProverCommittingG1, ProverCommittedG1, ProofG1, G1, G1Vector);
let n = 5;
test_PoK_VC!(
n,
ProverCommittingG1,
ProverCommittedG1,
ProofG1,
G1,
G1Vector
);
}
#[test]
fn test_PoK_VC_G2() {
impl_PoK_VC!(ProverCommittingG2, ProverCommittedG2, ProofG2, G2, G2Vector);
let n = 5;
test_PoK_VC!(
n,
ProverCommittingG2,
ProverCommittedG2,
ProofG2,
G2,
G2Vector
);
}
}