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