snarkvm_circuit_environment/helpers/
variable.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::{LinearCombination, Mode};
17use snarkvm_fields::traits::*;
18
19use core::{
20    cmp::Ordering,
21    fmt,
22    ops::{Add, Sub},
23};
24use std::sync::Arc;
25
26pub type Index = u64;
27
28#[derive(Clone, PartialEq, Eq, Hash)]
29pub enum Variable<F: PrimeField> {
30    Constant(Arc<F>),
31    Public(Arc<(Index, F)>),
32    Private(Arc<(Index, F)>),
33}
34
35impl<F: PrimeField> Variable<F> {
36    ///
37    /// Returns `true` if the variable is a constant.
38    ///
39    pub fn is_constant(&self) -> bool {
40        matches!(self, Self::Constant(..))
41    }
42
43    ///
44    /// Returns `true` if the variable is public.
45    ///
46    pub fn is_public(&self) -> bool {
47        matches!(self, Self::Public(..))
48    }
49
50    ///
51    /// Returns `true` if the variable is private.
52    ///
53    pub fn is_private(&self) -> bool {
54        matches!(self, Self::Private(..))
55    }
56
57    ///
58    /// Returns the mode of the variable.
59    ///
60    pub fn mode(&self) -> Mode {
61        match self {
62            Self::Constant(..) => Mode::Constant,
63            Self::Public(..) => Mode::Public,
64            Self::Private(..) => Mode::Private,
65        }
66    }
67
68    ///
69    /// Returns the relative index of the variable.
70    ///
71    pub fn index(&self) -> Index {
72        match self {
73            Self::Constant(..) => 0,
74            Self::Public(index_value) | Self::Private(index_value) => {
75                let (index, _value) = index_value.as_ref();
76                *index
77            }
78        }
79    }
80
81    ///
82    /// Returns the value of the variable.
83    ///
84    pub fn value(&self) -> F {
85        match self {
86            Self::Constant(value) => **value,
87            Self::Public(index_value) | Self::Private(index_value) => {
88                let (_index, value) = index_value.as_ref();
89                *value
90            }
91        }
92    }
93
94    ///
95    /// Returns the relative index and value of the variable.
96    ///
97    pub fn index_value(&self) -> (Index, F) {
98        match self {
99            Self::Constant(value) => (0, **value),
100            Self::Public(index_value) | Self::Private(index_value) => {
101                let (index, value) = index_value.as_ref();
102                (*index, *value)
103            }
104        }
105    }
106}
107
108impl<F: PrimeField> PartialOrd for Variable<F> {
109    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
110        Some(self.cmp(other))
111    }
112}
113
114impl<F: PrimeField> Ord for Variable<F> {
115    fn cmp(&self, other: &Self) -> Ordering {
116        match (self, other) {
117            (Self::Constant(v1), Self::Constant(v2)) => v1.cmp(v2),
118            (Self::Constant(..), Self::Public(..)) => Ordering::Less,
119            (Self::Constant(..), Self::Private(..)) => Ordering::Less,
120            (Self::Public(..), Self::Constant(..)) => Ordering::Greater,
121            (Self::Private(..), Self::Constant(..)) => Ordering::Greater,
122            (Self::Public(i1, ..), Self::Public(i2, ..)) => i1.cmp(i2),
123            (Self::Private(i1, ..), Self::Private(i2, ..)) => i1.cmp(i2),
124            (Self::Public(..), Self::Private(..)) => Ordering::Less,
125            (Self::Private(..), Self::Public(..)) => Ordering::Greater,
126        }
127    }
128}
129
130#[allow(clippy::op_ref)]
131impl<F: PrimeField> Add<Variable<F>> for Variable<F> {
132    type Output = LinearCombination<F>;
133
134    fn add(self, other: Variable<F>) -> Self::Output {
135        self + &other
136    }
137}
138
139#[allow(clippy::op_ref)]
140impl<F: PrimeField> Add<Variable<F>> for &Variable<F> {
141    type Output = LinearCombination<F>;
142
143    fn add(self, other: Variable<F>) -> Self::Output {
144        self + &other
145    }
146}
147
148#[allow(clippy::op_ref)]
149impl<F: PrimeField> Add<&Variable<F>> for Variable<F> {
150    type Output = LinearCombination<F>;
151
152    fn add(self, other: &Variable<F>) -> Self::Output {
153        &self + other
154    }
155}
156
157impl<F: PrimeField> Add<&Variable<F>> for &Variable<F> {
158    type Output = LinearCombination<F>;
159
160    fn add(self, other: &Variable<F>) -> Self::Output {
161        match (self, other) {
162            (Variable::Constant(a), Variable::Constant(b)) => Variable::Constant(Arc::new(**a + **b)).into(),
163            (first, second) => LinearCombination::from([first.clone(), second.clone()]),
164        }
165    }
166}
167
168#[allow(clippy::op_ref)]
169impl<F: PrimeField> Add<LinearCombination<F>> for Variable<F> {
170    type Output = LinearCombination<F>;
171
172    fn add(self, other: LinearCombination<F>) -> Self::Output {
173        self + &other
174    }
175}
176
177#[allow(clippy::op_ref)]
178impl<F: PrimeField> Add<LinearCombination<F>> for &Variable<F> {
179    type Output = LinearCombination<F>;
180
181    fn add(self, other: LinearCombination<F>) -> Self::Output {
182        self + &other
183    }
184}
185
186#[allow(clippy::op_ref)]
187impl<F: PrimeField> Add<&LinearCombination<F>> for Variable<F> {
188    type Output = LinearCombination<F>;
189
190    fn add(self, other: &LinearCombination<F>) -> Self::Output {
191        &self + other
192    }
193}
194
195impl<F: PrimeField> Add<&LinearCombination<F>> for &Variable<F> {
196    type Output = LinearCombination<F>;
197
198    fn add(self, other: &LinearCombination<F>) -> Self::Output {
199        LinearCombination::from(self) + other
200    }
201}
202
203#[allow(clippy::op_ref)]
204impl<F: PrimeField> Sub<Variable<F>> for Variable<F> {
205    type Output = LinearCombination<F>;
206
207    fn sub(self, other: Variable<F>) -> Self::Output {
208        self - &other
209    }
210}
211
212#[allow(clippy::op_ref)]
213impl<F: PrimeField> Sub<Variable<F>> for &Variable<F> {
214    type Output = LinearCombination<F>;
215
216    fn sub(self, other: Variable<F>) -> Self::Output {
217        self - &other
218    }
219}
220
221#[allow(clippy::op_ref)]
222impl<F: PrimeField> Sub<&Variable<F>> for Variable<F> {
223    type Output = LinearCombination<F>;
224
225    fn sub(self, other: &Variable<F>) -> Self::Output {
226        &self - other
227    }
228}
229
230impl<F: PrimeField> Sub<&Variable<F>> for &Variable<F> {
231    type Output = LinearCombination<F>;
232
233    fn sub(self, other: &Variable<F>) -> Self::Output {
234        match (self, other) {
235            (Variable::Constant(a), Variable::Constant(b)) => Variable::Constant(Arc::new(**a - **b)).into(),
236            (first, second) => LinearCombination::from(first) - second,
237        }
238    }
239}
240
241#[allow(clippy::op_ref)]
242impl<F: PrimeField> Sub<LinearCombination<F>> for Variable<F> {
243    type Output = LinearCombination<F>;
244
245    fn sub(self, other: LinearCombination<F>) -> Self::Output {
246        self - &other
247    }
248}
249
250#[allow(clippy::op_ref)]
251impl<F: PrimeField> Sub<LinearCombination<F>> for &Variable<F> {
252    type Output = LinearCombination<F>;
253
254    fn sub(self, other: LinearCombination<F>) -> Self::Output {
255        self - &other
256    }
257}
258
259#[allow(clippy::op_ref)]
260impl<F: PrimeField> Sub<&LinearCombination<F>> for Variable<F> {
261    type Output = LinearCombination<F>;
262
263    fn sub(self, other: &LinearCombination<F>) -> Self::Output {
264        &self - other
265    }
266}
267
268impl<F: PrimeField> Sub<&LinearCombination<F>> for &Variable<F> {
269    type Output = LinearCombination<F>;
270
271    fn sub(self, other: &LinearCombination<F>) -> Self::Output {
272        LinearCombination::from(self) - other
273    }
274}
275
276impl<F: PrimeField> fmt::Debug for Variable<F> {
277    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278        write!(f, "{}", match self {
279            Self::Constant(value) => format!("Constant({value})"),
280            Self::Public(index_value) => {
281                let (index, value) = index_value.as_ref();
282                format!("Public({index}, {value})")
283            }
284            Self::Private(index_value) => {
285                let (index, value) = index_value.as_ref();
286                format!("Private({index}, {value})")
287            }
288        })
289    }
290}
291
292impl<F: PrimeField> fmt::Display for Variable<F> {
293    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294        write!(f, "{}", self.value())
295    }
296}
297
298#[cfg(test)]
299mod tests {
300    use crate::*;
301
302    #[test]
303    fn test_size() {
304        assert_eq!(16, std::mem::size_of::<Variable<<Circuit as Environment>::BaseField>>());
305    }
306}