9#include <botan/internal/ed448_internal.h>
11#include <botan/exceptn.h>
12#include <botan/types.h>
14#include <botan/internal/buffer_slicer.h>
15#include <botan/internal/buffer_stuffer.h>
16#include <botan/internal/concat_util.h>
17#include <botan/internal/ct_utils.h>
18#include <botan/internal/loadstor.h>
23std::vector<uint8_t> dom4(uint8_t x, std::span<const uint8_t> y) {
32 store_le(
static_cast<uint8_t
>(y.size())),
37std::array<uint8_t, 2 * ED448_LEN> shake(
bool f, std::span<const uint8_t> context, Ts... xs) {
39 shake_xof->update(dom4(
static_cast<uint8_t
>(f), context));
40 (shake_xof->update(std::span(xs)), ...);
41 std::array<uint8_t, 2 * ED448_LEN> res{};
42 shake_xof->output(res);
46std::pair<std::span<const uint8_t, 57>, std::span<const uint8_t, 57>> split(std::span<const uint8_t, 114> arr) {
48 auto lhs = bs.take<57>();
49 auto rhs = bs.take<57>();
59 std::array<uint8_t, ED448_LEN> raw_s{};
60 shake_xof.output(raw_s);
80 if((enc.back() & 0x7F) != 0) {
81 throw Decoding_Error(
"Ed448 point has unacceptable x-distinguisher");
83 const bool x_distinguisher = enc.back() != 0;
84 const auto y_data = std::span(enc).first<56>();
105 if(v *
square(maybe_x) != u) {
111 if(maybe_x.is_zero() && x_distinguisher) {
114 const bool maybe_x_parity = maybe_x.
is_odd();
115 std::array<uint64_t, WORDS_448> x_data{};
117 .select_n(x_data.data(), maybe_x.words().data(), (-maybe_x).words().data(),
WORDS_448);
123 constexpr std::array<const uint64_t, WORDS_448>
x = {0x2626a82bc70cc05e,
130 constexpr std::array<const uint64_t, WORDS_448>
y = {0x9808795bf230fa14,
141 std::array<uint8_t, ED448_LEN> res_buf = {0};
148 y().
to_bytes(std::span(res_buf).first<56>());
152 res_buf.back() = (
static_cast<uint8_t
>(
x().
is_odd()) << 7);
166 const Gf448Elem H = (m_x + m_y) * (other.m_x + other.m_y);
167 const Gf448Elem X3 = A * F * (H - C - D);
208 for(
size_t i = 2; i < 16; ++i) {
210 table[i] = table[i / 2].double_point();
212 table[i] = table[i - 1] + *
this;
219 for(
int window = 111; window >= 0; --window) {
221 res = res.double_point();
222 res = res.double_point();
223 res = res.double_point();
224 res = res.double_point();
227 const uint64_t w = s.
get_window(
static_cast<size_t>(window) * 4, 4);
231 for(
size_t i = 0; i < 16; ++i) {
233 selected.ct_conditional_assign(correct_idx, table[i]);
236 res = res + selected;
248 constexpr size_t W = 4;
249 constexpr size_t WindowElements = (1 << W) - 1;
250 constexpr size_t Windows = (448 + W - 1) / W;
251 constexpr size_t TableSize = Windows * WindowElements;
253 static const auto table = []() {
258 for(
size_t i = 0; i < TableSize; i += WindowElements) {
261 for(
size_t j = 1; j < WindowElements; ++j) {
263 tbl[i + j] = tbl[i + j / 2].double_point();
265 tbl[i + j] = tbl[i + j - 1] + tbl[i];
277 for(
size_t i = 0; i != Windows; ++i) {
278 const uint8_t w =
static_cast<uint8_t
>(scalar.
get_window(i * W, W));
282 for(
size_t j = 0; j != WindowElements; ++j) {
284 selected.ct_conditional_assign(assign, table[i * WindowElements + j]);
287 res = res + selected;
303 const auto p1x3 = p1x2 + p1;
305 const auto p2x3 = p2x2 + p2;
308 const std::array<Ed448Point, 15> table = {
329 for(
int window = 222; window >= 0; --window) {
330 res = res.double_point();
331 res = res.double_point();
333 const size_t bit_pos =
static_cast<size_t>(window) * 2;
337 res = res + table[idx - 1];
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;
356 return (mask_x & mask_y).as_bool();
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);
373 shake_xof->update(sk);
375 const Scalar448 s = scalar_from_xof(*shake_xof);
382std::array<uint8_t, 2 * ED448_LEN>
sign_message(std::span<const uint8_t, ED448_LEN> sk,
383 std::span<const uint8_t, ED448_LEN> pk,
385 std::span<const uint8_t> context,
386 std::span<const uint8_t> msg) {
397 shake_xof->update(sk);
398 const Scalar448 s = scalar_from_xof(*shake_xof);
399 std::array<uint8_t, ED448_LEN> prefix{};
400 shake_xof->output(prefix);
405 const Scalar448 r(shake(pgflag, context, prefix, msg));
412 const Scalar448 k(shake(pgflag, context, big_r, pk, msg));
415 const auto big_s = r + k * s;
419 std::array<uint8_t, 2 * ED448_LEN> sig{};
430 std::span<const uint8_t> context,
431 std::span<const uint8_t> sig,
432 std::span<const uint8_t> msg) {
445 const auto [big_r_bytes, big_s_bytes] = split(sig.first<2 *
ED448_LEN>());
454 const Scalar448 k(shake(phflag, context, big_r_bytes, pk, msg));
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr void append(std::span< const uint8_t > buffer)
constexpr bool full() const
static constexpr Mask< T > is_equal(T x, T y)
static constexpr Mask< T > expand_bool(bool v)
Representation of a point on the Ed448 curve.
Ed448Point negate() const
Negate the point.
Gf448Elem y() const
Getter for point coordinate y.
static Ed448Point identity()
Return the identity element.
static Ed448Point base_point_mul(const Scalar448 &scalar)
Fixed base point scalar multiplication (precomputed table, no doublings).
Ed448Point(const Gf448Elem &x, const Gf448Elem &y, const Gf448Elem &z)
Create a point from its projective coordinates X, Y, Z.
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 decode(std::span< const uint8_t, ED448_LEN > enc)
Decode a point from its 57-byte encoding (RFC 8032 5.2.3).
Ed448Point scalar_mul(const Scalar448 &scalar) const
Scalar multiplication.
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).
void ct_conditional_assign(CT::Mask< uint64_t > mask, const Ed448Point &other)
Assign other to this if mask is set (constant time).
bool operator==(const Ed448Point &other) const
Check if two points are equal (constant time).
Ed448Point operator+(const Ed448Point &other) const
Add two points (RFC 8032 5.2.4).
Gf448Elem x() const
Getter for point coordinate x.
std::array< uint8_t, ED448_LEN > encode() const
Encode the point to its 57-byte representation (RFC 8032 5.2.2).
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.
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.
Representation of a scalar for X448.
uint32_t get_window(size_t starting_pos, size_t width) const
Extract a window of width bits starting at bit position starting_pos. Bits beyond position 445 are tr...
static bool bytes_are_reduced(std::span< const uint8_t > x)
static std::unique_ptr< XOF > create_or_throw(std::string_view algo_spec, std::string_view provider="")
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 operator*(const BigInt &x, const BigInt &y)
std::array< uint8_t, ED448_LEN > create_pk_from_sk(std::span< const uint8_t, ED448_LEN > sk)
Create a public key point from a secret key (RFC 8032 5.2.5).
BigInt square(const BigInt &x)
constexpr size_t ED448_LEN
constexpr auto store_le(ParamTs &&... params)
constexpr auto concat(Rs &&... ranges)
bool verify_signature(std::span< const uint8_t, ED448_LEN > pk, bool phflag, std::span< const uint8_t > context, std::span< const uint8_t > sig, std::span< const uint8_t > msg)
Verify a signature(RFC 8032 5.2.7).
constexpr size_t WORDS_448
std::array< uint8_t, 2 *ED448_LEN > sign_message(std::span< const uint8_t, ED448_LEN > sk, std::span< const uint8_t, ED448_LEN > pk, bool pgflag, std::span< const uint8_t > context, std::span< const uint8_t > msg)
Sign a message using a keypair (RFC 8032 5.2.6).