ark_relations/gr1cs/namespace.rs
1use super::ConstraintSystemRef;
2use ark_ff::Field;
3
4/// A namespaced `ConstraintSystemRef`.
5#[derive(Clone)]
6pub struct Namespace<F: Field> {
7 inner: ConstraintSystemRef<F>,
8 id: Option<tracing::Id>,
9}
10
11impl<F: Field> From<ConstraintSystemRef<F>> for Namespace<F> {
12 fn from(other: ConstraintSystemRef<F>) -> Self {
13 Self {
14 inner: other,
15 id: None,
16 }
17 }
18}
19
20impl<F: Field> Namespace<F> {
21 /// Construct a new `Namespace`.
22 pub fn new(inner: ConstraintSystemRef<F>, id: Option<tracing::Id>) -> Self {
23 Self { inner, id }
24 }
25
26 /// Obtain the inner `ConstraintSystemRef<F>`.
27 pub fn cs(&self) -> ConstraintSystemRef<F> {
28 self.inner.clone()
29 }
30
31 /// Manually leave the namespace.
32 pub fn leave_namespace(self) {
33 drop(self);
34 }
35}
36
37impl<F: Field> Drop for Namespace<F> {
38 fn drop(&mut self) {
39 if let Some(id) = self.id.as_ref() {
40 tracing::dispatcher::get_default(|dispatch| dispatch.exit(id));
41 }
42 let _ = self.inner;
43 }
44}
45
46/// Creates namespaces for different parts of a circuit when generating
47/// constraints. Here, a namespace is equivalent to having a unique span for
48/// each part of the circuit. For more information on spans, see the [tracing](https://docs.rs/tracing) crate.
49///
50/// Takes in a reference to a Constraint System and a string slice representing
51/// the name of the namespace. The name is used to identify the namespace.
52///
53/// # Simple Example of using namespaces
54///
55/// ```rust,ignore
56/// use ark_ff::Field;
57/// use ark_r1cs_std::prelude::*;
58/// use ark_relations::gr1cs::{ConstraintSystemRef, SynthesisError};
59///
60/// // Define the circuit structure
61/// pub struct SimpleAdditionCircuit<F: Field> {
62/// pub a: F, // Public input 1
63/// pub b: F, // Public input 2
64/// pub c: F, // Witness (private input)
65/// }
66///
67/// impl<F: Field> SimpleAdditionCircuit<F> {
68/// pub fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
69/// // Create a namespace for public inputs
70/// let cs = ns!(cs, "public_inputs");
71/// let a_var = FpVar::new_input(cs.clone(), || Ok(self.a))?;
72/// let b_var = FpVar::new_input(cs.clone(), || Ok(self.b))?;
73///
74/// // Create another namespace for the witness
75/// let cs = ns!(cs, "witness");
76/// let c_var = FpVar::new_witness(cs.clone(), || Ok(self.c))?;
77///
78/// // Create another namespace for the addition constraint
79/// let cs = ns!(cs, "addition_constraint");
80/// let sum = &a_var + &b_var;
81///
82/// // Enforce that a + b = c
83/// sum.enforce_equal(&c_var)?;
84///
85/// Ok(())
86/// }
87/// }
88/// ```
89#[macro_export]
90macro_rules! ns {
91 ($cs:expr, $name:expr) => {{
92 // Define a span with `gr1cs` as the target and the given name
93 let span = $crate::gr1cs::info_span!(target: "gr1cs", $name);
94 let id = span.id();
95 // Enter the span
96 let _enter_guard = span.enter();
97 // We want the span and the guard to live forever so we forget them
98 core::mem::forget(_enter_guard);
99 core::mem::forget(span);
100 // Create a new namespace
101 $crate::gr1cs::Namespace::new($cs.clone(), id)
102 }};
103}