// RFC-4253

#ifndef DSSH_TRANS_H
#define DSSH_TRANS_H

#include <stdatomic.h>
#include <threads.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Forward declarations -- full definitions in ssh-internal.h */
struct dssh_session_s;
struct dssh_channel_s;
struct dssh_tx_iov; /* full definition in deucessh.h */

/* Module type definitions -- public headers */
#include "deucessh-comp.h"
#include "deucessh-enc.h"
#include "deucessh-kex.h"
#include "deucessh-key-algo.h"
#include "deucessh-lang.h"
#include "deucessh-mac.h"

/* Transport layer generic */
#define SSH_MSG_DISCONNECT      UINT8_C(1)
#define SSH_MSG_IGNORE          UINT8_C(2)
#define SSH_MSG_UNIMPLEMENTED   UINT8_C(3)
#define SSH_MSG_DEBUG           UINT8_C(4)
#define SSH_MSG_SERVICE_REQUEST UINT8_C(5)
#define SSH_MSG_SERVICE_ACCEPT  UINT8_C(6)

/* Transport layer Algorithm negotiation */
#define SSH_MSG_KEXINIT UINT8_C(20)
#define SSH_MSG_NEWKEYS UINT8_C(21)

/* SSH_MSG_KEX_ECDH_INIT/REPLY are now in deucessh-kex.h */

/* SSH_MSG_DISCONNECT reason codes */
#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT    DSSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT
#define SSH_DISCONNECT_PROTOCOL_ERROR                 DSSH_DISCONNECT_PROTOCOL_ERROR
#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED            DSSH_DISCONNECT_KEY_EXCHANGE_FAILED
#define SSH_DISCONNECT_RESERVED                       DSSH_DISCONNECT_RESERVED
#define SSH_DISCONNECT_MAC_ERROR                      DSSH_DISCONNECT_MAC_ERROR
#define SSH_DISCONNECT_COMPRESSION_ERROR              DSSH_DISCONNECT_COMPRESSION_ERROR
#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE          DSSH_DISCONNECT_SERVICE_NOT_AVAILABLE
#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED DSSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED
#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE        DSSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE
#define SSH_DISCONNECT_CONNECTION_LOST                DSSH_DISCONNECT_CONNECTION_LOST
#define SSH_DISCONNECT_BY_APPLICATION                 DSSH_DISCONNECT_BY_APPLICATION
#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS           DSSH_DISCONNECT_TOO_MANY_CONNECTIONS
#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER         DSSH_DISCONNECT_AUTH_CANCELLED_BY_USER
#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE DSSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE
#define SSH_DISCONNECT_ILLEGAL_USER_NAME              DSSH_DISCONNECT_ILLEGAL_USER_NAME

/*
 * RFC 4253 s6.1: implementations MUST be able to process packets with
 * an uncompressed payload length of 32768 bytes or less.
 * Total packet = 4 (length) + 1 (padding_length) + payload + padding.
 * With max padding of 255 bytes, minimum buffer = 32768 + 260 = 33028.
 * We round up for alignment.
 */
#define SSH_BPP_PACKET_SIZE_MIN 33280
#define SSH_BPP_PACKET_SIZE_MAX (64 * 1024 * 1024) /* 64 MiB */

/* Module type definitions are now in the public headers above. */

/*
 * Messages buffered during self-initiated rekey (kexinit wait loop).
 * RFC 4253 s7.1: the peer may send connection-layer messages before
 * seeing our KEXINIT.  These are replayed through recv_packet() after
 * rekey completes.
 */
struct dssh_rekey_msg {
	struct dssh_rekey_msg *next;
	uint8_t                msg_type;
	size_t                 len;
	uint8_t                data[];
};

/*
 * Pre-allocated TX slot for fire-and-forget demux responses.
 * Each slot holds a complete packet buffer (same layout as tx_packet)
 * sized to the negotiated block_size and mac_digest.  The demux thread
 * writes the payload at buf[9]; drain_tx_slots() finalizes and sends.
 *
 * Session-level: global_reply (1 B), open_fail (16 B).
 * Channel-level: wa (9 B), chan_fail (8 B).
 */
struct dssh_tx_slot {
	_Atomic bool ready;       /* demux sets true; drain clears        */
	uint8_t      payload_len; /* bytes written at buf[9]              */
	size_t       buf_sz;      /* current allocation (for rekey resize)*/
	uint8_t     *buf;         /* packet buffer, or NULL before KEX    */
};

/* Rekey thresholds.  Packet limits per RFC 4344 s3.1 (MAC-tag
 * leakage); byte limit is per-module via dssh_enc_s::bytes_per_key
 * (RFC 4344 s3.2).  DSSH_REKEY_SECONDS is the historical 1-hour
 * suggestion (off by default; opt in via
 * dssh_session_set_rekey_seconds). */
#define DSSH_REKEY_SOFT_LIMIT UINT32_C(0x10000000) /* 2^28 packets */
#define DSSH_REKEY_HARD_LIMIT UINT32_C(0x80000000) /* 2^31 packets */
#define DSSH_REKEY_SECONDS    3600                 /* 1 hour */

struct dssh_transport_state_s {
	/* 8-byte fixed */
	uint64_t rx_bytes_since_rekey; /* bytes received since last (re)key (RX owner) */
	time_t   rekey_time;           /* time of last (re)key */

				       /* Pointers and size_t (pointer-sized) */
	size_t packet_buf_sz;
	/*
	 * Packet buffer layout (tx_packet and rx_packet):
	 *   [seq(4)][pkt_length(4)][padding_length(1)][payload][padding][MAC]
	 * Allocated as 4 + packet_buf_sz bytes.  The 4-byte seq prefix
	 * makes the MAC input (seq || unencrypted_packet) contiguous,
	 * eliminating the separate mac_scratch buffers.
	 * Only [pkt_length..padding] is encrypted; only [pkt_length..MAC]
	 * is sent on the wire (seq prefix is local-only).
	 */
	uint8_t               *tx_packet;
	uint8_t               *rx_packet;
	uint8_t               *rx_mac_buf;      /* received MAC from wire (digest_size bytes) */
	uint8_t               *rx_mac_computed; /* computed MAC for comparison */
	size_t                 id_str_sz;
	size_t                 remote_id_str_sz;
	char                 **remote_languages;
	_Atomic dssh_kex       kex_selected;
	size_t                 shared_secret_sz;
	uint8_t               *shared_secret;
	size_t                 exchange_hash_sz;
	uint8_t               *exchange_hash;
	size_t                 session_id_sz;
	uint8_t               *session_id;
	size_t                 our_kexinit_sz;
	uint8_t               *our_kexinit;
	size_t                 peer_kexinit_sz;
	uint8_t               *peer_kexinit;
	struct dssh_rekey_msg *rekey_queue_head;  /* buffered msgs during kexinit */
	struct dssh_rekey_msg *rekey_queue_tail;
	struct dssh_tx_slot    global_reply_slot; /* REQUEST_SUCCESS/FAILURE (1 B) */
	struct dssh_tx_slot    open_fail_slot;    /* CHANNEL_OPEN_FAILURE (16 B)   */
	_Atomic dssh_key_algo  key_algo_selected;
	dssh_enc_ctx          *enc_c2s_ctx;
	_Atomic dssh_enc       enc_c2s_selected;
	dssh_enc_ctx          *enc_s2c_ctx;
	_Atomic dssh_enc       enc_s2c_selected;
	dssh_mac_ctx          *mac_c2s_ctx;
	_Atomic dssh_mac       mac_c2s_selected;
	dssh_mac_ctx          *mac_s2c_ctx;
	_Atomic dssh_mac       mac_s2c_selected;
	dssh_comp_ctx         *comp_c2s_ctx;
	_Atomic dssh_comp      comp_c2s_selected;
	dssh_comp_ctx         *comp_s2c_ctx;
	_Atomic dssh_comp      comp_s2c_selected;

	/* C11 synchronization (platform-dependent size) */
	cnd_t rekey_cnd;    /* wakes senders blocked by TX ownership/rekey */
	/* tx_mtx protects only ownership/rekey predicates.  It is never held
	 * while packet data is built or an I/O/module callback is invoked. */
	mtx_t tx_mtx;
	mtx_t tx_queue_mtx; /* protects tx_queue and tx_slot_cnd */
	cnd_t tx_slot_cnd;  /* wakes demux stalled on occupied slot */
	/* Atomic TX counters -- read lock-free by rekey_needed() (RX
	 * owner), written by the exclusive packet-engine owner. */
	atomic_uint_fast32_t tx_since_rekey;
	atomic_uint_fast64_t tx_bytes_since_rekey;

	/* 4-byte */
	uint32_t tx_seq;
	uint32_t rx_seq;
	uint32_t rx_since_rekey; /* packets received since last (re)key (RX owner) */
	uint32_t last_rx_seq;    /* seq number of last received packet */
	uint32_t rekey_seconds;  /* time-based rekey threshold; 0 = disabled */

				 /* Pointer-sized — round-robin index for fair channel slot drain */
	size_t drain_next_ch;

	/* 1-byte */
	bool        client;
	atomic_bool rekey_in_progress;     /* true between KEXINIT and NEWKEYS */
	atomic_bool tx_owner_active;       /* exclusive packet-engine owner */
	bool        rekey_pending;         /* deferred auto-rekey (set in recv_packet) */
	bool        tx_slots_pending;      /* protected by tx_queue_mtx */

				       /* Char arrays (naturally aligned, go last) */
	char id_str[254];
	char remote_id_str[254];
};

/*
 * Algorithm registration -- call before any session is initialized.
 * Registration order determines negotiation preference (first registered
 * is most preferred).  Returns 0 on success.  After the first
 * transport_init() call, registration is locked.
 *
 * Applications may register their own custom modules alongside or
 * instead of the library's built-in algorithms.
 */
/* register_kex/key_algo/enc/mac/comp/lang are now in their public headers */
/*
 * Initialize transport state for a session.  Allocates packet buffers
 * sized to max_packet_size (pass 0 for the RFC minimum of 33280 bytes).
 * Locks the algorithm registry on first call.  Returns 0 on success.
 */
/* Public transport functions declared in deucessh.h:
 *   dssh_transport_handshake, dssh_transport_disconnect,
 *   dssh_transport_get_remote_version, dssh_transport_get_kex_name,
 *   dssh_transport_get_hostkey_name, dssh_transport_get_enc_name,
 *   dssh_transport_get_mac_name
 */
/* ================================================================
 * Internal functions -- used by other library modules, not by
 * applications.  DSSH_PRIVATE in shared builds.
 * ================================================================ */
DSSH_PRIVATE int      tx_finalize(struct dssh_session_s *sess, uint8_t *buf, size_t payload_len);
DSSH_PRIVATE void     drain_tx_slots(struct dssh_session_s *sess);
DSSH_PRIVATE int      send_packet(struct dssh_session_s *sess, const uint8_t *payload, size_t payload_len,
	 uint32_t *seq_out);
DSSH_PRIVATE uint8_t *send_begin(struct dssh_session_s *sess, uint8_t msg_type, size_t *max_len, int *err_out);
DSSH_PRIVATE int      send_commit(struct dssh_session_s *sess, size_t payload_len, uint32_t *seq_out);
DSSH_PRIVATE int      send_commit_sensitive(struct dssh_session_s *sess, size_t payload_len, uint32_t *seq_out);
DSSH_PRIVATE void     send_cancel(struct dssh_session_s *sess);
DSSH_PRIVATE int      send_to_slot(struct dssh_session_s *sess, struct dssh_tx_slot *slot, const uint8_t *payload,
	 size_t payload_len);
DSSH_PRIVATE int      schedule_wa_slot(struct dssh_session_s *sess);
DSSH_PRIVATE int      tx_acquire(struct dssh_session_s *sess, uint8_t msg_type);
DSSH_PRIVATE bool     tx_owner_is_current(struct dssh_session_s *sess);
DSSH_PRIVATE void     tx_unlock_with_slots(struct dssh_session_s *sess);
DSSH_PRIVATE size_t   tx_slot_buf_size(size_t max_payload, size_t block_size, uint16_t mac_digest);
DSSH_PRIVATE int      alloc_tx_slot(struct dssh_tx_slot *slot, size_t max_payload, size_t block_size,
	 uint16_t mac_digest);
DSSH_PRIVATE void     free_tx_slot(struct dssh_tx_slot *slot);
DSSH_PRIVATE bool     tx_gather_enabled(void);
DSSH_PRIVATE int      tx_gather_with_packet(struct dssh_session_s *sess, uint8_t *buf, size_t payload_len);
DSSH_PRIVATE int      alloc_channel_slots(struct dssh_session_s *sess, struct dssh_channel_s *ch);
DSSH_PRIVATE int      recv_packet(struct dssh_session_s *sess, uint8_t *msg_type, uint8_t **payload,
	 size_t *payload_len);
DSSH_PRIVATE int      send_unimplemented(struct dssh_session_s *sess, uint32_t rejected_seq);
DSSH_PRIVATE dssh_key_algo find_key_algo(const char *name);

/*
 * Global algorithm registry and I/O callback config.
 * In library code this is a file-scope variable in ssh-trans.c.
 * Under DSSH_TESTING it is externally visible for test access.
 */
struct dssh_transport_global_config {
	const char *software_version;
	const char *version_comment;
	int         (*tx)(uint8_t *buf, size_t bufsz, struct dssh_session_s *sess, void *cbdata);
	int         (*rx)(uint8_t *buf, size_t bufsz, struct dssh_session_s *sess, void *cbdata);
	int         (*rx_line)(uint8_t *buf, size_t bufsz, size_t *bytes_received, struct dssh_session_s *sess,
            void *cbdata);

	int (*extra_line_cb)(uint8_t *buf, size_t bufsz, void *cbdata);

	int (*tx_gather)(const struct dssh_tx_iov *iov, size_t iovcnt, struct dssh_session_s *sess,
	    void *cbdata); /* optional */

	size_t        kex_entries;
	dssh_kex      kex_head;
	dssh_kex      kex_tail;
	size_t        key_algo_entries;
	dssh_key_algo key_algo_head;
	dssh_key_algo key_algo_tail;
	size_t        enc_entries;
	dssh_enc      enc_head;
	dssh_enc      enc_tail;
	size_t        mac_entries;
	dssh_mac      mac_head;
	dssh_mac      mac_tail;
	size_t        comp_entries;
	dssh_comp     comp_head;
	dssh_comp     comp_tail;
	size_t        lang_entries;
	dssh_language lang_head;
	dssh_language lang_tail;
	atomic_bool   used;
};

/*
 * OpenSSL failure injection.  Under DSSH_TESTING, failable OpenSSL
 * calls are redirected to countdown wrappers in dssh_test_ossl.c.
 * Algorithm module files (enc/, mac/, kex/, key_algo/) include this
 * header, so the macros apply to all library OpenSSL usage.
 * OpenSSL's own internal calls are unaffected (it doesn't include
 * this header).  Free/destroy/cleanse are NOT redirected.
 */
#ifdef DSSH_TESTING

 #include <openssl/bn.h>
 #include <openssl/evp.h>
 #include <openssl/params.h>
/* Creation wrappers (return NULL on failure) */
EVP_MD_CTX     *dssh_test_EVP_MD_CTX_new(void);
EVP_CIPHER_CTX *dssh_test_EVP_CIPHER_CTX_new(void);
EVP_MAC_CTX    *dssh_test_EVP_MAC_CTX_new(EVP_MAC *mac);
EVP_MAC        *dssh_test_EVP_MAC_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, const char *properties);
EVP_MD         *dssh_test_EVP_MD_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, const char *properties);
EVP_PKEY_CTX   *dssh_test_EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
EVP_PKEY_CTX   *dssh_test_EVP_PKEY_CTX_new_id(int id, ENGINE *e);
EVP_PKEY_CTX   *dssh_test_EVP_PKEY_CTX_new_from_name(OSSL_LIB_CTX *ctx, const char *name, const char *propquery);
EVP_PKEY       *dssh_test_EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *pub, size_t len);
BN_CTX         *dssh_test_BN_CTX_new(void);
BIGNUM         *dssh_test_BN_new(void);
OSSL_PARAM_BLD *dssh_test_OSSL_PARAM_BLD_new(void);
OSSL_PARAM     *dssh_test_OSSL_PARAM_BLD_to_param(OSSL_PARAM_BLD *bld);

 #define EVP_MD_CTX_new()                        dssh_test_EVP_MD_CTX_new()
 #define EVP_CIPHER_CTX_new()                    dssh_test_EVP_CIPHER_CTX_new()
 #define EVP_MAC_CTX_new(m)                      dssh_test_EVP_MAC_CTX_new(m)
 #define EVP_MAC_fetch(c, a, p)                  dssh_test_EVP_MAC_fetch(c, a, p)
 #define EVP_MD_fetch(c, a, p)                   dssh_test_EVP_MD_fetch(c, a, p)
 #define EVP_PKEY_CTX_new(k, e)                  dssh_test_EVP_PKEY_CTX_new(k, e)
 #define EVP_PKEY_CTX_new_id(i, e)               dssh_test_EVP_PKEY_CTX_new_id(i, e)
 #define EVP_PKEY_CTX_new_from_name(c, n, p)     dssh_test_EVP_PKEY_CTX_new_from_name(c, n, p)
 #define EVP_PKEY_new_raw_public_key(t, e, p, l) dssh_test_EVP_PKEY_new_raw_public_key(t, e, p, l)
 #define BN_CTX_new()                            dssh_test_BN_CTX_new()
 #define BN_new()                                dssh_test_BN_new()
 #define OSSL_PARAM_BLD_new()                    dssh_test_OSSL_PARAM_BLD_new()
 #define OSSL_PARAM_BLD_to_param(b)              dssh_test_OSSL_PARAM_BLD_to_param(b)
/* Operation wrappers (return 0/<=0 on failure) */
int dssh_test_EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
int dssh_test_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
int dssh_test_EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s);
int dssh_test_EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e,
    EVP_PKEY *pkey);
int dssh_test_EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs,
    size_t tbslen);
int dssh_test_EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e,
    EVP_PKEY *pkey);
int dssh_test_EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
    const unsigned char *tbs, size_t tbslen);
int dssh_test_EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl,
    const unsigned char *key, const unsigned char *iv);
int dssh_test_EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in,
    int inl);
int dssh_test_EVP_MAC_init(EVP_MAC_CTX *ctx, const unsigned char *key, size_t keylen, const OSSL_PARAM params[]);
int dssh_test_EVP_MAC_update(EVP_MAC_CTX *ctx, const unsigned char *data, size_t datalen);
int dssh_test_EVP_MAC_final(EVP_MAC_CTX *ctx, unsigned char *out, size_t *outl, size_t outsize);
int dssh_test_EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
int dssh_test_EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
int dssh_test_EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx);
int dssh_test_EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer);
int dssh_test_EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
int dssh_test_EVP_PKEY_fromdata_init(EVP_PKEY_CTX *ctx);
int dssh_test_EVP_PKEY_fromdata(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey, int selection, OSSL_PARAM params[]);
int dssh_test_EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len);
int dssh_test_EVP_PKEY_get_bn_param(const EVP_PKEY *pkey, const char *key_name, BIGNUM **bn);
int dssh_test_EVP_Digest(const void *data, size_t count, unsigned char *md, unsigned int *size, const EVP_MD *type,
    ENGINE *impl);
int dssh_test_RAND_bytes(unsigned char *buf, int num);
int dssh_test_BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx);
int dssh_test_BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
BIGNUM *dssh_test_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
int     dssh_test_OSSL_PARAM_BLD_push_BN(OSSL_PARAM_BLD *bld, const char *key, const BIGNUM *bn);
int     dssh_test_EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad);
int     dssh_test_EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, const OSSL_PARAM *params);

 #define EVP_Digest(d, c, m, s, t, i)         dssh_test_EVP_Digest(d, c, m, s, t, i)
 #define EVP_DigestInit_ex(c, t, i)           dssh_test_EVP_DigestInit_ex(c, t, i)
 #define EVP_DigestUpdate(c, d, n)            dssh_test_EVP_DigestUpdate(c, d, n)
 #define EVP_DigestFinal_ex(c, m, s)          dssh_test_EVP_DigestFinal_ex(c, m, s)
 #define EVP_DigestSignInit(c, p, t, e, k)    dssh_test_EVP_DigestSignInit(c, p, t, e, k)
 #define EVP_DigestSign(c, s, sl, t, tl)      dssh_test_EVP_DigestSign(c, s, sl, t, tl)
 #define EVP_DigestVerifyInit(c, p, t, e, k)  dssh_test_EVP_DigestVerifyInit(c, p, t, e, k)
 #define EVP_DigestVerify(c, s, sl, t, tl)    dssh_test_EVP_DigestVerify(c, s, sl, t, tl)
 #define EVP_EncryptInit_ex(c, ci, i, k, iv)  dssh_test_EVP_EncryptInit_ex(c, ci, i, k, iv)
 #define EVP_EncryptUpdate(c, o, ol, i, il)   dssh_test_EVP_EncryptUpdate(c, o, ol, i, il)
 #define EVP_MAC_init(c, k, kl, p)            dssh_test_EVP_MAC_init(c, k, kl, p)
 #define EVP_MAC_update(c, d, dl)             dssh_test_EVP_MAC_update(c, d, dl)
 #define EVP_MAC_final(c, o, ol, os)          dssh_test_EVP_MAC_final(c, o, ol, os)
 #define EVP_PKEY_keygen_init(c)              dssh_test_EVP_PKEY_keygen_init(c)
 #define EVP_PKEY_keygen(c, p)                dssh_test_EVP_PKEY_keygen(c, p)
 #define EVP_PKEY_derive_init(c)              dssh_test_EVP_PKEY_derive_init(c)
 #define EVP_PKEY_derive_set_peer(c, p)       dssh_test_EVP_PKEY_derive_set_peer(c, p)
 #define EVP_PKEY_derive(c, k, kl)            dssh_test_EVP_PKEY_derive(c, k, kl)
 #define EVP_PKEY_fromdata_init(c)            dssh_test_EVP_PKEY_fromdata_init(c)
 #define EVP_PKEY_fromdata(c, p, s, pa)       dssh_test_EVP_PKEY_fromdata(c, p, s, pa)
 #define EVP_PKEY_get_raw_public_key(p, b, l) dssh_test_EVP_PKEY_get_raw_public_key(p, b, l)
 #define EVP_PKEY_get_bn_param(p, k, b)       dssh_test_EVP_PKEY_get_bn_param(p, k, b)
 #define RAND_bytes(b, n)                     dssh_test_RAND_bytes(b, n)
 #define BN_mod_exp(r, a, p, m, c)            dssh_test_BN_mod_exp(r, a, p, m, c)
 #define BN_rand(r, b, t, bo)                 dssh_test_BN_rand(r, b, t, bo)
 #define BN_bin2bn(s, l, r)                   dssh_test_BN_bin2bn(s, l, r)
 #define OSSL_PARAM_BLD_push_BN(b, k, bn)     dssh_test_OSSL_PARAM_BLD_push_BN(b, k, bn)
 #define EVP_CIPHER_CTX_set_padding(c, p)     dssh_test_EVP_CIPHER_CTX_set_padding(c, p)
 #define EVP_PKEY_CTX_set_params(c, p)        dssh_test_EVP_PKEY_CTX_set_params(c, p)

#endif /* DSSH_TESTING */

#ifdef __cplusplus
}
#endif

#endif   // ifndef DSSH_TRANS_H
