use crate::{PokSignatureProof, PublicKey, Signature};
use bls12_381_plus::{G1Projective, G2Affine, G2Projective, Scalar};
use digest::Update;
use group::Curve;
use rand_core::*;
use signature_core::constants::ALLOC_MSG;
use signature_core::{error::Error, lib::*};
pub struct PokSignature {
secrets: Vec<Scalar, 130>,
proof: ProofCommittedBuilder<G2Projective, G2Affine, 130, 130>,
commitment: G2Projective,
sigma_1: G1Projective,
sigma_2: G1Projective,
}
impl PokSignature {
pub fn init(
signature: Signature,
public_key: &PublicKey,
messages: &[ProofMessage],
mut rng: impl RngCore + CryptoRng,
) -> Result<Self, Error> {
if public_key.y.len() < messages.len() {
return Err(Error::new(1, "mismatched messages and generators"));
}
let r = Nonce::random(&mut rng);
let t = Nonce::random(&mut rng);
let sigma_1 = signature.sigma_1 * r.0;
let sigma_2 = (signature.sigma_2 + (signature.sigma_1 * t.0)) * r.0;
let mut proof = ProofCommittedBuilder::new(G2Projective::sum_of_products_in_place);
let mut points = Vec::<G2Projective, 130>::new();
let mut secrets = Vec::<Scalar, 130>::new();
proof.commit_random(G2Projective::generator(), &mut rng);
points.push(G2Projective::generator()).expect(ALLOC_MSG);
secrets.push(t.0).expect(ALLOC_MSG);
proof.commit_random(public_key.w, &mut rng);
points.push(public_key.w).expect(ALLOC_MSG);
secrets.push(signature.m_tick).expect(ALLOC_MSG);
#[allow(clippy::needless_range_loop)]
for i in 0..messages.len() {
match messages[i] {
ProofMessage::Hidden(HiddenMessage::ProofSpecificBlinding(m)) => {
proof.commit_random(public_key.y[i], &mut rng);
points.push(public_key.y[i]).expect(ALLOC_MSG);
secrets.push(m.0).expect(ALLOC_MSG);
}
ProofMessage::Hidden(HiddenMessage::ExternalBlinding(m, n)) => {
proof.commit(public_key.y[i], n.0);
points.push(public_key.y[i]).expect(ALLOC_MSG);
secrets.push(m.0).expect(ALLOC_MSG);
}
_ => {}
}
}
let commitment = G2Projective::sum_of_products_in_place(points.as_ref(), secrets.as_mut());
Ok(Self {
secrets,
proof,
commitment,
sigma_1,
sigma_2,
})
}
pub fn add_proof_contribution(&mut self, hasher: &mut impl Update) {
hasher.update(self.sigma_1.to_affine().to_uncompressed());
hasher.update(self.sigma_2.to_affine().to_uncompressed());
hasher.update(self.commitment.to_affine().to_uncompressed());
self.proof.add_challenge_contribution(hasher);
}
pub fn generate_proof(self, challenge: Challenge) -> Result<PokSignatureProof, Error> {
let proof = self
.proof
.generate_proof(challenge.0, self.secrets.as_ref())?
.iter()
.map(|s| Challenge(*s))
.collect();
Ok(PokSignatureProof {
sigma_1: self.sigma_1,
sigma_2: self.sigma_2,
commitment: self.commitment,
proof,
})
}
}