snarkvm_algorithms/r1cs/
constraint_system.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::r1cs::{Index, LinearCombination, Namespace, Variable, errors::SynthesisError};
17use snarkvm_fields::Field;
18
19use std::marker::PhantomData;
20
21/// Computations are expressed in terms of rank-1 constraint systems (R1CS).
22/// The `generate_constraints` method is called to generate constraints for
23/// both CRS generation and for proving.
24pub trait ConstraintSynthesizer<F: Field>: Sync {
25    /// Drives generation of new constraints inside `CS`.
26    fn generate_constraints<CS: ConstraintSystem<F>>(&self, cs: &mut CS) -> Result<(), SynthesisError>;
27}
28
29/// Represents a constraint system which can have new variables
30/// allocated and constraints between them formed.
31pub trait ConstraintSystem<F: Field>: Sized {
32    /// Represents the type of the "root" of this constraint system
33    /// so that nested namespaces can minimize indirection.
34    type Root: ConstraintSystem<F>;
35
36    /// Return the "one" input variable
37    fn one() -> Variable {
38        Variable::new_unchecked(Index::Public(0))
39    }
40
41    /// Allocate a private variable in the constraint system. The provided
42    /// function is used to determine the assignment of the variable. The
43    /// given `annotation` function is invoked in testing contexts in order
44    /// to derive a unique name for this variable in the current namespace.
45    fn alloc<FN, A, AR>(&mut self, annotation: A, f: FN) -> Result<Variable, SynthesisError>
46    where
47        FN: FnOnce() -> Result<F, SynthesisError>,
48        A: FnOnce() -> AR,
49        AR: AsRef<str>;
50
51    /// Allocate a public variable in the constraint system. The provided
52    /// function is used to determine the assignment of the variable.
53    fn alloc_input<FN, A, AR>(&mut self, annotation: A, f: FN) -> Result<Variable, SynthesisError>
54    where
55        FN: FnOnce() -> Result<F, SynthesisError>,
56        A: FnOnce() -> AR,
57        AR: AsRef<str>;
58
59    /// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in
60    /// testing contexts in order to derive a unique name for the constraint
61    /// in the current namespace.
62    fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
63    where
64        A: FnOnce() -> AR,
65        AR: AsRef<str>,
66        LA: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
67        LB: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
68        LC: FnOnce(LinearCombination<F>) -> LinearCombination<F>;
69
70    /// Create a new (sub)namespace and enter into it. Not intended
71    /// for downstream use; use `namespace` instead.
72    fn push_namespace<NR, N>(&mut self, name_fn: N)
73    where
74        NR: AsRef<str>,
75        N: FnOnce() -> NR;
76
77    /// Exit out of the existing namespace. Not intended for
78    /// downstream use; use `namespace` instead.
79    fn pop_namespace(&mut self);
80
81    /// Gets the "root" constraint system, bypassing the namespacing.
82    /// Not intended for downstream use; use `namespace` instead.
83    fn get_root(&mut self) -> &mut Self::Root;
84
85    /// Begin a namespace for this constraint system.
86    fn ns<NR, N>(&mut self, name_fn: N) -> Namespace<'_, F, Self::Root>
87    where
88        NR: AsRef<str>,
89        N: FnOnce() -> NR,
90    {
91        self.get_root().push_namespace(name_fn);
92
93        Namespace(self.get_root(), PhantomData)
94    }
95
96    /// Output the number of constraints in the system.
97    fn num_constraints(&self) -> usize;
98
99    /// Output the number of public input variables to the system.
100    fn num_public_variables(&self) -> usize;
101
102    /// Output the number of private input variables to the system.
103    fn num_private_variables(&self) -> usize;
104
105    /// Output whether the constraint system is in the setup mode.
106    fn is_in_setup_mode(&self) -> bool;
107}
108
109/// Convenience implementation of ConstraintSystem<F> for mutable references to
110/// constraint systems.
111impl<F: Field, CS: ConstraintSystem<F>> ConstraintSystem<F> for &mut CS {
112    type Root = CS::Root;
113
114    #[inline]
115    fn one() -> Variable {
116        CS::one()
117    }
118
119    #[inline]
120    fn alloc<FN, A, AR>(&mut self, annotation: A, f: FN) -> Result<Variable, SynthesisError>
121    where
122        FN: FnOnce() -> Result<F, SynthesisError>,
123        A: FnOnce() -> AR,
124        AR: AsRef<str>,
125    {
126        (**self).alloc(annotation, f)
127    }
128
129    #[inline]
130    fn alloc_input<FN, A, AR>(&mut self, annotation: A, f: FN) -> Result<Variable, SynthesisError>
131    where
132        FN: FnOnce() -> Result<F, SynthesisError>,
133        A: FnOnce() -> AR,
134        AR: AsRef<str>,
135    {
136        (**self).alloc_input(annotation, f)
137    }
138
139    #[inline]
140    fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
141    where
142        A: FnOnce() -> AR,
143        AR: AsRef<str>,
144        LA: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
145        LB: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
146        LC: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
147    {
148        (**self).enforce(annotation, a, b, c)
149    }
150
151    #[inline]
152    fn push_namespace<NR, N>(&mut self, name_fn: N)
153    where
154        NR: AsRef<str>,
155        N: FnOnce() -> NR,
156    {
157        (**self).push_namespace(name_fn)
158    }
159
160    #[inline]
161    fn pop_namespace(&mut self) {
162        (**self).pop_namespace()
163    }
164
165    #[inline]
166    fn get_root(&mut self) -> &mut Self::Root {
167        (**self).get_root()
168    }
169
170    #[inline]
171    fn num_constraints(&self) -> usize {
172        (**self).num_constraints()
173    }
174
175    #[inline]
176    fn num_public_variables(&self) -> usize {
177        (**self).num_public_variables()
178    }
179
180    #[inline]
181    fn num_private_variables(&self) -> usize {
182        (**self).num_private_variables()
183    }
184
185    #[inline]
186    fn is_in_setup_mode(&self) -> bool {
187        (**self).is_in_setup_mode()
188    }
189}