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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#![deny(clippy::unwrap_used)]
// Requires nightly.
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

use anyhow::{bail, Result};
use ark_groth16::{PreparedVerifyingKey, ProvingKey, VerifyingKey};
use ark_serialize::CanonicalDeserialize;
use decaf377::Bls12_377;
use once_cell::sync::{Lazy, OnceCell};
use std::ops::Deref;

/// The length of our Groth16 proofs in bytes.
pub const GROTH16_PROOF_LENGTH_BYTES: usize = 192;

mod traits;

pub use traits::{
    generate_constraint_matrices, generate_prepared_test_parameters, generate_test_parameters,
    DummyWitness, ProvingKeyExt, VerifyingKeyExt,
};

/// A wrapper around a proving key that can be lazily loaded.
///
/// One instance of this struct is created for each proving key.
///
/// The behavior of those instances is controlled by the `bundled-proving-keys`
/// feature. When the feature is enabled, the proving key data is bundled into
/// the binary at compile time, and the proving key is loaded from the bundled
/// data on first use.  When the feature is not enabled, the proving key must be
/// loaded using `try_load` prior to its first use.
///
/// The `bundled-proving-keys` feature needs access to proving keys at build
/// time.  When pulling the crate as a dependency, these may not be available.
/// To address this, the `download-proving-keys` feature will download them from
/// the network at build time. All proving keys are checked against hardcoded hashes
/// to ensure they have not been tampered with.
#[derive(Debug, Default)]
pub struct LazyProvingKey {
    pk_id: &'static str,
    inner: OnceCell<ProvingKey<Bls12_377>>,
}

impl LazyProvingKey {
    // Not making this pub means only the statically defined proving keys can exist.
    fn new(pk_id: &'static str) -> Self {
        LazyProvingKey {
            pk_id,
            inner: OnceCell::new(),
        }
    }

    /// Attempt to load the proving key from the given bytes.
    ///
    /// The provided bytes are validated against a hardcoded hash of the expected proving key,
    /// so passing the wrong proving key will fail.
    ///
    /// If the proving key is already loaded, this method is a no-op.
    pub fn try_load(&self, bytes: &[u8]) -> Result<&ProvingKey<Bls12_377>> {
        self.inner.get_or_try_init(|| {
            let pk = ProvingKey::deserialize_uncompressed_unchecked(bytes)?;

            let pk_id = pk.debug_id();
            if pk_id != self.pk_id {
                bail!(
                    "proving key ID mismatch: expected {}, loaded {}",
                    self.pk_id,
                    pk_id
                );
            }

            Ok(pk)
        })
    }

    /// Attempt to load the proving key from the given bytes.
    ///
    /// This method bypasses the validation checks against the hardcoded
    /// hash of the expected proving key.
    pub fn try_load_unchecked(&self, bytes: &[u8]) -> Result<&ProvingKey<Bls12_377>> {
        self.inner.get_or_try_init(|| {
            let pk = ProvingKey::deserialize_uncompressed_unchecked(bytes)?;

            Ok(pk)
        })
    }
}

impl Deref for LazyProvingKey {
    type Target = ProvingKey<Bls12_377>;

    fn deref(&self) -> &Self::Target {
        self.inner.get().expect("Proving key cannot be loaded!")
    }
}

// Note: Conditionally load the proving key objects if the
// bundled-proving-keys is present.

/// Proving key for the spend proof.
pub static SPEND_PROOF_PROVING_KEY: Lazy<LazyProvingKey> = Lazy::new(|| {
    let spend_proving_key = LazyProvingKey::new(spend::PROVING_KEY_ID);

    #[cfg(feature = "bundled-proving-keys")]
    spend_proving_key
        .try_load(include_bytes!("gen/spend_pk.bin"))
        .expect("bundled proving key is valid");

    spend_proving_key
});

/// Verification key for the spend proof.
pub static SPEND_PROOF_VERIFICATION_KEY: Lazy<PreparedVerifyingKey<Bls12_377>> =
    Lazy::new(|| spend_verification_parameters().into());

pub mod spend {
    include!("gen/spend_id.rs");
}

/// Proving key for the output proof.
pub static OUTPUT_PROOF_PROVING_KEY: Lazy<LazyProvingKey> = Lazy::new(|| {
    let output_proving_key = LazyProvingKey::new(output::PROVING_KEY_ID);

    #[cfg(feature = "bundled-proving-keys")]
    output_proving_key
        .try_load(include_bytes!("gen/output_pk.bin"))
        .expect("bundled proving key is valid");

    output_proving_key
});

/// Verification key for the output proof.
pub static OUTPUT_PROOF_VERIFICATION_KEY: Lazy<PreparedVerifyingKey<Bls12_377>> =
    Lazy::new(|| output_verification_parameters().into());

pub mod output {
    include!("gen/output_id.rs");
}

/// Proving key for the swap proof.
pub static SWAP_PROOF_PROVING_KEY: Lazy<LazyProvingKey> = Lazy::new(|| {
    let swap_proving_key = LazyProvingKey::new(swap::PROVING_KEY_ID);

    #[cfg(feature = "bundled-proving-keys")]
    swap_proving_key
        .try_load(include_bytes!("gen/swap_pk.bin"))
        .expect("bundled proving key is valid");

    swap_proving_key
});

/// Verification key for the swap proof.
pub static SWAP_PROOF_VERIFICATION_KEY: Lazy<PreparedVerifyingKey<Bls12_377>> =
    Lazy::new(|| swap_verification_parameters().into());

pub mod swap {
    include!("gen/swap_id.rs");
}

/// Proving key for the swap claim proof.
pub static SWAPCLAIM_PROOF_PROVING_KEY: Lazy<LazyProvingKey> = Lazy::new(|| {
    let swapclaim_proving_key = LazyProvingKey::new(swapclaim::PROVING_KEY_ID);

    #[cfg(feature = "bundled-proving-keys")]
    swapclaim_proving_key
        .try_load(include_bytes!("gen/swapclaim_pk.bin"))
        .expect("bundled proving key is valid");

    swapclaim_proving_key
});

/// Verification key for the swap claim proof.
pub static SWAPCLAIM_PROOF_VERIFICATION_KEY: Lazy<PreparedVerifyingKey<Bls12_377>> =
    Lazy::new(|| swapclaim_verification_parameters().into());

pub mod swapclaim {
    include!("gen/swapclaim_id.rs");
}

/// Proving key for the convert proof.
pub static CONVERT_PROOF_PROVING_KEY: Lazy<LazyProvingKey> = Lazy::new(|| {
    let convert_proving_key = LazyProvingKey::new(convert::PROVING_KEY_ID);

    #[cfg(feature = "bundled-proving-keys")]
    convert_proving_key
        .try_load(include_bytes!("gen/convert_pk.bin"))
        .expect("bundled proving key is valid");

    convert_proving_key
});

/// Verification key for the convert proof.
pub static CONVERT_PROOF_VERIFICATION_KEY: Lazy<PreparedVerifyingKey<Bls12_377>> =
    Lazy::new(|| convert_verification_parameters().into());

pub mod convert {
    include!("gen/convert_id.rs");
}

/// Proving key for the delegator vote proof.
pub static DELEGATOR_VOTE_PROOF_PROVING_KEY: Lazy<LazyProvingKey> = Lazy::new(|| {
    let delegator_vote_proving_key = LazyProvingKey::new(delegator_vote::PROVING_KEY_ID);

    #[cfg(feature = "bundled-proving-keys")]
    delegator_vote_proving_key
        .try_load(include_bytes!("gen/delegator_vote_pk.bin"))
        .expect("bundled proving key is valid");

    delegator_vote_proving_key
});

/// Verification key for the delegator vote proof.
pub static DELEGATOR_VOTE_PROOF_VERIFICATION_KEY: Lazy<PreparedVerifyingKey<Bls12_377>> =
    Lazy::new(|| delegator_vote_verification_parameters().into());

pub mod delegator_vote {
    include!("gen/delegator_vote_id.rs");
}

/// Proving key for the nullifier derivation proof.
pub static NULLIFIER_DERIVATION_PROOF_PROVING_KEY: Lazy<LazyProvingKey> = Lazy::new(|| {
    let nullifier_proving_key = LazyProvingKey::new(nullifier_derivation::PROVING_KEY_ID);

    #[cfg(feature = "bundled-proving-keys")]
    nullifier_proving_key
        .try_load(include_bytes!("gen/nullifier_derivation_pk.bin"))
        .expect("bundled proving key is valid");

    nullifier_proving_key
});

/// Verification key for the delegator vote proof.
pub static NULLIFIER_DERIVATION_PROOF_VERIFICATION_KEY: Lazy<PreparedVerifyingKey<Bls12_377>> =
    Lazy::new(|| nullifier_derivation_verification_parameters().into());

pub mod nullifier_derivation {
    include!("gen/nullifier_derivation_id.rs");
}

// Note: Here we are using `CanonicalDeserialize::deserialize_uncompressed_unchecked` as the
// parameters are being loaded from a trusted source (our source code).

fn spend_verification_parameters() -> VerifyingKey<Bls12_377> {
    let vk_params = include_bytes!("gen/spend_vk.param");
    VerifyingKey::deserialize_uncompressed_unchecked(&vk_params[..])
        .expect("can deserialize VerifyingKey")
}

fn output_verification_parameters() -> VerifyingKey<Bls12_377> {
    let vk_params = include_bytes!("gen/output_vk.param");
    VerifyingKey::deserialize_uncompressed_unchecked(&vk_params[..])
        .expect("can deserialize VerifyingKey")
}

fn swap_verification_parameters() -> VerifyingKey<Bls12_377> {
    let vk_params = include_bytes!("gen/swap_vk.param");
    VerifyingKey::deserialize_uncompressed_unchecked(&vk_params[..])
        .expect("can deserialize VerifyingKey")
}

fn swapclaim_verification_parameters() -> VerifyingKey<Bls12_377> {
    let vk_params = include_bytes!("gen/swapclaim_vk.param");
    VerifyingKey::deserialize_uncompressed_unchecked(&vk_params[..])
        .expect("can deserialize VerifyingKey")
}

fn convert_verification_parameters() -> VerifyingKey<Bls12_377> {
    let vk_params = include_bytes!("gen/convert_vk.param");
    VerifyingKey::deserialize_uncompressed_unchecked(&vk_params[..])
        .expect("can deserialize VerifyingKey")
}

fn delegator_vote_verification_parameters() -> VerifyingKey<Bls12_377> {
    let vk_params = include_bytes!("gen/delegator_vote_vk.param");
    VerifyingKey::deserialize_uncompressed_unchecked(&vk_params[..])
        .expect("can deserialize VerifyingKey")
}

fn nullifier_derivation_verification_parameters() -> VerifyingKey<Bls12_377> {
    let vk_params = include_bytes!("gen/nullifier_derivation_vk.param");
    VerifyingKey::deserialize_uncompressed_unchecked(&vk_params[..])
        .expect("can deserialize VerifyingKey")
}