snarkvm_circuit_environment/helpers/
r1cs.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::{
17    helpers::{Constraint, Counter},
18    prelude::*,
19};
20use snarkvm_fields::PrimeField;
21
22use std::rc::Rc;
23
24pub type Scope = String;
25
26#[derive(Debug)]
27pub struct R1CS<F: PrimeField> {
28    constants: Vec<Variable<F>>,
29    public: Vec<Variable<F>>,
30    private: Vec<Variable<F>>,
31    constraints: Vec<Rc<Constraint<F>>>,
32    counter: Counter<F>,
33    num_variables: u64,
34    nonzeros: (u64, u64, u64),
35}
36
37impl<F: PrimeField> R1CS<F> {
38    /// Returns a new instance of a constraint system.
39    pub(crate) fn new() -> Self {
40        Self {
41            constants: Default::default(),
42            public: vec![Variable::Public(Rc::new((0u64, F::one())))],
43            private: Default::default(),
44            constraints: Default::default(),
45            counter: Default::default(),
46            num_variables: 1u64,
47            nonzeros: (0, 0, 0),
48        }
49    }
50
51    /// Appends the given scope to the current environment.
52    pub(crate) fn push_scope<S: Into<String>>(&mut self, name: S) -> Result<(), String> {
53        self.counter.push(name)
54    }
55
56    /// Removes the given scope from the current environment.
57    pub(crate) fn pop_scope<S: Into<String>>(&mut self, name: S) -> Result<(), String> {
58        self.counter.pop(name)
59    }
60
61    /// Returns a new constant with the given value and scope.
62    pub(crate) fn new_constant(&mut self, value: F) -> Variable<F> {
63        let variable = Variable::Constant(Rc::new(value));
64        self.constants.push(variable.clone());
65        self.counter.increment_constant();
66        self.num_variables += 1;
67        variable
68    }
69
70    /// Returns a new public variable with the given value and scope.
71    pub(crate) fn new_public(&mut self, value: F) -> Variable<F> {
72        let variable = Variable::Public(Rc::new((self.public.len() as u64, value)));
73        self.public.push(variable.clone());
74        self.counter.increment_public();
75        self.num_variables += 1;
76        variable
77    }
78
79    /// Returns a new private variable with the given value and scope.
80    pub(crate) fn new_private(&mut self, value: F) -> Variable<F> {
81        let variable = Variable::Private(Rc::new((self.private.len() as u64, value)));
82        self.private.push(variable.clone());
83        self.counter.increment_private();
84        self.num_variables += 1;
85        variable
86    }
87
88    /// Adds one constraint enforcing that `(A * B) == C`.
89    pub(crate) fn enforce(&mut self, constraint: Constraint<F>) {
90        let (a_nonzeros, b_nonzeros, c_nonzeros) = constraint.num_nonzeros();
91        self.nonzeros.0 += a_nonzeros;
92        self.nonzeros.1 += b_nonzeros;
93        self.nonzeros.2 += c_nonzeros;
94
95        let constraint = Rc::new(constraint);
96        self.constraints.push(Rc::clone(&constraint));
97        self.counter.add_constraint(constraint);
98    }
99
100    /// Returns `true` if all of the constraints are satisfied.
101    ///
102    /// In addition, when in debug mode, this function also checks that
103    /// all constraints use variables corresponding to the declared variables.
104    pub fn is_satisfied(&self) -> bool {
105        // Ensure all constraints are satisfied.
106        let constraints_satisfied = self.constraints.iter().all(|constraint| constraint.is_satisfied());
107        if !constraints_satisfied {
108            return false;
109        }
110
111        // In debug mode, ensure all constraints use variables corresponding to the declared variables.
112        #[cfg(not(debug_assertions))]
113        return true;
114        #[cfg(debug_assertions)]
115        self.constraints.iter().all(|constraint| {
116            let (a, b, c) = constraint.to_terms();
117            [a, b, c].into_iter().all(|lc| {
118                lc.to_terms().iter().all(|(variable, _)| match variable {
119                    Variable::Constant(_value) => false, // terms should not contain Constants
120                    Variable::Private(private) => {
121                        let (index, value) = private.as_ref();
122                        self.private.get(*index as usize).map_or_else(|| false, |v| v.value() == *value)
123                    }
124                    Variable::Public(public) => {
125                        let (index, value) = public.as_ref();
126                        self.public.get(*index as usize).map_or_else(|| false, |v| v.value() == *value)
127                    }
128                })
129            })
130        })
131    }
132
133    /// Returns `true` if all constraints in the current scope are satisfied.
134    pub(crate) fn is_satisfied_in_scope(&self) -> bool {
135        self.counter.is_satisfied_in_scope()
136    }
137
138    /// Returns the current scope.
139    pub(crate) fn scope(&self) -> Scope {
140        self.counter.scope()
141    }
142
143    /// Returns the number of constants in the constraint system.
144    pub fn num_constants(&self) -> u64 {
145        self.constants.len() as u64
146    }
147
148    /// Returns the number of public variables in the constraint system.
149    pub fn num_public(&self) -> u64 {
150        self.public.len() as u64
151    }
152
153    /// Returns the number of private variables in the constraint system.
154    pub fn num_private(&self) -> u64 {
155        self.private.len() as u64
156    }
157
158    /// Returns the number of constant, public, and private variables in the constraint system.
159    pub fn num_variables(&self) -> u64 {
160        self.num_variables
161    }
162
163    /// Returns the number of constraints in the constraint system.
164    pub fn num_constraints(&self) -> u64 {
165        self.constraints.len() as u64
166    }
167
168    /// Returns the number of nonzeros in the constraint system.
169    pub fn num_nonzeros(&self) -> (u64, u64, u64) {
170        self.nonzeros
171    }
172
173    /// Returns the number of constants for the current scope.
174    pub(crate) fn num_constants_in_scope(&self) -> u64 {
175        self.counter.num_constants_in_scope()
176    }
177
178    /// Returns the number of public variables for the current scope.
179    pub(crate) fn num_public_in_scope(&self) -> u64 {
180        self.counter.num_public_in_scope()
181    }
182
183    /// Returns the number of private variables for the current scope.
184    pub(crate) fn num_private_in_scope(&self) -> u64 {
185        self.counter.num_private_in_scope()
186    }
187
188    /// Returns the number of constraints for the current scope.
189    pub(crate) fn num_constraints_in_scope(&self) -> u64 {
190        self.counter.num_constraints_in_scope()
191    }
192
193    /// Returns the number of nonzeros for the current scope.
194    pub(crate) fn num_nonzeros_in_scope(&self) -> (u64, u64, u64) {
195        self.counter.num_nonzeros_in_scope()
196    }
197
198    /// Returns the public variables in the constraint system.
199    pub fn to_public_variables(&self) -> &Vec<Variable<F>> {
200        &self.public
201    }
202
203    /// Returns the private variables in the constraint system.
204    pub fn to_private_variables(&self) -> &Vec<Variable<F>> {
205        &self.private
206    }
207
208    /// Returns the constraints in the constraint system.
209    pub fn to_constraints(&self) -> &Vec<Rc<Constraint<F>>> {
210        &self.constraints
211    }
212}
213
214impl<F: PrimeField> Display for R1CS<F> {
215    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216        let mut output = String::default();
217        for constraint in self.to_constraints() {
218            output += &constraint.to_string();
219        }
220        output += "\n";
221
222        write!(f, "{output}")
223    }
224}