use bls12_381 as bls;
use itertools::{chain, izip};
use crate::bls_extensions::*;
use crate::elgamal::*;
use crate::parameters::*;
use crate::proofs::proof::*;
pub struct SignatureProofBuilder<'a, R: RngInstance> {
params: &'a Parameters<R>,
private_attributes: &'a Vec<bls::Scalar>,
public_attributes: &'a Vec<bls::Scalar>,
attribute_keys: &'a Vec<bls::Scalar>,
blinding_factor: &'a bls::Scalar,
witness_blind: bls::Scalar,
witness_attributes: Vec<bls::Scalar>,
witness_keys: Vec<bls::Scalar>,
}
pub struct SignatureProofCommitments<'a, R: RngInstance> {
params: &'a Parameters<R>,
gamma: &'a ElGamalPublicKey<'a, R>,
commit_hash: &'a bls::G1Projective,
attribute_commit: &'a bls::G1Projective,
commit_attributes: bls::G1Projective,
commit_keys: Vec<(bls::G1Projective, bls::G1Projective)>,
}
pub struct SignatureProof {
response_blind: bls::Scalar,
response_attributes: Vec<bls::Scalar>,
response_keys: Vec<bls::Scalar>,
}
impl<'a, R: RngInstance> SignatureProofBuilder<'a, R> {
pub fn new(
params: &'a Parameters<R>,
private_attributes: &'a Vec<bls::Scalar>,
public_attributes: &'a Vec<bls::Scalar>,
attribute_keys: &'a Vec<bls::Scalar>,
blinding_factor: &'a bls::Scalar,
) -> Self {
assert_eq!(
params.hs.len(),
private_attributes.len() + public_attributes.len()
);
Self {
params,
private_attributes,
public_attributes,
attribute_keys,
blinding_factor,
witness_blind: params.random_scalar(),
witness_attributes: params
.random_scalars(private_attributes.len() + public_attributes.len()),
witness_keys: params.random_scalars(attribute_keys.len()),
}
}
pub fn commitments(
&self,
gamma: &'a ElGamalPublicKey<'a, R>,
commit_hash: &'a bls::G1Projective,
attribute_commit: &'a bls::G1Projective,
) -> Box<SignatureProofCommitments<'a, R>> {
assert_eq!(self.witness_attributes.len(), self.params.hs.len());
let mut commit_attributes = self.params.g1 * self.witness_blind;
for (h, witness) in izip!(&self.params.hs, &self.witness_attributes) {
commit_attributes += h * witness;
}
Box::new(SignatureProofCommitments {
params: self.params,
gamma,
commit_hash,
attribute_commit,
commit_attributes,
commit_keys: izip!(&self.witness_attributes, &self.witness_keys)
.map(|(witness_attribute, witness_key)| {
(
self.params.g1 * witness_key,
commit_hash * witness_attribute + gamma.public_key * witness_key,
)
})
.collect(),
})
}
pub fn finish(&self, challenge: &bls::Scalar) -> SignatureProof {
assert_eq!(
self.witness_attributes.len(),
self.private_attributes.len() + self.public_attributes.len()
);
assert_eq!(self.witness_keys.len(), self.attribute_keys.len());
SignatureProof {
response_blind: self.witness_blind - challenge * self.blinding_factor,
response_attributes: izip!(
chain(self.private_attributes, self.public_attributes),
&self.witness_attributes
)
.map(|(attribute, witness)| witness - challenge * attribute)
.collect(),
response_keys: izip!(self.attribute_keys, &self.witness_keys)
.map(|(key, witness)| witness - challenge * key)
.collect(),
}
}
}
impl<'a, R: RngInstance> ProofCommitments for SignatureProofCommitments<'a, R> {
fn commit(&self, hasher: &mut ProofHasher) {
hasher.add_g1_affine(&self.params.g1);
hasher.add_g2_affine(&self.params.g2);
for h in &self.params.hs {
hasher.add_g1_affine(h);
}
hasher.add_g1(&self.gamma.public_key);
hasher.add_g1(self.commit_hash);
hasher.add_g1(self.attribute_commit);
hasher.add_g1(&self.commit_attributes);
for (commit_a, commit_b) in &self.commit_keys {
hasher.add_g1(&commit_a);
hasher.add_g1(&commit_b);
}
}
}
impl SignatureProof {
pub fn commitments<'a, R: RngInstance>(
&self,
params: &'a Parameters<R>,
challenge: &bls::Scalar,
gamma: &'a ElGamalPublicKey<'a, R>,
commit_hash: &'a bls::G1Projective,
attribute_commit: &'a bls::G1Projective,
ciphertexts: &Vec<EncryptedValue>,
) -> Box<SignatureProofCommitments<'a, R>> {
let mut commit_attributes = attribute_commit * challenge + params.g1 * self.response_blind;
for (h, response) in izip!(¶ms.hs, &self.response_attributes) {
commit_attributes += h * response;
}
Box::new(SignatureProofCommitments {
params,
gamma,
commit_hash,
attribute_commit,
commit_attributes,
commit_keys: izip!(&self.response_attributes, &self.response_keys, ciphertexts)
.map(|(response_attribute, response_key, ciphertext)| {
(
ciphertext.0 * challenge + params.g1 * response_key,
ciphertext.1 * challenge
+ gamma.public_key * response_key
+ commit_hash * response_attribute,
)
})
.collect(),
})
}
}