@@ -76,6 +76,53 @@ pub trait AllocVar<V: ?Sized, F: Field>: Sized {
7676 ) -> Result < Self , SynthesisError > {
7777 Self :: new_variable ( cs, f, AllocationMode :: Witness )
7878 }
79+
80+ /// Allocates a new constant or private witness of type `Self` in the
81+ /// `ConstraintSystem` `cs` with the allocation mode inferred from `cs`.
82+ /// A constant is allocated if `cs` is `None`, and a private witness is
83+ /// allocated otherwise.
84+ ///
85+ /// A common use case is the creation of non-deterministic advice (a.k.a.
86+ /// hints) in the circuit, where this method can avoid boilerplate code
87+ /// while allowing optimization on circuit size.
88+ ///
89+ /// For example, to compute `x_var / y_var` where `y_var` is a non-zero
90+ /// variable, one can write:
91+ /// ```
92+ /// use ark_ff::PrimeField;
93+ /// use ark_r1cs_std::{alloc::AllocVar, fields::{fp::FpVar, FieldVar}, R1CSVar};
94+ /// use ark_relations::r1cs::SynthesisError;
95+ ///
96+ /// fn div<F: PrimeField>(x_var: &FpVar<F>, y_var: &FpVar<F>) -> Result<FpVar<F>, SynthesisError> {
97+ /// let cs = x_var.cs().or(y_var.cs());
98+ /// let z_var = FpVar::new_variable_with_inferred_mode(cs, || Ok(x_var.value()? / y_var.value()?))?;
99+ /// z_var.mul_equals(y_var, x_var)?;
100+ /// Ok(z_var)
101+ /// }
102+ /// ```
103+ /// In this example, if either `x_var` or `y_var` is a witness variable,
104+ /// then `z_var` is also a witness variable. On the other hand, `z_var`
105+ /// is a constant if both `x_var` and `y_var` are constants (i.e., `cs`
106+ /// is `None`), and future operations on `z_var` do not generate any
107+ /// constraints.
108+ ///
109+ /// (Note that we use division as an example for simplicity. You may
110+ /// call `x_var.mul_by_inverse(y_var)?` directly, which internally works
111+ /// similarly to the above code.)
112+ #[ tracing:: instrument( target = "r1cs" , skip( cs, f) ) ]
113+ fn new_variable_with_inferred_mode < T : Borrow < V > > (
114+ cs : impl Into < Namespace < F > > ,
115+ f : impl FnOnce ( ) -> Result < T , SynthesisError > ,
116+ ) -> Result < Self , SynthesisError > {
117+ let ns: Namespace < F > = cs. into ( ) ;
118+ let cs = ns. cs ( ) ;
119+ let mode = if cs. is_none ( ) {
120+ AllocationMode :: Constant
121+ } else {
122+ AllocationMode :: Witness
123+ } ;
124+ Self :: new_variable ( cs, f, mode)
125+ }
79126}
80127
81128/// This blanket implementation just allocates variables in `Self`
0 commit comments