1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::{MessageGenerators, PokSignatureProof, Signature};
use bls12_381_plus::{G1Affine, G1Projective, Scalar};
use core::ops::Neg;
use digest::Update;
use ff::Field;
use group::Curve;
use rand_core::{CryptoRng, RngCore};
use signature_core::{error::Error, lib::*};

/// Proof of Knowledge of a Signature that is used by the prover
/// to construct `PoKOfSignatureProof`.
pub struct PokSignature {
    /// A' in section 4.5
    a_prime: G1Projective,
    /// \overline{A} in section 4.5
    a_bar: G1Projective,
    /// d in section 4.5
    d: G1Projective,
    /// For proving relation a_bar / d == a_prime^{-e} * h_0^r2
    proof1: ProofCommittedBuilder<G1Projective, G1Affine, 2, 2>,
    /// The messages
    secrets1: [Scalar; 2],
    /// For proving relation g1 * h1^m1 * h2^m2.... for all disclosed messages m_i == d^r3 * h_0^{-s_prime} * h1^-m1 * h2^-m2.... for all undisclosed messages m_i
    /// 130 because 128 messages + 2 extra for blinding
    proof2: ProofCommittedBuilder<G1Projective, G1Affine, 130, 130>,
    /// The blinding factors
    secrets2: Vec<Scalar, 130>,
}

impl PokSignature {
    /// Creates the initial proof data before a Fiat-Shamir calculation
    pub fn init(
        signature: Signature,
        generators: &MessageGenerators,
        messages: &[ProofMessage],
        mut rng: impl RngCore + CryptoRng,
    ) -> Result<Self, Error> {
        if messages.len() != generators.len() {
            return Err(Error::new(1, "mismatched messages with and generators"));
        }

        let r1 = Scalar::random(&mut rng);
        let r2 = Scalar::random(&mut rng);
        let r3 = r1.invert().unwrap();

        let m = messages
            .iter()
            .map(|m| m.get_message())
            .collect::<Vec<Message, 128>>();

        let b = Signature::compute_b(signature.s, m.as_ref(), generators);

        let a_prime = signature.a * r1;
        let a_bar = b * r1 - a_prime * signature.e;

        // d = b * r1 + h0 * r2
        let d = G1Projective::sum_of_products_in_place(&[b, generators.h0], [r1, r2].as_mut());

        // s' = s - r2 r3
        let s_prime = signature.s + r2 * r3;

        // For proving relation a_bar / d == a_prime^{-e} * h_0^r2
        let mut proof1 = ProofCommittedBuilder::<G1Projective, G1Affine, 2, 2>::new(
            G1Projective::sum_of_products_in_place,
        );
        // For a_prime * -e
        proof1.commit_random(a_prime, &mut rng);
        // For h0 * r2
        proof1.commit_random(generators.h0, &mut rng);
        let secrets1 = [signature.e, r2];

        let mut proof2 = ProofCommittedBuilder::<G1Projective, G1Affine, 130, 130>::new(
            G1Projective::sum_of_products_in_place,
        );
        let mut secrets2 = Vec::new();
        // for d * -r3
        proof2.commit_random(d.neg(), &mut rng);
        secrets2.push(r3).expect("allocate more space");
        // for h0 * s_prime
        proof2.commit_random(generators.h0, &mut rng);
        secrets2.push(s_prime).expect("allocate more space");

        #[allow(clippy::needless_range_loop)]
        for i in 0..generators.len() {
            match messages[i] {
                ProofMessage::Hidden(HiddenMessage::ProofSpecificBlinding(m)) => {
                    proof2.commit_random(generators.get(i), &mut rng);
                    secrets2.push(m.0).expect("allocate more space");
                }
                ProofMessage::Hidden(HiddenMessage::ExternalBlinding(m, e)) => {
                    proof2.commit(generators.get(i), e.0);
                    secrets2.push(m.0).expect("allocate more space");
                }
                _ => {}
            }
        }

        Ok(Self {
            a_prime,
            a_bar,
            d,
            proof1,
            secrets1,
            proof2,
            secrets2,
        })
    }

    /// Convert the committed values to bytes for the fiat-shamir challenge
    pub fn add_proof_contribution(&mut self, hasher: &mut impl Update) {
        hasher.update(self.a_prime.to_affine().to_uncompressed());
        hasher.update(self.a_bar.to_affine().to_uncompressed());
        hasher.update(self.d.to_affine().to_uncompressed());
        self.proof1.add_challenge_contribution(hasher);
        self.proof2.add_challenge_contribution(hasher);
    }

    /// Generate the Schnorr challenges for the selective disclosure proofs
    pub fn generate_proof(self, challenge: Challenge) -> Result<PokSignatureProof, Error> {
        let proof1 = self
            .proof1
            .generate_proof(challenge.0, self.secrets1.as_ref())?;
        let proofs1 = [Challenge(proof1[0]), Challenge(proof1[1])];
        let proofs2: Vec<Challenge, 130> = self
            .proof2
            .generate_proof(challenge.0, self.secrets2.as_ref())?
            .iter()
            .map(|s| Challenge(*s))
            .collect();
        Ok(PokSignatureProof {
            a_prime: self.a_prime,
            a_bar: self.a_bar,
            d: self.d,
            proofs1,
            proofs2,
        })
    }
}