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}