mina_tree/proofs/
provers.rs

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
28// TODO(tizoc): right now all tests are for devnets, and the above
29// function is used for those tests.
30// pub fn mainnet_circuit_directory() -> &'static str {
31//     openmina_core::network::devnet::CIRCUITS_CONFIG.directory_name
32// }
33//
34// pub fn circuit_directory() -> &'static str {
35//     openmina_core::NetworkConfig::global().circuits_config.directory_name
36// }
37
38fn 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    /// Called must make sure that before calling this,
260    /// `BlockProver::make` call was made.
261    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    // ((Fp.t * V.t) list * Fp.t option)
327    let internal_vars = circuit_blobs::fetch_blocking(&internal_vars_path).ok()?;
328
329    // V.t option array list
330    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}