#ifndef STP_DKG_H
#define STP_DKG_H
/**
 * @file stp-dkg.h

  SPDX-FileCopyrightText: 2025, Marsiske Stefan
  SPDX-License-Identifier: LGPL-3.0-or-later

  API for the Semi-Trusted Party Distributed Key Generation Protocol

  In this protocol there is two roles, the semi-trusted party (STP)
  and the peers. The trusted party connects to all peers and
  orchestrates the protocol which commuicate only via the STP with
  each other. This way the STP acts also as a broadcast medium which
  is an essential part of all DKG protocols.

  The protocol consists of more than 20 steps, but the API hides this
  and provides a state-engine loop, which any user can call
  iteratively while implementing the networking communication
  themselves. This makes it possible to support different
  communication channels like TCP/IP, Bluetooth, USB, UART, etc. A
  peer needs only to support the medium they use, the STP however must
  of course be able to support all the media that the peers require.

  The protocol is based on R. Gennaro, M. O. Rabin, and
  T. Rabin. "Simplified VSS and fact-track multiparty computations
  with applications to threshold cryptography" In B. A. Coan and
  Y. Afek, editors, 17th ACM PODC, pages 101–111. ACM, June / July
  1998 and is fully specified in /docs/stp-dkg.txt

  Both the peers and the STP share a similar API schema:

  (0. msg0 = read()) // only for peers
  1. start_{stp|peer}(state, ...)
  (1.5 send(msg0)) // only for STP
  2. {stp|peer}_set_bufs()
  3. while {stp|peer}_not_done(state):
     - input = allocate_memory( dkg_{stp|peer}_input_size(state) )
     - output = allocate_memory( dkg_{stp|peer}_output_size(state) )
     - input = read()
     - res = {stp|peer}_next_step(state, input, output)
     - if res!=0: fail&abort
     (- dkg_stp_peer_msg(state, output, peer_index, msg) // for STP
     (- msg = output) // for peers
     - send(msg)

  // only for peers
  (4. store share)
  (5. peer_free(state))

 */
#include <stdint.h>
#include <sodium.h>
#include "dkg.h"
#include "toprf.h"

typedef DKG_Message STP_DKG_Message;
typedef DKG_Cheater STP_DKG_Cheater;

#define stp_dkg_commitment_HASHBYTES 32U
#define stp_dkg_encrypted_share_SIZE (TOPRF_Share_BYTES * 2 + crypto_secretbox_xchacha20poly1305_MACBYTES)
#define stpvssdkg_start_msg_SIZE ( sizeof(STP_DKG_Message)                            \
                                 + crypto_generichash_BYTES/*dst*/                    \
                                 + 2 /* n&t */                                        \
                                 + crypto_sign_PUBLICKEYBYTES                         )

/** Error code enum
 */
typedef enum {
  STP_DKG_Err_OK = 0,
  STP_DKG_Err_ISize,
  STP_DKG_Err_OSize,
  STP_DKG_Err_OOB,
  STP_DKG_Err_Send,
  STP_DKG_Err_CheatersFound,
  STP_DKG_Err_CheatersFull,
  STP_DKG_Err_InvSessionID,
  STP_DKG_Err_Share,
  STP_DKG_Err_Noise,
  STP_DKG_Err_NoiseEncrypt,
  STP_DKG_Err_NoiseDecrypt,
  STP_DKG_Err_HMac,
  STP_DKG_Err_Index,
  STP_DKG_Err_NoSubVSPSFail,
  STP_DKG_Err_NotEnoughDealers,
  STP_DKG_Err_TooManyCheaters,
  STP_DKG_Err_DKGFinish,
  STP_DKG_Err_BroadcastEnv = 32,
  STP_DKG_Err_Env = 64
} STP_DKG_Err;

/** Steps of the STP enum
 */
typedef enum {
  STP_DKG_STP_Send_Index,
  STP_DKG_STP_Broadcast_NPKs,
  STP_DKG_STP_Route_Noise_Handshakes1,
  STP_DKG_STP_Route_Noise_Handshakes2,
  STP_DKG_STP_Broadcast_DKG_Hash_Commitments,
  STP_DKG_STP_Broadcast_DKG_Commitments,
  STP_DKG_STP_Route_Encrypted_Shares,
  STP_DKG_STP_Broadcast_Complaints,
  STP_DKG_STP_Broadcast_DKG_Defenses,
  STP_DKG_STP_Broadcast_DKG_Transcripts,
  STP_DKG_STP_Broadcast_DKG_Final_Commitments,
  STP_DKG_STP_Done
} STP_DKG_STP_Steps;

/** Message types used as msgno in DKG_Message enum
 */
typedef enum {
  stpvssdkg_stp_start_msg,
  stpvssdkg_stp_index_msg,
  stpvssdkg_peer_init1_msg,
  stpvssdkg_stp_bc_init1_msg,
  stpvssdkg_peer_start_noise_msg,
  stpvssdkg_peer_respond_noise_msg,
  stpvssdkg_peer_dkg1_msg,
  stpvssdkg_stp_bc_dkg1_msg,
  stpvssdkg_peer_dkg2_msg,
  stpvssdkg_stp_bc_dkg2_msg,
  stpvssdkg_peer_dkg3_msg,
  stpvssdkg_stp_bc_dkg3_msg,
  stpvssdkg_peer_verify_shares_msg,
  stpvssdkg_stp_bc_verify_shares_msg,
  stpvssdkg_peer_share_key_msg,
  stpvssdkg_stp_bc_key_msg,
  stpvssdkg_peer_bc_transcript_msg,
  stpvssdkg_stp_bc_transcript_msg,
} STP_DKG_Message_Type;

/** @struct STP_DKG_STPState

    This struct contains the state of the STP during the execution of
    the STP DKG protocol.

    Most values of this struct are internal variables and should not
    be used. The following variables are useful and can be used by
    users of this API:

    @var STP_DKG_PeerState:n This field contains the value N,
         specifying the total number of peers participating in this
         protocol.

    @var STP_DKG_PeerState:t This field contains the value T,
         specifying the threshold necessary to use shared secret
         generated by this DKG.

    @var STP_DKG_PeerState:cheaters This field contains a list of
         cheaters and protocol violators at the end of a failed
         protocol run.

    @var STP_DKG_PeerState:cheater_len This field contains the length
         of the cheaters list.
 */
typedef struct {
  STP_DKG_STP_Steps step;
  STP_DKG_STP_Steps prev;
  uint8_t sessionid[dkg_sessionid_SIZE];
  uint8_t n;
  uint8_t t;
  uint8_t sig_pk[crypto_sign_PUBLICKEYBYTES];
  uint8_t sig_sk[crypto_sign_SECRETKEYBYTES];
  uint64_t *last_ts;
  uint64_t ts_epsilon;
  uint8_t (*sig_pks)[][crypto_sign_PUBLICKEYBYTES];
  uint8_t (*commitment_hashes)[][stp_dkg_commitment_HASHBYTES];
  uint8_t (*share_macs)[][crypto_auth_hmacsha256_BYTES];
  uint8_t (*commitments)[][crypto_core_ristretto255_BYTES];
  uint16_t share_complaints_len;
  uint16_t (*share_complaints)[];
  size_t cheater_len;
  STP_DKG_Cheater (*cheaters)[];
  size_t cheater_max;
  crypto_generichash_state transcript;
} STP_DKG_STPState;

/** Gets the size needed for allocation of a STP_DKG_STPState struct
 */
size_t stp_dkg_stpstate_size(void);
/** Getter for the n parameter of the STP State
 */
uint8_t stp_dkg_stpstate_n(const STP_DKG_STPState *ctx);
/** Getter for the t parameter of the STP State
 */
uint8_t stp_dkg_stpstate_t(const STP_DKG_STPState *ctx);
/** Getter for the number of cheaters in the cheater list of the STP State
 */
size_t stp_dkg_stpstate_cheater_len(const STP_DKG_STPState *ctx);
/** Getter for the sessionid of the STP State
 */
const uint8_t* stp_dkg_stpstate_sessionid(const STP_DKG_STPState *ctx);
/** Getter for the current step of the STP State
 */
int stp_dkg_stpstate_step(const STP_DKG_STPState *ctx);

/** Starts a new execution of a STP DKG protocol.

    This function initializes the state of the STP and creates an
    initial message containing the parameters for the peers.

    @param [in] ctx : pointer to a STP_DKG_STPState struct, this
                struct will be initialized by this function.

    @param [in] ts_epsilon: how many seconds a message can be old,
                before it is considered unfresh and is rejected. The
                correct value here is difficult to set, small local
                executions with only 2-out-of-3 setups will work with
                as few as 2-3 seconds, big deployments with
                126-out-of-127 might need up to a few hours...

    @param [in] n: the number of peers participating in this execution.

    @param [in] t: the threshold necessary to use the results of this DKG.

    @param [in] proto_name: an array of bytes used as a domain
           seperation tag (DST). Set it to the name of your application.

    @param [in] proto_name_len: the size of the array proto_name, to
           allow non-zero terminated DSTs.

    @param [in] sig_pks: pointer to a list of N+1 items containing the
           long-term signing keys of all parties, with the STPs pk at
           index 0.

    @param [in] ltssk the private long-term signing key of the STP.

    @param [in] msg0_len: the size of memory allocated to the msg0 parameter.
           should be exactly stpvssdkg_msg0_SIZE;

    @param [out] msg0: a message to be sent to all peers to initalize them.
    @return 0 if no errors.
 **/
int stp_dkg_start_stp(STP_DKG_STPState *ctx, const uint64_t ts_epsilon,
                           const uint8_t n, const uint8_t t,
                           const char *proto_name, const size_t proto_name_len,
                           uint8_t (*sig_pks)[][crypto_sign_PUBLICKEYBYTES],
                           const uint8_t ltssk[crypto_sign_SECRETKEYBYTES],
                           const size_t msg0_len, STP_DKG_Message *msg0);

/**
   This function sets all the variable sized buffers in the STP_DKG_STPState structure.

   @param [in] cheater_max: is the number of max cheat attempts to be
          recorded. Normally the maximum is t*t-1. It should be provided as
          (sizeof(cheaters) / sizeof(TP_DKG_Cheater))

   A number of buffers are needed in the STP state that depend on the N and T parameters.
   These can be allocated on the stack as follows:

   @code
   uint16_t stp_share_complaints[n*n];
   uint64_t last_ts[n];
   STP_DKG_Cheater stp_cheaters[t*t - 1];
   uint8_t tp_commitments_hashes[n][stp_dkg_commitment_HASHBYTES];
   uint8_t tp_share_macs[n*n][crypto_auth_hmacsha256_BYTES];
   uint8_t tp_commitments[n*n][crypto_core_ristretto255_BYTES];

   stp_dkg_stp_set_bufs(&stp,
                        &tp_commitments_hashes,
                        &tp_share_macs,
                        &tp_commitments,
                        &stp_share_complaints,
                        &stp_cheaters,
                        sizeof(stp_cheaters) / sizeof(STP_DKG_Cheater),
                        last_ts);
   @endcode
 */
void stp_dkg_stp_set_bufs(STP_DKG_STPState *ctx,
                              uint8_t (*commitment_hashes)[][stp_dkg_commitment_HASHBYTES],
                              uint8_t (*share_macs)[][crypto_auth_hmacsha256_BYTES],
                              uint8_t (*commitments)[][crypto_core_ristretto255_BYTES],
                              uint16_t (*share_complaints)[],
                              STP_DKG_Cheater (*cheaters)[], const size_t cheater_max,
                              uint64_t *last_ts);

/** Steps of the peer state engine
 */
typedef enum {
  STP_DKG_Peer_Broadcast_NPK_SIDNonce,
  STP_DKG_Peer_Rcv_NPK_SIDNonce,
  STP_DKG_Peer_Noise_Handshake,
  STP_DKG_Peer_Finish_Noise_Handshake,
  STP_DKG_Peer_Rcv_Commitments_Send_Commitments,
  STP_DKG_Peer_Rcv_Commitments_Send_Shares,
  STP_DKG_Peer_Verify_Commitments,
  STP_DKG_Peer_Handle_DKG_Complaints,
  STP_DKG_Peer_Defend_DKG_Accusations,
  STP_DKG_Peer_Check_Shares,
  STP_DKG_Peer_Finish_DKG,
  STP_DKG_Peer_Confirm_Transcripts,
  STP_DKG_Peer_Done
} STP_DKG_Peer_Steps;

/** Callback function type for loading the corresponding long-term signing public keys and noise public keys of a peer

    The user of this API may provide a callback function that gets
    called during the processing of the 1st message by the peer, to
    load the corresponding keys related to a peer id.

    @param [in] id: the peer id
    @param [in] arg: a void pointer to some argument stored in the peers state context
                this  can be set during stp_dkg_peer_set_bufs()
    @param [out] sigpk: the buffer which should hold the corresponding
                 long-term signing public key
    @param [out] noise_pk: the buffer which should hold the corresponding
                 long-term noise public key
    @return 0 if no errors
 */
typedef int (*Keyloader_CB)(const uint8_t id[crypto_generichash_BYTES],
                 void *arg,
                 uint8_t sigpk[crypto_sign_PUBLICKEYBYTES],
                 uint8_t noise_pk[crypto_scalarmult_BYTES]);

/** @struct STP_DKG_PeerState

    This struct contains the state of a peer during the execution of
    the STP DKG protocol.

    Most values of this struct are internal variables and should not
    be used. The following variables are useful and can be used by
    users of this API:

    @var TP_DKG_PeerState:n This field contains the value N,
         specifying the total number of peers participating in this
         protocol.

    @var TP_DKG_PeerState:t This field contains the value T,
         specifying the threshold necessary to use shared secret
         generated by this DKG.

    @var TP_DKG_PeerState:index This field contains the index of the
         peer, it is a value between 1 and and N inclusive.

    @var TP_DKG_PeerState:peerids This field is a pointer at a list of
         n items, containing the hashes of all peers long-term signing
         keys.

    @var TP_DKG_PeerState:sig_pks This field is a pointer at a list of
         n items, containing the long-term signing keys of all peers.

    @var TP_DKG_PeerState:peers_noise_pks This field is a pointer at a
         list of n items, containing the public noise keys of all
         peers.

    @var TP_DKG_PeerState:share This field contains the resulting
         share at the end of the DKG and should most probably be
         persisted for later usage. This is the output of the DKG for
         a peer.

    @var STP_DKG_PeerState:cheaters This field contains a list of
         cheaters and protocol violators at the end of a failed
         protocol run.

    @var STP_DKG_PeerState:cheater_len This field contains the length
         of the cheaters list.
 */
typedef struct {
  uint8_t (*peerids)[][crypto_generichash_BYTES];
  STP_DKG_Peer_Steps step;
  STP_DKG_Peer_Steps prev;
  uint8_t sessionid[dkg_sessionid_SIZE];
  uint8_t n;
  uint8_t t;
  uint8_t index;
  Keyloader_CB keyloader_cb;
  void *keyloader_cb_arg;
  uint8_t sig_pk[crypto_sign_PUBLICKEYBYTES];
  uint8_t sig_sk[crypto_sign_SECRETKEYBYTES];
  uint8_t stp_sig_pk[crypto_sign_PUBLICKEYBYTES];
  uint8_t noise_pk[crypto_scalarmult_BYTES];
  uint8_t noise_sk[crypto_scalarmult_SCALARBYTES];
  uint64_t stp_last_ts;
  uint64_t *last_ts;
  uint64_t ts_epsilon;
  uint8_t (*sig_pks)[][crypto_sign_PUBLICKEYBYTES];
  uint8_t (*peer_noise_pks)[][crypto_scalarmult_BYTES];
  Noise_XK_device_t *dev;
  Noise_XK_session_t *(*noise_outs)[];
  Noise_XK_session_t *(*noise_ins)[];
  TOPRF_Share (*k_shares)[][2];
  uint8_t (*encrypted_shares)[][noise_xk_handshake3_SIZE + stp_dkg_encrypted_share_SIZE];
  uint8_t (*share_macs)[][crypto_auth_hmacsha256_BYTES];
  uint8_t (*ki_commitments)[][crypto_core_ristretto255_BYTES];
  uint8_t (*k_commitments)[][crypto_core_ristretto255_BYTES];
  uint8_t (*commitments_hashes)[][stp_dkg_commitment_HASHBYTES];
  uint16_t share_complaints_len;
  uint16_t *share_complaints;
  uint8_t my_share_complaints_len;
  uint8_t *my_share_complaints;
  uint8_t k_commitment[crypto_core_ristretto255_BYTES];
  size_t cheater_len;
  STP_DKG_Cheater (*cheaters)[];
  size_t cheater_max;
  crypto_generichash_state transcript;
  uint8_t final_transcript[crypto_generichash_BYTES];
  TOPRF_Share share[2];
} STP_DKG_PeerState;

/** Gets the size needed for allocation of a STP_DKG_PeerState struct
 */
size_t stp_dkg_peerstate_size(void);
/** Getter for the n parameter of the Peer State
 */
uint8_t stp_dkg_peerstate_n(const STP_DKG_PeerState *ctx);
/** Getter for the n parameter of the Peer State
 */
uint8_t stp_dkg_peerstate_t(const STP_DKG_PeerState *ctx);
/** Getter for the sessionid of the Peer State
 */
const uint8_t* stp_dkg_peerstate_sessionid(const STP_DKG_PeerState *ctx);
/** Getter for the long-term private signing key of the Peer
 */
const uint8_t* stp_dkg_peerstate_lt_sk(const STP_DKG_PeerState *ctx);
/** Getter for the generated share of the Peer as a result of this protocol
    The size of the final share is TOPRF_Share_BYTES * 2
 */
const uint8_t* stp_dkg_peerstate_share(const STP_DKG_PeerState *ctx);

/** Getter for the commitments of the generated shares result of this protocol
 */
const uint8_t* stp_dkg_peerstate_commitments(const STP_DKG_PeerState *ctx);
/** Getter for the current step of the Peer State
 */
int stp_dkg_peerstate_step(const STP_DKG_PeerState *ctx);

/** Starts a new execution of a STP DKG protocol for a peer.

    This function initializes the state of the peer.

    @param [in] ctx : pointer to a STP_DKG_PeerState struct, this struct
                will be initialized by this function.

    @param [in] ts_epsilon: how many seconds a message can be old,
                before it is considered unfresh and is rejected. The
                correct value here is difficult to set, small local
                executions with only 2-out-of-3 setups will work with
                as few as 2-3 seconds, big deployments with
                126-out-of-127 might need up to a few hours...

    @param [in] peer_lt_sk: the long-term private signing key of the peer.

    @param [in] noise_sks: the long-term noise secret key of the peer.

    @param [in] msg0: the initiating msg sent from the TP after the TP
                run tpdkg_tp_start().

    @param [out] stp_ltpk: the STPs long-term public signing
           key. Should be used to verify if this key is actually
           authorized to initiate an STP DKG with the peer.

    @return 0 if no errors.
 **/
STP_DKG_Err stp_dkg_start_peer(STP_DKG_PeerState *ctx,
                               const uint64_t ts_epsilon,
                               const uint8_t lt_sk[crypto_sign_SECRETKEYBYTES],
                               const uint8_t noise_sks[crypto_scalarmult_SCALARBYTES],
                               const STP_DKG_Message *msg0,
                               uint8_t stp_ltpk[crypto_sign_PUBLICKEYBYTES]);

/** This function sets all the variable sized buffers in the STP_DKG_PeerState structure.

  The buffer sizes depend on the n and t parameters to the DKG these
  are announced by the STP in msg0, which is an input to the
  tpdkg_start_peer() function, after this tpdkg_start_peer() function
  the peerstate is initialized and can be used to find out the n and t
  parameters.

  If you want you can allocate all the buffers on the stack like this:

  @code
  STP_DKG_PeerState ctx;
  stp_dkg_start_peer(&ctx,....);
  const uint8_t n = ctx->n;
  const uint8_t t = ctx->t;

  uint8_t peerids[n][crypto_generichash_BYTES];
  Noise_XK_session_t *noise_outs[n];
  Noise_XK_session_t *noise_ins[n];
  TOPRF_Share dealer_shares[n][2];
  uint8_t encrypted_shares[n][noise_xk_handshake3_SIZE + stp_dkg_encrypted_share_SIZE];
  uint8_t dealer_commitments[n*n][crypto_core_ristretto255_BYTES];
  uint8_t share_macs[n][n*n][crypto_auth_hmacsha256_BYTES];
  uint8_t peer_k_commitments[n][crypto_core_ristretto255_BYTES];
  uint8_t commitments_hashes[n][stp_dkg_commitment_HASHBYTES];
  uint16_t peer_dealer_share_complaints[n*n];
  uint8_t peer_my_dealer_share_complaints[n];
  uint64_t peer_last_ts[n];
  STP_DKG_Cheater peer_cheaters[t*t - 1];
  if(0!=stp_dkg_peer_set_bufs(&peer, &peerids,
                              &keyloader_cb, &cb_arg,
                              &lt_pks,
                              &peers_noise_pks,
                              &noise_outs, &noise_ins,
                              &dealer_shares,
                              &encrypted_shares,
                              &share_macs,
                              &dealer_commitments,
                              &peer_k_commitments,
                              &commitments_hashes,
                              &peer_cheaters, sizeof(peer_cheaters) / sizeof(STP_DKG_Cheater) / n,
                              peer_dealer_share_complaints,
                              peer_my_dealer_share_complaints,
                              peer_last_ts)) return 1;
  @endcode

**/
int stp_dkg_peer_set_bufs(STP_DKG_PeerState *ctx,
                          uint8_t (*peerids)[][crypto_generichash_BYTES],
                          Keyloader_CB keyloader_cb,
                          void *keyloader_cb_arg,
                          uint8_t (*peers_sig_pks)[][crypto_sign_PUBLICKEYBYTES],
                          uint8_t (*peers_noise_pks)[][crypto_scalarmult_BYTES],
                          Noise_XK_session_t *(*noise_outs)[],
                          Noise_XK_session_t *(*noise_ins)[],
                          TOPRF_Share (*k_shares)[][2],
                          uint8_t (*encrypted_shares)[][noise_xk_handshake3_SIZE + stp_dkg_encrypted_share_SIZE],
                          uint8_t (*share_macs)[][crypto_auth_hmacsha256_BYTES],
                          uint8_t (*ki_commitments)[][crypto_core_ristretto255_BYTES],
                          uint8_t (*k_commitments)[][crypto_core_ristretto255_BYTES],
                          uint8_t (*commitments_hashes)[][stp_dkg_commitment_HASHBYTES],
                          STP_DKG_Cheater (*cheaters)[], const size_t cheater_max,
                          uint16_t *share_complaints,
                          uint8_t *my_share_complaints,
                          uint64_t *last_ts);

/**
   This function calculates the size of the buffer needed to hold all
   outputs from the peers serving as input to the next step of the STP.

   An implementer should allocate a buffer of this size, and
   concatenate all messages from all peers in the order of the peers.

   The allocated buffer is to be passed as an input to the
   stp_dkg_stp_next() function, after this the buffer SHOULD be
   deallocated.

   @param [in] ctx: an initialized STP_DKG_STPState struct.
   @return 1 on error, otherwise the size to be allocated (can be 0)
 */
size_t stp_dkg_stp_input_size(const STP_DKG_STPState *ctx);

/**
   This function calculates the size of the message from each peer to
   be received by the STP.

   @param [in] ctx: an initialized STP_DKG_STPState struct.
   @param [out] sizes: a array of type size_t with exactly N elements.

   @return 0 on if the sizes differ from peer to peer, otherwise all
           peers will be sending messages of equal size. In the latter
           case all items of the sizes array hold the same valid value.
 */
int stp_dkg_stp_input_sizes(const STP_DKG_STPState *ctx, size_t *sizes);

/**
   This function calculates the size of the buffer needed to hold the
   output from the stp_dkg_stp_next() function.

   An implementer should allocate a buffer of this size and pass it as
   parameter to stp_dkg_stp_next().

   @param [in] ctx: an initialized STP_DKG_STPState struct.
   @return 1 on error, otherwise the size to be allocated (can be 0)
*/
size_t stp_dkg_stp_output_size(const STP_DKG_STPState *ctx);

/**
   This function exeutes the next step of the STP DKG protocol for the
   semi-trusted party.

   @param [in] ctx: pointer to a valid STP_DKG_STPState.
   @param [in] input: buffer to the input of the current step.
   @param [in] input_len: size of the input buffer.
   @param [out] output: buffer to the output of the current step.
   @param [in] output_len: size of the output buffer.
   @return 0 if no error

   An example of how to use this in concert with stp_dkg_stp_input_size()
   and stp_dkg_stp_output_size():

   @code
    uint8_t stp_out[stp_dkg_stp_output_size(&tp)];
    uint8_t stp_in[stp_dkg_stp_input_size(&tp)];
    recv(socket, stp_in, sizeof(stp_in));
    ret = stp_dkg_stp_next(&tp, stp_in, sizeof(stp_in), stp_out, sizeof stp_out);
   @endcode
 */
int stp_dkg_stp_next(STP_DKG_STPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len);

/**
   This function "converts" the output of stp_dkg_stp_next() into a
   message for the i-th peer.

   The outputs of steps of the protocol are sometimes broadcast
   messages where the output is the same for all peers, but some of
   the outputs are dedicated and unique messages for each peer. This
   function returns a pointer to a message and the size of the message
   to be sent for a particular peer specified as a parameter.

   @param [in] ctx: pointer to a valid STP_DKG_STPState.
   @param [in] base: a pointer to the output of the stp_dkg_stp_next() function.
   @param [in] base_size: the size of the output of the stp_dkg_stp_next() function.
   @param [in] peer: the index of the peer (starting with 0 for the first)
   @param [out] msg: pointer to a pointer to the message to be sent to the ith peer.
   @param [out] len: pointer to the length of the message to be sent to the ith peer.
   @return 0 if no error

   example how to use this in concert with stp_dkg_stp_next():

   @code
    ret = stp_dkg_stp_next(&tp, tp_in, sizeof(tp_in), tp_out, sizeof tp_out);

    for(int i=0;i<tp.n;i++) {
      const uint8_t *msg;
      size_t len;
      if(0!=stp_dkg_stp_peer_msg(&tp, tp_out, sizeof tp_out, i, &msg, &len)) {
        return 1;
      }
      send(i, msg, len);
    }
    @endcode

 */
int stp_dkg_stp_peer_msg(const STP_DKG_STPState *ctx, const uint8_t *base, const size_t base_size, const uint8_t peer, const uint8_t **msg, size_t *len);

/** This function checks if the protocol has finished for the STP or
    more stp_dkg_stp_next() calls are necessary.

   @return 1 if more steps outstanding
 */
int stp_dkg_stp_not_done(const STP_DKG_STPState *stp);

/** This function converts a cheater object to a human readable string.

    use this variant for cheater objects created by STP

    @param [in] c: the cheater object.
    @param [out] out: the pointer to the pre-allocated buffer receiving the string
    @param [in] outlen: the size of the pre-allocated buffer
    @return the index of the cheating peer.
 */
uint8_t stp_dkg_stp_cheater_msg(const STP_DKG_Cheater *c, char *out, const size_t outlen);

/**
   This function calculates the size of the buffer needed to hold the
   output from the STP serving as input to the next step of the peer.

   An implementer should allocate a buffer of this size.

   The allocated buffer is to be passed as an input to the
   stp_dkg_peer_next() function, after this the buffer SHOULD be
   deallocated.

   @param [in] ctx: an initialized STP_DKG_PeerState struct.
   @return 1 on error, otherwise the size to be allocated (can be 0)
 */
size_t stp_dkg_peer_input_size(const STP_DKG_PeerState *ctx);

/**
   This function calculates the size of the buffer needed to hold the
   output from the stp_dkg_peer_next() function.

   An implementer should allocate a buffer of this size and pass it as
   parameter to stp_dkg_peer_next().

   @param [in] ctx: an initialized STP_DKG_PeerState struct.
   @return 1 on error, otherwise the size to be allocated (can be 0)
*/
size_t stp_dkg_peer_output_size(const STP_DKG_PeerState *ctx);

/**
   This function exeutes the next step of the STP DKG protocol for a
   peer.

   @param [in] ctx: pointer to a valid STP_DKG_PeerState.
   @param [in] input: buffer to the input of the current step.
   @param [in] input_len: size of the input buffer.
   @param [out] output: buffer to the output of the current step.
   @param [in] output_len: size of the output buffer.
   @return 0 if no error

   An example of how to use this in concert with stp_dkg_peer_input_size()
   and stp_dkg_peer_output_size() while allocating the buffers on the stack:

   @code
   uint8_t peers_out[stp_dkg_peer_output_size(&peer)];

   uint8_t peer_in[stp_dkg_peer_input_size(&peer)];
   recv(socket, peer_in, sizeof(peer_in));
   ret = stp_dkg_peer_next(&peer,
                           peer_in, sizeof(peer_in),
                           peers_out, sizeof(peers_out));
   @endcode
 */
int stp_dkg_peer_next(STP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len);

/**
   This function checks if the protocol has finished for the peer or
   more stp_dkg_peer_next() calls are necessary.

   @return 1 if more steps outstanding
 */
int stp_dkg_peer_not_done(const STP_DKG_PeerState *peer);

/**
   This function MUST be called before a peers state is
   deallocated.

   Unfortunately the underlying (but very cool and formally verified)
   Noise XK implementation does allocate a lot of internal state on
   the heap, and thus this must be freed manually.
 */
void stp_dkg_peer_free(STP_DKG_PeerState *ctx);

/** This function converts a cheater object to a human readable string.

    use this variant for cheater objects created by a peer

    @param [in] c: the cheater object.
    @param [out] out: the pointer to the pre-allocated buffer receiving the string
    @param [in] outlen: the size of the pre-allocated buffer
    @return the index of the cheating peer.
 */
uint8_t stp_dkg_peer_cheater_msg(const STP_DKG_Cheater *c, char *out, const size_t outlen);

extern FILE* log_file;

#endif //STP_DKG_H
