/ circuit / environment / src / helpers / variable.rs
variable.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm 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  
 16  use crate::{LinearCombination, Mode};
 17  use deltavm_fields::traits::*;
 18  
 19  use core::{
 20      cmp::Ordering,
 21      fmt,
 22      ops::{Add, Sub},
 23  };
 24  use std::sync::Arc;
 25  
 26  pub type Index = u64;
 27  
 28  #[derive(Clone, PartialEq, Eq, Hash)]
 29  pub enum Variable<F: PrimeField> {
 30      Constant(Arc<F>),
 31      Public(Arc<(Index, F)>),
 32      Private(Arc<(Index, F)>),
 33  }
 34  
 35  impl<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  
108  impl<F: PrimeField> PartialOrd for Variable<F> {
109      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
110          Some(self.cmp(other))
111      }
112  }
113  
114  impl<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)]
131  impl<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)]
140  impl<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)]
149  impl<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  
157  impl<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)]
169  impl<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)]
178  impl<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)]
187  impl<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  
195  impl<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)]
204  impl<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)]
213  impl<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)]
222  impl<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  
230  impl<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)]
242  impl<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)]
251  impl<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)]
260  impl<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  
268  impl<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  
276  impl<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  
292  impl<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)]
299  mod 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  }