diff options
Diffstat (limited to 'src/util/wallet_signatures.c')
-rw-r--r-- | src/util/wallet_signatures.c | 1787 |
1 files changed, 1770 insertions, 17 deletions
diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c index 1916740c6..0b6ab5432 100644 --- a/src/util/wallet_signatures.c +++ b/src/util/wallet_signatures.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020 Taler Systems SA + Copyright (C) 2021-2023 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 @@ -14,20 +14,248 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ /** - * @file secmod_signatures.c - * @brief Utility functions for Taler security module signatures + * @file wallet_signatures.c + * @brief Utility functions for Taler wallet signatures * @author Christian Grothoff + * @author Özgür Kesim */ #include "platform.h" #include "taler_util.h" #include "taler_signatures.h" +#include <gnunet/gnunet_common.h> +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used to generate the signature on a request to deposit + * a coin into the account of a merchant. + */ +struct TALER_DepositRequestPS +{ + /** + * Purpose must be #TALER_SIGNATURE_WALLET_COIN_DEPOSIT. + * Used for an EdDSA signature with the `struct TALER_CoinSpendPublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the contract for which this deposit is made. + */ + struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED; + + /** + * Hash over the age commitment that went into the coin. Maybe all zero, if + * age commitment isn't applicable to the denomination. + */ + struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED; + + /** + * Hash over optional policy extension attributes shared with the exchange. + */ + struct TALER_ExtensionPolicyHashP h_policy GNUNET_PACKED; + + /** + * Hash over the wiring information of the merchant. + */ + struct TALER_MerchantWireHashP h_wire GNUNET_PACKED; + + /** + * Hash over the denomination public key used to sign the coin. + */ + struct TALER_DenominationHashP h_denom_pub GNUNET_PACKED; + + /** + * Time when this request was generated. Used, for example, to + * assess when (roughly) the income was achieved for tax purposes. + * Note that the Exchange will only check that the timestamp is not "too + * far" into the future (i.e. several days). The fact that the + * timestamp falls within the validity period of the coin's + * denomination key is irrelevant for the validity of the deposit + * request, as obviously the customer and merchant could conspire to + * set any timestamp. Also, the Exchange must accept very old deposit + * requests, as the merchant might have been unable to transmit the + * deposit request in a timely fashion (so back-dating is not + * prevented). + */ + struct GNUNET_TIME_TimestampNBO wallet_timestamp; + + /** + * How much time does the merchant have to issue a refund request? + * Zero if refunds are not allowed. After this time, the coin + * cannot be refunded. + */ + struct GNUNET_TIME_TimestampNBO refund_deadline; + + /** + * Amount to be deposited, including deposit fee charged by the + * exchange. This is the total amount that the coin's value at the exchange + * will be reduced by. + */ + struct TALER_AmountNBO amount_with_fee; + + /** + * Depositing fee charged by the exchange. This must match the Exchange's + * denomination key's depositing fee. If the client puts in an + * invalid deposit fee (too high or too low) that does not match the + * Exchange's denomination key, the deposit operation is invalid and + * will be rejected by the exchange. The @e amount_with_fee minus the + * @e deposit_fee is the amount that will be transferred to the + * account identified by @e h_wire. + */ + struct TALER_AmountNBO deposit_fee; + + /** + * The Merchant's public key. Allows the merchant to later refund + * the transaction or to inquire about the wire transfer identifier. + */ + struct TALER_MerchantPublicKeyP merchant; + + /** + * Hash over a JSON containing data provided by the + * wallet to complete the contract upon payment. + */ + struct GNUNET_HashCode wallet_data_hash; + +}; + +GNUNET_NETWORK_STRUCT_END + +void +TALER_wallet_deposit_sign ( + const struct TALER_Amount *amount, + const struct TALER_Amount *deposit_fee, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct GNUNET_HashCode *wallet_data_hash, + const struct TALER_AgeCommitmentHash *h_age_commitment, + const struct TALER_ExtensionPolicyHashP *h_policy, + const struct TALER_DenominationHashP *h_denom_pub, + const struct GNUNET_TIME_Timestamp wallet_timestamp, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct GNUNET_TIME_Timestamp refund_deadline, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_DepositRequestPS dr = { + .purpose.size = htonl (sizeof (dr)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT), + .h_contract_terms = *h_contract_terms, + .h_wire = *h_wire, + .h_denom_pub = *h_denom_pub, + .wallet_timestamp = GNUNET_TIME_timestamp_hton (wallet_timestamp), + .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline), + .merchant = *merchant_pub + }; + + if (NULL != wallet_data_hash) + dr.wallet_data_hash = *wallet_data_hash; + if (NULL != h_age_commitment) + dr.h_age_commitment = *h_age_commitment; + if (NULL != h_policy) + dr.h_policy = *h_policy; + TALER_amount_hton (&dr.amount_with_fee, + amount); + TALER_amount_hton (&dr.deposit_fee, + deposit_fee); + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &dr, + &coin_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_deposit_verify ( + const struct TALER_Amount *amount, + const struct TALER_Amount *deposit_fee, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct GNUNET_HashCode *wallet_data_hash, + const struct TALER_AgeCommitmentHash *h_age_commitment, + const struct TALER_ExtensionPolicyHashP *h_policy, + const struct TALER_DenominationHashP *h_denom_pub, + struct GNUNET_TIME_Timestamp wallet_timestamp, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct GNUNET_TIME_Timestamp refund_deadline, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_DepositRequestPS dr = { + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT), + .purpose.size = htonl (sizeof (dr)), + .h_contract_terms = *h_contract_terms, + .h_wire = *h_wire, + .h_denom_pub = *h_denom_pub, + .wallet_timestamp = GNUNET_TIME_timestamp_hton (wallet_timestamp), + .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline), + .merchant = *merchant_pub, + }; + + if (NULL != wallet_data_hash) + dr.wallet_data_hash = *wallet_data_hash; + if (NULL != h_age_commitment) + dr.h_age_commitment = *h_age_commitment; + if (NULL != h_policy) + dr.h_policy = *h_policy; + TALER_amount_hton (&dr.amount_with_fee, + amount); + TALER_amount_hton (&dr.deposit_fee, + deposit_fee); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, + &dr, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used for to allow the wallet to authenticate + * link data provided by the exchange. + */ +struct TALER_LinkDataPS +{ + + /** + * Purpose must be #TALER_SIGNATURE_WALLET_COIN_LINK. + * Used with an EdDSA signature of a `struct TALER_CoinPublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash of the denomination public key of the new coin. + */ + struct TALER_DenominationHashP h_denom_pub; + + /** + * Transfer public key (for which the private key was not revealed) + */ + struct TALER_TransferPublicKeyP transfer_pub; + + /** + * Hash of the age commitment, if applicable. Can be all zero + */ + struct TALER_AgeCommitmentHash h_age_commitment; + + /** + * Hash of the blinded new coin. + */ + struct TALER_BlindedCoinHashP coin_envelope_hash; +}; + +GNUNET_NETWORK_STRUCT_END + void -TALER_wallet_link_sign (const struct GNUNET_HashCode *h_denom_pub, +TALER_wallet_link_sign (const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_TransferPublicKeyP *transfer_pub, - const void *coin_ev, - size_t coin_ev_size, + const struct TALER_BlindedCoinHashP *bch, const struct TALER_CoinSpendPrivateKeyP *old_coin_priv, struct TALER_CoinSpendSignatureP *coin_sig) { @@ -35,12 +263,10 @@ TALER_wallet_link_sign (const struct GNUNET_HashCode *h_denom_pub, .purpose.size = htonl (sizeof (ldp)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK), .h_denom_pub = *h_denom_pub, - .transfer_pub = *transfer_pub + .transfer_pub = *transfer_pub, + .coin_envelope_hash = *bch }; - GNUNET_CRYPTO_hash (coin_ev, - coin_ev_size, - &ldp.coin_envelope_hash); GNUNET_CRYPTO_eddsa_sign (&old_coin_priv->eddsa_priv, &ldp, &coin_sig->eddsa_signature); @@ -49,10 +275,9 @@ TALER_wallet_link_sign (const struct GNUNET_HashCode *h_denom_pub, enum GNUNET_GenericReturnValue TALER_wallet_link_verify ( - const struct GNUNET_HashCode *h_denom_pub, + const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_TransferPublicKeyP *transfer_pub, - const void *coin_ev, - size_t coin_ev_size, + const struct TALER_BlindedCoinHashP *h_coin_ev, const struct TALER_CoinSpendPublicKeyP *old_coin_pub, const struct TALER_CoinSpendSignatureP *coin_sig) { @@ -60,12 +285,10 @@ TALER_wallet_link_verify ( .purpose.size = htonl (sizeof (ldp)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK), .h_denom_pub = *h_denom_pub, - .transfer_pub = *transfer_pub + .transfer_pub = *transfer_pub, + .coin_envelope_hash = *h_coin_ev, }; - GNUNET_CRYPTO_hash (coin_ev, - coin_ev_size, - &ldp.coin_envelope_hash); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_LINK, &ldp, @@ -74,4 +297,1534 @@ TALER_wallet_link_verify ( } +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Signed data to request that a coin should be refunded as part of + * the "emergency" /recoup protocol. The refund will go back to the bank + * account that created the reserve. + */ +struct TALER_RecoupRequestPS +{ + /** + * Purpose is #TALER_SIGNATURE_WALLET_COIN_RECOUP + * or #TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash of the (revoked) denomination public key of the coin. + */ + struct TALER_DenominationHashP h_denom_pub; + + /** + * Blinding factor that was used to withdraw the coin. + */ + union GNUNET_CRYPTO_BlindingSecretP coin_blind; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum GNUNET_GenericReturnValue +TALER_wallet_recoup_verify ( + const struct TALER_DenominationHashP *h_denom_pub, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_RecoupRequestPS pr = { + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), + .purpose.size = htonl (sizeof (pr)), + .h_denom_pub = *h_denom_pub, + .coin_blind = *coin_bks + }; + + return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, + &pr, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); +} + + +void +TALER_wallet_recoup_sign ( + const struct TALER_DenominationHashP *h_denom_pub, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_RecoupRequestPS pr = { + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), + .purpose.size = htonl (sizeof (pr)), + .h_denom_pub = *h_denom_pub, + .coin_blind = *coin_bks + }; + + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &pr, + &coin_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_recoup_refresh_verify ( + const struct TALER_DenominationHashP *h_denom_pub, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_RecoupRequestPS pr = { + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH), + .purpose.size = htonl (sizeof (pr)), + .h_denom_pub = *h_denom_pub, + .coin_blind = *coin_bks + }; + + return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH, + &pr, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); +} + + +void +TALER_wallet_recoup_refresh_sign ( + const struct TALER_DenominationHashP *h_denom_pub, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_RecoupRequestPS pr = { + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH), + .purpose.size = htonl (sizeof (struct TALER_RecoupRequestPS)), + .h_denom_pub = *h_denom_pub, + .coin_blind = *coin_bks + }; + + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &pr, + &coin_sig->eddsa_signature); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Message signed by a coin to indicate that the coin should be + * melted. + */ +struct TALER_RefreshMeltCoinAffirmationPS +{ + /** + * Purpose is #TALER_SIGNATURE_WALLET_COIN_MELT. + * Used for an EdDSA signature with the `struct TALER_CoinSpendPublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Which melt commitment is made by the wallet. + */ + struct TALER_RefreshCommitmentP rc GNUNET_PACKED; + + /** + * Hash over the denomination public key used to sign the coin. + */ + struct TALER_DenominationHashP h_denom_pub GNUNET_PACKED; + + /** + * If age commitment was provided during the withdrawal of the coin, this is + * the hash of the age commitment vector. It must be all zeroes if no age + * commitment was provided. + */ + struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED; + + /** + * How much of the value of the coin should be melted? This amount + * includes the fees, so the final amount contributed to the melt is + * this value minus the fee for melting the coin. We include the + * fee in what is being signed so that we can verify a reserve's + * remaining total balance without needing to access the respective + * denomination key information each time. + */ + struct TALER_AmountNBO amount_with_fee; + + /** + * Melting fee charged by the exchange. This must match the Exchange's + * denomination key's melting fee. If the client puts in an invalid + * melting fee (too high or too low) that does not match the Exchange's + * denomination key, the melting operation is invalid and will be + * rejected by the exchange. The @e amount_with_fee minus the @e + * melt_fee is the amount that will be credited to the melting + * session. + */ + struct TALER_AmountNBO melt_fee; +}; + +GNUNET_NETWORK_STRUCT_END + +void +TALER_wallet_melt_sign ( + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *melt_fee, + const struct TALER_RefreshCommitmentP *rc, + const struct TALER_DenominationHashP *h_denom_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_RefreshMeltCoinAffirmationPS melt = { + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT), + .purpose.size = htonl (sizeof (melt)), + .rc = *rc, + .h_denom_pub = *h_denom_pub, + .h_age_commitment = {{{0}}}, + }; + + if (NULL != h_age_commitment) + melt.h_age_commitment = *h_age_commitment; + + + TALER_amount_hton (&melt.amount_with_fee, + amount_with_fee); + TALER_amount_hton (&melt.melt_fee, + melt_fee); + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &melt, + &coin_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_melt_verify ( + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *melt_fee, + const struct TALER_RefreshCommitmentP *rc, + const struct TALER_DenominationHashP *h_denom_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_RefreshMeltCoinAffirmationPS melt = { + .purpose.size = htonl (sizeof (melt)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT), + .rc = *rc, + .h_denom_pub = *h_denom_pub, + .h_age_commitment = {{{0}}}, + }; + + if (NULL != h_age_commitment) + melt.h_age_commitment = *h_age_commitment; + + TALER_amount_hton (&melt.amount_with_fee, + amount_with_fee); + TALER_amount_hton (&melt.melt_fee, + melt_fee); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_COIN_MELT, + &melt, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + + +/** + * @brief Format used for to generate the signature on a request to withdraw + * coins from a reserve. + */ +struct TALER_WithdrawRequestPS +{ + + /** + * Purpose must be #TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW. + * Used with an EdDSA signature of a `struct TALER_ReservePublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Value of the coin being exchanged (matching the denomination key) + * plus the transaction fee. We include this in what is being + * signed so that we can verify a reserve's remaining total balance + * without needing to access the respective denomination key + * information each time. + */ + struct TALER_AmountNBO amount_with_fee; + + /** + * Hash of the denomination public key for the coin that is withdrawn. + */ + struct TALER_DenominationHashP h_denomination_pub GNUNET_PACKED; + + /** + * Hash of the (blinded) message to be signed by the Exchange. + */ + struct TALER_BlindedCoinHashP h_coin_envelope GNUNET_PACKED; +}; + + +GNUNET_NETWORK_STRUCT_END + +void +TALER_wallet_withdraw_sign ( + const struct TALER_DenominationHashP *h_denom_pub, + const struct TALER_Amount *amount_with_fee, + const struct TALER_BlindedCoinHashP *bch, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_WithdrawRequestPS req = { + .purpose.size = htonl (sizeof (req)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW), + .h_denomination_pub = *h_denom_pub, + .h_coin_envelope = *bch + }; + + TALER_amount_hton (&req.amount_with_fee, + amount_with_fee); + GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + &req, + &reserve_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_withdraw_verify ( + const struct TALER_DenominationHashP *h_denom_pub, + const struct TALER_Amount *amount_with_fee, + const struct TALER_BlindedCoinHashP *bch, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_WithdrawRequestPS wsrd = { + .purpose.size = htonl (sizeof (wsrd)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW), + .h_denomination_pub = *h_denom_pub, + .h_coin_envelope = *bch + }; + + TALER_amount_hton (&wsrd.amount_with_fee, + amount_with_fee); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, + &wsrd, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used for to generate the signature on a request to + * age-withdraw from a reserve. + */ +struct TALER_AgeWithdrawRequestPS +{ + + /** + * Purpose must be #TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW. + * Used with an EdDSA signature of a `struct TALER_ReservePublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * The reserve's public key + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Value of the coin being exchanged (matching the denomination key) + * plus the transaction fee. We include this in what is being + * signed so that we can verify a reserve's remaining total balance + * without needing to access the respective denomination key + * information each time. + */ + struct TALER_AmountNBO amount_with_fee; + + /** + * Running SHA512 hash of the commitment of n*kappa coins + */ + struct TALER_AgeWithdrawCommitmentHashP h_commitment; + + /** + * The mask that defines the age groups. MUST be the same for all denominations. + */ + struct TALER_AgeMask mask; + + /** + * Maximum age group that the coins are going to be restricted to. + */ + uint8_t max_age_group; +}; + + +GNUNET_NETWORK_STRUCT_END + +void +TALER_wallet_age_withdraw_sign ( + const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + const struct TALER_Amount *amount_with_fee, + const struct TALER_AgeMask *mask, + uint8_t max_age, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AgeWithdrawRequestPS req = { + .purpose.size = htonl (sizeof (req)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW), + .h_commitment = *h_commitment, + .mask = *mask, + .max_age_group = TALER_get_age_group (mask, max_age) + }; + + GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, + &req.reserve_pub.eddsa_pub); + TALER_amount_hton (&req.amount_with_fee, + amount_with_fee); + GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + &req, + &reserve_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_age_withdraw_verify ( + const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + const struct TALER_Amount *amount_with_fee, + const struct TALER_AgeMask *mask, + uint8_t max_age, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AgeWithdrawRequestPS awsrd = { + .purpose.size = htonl (sizeof (awsrd)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW), + .reserve_pub = *reserve_pub, + .h_commitment = *h_commitment, + .mask = *mask, + .max_age_group = TALER_get_age_group (mask, max_age) + }; + + TALER_amount_hton (&awsrd.amount_with_fee, + amount_with_fee); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW, + &awsrd, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + + +/** + * @brief Format used for to generate the signature on a request to withdraw + * coins from a reserve. + */ +struct TALER_AccountSetupRequestSignaturePS +{ + + /** + * Purpose must be #TALER_SIGNATURE_WALLET_ACCOUNT_SETUP. + * Used with an EdDSA signature of a `struct TALER_ReservePublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Balance threshold the wallet is about to cross. + */ + struct TALER_AmountNBO threshold; + +}; + + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_wallet_account_setup_sign ( + const struct TALER_ReservePrivateKeyP *reserve_priv, + const struct TALER_Amount *balance_threshold, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AccountSetupRequestSignaturePS asap = { + .purpose.size = htonl (sizeof (asap)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP) + }; + + TALER_amount_hton (&asap.threshold, + balance_threshold); + GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + &asap, + &reserve_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_account_setup_verify ( + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *balance_threshold, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AccountSetupRequestSignaturePS asap = { + .purpose.size = htonl (sizeof (asap)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP) + }; + + TALER_amount_hton (&asap.threshold, + balance_threshold); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_ACCOUNT_SETUP, + &asap, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + + +/** + * Response by which a wallet requests a reserve history. + */ +struct TALER_ReserveHistoryRequestPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_HISTORY + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Which entries to exclude. Only return above this offset. + */ + uint64_t start_off; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum GNUNET_GenericReturnValue +TALER_wallet_reserve_history_verify ( + uint64_t start_off, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveHistoryRequestPS rhr = { + .purpose.size = htonl (sizeof (rhr)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY), + .start_off = GNUNET_htonll (start_off) + }; + + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_RESERVE_HISTORY, + &rhr, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +void +TALER_wallet_reserve_history_sign ( + uint64_t start_off, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveHistoryRequestPS rhr = { + .purpose.size = htonl (sizeof (rhr)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY), + .start_off = GNUNET_htonll (start_off) + }; + + GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + &rhr, + &reserve_sig->eddsa_signature); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which a wallet requests a coin history. + */ +struct TALER_CoinHistoryRequestPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_COIN_HISTORY + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Which entries to exclude. Only return above this offset. + */ + uint64_t start_off; + +}; + +GNUNET_NETWORK_STRUCT_END + +enum GNUNET_GenericReturnValue +TALER_wallet_coin_history_verify ( + uint64_t start_off, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_CoinHistoryRequestPS rsr = { + .purpose.size = htonl (sizeof (rsr)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY), + .start_off = GNUNET_htonll (start_off) + }; + + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_COIN_HISTORY, + &rsr, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); +} + + +void +TALER_wallet_coin_history_sign ( + uint64_t start_off, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_CoinHistoryRequestPS rsr = { + .purpose.size = htonl (sizeof (rsr)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY), + .start_off = GNUNET_htonll (start_off) + }; + + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &rsr, + &coin_sig->eddsa_signature); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed to create a purse (without reserve). + */ +struct TALER_PurseCreatePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_CREATE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the purse will expire if still unmerged or unpaid. + */ + struct GNUNET_TIME_TimestampNBO purse_expiration; + + /** + * Total amount (with fees) to be put into the purse. + */ + struct TALER_AmountNBO purse_amount; + + /** + * Contract this purse pays for. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Public key identifying the merge capability. + */ + struct TALER_PurseMergePublicKeyP merge_pub; + + /** + * Minimum age required for payments into this purse. + */ + uint32_t min_age GNUNET_PACKED; + +}; + + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_wallet_purse_create_sign ( + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_PurseMergePublicKeyP *merge_pub, + uint32_t min_age, + const struct TALER_Amount *amount, + const struct TALER_PurseContractPrivateKeyP *purse_priv, + struct TALER_PurseContractSignatureP *purse_sig) +{ + struct TALER_PurseCreatePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_CREATE), + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .merge_pub = *merge_pub, + .min_age = htonl (min_age) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + GNUNET_CRYPTO_eddsa_sign (&purse_priv->eddsa_priv, + &pm, + &purse_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_create_verify ( + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_PurseMergePublicKeyP *merge_pub, + uint32_t min_age, + const struct TALER_Amount *amount, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig) +{ + struct TALER_PurseCreatePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_CREATE), + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .merge_pub = *merge_pub, + .min_age = htonl (min_age) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_PURSE_CREATE, + &pm, + &purse_sig->eddsa_signature, + &purse_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed to delete a purse. + */ +struct TALER_PurseDeletePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_DELETE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + +}; + + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_wallet_purse_delete_sign ( + const struct TALER_PurseContractPrivateKeyP *purse_priv, + struct TALER_PurseContractSignatureP *purse_sig) +{ + struct TALER_PurseDeletePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DELETE) + }; + + GNUNET_CRYPTO_eddsa_sign (&purse_priv->eddsa_priv, + &pm, + &purse_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_delete_verify ( + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig) +{ + struct TALER_PurseDeletePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DELETE) + }; + + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_PURSE_DELETE, + &pm, + &purse_sig->eddsa_signature, + &purse_pub->eddsa_pub); +} + + +void +TALER_wallet_purse_status_sign ( + const struct TALER_PurseContractPrivateKeyP *purse_priv, + struct TALER_PurseContractSignatureP *purse_sig) +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_STATUS) + }; + + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&purse_priv->eddsa_priv, + &purpose, + &purse_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_status_verify ( + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig) +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_STATUS) + }; + + return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_PURSE_STATUS, + &purpose, + &purse_sig->eddsa_signature, + &purse_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed to deposit a coin into a purse. + */ +struct TALER_PurseDepositPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_DEPOSIT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Amount (with deposit fee) to be deposited into the purse. + */ + struct TALER_AmountNBO coin_amount; + + /** + * Hash over the denomination public key used to sign the coin. + */ + struct TALER_DenominationHashP h_denom_pub GNUNET_PACKED; + + /** + * Hash over the age commitment that went into the coin. Maybe all zero, if + * age commitment isn't applicable to the denomination. + */ + struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED; + + /** + * Purse to deposit funds into. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Hash of the base URL of the exchange hosting the + * @e purse_pub. + */ + struct GNUNET_HashCode h_exchange_base_url GNUNET_PACKED; +}; + +GNUNET_NETWORK_STRUCT_END + +void +TALER_wallet_purse_deposit_sign ( + const char *exchange_base_url, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_Amount *amount, + const struct TALER_DenominationHashP *h_denom_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_PurseDepositPS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DEPOSIT), + .purse_pub = *purse_pub, + .h_denom_pub = *h_denom_pub, + .h_age_commitment = *h_age_commitment + }; + + GNUNET_CRYPTO_hash (exchange_base_url, + strlen (exchange_base_url) + 1, + &pm.h_exchange_base_url); + TALER_amount_hton (&pm.coin_amount, + amount); + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &pm, + &coin_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_deposit_verify ( + const char *exchange_base_url, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_Amount *amount, + const struct TALER_DenominationHashP *h_denom_pub, + const struct TALER_AgeCommitmentHash *h_age_commitment, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_PurseDepositPS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DEPOSIT), + .purse_pub = *purse_pub, + .h_denom_pub = *h_denom_pub, + .h_age_commitment = *h_age_commitment + }; + + GNUNET_CRYPTO_hash (exchange_base_url, + strlen (exchange_base_url) + 1, + &pm.h_exchange_base_url); + TALER_amount_hton (&pm.coin_amount, + amount); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_PURSE_DEPOSIT, + &pm, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed to merge a purse into a reserve. + */ +struct TALER_PurseMergePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_MERGE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the purse is merged into the reserve. + */ + struct GNUNET_TIME_TimestampNBO merge_timestamp; + + /** + * Which purse is being merged? + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Which reserve should the purse be merged with. + * Hash of the reserve's payto:// URI. + */ + struct TALER_PaytoHashP h_payto; + +}; + +GNUNET_NETWORK_STRUCT_END + +void +TALER_wallet_purse_merge_sign ( + const char *reserve_uri, + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseMergePrivateKeyP *merge_priv, + struct TALER_PurseMergeSignatureP *merge_sig) +{ + struct TALER_PurseMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .purse_pub = *purse_pub + }; + + GNUNET_assert (0 == + strncasecmp (reserve_uri, + "payto://taler-reserve", + strlen ("payto://taler-reserve"))); + TALER_payto_hash (reserve_uri, + &pm.h_payto); + GNUNET_CRYPTO_eddsa_sign (&merge_priv->eddsa_priv, + &pm, + &merge_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_merge_verify ( + const char *reserve_uri, + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseMergePublicKeyP *merge_pub, + const struct TALER_PurseMergeSignatureP *merge_sig) +{ + struct TALER_PurseMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .purse_pub = *purse_pub + }; + + if (0 != + strncasecmp (reserve_uri, + "payto://taler-reserve", + strlen ("payto://taler-reserve"))) + { + GNUNET_break (0); + return GNUNET_NO; + } + TALER_payto_hash (reserve_uri, + &pm.h_payto); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_PURSE_MERGE, + &pm, + &merge_sig->eddsa_signature, + &merge_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed by account to merge a purse into a reserve. + */ +struct TALER_AccountMergePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_ACCOUNT_MERGE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the purse will expire if still unmerged or unpaid. + */ + struct GNUNET_TIME_TimestampNBO purse_expiration; + + /** + * Total amount (with fees) to be put into the purse. + */ + struct TALER_AmountNBO purse_amount; + + /** + * Purse creation fee to be paid by the reserve for + * this operation. + */ + struct TALER_AmountNBO purse_fee; + + /** + * Contract this purse pays for. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Purse to merge. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Time when the purse is merged into the reserve. + */ + struct GNUNET_TIME_TimestampNBO merge_timestamp; + + /** + * Minimum age required for payments into this purse, + * in NBO. + */ + uint32_t min_age GNUNET_PACKED; + + /** + * Flags for the operation, in NBO. See + * `enum TALER_WalletAccountMergeFlags`. + */ + uint32_t flags GNUNET_PACKED; +}; + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_wallet_account_merge_sign ( + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PurseContractPublicKeyP *purse_pub, + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_Amount *amount, + const struct TALER_Amount *purse_fee, + uint32_t min_age, + enum TALER_WalletAccountMergeFlags flags, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AccountMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .purse_pub = *purse_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .min_age = htonl (min_age), + .flags = htonl ((uint32_t) flags) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + TALER_amount_hton (&pm.purse_fee, + purse_fee); + GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + &pm, + &reserve_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_account_merge_verify ( + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PurseContractPublicKeyP *purse_pub, + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_Amount *amount, + const struct TALER_Amount *purse_fee, + uint32_t min_age, + enum TALER_WalletAccountMergeFlags flags, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AccountMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .purse_pub = *purse_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .min_age = htonl (min_age), + .flags = htonl ((uint32_t) flags) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + TALER_amount_hton (&pm.purse_fee, + purse_fee); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_ACCOUNT_MERGE, + &pm, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed by reserve key. + */ +struct TALER_ReserveOpenPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_OPEN + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Amount to be paid from the reserve balance to open + * the reserve. + */ + struct TALER_AmountNBO reserve_payment; + + /** + * When was the request created. + */ + struct GNUNET_TIME_TimestampNBO request_timestamp; + + /** + * For how long should the reserve be kept open. + * (Determines amount to be paid.) + */ + struct GNUNET_TIME_TimestampNBO reserve_expiration; + + /** + * How many open purses should be included with the + * open reserve? + * (Determines amount to be paid.) + */ + uint32_t purse_limit GNUNET_PACKED; + +}; + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_wallet_reserve_open_sign ( + const struct TALER_Amount *reserve_payment, + struct GNUNET_TIME_Timestamp request_timestamp, + struct GNUNET_TIME_Timestamp reserve_expiration, + uint32_t purse_limit, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveOpenPS rop = { + .purpose.size = htonl (sizeof (rop)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN), + .request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp), + .reserve_expiration = GNUNET_TIME_timestamp_hton (reserve_expiration), + .purse_limit = htonl (purse_limit) + }; + + TALER_amount_hton (&rop.reserve_payment, + reserve_payment); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&reserve_priv->eddsa_priv, + &rop.purpose, + &reserve_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_reserve_open_verify ( + const struct TALER_Amount *reserve_payment, + struct GNUNET_TIME_Timestamp request_timestamp, + struct GNUNET_TIME_Timestamp reserve_expiration, + uint32_t purse_limit, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveOpenPS rop = { + .purpose.size = htonl (sizeof (rop)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN), + .request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp), + .reserve_expiration = GNUNET_TIME_timestamp_hton (reserve_expiration), + .purse_limit = htonl (purse_limit) + }; + + TALER_amount_hton (&rop.reserve_payment, + reserve_payment); + return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_RESERVE_OPEN, + &rop.purpose, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed by + */ +struct TALER_ReserveOpenDepositPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Which reserve's opening signature should be paid for? + */ + struct TALER_ReserveSignatureP reserve_sig; + + /** + * Specifies how much of the coin's value should be spent on opening this + * reserve. + */ + struct TALER_AmountNBO coin_contribution; +}; + +GNUNET_NETWORK_STRUCT_END + + +// FIXME-#7267: add h_age_commitment, h_denom_pub to have proof! +void +TALER_wallet_reserve_open_deposit_sign ( + const struct TALER_Amount *coin_contribution, + const struct TALER_ReserveSignatureP *reserve_sig, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_ReserveOpenDepositPS rod = { + .purpose.size = htonl (sizeof (rod)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT), + .reserve_sig = *reserve_sig + }; + + TALER_amount_hton (&rod.coin_contribution, + coin_contribution); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&coin_priv->eddsa_priv, + &rod.purpose, + &coin_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_reserve_open_deposit_verify ( + const struct TALER_Amount *coin_contribution, + const struct TALER_ReserveSignatureP *reserve_sig, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_ReserveOpenDepositPS rod = { + .purpose.size = htonl (sizeof (rod)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT), + .reserve_sig = *reserve_sig + }; + + TALER_amount_hton (&rod.coin_contribution, + coin_contribution); + return GNUNET_CRYPTO_eddsa_verify_ ( + TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT, + &rod.purpose, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed by reserve key. + */ +struct TALER_ReserveClosePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_CLOSE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When was the request created. + */ + struct GNUNET_TIME_TimestampNBO request_timestamp; + + /** + * Hash of the payto://-URI of the target account + * for the closure, or all zeros for the reserve + * origin account. + */ + struct TALER_PaytoHashP target_account_h_payto; + +}; + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_wallet_reserve_close_sign ( + struct GNUNET_TIME_Timestamp request_timestamp, + const struct TALER_PaytoHashP *h_payto, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveClosePS rcp = { + .purpose.size = htonl (sizeof (rcp)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_CLOSE), + .request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp) + }; + + if (NULL != h_payto) + rcp.target_account_h_payto = *h_payto; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&reserve_priv->eddsa_priv, + &rcp.purpose, + &reserve_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_reserve_close_verify ( + struct GNUNET_TIME_Timestamp request_timestamp, + const struct TALER_PaytoHashP *h_payto, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveClosePS rcp = { + .purpose.size = htonl (sizeof (rcp)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_CLOSE), + .request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp) + }; + + if (NULL != h_payto) + rcp.target_account_h_payto = *h_payto; + return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_RESERVE_CLOSE, + &rcp.purpose, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed by reserve private key. + */ +struct TALER_ReserveAttestRequestPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_ATTEST_REQUEST + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When was the request created. + */ + struct GNUNET_TIME_TimestampNBO request_timestamp; + + /** + * Hash over the JSON array of requested attributes. + */ + struct GNUNET_HashCode h_details; + +}; + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_wallet_reserve_attest_request_sign ( + struct GNUNET_TIME_Timestamp request_timestamp, + const json_t *details, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveAttestRequestPS rcp = { + .purpose.size = htonl (sizeof (rcp)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_ATTEST_DETAILS), + .request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp) + }; + + TALER_json_hash (details, + &rcp.h_details); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&reserve_priv->eddsa_priv, + &rcp.purpose, + &reserve_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_reserve_attest_request_verify ( + struct GNUNET_TIME_Timestamp request_timestamp, + const json_t *details, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_ReserveAttestRequestPS rcp = { + .purpose.size = htonl (sizeof (rcp)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_ATTEST_DETAILS), + .request_timestamp = GNUNET_TIME_timestamp_hton (request_timestamp) + }; + + TALER_json_hash (details, + &rcp.h_details); + return GNUNET_CRYPTO_eddsa_verify_ ( + TALER_SIGNATURE_WALLET_RESERVE_ATTEST_DETAILS, + &rcp.purpose, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed by purse to associate an encrypted contract. + */ +struct TALER_PurseContractPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_ECONTRACT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the encrypted contract. + */ + struct GNUNET_HashCode h_econtract; + + /** + * Public key to decrypt the contract. + */ + struct TALER_ContractDiffiePublicP contract_pub; +}; + +GNUNET_NETWORK_STRUCT_END + +void +TALER_wallet_econtract_upload_sign ( + const void *econtract, + size_t econtract_size, + const struct TALER_ContractDiffiePublicP *contract_pub, + const struct TALER_PurseContractPrivateKeyP *purse_priv, + struct TALER_PurseContractSignatureP *purse_sig) +{ + struct TALER_PurseContractPS pc = { + .purpose.size = htonl (sizeof (pc)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_ECONTRACT), + .contract_pub = *contract_pub + }; + + GNUNET_CRYPTO_hash (econtract, + econtract_size, + &pc.h_econtract); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&purse_priv->eddsa_priv, + &pc.purpose, + &purse_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_econtract_upload_verify2 ( + const struct GNUNET_HashCode *h_econtract, + const struct TALER_ContractDiffiePublicP *contract_pub, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig) +{ + struct TALER_PurseContractPS pc = { + .purpose.size = htonl (sizeof (pc)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_ECONTRACT), + .contract_pub = *contract_pub, + .h_econtract = *h_econtract + }; + + return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_PURSE_ECONTRACT, + &pc.purpose, + &purse_sig->eddsa_signature, + &purse_pub->eddsa_pub); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_econtract_upload_verify ( + const void *econtract, + size_t econtract_size, + const struct TALER_ContractDiffiePublicP *contract_pub, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PurseContractSignatureP *purse_sig) +{ + struct GNUNET_HashCode h_econtract; + + GNUNET_CRYPTO_hash (econtract, + econtract_size, + &h_econtract); + return TALER_wallet_econtract_upload_verify2 (&h_econtract, + contract_pub, + purse_pub, + purse_sig); +} + + /* end of wallet_signatures.c */ |