#ifndef OTA_SIGNED_H
#define OTA_SIGNED_H

// ============================================================================
// ota_signed.h — Ed25519 signed-OTA chunk verification
//
// Extends the existing ota_adapter pattern with a verify-only Ed25519
// signature check. The public key is stored in NVS (namespace "pdl_pki",
// key "ed25519_pk") and can be seeded either from the enrollment response
// (auth_pubkey_first16 + OTA delivery of the remaining 16 bytes) or via a
// factory-provisioned NVS blob.
//
// The OTA chunk path only ever verifies -- no signing. ADDED 2026-07-30:
// Ed25519 keygen+sign and X25519 keygen, for reticulum_identity.{h,cpp}'s
// real RNS node identity (an RNS Identity holds BOTH an Ed25519 signing
// keypair and an X25519 encryption keypair, and needs to actually create
// them and sign its own announce packets, not just verify someone else's
// signature). These reuse this file's existing field-arithmetic/SHA-512
// primitives rather than duplicating them in a second module. Verified
// byte-exact against the real `cryptography` Python library -- see
// test/test_reticulum_identity/test_reticulum_identity.cpp.
//
// Typical call sequence from ota_handle_chunk():
//   1. ota_signed_get_pubkey(pk)        — load from NVS (once)
//   2. ota_signed_set_pubkey(pk)        — store in module if just loaded
//   3. ota_signed_verify_chunk(chunk, len, sig64) — before every apply
//      → reject (return false, do not apply) on failure
// ============================================================================

#include <cstdint>
#include <cstddef>
#include <stdbool.h>

// Ed25519 key / signature sizes (fixed by the algorithm)
#define ED25519_PUBKEY_BYTES  32
#define ED25519_SIG_BYTES     64

// NVS namespace and key for the stored public key
#define OTA_PKI_NVS_NS        "pdl_pki"
#define OTA_PKI_NVS_KEY       "ed25519_pk"

// ---------------------------------------------------------------------------
// Public-key management
// ---------------------------------------------------------------------------

// Write pk32 (32 bytes) as the active verification key, both in-module and
// persisted to NVS. Returns false if NVS write fails (key still cached
// in-module for the current session).
bool ota_signed_set_pubkey(const uint8_t* pk32);

// Load the public key from NVS into the supplied 32-byte buffer.
// Returns false if NVS key is absent or corrupt.
bool ota_signed_get_pubkey(uint8_t* pk32_out);

// ---------------------------------------------------------------------------
// Chunk verification
// ---------------------------------------------------------------------------

// Verify that Ed25519 signature sig64 (64 bytes) over chunk[0..len-1] is
// valid under the currently set public key.
//
// Returns false (silently) if:
//   - No public key has been set / loaded yet
//   - sig64 is nullptr
//   - The signature does not verify
//
// The caller MUST treat a false return as "reject this chunk" — do not
// pass it to ota_handle_chunk / ota_apply_model.
bool ota_signed_verify_chunk(const uint8_t* chunk, size_t len,
                             const uint8_t* sig64);

// ---------------------------------------------------------------------------
// Ed25519 / X25519 primitives (shared with reticulum_identity.{h,cpp})
// ---------------------------------------------------------------------------

// Deterministic Ed25519 keypair from a 32-byte seed (RFC 8032 / ref10
// convention). out_sk is the 64-byte EXPANDED secret key (seed || pubkey)
// that ed25519_sign() below expects -- not raw scalar bytes.
void ed25519_keypair_from_seed(const uint8_t seed[32], uint8_t out_pk[32], uint8_t out_sk[64]);

// Deterministic (RFC 8032) Ed25519 signature. sk must be the 64-byte
// expanded form from ed25519_keypair_from_seed().
void ed25519_sign(const uint8_t sk[64], const uint8_t* msg, size_t msg_len, uint8_t out_sig[64]);

// X25519 (RFC 7748) scalar multiplication. Internally clamps `scalar`, so
// pass the raw unclamped 32-byte private key directly -- works for both
// keypair generation (point = the fixed base point) and ECDH (point =
// peer's public key).
void x25519_scalarmult(const uint8_t scalar[32], const uint8_t point[32], uint8_t out[32]);

// X25519 keypair from a 32-byte seed. The private key IS the seed itself
// (RFC 7748 convention) -- callers keep `seed` and pass it to
// x25519_scalarmult() again later for ECDH.
void x25519_keypair_from_seed(const uint8_t seed[32], uint8_t out_pk[32]);

#endif // OTA_SIGNED_H
