darkfi/zk/
tracer.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::sync::{Arc, Mutex};
20
21use darkfi_sdk::{crypto::constants::OrchardFixedBases, pasta::pallas};
22use halo2_gadgets::ecc as ecc_gadget;
23use halo2_proofs::{arithmetic::Field, circuit::AssignedCell};
24
25#[derive(Clone, Debug)]
26pub enum DebugOpValue {
27    EcPoint(pallas::Base, pallas::Base),
28    Base(pallas::Base),
29    Void,
30}
31
32#[derive(Clone, Debug)]
33pub struct ZkTracer {
34    pub opvalues: Arc<Mutex<Option<Vec<DebugOpValue>>>>,
35    init_allowed: bool,
36    is_enabled: bool,
37}
38
39impl ZkTracer {
40    pub(crate) fn new(init_allowed: bool) -> Self {
41        Self { opvalues: Arc::new(Mutex::new(None)), init_allowed, is_enabled: false }
42    }
43
44    pub(crate) fn init(&mut self) {
45        if !self.init_allowed {
46            panic!("Cannot initialize tracer for verifier circuit!");
47        }
48        self.is_enabled = true;
49        *self.opvalues.lock().unwrap() = Some(Vec::new());
50    }
51
52    pub(crate) fn clear(&self) {
53        if !self.is_enabled {
54            return
55        }
56
57        self.opvalues.lock().unwrap().as_mut().unwrap().clear();
58    }
59
60    fn push(&self, value: DebugOpValue) {
61        self.opvalues.lock().unwrap().as_mut().unwrap().push(value);
62    }
63
64    pub(crate) fn push_ecpoint(
65        &self,
66        point: &ecc_gadget::Point<pallas::Affine, ecc_gadget::chip::EccChip<OrchardFixedBases>>,
67    ) {
68        if !self.is_enabled {
69            return
70        }
71
72        let (mut x, mut y) = (pallas::Base::ZERO, pallas::Base::ZERO);
73        point.inner().x().value().map(|rx| x = *rx);
74        point.inner().y().value().map(|ry| y = *ry);
75        self.push(DebugOpValue::EcPoint(x, y));
76    }
77
78    pub(crate) fn push_base(&self, value: &AssignedCell<pallas::Base, pallas::Base>) {
79        if !self.is_enabled {
80            return
81        }
82
83        let mut x = pallas::Base::ZERO;
84        value.value().map(|rx| x = *rx);
85        self.push(DebugOpValue::Base(x));
86    }
87
88    pub(crate) fn push_void(&self) {
89        if !self.is_enabled {
90            return
91        }
92
93        self.push(DebugOpValue::Void);
94    }
95
96    pub(crate) fn assert_correct(&self, opcodes_len: usize) {
97        if !self.is_enabled {
98            return
99        }
100
101        let opvalues_len = self.opvalues.lock().unwrap().as_ref().map_or(0, |v| v.len());
102        assert_eq!(opvalues_len, opcodes_len);
103    }
104}