darkfi/zk/
vm_heap.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
19//! VM heap type abstractions
20use darkfi_sdk::crypto::{
21    constants::{OrchardFixedBases, MERKLE_DEPTH_ORCHARD},
22    smt::SMT_FP_DEPTH,
23    MerkleNode,
24};
25use halo2_gadgets::ecc::{
26    chip::EccChip, FixedPoint, FixedPointBaseField, FixedPointShort, NonIdentityPoint, Point,
27    ScalarFixed,
28};
29use halo2_proofs::{
30    circuit::{AssignedCell, Value},
31    pasta::pallas,
32    plonk,
33};
34use tracing::error;
35
36use crate::{
37    zkas::{decoder::ZkBinary, types::VarType},
38    Error::ZkasDecoderError,
39    Result,
40};
41
42/// These represent the witness types outside of the circuit
43#[allow(clippy::large_enum_variant)]
44#[derive(Clone, Debug)]
45pub enum Witness {
46    EcPoint(Value<pallas::Point>),
47    EcNiPoint(Value<pallas::Point>),
48    EcFixedPoint(Value<pallas::Point>),
49    Base(Value<pallas::Base>),
50    Scalar(Value<pallas::Scalar>),
51    MerklePath(Value<[MerkleNode; MERKLE_DEPTH_ORCHARD]>),
52    SparseMerklePath(Value<[pallas::Base; SMT_FP_DEPTH]>),
53    Uint32(Value<u32>),
54    Uint64(Value<u64>),
55}
56
57impl Witness {
58    pub fn name(&self) -> &str {
59        match self {
60            Self::EcPoint(_) => "EcPoint",
61            Self::EcNiPoint(_) => "EcNiPoint",
62            Self::EcFixedPoint(_) => "EcFixedPoint",
63            Self::Base(_) => "Base",
64            Self::Scalar(_) => "Scalar",
65            Self::MerklePath(_) => "MerklePath",
66            Self::SparseMerklePath(_) => "SparseMerklePath",
67            Self::Uint32(_) => "Uint32",
68            Self::Uint64(_) => "Uint64",
69        }
70    }
71}
72
73/// Helper function for verifiers to generate empty witnesses for
74/// a given decoded zkas binary
75pub fn empty_witnesses(zkbin: &ZkBinary) -> Result<Vec<Witness>> {
76    let mut ret = Vec::with_capacity(zkbin.witnesses.len());
77
78    for witness in &zkbin.witnesses {
79        match witness {
80            VarType::EcPoint => ret.push(Witness::EcPoint(Value::unknown())),
81            VarType::EcNiPoint => ret.push(Witness::EcNiPoint(Value::unknown())),
82            VarType::EcFixedPoint => ret.push(Witness::EcFixedPoint(Value::unknown())),
83            VarType::Base => ret.push(Witness::Base(Value::unknown())),
84            VarType::Scalar => ret.push(Witness::Scalar(Value::unknown())),
85            VarType::MerklePath => ret.push(Witness::MerklePath(Value::unknown())),
86            VarType::SparseMerklePath => ret.push(Witness::SparseMerklePath(Value::unknown())),
87            VarType::Uint32 => ret.push(Witness::Uint32(Value::unknown())),
88            VarType::Uint64 => ret.push(Witness::Uint64(Value::unknown())),
89            x => return Err(ZkasDecoderError(format!("Unsupported witness type: {x:?}"))),
90        }
91    }
92
93    Ok(ret)
94}
95
96/// These represent the witness types inside the circuit
97#[allow(clippy::large_enum_variant)]
98#[derive(Debug, Clone)]
99pub enum HeapVar {
100    EcPoint(Point<pallas::Affine, EccChip<OrchardFixedBases>>),
101    EcNiPoint(NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
102    EcFixedPoint(FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
103    EcFixedPointShort(FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>>),
104    EcFixedPointBase(FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>>),
105    Base(AssignedCell<pallas::Base, pallas::Base>),
106    Scalar(ScalarFixed<pallas::Affine, EccChip<OrchardFixedBases>>),
107    MerklePath(Value<[pallas::Base; MERKLE_DEPTH_ORCHARD]>),
108    SparseMerklePath(Value<[pallas::Base; SMT_FP_DEPTH]>),
109    Uint32(Value<u32>),
110    Uint64(Value<u64>),
111}
112
113macro_rules! impl_try_from {
114    ($variant:ident, $fortype:ty) => {
115        impl std::convert::TryFrom<HeapVar> for $fortype {
116            type Error = plonk::Error;
117
118            fn try_from(value: HeapVar) -> std::result::Result<Self, Self::Error> {
119                match value {
120                    HeapVar::$variant(v) => Ok(v),
121                    x => {
122                        error!("Expected {}, but instead got: {x:?}", stringify!($variant));
123                        Err(plonk::Error::Synthesis)
124                    }
125                }
126            }
127        }
128    };
129}
130
131impl_try_from!(EcPoint, Point<pallas::Affine, EccChip<OrchardFixedBases>>);
132impl_try_from!(EcNiPoint, NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>>);
133impl_try_from!(EcFixedPoint, FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>);
134impl_try_from!(EcFixedPointShort, FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>>);
135impl_try_from!(EcFixedPointBase, FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>>);
136impl_try_from!(Scalar, ScalarFixed<pallas::Affine, EccChip<OrchardFixedBases>>);
137impl_try_from!(Base, AssignedCell<pallas::Base, pallas::Base>);
138impl_try_from!(Uint32, Value<u32>);
139impl_try_from!(MerklePath, Value<[pallas::Base; MERKLE_DEPTH_ORCHARD]>);
140impl_try_from!(SparseMerklePath, Value<[pallas::Base; SMT_FP_DEPTH]>);