Skip to main content

a/math/ec/
domain.rs

1//! Curves with a generator.
2
3use super::curve::{Curve, CurveError};
4use super::field::limbs_of;
5use super::group::Table;
6use super::point::Point;
7use crate::math::numbers::Number;
8use core::ops::Deref;
9use std::sync::OnceLock;
10
11/// A curve with a generator of a subgroup, the subgroup's order and its cofactor: the domain
12/// parameters that the [named curves](super::named) are, and that any curve can be given. It
13/// dereferences to its curve.
14///
15/// It keeps the multiples of the generator once [`mul_generator`](Domain::mul_generator) has first
16/// needed them, as a [`Divisor`](crate::math::numbers::Divisor) keeps what it prepares.
17///
18/// # Examples
19///
20/// ```
21/// use a::math::ec::{Curve, Domain, Weierstrass};
22/// use a::math::numbers::{ByteOrder, Number};
23///
24/// let n = |x| Number::new_from_u32(x, ByteOrder::BigEndian);
25/// let curve = Weierstrass::new(&n(2), &n(3), &n(97)).unwrap();
26/// // (3, 6) has order 5, and the curve 100 points.
27/// let domain = Domain::new(curve, &n(3), &n(6), &n(5), &n(20)).unwrap();
28/// let p = domain.mul_generator(&n(2));
29/// assert_eq!(p, domain.generator().double());
30/// assert!(domain.in_subgroup(&p));
31/// ```
32pub struct Domain<C: Curve> {
33    /// The curve.
34    curve: C,
35    /// The generator's stored coordinates.
36    generator: Vec<u64>,
37    /// The order of the generator.
38    order: Number,
39    /// The curve's order over the generator's.
40    cofactor: Number,
41    /// The multiples of the generator, built when first needed.
42    table: OnceLock<Table>,
43}
44
45impl<C: Curve> Domain<C> {
46    /// `curve` with the generator `(x, y)` of the given order and cofactor.
47    ///
48    /// # Errors
49    ///
50    /// [`CurveError::NotOnCurve`] when `(x, y)` is not on the curve; [`CurveError::WrongOrder`]
51    /// when `order` is not positive or `order` times it is not the neutral element.
52    pub fn new(
53        curve: C,
54        x: &Number,
55        y: &Number,
56        order: &Number,
57        cofactor: &Number,
58    ) -> Result<Domain<C>, CurveError> {
59        let generator = {
60            let g = curve.point(x, y).map_err(|_| CurveError::NotOnCurve)?;
61            if !order.is_positive() || !(&g * order).is_identity() {
62                return Err(CurveError::WrongOrder);
63            }
64            g.limbs.clone()
65        };
66        Ok(Domain {
67            curve,
68            generator,
69            order: order.clone(),
70            cofactor: cofactor.clone(),
71            table: OnceLock::new(),
72        })
73    }
74
75    /// The generator.
76    pub fn generator(&self) -> Point<'_, C> {
77        Point::from_limbs(&self.curve, self.generator.clone())
78    }
79
80    /// The order of the generator.
81    pub fn order(&self) -> &Number {
82        &self.order
83    }
84
85    /// The number of points of the curve over the order of the generator.
86    pub fn cofactor(&self) -> &Number {
87        &self.cofactor
88    }
89
90    /// `k` times the generator, from a table of its multiples, several times faster than a product
91    /// of any other point. The first call builds the table.
92    pub fn mul_generator(&self, k: &Number) -> Point<'_, C> {
93        let table = self.table();
94        let k = k.rem_euclid(&self.order);
95        let mut limbs = vec![0; self.generator.len()];
96        self.curve
97            .prepared_limbs(&mut limbs, table, &limbs_of(&k), false);
98        Point::from_limbs(&self.curve, limbs)
99    }
100
101    /// `a` times the generator plus `b` times `point`, as a signature's verification needs.
102    ///
103    /// # Panics
104    ///
105    /// Panics if `point` is not on this curve.
106    pub fn mul_add<'c>(&'c self, a: &Number, b: &Number, point: &Point<'c, C>) -> Point<'c, C> {
107        point.check_curve(&self.curve);
108        self.mul_generator(a) + point * b
109    }
110
111    /// Whether `point` is on this curve and `order` times it is the neutral element. When the order
112    /// is coprime to the cofactor, as on every [named curve](super::named), those are the points
113    /// of the generator's subgroup. Otherwise more can be: on `y^2 = x^3 - x` modulo 5, with the
114    /// generator `(0, 0)` of order 2 and the cofactor 4, so is `(1, 0)`.
115    pub fn in_subgroup(&self, point: &Point<'_, C>) -> bool {
116        point.belongs_to(&self.curve) && (point * &self.order).is_identity()
117    }
118
119    /// `point` times the cofactor, which lands in the generator's subgroup when the order is
120    /// coprime to the cofactor.
121    ///
122    /// # Panics
123    ///
124    /// Panics if `point` is not on this curve.
125    pub fn clear_cofactor<'c>(&self, point: &Point<'c, C>) -> Point<'c, C> {
126        point.check_curve(&self.curve);
127        point * &self.cofactor
128    }
129
130    /// The multiples of the generator.
131    fn table(&self) -> &Table {
132        self.table.get_or_init(|| {
133            self.curve
134                .prepare_limbs(&self.generator, self.order.bits() as usize)
135        })
136    }
137}
138
139impl<C: Curve> Deref for Domain<C> {
140    type Target = C;
141
142    fn deref(&self) -> &C {
143        &self.curve
144    }
145}