9#include <botan/internal/ed448_internal.h>
11#include <botan/exceptn.h>
12#include <botan/types.h>
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/loadstor.h>
15#include <botan/internal/shake_xof.h>
16#include <botan/internal/stl_util.h>
21constexpr uint64_t MINUS_D = 39081;
23std::vector<uint8_t> dom4(uint8_t x, std::span<const uint8_t> y) {
32 store_le(
static_cast<uint8_t
>(y.size())),
36template <ranges::spanable_range... Ts>
37std::array<uint8_t, 2 * ED448_LEN> shake(
bool f, std::span<const uint8_t> context, Ts... xs) {
38 auto shake_xof = SHAKE_256_XOF();
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>();
53Scalar448 scalar_from_xof(XOF& shake_xof) {
59 std::array<uint8_t, ED448_LEN> raw_s;
60 shake_xof.output(raw_s);
68 return Scalar448(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>();
106 if(v *
square(maybe_x) != u) {
112 if(maybe_x.is_zero() && x_distinguisher) {
115 bool maybe_x_parity = maybe_x.
is_odd();
116 std::array<uint64_t, WORDS_448> x_data;
118 .select_n(x_data.data(), maybe_x.words().data(), (-maybe_x).words().data(), 7);
124 constexpr std::array<const uint64_t, WORDS_448>
x = {0x2626a82bc70cc05e,
131 constexpr std::array<const uint64_t, WORDS_448>
y = {0x9808795bf230fa14,
142 std::array<uint8_t, ED448_LEN> res_buf = {0};
149 y().
to_bytes(std::span(res_buf).first<56>());
153 res_buf.back() = (
static_cast<uint8_t
>(
x().
is_odd()) << 7);
167 const Gf448Elem H = (m_x + m_y) * (other.m_x + other.m_y);
168 const Gf448Elem X3 = A * F * (H - C - D);
197 for(int16_t i = 445; i >= 0; --i) {
200 auto add_sum = res + *
this;
211 return (mask_x & mask_y).as_bool();
228 shake_xof.update(sk);
230 const Scalar448 s = scalar_from_xof(shake_xof);
237std::array<uint8_t, 2 * ED448_LEN>
sign_message(std::span<const uint8_t, ED448_LEN> sk,
238 std::span<const uint8_t, ED448_LEN> pk,
240 std::span<const uint8_t> context,
241 std::span<const uint8_t> msg) {
252 shake_xof.update(sk);
253 const Scalar448 s = scalar_from_xof(shake_xof);
254 std::array<uint8_t, ED448_LEN> prefix;
255 shake_xof.output(prefix);
260 const Scalar448 r(shake(pgflag, context, prefix, msg));
267 const Scalar448 k(shake(pgflag, context, big_r, pk, msg));
270 const auto big_s = r + k * s;
274 std::array<uint8_t, 2 * ED448_LEN> sig;
285 std::span<const uint8_t> context,
286 std::span<const uint8_t> sig,
287 std::span<const uint8_t> msg) {
300 const auto [big_r_bytes, big_s_bytes] = split(sig.first<2 *
ED448_LEN>());
309 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 > expand(T v)
Representation of a point on the Ed448 curve.
Gf448Elem y() const
Getter for point coordinate y.
Ed448Point(const Gf448Elem &x, const Gf448Elem &y, const Gf448Elem &z)
Create a point from its projective coordinates X, Y, Z.
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)
void ct_conditional_assign(bool cond, const Ed448Point &other)
Assign other to this if cond is true (constant time)
static Ed448Point base_point()
Create the curve's base point ('B' in RFC 8032 5.2)
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,...
void ct_cond_assign(bool b, const Gf448Elem &other)
Set this to other if b is true. Constant time for any b.
bool is_odd() const
Return true iff this element is odd. Constant time.
Representation of a scalar for X448.
static bool bytes_are_reduced(std::span< const uint8_t > x)
bool get_bit(size_t i) const
Access the i-th bit of the scalar. From 0 (lsb) to 445 (msb).
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)
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)
BigInt square(const BigInt &x)
constexpr size_t ED448_LEN
constexpr auto store_le(ParamTs &&... params)
constexpr auto concat(Rs &&... ranges)
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)