ark-r1cs-std/r1cs-std/src/fields/cubic_extension.rs
r1cs-std/src/fields/cubic_extension.rsRaw
1use algebra::{
2 fields::{CubicExtField, CubicExtParameters, Field},
3 Zero,
4};
5use core::{borrow::Borrow, marker::PhantomData};
6use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError};
7
8use crate::fields::fp::FpVar;
9use crate::{
10 fields::{FieldOpsBounds, FieldVar},
11 prelude::*,
12 ToConstraintFieldGadget, Vec,
13};
14
15/// This struct is the `R1CS` equivalent of the cubic extension field type
16/// in `algebra-core`, i.e. `algebra_core::CubicExtField`.
17#[derive(Derivative)]
18#[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))]
19#[must_use]
20pub struct CubicExtVar<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>>
21where
22 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
23{
24 /// The zero-th coefficient of this field element.
25 pub c0: BF,
26 /// The first coefficient of this field element.
27 pub c1: BF,
28 /// The second coefficient of this field element.
29 pub c2: BF,
30 #[derivative(Debug = "ignore")]
31 _params: PhantomData<P>,
32}
33
34/// This trait describes parameters that are used to implement arithmetic for `CubicExtVar`.
35pub trait CubicExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>:
36 CubicExtParameters
37where
38 for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>,
39{
40 /// Multiply the base field of the `CubicExtVar` by the appropriate Frobenius coefficient.
41 /// This is equivalent to `Self::mul_base_field_by_frob_coeff(c1, c2, power)`.
42 fn mul_base_field_vars_by_frob_coeff(c1: &mut BF, c2: &mut BF, power: usize);
43}
44
45impl<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>> CubicExtVar<BF, P>
46where
47 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
48{
49 /// Constructs a `CubicExtVar` from the underlying coefficients.
50 #[inline]
51 pub fn new(c0: BF, c1: BF, c2: BF) -> Self {
52 let _params = PhantomData;
53 Self {
54 c0,
55 c1,
56 c2,
57 _params,
58 }
59 }
60
61 /// Multiplies a variable of the base field by the cubic nonresidue `P::NONRESIDUE` that
62 /// is used to construct the extension field.
63 #[inline]
64 pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> {
65 Ok(fe * P::NONRESIDUE)
66 }
67
68 /// Multiplies `self` by a constant from the base field.
69 #[inline]
70 pub fn mul_by_base_field_constant(&self, fe: P::BaseField) -> Self {
71 let c0 = &self.c0 * fe;
72 let c1 = &self.c1 * fe;
73 let c2 = &self.c2 * fe;
74 Self::new(c0, c1, c2)
75 }
76
77 /// Sets `self = self.mul_by_base_field_constant(fe)`.
78 #[inline]
79 pub fn mul_assign_by_base_field_constant(&mut self, fe: P::BaseField) {
80 *self = (&*self).mul_by_base_field_constant(fe);
81 }
82}
83
84impl<BF, P> R1CSVar<P::BasePrimeField> for CubicExtVar<BF, P>
85where
86 BF: FieldVar<P::BaseField, P::BasePrimeField>,
87 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
88 P: CubicExtVarParams<BF>,
89{
90 type Value = CubicExtField<P>;
91
92 fn cs(&self) -> ConstraintSystemRef<P::BasePrimeField> {
93 [&self.c0, &self.c1, &self.c2].cs()
94 }
95
96 #[inline]
97 fn value(&self) -> Result<Self::Value, SynthesisError> {
98 match (self.c0.value(), self.c1.value(), self.c2.value()) {
99 (Ok(c0), Ok(c1), Ok(c2)) => Ok(CubicExtField::new(c0, c1, c2)),
100 (..) => Err(SynthesisError::AssignmentMissing),
101 }
102 }
103}
104
105impl<BF, P> From<Boolean<P::BasePrimeField>> for CubicExtVar<BF, P>
106where
107 BF: FieldVar<P::BaseField, P::BasePrimeField>,
108 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
109 P: CubicExtVarParams<BF>,
110{
111 fn from(other: Boolean<P::BasePrimeField>) -> Self {
112 let c0 = BF::from(other);
113 let c1 = BF::zero();
114 let c2 = BF::zero();
115 Self::new(c0, c1, c2)
116 }
117}
118
119impl<'a, BF, P> FieldOpsBounds<'a, CubicExtField<P>, CubicExtVar<BF, P>> for CubicExtVar<BF, P>
120where
121 BF: FieldVar<P::BaseField, P::BasePrimeField>,
122 for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
123 P: CubicExtVarParams<BF>,
124{
125}
126impl<'a, BF, P> FieldOpsBounds<'a, CubicExtField<P>, CubicExtVar<BF, P>> for &'a CubicExtVar<BF, P>
127where
128 BF: FieldVar<P::BaseField, P::BasePrimeField>,
129 for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
130 P: CubicExtVarParams<BF>,
131{
132}
133
134impl<BF, P> FieldVar<CubicExtField<P>, P::BasePrimeField> for CubicExtVar<BF, P>
135where
136 BF: FieldVar<P::BaseField, P::BasePrimeField>,
137 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
138 P: CubicExtVarParams<BF>,
139{
140 fn constant(other: CubicExtField<P>) -> Self {
141 let c0 = BF::constant(other.c0);
142 let c1 = BF::constant(other.c1);
143 let c2 = BF::constant(other.c2);
144 Self::new(c0, c1, c2)
145 }
146
147 fn zero() -> Self {
148 let c0 = BF::zero();
149 let c1 = BF::zero();
150 let c2 = BF::zero();
151 Self::new(c0, c1, c2)
152 }
153
154 fn one() -> Self {
155 let c0 = BF::one();
156 let c1 = BF::zero();
157 let c2 = BF::zero();
158 Self::new(c0, c1, c2)
159 }
160
161 #[inline]
162 #[tracing::instrument(target = "r1cs")]
163 fn double(&self) -> Result<Self, SynthesisError> {
164 let c0 = self.c0.double()?;
165 let c1 = self.c1.double()?;
166 let c2 = self.c2.double()?;
167 Ok(Self::new(c0, c1, c2))
168 }
169
170 #[inline]
171 #[tracing::instrument(target = "r1cs")]
172 fn negate(&self) -> Result<Self, SynthesisError> {
173 let mut result = self.clone();
174 result.c0.negate_in_place()?;
175 result.c1.negate_in_place()?;
176 result.c2.negate_in_place()?;
177 Ok(result)
178 }
179
180 /// Use the Chung-Hasan asymmetric squaring formula.
181 ///
182 /// (Devegili OhEig Scott Dahab --- Multiplication and Squaring on
183 /// Abstract Pairing-Friendly
184 /// Fields.pdf; Section 4 (CH-SQR2))
185 #[inline]
186 #[tracing::instrument(target = "r1cs")]
187 fn square(&self) -> Result<Self, SynthesisError> {
188 let a = self.c0.clone();
189 let b = self.c1.clone();
190 let c = self.c2.clone();
191
192 let s0 = a.square()?;
193 let ab = &a * &b;
194 let s1 = ab.double()?;
195 let s2 = (&a - &b + &c).square()?;
196 let s3 = (&b * &c).double()?;
197 let s4 = c.square()?;
198
199 let c0 = Self::mul_base_field_by_nonresidue(&s3)? + &s0;
200 let c1 = Self::mul_base_field_by_nonresidue(&s4)? + &s1;
201 let c2 = s1 + &s2 + &s3 - &s0 - &s4;
202
203 Ok(Self::new(c0, c1, c2))
204 }
205
206 #[tracing::instrument(target = "r1cs")]
207 fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
208 // Karatsuba multiplication for cubic extensions:
209 // v0 = A.c0 * B.c0
210 // v1 = A.c1 * B.c1
211 // v2 = A.c2 * B.c2
212 // result.c0 = v0 + β((a1 + a2)(b1 + b2) − v1 − v2)
213 // result.c1 = (a0 + a1)(b0 + b1) − v0 − v1 + βv2
214 // result.c2 = (a0 + a2)(b0 + b2) − v0 + v1 − v2,
215 // We enforce this with six constraints:
216 //
217 // v0 = A.c0 * B.c0
218 // v1 = A.c1 * B.c1
219 // v2 = A.c2 * B.c2
220 //
221 // result.c0 - v0 + \beta*(v1 + v2) = β(a1 + a2)(b1 + b2))
222 // result.c1 + v0 + v1 - βv2 = (a0 + a1)(b0 + b1)
223 // result.c2 + v0 - v1 + v2 = (a0 + a2)(b0 + b2)
224 // Reference:
225 // "Multiplication and Squaring on Pairing-Friendly Fields"
226 // Devegili, OhEigeartaigh, Scott, Dahab
227 //
228 // This implementation adapted from
229 // https://github.com/ZencashOfficial/ginger-lib/blob/development/r1cs/gadgets/std/src/fields/fp3.rs
230 let v0 = &self.c0 * &other.c0;
231 let v1 = &self.c1 * &other.c1;
232 let v2 = &self.c2 * &other.c2;
233
234 // Check c0
235 let nr_a1_plus_a2 = (&self.c1 + &self.c2) * P::NONRESIDUE;
236 let b1_plus_b2 = &other.c1 + &other.c2;
237 let nr_v1 = &v1 * P::NONRESIDUE;
238 let nr_v2 = &v2 * P::NONRESIDUE;
239 let to_check = &result.c0 - &v0 + &nr_v1 + &nr_v2;
240 nr_a1_plus_a2.mul_equals(&b1_plus_b2, &to_check)?;
241
242 // Check c1
243 let a0_plus_a1 = &self.c0 + &self.c1;
244 let b0_plus_b1 = &other.c0 + &other.c1;
245 let to_check = &result.c1 - &nr_v2 + &v0 + &v1;
246 a0_plus_a1.mul_equals(&b0_plus_b1, &to_check)?;
247
248 // Check c2
249 let a0_plus_a2 = &self.c0 + &self.c2;
250 let b0_plus_b2 = &other.c0 + &other.c2;
251 let to_check = &result.c2 + &v0 - &v1 + &v2;
252 a0_plus_a2.mul_equals(&b0_plus_b2, &to_check)?;
253 Ok(())
254 }
255
256 #[tracing::instrument(target = "r1cs")]
257 fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError> {
258 let mut result = self.clone();
259 result.c0.frobenius_map_in_place(power)?;
260 result.c1.frobenius_map_in_place(power)?;
261 result.c2.frobenius_map_in_place(power)?;
262
263 P::mul_base_field_vars_by_frob_coeff(&mut result.c1, &mut result.c2, power);
264 Ok(result)
265 }
266
267 #[tracing::instrument(target = "r1cs")]
268 fn inverse(&self) -> Result<Self, SynthesisError> {
269 let mode = if self.is_constant() {
270 AllocationMode::Constant
271 } else {
272 AllocationMode::Witness
273 };
274 let inverse = Self::new_variable(
275 self.cs(),
276 || {
277 self.value()
278 .map(|f| f.inverse().unwrap_or(CubicExtField::zero()))
279 },
280 mode,
281 )?;
282 self.mul_equals(&inverse, &Self::one())?;
283 Ok(inverse)
284 }
285}
286
287impl_bounded_ops!(
288 CubicExtVar<BF, P>,
289 CubicExtField<P>,
290 Add,
291 add,
292 AddAssign,
293 add_assign,
294 |this: &'a CubicExtVar<BF, P>, other: &'a CubicExtVar<BF, P>| {
295 let c0 = &this.c0 + &other.c0;
296 let c1 = &this.c1 + &other.c1;
297 let c2 = &this.c2 + &other.c2;
298 CubicExtVar::new(c0, c1, c2)
299 },
300 |this: &'a CubicExtVar<BF, P>, other: CubicExtField<P>| {
301 this + CubicExtVar::constant(other)
302 },
303 (BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>),
304 for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
305);
306impl_bounded_ops!(
307 CubicExtVar<BF, P>,
308 CubicExtField<P>,
309 Sub,
310 sub,
311 SubAssign,
312 sub_assign,
313 |this: &'a CubicExtVar<BF, P>, other: &'a CubicExtVar<BF, P>| {
314 let c0 = &this.c0 - &other.c0;
315 let c1 = &this.c1 - &other.c1;
316 let c2 = &this.c2 - &other.c2;
317 CubicExtVar::new(c0, c1, c2)
318 },
319 |this: &'a CubicExtVar<BF, P>, other: CubicExtField<P>| {
320 this - CubicExtVar::constant(other)
321 },
322 (BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>),
323 for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
324);
325impl_bounded_ops!(
326 CubicExtVar<BF, P>,
327 CubicExtField<P>,
328 Mul,
329 mul,
330 MulAssign,
331 mul_assign,
332 |this: &'a CubicExtVar<BF, P>, other: &'a CubicExtVar<BF, P>| {
333 // Karatsuba multiplication for cubic extensions:
334 // v0 = A.c0 * B.c0
335 // v1 = A.c1 * B.c1
336 // v2 = A.c2 * B.c2
337 // result.c0 = v0 + β((a1 + a2)(b1 + b2) − v1 − v2)
338 // result.c1 = (a0 + a1)(b0 + b1) − v0 − v1 + βv2
339 // result.c2 = (a0 + a2)(b0 + b2) − v0 + v1 − v2,
340 //
341 // Reference:
342 // "Multiplication and Squaring on Pairing-Friendly Fields"
343 // Devegili, OhEigeartaigh, Scott, Dahab
344 let v0 = &this.c0 * &other.c0;
345 let v1 = &this.c1 * &other.c1;
346 let v2 = &this.c2 * &other.c2;
347 let c0 =
348 (((&this.c1 + &this.c2) * (&other.c1 + &other.c2) - &v1 - &v2) * P::NONRESIDUE) + &v0 ;
349 let c1 =
350 (&this.c0 + &this.c1) * (&other.c0 + &other.c1) - &v0 - &v1 + (&v2 * P::NONRESIDUE);
351 let c2 =
352 (&this.c0 + &this.c2) * (&other.c0 + &other.c2) - &v0 + &v1 - &v2;
353
354 CubicExtVar::new(c0, c1, c2)
355 },
356 |this: &'a CubicExtVar<BF, P>, other: CubicExtField<P>| {
357 this * CubicExtVar::constant(other)
358 },
359 (BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>),
360 for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>,
361);
362
363impl<BF, P> EqGadget<P::BasePrimeField> for CubicExtVar<BF, P>
364where
365 BF: FieldVar<P::BaseField, P::BasePrimeField>,
366 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
367 P: CubicExtVarParams<BF>,
368{
369 #[tracing::instrument(target = "r1cs")]
370 fn is_eq(&self, other: &Self) -> Result<Boolean<P::BasePrimeField>, SynthesisError> {
371 let b0 = self.c0.is_eq(&other.c0)?;
372 let b1 = self.c1.is_eq(&other.c1)?;
373 let b2 = self.c2.is_eq(&other.c2)?;
374 b0.and(&b1)?.and(&b2)
375 }
376
377 #[inline]
378 #[tracing::instrument(target = "r1cs")]
379 fn conditional_enforce_equal(
380 &self,
381 other: &Self,
382 condition: &Boolean<P::BasePrimeField>,
383 ) -> Result<(), SynthesisError> {
384 self.c0.conditional_enforce_equal(&other.c0, condition)?;
385 self.c1.conditional_enforce_equal(&other.c1, condition)?;
386 self.c2.conditional_enforce_equal(&other.c2, condition)?;
387 Ok(())
388 }
389
390 #[inline]
391 #[tracing::instrument(target = "r1cs")]
392 fn conditional_enforce_not_equal(
393 &self,
394 other: &Self,
395 condition: &Boolean<P::BasePrimeField>,
396 ) -> Result<(), SynthesisError> {
397 let is_equal = self.is_eq(other)?;
398 is_equal
399 .and(condition)?
400 .enforce_equal(&Boolean::Constant(false))
401 }
402}
403
404impl<BF, P> ToBitsGadget<P::BasePrimeField> for CubicExtVar<BF, P>
405where
406 BF: FieldVar<P::BaseField, P::BasePrimeField>,
407 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
408 P: CubicExtVarParams<BF>,
409{
410 #[tracing::instrument(target = "r1cs")]
411 fn to_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
412 let mut c0 = self.c0.to_bits_le()?;
413 let mut c1 = self.c1.to_bits_le()?;
414 let mut c2 = self.c2.to_bits_le()?;
415 c0.append(&mut c1);
416 c0.append(&mut c2);
417 Ok(c0)
418 }
419
420 #[tracing::instrument(target = "r1cs")]
421 fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<P::BasePrimeField>>, SynthesisError> {
422 let mut c0 = self.c0.to_non_unique_bits_le()?;
423 let mut c1 = self.c1.to_non_unique_bits_le()?;
424 let mut c2 = self.c2.to_non_unique_bits_le()?;
425 c0.append(&mut c1);
426 c0.append(&mut c2);
427 Ok(c0)
428 }
429}
430
431impl<BF, P> ToBytesGadget<P::BasePrimeField> for CubicExtVar<BF, P>
432where
433 BF: FieldVar<P::BaseField, P::BasePrimeField>,
434 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
435 P: CubicExtVarParams<BF>,
436{
437 #[tracing::instrument(target = "r1cs")]
438 fn to_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
439 let mut c0 = self.c0.to_bytes()?;
440 let mut c1 = self.c1.to_bytes()?;
441 let mut c2 = self.c2.to_bytes()?;
442 c0.append(&mut c1);
443 c0.append(&mut c2);
444
445 Ok(c0)
446 }
447
448 #[tracing::instrument(target = "r1cs")]
449 fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::BasePrimeField>>, SynthesisError> {
450 let mut c0 = self.c0.to_non_unique_bytes()?;
451 let mut c1 = self.c1.to_non_unique_bytes()?;
452 let mut c2 = self.c2.to_non_unique_bytes()?;
453
454 c0.append(&mut c1);
455 c0.append(&mut c2);
456
457 Ok(c0)
458 }
459}
460
461impl<BF, P> ToConstraintFieldGadget<P::BasePrimeField> for CubicExtVar<BF, P>
462where
463 BF: FieldVar<P::BaseField, P::BasePrimeField>,
464 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
465 P: CubicExtVarParams<BF>,
466 BF: ToConstraintFieldGadget<P::BasePrimeField>,
467{
468 #[tracing::instrument(target = "r1cs")]
469 fn to_constraint_field(&self) -> Result<Vec<FpVar<P::BasePrimeField>>, SynthesisError> {
470 let mut res = Vec::new();
471
472 res.extend_from_slice(&self.c0.to_constraint_field()?);
473 res.extend_from_slice(&self.c1.to_constraint_field()?);
474 res.extend_from_slice(&self.c2.to_constraint_field()?);
475
476 Ok(res)
477 }
478}
479
480impl<BF, P> CondSelectGadget<P::BasePrimeField> for CubicExtVar<BF, P>
481where
482 BF: FieldVar<P::BaseField, P::BasePrimeField>,
483 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
484 P: CubicExtVarParams<BF>,
485{
486 #[inline]
487 #[tracing::instrument(target = "r1cs")]
488 fn conditionally_select(
489 cond: &Boolean<P::BasePrimeField>,
490 true_value: &Self,
491 false_value: &Self,
492 ) -> Result<Self, SynthesisError> {
493 let c0 = BF::conditionally_select(cond, &true_value.c0, &false_value.c0)?;
494 let c1 = BF::conditionally_select(cond, &true_value.c1, &false_value.c1)?;
495 let c2 = BF::conditionally_select(cond, &true_value.c2, &false_value.c2)?;
496 Ok(Self::new(c0, c1, c2))
497 }
498}
499
500impl<BF, P> TwoBitLookupGadget<P::BasePrimeField> for CubicExtVar<BF, P>
501where
502 BF: FieldVar<P::BaseField, P::BasePrimeField>
503 + TwoBitLookupGadget<P::BasePrimeField, TableConstant = P::BaseField>,
504 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
505 P: CubicExtVarParams<BF>,
506{
507 type TableConstant = CubicExtField<P>;
508
509 #[tracing::instrument(target = "r1cs")]
510 fn two_bit_lookup(
511 b: &[Boolean<P::BasePrimeField>],
512 c: &[Self::TableConstant],
513 ) -> Result<Self, SynthesisError> {
514 let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>();
515 let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>();
516 let c2s = c.iter().map(|f| f.c2).collect::<Vec<_>>();
517 let c0 = BF::two_bit_lookup(b, &c0s)?;
518 let c1 = BF::two_bit_lookup(b, &c1s)?;
519 let c2 = BF::two_bit_lookup(b, &c2s)?;
520 Ok(Self::new(c0, c1, c2))
521 }
522}
523
524impl<BF, P> ThreeBitCondNegLookupGadget<P::BasePrimeField> for CubicExtVar<BF, P>
525where
526 BF: FieldVar<P::BaseField, P::BasePrimeField>
527 + ThreeBitCondNegLookupGadget<P::BasePrimeField, TableConstant = P::BaseField>,
528 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
529 P: CubicExtVarParams<BF>,
530{
531 type TableConstant = CubicExtField<P>;
532
533 #[tracing::instrument(target = "r1cs")]
534 fn three_bit_cond_neg_lookup(
535 b: &[Boolean<P::BasePrimeField>],
536 b0b1: &Boolean<P::BasePrimeField>,
537 c: &[Self::TableConstant],
538 ) -> Result<Self, SynthesisError> {
539 let c0s = c.iter().map(|f| f.c0).collect::<Vec<_>>();
540 let c1s = c.iter().map(|f| f.c1).collect::<Vec<_>>();
541 let c2s = c.iter().map(|f| f.c2).collect::<Vec<_>>();
542 let c0 = BF::three_bit_cond_neg_lookup(b, b0b1, &c0s)?;
543 let c1 = BF::three_bit_cond_neg_lookup(b, b0b1, &c1s)?;
544 let c2 = BF::three_bit_cond_neg_lookup(b, b0b1, &c2s)?;
545 Ok(Self::new(c0, c1, c2))
546 }
547}
548
549impl<BF, P> AllocVar<CubicExtField<P>, P::BasePrimeField> for CubicExtVar<BF, P>
550where
551 BF: FieldVar<P::BaseField, P::BasePrimeField>,
552 for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>,
553 P: CubicExtVarParams<BF>,
554{
555 fn new_variable<T: Borrow<CubicExtField<P>>>(
556 cs: impl Into<Namespace<P::BasePrimeField>>,
557 f: impl FnOnce() -> Result<T, SynthesisError>,
558 mode: AllocationMode,
559 ) -> Result<Self, SynthesisError> {
560 let ns = cs.into();
561 let cs = ns.cs();
562
563 use SynthesisError::*;
564 let (c0, c1, c2) = match f() {
565 Ok(fe) => (Ok(fe.borrow().c0), Ok(fe.borrow().c1), Ok(fe.borrow().c2)),
566 Err(_) => (
567 Err(AssignmentMissing),
568 Err(AssignmentMissing),
569 Err(AssignmentMissing),
570 ),
571 };
572
573 let c0 = BF::new_variable(r1cs_core::ns!(cs, "c0"), || c0, mode)?;
574 let c1 = BF::new_variable(r1cs_core::ns!(cs, "c1"), || c1, mode)?;
575 let c2 = BF::new_variable(r1cs_core::ns!(cs, "c2"), || c2, mode)?;
576 Ok(Self::new(c0, c1, c2))
577 }
578}