@@ -76,6 +76,53 @@ pub trait AllocVar<V: ?Sized, F: Field>: Sized {
76
76
) -> Result < Self , SynthesisError > {
77
77
Self :: new_variable ( cs, f, AllocationMode :: Witness )
78
78
}
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
+ }
79
126
}
80
127
81
128
/// This blanket implementation just allocates variables in `Self`
0 commit comments