openzeppelin_crypto/curve/
mod.rs

1//! This module provides common operations to work with elliptic curves.
2//!
3//! Abstractions and api in this module are similar to Arkworks Algebra [ark-ec
4//! library].
5//!
6//! [ark-ec library]: https://github.com/arkworks-rs/algebra/tree/master/ec
7
8use alloc::vec::Vec;
9use core::{
10    fmt::{Debug, Display},
11    hash::Hash,
12    ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
13};
14
15use num_traits::Zero;
16use zeroize::Zeroize;
17
18use crate::{
19    bits::BitIteratorBE,
20    field::{group::AdditiveGroup, prime::PrimeField, Field},
21};
22
23mod helpers;
24pub mod sw;
25pub mod te;
26
27/// Elliptic curves can be represented via different "models" with varying
28/// efficiency properties.
29///
30/// [`CurveConfig`] bundles together the types that are common
31/// to all models of the given curve, namely the [`Self::BaseField`] over which
32/// the curve is defined, and the [`Self::ScalarField`] defined by the
33/// appropriate prime-order subgroup of the curve.
34pub trait CurveConfig: Send + Sync + Sized + 'static {
35    /// Base field that the curve is defined over.
36    type BaseField: Field;
37    /// Finite prime field corresponding to an appropriate prime-order subgroup
38    /// of the curve group.
39    type ScalarField: PrimeField;
40
41    /// The cofactor of this curve, represented as a sequence of little-endian
42    /// limbs.
43    const COFACTOR: &'static [u64];
44
45    /// The inverse of the cofactor.
46    const COFACTOR_INV: Self::ScalarField;
47
48    /// Returns `true` if the cofactor is one.
49    fn cofactor_is_one() -> bool {
50        let mut iter = Self::COFACTOR.iter();
51        matches!(iter.next(), Some(1)) && iter.all(Zero::is_zero)
52    }
53}
54
55/// Represents (elements of) a group of prime order `r`.
56pub trait PrimeGroup: AdditiveGroup<Scalar = Self::ScalarField> {
57    /// The scalar field `F_r`, where `r` is the order of this group.
58    type ScalarField: PrimeField;
59
60    /// Returns a fixed generator of this group.
61    #[must_use]
62    fn generator() -> Self;
63
64    /// Performs scalar multiplication of this element.
65    #[must_use]
66    fn mul_bigint(&self, other: impl BitIteratorBE) -> Self;
67
68    /// Computes `other * self`, where `other` is a *big-endian*
69    /// bit representation of some integer.
70    #[must_use]
71    fn mul_bits_be(&self, other: impl Iterator<Item = bool>) -> Self {
72        let mut res = Self::zero();
73        for b in other.skip_while(|b| !b) {
74            // skip leading zeros
75            res.double_in_place();
76            if b {
77                res += self;
78            }
79        }
80        res
81    }
82}
83
84/// An opaque representation of an elliptic curve group element that is suitable
85/// for efficient group arithmetic.
86///
87/// The point is guaranteed to be in the correct prime order subgroup.
88pub trait CurveGroup:
89    PrimeGroup
90    + Add<Self::Affine, Output = Self>
91    + AddAssign<Self::Affine>
92    + Sub<Self::Affine, Output = Self>
93    + SubAssign<Self::Affine>
94    + From<Self::Affine>
95    + Into<Self::Affine>
96    + core::iter::Sum<Self::Affine>
97    + for<'a> core::iter::Sum<&'a Self::Affine>
98{
99    /// Associated configuration for this curve.
100    type Config: CurveConfig<
101        ScalarField = Self::ScalarField,
102        BaseField = Self::BaseField,
103    >;
104
105    /// The field over which this curve is defined.
106    type BaseField: Field;
107
108    /// The affine representation of this element.
109    type Affine: AffineRepr<
110            Config = Self::Config,
111            Group = Self,
112            ScalarField = Self::ScalarField,
113            BaseField = Self::BaseField,
114        > + From<Self>
115        + Into<Self>;
116
117    /// Type representing an element of the full elliptic curve group, not just
118    /// the prime order subgroup.
119    type FullGroup;
120
121    /// Normalizes a slice of group elements into affine.
122    #[must_use]
123    fn normalize_batch(v: &[Self]) -> Vec<Self::Affine>;
124
125    /// Converts `self` into the affine representation.
126    fn into_affine(self) -> Self::Affine {
127        self.into()
128    }
129}
130
131/// The canonical representation of an elliptic curve group element.
132/// This should represent the affine coordinates of the point corresponding
133/// to this group element.
134///
135/// The point is guaranteed to be in the correct prime order subgroup.
136pub trait AffineRepr:
137    Eq
138    + 'static
139    + Sized
140    + Copy
141    + Clone
142    + Default
143    + Send
144    + Sync
145    + Hash
146    + Debug
147    + Display
148    + Zeroize
149    + Neg
150    + From<<Self as AffineRepr>::Group>
151    + Into<<Self as AffineRepr>::Group>
152    + Add<Self, Output = Self::Group>
153    + for<'a> Add<&'a Self, Output = Self::Group>
154    + Add<Self::Group, Output = Self::Group>
155    + for<'a> Add<&'a Self::Group, Output = Self::Group>
156    + Sub<Self, Output = Self::Group>
157    + for<'a> Sub<&'a Self, Output = Self::Group>
158    + Sub<Self::Group, Output = Self::Group>
159    + for<'a> Sub<&'a Self::Group, Output = Self::Group>
160    + Mul<Self::ScalarField, Output = Self::Group>
161    + for<'a> Mul<&'a Self::ScalarField, Output = Self::Group>
162{
163    /// Associated configuration for this curve.
164    type Config: CurveConfig<
165        ScalarField = Self::ScalarField,
166        BaseField = Self::BaseField,
167    >;
168
169    /// Finite prime field corresponding to an appropriate prime-order subgroup
170    /// of the curve group.
171    type ScalarField: PrimeField;
172
173    /// Base field that the curve is defined over.
174    type BaseField: Field;
175
176    /// The projective representation of points on this curve.
177    type Group: CurveGroup<
178            Config = Self::Config,
179            Affine = Self,
180            ScalarField = Self::ScalarField,
181            BaseField = Self::BaseField,
182        > + From<Self>
183        + Into<Self>
184        + MulAssign<Self::ScalarField>; // needed due to https://github.com/rust-lang/rust/issues/69640
185
186    /// Returns the x and y coordinates of this affine point.
187    fn xy(&self) -> Option<(Self::BaseField, Self::BaseField)>;
188
189    /// Returns the x coordinate of this affine point.
190    fn x(&self) -> Option<Self::BaseField> {
191        self.xy().map(|(x, _)| x)
192    }
193
194    /// Returns the y coordinate of this affine point.
195    fn y(&self) -> Option<Self::BaseField> {
196        self.xy().map(|(_, y)| y)
197    }
198
199    /// Returns the point at infinity.
200    fn zero() -> Self;
201
202    /// Is `self` the point at infinity?
203    fn is_zero(&self) -> bool {
204        self.xy().is_none()
205    }
206
207    /// Returns a fixed generator of unknown exponent.
208    #[must_use]
209    fn generator() -> Self;
210
211    /// Converts self into the projective representation.
212    fn into_group(self) -> Self::Group {
213        self.into()
214    }
215
216    /// Performs scalar multiplication of this element with mixed addition.
217    #[must_use]
218    fn mul_bigint(&self, by: impl BitIteratorBE) -> Self::Group;
219
220    /// Performs cofactor clearing.
221    /// The default method is simply to multiply by the cofactor.
222    /// For some curve families more efficient methods exist.
223    #[must_use]
224    fn clear_cofactor(&self) -> Self;
225
226    /// Multiplies this element by the cofactor and output the
227    /// resulting projective element.
228    #[must_use]
229    fn mul_by_cofactor_to_group(&self) -> Self::Group;
230
231    /// Multiplies this element by the cofactor.
232    #[must_use]
233    fn mul_by_cofactor(&self) -> Self {
234        self.mul_by_cofactor_to_group().into()
235    }
236
237    /// Multiplies this element by the inverse of the cofactor in
238    /// `Self::ScalarField`.
239    #[must_use]
240    fn mul_by_cofactor_inv(&self) -> Self {
241        self.mul_bigint(Self::Config::COFACTOR_INV.into_bigint()).into()
242    }
243}
244
245/// Efficiently computes inverses of non-zero elements in the slice.
246///
247/// Uses Montgomery's trick to compute multiple inverses with fewer field
248/// operations.
249/// Zero elements remain unchanged.
250///
251/// # Arguments
252///
253/// * `v` - Mutable slice of field elements for in-place inversion.
254pub fn batch_inversion<F: Field>(v: &mut [F]) {
255    batch_inversion_and_mul(v, &F::one());
256}
257
258/// Efficiently computes `coeff * v_i^(-1)` for each non-zero element.
259///
260/// Optimizes batch inversion by multiplying each result by a coefficient.
261/// Implements Montgomery's trick in two passes to minimize field inversions.
262/// Zero elements remain unchanged.
263///
264/// # Arguments
265///
266/// * `v` - Mutable slice for in-place computation.
267/// * `coeff` - Coefficient to multiply each inverse by.
268fn batch_inversion_and_mul<F: Field>(v: &mut [F], coeff: &F) {
269    // Montgomery's Trick and Fast Implementation of Masked AES
270    // Genelle, Prouff and Quisquater
271    // Section 3.2
272    // but with an optimization to multiply every element in the returned vector
273    // by coeff.
274
275    // First pass: compute [a, ab, abc, ...]
276    let mut tmp = F::one();
277    let prod: Vec<_> = v
278        .iter()
279        .filter(|f| !f.is_zero())
280        .map(|f| {
281            tmp *= f;
282            tmp
283        })
284        .collect();
285
286    // Invert `tmp`.
287    tmp = tmp.inverse().expect("should not be zero");
288
289    // Multiply product by coeff, so coeff will scale all inverses.
290    tmp *= coeff;
291
292    // Second pass: iterate backwards to compute inverses
293    for (f, s) in v
294        .iter_mut()
295        // Backwards
296        .rev()
297        // Ignore normalized elements
298        .filter(|f| !f.is_zero())
299        // Backwards, skip the last element, fill in `one()` for the last term.
300        .zip(prod.into_iter().rev().skip(1).chain([F::one()]))
301    {
302        // tmp := tmp * f; f := tmp * s = 1/f
303        let new_tmp = tmp * *f;
304        *f = tmp * s;
305        tmp = new_tmp;
306    }
307}
308
309#[cfg(test)]
310mod test {
311    use alloc::{vec, vec::Vec};
312
313    use crate::{
314        curve::batch_inversion, field::instance::FpBN256, fp_from_num,
315    };
316
317    #[test]
318    fn batch_inversion_works() {
319        let mut v: Vec<FpBN256> = vec![
320            fp_from_num!("3423432434"),
321            fp_from_num!("342"),
322            fp_from_num!("343443534234234"),
323        ];
324
325        let expected_v: Vec<FpBN256> = vec![
326            fp_from_num!("3537284798280370862969965094761407641979943185930201162008302715970127239037"),
327            fp_from_num!("19520216596230932581243139626618330122828219713821317177859509581595384769483"),
328            fp_from_num!("13917121828095828097189447294655626368886333473718821676252546722946587466026"),
329        ];
330
331        batch_inversion(&mut v);
332
333        assert_eq!(v, expected_v);
334    }
335
336    #[test]
337    fn batch_inversion_remains_zeroes() {
338        let mut v: Vec<FpBN256> = vec![
339            fp_from_num!("0"),
340            fp_from_num!("342"),
341            fp_from_num!("343443534234234"),
342        ];
343        batch_inversion(&mut v);
344
345        assert!(v[0].is_zero());
346    }
347}