#ifndef HYPERSWARM_NOISE_STREAM_H
#define HYPERSWARM_NOISE_STREAM_H
#include <cstdint>
#include <vector>
#include <sodium.h>
// Symmetric stream encryption/decryption using XChaCha20-Poly1305.
// Used after Noise handshake completes to encrypt all game data.
//
// Each direction has its own state (initialised from the handshake-derived key).
// TX: encrypt outgoing data.
// RX: decrypt incoming data (requires the remote's TX header).
class NoiseStream {
public:
static constexpr int HEADER_BYTES = crypto_secretstream_xchacha20poly1305_HEADERBYTES; // 24
static constexpr int TAG_BYTES = crypto_secretstream_xchacha20poly1305_ABYTES; // 17
NoiseStream();
~NoiseStream();
// Initialise TX state from handshake-derived key.
// Generates a 24-byte header that must be sent to remote.
void init_tx(const uint8_t *key);
// Initialise RX state from handshake-derived key + remote's TX header.
bool init_rx(const uint8_t *key, const uint8_t *header);
// Encrypt plaintext → ciphertext (adds TAG_BYTES overhead).
std::vector<uint8_t> encrypt(const uint8_t *data, size_t len);
// Decrypt ciphertext → plaintext. Returns empty on auth failure.
std::vector<uint8_t> decrypt(const uint8_t *data, size_t len);
// ⛔ THE SAME CALL, WITH THE ONE ANSWER THE OTHER CANNOT GIVE.
//
// decrypt() returns {} for an authentication failure AND for a frame whose
// plaintext is legitimately empty, and those must be told apart: an EMPTY
// authenticated frame is the keepalive @hyperswarm/secret-stream sends
// (`sendKeepAlive` writes `this.alloc(0)`), and the reference eats it on
// receipt rather than treating it as an error. Conflating them means a
// keepalive is indistinguishable from an attack.
//
// Returns false only on authentication failure.
bool decrypt(const uint8_t *data, size_t len, std::vector<uint8_t> &out);
// Get the TX header (24 bytes, send to remote for their RX init).
const uint8_t *tx_header() const { return _tx_header; }
bool tx_ready() const { return _tx_init; }
bool rx_ready() const { return _rx_init; }
private:
crypto_secretstream_xchacha20poly1305_state _tx_state;
crypto_secretstream_xchacha20poly1305_state _rx_state;
uint8_t _tx_header[HEADER_BYTES];
bool _tx_init;
bool _rx_init;
};
#endif // HYPERSWARM_NOISE_STREAM_H