/*
  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 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 General Public License for more details.

  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file include/donau_crypto_lib.h
 * @file include/gnunet_crypto_lib.h
 * @brief taler-specific crypto functions
 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
 * @author Christian Grothoff <christian@grothoff.org>
 * @author Özgür Kesim <oec-taler@kesim.org>
 * @author Lukas Matyja
 * @author Pius Loosli
 */

#if ! defined (__DONAU_UTIL_LIB_H_INSIDE__)
 #error "Only <donau_util.h> can be included directly."
#endif

#ifndef DONAU_CRYPTO_LIB_H
#define DONAU_CRYPTO_LIB_H

#include <gnunet/gnunet_util_lib.h>
#include <taler/taler_error_codes.h>
#include <taler/taler_util.h>
#include <gcrypt.h>
#include <jansson.h>


/* ****************** donau crypto primitives ************* */

/**
 * Regular online message signing key used by Donau.
 */
struct DONAU_DonauPublicKeyP
{
  /**
   * Donau uses EdDSA for non-blind signing.
   */
  struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;

};

/**
 * @brief Private key used by the donau to
 * sign messages.
 */
struct DONAU_PrivateKeyP
{
  /**
   * Donau uses EdDSA for non-blind signing.
   */
  struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
};


/**
 * Signing key for whole batches of BUDI-key-pairs. Used by a Charity.
 */
struct DONAU_CharityPublicKeyP
{
  /**
   * Donau uses EdDSA for BUDI-key-pair signing
   */
  struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;

};

/**
 * Signing key for whole batches of BUDI-key-pairs. Used by a Charity.
 */
struct DONAU_CharityPrivateKeyP
{
  /**
   * Donau uses EdDSA for BUDI-key-pair signing
   */
  struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;

};

/**
 * @brief Type of public signing keys for verifying blindly signed budis.
 */
struct DONAU_DonationUnitPublicKey
{

  /**
   * Type of the public key.
   */
  struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub_key;

};

/**
 * @brief Type of private signing keys for blind signing of budis.
 */
struct DONAU_DonationUnitPrivateKey
{

  struct GNUNET_CRYPTO_BlindSignPrivateKey *bsign_priv_key;

};

/**
 * Hash of a donation unit public key. MUST match the
 * `struct TALER_CsPubHashP` and `struct TALER_RsaPubHashP`
 * of the GNU Taler exchange secmod helpers!
 */
struct DONAU_DonationUnitHashP
{
  struct GNUNET_HashCode hash;
};

/**
 * Compare two donation unit public keys.
 *
 * @param donation_unit1 first key
 * @param donation_unit2 second key
 * @return 0 if the keys are equal, otherwise -1 or 1
 */
int
DONAU_donation_unit_pub_cmp (
  const struct DONAU_DonationUnitPublicKey *donation_unit1,
  const struct DONAU_DonationUnitPublicKey *donation_unit2);

/**
 * Make a (deep) copy of the given @a donation_unit_src to
 * @a donation_unit_dst.
 *
 * @param[out] donation_unit_dst target to copy to
 * @param donation_unit_src public key to copy
 */
void
DONAU_donation_unit_pub_deep_copy (
  struct DONAU_DonationUnitPublicKey *donation_unit_dst,
  const struct DONAU_DonationUnitPublicKey *donation_unit_src);

/**
 * Free internals of @a donation_unit_pub, but not @a donation_unit_pub itself.
 *
 * @param[in] donation_unit_pub key to free
 */
void
DONAU_donation_unit_pub_free (
  struct DONAU_DonationUnitPublicKey *donation_unit_pub);

/**
 * Compute the hash of the given @a donation_unit_pub.
 *
 * @param donation_unit_pub public key to hash
 * @param[out] donation_unit_hash resulting hash value
 */
void
DONAU_donation_unit_pub_hash (
  const struct DONAU_DonationUnitPublicKey *donation_unit_pub,
  struct DONAU_DonationUnitHashP *donation_unit_hash
  );


/**
 * Hash used to represent a Donation Receipt
 */
struct DONAU_DonationReceiptHashP
{
  /**
   * Actual hash value.
   */
  struct GNUNET_HashCode hash;
};

/**
 * Nonce for Donation Receipt
 */
struct DONAU_UniqueDonorIdentifierNonce
{
  /**
   * Actual nonce value.
   */
  uint32_t value[32 / 4];
};

/**
 * Donor's hashed and salted unique donation identifier.
 */
struct DONAU_HashDonorTaxId
{
  unsigned char hash[512 / 8];
};

/**
 * blind signatures from the blinded donation envelopes.
 */
struct DONAU_BlindedDonationUnitSignature
{
  /**
   * Donation Units use blind signatures.
   */
  struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;

};


/**
 * @brief Type of (unblinded) donation receipts signatures for Taler.
 */
struct DONAU_DonationUnitSignature
{
  /**
   * Donation units use blind signatures.
   */
  struct GNUNET_CRYPTO_UnblindedSignature *unblinded_sig;
};


/**
 * @brief Type of signature used by the donau for non-blind signatures.
 */
struct DONAU_DonauSignatureP
{
  /**
   * Donau uses EdDSA for for non-blind signatures.
   */
  struct GNUNET_CRYPTO_EddsaSignature eddsa_sig;
};

/**
 * @brief Type of signature used by charities
 */
struct DONAU_CharitySignatureP
{
  /**
   * Charities use EdDSA signatures.
   */
  struct GNUNET_CRYPTO_EddsaSignature eddsa_sig;
};

/**
 * Token used for access control for admin to the donau.
 */
struct DONAU_BearerToken
{
  /**
   * The token of variable length.
   */
  const char *token;
};


/**
 * @brief Wrapper around GNUNET primitive for the blinded unique donation identifier
 */
struct DONAU_BlindedUniqueDonorIdentifier
{
  /**
   * GNUNET primitive type representing a generic blinded message
   */
  struct GNUNET_CRYPTO_BlindedMessage *blinded_message;
};


/**
 * Information needed for a donation receipt to be signed.
 */
struct DONAU_BlindedUniqueDonorIdentifierKeyPair
{

  /**
   * The hash of the donation unit's public key.
   */
  struct DONAU_DonationUnitHashP h_donation_unit_pub;

  /**
   * Donor's blinded donation identifier. It must be blindly signed
   * to become donation receipt.
   */
  struct DONAU_BlindedUniqueDonorIdentifier blinded_udi;

};

/**
 * Donation Receipt
 */
struct DONAU_DonationReceipt
{

  /**
   * The hash of the donation unit's public key.
   */
  struct DONAU_DonationUnitHashP h_donation_unit_pub;

  /**
   * Nonce from the Unique Donor Identifier.
   */
  struct DONAU_UniqueDonorIdentifierNonce nonce;

  /**
   * Unblinded donation unit signature from the donau.
   */
  struct DONAU_DonationUnitSignature donation_unit_sig;

};

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

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

/**
 * Hash of a Unique Donor Identifier (h_donor_tax_id + nonce)
 */
struct DONAU_UniqueDonorIdentifierHashP
{
  struct GNUNET_HashCode hash;
};

/**
 * Hash of a budikeypair array
 */
struct DONAU_BudiHashP
{
  struct GNUNET_HashCode hash;
};

/**
 * @brief Inputs needed from the donau for blind signing.
 */
struct DONAU_BatchIssueValues
{
  /**
   * Input values.
   */
  struct GNUNET_CRYPTO_BlindingInputValues *blinding_inputs;
};

/**
 * Master key material for the deriviation of
 * blinding factors during issuing receipts.
 */
struct DONAU_BudiMasterSecretP
{

  /**
   * Key material.
   */
  uint32_t key_data[8];

};

/**
 * Donation Statement
 */
struct DONAU_DonationStatement
{
  /**
   * The corresponding year.
   */
  uint64_t year;

  /**
   * The salted and hashed donor id.
   */
  const struct DONAU_HashDonorTaxId *h_donor_tax_id;

  /**
   * The salt used for @h_donor_tax_id.
   */
  const char *donor_tax_id;

  /**
   * The cleartext tax id of the user used for @h_donor_tax_id.
   */
  const char *salt;

  /**
   * The total donated amount.
   */
  struct TALER_Amount total_amount;

  /**
   * The donation statement signature over @year, @h_donor_tax_id and @total_amount.
   */
  struct DONAU_DonauSignatureP donation_statement_sig;

};

/* ********************* charity eddsa signing ************************** */


/**
 * Create charity eddsa signature approving to issue a donation part.
 *
 * @param num_bkp number of bkps
 * @param bkp to be signed
 * @param charity_priv private key of the charity
 * @param[out] charity_sig where to write the signature
 */
void
DONAU_charity_bkp_sign (
  const size_t num_bkp,
  const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp,
  const struct DONAU_CharityPrivateKeyP *charity_priv,
  struct DONAU_CharitySignatureP *charity_sig);


/**
 * Verify charity eddsa signature approving to issue a donation part.
 *
 * @param num_bkp number of bkps
 * @param bkp array to verify
 * @param charity_pub public key of the charity
 * @param charity_sig where to write the signature
 * @return #GNUNET_OK if the signature is valid
 */
enum GNUNET_GenericReturnValue
DONAU_charity_bkp_verify (
  const size_t num_bkp,
  const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp,
  const struct DONAU_CharityPublicKeyP *charity_pub,
  const struct DONAU_CharitySignatureP *charity_sig);


/**
 * Create charity eddsa signature approving a request for charity
 * status information.
 *
 * @param charity_priv private key of the charity
 * @param[out] charity_sig where to write the signature
 */
void
DONAU_charity_get_info_sign (
  const struct DONAU_CharityPrivateKeyP *charity_priv,
  struct DONAU_CharitySignatureP *charity_sig);


/**
 * Verify charity eddsa signature requesting charity information.
 *
 * @param charity_pub public key of the charity
 * @param charity_sig where to write the signature
 * @return #GNUNET_OK if the signature is valid
 */
enum GNUNET_GenericReturnValue
DONAU_charity_get_info_verify (
  const struct DONAU_CharityPublicKeyP *charity_pub,
  const struct DONAU_CharitySignatureP *charity_sig);


/* ********************* donau eddsa signing ************************** */

/**
 * Signature of a function that signs the message in @a purpose with the
 * exchange'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. *
 * @param purpose the message to sign
 * @param[out] pub set to the current public signing key of the exchange
 * @param[out] sig signature over purpose using current signing key
 * @return #TALER_EC_NONE on success
 */
typedef enum TALER_ErrorCode
(*DONAU_DonauSignCallback)(
  const struct GNUNET_CRYPTO_SignaturePurpose *purpose,
  struct DONAU_DonauPublicKeyP *pub,
  struct DONAU_DonauSignatureP *sig);

/**
 * Create donau eddsa signature. Another name for this
 * is the donation statement.
 *
 * @param scb function to call to create the signature
 * @param amount_tot total donated amount of @a year
 * @param year
 * @param i hash value, the identifier of the donor
 * @param donau_pub public key of the donau
 * @param[out] donau_sig where to write the signature
 */
enum TALER_ErrorCode
DONAU_donation_statement_sign (
  DONAU_DonauSignCallback scb,
  const struct TALER_Amount *amount_tot,
  const uint64_t year,
  const struct DONAU_HashDonorTaxId *i,
  struct DONAU_DonauPublicKeyP *donau_pub,
  struct DONAU_DonauSignatureP *donau_sig);


/**
 * Verify donau eddsa signature/donation statement.
 *
 * @param amount_tot total donated amount of @a year
 * @param year
 * @param i hash value, the identifier of the donor
 * @param donau_priv private key of the donau
 * @param statement_sig signature to verify
 * @return #GNUNET_OK if the signature is valid
 */
enum GNUNET_GenericReturnValue
DONAU_donation_statement_verify (
  const struct TALER_Amount *amount_tot,
  const uint64_t year,
  const struct DONAU_HashDonorTaxId *i,
  const struct DONAU_DonauPublicKeyP *donau_pub,
  const struct DONAU_DonauSignatureP *statement_sig);


/* ********************* donau blind signing ************************** */

/**
 * Verify donation receipt.
 *
 * @param donation_unit_pub public key of the donation_unit
 * @param h_udi hash of h_donor_tax_id + nonce
 * @param donation_unit_sig signature to verify
 * @return #GNUNET_OK if the signature is valid
 */
enum GNUNET_GenericReturnValue
DONAU_donation_receipt_verify (
  const struct DONAU_DonationUnitPublicKey *donation_unit_pub,
  const struct DONAU_UniqueDonorIdentifierHashP *h_udi,
  const struct DONAU_DonationUnitSignature *donation_unit_sig);


/**
 * Free internals of @a donation_unit_sig, but not @a donation_unit_sig itself.
 *
 * @param[in] donation_unit_sig signature to free
 */
void
DONAU_blinded_donation_unit_sig_free (
  struct DONAU_BlindedDonationUnitSignature *donation_unit_sig);


/**
 * Verify signature made with a donation unit public key
 * over a budi.
 *
 * @param du_pub public donation unit key
 * @param du_sig signature made with the private key
 * @param budi_hash hash over the budi
 * @return #GNUNET_OK if the signature is valid
 */
enum GNUNET_GenericReturnValue
TALER_donation_unit_pub_verify (const struct
                                DONAU_DonationUnitPublicKey *du_pub,
                                const struct
                                DONAU_DonationUnitSignature *du_sig,
                                const struct DONAU_BudiHashP *budi_hash);


/* ********************* client blind/unblind ************************** */

/**
 * Create a blinding secret @a bks given the client's @a ps and the alg_values
 * from the exchange.
 *
 * @param ps secret to derive blindings from
 * @param alg_values containing cipher and additional CS values
 * @param[out] bks blinding secrets
 */
void
DONAU_budi_secret_create (
  const struct DONAU_BudiMasterSecretP *ps,
  const struct DONAU_BatchIssueValues *alg_values,
  union GNUNET_CRYPTO_BlindingSecretP *bks);


/**
 * Return the alg value singleton for creation of
 * blinding secrets for RSA.
 *
 * @return singleton to use for RSA blinding
 */
const struct DONAU_BatchIssueValues *
DONAU_donation_unit_ewv_rsa_singleton (void);


/**
 * Make a (deep) copy of the given @a bi_src to
 * @a bi_dst.
 *
 * @param[out] bi_dst target to copy to
 * @param bi_src blinding input values to copy
 */
void
DONAU_donation_unit_ewv_copy (
  struct DONAU_BatchIssueValues *bi_dst,
  const struct DONAU_BatchIssueValues *bi_src);


/**
 * Blind udi for blind signing with @a du_pub using blinding secret @a budi_secret.
 *
 * NOTE: As a particular oddity, the @a budi is only partially
 * initialized by this function in the case of CS donation units. Here, the
 * 'nonce' must be initialized separately!
 *
 * @param du_pub donation unit public key to blind for
 * @param budi_secret blinding secret to use
 * @param cs_nonce nonce used to derive session values,
 *        could be NULL for ciphers that do not use it
 * @param udi_nonce guarantees uniqueness, part of the message to blind
 * @param h_tax_id hashed and salted tax id, part of the message to blind
 * @param alg_values algorithm specific values to blind the udi
 * @param[out] udi_hash resulting hashed @a h_tax_id with @a udi_nonce
 * @param[out] budi blinded udi data to initialize
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
DONAU_donation_unit_blind (
  const struct DONAU_DonationUnitPublicKey *du_pub,
  const union GNUNET_CRYPTO_BlindingSecretP *budi_secret,
  const union GNUNET_CRYPTO_BlindSessionNonce *cs_nonce,
  const struct DONAU_UniqueDonorIdentifierNonce *udi_nonce,// message
  const struct DONAU_HashDonorTaxId *h_tax_id, // message
  const struct DONAU_BatchIssueValues *alg_values,
  struct DONAU_UniqueDonorIdentifierHashP *udi_hash,
  struct DONAU_BlindedUniqueDonorIdentifier *budi);


/**
 * Unblind blinded signature.
 *
 * @param[out] du_sig where to write the unblinded signature
 * @param blind_du_sig the blinded signature
 * @param budi_secret blinding secret to use
 * @param udi_hash hash of udi for verification of the signature
 * @param alg_values algorithm specific values
 * @param du_pub public key used for signing
 * @return #GNUNET_OK on success
 */
enum GNUNET_GenericReturnValue
DONAU_donation_unit_sig_unblind (
  struct DONAU_DonationUnitSignature *du_sig,
  const struct DONAU_BlindedDonationUnitSignature *blind_du_sig,
  const union GNUNET_CRYPTO_BlindingSecretP *budi_secret,
  const struct DONAU_UniqueDonorIdentifierHashP *udi_hash,
  const struct DONAU_BatchIssueValues *alg_values,
  const struct DONAU_DonationUnitPublicKey *du_pub);

/*********************** helpers ************************************************/
/**
 * Group of donation units. These are the common fields of an array of
 * donation units.
 */
struct DONAU_DonationUnitGroup
{

  /**
   * Value of coins in this donation unit group.
   */
  struct TALER_Amount value;

  /**
   * Cipher used for the donation unit.
   */
  enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher;

};

/**
 * Compute a unique key for the meta data of a donation unit group.
 *
 * @param dg donation unit group to evaluate
 * @param[out] key key to set
 */
void
DONAU_donation_unit_group_get_key (
  const struct DONAU_DonationUnitGroup *dg,
  struct GNUNET_HashCode *key);

/**
 * Compute the hash of a Unique Donor Identifier.
 *
 * @param h_donor_tax_id hash of the tax id
 * @param nonce that makes the Donor Identifier unique
 * @param[out] h_udi where to write the hash
 */
void
DONAU_unique_donor_id_hash (
  const struct DONAU_HashDonorTaxId *h_donor_tax_id,
  const struct DONAU_UniqueDonorIdentifierNonce *nonce,
  struct DONAU_UniqueDonorIdentifierHashP *h_udi);

#endif
