/*
   This file is part of TALER
   Copyright (C) 2020-2026 Taler Systems SA

   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free Software
   Foundation; either version 3, or (at your option) any later version.

   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License along with
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
/**
 * @file taler-exchange-httpd_secmod-helpers.h
 * @brief management of state with secmod helpers
 * @author Christian Grothoff
 * @author Özgür Kesim
 */
#ifndef TALER_EXCHANGE_HTTP_SECMOD_HELPERS_H
#define TALER_EXCHANGE_HTTP_SECMOD_HELPERS_H

#include "taler-exchange-httpd.h"
#include <jansson.h>

/**
 * Setup SECMOD helper state.
 *
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TEH_SECMOD_setup_key_helpers (void);


/**
 * Synchronize helper state. Polls the key helper for updates.
 */
void
TEH_SECMOD_sync_key_helpers (void);


/**
 * Destroy SECMOD helper module state.
 */
void
TEH_SECMOD_destroy_key_helpers (void);


/**
 * Check if we have at least one SECMOD for denomination public keys.
 *
 * @return true if we have one
 */
bool
TEH_SECMOD_have_denom_sm_pub (void);

/**
 * Check if we have at least one SECMOD for exchange signing keys.
 *
 * @return true if we have one
 */
bool
TEH_SECMOD_have_esign_sm_pub (void);


/**
 * Return JSON with all of the offline security module public keys.
 *
 * @return JSON object
 */
json_t *
TEH_SECMOD_get_sm_pubs_as_json (void);


/**
 * Information about a denomination on offer by the denomination helper.
 */
struct HelperDenomination
{

  /**
   * When will the helper start to use this key for signing?
   */
  struct GNUNET_TIME_Timestamp start_time;

  /**
   * For how long will the helper allow signing? 0 if
   * the key was revoked or purged.
   */
  struct GNUNET_TIME_Relative validity_duration;

  /**
   * Hash of the full denomination key.
   */
  struct TALER_DenominationHashP h_denom_pub;

  /**
   * Signature over this key from the security module's key.
   */
  struct TALER_SecurityModuleSignatureP sm_sig;

  /**
   * The (full) public key.
   */
  struct TALER_DenominationPublicKey denom_pub;

  /**
   * Details depend on the @e denom_pub.cipher type.
   */
  union
  {

    /**
     * Hash of the RSA key.
     */
    struct TALER_RsaPubHashP h_rsa;

    /**
     * Hash of the CS key.
     */
    struct TALER_CsPubHashP h_cs;

  } h_details;

  /**
   * Name in configuration section for this denomination type.
   */
  char *section_name;

};


/**
 * Iterate over all known denomination keys.
 *
 * @param cb function to call
 * @param cb_cls closure to pass to @a cb
 */
void
TEH_SECMOD_iterate_denom_keys (
  GNUNET_CONTAINER_MultiHashMapIteratorCallback cb,
  void *cb_cls);


/**
 * Information about a signing key on offer by the esign helper.
 */
struct HelperSignkey
{
  /**
   * When will the helper start to use this key for signing?
   */
  struct GNUNET_TIME_Timestamp start_time;

  /**
   * For how long will the helper allow signing? 0 if
   * the key was revoked or purged.
   */
  struct GNUNET_TIME_Relative validity_duration;

  /**
   * The public key.
   */
  struct TALER_ExchangePublicKeyP exchange_pub;

  /**
   * Signature over this key from the security module's key.
   */
  struct TALER_SecurityModuleSignatureP sm_sig;

};


/**
 * Iterate over all known exchange signing keys.
 *
 * @param cb function to call
 * @param cb_cls closure to pass to @a cb
 */
void
TEH_SECMOD_iterate_esign_keys (
  GNUNET_CONTAINER_PeerMapIterator cb,
  void *cb_cls);


/**
 * Load fees and expiration times (!) for the denomination type configured for
 * the denomination matching @a h_denom_pub.
 *
 * @param h_denom_pub hash of the denomination public key
 *        to use to derive the section name of the configuration to use
 * @param[out] denom_pub set to the denomination public key (to be freed by caller!)
 * @param[out] meta denomination type data to complete
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO if @a h_denom_pub is not known
 *         #GNUNET_SYSERR on hard errors
 */
enum GNUNET_GenericReturnValue
TEH_SECMOD_denom_load_meta (
  const struct TALER_DenominationHashP *h_denom_pub,
  struct TALER_DenominationPublicKey *denom_pub,
  struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta);


/**
 * Load expiration times for the given onling signing key.
 *
 * @param exchange_pub the online signing key
 * @param[out] meta set to meta data about the key
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
TEH_SECMOD_esign_load_meta (const struct TALER_ExchangePublicKeyP *exchange_pub,
                            struct TALER_EXCHANGEDB_SignkeyMetaData *meta);


/**
 * Information needed to derive the CS r_pub.
 */
struct TEH_SECMOD_CsDeriveData
{
  /**
   * Hash of key to sign with.
   */
  const struct TALER_DenominationHashP *h_denom_pub;

  /**
   * Nonce to use.
   */
  const struct GNUNET_CRYPTO_CsSessionNonce *nonce;
};


/**
 * Request to derive a bunch of CS @a r_pubs using the
 * denominations and nonces from @a cdds.
 *
 * @param cdds array to compute @a r_pubs from
 * @param cdds_length length of the @a cdds array
 * @param for_melt true if this is for a melt operation
 * @param[out] r_pubs array where to write the result; must be of length @a cdds_length
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TEH_SECMOD_denom_cs_batch_r_pub_simple (
  unsigned int cdds_length,
  const struct TEH_SECMOD_CsDeriveData cdds[static cdds_length],
  bool for_melt,
  struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length]);


/**
 * Request to derive a bunch of CS @a r_pubs using the
 * denominations and nonces from @a cdds.
 *
 * @param num number of input elements
 * @param h_denom_pubs array @a num of hashes of keys to sign with
 * @param nonces array @a num of nonces to use
 * @param for_melt true if this is for a melt operation
 * @param[out] r_pubs array where to write the result; must be of length @a num
 * @param[out] err_idx in case of error, the index into @e cdds that caused it
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TEH_SECMOD_denom_cs_batch_r_pub (
  size_t num,
  const struct TALER_DenominationHashP h_denom_pubs[static num],
  const struct GNUNET_CRYPTO_CsSessionNonce nonces[static num],
  bool for_melt,
  struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static num],
  size_t *err_idx);


/**
 * Information needed to create a blind signature.
 */
struct TEH_SECMOD_CoinSignData
{
  /**
   * Hash of key to sign with.
   */
  const struct TALER_DenominationHashP *h_denom_pub;

  /**
   * Blinded planchet to sign over.
   */
  const struct TALER_BlindedPlanchet *bp;
};


/**
 * Request to sign @a csds.
 *
 * @param csds array with data to blindly sign (and keys to sign with)
 * @param csds_length length of @a csds array
 * @param for_melt true if this is for a melt operation
 * @param[out] bss array set to the blind signature on success; must be of length @a csds_length
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TEH_SECMOD_denom_batch_sign (
  unsigned int csds_length,
  const struct TEH_SECMOD_CoinSignData csds[static csds_length],
  bool for_melt,
  struct TALER_BlindedDenominationSignature bss[static csds_length]);


/**
 * Request to sign @a purpose. Note that this function does NOT check if @a
 * pub is actually signed by our offline tool. Thus, clients should usually
 * use TEH_keys_exchange_sign() and related APIs that include this check.
 *
 * @param purpose message to sign
 * @param[out] pub set to public key used to sign
 * @param[out] sig set to resulting signature
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
TEH_SECMOD_exchange_sign (
  const struct GNUNET_CRYPTO_SignaturePurpose *purpose,
  struct TALER_ExchangePublicKeyP *pub,
  struct TALER_ExchangeSignatureP *sig);


/**
 * Check if we lost the private denomination key for the
 * denomination @a h_denom_pub
 *
 * @param h_denom_pub hash over the public key
 * @return true if we lost the private key
 */
bool
TEH_SECMOD_denom_priv_check_lost (
  const struct TALER_DenominationHashP *h_denom_pub);


/**
 * Revoke the public key associated with @a h_denom_pub.
 * This function should be called AFTER the database was
 * updated, as it also triggers #TEH_keys_update_states().
 *
 * Note that the actual revocation happens asynchronously and
 * may thus fail silently. To verify that the revocation succeeded,
 * clients must watch for the associated change to the key state.
 *
 * @param h_denom_pub hash of the public key to revoke
 */
void
TEH_SECMOD_denom_revoke (
  const struct TALER_DenominationHashP *h_denom_pub);


/**
 * Revoke the given exchange's signing key.
 * This function should be called AFTER the database was
 * updated, as it also triggers #TEH_keys_update_states().
 *
 * Note that the actual revocation happens asynchronously and
 * may thus fail silently. To verify that the revocation succeeded,
 * clients must watch for the associated change to the key state.
 *
 * @param exchange_pub key to revoke
 */
void
TEH_SECMOD_esign_revoke (
  const struct TALER_ExchangePublicKeyP *exchange_pub);


#endif
