zebra_consensus/primitives/groth16/params/
parse_parameters.rs
1use std::{
8 fmt::Write,
9 io::{self, Read},
10};
11
12use bellman::groth16;
13use blake2b_simd::State;
14use bls12_381::Bls12;
15use zcash_proofs::{SAPLING_OUTPUT_NAME, SAPLING_SPEND_NAME};
16
17use super::SaplingParameters;
18
19const SAPLING_SPEND_HASH: &str = "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c";
23const SAPLING_OUTPUT_HASH: &str = "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028";
24
25const SAPLING_SPEND_BYTES: u64 = 47958396;
27const SAPLING_OUTPUT_BYTES: u64 = 3592860;
28
29pub fn parse_sapling_parameters<R: io::Read>(spend_fs: R, output_fs: R) -> SaplingParameters {
35 let mut spend_fs = HashReader::new(spend_fs);
36 let mut output_fs = HashReader::new(output_fs);
37
38 let spend_params = groth16::Parameters::<Bls12>::read(&mut spend_fs, false)
40 .expect("couldn't deserialize Sapling spend parameters");
41 let output_params = groth16::Parameters::<Bls12>::read(&mut output_fs, false)
42 .expect("couldn't deserialize Sapling spend parameters");
43
44 let mut sink = io::sink();
49
50 verify_hash(
53 spend_fs,
54 &mut sink,
55 SAPLING_SPEND_HASH,
56 SAPLING_SPEND_BYTES,
57 SAPLING_SPEND_NAME,
58 "a file",
59 )
60 .expect(
61 "Sapling spend parameter file is not correct, \
62 please clean your `~/.zcash-params/` and re-run `fetch-params`.",
63 );
64
65 verify_hash(
66 output_fs,
67 &mut sink,
68 SAPLING_OUTPUT_HASH,
69 SAPLING_OUTPUT_BYTES,
70 SAPLING_OUTPUT_NAME,
71 "a file",
72 )
73 .expect(
74 "Sapling output parameter file is not correct, \
75 please clean your `~/.zcash-params/` and re-run `fetch-params`.",
76 );
77
78 let spend_vk = groth16::prepare_verifying_key(&spend_params.vk);
80 let output_vk = groth16::prepare_verifying_key(&output_params.vk);
81
82 SaplingParameters {
83 spend: spend_params,
84 spend_prepared_verifying_key: spend_vk,
85 output: output_params,
86 output_prepared_verifying_key: output_vk,
87 }
88}
89
90pub struct HashReader<R: Read> {
92 reader: R,
93 hasher: State,
94 byte_count: u64,
95}
96
97impl<R: Read> HashReader<R> {
98 pub fn new(reader: R) -> Self {
100 HashReader {
101 reader,
102 hasher: State::new(),
103 byte_count: 0,
104 }
105 }
106
107 pub fn into_hash(self) -> String {
109 let hash = self.hasher.finalize();
110
111 let mut s = String::new();
112 for c in hash.as_bytes().iter() {
113 write!(&mut s, "{:02x}", c).expect("writing to a string never fails");
114 }
115
116 s
117 }
118
119 pub fn byte_count(&self) -> u64 {
121 self.byte_count
122 }
123}
124
125impl<R: Read> Read for HashReader<R> {
126 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
127 let bytes = self.reader.read(buf)?;
128
129 if bytes > 0 {
130 self.hasher.update(&buf[0..bytes]);
131 let byte_count = u64::try_from(bytes).map_err(|_| {
132 io::Error::new(
133 io::ErrorKind::InvalidData,
134 "Could not fit the number of read bytes into u64.",
135 )
136 })?;
137 self.byte_count += byte_count;
138 }
139
140 Ok(bytes)
141 }
142}
143
144fn verify_hash<R: io::Read, W: io::Write>(
152 mut hash_reader: HashReader<R>,
153 mut sink: W,
154 expected_hash: &str,
155 expected_bytes: u64,
156 name: &str,
157 params_source: &str,
158) -> Result<(), io::Error> {
159 let read_result = io::copy(&mut hash_reader, &mut sink);
160
161 if let Err(read_error) = read_result {
162 return Err(io::Error::new(
163 read_error.kind(),
164 format!(
165 "{} failed reading:\n\
166 expected: {} bytes,\n\
167 actual: {} bytes from {:?},\n\
168 error: {:?}",
169 name,
170 expected_bytes,
171 hash_reader.byte_count(),
172 params_source,
173 read_error,
174 ),
175 ));
176 }
177
178 let byte_count = hash_reader.byte_count();
179 let hash = hash_reader.into_hash();
180 if hash != expected_hash {
181 return Err(io::Error::new(
182 io::ErrorKind::InvalidData,
183 format!(
184 "{} failed validation:\n\
185 expected: {} hashing {} bytes,\n\
186 actual: {} hashing {} bytes from {:?}",
187 name, expected_hash, expected_bytes, hash, byte_count, params_source,
188 ),
189 ));
190 }
191
192 Ok(())
193}