Skip to main content

sonobe_primitives/algebra/group/
mod.rs

1//! This module defines extension traits for elliptic curve points and their
2//! in-circuit counterparts, along with some common implementations.
3
4use ark_ec::{
5    AffineRepr, CurveGroup, PrimeGroup,
6    short_weierstrass::{Projective, SWCurveConfig},
7};
8use ark_ff::{Field, One, PrimeField, Zero};
9use ark_r1cs_std::{
10    convert::ToConstraintFieldGadget,
11    fields::fp::FpVar,
12    groups::{CurveVar, curves::short_weierstrass::ProjectiveVar},
13};
14use ark_relations::gr1cs::SynthesisError;
15
16use crate::{
17    algebra::{Val, field::SonobeField, group::emulated::EmulatedAffineVar},
18    circuits::WitnessToPublic,
19    traits::{Dummy, Inputize, InputizeEmulated},
20    transcripts::{Absorbable, AbsorbableVar},
21};
22
23pub mod emulated;
24
25/// [`CF1`] is a type alias for the scalar field of a curve `C`.
26pub type CF1<C> = <C as PrimeGroup>::ScalarField;
27/// [`CF2`] is a type alias for the base field of a curve `C`.
28pub type CF2<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
29
30/// [`SonobeCurve`] trait is a wrapper around [`CurveGroup`] that also includes
31/// necessary bounds for the curve to be used conveniently in folding schemes.
32pub trait SonobeCurve:
33    CurveGroup<ScalarField: SonobeField, BaseField: SonobeField, Config: SWCurveConfig>
34    + Absorbable
35    + Inputize<Self::BaseField>
36    + InputizeEmulated<Self::ScalarField>
37    + Val<
38        Var: CurveVar<Self, Self::BaseField> + AbsorbableVar<Self::BaseField> + WitnessToPublic,
39        EmulatedVar<Self::ScalarField> = EmulatedAffineVar<Self::ScalarField, Self>,
40    >
41{
42}
43
44impl<P: SWCurveConfig<ScalarField: SonobeField, BaseField: SonobeField>> SonobeCurve
45    for Projective<P>
46{
47}
48
49impl<P: SWCurveConfig<ScalarField: SonobeField, BaseField: SonobeField>> Val for Projective<P> {
50    type PreferredConstraintField = P::BaseField;
51    type Var = ProjectiveVar<P, FpVar<P::BaseField>>;
52
53    type EmulatedVar<F: SonobeField> = EmulatedAffineVar<F, Self>;
54}
55
56impl<T, C: SonobeCurve> Dummy<T> for C {
57    fn dummy(_: T) -> Self {
58        Default::default()
59    }
60}
61
62impl<P: SWCurveConfig<BaseField: Absorbable>> Absorbable for Projective<P> {
63    fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>) {
64        let affine = self.into_affine();
65        let (x, y) = affine.xy().unwrap_or_default();
66        [x, y].absorb_into(dest);
67    }
68}
69
70impl<P: SWCurveConfig<BaseField: PrimeField>> AbsorbableVar<P::BaseField>
71    for ProjectiveVar<P, FpVar<P::BaseField>>
72{
73    fn absorb_into(&self, dest: &mut Vec<FpVar<P::BaseField>>) -> Result<(), SynthesisError> {
74        let mut vec = self.to_constraint_field()?;
75        // The last element in the vector tells whether the point is infinity,
76        // but we can in fact avoid absorbing it without loss of soundness.
77        // This is because the `to_constraint_field` method internally invokes
78        // [`ProjectiveVar::to_afine`](https://github.com/arkworks-rs/r1cs-std/blob/4020fbc22625621baa8125ede87abaeac3c1ca26/src/groups/curves/short_weierstrass/mod.rs#L160-L195),
79        // which guarantees that an infinity point is represented as `(0, 0)`,
80        // but the y-coordinate of a non-infinity point is never 0 (for why, see
81        // https://crypto.stackexchange.com/a/108242 ).
82        vec.pop();
83        dest.extend(vec);
84        Ok(())
85    }
86}
87
88impl<P: SWCurveConfig<BaseField: SonobeField>> Inputize<P::BaseField> for Projective<P> {
89    fn inputize(&self) -> Vec<P::BaseField> {
90        let affine = self.into_affine();
91        match affine.xy() {
92            Some((x, y)) => vec![x, y, One::one()],
93            None => vec![Zero::zero(), One::one(), Zero::zero()],
94        }
95    }
96}
97
98impl<P: SWCurveConfig<BaseField: SonobeField, ScalarField: SonobeField>>
99    InputizeEmulated<P::ScalarField> for Projective<P>
100{
101    fn inputize_emulated(&self) -> Vec<P::ScalarField> {
102        let affine = self.into_affine();
103        let (x, y) = affine.xy().unwrap_or_default();
104
105        [x, y].inputize_emulated()
106    }
107}
108
109impl<P: SWCurveConfig<BaseField: PrimeField>> WitnessToPublic
110    for ProjectiveVar<P, FpVar<P::BaseField>>
111{
112    fn mark_as_public(&self) -> Result<(), SynthesisError> {
113        // We only need the x and y coordinates of the point, but the `infinity`
114        // flag is not necessary.
115        self.to_constraint_field()?[..2].mark_as_public()
116    }
117}