Skip to main content

ark_ec/models/twisted_edwards/
mod.rs

1use ark_serialize::{
2    CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
3    CanonicalSerializeWithFlags, Compress, SerializationError, Valid, Validate,
4};
5use ark_std::io::{Read, Write};
6
7use crate::{
8    scalar_mul::{double_and_add, double_and_add_affine, variable_base::VariableBaseMSM},
9    AffineRepr,
10};
11use num_traits::Zero;
12
13use ark_ff::fields::Field;
14
15mod affine;
16pub use affine::*;
17
18mod group;
19pub use group::*;
20
21mod serialization_flags;
22pub use serialization_flags::*;
23
24/// Constants and convenience functions that collectively define the [Twisted Edwards model](https://www.hyperelliptic.org/EFD/g1p/auto-twisted.html)
25/// of the curve.
26///
27/// In this model, the curve equation is `a * x² + y² = 1 + d * x² * y²`, for constants `a` and `d`.
28pub trait TECurveConfig: super::CurveConfig {
29    /// Coefficient `a` of the curve equation.
30    const COEFF_A: Self::BaseField;
31    /// Coefficient `d` of the curve equation.
32    const COEFF_D: Self::BaseField;
33    /// Generator of the prime-order subgroup.
34    const GENERATOR: Affine<Self>;
35
36    /// Model parameters for the Montgomery curve that is birationally
37    /// equivalent to this curve.
38    type MontCurveConfig: MontCurveConfig<BaseField = Self::BaseField>;
39
40    /// Helper method for computing `elem * Self::COEFF_A`.
41    ///
42    /// The default implementation should be overridden only if
43    /// the product can be computed faster than standard field multiplication
44    /// (eg: via doubling if `COEFF_A == 2`, or if `COEFF_A.is_zero()`).
45    #[inline(always)]
46    fn mul_by_a(elem: Self::BaseField) -> Self::BaseField {
47        elem * Self::COEFF_A
48    }
49
50    /// Checks that the current point is in the prime order subgroup given
51    /// the point on the curve.
52    fn is_in_correct_subgroup_assuming_on_curve(item: &Affine<Self>) -> bool {
53        // Directly use `double_and_add_affine` to avoid incorrect zero results from
54        // custom `mul_affine` implementations that reduce scalars modulo the group order.
55        double_and_add_affine(item, Self::ScalarField::characteristic()).is_zero()
56    }
57
58    /// Performs cofactor clearing.
59    /// The default method is simply to multiply by the cofactor.
60    /// For some curve families though, it is sufficient to multiply
61    /// by a smaller scalar.
62    fn clear_cofactor(item: &Affine<Self>) -> Affine<Self> {
63        item.mul_by_cofactor()
64    }
65
66    /// Default implementation of group multiplication for projective coordinates
67    fn mul_projective(base: &Projective<Self>, scalar: &[u64]) -> Projective<Self> {
68        double_and_add(base, scalar)
69    }
70
71    /// Default implementation of group multiplication for affine coordinates
72    fn mul_affine(base: &Affine<Self>, scalar: &[u64]) -> Projective<Self> {
73        double_and_add_affine(base, scalar)
74    }
75
76    /// Default implementation for multi scalar multiplication
77    fn msm(
78        bases: &[Affine<Self>],
79        scalars: &[Self::ScalarField],
80    ) -> Result<Projective<Self>, usize> {
81        (bases.len() == scalars.len())
82            .then(|| VariableBaseMSM::msm_unchecked(bases, scalars))
83            .ok_or_else(|| bases.len().min(scalars.len()))
84    }
85
86    /// If uncompressed, serializes both x and y coordinates.
87    /// If compressed, serializes y coordinate with a bit to encode whether x is positive.
88    #[inline]
89    fn serialize_with_mode<W: Write>(
90        item: &Affine<Self>,
91        mut writer: W,
92        compress: ark_serialize::Compress,
93    ) -> Result<(), SerializationError> {
94        let flags = TEFlags::from_x_coordinate(item.x);
95        match compress {
96            Compress::Yes => item.y.serialize_with_flags(writer, flags),
97            Compress::No => {
98                item.x.serialize_uncompressed(&mut writer)?;
99                item.y.serialize_uncompressed(&mut writer)
100            },
101        }
102    }
103
104    /// If `validate` is `Yes`, calls `check()` to make sure the element is valid.
105    ///
106    /// Uses `Affine::get_xs_from_y_unchecked()` for the compressed version.
107    fn deserialize_with_mode<R: Read>(
108        mut reader: R,
109        compress: Compress,
110        validate: Validate,
111    ) -> Result<Affine<Self>, SerializationError> {
112        let (x, y) = match compress {
113            Compress::Yes => {
114                let (y, flags): (_, TEFlags) =
115                    CanonicalDeserializeWithFlags::deserialize_with_flags(reader)?;
116                let (x, neg_x) = Affine::<Self>::get_xs_from_y_unchecked(y)
117                    .ok_or(SerializationError::InvalidData)?;
118                if flags.is_negative() {
119                    (neg_x, y)
120                } else {
121                    (x, y)
122                }
123            },
124            Compress::No => {
125                let x: Self::BaseField =
126                    CanonicalDeserialize::deserialize_uncompressed(&mut reader)?;
127                let y: Self::BaseField =
128                    CanonicalDeserialize::deserialize_uncompressed(&mut reader)?;
129                (x, y)
130            },
131        };
132        let point = Affine::new_unchecked(x, y);
133        if validate == Validate::Yes {
134            point.check()?;
135        }
136        Ok(point)
137    }
138
139    #[inline]
140    fn serialized_size(compress: Compress) -> usize {
141        let zero = Self::BaseField::zero();
142        match compress {
143            Compress::Yes => zero.serialized_size_with_flags::<TEFlags>(),
144            Compress::No => zero.uncompressed_size() + zero.uncompressed_size(),
145        }
146    }
147}
148
149/// Constants and convenience functions that collectively define the [Montgomery model](https://www.hyperelliptic.org/EFD/g1p/auto-montgom.html)
150/// of the curve.
151///
152/// In this model, the curve equation is `b * y² = x³ + a * x² + x`, for constants `a` and `b`.
153pub trait MontCurveConfig: super::CurveConfig {
154    /// Coefficient `a` of the curve equation.
155    const COEFF_A: Self::BaseField;
156    /// Coefficient `b` of the curve equation.
157    const COEFF_B: Self::BaseField;
158
159    /// Model parameters for the Twisted Edwards curve that is birationally
160    /// equivalent to this curve.
161    type TECurveConfig: TECurveConfig<BaseField = Self::BaseField>;
162}
163
164//////////////////////////////////////////////////////////////////////////////