/*
  This file is part of TALER
  Copyright (C) 2023-2024 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 donau-httpd_keys.h
 * @brief management of our various keys
 * @author Christian Grothoff
 */
#include <donau_config.h>
#include <taler/taler_json_lib.h>
#include <taler/taler_mhd_lib.h>
#include "donau_util.h"
#include "donaudb_plugin.h"
#include "donau-httpd.h"

#ifndef DONAU_HTTPD_KEYS_H
#define DONAU_HTTPD_KEYS_H


/**
 * @brief All information about a donation unit key (which is used to
 * sign donation receipts into existence).
 */
struct DH_DonationUnitKey
{

  /**
   * Hash code of the donation unit public key.
   */
  struct DONAU_DonationUnitHashP h_donation_unit_pub;

  /**
   * Decoded donation unit public key (the hash of it is in
   * @e issue, but we sometimes need the full public key as well).
   */
  struct DONAU_DonationUnitPublicKey donation_unit_pub;

  /**
   * The validity year.
   */
  uint64_t validity_year;

  /**
   * Value that the donation unit represents.
   */
  struct TALER_Amount value;

  /**
   * Did we lose the private keys?
   */
  bool lost;

};

/**
 * Information needed to create a blind signature.
 */
struct DH_BlindSignData
{
  /**
   * Hash of key to sign with.
   */
  const struct DONAU_DonationUnitHashP *h_du_pub;

  /**
   * Blinded planchet to sign over.
   */
  const struct DONAU_BlindedUniqueDonorIdentifier *budi;
};

/**
 * Sign the message in @a purpose with the doanu's signing key.
 *
 * The @a purpose data is the beginning of the data of which the signature is
 * to be created. The `size` field in @a purpose must correctly indicate the
 * number of bytes of the data structure, including its header.  Use
 * #DH_keys_doanu_sign() instead of calling this function directly!
 *
 * @param purpose the message to sign
 * @param[out] pub set to the current public signing key of the doanu
 * @param[out] sig signature over purpose using current signing key
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
DH_keys_donau_sign_ (
  const struct GNUNET_CRYPTO_SignaturePurpose *purpose,
  struct DONAU_DonauPublicKeyP *pub,
  struct DONAU_DonauSignatureP *sig);

/**
 * @ingroup crypto
 * @brief EdDSA sign a given block.
 *
 * The @a ps data must be a fixed-size struct for which the signature is to be
 * created. The `size` field in @a ps->purpose must correctly indicate the
 * number of bytes of the data structure, including its header.
 *
 * @param ps packed struct with what to sign, MUST begin with a purpose
 * @param[out] pub where to store the public key to use for the signing
 * @param[out] sig where to write the signature
 * @return #TALER_EC_NONE on success
 */
#define DH_keys_donau_sign(ps,pub,sig) \
        ({                                                  \
    /* check size is set correctly */                 \
    GNUNET_assert (htonl ((ps)->purpose.size) ==      \
                   sizeof (*ps));                     \
    /* check 'ps' begins with the purpose */          \
    GNUNET_static_assert (((void*) (ps)) ==           \
                          ((void*) &(ps)->purpose));  \
    DH_keys_donau_sign_ (&(ps)->purpose,              \
                         pub,                         \
                         sig);                        \
  })

/**
 * Resumes all suspended /keys requests, we may now have key material
 * (or are shutting down).
 *
 * @param do_shutdown are we shutting down?
 */
void
TEH_resume_keys_requests (bool do_shutdown);


/**
 * Function to call to handle requests to "/keys" by sending
 * back our current key material.
 *
 * @param rc request context
 * @param args array of additional options (must be empty for this function)
 * @return MHD result code
 */
MHD_RESULT
DH_handler_keys (struct DH_RequestContext *rc,
                 const char *const args[]);


/**
 * Look up the issue for a donation unit public key.
 *
 * @param h_du_pub hash of donation unit public key
 * @return the donation unit key issue,
 *         or NULL if @a h_du_pub could not be found
 */
struct DH_DonationUnitKey *
DH_keys_donation_unit_by_hash (
  const struct DONAU_DonationUnitHashP *h_du_pub);


/**
 * Initialize keys subsystem.
 *
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
DH_keys_init (void);


/**
 * Fully clean up keys subsystem.
 */
void
DH_keys_finished (void);


/**
 * Request to sign @a budis.
 *
 * @param num_bkps length of @a budis array
 * @param bkps array with data to blindly sign (and keys to sign with)
 * @param[out] du_sigs array set to the blind signature on success; must be of length @a num_bkps
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
DH_keys_donation_unit_batch_sign (
  unsigned int num_bkps,
  const struct DONAU_BkpSignData bkps[num_bkps],
  struct DONAU_BlindedDonationUnitSignature du_sigs[num_bkps]);

/**
 * Request to derive CS @a r_pub using the donation_unit and nonce from @a cdd.
 *
 * @param h_donation_unit_pub hash to compute @a r_pub from
 * @param nonce
 * @param[out] r_pub where to write the result
 * @return #TALER_EC_NONE on success
 */
enum TALER_ErrorCode
DH_keys_donation_unit_cs_r_pub (
  const struct DONAU_DonationUnitHashP *h_donation_unit_pub,
  const struct GNUNET_CRYPTO_CsSessionNonce *nonce,
  struct GNUNET_CRYPTO_CSPublicRPairP *r_pub);

#endif
