Botan 3.11.0
Crypto and TLS for C&
Botan::Ed448Point Class Referencefinal

Representation of a point on the Ed448 curve. More...

#include <ed448_internal.h>

Public Member Functions

void ct_conditional_assign (CT::Mask< uint64_t > mask, const Ed448Point &other)
 Assign other to this if mask is set (constant time).
Ed448Point double_point () const
 Double a point (RFC 8032 5.2.4).
 Ed448Point (const Gf448Elem &x, const Gf448Elem &y)
 Create a point from its coordinates x, y.
 Ed448Point (const Gf448Elem &x, const Gf448Elem &y, const Gf448Elem &z)
 Create a point from its projective coordinates X, Y, Z.
std::array< uint8_t, ED448_LENencode () const
 Encode the point to its 57-byte representation (RFC 8032 5.2.2).
Ed448Point negate () const
 Negate the point.
Ed448Point operator+ (const Ed448Point &other) const
 Add two points (RFC 8032 5.2.4).
bool operator== (const Ed448Point &other) const
 Check if two points are equal (constant time).
Ed448Point scalar_mul (const Scalar448 &scalar) const
 Scalar multiplication.
Gf448Elem x () const
 Getter for point coordinate x.
Gf448Elem x_proj () const
 Getter for projective coordinate X.
Gf448Elem y () const
 Getter for point coordinate y.
Gf448Elem y_proj () const
 Getter for projective coordinate Y.
Gf448Elem z_proj () const
 Getter for projective coordinate Z.

Static Public Member Functions

static Ed448Point base_point ()
 Create the curve's base point ('B' in RFC 8032 5.2).
static Ed448Point base_point_mul (const Scalar448 &scalar)
 Fixed base point scalar multiplication (precomputed table, no doublings).
static Ed448Point decode (std::span< const uint8_t, ED448_LEN > enc)
 Decode a point from its 57-byte encoding (RFC 8032 5.2.3).
static Ed448Point double_scalar_mul_vartime (const Scalar448 &s1, const Ed448Point &p1, const Scalar448 &s2, const Ed448Point &p2)
 Variable-time double scalar multiplication using Shamir's trick: [s1]P + [s2]Q.
static Ed448Point identity ()
 Return the identity element.

Detailed Description

Representation of a point on the Ed448 curve.

The point is represented in projective coordinates (X, Y, Z). All operations are constant time.

Definition at line 26 of file ed448_internal.h.

Constructor & Destructor Documentation

◆ Ed448Point() [1/2]

Botan::Ed448Point::Ed448Point ( const Gf448Elem & x,
const Gf448Elem & y,
const Gf448Elem & z )
inline

Create a point from its projective coordinates X, Y, Z.

Definition at line 35 of file ed448_internal.h.

35: m_x(x), m_y(y), m_z(z) {}
Gf448Elem y() const
Getter for point coordinate y.
Gf448Elem x() const
Getter for point coordinate x.

References x(), and y().

Referenced by base_point(), base_point_mul(), ct_conditional_assign(), decode(), double_point(), double_scalar_mul_vartime(), identity(), negate(), operator+(), operator==(), and scalar_mul().

◆ Ed448Point() [2/2]

Botan::Ed448Point::Ed448Point ( const Gf448Elem & x,
const Gf448Elem & y )
inline

Create a point from its coordinates x, y.

Definition at line 38 of file ed448_internal.h.

38: m_x(x), m_y(y), m_z(1) {}

References x(), and y().

Member Function Documentation

◆ base_point()

Ed448Point Botan::Ed448Point::base_point ( )
static

Create the curve's base point ('B' in RFC 8032 5.2).

Definition at line 122 of file ed448_internal.cpp.

122 {
123 constexpr std::array<const uint64_t, WORDS_448> x = {0x2626a82bc70cc05e,
124 0x433b80e18b00938e,
125 0x12ae1af72ab66511,
126 0xea6de324a3d3a464,
127 0x9e146570470f1767,
128 0x221d15a622bf36da,
129 0x4f1970c66bed0ded};
130 constexpr std::array<const uint64_t, WORDS_448> y = {0x9808795bf230fa14,
131 0xfdbd132c4ed7c8ad,
132 0x3ad3ff1ce67c39c4,
133 0x87789c1e05a0c2d7,
134 0x4bea73736ca39840,
135 0x8876203756c9c762,
136 0x693f46716eb6bc24};
137 return Ed448Point(Gf448Elem(x), Gf448Elem(y));
138}
Ed448Point(const Gf448Elem &x, const Gf448Elem &y, const Gf448Elem &z)
Create a point from its projective coordinates X, Y, Z.

References Ed448Point(), x(), and y().

Referenced by base_point_mul(), and Botan::verify_signature().

◆ base_point_mul()

Ed448Point Botan::Ed448Point::base_point_mul ( const Scalar448 & scalar)
static

Fixed base point scalar multiplication (precomputed table, no doublings).

Definition at line 242 of file ed448_internal.cpp.

242 {
243 /*
244 Fixed base point multiplication
245
246 Same idea as base point multiply used in pcurves
247 */
248 constexpr size_t W = 4;
249 constexpr size_t WindowElements = (1 << W) - 1; // 15
250 constexpr size_t Windows = (448 + W - 1) / W; // 112
251 constexpr size_t TableSize = Windows * WindowElements; // 1680
252
253 static const auto table = []() {
254 std::vector<Ed448Point> tbl(TableSize, Ed448Point::identity());
255
256 auto accum = Ed448Point::base_point();
257
258 for(size_t i = 0; i < TableSize; i += WindowElements) {
259 tbl[i] = accum;
260
261 for(size_t j = 1; j < WindowElements; ++j) {
262 if(j % 2 == 1) {
263 tbl[i + j] = tbl[i + j / 2].double_point();
264 } else {
265 tbl[i + j] = tbl[i + j - 1] + tbl[i];
266 }
267 }
268
269 accum = tbl[i + (WindowElements / 2)].double_point();
270 }
271
272 return tbl;
273 }();
274
275 auto res = Ed448Point::identity();
276
277 for(size_t i = 0; i != Windows; ++i) {
278 const uint8_t w = static_cast<uint8_t>(scalar.get_window(i * W, W));
279
280 // Constant-time table lookup from this window's 15-entry subtable
281 auto selected = Ed448Point::identity();
282 for(size_t j = 0; j != WindowElements; ++j) {
283 const auto assign = CT::Mask<uint64_t>::is_equal(j + 1, w);
284 selected.ct_conditional_assign(assign, table[i * WindowElements + j]);
285 }
286
287 res = res + selected;
288 }
289
290 return res;
291}
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:442
static Ed448Point identity()
Return the identity element.
Ed448Point double_point() const
Double a point (RFC 8032 5.2.4).
static Ed448Point base_point()
Create the curve's base point ('B' in RFC 8032 5.2).

References base_point(), double_point(), Ed448Point(), Botan::Scalar448::get_window(), identity(), and Botan::CT::Mask< T >::is_equal().

Referenced by Botan::create_pk_from_sk(), and Botan::sign_message().

◆ ct_conditional_assign()

void Botan::Ed448Point::ct_conditional_assign ( CT::Mask< uint64_t > mask,
const Ed448Point & other )

Assign other to this if mask is set (constant time).

Definition at line 359 of file ed448_internal.cpp.

359 {
360 m_x.ct_cond_assign(mask, other.m_x);
361 m_y.ct_cond_assign(mask, other.m_y);
362 m_z.ct_cond_assign(mask, other.m_z);
363}

References Ed448Point().

◆ decode()

Ed448Point Botan::Ed448Point::decode ( std::span< const uint8_t, ED448_LEN > enc)
static

Decode a point from its 57-byte encoding (RFC 8032 5.2.3).

Definition at line 73 of file ed448_internal.cpp.

73 {
74 // RFC 8032 5.2.3 Decoding
75 // 1. First, interpret the string as an integer in little-endian
76 // representation. Bit 455 of this number is the least significant
77 // bit of the x-coordinate, and denote this value x_0. The
78 // y-coordinate is recovered simply by clearing this bit. If the
79 // resulting value is >= p, decoding fails.
80 if((enc.back() & 0x7F) != 0) { // last byte is either 0x00 or 0x80
81 throw Decoding_Error("Ed448 point has unacceptable x-distinguisher");
82 }
83 const bool x_distinguisher = enc.back() != 0;
84 const auto y_data = std::span(enc).first<56>();
86 throw Decoding_Error("Ed448 y-coordinate is not smaller than p");
87 }
88 const auto y = Gf448Elem(y_data);
89
90 // 2. To recover the x-coordinate, the curve equation implies
91 // x^2 = (y^2 - 1) / (d y^2 - 1) (mod p). The denominator is always
92 // non-zero mod p. Let u = y^2 - 1 and v = d y^2 - 1. To compute
93 // the square root of (u/v), the first step is to compute the
94 // candidate root x = (u/v)^((p+1)/4). This can be done using the
95 // following trick, to use a single modular powering for both the
96 // inversion of v and the square root:
97 // (p+1)/4 3 (p-3)/4
98 // x = (u/v) = u v (u^5 v^3) (mod p)
99 const auto u = square(Gf448Elem(y)) - Gf448Elem::one();
100 const auto v = -mul_a24(square(Gf448Elem(y))) - Gf448Elem::one();
101 const auto maybe_x = (u * square(u)) * v * root((square(square(u)) * u) * square(v) * v);
102
103 // 3. If v * x^2 = u, the recovered x-coordinate is x. Otherwise, no
104 // square root exists, and the decoding fails.
105 if(v * square(maybe_x) != u) {
106 throw Decoding_Error("Square root does not exist");
107 }
108 // 4. Finally, use the x_0 bit to select the right square root. If
109 // x = 0, and x_0 = 1, decoding fails. Otherwise, if x_0 != x mod
110 // 2, set x <-- p - x. Return the decoded point (x,y).
111 if(maybe_x.is_zero() && x_distinguisher) {
112 throw Decoding_Error("Square root of zero cannot be odd");
113 }
114 const bool maybe_x_parity = maybe_x.is_odd();
115 std::array<uint64_t, WORDS_448> x_data{};
116 CT::Mask<uint64_t>::expand_bool(maybe_x_parity == x_distinguisher)
117 .select_n(x_data.data(), maybe_x.words().data(), (-maybe_x).words().data(), WORDS_448);
118
119 return {Gf448Elem(x_data), y};
120}
static constexpr Mask< T > expand_bool(bool v)
Definition ct_utils.h:397
static bool bytes_are_canonical_representation(std::span< const uint8_t, BYTES_448 > x)
Given 56 bytes, checks that the (little endian) number from this bytes is a valid GF element,...
bool is_odd() const
Return true iff this element is odd. Constant time.
static Gf448Elem one()
Definition curve448_gf.h:64
Gf448Elem mul_a24(const Gf448Elem &a)
Multiply a field element by the Curve448 constant a24 = 39081.
Gf448Elem root(const Gf448Elem &elem)
Compute the root of elem in the field.
BigInt square(const BigInt &x)
Definition numthry.cpp:184
constexpr size_t WORDS_448
Definition curve448_gf.h:23

References Botan::Gf448Elem::bytes_are_canonical_representation(), Ed448Point(), Botan::CT::Mask< T >::expand_bool(), Botan::Gf448Elem::is_odd(), Botan::mul_a24(), Botan::Gf448Elem::one(), Botan::root(), Botan::square(), Botan::WORDS_448, and y().

Referenced by Botan::Ed448_PublicKey::check_key(), and Botan::verify_signature().

◆ double_point()

Ed448Point Botan::Ed448Point::double_point ( ) const

Double a point (RFC 8032 5.2.4).

Definition at line 174 of file ed448_internal.cpp.

174 {
175 // RFC 8032 5.2.4. - Point Addition (Double)
176 const Gf448Elem B = square(m_x + m_y);
177 const Gf448Elem C = square(m_x);
178 const Gf448Elem D = square(m_y);
179 const Gf448Elem E = C + D;
180 const Gf448Elem H = square(m_z);
181 const Gf448Elem J = E - (H + H);
182 const Gf448Elem X3 = (B - E) * J;
183 const Gf448Elem Y3 = E * (C - D);
184 const Gf448Elem Z3 = E * J;
185
186 return Ed448Point(X3, Y3, Z3);
187}

References Ed448Point(), and Botan::square().

Referenced by base_point_mul(), and double_scalar_mul_vartime().

◆ double_scalar_mul_vartime()

Ed448Point Botan::Ed448Point::double_scalar_mul_vartime ( const Scalar448 & s1,
const Ed448Point & p1,
const Scalar448 & s2,
const Ed448Point & p2 )
static

Variable-time double scalar multiplication using Shamir's trick: [s1]P + [s2]Q.

Definition at line 293 of file ed448_internal.cpp.

296 {
297 // 2-bit 2-ary Shamir's trick (variable time)
298 // Process 2 bits from each scalar per iteration, using a 16-entry table.
299 // table[w1 | (w2 << 2)] = w1*p1 + w2*p2, for w1,w2 in 0..3.
300
301 // Precompute small multiples of each point
302 const auto p1x2 = p1.double_point();
303 const auto p1x3 = p1x2 + p1;
304 const auto p2x2 = p2.double_point();
305 const auto p2x3 = p2x2 + p2;
306
307 // Build table indexed by (w2 << 2) | w1, excluding identity at index 0
308 const std::array<Ed448Point, 15> table = {
309 p1, // 1*p1 + 0*p2
310 p1x2, // 2*p1 + 0*p2
311 p1x3, // 3*p1 + 0*p2
312 p2, // 0*p1 + 1*p2
313 p1 + p2, // 1*p1 + 1*p2
314 p1x2 + p2, // 2*p1 + 1*p2
315 p1x3 + p2, // 3*p1 + 1*p2
316 p2x2, // 0*p1 + 2*p2
317 p1 + p2x2, // 1*p1 + 2*p2
318 p1x2 + p2x2, // 2*p1 + 2*p2
319 p1x3 + p2x2, // 3*p1 + 2*p2
320 p2x3, // 0*p1 + 3*p2
321 p1 + p2x3, // 1*p1 + 3*p2
322 p1x2 + p2x3, // 2*p1 + 3*p2
323 p1x3 + p2x3, // 3*p1 + 3*p2
324 };
325
326 auto res = Ed448Point::identity();
327
328 // 446 bits / 2 = 223 windows, covering bit positions 0..445
329 for(int window = 222; window >= 0; --window) {
330 res = res.double_point();
331 res = res.double_point();
332
333 const size_t bit_pos = static_cast<size_t>(window) * 2;
334 const size_t idx = s1.get_window(bit_pos, 2) | (s2.get_window(bit_pos, 2) << 2);
335
336 if(idx > 0) {
337 res = res + table[idx - 1];
338 }
339 }
340
341 return res;
342}

References double_point(), Ed448Point(), Botan::Scalar448::get_window(), and identity().

Referenced by Botan::verify_signature().

◆ encode()

std::array< uint8_t, ED448_LEN > Botan::Ed448Point::encode ( ) const

Encode the point to its 57-byte representation (RFC 8032 5.2.2).

Definition at line 140 of file ed448_internal.cpp.

140 {
141 std::array<uint8_t, ED448_LEN> res_buf = {0};
142
143 // RFC 8032 5.2.2
144 // All values are coded as octet strings, and integers are coded using
145 // little-endian convention. [...]
146 // First, encode the y-coordinate as a little-endian string of 57 octets.
147 // The final octet is always zero.
148 y().to_bytes(std::span(res_buf).first<56>());
149
150 // To form the encoding of the point, copy the least significant bit of
151 // the x-coordinate to the most significant bit of the final octet.
152 res_buf.back() = (static_cast<uint8_t>(x().is_odd()) << 7);
153
154 return res_buf;
155}
void to_bytes(std::span< uint8_t, BYTES_448 > out) const
Store the canonical representation of the GF element as 56 bytes in little-endian order.

References Botan::Gf448Elem::is_odd(), Botan::Gf448Elem::to_bytes(), x(), and y().

Referenced by Botan::create_pk_from_sk(), and Botan::sign_message().

◆ identity()

Ed448Point Botan::Ed448Point::identity ( )
inlinestatic

Return the identity element.

Definition at line 41 of file ed448_internal.h.

static Gf448Elem zero()
Definition curve448_gf.h:59

References Ed448Point(), Botan::Gf448Elem::one(), and Botan::Gf448Elem::zero().

Referenced by base_point_mul(), double_scalar_mul_vartime(), and scalar_mul().

◆ negate()

Ed448Point Botan::Ed448Point::negate ( ) const
inline

Negate the point.

Definition at line 65 of file ed448_internal.h.

65{ return Ed448Point(-m_x, m_y, m_z); }

References Ed448Point().

Referenced by Botan::verify_signature().

◆ operator+()

Ed448Point Botan::Ed448Point::operator+ ( const Ed448Point & other) const

Add two points (RFC 8032 5.2.4).

Definition at line 157 of file ed448_internal.cpp.

157 {
158 // RFC 8032 5.2.4. - Point Addition (Add)
159 const Gf448Elem A = m_z * other.m_z;
160 const Gf448Elem B = square(A);
161 const Gf448Elem C = m_x * other.m_x;
162 const Gf448Elem D = m_y * other.m_y;
163 const Gf448Elem E = -mul_a24(C * D);
164 const Gf448Elem F = B - E;
165 const Gf448Elem G = B + E;
166 const Gf448Elem H = (m_x + m_y) * (other.m_x + other.m_y);
167 const Gf448Elem X3 = A * F * (H - C - D);
168 const Gf448Elem Y3 = A * G * (D - C);
169 const Gf448Elem Z3 = F * G;
170
171 return Ed448Point(X3, Y3, Z3);
172}

References Ed448Point(), Botan::mul_a24(), and Botan::square().

◆ operator==()

bool Botan::Ed448Point::operator== ( const Ed448Point & other) const

Check if two points are equal (constant time).

Definition at line 344 of file ed448_internal.cpp.

344 {
345 // Compare in projective coordinates: (X1:Y1:Z1) == (X2:Y2:Z2)
346 // iff X1*Z2 == X2*Z1 && Y1*Z2 == Y2*Z1
347 // This avoids two field inversions that x() and y() would require.
348 const auto lhs_x = m_x * other.m_z;
349 const auto rhs_x = other.m_x * m_z;
350 const auto lhs_y = m_y * other.m_z;
351 const auto rhs_y = other.m_y * m_z;
352
353 const auto mask_x = CT::Mask<uint8_t>::expand_bool(lhs_x == rhs_x);
354 const auto mask_y = CT::Mask<uint8_t>::expand_bool(lhs_y == rhs_y);
355
356 return (mask_x & mask_y).as_bool();
357}

References Ed448Point(), and Botan::CT::Mask< T >::expand_bool().

◆ scalar_mul()

Ed448Point Botan::Ed448Point::scalar_mul ( const Scalar448 & scalar) const

Scalar multiplication.

Definition at line 189 of file ed448_internal.cpp.

189 {
190 // 4-bit windowed scalar multiplication.
191 std::array<Ed448Point, 16> table = {Ed448Point::identity(),
192 *this,
207
208 for(size_t i = 2; i < 16; ++i) {
209 if(i % 2 == 0) {
210 table[i] = table[i / 2].double_point();
211 } else {
212 table[i] = table[i - 1] + *this;
213 }
214 }
215
216 // Process 448 bits (446-bit scalar + 2 leading zero bits) in 112 4-bit windows
217 auto res = Ed448Point::identity();
218
219 for(int window = 111; window >= 0; --window) {
220 // Double 4 times
221 res = res.double_point();
222 res = res.double_point();
223 res = res.double_point();
224 res = res.double_point();
225
226 // Extract 4-bit window value. Bits at position >= 446 are zero.
227 const uint64_t w = s.get_window(static_cast<size_t>(window) * 4, 4);
228
229 // Constant-time table lookup
230 auto selected = Ed448Point::identity();
231 for(size_t i = 0; i < 16; ++i) {
232 const auto correct_idx = CT::Mask<uint64_t>::is_equal(static_cast<uint64_t>(i), w);
233 selected.ct_conditional_assign(correct_idx, table[i]);
234 }
235
236 res = res + selected;
237 }
238
239 return res;
240}

References Ed448Point(), Botan::Scalar448::get_window(), identity(), and Botan::CT::Mask< T >::is_equal().

Referenced by Botan::operator*().

◆ x()

Gf448Elem Botan::Ed448Point::x ( ) const
inline

Getter for point coordinate x.

Definition at line 77 of file ed448_internal.h.

77{ return m_x / m_z; }

Referenced by base_point(), Ed448Point(), Ed448Point(), and encode().

◆ x_proj()

Gf448Elem Botan::Ed448Point::x_proj ( ) const
inline

Getter for projective coordinate X.

Definition at line 68 of file ed448_internal.h.

68{ return m_x; }

◆ y()

Gf448Elem Botan::Ed448Point::y ( ) const
inline

Getter for point coordinate y.

Definition at line 80 of file ed448_internal.h.

80{ return m_y / m_z; }

Referenced by base_point(), decode(), Ed448Point(), Ed448Point(), and encode().

◆ y_proj()

Gf448Elem Botan::Ed448Point::y_proj ( ) const
inline

Getter for projective coordinate Y.

Definition at line 71 of file ed448_internal.h.

71{ return m_y; }

◆ z_proj()

Gf448Elem Botan::Ed448Point::z_proj ( ) const
inline

Getter for projective coordinate Z.

Definition at line 74 of file ed448_internal.h.

74{ return m_z; }

The documentation for this class was generated from the following files: