// SPDX-License-Identifier: GPL-2.0-only
/*
 *  ppm/include/ppm/crypto.h
 *
 *  Copyright (C) 2026 Project Tick
 */

#ifndef PPM_CRYPTO_H
#define PPM_CRYPTO_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

#include <ppm/error.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Crypto primitives used throughout ppm.
 *
 * Hash:      SHA-512 (64-byte digest, hex-encoded as 128 chars + NUL).
 * Signature: Ed25519 (32-byte public key, 64-byte signature).
 *
 * All implementations are thin wrappers over libsodium. Do not introduce
 * alternative backends.
 */

#define PPM_SHA512_BYTES        64
#define PPM_SHA512_HEX_BYTES   128 /* without trailing NUL */
#define PPM_SHA512_HEX_BUFSZ   (PPM_SHA512_HEX_BYTES + 1)

#define PPM_ED25519_PK_BYTES    32
#define PPM_ED25519_SIG_BYTES   64

typedef struct ppm_sha512 {
    uint8_t bytes[PPM_SHA512_BYTES];
} ppm_sha512_t;

/* One-shot hashing helpers. */
ppm_error_t ppm_sha512_buf(const void *data, size_t len, ppm_sha512_t *out);
ppm_error_t ppm_sha512_file(const char *path, ppm_sha512_t *out);
ppm_error_t ppm_sha512_stream(FILE *stream, ppm_sha512_t *out);

/* Streaming API for hashing large or pipelined inputs. */
typedef struct ppm_sha512_ctx ppm_sha512_ctx_t;

ppm_error_t ppm_sha512_init(ppm_sha512_ctx_t **ctx);
ppm_error_t ppm_sha512_update(ppm_sha512_ctx_t *ctx, const void *data, size_t len);
ppm_error_t ppm_sha512_final(ppm_sha512_ctx_t *ctx, ppm_sha512_t *out);
void        ppm_sha512_free(ppm_sha512_ctx_t *ctx);

/* Hex encode/decode. `out` must point to at least PPM_SHA512_HEX_BUFSZ bytes. */
void        ppm_sha512_to_hex(const ppm_sha512_t *in, char *out);
ppm_error_t ppm_sha512_from_hex(const char *hex, ppm_sha512_t *out);

/* Constant-time compare. Returns true iff the two digests are byte-equal. */
bool ppm_sha512_equal(const ppm_sha512_t *a, const ppm_sha512_t *b);

/* Ed25519 signature verification. */
ppm_error_t ppm_ed25519_verify(const uint8_t pk[PPM_ED25519_PK_BYTES],
                               const uint8_t sig[PPM_ED25519_SIG_BYTES],
                               const void *msg, size_t msg_len);

/*
 * Decode a hex-encoded Ed25519 public key (64 hex chars => 32 bytes) or
 * detached signature (128 hex chars => 64 bytes) into the caller's buffer.
 * Surrounding whitespace and embedded newlines are ignored, so a key or
 * signature file with a trailing newline decodes cleanly. Returns
 * PPM_ERR_PARSE if the input is not valid hex of exactly the right length.
 */
ppm_error_t ppm_ed25519_pk_from_hex(const char *hex,
                                    uint8_t out[PPM_ED25519_PK_BYTES]);
ppm_error_t ppm_ed25519_sig_from_hex(const char *hex,
                                     uint8_t out[PPM_ED25519_SIG_BYTES]);

/* Initialise libsodium. Call exactly once at process start (main does this). */
ppm_error_t ppm_crypto_init(void);

#ifdef __cplusplus
}
#endif

#endif /* PPM_CRYPTO_H */
