1use std::{collections::HashMap, path::Path, sync::Arc};
2
3use kimchi::circuits::gate::CircuitGate;
4use mina_curves::pasta::{Fp, Fq};
5use once_cell::sync::OnceCell;
6use openmina_core::network::CircuitsConfig;
7
8use super::{
9 circuit_blobs,
10 constants::{
11 StepBlockProof, StepMergeProof, StepTransactionProof, StepZkappOptSignedOptSignedProof,
12 StepZkappOptSignedProof, StepZkappProvedProof, WrapBlockProof, WrapTransactionProof,
13 },
14 field::FieldWitness,
15 transaction::{make_prover_index, InternalVars, Prover, V},
16 verifiers::{BlockVerifier, TransactionVerifier},
17};
18
19use mina_p2p_messages::binprot::{
20 self,
21 macros::{BinProtRead, BinProtWrite},
22};
23
24pub fn devnet_circuit_directory() -> &'static str {
25 openmina_core::network::devnet::CIRCUITS_CONFIG.directory_name
26}
27
28fn decode_gates_file<F: FieldWitness>(
39 reader: impl std::io::Read,
40) -> std::io::Result<Vec<CircuitGate<F>>> {
41 #[serde_with::serde_as]
42 #[derive(serde::Deserialize)]
43 struct GatesFile<F: ark_ff::PrimeField> {
44 public_input_size: usize,
45 #[serde_as(as = "Vec<_>")]
46 gates: Vec<CircuitGate<F>>,
47 }
48 let data: GatesFile<F> = serde_json::from_reader(reader)?;
49 Ok(data.gates)
50}
51
52fn read_gates_file<F: FieldWitness>(
53 filename: &impl AsRef<Path>,
54) -> std::io::Result<Vec<CircuitGate<F>>> {
55 let bytes = circuit_blobs::fetch_blocking(filename)?;
56 decode_gates_file(bytes.as_slice())
57}
58
59fn make_gates<F: FieldWitness>(
60 filename: &str,
61) -> (
62 HashMap<usize, (Vec<(F, V)>, Option<F>)>,
63 Vec<Vec<Option<V>>>,
64 Vec<CircuitGate<F>>,
65) {
66 let circuits_config = openmina_core::NetworkConfig::global().circuits_config;
67 let base_dir = Path::new(&circuits_config.directory_name);
68
69 let internal_vars_path = base_dir.join(format!("{}_internal_vars.bin", filename));
70 let rows_rev_path = base_dir.join(format!("{}_rows_rev.bin", filename));
71 let gates_path = base_dir.join(format!("{}_gates.json", filename));
72
73 let gates: Vec<CircuitGate<F>> = read_gates_file(&gates_path).unwrap();
74 let (internal_vars_path, rows_rev_path) =
75 read_constraints_data::<F>(&internal_vars_path, &rows_rev_path).unwrap();
76
77 (internal_vars_path, rows_rev_path, gates)
78}
79
80macro_rules! get_or_make {
81 ($constant: ident, $type: ty, $filename: expr) => {{
82 get_or_make!($constant, $type, None, $filename)
83 }};
84 ($constant: ident, $type: ty, $verifier_index: expr, $filename: expr) => {{
85 if let Some(prover) = $constant.get() {
86 return prover.clone();
87 }
88
89 let (internal_vars, rows_rev, gates) = make_gates($filename);
90
91 let index = make_prover_index::<$type, _>(gates, $verifier_index);
92 let prover = Prover {
93 internal_vars,
94 rows_rev,
95 index,
96 };
97
98 $constant.get_or_init(|| prover.into()).clone()
99 }};
100}
101
102static TX_STEP_PROVER: OnceCell<Arc<Prover<Fp>>> = OnceCell::new();
103static TX_WRAP_PROVER: OnceCell<Arc<Prover<Fq>>> = OnceCell::new();
104static MERGE_STEP_PROVER: OnceCell<Arc<Prover<Fp>>> = OnceCell::new();
105static BLOCK_STEP_PROVER: OnceCell<Arc<Prover<Fp>>> = OnceCell::new();
106static BLOCK_WRAP_PROVER: OnceCell<Arc<Prover<Fq>>> = OnceCell::new();
107static ZKAPP_STEP_OPT_SIGNED_OPT_SIGNED_PROVER: OnceCell<Arc<Prover<Fp>>> = OnceCell::new();
108static ZKAPP_STEP_OPT_SIGNED_PROVER: OnceCell<Arc<Prover<Fp>>> = OnceCell::new();
109static ZKAPP_STEP_PROOF_PROVER: OnceCell<Arc<Prover<Fp>>> = OnceCell::new();
110
111fn default_circuits_config() -> &'static CircuitsConfig {
112 openmina_core::NetworkConfig::global().circuits_config
113}
114
115mod prover_makers {
116 use super::*;
117
118 fn get_or_make_tx_step_prover(config: &CircuitsConfig) -> Arc<Prover<Fp>> {
119 get_or_make!(
120 TX_STEP_PROVER,
121 StepTransactionProof,
122 config.step_transaction_gates
123 )
124 }
125 fn get_or_make_tx_wrap_prover(
126 config: &CircuitsConfig,
127 verifier_index: Option<TransactionVerifier>,
128 ) -> Arc<Prover<Fq>> {
129 get_or_make!(
130 TX_WRAP_PROVER,
131 WrapTransactionProof,
132 verifier_index.map(Into::into),
133 config.wrap_transaction_gates
134 )
135 }
136 fn get_or_make_merge_step_prover(config: &CircuitsConfig) -> Arc<Prover<Fp>> {
137 get_or_make!(MERGE_STEP_PROVER, StepMergeProof, config.step_merge_gates)
138 }
139 fn get_or_make_block_step_prover(config: &CircuitsConfig) -> Arc<Prover<Fp>> {
140 get_or_make!(
141 BLOCK_STEP_PROVER,
142 StepBlockProof,
143 config.step_blockchain_gates
144 )
145 }
146 fn get_or_make_block_wrap_prover(
147 config: &CircuitsConfig,
148 verifier_index: Option<BlockVerifier>,
149 ) -> Arc<Prover<Fq>> {
150 get_or_make!(
151 BLOCK_WRAP_PROVER,
152 WrapBlockProof,
153 verifier_index.map(Into::into),
154 config.wrap_blockchain_gates
155 )
156 }
157 fn get_or_make_zkapp_step_opt_signed_opt_signed_prover(
158 config: &CircuitsConfig,
159 ) -> Arc<Prover<Fp>> {
160 get_or_make!(
161 ZKAPP_STEP_OPT_SIGNED_OPT_SIGNED_PROVER,
162 StepZkappOptSignedOptSignedProof,
163 config.step_transaction_opt_signed_opt_signed_gates
164 )
165 }
166 fn get_or_make_zkapp_step_opt_signed_prover(config: &CircuitsConfig) -> Arc<Prover<Fp>> {
167 get_or_make!(
168 ZKAPP_STEP_OPT_SIGNED_PROVER,
169 StepZkappOptSignedProof,
170 config.step_transaction_opt_signed_gates
171 )
172 }
173 fn get_or_make_zkapp_step_proof_prover(config: &CircuitsConfig) -> Arc<Prover<Fp>> {
174 get_or_make!(
175 ZKAPP_STEP_PROOF_PROVER,
176 StepZkappProvedProof,
177 config.step_transaction_proved_gates
178 )
179 }
180
181 impl BlockProver {
182 pub fn make(
183 block_verifier_index: Option<BlockVerifier>,
184 tx_verifier_index: Option<TransactionVerifier>,
185 ) -> Self {
186 let config = default_circuits_config();
187 let block_step_prover = get_or_make_block_step_prover(config);
188 let block_wrap_prover = get_or_make_block_wrap_prover(config, block_verifier_index);
189 let tx_wrap_prover = get_or_make_tx_wrap_prover(config, tx_verifier_index);
190
191 Self {
192 block_step_prover,
193 block_wrap_prover,
194 tx_wrap_prover,
195 }
196 }
197 }
198
199 impl TransactionProver {
200 pub fn make(tx_verifier_index: Option<TransactionVerifier>) -> Self {
201 let config = default_circuits_config();
202 let tx_step_prover = get_or_make_tx_step_prover(config);
203 let tx_wrap_prover = get_or_make_tx_wrap_prover(config, tx_verifier_index);
204 let merge_step_prover = get_or_make_merge_step_prover(config);
205
206 Self {
207 tx_step_prover,
208 tx_wrap_prover,
209 merge_step_prover,
210 }
211 }
212 }
213
214 impl ZkappProver {
215 pub fn make(tx_verifier_index: Option<TransactionVerifier>) -> Self {
216 let config = default_circuits_config();
217 let tx_wrap_prover = get_or_make_tx_wrap_prover(config, tx_verifier_index);
218 let merge_step_prover = get_or_make_merge_step_prover(config);
219 let step_opt_signed_opt_signed_prover =
220 get_or_make_zkapp_step_opt_signed_opt_signed_prover(config);
221 let step_opt_signed_prover = get_or_make_zkapp_step_opt_signed_prover(config);
222 let step_proof_prover = get_or_make_zkapp_step_proof_prover(config);
223
224 Self {
225 tx_wrap_prover,
226 merge_step_prover,
227 step_opt_signed_opt_signed_prover,
228 step_opt_signed_prover,
229 step_proof_prover,
230 }
231 }
232 }
233}
234
235#[derive(Clone)]
236pub struct BlockProver {
237 pub block_step_prover: Arc<Prover<Fp>>,
238 pub block_wrap_prover: Arc<Prover<Fq>>,
239 pub tx_wrap_prover: Arc<Prover<Fq>>,
240}
241
242#[derive(Clone)]
243pub struct TransactionProver {
244 pub tx_step_prover: Arc<Prover<Fp>>,
245 pub tx_wrap_prover: Arc<Prover<Fq>>,
246 pub merge_step_prover: Arc<Prover<Fp>>,
247}
248
249#[derive(Clone)]
250pub struct ZkappProver {
251 pub tx_wrap_prover: Arc<Prover<Fq>>,
252 pub merge_step_prover: Arc<Prover<Fp>>,
253 pub step_opt_signed_opt_signed_prover: Arc<Prover<Fp>>,
254 pub step_opt_signed_prover: Arc<Prover<Fp>>,
255 pub step_proof_prover: Arc<Prover<Fp>>,
256}
257
258impl BlockProver {
259 pub fn get_once_made() -> Self {
262 Self {
263 block_step_prover: BLOCK_STEP_PROVER.wait().clone(),
264 block_wrap_prover: BLOCK_WRAP_PROVER.wait().clone(),
265 tx_wrap_prover: TX_WRAP_PROVER.wait().clone(),
266 }
267 }
268}
269
270fn decode_constraints_data<F: FieldWitness>(
271 mut internal_vars: &[u8],
272 mut rows_rev: &[u8],
273) -> Option<(InternalVars<F>, Vec<Vec<Option<V>>>)> {
274 use mina_p2p_messages::bigint::BigInt;
275
276 impl From<&VRaw> for V {
277 fn from(value: &VRaw) -> Self {
278 match value {
279 VRaw::External(index) => Self::External(*index as usize),
280 VRaw::Internal(id) => Self::Internal(*id as usize),
281 }
282 }
283 }
284
285 #[derive(Clone, Debug, PartialEq, BinProtRead, BinProtWrite)]
286 enum VRaw {
287 External(u32),
288 Internal(u32),
289 }
290
291 use binprot::BinProtRead;
292
293 type InternalVarsRaw = HashMap<u32, (Vec<(BigInt, VRaw)>, Option<BigInt>)>;
294
295 let internal_vars: InternalVarsRaw = HashMap::binprot_read(&mut internal_vars).unwrap();
296 let rows_rev: Vec<Vec<Option<VRaw>>> = Vec::binprot_read(&mut rows_rev).unwrap();
297
298 let internal_vars: InternalVars<F> = internal_vars
299 .into_iter()
300 .map(|(id, (list, opt))| {
301 let id = id as usize;
302 let list: Vec<_> = list
303 .iter()
304 .map(|(n, v)| (n.to_field::<F>().unwrap(), V::from(v)))
305 .collect();
306 let opt = opt.as_ref().map(|v| BigInt::to_field::<F>(v).unwrap());
307 (id, (list, opt))
308 })
309 .collect();
310
311 let rows_rev: Vec<_> = rows_rev
312 .iter()
313 .map(|row| {
314 let row: Vec<_> = row.iter().map(|v| v.as_ref().map(V::from)).collect();
315 row
316 })
317 .collect();
318
319 Some((internal_vars, rows_rev))
320}
321
322fn read_constraints_data<F: FieldWitness>(
323 internal_vars_path: &Path,
324 rows_rev_path: &Path,
325) -> Option<(InternalVars<F>, Vec<Vec<Option<V>>>)> {
326 let internal_vars = circuit_blobs::fetch_blocking(&internal_vars_path).ok()?;
328
329 let rows_rev = circuit_blobs::fetch_blocking(&rows_rev_path).ok()?;
331
332 decode_constraints_data(internal_vars.as_slice(), rows_rev.as_slice())
333}