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