penumbra_sdk_proof_params/
traits.rs

1use ark_ec::pairing::Pairing;
2use ark_groth16::{
3    r1cs_to_qap::LibsnarkReduction, Groth16, PreparedVerifyingKey, ProvingKey, VerifyingKey,
4};
5use ark_relations::r1cs::{self, ConstraintMatrices, ConstraintSynthesizer};
6use ark_serialize::CanonicalSerialize;
7use ark_snark::SNARK;
8use decaf377::Bls12_377;
9use rand_core::CryptoRngCore;
10
11/// This trait characterizes circuits which can generate constraints.
12pub trait DummyWitness: ConstraintSynthesizer<<Bls12_377 as Pairing>::ScalarField> {
13    /// This will create a circuit with dummy witness values, for constraint synthesis
14    ///
15    /// (The reason this is needed is because constraint synthesis encapsulates both the act
16    /// of generating the constraints, but also that of providing the witness values when proving).
17    /// ((For the record, I am not a fan of this)).
18    fn with_dummy_witness() -> Self;
19}
20
21/// Generate constraint matrices from a circuit type.
22///
23/// This is useful because it provides a way to get the actual constraints
24/// associated with some circuit, without actually generating a proving key via a trusted setup.
25/// This is what you need for doing a setup ceremony, among other things.
26pub fn generate_constraint_matrices<T: DummyWitness>(
27) -> ConstraintMatrices<<Bls12_377 as Pairing>::ScalarField> {
28    let circuit = T::with_dummy_witness();
29
30    let cs = r1cs::ConstraintSystem::new_ref();
31    cs.set_optimization_goal(r1cs::OptimizationGoal::Constraints);
32    cs.set_mode(r1cs::SynthesisMode::Setup);
33    // For why this is ok, see `generate_test_parameters`.
34    circuit
35        .generate_constraints(cs.clone())
36        .expect("can generate constraints from circuit");
37    cs.finalize();
38
39    // I honestly don't know why this would fail.
40    // But if it does, it's not at runtime in a node.
41    cs.to_matrices()
42        .expect("can convert R1CS constraints into matrices")
43}
44
45/// Generate parameters for proving and verifying, for *tests*.
46///
47/// These parameters should not be used for actual production code,
48/// because the randomness may not have been securely destroyed.
49pub fn generate_test_parameters<T: DummyWitness>(
50    rng: &mut impl CryptoRngCore,
51) -> (ProvingKey<Bls12_377>, VerifyingKey<Bls12_377>) {
52    let circuit = T::with_dummy_witness();
53
54    // Unwrapping here is ok because:
55    // 1. This code is not run in node software at run time (or shouldn't be)
56    // 2. If this fails, there's a bug in one of our circuits (which is bad)
57    Groth16::<Bls12_377, LibsnarkReduction>::circuit_specific_setup(circuit, rng)
58        .expect("can generate constraints from circuit")
59}
60
61/// A variant of `generate_test_parameters` which spits out a verifying key with some
62/// precomputation.
63pub fn generate_prepared_test_parameters<T: DummyWitness>(
64    rng: &mut impl CryptoRngCore,
65) -> (ProvingKey<Bls12_377>, PreparedVerifyingKey<Bls12_377>) {
66    let (pk, vk) = generate_test_parameters::<T>(rng);
67    (pk, vk.into())
68}
69
70pub trait VerifyingKeyExt {
71    fn debug_id(&self) -> String;
72}
73
74impl VerifyingKeyExt for VerifyingKey<Bls12_377> {
75    fn debug_id(&self) -> String {
76        let mut buf = Vec::new();
77        self.serialize_compressed(&mut buf)
78            .expect("can serialize vk");
79        use sha2::Digest;
80        let hash = sha2::Sha256::digest(&buf);
81        use bech32::ToBase32;
82        bech32::encode("groth16vk", hash.to_base32(), bech32::Variant::Bech32m)
83            .expect("can encode vk as bech32")
84    }
85}
86
87impl VerifyingKeyExt for PreparedVerifyingKey<Bls12_377> {
88    fn debug_id(&self) -> String {
89        self.vk.debug_id()
90    }
91}
92
93pub trait ProvingKeyExt {
94    fn debug_id(&self) -> String;
95}
96
97impl ProvingKeyExt for ProvingKey<Bls12_377> {
98    fn debug_id(&self) -> String {
99        let mut buf = Vec::new();
100        self.serialize_compressed(&mut buf)
101            .expect("can serialize pk");
102        use sha2::Digest;
103        let hash = sha2::Sha256::digest(&buf);
104        use bech32::ToBase32;
105        bech32::encode("groth16pk", hash.to_base32(), bech32::Variant::Bech32m)
106            .expect("can encode pk as bech32")
107    }
108}