arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/groups/curves/short_weierstrass/mod.rs
r1cs-std/src/groups/curves/short_weierstrass/mod.rsRaw
  1use algebra::{
  2    curves::{
  3        short_weierstrass_jacobian::{GroupAffine as SWAffine, GroupProjective as SWProjective},
  4        SWModelParameters,
  5    },
  6    AffineCurve, BitIterator, Field, PrimeField, ProjectiveCurve,
  7};
  8use r1cs_core::{ConstraintSystem, SynthesisError};
  9use std::{borrow::Borrow, marker::PhantomData, ops::Neg};
 10
 11use crate::{prelude::*, Assignment};
 12
 13pub mod bls12;
 14
 15#[derive(Derivative)]
 16#[derivative(Debug, Clone)]
 17#[must_use]
 18pub struct AffineGadget<
 19    P: SWModelParameters,
 20    ConstraintF: Field,
 21    F: FieldGadget<P::BaseField, ConstraintF>,
 22> {
 23    pub x:   F,
 24    pub y:   F,
 25    _params: PhantomData<P>,
 26    _engine: PhantomData<ConstraintF>,
 27}
 28
 29impl<P: SWModelParameters, ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>>
 30    AffineGadget<P, ConstraintF, F>
 31{
 32    pub fn new(x: F, y: F) -> Self {
 33        Self {
 34            x,
 35            y,
 36            _params: PhantomData,
 37            _engine: PhantomData,
 38        }
 39    }
 40
 41    pub fn alloc_without_check<FN, CS: ConstraintSystem<ConstraintF>>(
 42        mut cs: CS,
 43        value_gen: F,
 44    ) -> Result<Self, SynthesisError>
 45    where
 46        F: FnOnce() -> Result<SWProjective<P>, SynthesisError>,
 47    {
 48        let (x, y) = match value_gen() {
 49            Ok(fe) => {
 50                let fe = fe.into_affine();
 51                (Ok(fe.x), Ok(fe.y))
 52            },
 53            _ => (
 54                Err(SynthesisError::AssignmentMissing),
 55                Err(SynthesisError::AssignmentMissing),
 56            ),
 57        };
 58
 59        let x = F::alloc(&mut cs.ns(|| "x"), || x)?;
 60        let y = F::alloc(&mut cs.ns(|| "y"), || y)?;
 61
 62        Ok(Self::new(x, y))
 63    }
 64}
 65
 66impl<P, ConstraintF, F> PartialEq for AffineGadget<P, ConstraintF, F>
 67where
 68    P: SWModelParameters,
 69    ConstraintF: Field,
 70    F: FieldGadget<P::BaseField, ConstraintF>,
 71{
 72    fn eq(&self, other: &Self) -> bool {
 73        self.x == other.x && self.y == other.y
 74    }
 75}
 76
 77impl<P, ConstraintF, F> Eq for AffineGadget<P, ConstraintF, F>
 78where
 79    P: SWModelParameters,
 80    ConstraintF: Field,
 81    F: FieldGadget<P::BaseField, ConstraintF>,
 82{
 83}
 84
 85impl<P, ConstraintF, F> GroupGadget<SWProjective<P>, ConstraintF>
 86    for AffineGadget<P, ConstraintF, F>
 87where
 88    P: SWModelParameters,
 89    ConstraintF: Field,
 90    F: FieldGadget<P::BaseField, ConstraintF>,
 91{
 92    type Value = SWProjective<P>;
 93    type Variable = (F::Variable, F::Variable);
 94
 95    #[inline]
 96    fn get_value(&self) -> Option<Self::Value> {
 97        match (self.x.get_value(), self.y.get_value()) {
 98            (Some(x), Some(y)) => {
 99                let is_zero = x.is_zero() && y.is_one();
100                Some(SWAffine::new(x, y, is_zero).into_projective())
101            },
102            (None, None) => None,
103            _ => unreachable!(),
104        }
105    }
106
107    #[inline]
108    fn get_variable(&self) -> Self::Variable {
109        (self.x.get_variable(), self.y.get_variable())
110    }
111
112    #[inline]
113    fn zero<CS: ConstraintSystem<ConstraintF>>(mut cs: CS) -> Result<Self, SynthesisError> {
114        Ok(Self::new(
115            F::zero(cs.ns(|| "zero"))?,
116            F::one(cs.ns(|| "one"))?,
117        ))
118    }
119
120    #[inline]
121    /// Incomplete addition: neither `self` nor `other` can be the neutral
122    /// element.
123    fn add<CS: ConstraintSystem<ConstraintF>>(
124        &self,
125        mut cs: CS,
126        other: &Self,
127    ) -> Result<Self, SynthesisError> {
128        // lambda = (B.y - A.y)/(B.x - A.x)
129        // C.x = lambda^2 - A.x - B.x
130        // C.y = lambda(A.x - C.x) - A.y
131        //
132        // Special cases:
133        //
134        // doubling: if B.y = A.y and B.x = A.x then lambda is unbound and
135        // C = (lambda^2, lambda^3)
136        //
137        // addition of negative point: if B.y = -A.y and B.x = A.x then no
138        // lambda can satisfy the first equation unless B.y - A.y = 0. But
139        // then this reduces to doubling.
140        //
141        // So we need to check that A.x - B.x != 0, which can be done by
142        // enforcing I * (B.x - A.x) = 1
143
144        let x2_minus_x1 = other.x.sub(cs.ns(|| "x2 - x1"), &self.x)?;
145        let y2_minus_y1 = other.y.sub(cs.ns(|| "y2 - y1"), &self.y)?;
146
147        let inv = x2_minus_x1.inverse(cs.ns(|| "compute inv"))?;
148
149        let lambda = F::alloc(cs.ns(|| "lambda"), || {
150            Ok(y2_minus_y1.get_value().get()? * &inv.get_value().get()?)
151        })?;
152
153        let x_3 = F::alloc(&mut cs.ns(|| "x_3"), || {
154            let lambda_val = lambda.get_value().get()?;
155            let x1 = self.x.get_value().get()?;
156            let x2 = other.x.get_value().get()?;
157            Ok((lambda_val.square() - &x1) - &x2)
158        })?;
159
160        let y_3 = F::alloc(&mut cs.ns(|| "y_3"), || {
161            let lambda_val = lambda.get_value().get()?;
162            let x_1 = self.x.get_value().get()?;
163            let y_1 = self.y.get_value().get()?;
164            let x_3 = x_3.get_value().get()?;
165            Ok(lambda_val * &(x_1 - &x_3) - &y_1)
166        })?;
167
168        // Check lambda
169        lambda.mul_equals(cs.ns(|| "check lambda"), &x2_minus_x1, &y2_minus_y1)?;
170
171        // Check x3
172        let x3_plus_x1_plus_x2 = x_3
173            .add(cs.ns(|| "x3 + x1"), &self.x)?
174            .add(cs.ns(|| "x3 + x1 + x2"), &other.x)?;
175        lambda.mul_equals(cs.ns(|| "check x3"), &lambda, &x3_plus_x1_plus_x2)?;
176
177        // Check y3
178        let y3_plus_y1 = y_3.add(cs.ns(|| "y3 + y1"), &self.y)?;
179        let x1_minus_x3 = self.x.sub(cs.ns(|| "x1 - x3"), &x_3)?;
180
181        lambda.mul_equals(cs.ns(|| ""), &x1_minus_x3, &y3_plus_y1)?;
182
183        Ok(Self::new(x_3, y_3))
184    }
185
186    /// Incomplete addition: neither `self` nor `other` can be the neutral
187    /// element.
188    fn add_constant<CS: ConstraintSystem<ConstraintF>>(
189        &self,
190        mut cs: CS,
191        other: &SWProjective<P>,
192    ) -> Result<Self, SynthesisError> {
193        // lambda = (B.y - A.y)/(B.x - A.x)
194        // C.x = lambda^2 - A.x - B.x
195        // C.y = lambda(A.x - C.x) - A.y
196        //
197        // Special cases:
198        //
199        // doubling: if B.y = A.y and B.x = A.x then lambda is unbound and
200        // C = (lambda^2, lambda^3)
201        //
202        // addition of negative point: if B.y = -A.y and B.x = A.x then no
203        // lambda can satisfy the first equation unless B.y - A.y = 0. But
204        // then this reduces to doubling.
205        //
206        // So we need to check that A.x - B.x != 0, which can be done by
207        // enforcing I * (B.x - A.x) = 1
208        if other.is_zero() {
209            return Err(SynthesisError::AssignmentMissing);
210        }
211        let other = other.into_affine();
212        let other_x = other.x;
213        let other_y = other.y;
214
215        let x2_minus_x1 = self
216            .x
217            .sub_constant(cs.ns(|| "x2 - x1"), &other_x)?
218            .negate(cs.ns(|| "neg1"))?;
219        let y2_minus_y1 = self
220            .y
221            .sub_constant(cs.ns(|| "y2 - y1"), &other_y)?
222            .negate(cs.ns(|| "neg2"))?;
223
224        let inv = x2_minus_x1.inverse(cs.ns(|| "compute inv"))?;
225
226        let lambda = F::alloc(cs.ns(|| "lambda"), || {
227            Ok(y2_minus_y1.get_value().get()? * &inv.get_value().get()?)
228        })?;
229
230        let x_3 = F::alloc(&mut cs.ns(|| "x_3"), || {
231            let lambda_val = lambda.get_value().get()?;
232            let x1 = self.x.get_value().get()?;
233            let x2 = other_x;
234            Ok((lambda_val.square() - &x1) - &x2)
235        })?;
236
237        let y_3 = F::alloc(&mut cs.ns(|| "y_3"), || {
238            let lambda_val = lambda.get_value().get()?;
239            let x_1 = self.x.get_value().get()?;
240            let y_1 = self.y.get_value().get()?;
241            let x_3 = x_3.get_value().get()?;
242            Ok(lambda_val * &(x_1 - &x_3) - &y_1)
243        })?;
244
245        // Check lambda
246        lambda.mul_equals(cs.ns(|| "check lambda"), &x2_minus_x1, &y2_minus_y1)?;
247
248        // Check x3
249        let x3_plus_x1_plus_x2 = x_3
250            .add(cs.ns(|| "x3 + x1"), &self.x)?
251            .add_constant(cs.ns(|| "x3 + x1 + x2"), &other_x)?;
252        lambda.mul_equals(cs.ns(|| "check x3"), &lambda, &x3_plus_x1_plus_x2)?;
253
254        // Check y3
255        let y3_plus_y1 = y_3.add(cs.ns(|| "y3 + y1"), &self.y)?;
256        let x1_minus_x3 = self.x.sub(cs.ns(|| "x1 - x3"), &x_3)?;
257
258        lambda.mul_equals(cs.ns(|| ""), &x1_minus_x3, &y3_plus_y1)?;
259
260        Ok(Self::new(x_3, y_3))
261    }
262
263    #[inline]
264    fn double_in_place<CS: ConstraintSystem<ConstraintF>>(
265        &mut self,
266        mut cs: CS,
267    ) -> Result<(), SynthesisError> {
268        let a = P::COEFF_A;
269        let x_squared = self.x.square(cs.ns(|| "x^2"))?;
270
271        let one = P::BaseField::one();
272        let two = one.double();
273        let three = two + &one;
274
275        let three_x_squared = x_squared.mul_by_constant(cs.ns(|| "3 * x^2"), &three)?;
276        let three_x_squared_plus_a = three_x_squared.add_constant(cs.ns(|| "3 * x^2 + a"), &a)?;
277
278        let two_y = self.y.double(cs.ns(|| "2y"))?;
279
280        let lambda = F::alloc(cs.ns(|| "lambda"), || {
281            let y_doubled_inv = two_y.get_value().get()?.inverse().get()?;
282            Ok(three_x_squared_plus_a.get_value().get()? * &y_doubled_inv)
283        })?;
284
285        // Check lambda
286        lambda.mul_equals(cs.ns(|| "check lambda"), &two_y, &three_x_squared_plus_a)?;
287
288        let x = lambda
289            .square(cs.ns(|| "lambda^2"))?
290            .sub(cs.ns(|| "lambda^2 - x"), &self.x)?
291            .sub(cs.ns(|| "lambda^2 - 2x"), &self.x)?;
292
293        let y = self
294            .x
295            .sub(cs.ns(|| "x - self.x"), &x)?
296            .mul(cs.ns(|| "times lambda"), &lambda)?
297            .sub(cs.ns(|| "plus self.y"), &self.y)?;
298
299        *self = Self::new(x, y);
300        Ok(())
301    }
302
303    fn negate<CS: ConstraintSystem<ConstraintF>>(
304        &self,
305        mut cs: CS,
306    ) -> Result<Self, SynthesisError> {
307        Ok(Self::new(
308            self.x.clone(),
309            self.y.negate(cs.ns(|| "negate y"))?,
310        ))
311    }
312
313    fn cost_of_add() -> usize {
314        3 * F::cost_of_mul() + F::cost_of_inv()
315    }
316
317    fn cost_of_double() -> usize {
318        4 * F::cost_of_mul()
319    }
320}
321
322impl<P, ConstraintF, F> CondSelectGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
323where
324    P: SWModelParameters,
325    ConstraintF: Field,
326    F: FieldGadget<P::BaseField, ConstraintF>,
327{
328    #[inline]
329    fn conditionally_select<CS: ConstraintSystem<ConstraintF>>(
330        mut cs: CS,
331        cond: &Boolean,
332        first: &Self,
333        second: &Self,
334    ) -> Result<Self, SynthesisError> {
335        let x = F::conditionally_select(&mut cs.ns(|| "x"), cond, &first.x, &second.x)?;
336        let y = F::conditionally_select(&mut cs.ns(|| "y"), cond, &first.y, &second.y)?;
337
338        Ok(Self::new(x, y))
339    }
340
341    fn cost() -> usize {
342        2 * <F as CondSelectGadget<ConstraintF>>::cost()
343    }
344}
345
346impl<P, ConstraintF, F> EqGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
347where
348    P: SWModelParameters,
349    ConstraintF: Field,
350    F: FieldGadget<P::BaseField, ConstraintF>,
351{
352}
353
354impl<P, ConstraintF, F> ConditionalEqGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
355where
356    P: SWModelParameters,
357    ConstraintF: Field,
358    F: FieldGadget<P::BaseField, ConstraintF>,
359{
360    #[inline]
361    fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
362        &self,
363        mut cs: CS,
364        other: &Self,
365        condition: &Boolean,
366    ) -> Result<(), SynthesisError> {
367        self.x.conditional_enforce_equal(
368            &mut cs.ns(|| "X Coordinate Conditional Equality"),
369            &other.x,
370            condition,
371        )?;
372        self.y.conditional_enforce_equal(
373            &mut cs.ns(|| "Y Coordinate Conditional Equality"),
374            &other.y,
375            condition,
376        )?;
377        Ok(())
378    }
379
380    fn cost() -> usize {
381        2 * <F as ConditionalEqGadget<ConstraintF>>::cost()
382    }
383}
384
385impl<P, ConstraintF, F> NEqGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
386where
387    P: SWModelParameters,
388    ConstraintF: Field,
389    F: FieldGadget<P::BaseField, ConstraintF>,
390{
391    #[inline]
392    fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>(
393        &self,
394        mut cs: CS,
395        other: &Self,
396    ) -> Result<(), SynthesisError> {
397        self.x
398            .enforce_not_equal(&mut cs.ns(|| "X Coordinate Inequality"), &other.x)?;
399        self.y
400            .enforce_not_equal(&mut cs.ns(|| "Y Coordinate Inequality"), &other.y)?;
401        Ok(())
402    }
403
404    fn cost() -> usize {
405        2 * <F as NEqGadget<ConstraintF>>::cost()
406    }
407}
408
409impl<P, ConstraintF, F> AllocGadget<SWProjective<P>, ConstraintF>
410    for AffineGadget<P, ConstraintF, F>
411where
412    P: SWModelParameters,
413    ConstraintF: Field,
414    F: FieldGadget<P::BaseField, ConstraintF>,
415{
416    #[inline]
417    fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
418        mut cs: CS,
419        value_gen: FN,
420    ) -> Result<Self, SynthesisError>
421    where
422        FN: FnOnce() -> Result<T, SynthesisError>,
423        T: Borrow<SWProjective<P>>,
424    {
425        let (x, y) = match value_gen() {
426            Ok(ge) => {
427                let ge = ge.borrow().into_affine();
428                (Ok(ge.x), Ok(ge.y))
429            },
430            _ => (
431                Err(SynthesisError::AssignmentMissing),
432                Err(SynthesisError::AssignmentMissing),
433            ),
434        };
435
436        // Perform on-curve check.
437        let b = P::COEFF_B;
438        let a = P::COEFF_A;
439
440        let x = F::alloc(&mut cs.ns(|| "x"), || x)?;
441        let y = F::alloc(&mut cs.ns(|| "y"), || y)?;
442
443        // Check that y^2 = x^3 + ax +b
444        // We do this by checking that y^2 - b = x * (x^2 +a)
445        let x2 = x.square(&mut cs.ns(|| "x^2"))?;
446        let y2 = y.square(&mut cs.ns(|| "y^2"))?;
447
448        let x2_plus_a = x2.add_constant(cs.ns(|| "x^2 + a"), &a)?;
449        let y2_minus_b = y2.add_constant(cs.ns(|| "y^2 - b"), &b.neg())?;
450
451        x2_plus_a.mul_equals(cs.ns(|| "on curve check"), &x, &y2_minus_b)?;
452
453        Ok(Self::new(x, y))
454    }
455
456    #[inline]
457    fn alloc_checked<FN, T, CS: ConstraintSystem<ConstraintF>>(
458        mut cs: CS,
459        value_gen: FN,
460    ) -> Result<Self, SynthesisError>
461    where
462        FN: FnOnce() -> Result<T, SynthesisError>,
463        T: Borrow<SWProjective<P>>,
464    {
465        let cofactor_weight = BitIterator::new(P::COFACTOR).filter(|b| *b).count();
466        // If we multiply by r, we actually multiply by r - 2.
467        let r_minus_1 = (-P::ScalarField::one()).into_repr();
468        let r_weight = BitIterator::new(&r_minus_1).filter(|b| *b).count();
469
470        // We pick the most efficient method of performing the prime order check:
471        // If the cofactor has lower hamming weight than the scalar field's modulus,
472        // we first multiply by the inverse of the cofactor, and then, after allocating,
473        // multiply by the cofactor. This ensures the resulting point has no cofactors
474        //
475        // Else, we multiply by the scalar field's modulus and ensure that the result
476        // is zero.
477        if cofactor_weight < r_weight {
478            let ge = Self::alloc(cs.ns(|| "Alloc checked"), || {
479                value_gen().map(|ge| {
480                    ge.borrow()
481                        .into_affine()
482                        .mul_by_cofactor_inv()
483                        .into_projective()
484                })
485            })?;
486            let mut seen_one = false;
487            let mut result = Self::zero(cs.ns(|| "result"))?;
488            for (i, b) in BitIterator::new(P::COFACTOR).enumerate() {
489                let mut cs = cs.ns(|| format!("Iteration {}", i));
490
491                let old_seen_one = seen_one;
492                if seen_one {
493                    result.double_in_place(cs.ns(|| "Double"))?;
494                } else {
495                    seen_one = b;
496                }
497
498                if b {
499                    result = if old_seen_one {
500                        result.add(cs.ns(|| "Add"), &ge)?
501                    } else {
502                        ge.clone()
503                    };
504                }
505            }
506            Ok(result)
507        } else {
508            let ge = Self::alloc(cs.ns(|| "Alloc checked"), value_gen)?;
509            let mut seen_one = false;
510            let mut result = Self::zero(cs.ns(|| "result"))?;
511            // Returns bits in big-endian order
512            for (i, b) in BitIterator::new(r_minus_1).enumerate() {
513                let mut cs = cs.ns(|| format!("Iteration {}", i));
514
515                let old_seen_one = seen_one;
516                if seen_one {
517                    result.double_in_place(cs.ns(|| "Double"))?;
518                } else {
519                    seen_one = b;
520                }
521
522                if b {
523                    result = if old_seen_one {
524                        result.add(cs.ns(|| "Add"), &ge)?
525                    } else {
526                        ge.clone()
527                    };
528                }
529            }
530            let neg_ge = ge.negate(cs.ns(|| "Negate ge"))?;
531            neg_ge.enforce_equal(cs.ns(|| "Check equals"), &result)?;
532            Ok(ge)
533        }
534    }
535
536    #[inline]
537    fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
538        mut cs: CS,
539        value_gen: FN,
540    ) -> Result<Self, SynthesisError>
541    where
542        FN: FnOnce() -> Result<T, SynthesisError>,
543        T: Borrow<SWProjective<P>>,
544    {
545        let (x, y) = match value_gen() {
546            Ok(ge) => {
547                let ge = ge.borrow().into_affine();
548                (Ok(ge.x), Ok(ge.y))
549            },
550            _ => (
551                Err(SynthesisError::AssignmentMissing),
552                Err(SynthesisError::AssignmentMissing),
553            ),
554        };
555
556        let b = P::COEFF_B;
557        let a = P::COEFF_A;
558
559        let x = F::alloc_input(&mut cs.ns(|| "x"), || x)?;
560        let y = F::alloc_input(&mut cs.ns(|| "y"), || y)?;
561
562        // Check that y^2 = x^3 + ax +b
563        // We do this by checking that y^2 - b = x * (x^2 +a)
564        let x2 = x.square(&mut cs.ns(|| "x^2"))?;
565        let y2 = y.square(&mut cs.ns(|| "y^2"))?;
566
567        let x2_plus_a = x2.add_constant(cs.ns(|| "x^2 + a"), &a)?;
568        let y2_minus_b = y2.add_constant(cs.ns(|| "y^2 - b"), &b.neg())?;
569
570        x2_plus_a.mul_equals(cs.ns(|| "on curve check"), &x, &y2_minus_b)?;
571
572        Ok(Self::new(x, y))
573    }
574}
575
576impl<P, ConstraintF, F> ToBitsGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
577where
578    P: SWModelParameters,
579    ConstraintF: Field,
580    F: FieldGadget<P::BaseField, ConstraintF>,
581{
582    fn to_bits<CS: ConstraintSystem<ConstraintF>>(
583        &self,
584        mut cs: CS,
585    ) -> Result<Vec<Boolean>, SynthesisError> {
586        let mut x_bits = self.x.to_bits(&mut cs.ns(|| "X Coordinate To Bits"))?;
587        let y_bits = self.y.to_bits(&mut cs.ns(|| "Y Coordinate To Bits"))?;
588        x_bits.extend_from_slice(&y_bits);
589        Ok(x_bits)
590    }
591
592    fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
593        &self,
594        mut cs: CS,
595    ) -> Result<Vec<Boolean>, SynthesisError> {
596        let mut x_bits = self
597            .x
598            .to_bits_strict(&mut cs.ns(|| "X Coordinate To Bits"))?;
599        let y_bits = self
600            .y
601            .to_bits_strict(&mut cs.ns(|| "Y Coordinate To Bits"))?;
602        x_bits.extend_from_slice(&y_bits);
603
604        Ok(x_bits)
605    }
606}
607
608impl<P, ConstraintF, F> ToBytesGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
609where
610    P: SWModelParameters,
611    ConstraintF: Field,
612    F: FieldGadget<P::BaseField, ConstraintF>,
613{
614    fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
615        &self,
616        mut cs: CS,
617    ) -> Result<Vec<UInt8>, SynthesisError> {
618        let mut x_bytes = self.x.to_bytes(&mut cs.ns(|| "X Coordinate To Bytes"))?;
619        let y_bytes = self.y.to_bytes(&mut cs.ns(|| "Y Coordinate To Bytes"))?;
620        x_bytes.extend_from_slice(&y_bytes);
621        Ok(x_bytes)
622    }
623
624    fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
625        &self,
626        mut cs: CS,
627    ) -> Result<Vec<UInt8>, SynthesisError> {
628        let mut x_bytes = self
629            .x
630            .to_bytes_strict(&mut cs.ns(|| "X Coordinate To Bytes"))?;
631        let y_bytes = self
632            .y
633            .to_bytes_strict(&mut cs.ns(|| "Y Coordinate To Bytes"))?;
634        x_bytes.extend_from_slice(&y_bytes);
635
636        Ok(x_bytes)
637    }
638}