-
Notifications
You must be signed in to change notification settings - Fork 107
/
params.rs
217 lines (188 loc) · 8.24 KB
/
params.rs
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
//! Downloading, checking, and loading Groth16 Sapling and Sprout parameters.
use std::path::{Path, PathBuf};
use bellman::groth16;
use bls12_381::Bls12;
use zcash_proofs::SaplingParameterPaths;
use crate::BoxError;
/// The timeout for each parameter file download, in seconds.
///
/// Zebra assumes that it's running on at least a 10 Mbps connection.
/// So the parameter files should download in about 15 minutes using `zebrad download`.
/// But `zebrad start` downloads blocks at the same time, so we allow some extra time.
pub const PARAMETER_DOWNLOAD_TIMEOUT: u64 = 60 * 60;
/// The maximum number of times to retry download parameters.
///
/// Zebra will retry to download Sprout of Sapling parameters only if they
/// failed for whatever reason.
pub const PARAMETER_DOWNLOAD_MAX_RETRIES: usize = 3;
lazy_static::lazy_static! {
/// Groth16 Zero-Knowledge Proof parameters for the Sapling and Sprout circuits.
///
/// When this static is accessed:
/// - the parameters are downloaded if needed, then cached to a shared directory,
/// - the file hashes are checked, for both newly downloaded and previously cached files,
/// - the parameters are loaded into Zebra.
///
/// # Panics
///
/// If the downloaded or pre-existing parameter files are invalid.
pub static ref GROTH16_PARAMETERS: Groth16Parameters = Groth16Parameters::new();
}
/// Groth16 Zero-Knowledge Proof parameters for the Sapling and Sprout circuits.
pub struct Groth16Parameters {
/// The Sapling circuit Groth16 parameters.
pub sapling: SaplingParameters,
/// The Sprout circuit Groth16 spend parameter.
pub sprout: SproutParameters,
}
/// Groth16 Zero-Knowledge Proof spend and output parameters for the Sapling circuit.
pub struct SaplingParameters {
pub spend: groth16::Parameters<Bls12>,
pub spend_prepared_verifying_key: groth16::PreparedVerifyingKey<Bls12>,
pub output: groth16::Parameters<Bls12>,
pub output_prepared_verifying_key: groth16::PreparedVerifyingKey<Bls12>,
}
/// Groth16 Zero-Knowledge Proof spend parameters for the Sprout circuit.
///
/// New Sprout outputs were disabled by the Canopy network upgrade.
pub struct SproutParameters {
pub joinsplit_prepared_verifying_key: groth16::PreparedVerifyingKey<Bls12>,
}
impl Groth16Parameters {
/// Download if needed, cache, check, and load the Sprout and Sapling Groth16 parameters.
///
/// # Panics
///
/// If the parameters were downloaded to the wrong path.
/// After `PARAMETER_DOWNLOAD_MAX_RETRIES` failed download attempts.
/// If the downloaded or pre-existing parameter files are invalid.
fn new() -> Groth16Parameters {
let params_directory = Groth16Parameters::directory();
let sapling_spend_path = params_directory.join(zcash_proofs::SAPLING_SPEND_NAME);
let sapling_output_path = params_directory.join(zcash_proofs::SAPLING_OUTPUT_NAME);
let sprout_path = params_directory.join(zcash_proofs::SPROUT_NAME);
Groth16Parameters::retry_download_sapling_parameters(
&sapling_spend_path,
&sapling_output_path,
);
Groth16Parameters::retry_download_sprout_parameters(&sprout_path);
// TODO: if loading fails, log a message including `failure_hint`
tracing::info!("checking and loading Zcash Sapling and Sprout parameters");
let parameters = zcash_proofs::load_parameters(
&sapling_spend_path,
&sapling_output_path,
Some(&sprout_path),
);
let sapling = SaplingParameters {
spend: parameters.spend_params,
spend_prepared_verifying_key: parameters.spend_vk,
output: parameters.output_params,
output_prepared_verifying_key: parameters.output_vk,
};
let sprout = SproutParameters {
joinsplit_prepared_verifying_key: parameters
.sprout_vk
.expect("unreachable code: sprout loader panics on failure"),
};
Groth16Parameters { sapling, sprout }
}
/// Returns the path to the Groth16 parameters directory.
pub fn directory() -> PathBuf {
zcash_proofs::default_params_folder().expect("unable to find user home directory")
}
/// Returns a hint that helps users recover from parameter download failures.
pub fn failure_hint() -> String {
format!(
"Hint: try deleting {:?}, then running 'zebrad download' to re-download the parameters",
Groth16Parameters::directory(),
)
}
/// Download Sapling parameters and retry [`PARAMETER_DOWNLOAD_MAX_RETRIES`] if it fails.
///
/// # Panics
///
/// If the parameters were downloaded to the wrong path.
/// After `PARAMETER_DOWNLOAD_MAX_RETRIES` failed download attempts.
fn retry_download_sapling_parameters(sapling_spend_path: &Path, sapling_output_path: &Path) {
// TODO: instead of the path check, add a zcash_proofs argument to skip hashing existing files
// (we check them on load anyway)
if !sapling_spend_path.exists() || !sapling_output_path.exists() {
tracing::info!("downloading Zcash Sapling parameters");
let mut retries = 0;
while let Err(error) = Groth16Parameters::download_sapling_parameters_once(
sapling_spend_path,
sapling_output_path,
) {
retries += 1;
if retries >= PARAMETER_DOWNLOAD_MAX_RETRIES {
panic!(
"error downloading Sapling parameter files after {} retries. {:?} {}",
PARAMETER_DOWNLOAD_MAX_RETRIES,
error,
Groth16Parameters::failure_hint(),
);
} else {
tracing::info!(
?error,
"error downloading Zcash Sapling parameters, retrying"
);
}
}
}
}
/// Try to download the Sapling parameters once, and return the result.
///
/// # Panics
///
/// If the parameters were downloaded to different paths to `sapling_spend_path`
/// or `sapling_output_path`.
fn download_sapling_parameters_once(
sapling_spend_path: &Path,
sapling_output_path: &Path,
) -> Result<SaplingParameterPaths, BoxError> {
let new_sapling_paths =
zcash_proofs::download_sapling_parameters(Some(PARAMETER_DOWNLOAD_TIMEOUT))?;
assert_eq!(sapling_spend_path, new_sapling_paths.spend);
assert_eq!(sapling_output_path, new_sapling_paths.output);
Ok(new_sapling_paths)
}
/// Download Sprout parameters and retry [`PARAMETER_DOWNLOAD_MAX_RETRIES`] if it fails.
///
/// # Panics
///
/// If the parameters were downloaded to the wrong path.
/// After `PARAMETER_DOWNLOAD_MAX_RETRIES` failed download attempts.
fn retry_download_sprout_parameters(sprout_path: &Path) {
if !sprout_path.exists() {
tracing::info!("downloading Zcash Sprout parameters");
let mut retries = 0;
while let Err(error) = Groth16Parameters::download_sprout_parameters_once(sprout_path) {
retries += 1;
if retries >= PARAMETER_DOWNLOAD_MAX_RETRIES {
panic!(
"error downloading Sprout parameter files after {} retries. {:?} {}",
PARAMETER_DOWNLOAD_MAX_RETRIES,
error,
Groth16Parameters::failure_hint(),
);
} else {
tracing::info!(
?error,
"error downloading Zcash Sprout parameters, retrying"
);
}
}
}
}
/// Try to download the Sprout parameters once, and return the result.
///
/// # Panics
///
/// If the parameters were downloaded to a different path to `sprout_path`.
fn download_sprout_parameters_once(sprout_path: &Path) -> Result<PathBuf, BoxError> {
let new_sprout_path =
zcash_proofs::download_sprout_parameters(Some(PARAMETER_DOWNLOAD_TIMEOUT))?;
assert_eq!(sprout_path, new_sprout_path);
Ok(new_sprout_path)
}
}