Skip to main content

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}