snarkvm_circuit_environment/helpers/
variable.rs

1// Copyright 2024 Aleo Network Foundation
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::rc::Rc;
25
26pub type Index = u64;
27
28#[derive(Clone, PartialEq, Eq, Hash)]
29pub enum Variable<F: PrimeField> {
30    Constant(Rc<F>),
31    Public(Rc<(Index, F)>),
32    Private(Rc<(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
95impl<F: PrimeField> PartialOrd for Variable<F> {
96    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
97        Some(self.cmp(other))
98    }
99}
100
101impl<F: PrimeField> Ord for Variable<F> {
102    fn cmp(&self, other: &Self) -> Ordering {
103        match (self, other) {
104            (Self::Constant(v1), Self::Constant(v2)) => v1.cmp(v2),
105            (Self::Constant(..), Self::Public(..)) => Ordering::Less,
106            (Self::Constant(..), Self::Private(..)) => Ordering::Less,
107            (Self::Public(..), Self::Constant(..)) => Ordering::Greater,
108            (Self::Private(..), Self::Constant(..)) => Ordering::Greater,
109            (Self::Public(i1, ..), Self::Public(i2, ..)) => i1.cmp(i2),
110            (Self::Private(i1, ..), Self::Private(i2, ..)) => i1.cmp(i2),
111            (Self::Public(..), Self::Private(..)) => Ordering::Less,
112            (Self::Private(..), Self::Public(..)) => Ordering::Greater,
113        }
114    }
115}
116
117#[allow(clippy::op_ref)]
118impl<F: PrimeField> Add<Variable<F>> for Variable<F> {
119    type Output = LinearCombination<F>;
120
121    fn add(self, other: Variable<F>) -> Self::Output {
122        self + &other
123    }
124}
125
126#[allow(clippy::op_ref)]
127impl<F: PrimeField> Add<Variable<F>> for &Variable<F> {
128    type Output = LinearCombination<F>;
129
130    fn add(self, other: Variable<F>) -> Self::Output {
131        self + &other
132    }
133}
134
135#[allow(clippy::op_ref)]
136impl<F: PrimeField> Add<&Variable<F>> for Variable<F> {
137    type Output = LinearCombination<F>;
138
139    fn add(self, other: &Variable<F>) -> Self::Output {
140        &self + other
141    }
142}
143
144impl<F: PrimeField> Add<&Variable<F>> for &Variable<F> {
145    type Output = LinearCombination<F>;
146
147    fn add(self, other: &Variable<F>) -> Self::Output {
148        match (self, other) {
149            (Variable::Constant(a), Variable::Constant(b)) => Variable::Constant(Rc::new(**a + **b)).into(),
150            (first, second) => LinearCombination::from([first.clone(), second.clone()]),
151        }
152    }
153}
154
155#[allow(clippy::op_ref)]
156impl<F: PrimeField> Add<LinearCombination<F>> for Variable<F> {
157    type Output = LinearCombination<F>;
158
159    fn add(self, other: LinearCombination<F>) -> Self::Output {
160        self + &other
161    }
162}
163
164#[allow(clippy::op_ref)]
165impl<F: PrimeField> Add<LinearCombination<F>> for &Variable<F> {
166    type Output = LinearCombination<F>;
167
168    fn add(self, other: LinearCombination<F>) -> Self::Output {
169        self + &other
170    }
171}
172
173#[allow(clippy::op_ref)]
174impl<F: PrimeField> Add<&LinearCombination<F>> for Variable<F> {
175    type Output = LinearCombination<F>;
176
177    fn add(self, other: &LinearCombination<F>) -> Self::Output {
178        &self + other
179    }
180}
181
182impl<F: PrimeField> Add<&LinearCombination<F>> for &Variable<F> {
183    type Output = LinearCombination<F>;
184
185    fn add(self, other: &LinearCombination<F>) -> Self::Output {
186        LinearCombination::from(self) + other
187    }
188}
189
190#[allow(clippy::op_ref)]
191impl<F: PrimeField> Sub<Variable<F>> for Variable<F> {
192    type Output = LinearCombination<F>;
193
194    fn sub(self, other: Variable<F>) -> Self::Output {
195        self - &other
196    }
197}
198
199#[allow(clippy::op_ref)]
200impl<F: PrimeField> Sub<Variable<F>> for &Variable<F> {
201    type Output = LinearCombination<F>;
202
203    fn sub(self, other: Variable<F>) -> Self::Output {
204        self - &other
205    }
206}
207
208#[allow(clippy::op_ref)]
209impl<F: PrimeField> Sub<&Variable<F>> for Variable<F> {
210    type Output = LinearCombination<F>;
211
212    fn sub(self, other: &Variable<F>) -> Self::Output {
213        &self - other
214    }
215}
216
217impl<F: PrimeField> Sub<&Variable<F>> for &Variable<F> {
218    type Output = LinearCombination<F>;
219
220    fn sub(self, other: &Variable<F>) -> Self::Output {
221        match (self, other) {
222            (Variable::Constant(a), Variable::Constant(b)) => Variable::Constant(Rc::new(**a - **b)).into(),
223            (first, second) => LinearCombination::from(first) - second,
224        }
225    }
226}
227
228#[allow(clippy::op_ref)]
229impl<F: PrimeField> Sub<LinearCombination<F>> for Variable<F> {
230    type Output = LinearCombination<F>;
231
232    fn sub(self, other: LinearCombination<F>) -> Self::Output {
233        self - &other
234    }
235}
236
237#[allow(clippy::op_ref)]
238impl<F: PrimeField> Sub<LinearCombination<F>> for &Variable<F> {
239    type Output = LinearCombination<F>;
240
241    fn sub(self, other: LinearCombination<F>) -> Self::Output {
242        self - &other
243    }
244}
245
246#[allow(clippy::op_ref)]
247impl<F: PrimeField> Sub<&LinearCombination<F>> for Variable<F> {
248    type Output = LinearCombination<F>;
249
250    fn sub(self, other: &LinearCombination<F>) -> Self::Output {
251        &self - other
252    }
253}
254
255impl<F: PrimeField> Sub<&LinearCombination<F>> for &Variable<F> {
256    type Output = LinearCombination<F>;
257
258    fn sub(self, other: &LinearCombination<F>) -> Self::Output {
259        LinearCombination::from(self) - other
260    }
261}
262
263impl<F: PrimeField> fmt::Debug for Variable<F> {
264    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
265        write!(f, "{}", match self {
266            Self::Constant(value) => format!("Constant({value})"),
267            Self::Public(index_value) => {
268                let (index, value) = index_value.as_ref();
269                format!("Public({index}, {value})")
270            }
271            Self::Private(index_value) => {
272                let (index, value) = index_value.as_ref();
273                format!("Private({index}, {value})")
274            }
275        })
276    }
277}
278
279impl<F: PrimeField> fmt::Display for Variable<F> {
280    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
281        write!(f, "{}", self.value())
282    }
283}
284
285#[cfg(test)]
286mod tests {
287    use crate::*;
288
289    #[test]
290    fn test_size() {
291        assert_eq!(16, std::mem::size_of::<Variable<<Circuit as Environment>::BaseField>>());
292    }
293}