diff options
Diffstat (limited to 'src/util/exchange_signatures.c')
-rw-r--r-- | src/util/exchange_signatures.c | 1894 |
1 files changed, 1894 insertions, 0 deletions
diff --git a/src/util/exchange_signatures.c b/src/util/exchange_signatures.c new file mode 100644 index 000000000..aaefb5cec --- /dev/null +++ b/src/util/exchange_signatures.c @@ -0,0 +1,1894 @@ +/* + This file is part of TALER + 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 + 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 exchange_signatures.c + * @brief Utility functions for Taler security module signatures + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used to generate the signature on a confirmation + * from the exchange that a deposit request succeeded. + */ +struct TALER_DepositConfirmationPS +{ + /** + * Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT. Signed + * by a `struct TALER_ExchangePublicKeyP` using EdDSA. + */ + 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 wiring information of the merchant. + */ + struct TALER_MerchantWireHashP h_wire GNUNET_PACKED; + + /** + * Hash over the optional policy extension of the deposit, 0 if there + * was no policy. + */ + struct TALER_ExtensionPolicyHashP h_policy GNUNET_PACKED; + + /** + * Time when this confirmation was generated / when the exchange received + * the deposit request. + */ + struct GNUNET_TIME_TimestampNBO exchange_timestamp; + + /** + * By when does the exchange expect to pay the merchant + * (as per the merchant's request). + */ + struct GNUNET_TIME_TimestampNBO wire_deadline; + + /** + * How much time does the @e merchant have to issue a refund + * request? Zero if refunds are not allowed. After this time, the + * coin cannot be refunded. Note that the wire transfer will not be + * performed by the exchange until the refund deadline. This value + * is taken from the original deposit request. + */ + struct GNUNET_TIME_TimestampNBO refund_deadline; + + /** + * Amount to be deposited, excluding fee. Calculated from the + * amount with fee and the fee from the deposit request. + */ + struct TALER_AmountNBO total_without_fee; + + /** + * Hash over all of the coin signatures. + */ + struct GNUNET_HashCode h_coin_sigs; + + /** + * 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_pub; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_deposit_confirmation_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_ExtensionPolicyHashP *h_policy, + struct GNUNET_TIME_Timestamp exchange_timestamp, + struct GNUNET_TIME_Timestamp wire_deadline, + struct GNUNET_TIME_Timestamp refund_deadline, + const struct TALER_Amount *total_without_fee, + unsigned int num_coins, + const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins], + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_DepositConfirmationPS dcs = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT), + .purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)), + .h_contract_terms = *h_contract_terms, + .h_wire = *h_wire, + .exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp), + .wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline), + .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline), + .merchant_pub = *merchant_pub, + .h_policy = {{{0}}} + }; + struct GNUNET_HashContext *hc; + + hc = GNUNET_CRYPTO_hash_context_start (); + for (unsigned int i = 0; i<num_coins; i++) + GNUNET_CRYPTO_hash_context_read (hc, + coin_sigs[i], + sizeof (*coin_sigs[i])); + GNUNET_CRYPTO_hash_context_finish (hc, + &dcs.h_coin_sigs); + if (NULL != h_policy) + dcs.h_policy = *h_policy; + TALER_amount_hton (&dcs.total_without_fee, + total_without_fee); + return scb (&dcs.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_deposit_confirmation_verify ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_ExtensionPolicyHashP *h_policy, + struct GNUNET_TIME_Timestamp exchange_timestamp, + struct GNUNET_TIME_Timestamp wire_deadline, + struct GNUNET_TIME_Timestamp refund_deadline, + const struct TALER_Amount *total_without_fee, + unsigned int num_coins, + const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins], + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const struct TALER_ExchangeSignatureP *exchange_sig) +{ + struct TALER_DepositConfirmationPS dcs = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT), + .purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)), + .h_contract_terms = *h_contract_terms, + .h_wire = *h_wire, + .exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp), + .wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline), + .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline), + .merchant_pub = *merchant_pub + }; + struct GNUNET_HashContext *hc; + + hc = GNUNET_CRYPTO_hash_context_start (); + for (unsigned int i = 0; i<num_coins; i++) + GNUNET_CRYPTO_hash_context_read (hc, + coin_sigs[i], + sizeof (*coin_sigs[i])); + GNUNET_CRYPTO_hash_context_finish (hc, + &dcs.h_coin_sigs); + if (NULL != h_policy) + dcs.h_policy = *h_policy; + TALER_amount_hton (&dcs.total_without_fee, + total_without_fee); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT, + &dcs, + &exchange_sig->eddsa_signature, + &exchange_pub->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used to generate the signature on a request to refund + * a coin into the account of the customer. + */ +struct TALER_RefundConfirmationPS +{ + /** + * Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the proposal data to identify the contract + * which is being refunded. + */ + struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED; + + /** + * The coin's public key. This is the value that must have been + * signed (blindly) by the Exchange. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * 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; + + /** + * Merchant-generated transaction ID for the refund. + */ + uint64_t rtransaction_id GNUNET_PACKED; + + /** + * Amount to be refunded, including refund fee charged by the + * exchange to the customer. + */ + struct TALER_AmountNBO refund_amount; +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_refund_confirmation_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant, + uint64_t rtransaction_id, + const struct TALER_Amount *refund_amount, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_RefundConfirmationPS rc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND), + .purpose.size = htonl (sizeof (rc)), + .h_contract_terms = *h_contract_terms, + .coin_pub = *coin_pub, + .merchant = *merchant, + .rtransaction_id = GNUNET_htonll (rtransaction_id) + }; + + TALER_amount_hton (&rc.refund_amount, + refund_amount); + return scb (&rc.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_refund_confirmation_verify ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPublicKeyP *merchant, + uint64_t rtransaction_id, + const struct TALER_Amount *refund_amount, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_RefundConfirmationPS rc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND), + .purpose.size = htonl (sizeof (rc)), + .h_contract_terms = *h_contract_terms, + .coin_pub = *coin_pub, + .merchant = *merchant, + .rtransaction_id = GNUNET_htonll (rtransaction_id) + }; + + TALER_amount_hton (&rc.refund_amount, + refund_amount); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND, + &rc, + &sig->eddsa_signature, + &pub->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format of the block signed by the Exchange in response to a successful + * "/refresh/melt" request. Hereby the exchange affirms that all of the + * coins were successfully melted. This also commits the exchange to a + * particular index to not be revealed during the refresh. + */ +struct TALER_RefreshMeltConfirmationPS +{ + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT. Signed + * by a `struct TALER_ExchangePublicKeyP` using EdDSA. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Commitment made in the /refresh/melt. + */ + struct TALER_RefreshCommitmentP rc GNUNET_PACKED; + + /** + * Index that the client will not have to reveal, in NBO. + * Must be smaller than #TALER_CNC_KAPPA. + */ + uint32_t noreveal_index GNUNET_PACKED; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_melt_confirmation_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_RefreshCommitmentP *rc, + uint32_t noreveal_index, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_RefreshMeltConfirmationPS confirm = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT), + .purpose.size = htonl (sizeof (confirm)), + .rc = *rc, + .noreveal_index = htonl (noreveal_index) + }; + + return scb (&confirm.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_melt_confirmation_verify ( + const struct TALER_RefreshCommitmentP *rc, + uint32_t noreveal_index, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const struct TALER_ExchangeSignatureP *exchange_sig) +{ + struct TALER_RefreshMeltConfirmationPS confirm = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT), + .purpose.size = htonl (sizeof (confirm)), + .rc = *rc, + .noreveal_index = htonl (noreveal_index) + }; + + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT, + &confirm, + &exchange_sig->eddsa_signature, + &exchange_pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format of the block signed by the Exchange in response to a + * successful "/reserves/$RESERVE_PUB/age-withdraw" request. Hereby the + * exchange affirms that the commitment along with the maximum age group and + * the amount were accepted. This also commits the exchange to a particular + * index to not be revealed during the reveal. + */ +struct TALER_AgeWithdrawConfirmationPS +{ + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW. Signed by a + * `struct TALER_ExchangePublicKeyP` using EdDSA. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Commitment made in the /reserves/$RESERVE_PUB/age-withdraw. + */ + struct TALER_AgeWithdrawCommitmentHashP h_commitment GNUNET_PACKED; + + /** + * Index that the client will not have to reveal, in NBO. + * Must be smaller than #TALER_CNC_KAPPA. + */ + uint32_t noreveal_index GNUNET_PACKED; + +}; + +GNUNET_NETWORK_STRUCT_END + +enum TALER_ErrorCode +TALER_exchange_online_age_withdraw_confirmation_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + uint32_t noreveal_index, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + + struct TALER_AgeWithdrawConfirmationPS confirm = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW), + .purpose.size = htonl (sizeof (confirm)), + .h_commitment = *h_commitment, + .noreveal_index = htonl (noreveal_index) + }; + + return scb (&confirm.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_age_withdraw_confirmation_verify ( + const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + uint32_t noreveal_index, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const struct TALER_ExchangeSignatureP *exchange_sig) +{ + struct TALER_AgeWithdrawConfirmationPS confirm = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW), + .purpose.size = htonl (sizeof (confirm)), + .h_commitment = *h_commitment, + .noreveal_index = htonl (noreveal_index) + }; + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW, + &confirm, + &exchange_sig->eddsa_signature, + &exchange_pub->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/* TODO:oec: add signature for age-withdraw, age-reveal */ + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Signature made by the exchange over the full set of keys, used + * to detect cheating exchanges that give out different sets to + * different users. + */ +struct TALER_ExchangeKeySetPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_KEY_SET. Signed + * by a `struct TALER_ExchangePublicKeyP` using EdDSA. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time of the key set issue. + */ + struct GNUNET_TIME_TimestampNBO list_issue_date; + + /** + * Hash over the various denomination signing keys returned. + */ + struct GNUNET_HashCode hc GNUNET_PACKED; +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_key_set_sign ( + TALER_ExchangeSignCallback2 scb, + void *cls, + struct GNUNET_TIME_Timestamp timestamp, + const struct GNUNET_HashCode *hc, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ExchangeKeySetPS ks = { + .purpose.size = htonl (sizeof (ks)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET), + .list_issue_date = GNUNET_TIME_timestamp_hton (timestamp), + .hc = *hc + }; + + return scb (cls, + &ks.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_key_set_verify ( + struct GNUNET_TIME_Timestamp timestamp, + const struct GNUNET_HashCode *hc, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ExchangeKeySetPS ks = { + .purpose.size = htonl (sizeof (ks)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET), + .list_issue_date = GNUNET_TIME_timestamp_hton (timestamp), + .hc = *hc + }; + + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET, + &ks, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Signature by which an exchange affirms that an account + * successfully passed the KYC checks. + */ +struct TALER_ExchangeAccountSetupSuccessPS +{ + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS. Signed by a + * `struct TALER_ExchangePublicKeyP` using EdDSA. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the payto for which the signature was made. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Hash over details on *which* KYC obligations were discharged! + */ + struct GNUNET_HashCode h_kyc; + + /** + * When was the signature made. + */ + struct GNUNET_TIME_TimestampNBO timestamp; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_account_setup_success_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_PaytoHashP *h_payto, + const json_t *kyc, + struct GNUNET_TIME_Timestamp timestamp, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ExchangeAccountSetupSuccessPS kyc_purpose = { + .purpose.size = htonl (sizeof (kyc_purpose)), + .purpose.purpose = htonl ( + TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS), + .h_payto = *h_payto, + .timestamp = GNUNET_TIME_timestamp_hton (timestamp) + }; + + TALER_json_hash (kyc, + &kyc_purpose.h_kyc); + return scb (&kyc_purpose.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_account_setup_success_verify ( + const struct TALER_PaytoHashP *h_payto, + const json_t *kyc, + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ExchangeAccountSetupSuccessPS kyc_purpose = { + .purpose.size = htonl (sizeof (kyc_purpose)), + .purpose.purpose = htonl ( + TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS), + .h_payto = *h_payto, + .timestamp = GNUNET_TIME_timestamp_hton (timestamp) + }; + + TALER_json_hash (kyc, + &kyc_purpose.h_kyc); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS, + &kyc_purpose, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format internally used for packing the detailed information + * to generate the signature for /track/transfer signatures. + */ +struct TALER_WireDepositDetailP +{ + + /** + * Hash of the contract + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Time when the wire transfer was performed by the exchange. + */ + struct GNUNET_TIME_TimestampNBO execution_time; + + /** + * Coin's public key. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Total value of the coin. + */ + struct TALER_AmountNBO deposit_value; + + /** + * Fees charged by the exchange for the deposit. + */ + struct TALER_AmountNBO deposit_fee; + +}; + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_exchange_online_wire_deposit_append ( + struct GNUNET_HashContext *hash_context, + const struct TALER_PrivateContractHashP *h_contract_terms, + struct GNUNET_TIME_Timestamp execution_time, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *deposit_value, + const struct TALER_Amount *deposit_fee) +{ + struct TALER_WireDepositDetailP dd = { + .h_contract_terms = *h_contract_terms, + .execution_time = GNUNET_TIME_timestamp_hton (execution_time), + .coin_pub = *coin_pub + }; + TALER_amount_hton (&dd.deposit_value, + deposit_value); + TALER_amount_hton (&dd.deposit_fee, + deposit_fee); + GNUNET_CRYPTO_hash_context_read (hash_context, + &dd, + sizeof (dd)); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used to generate the signature for /wire/deposit + * replies. + */ +struct TALER_WireDepositDataPS +{ + /** + * Purpose header for the signature over the contract with + * purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Total amount that was transferred. + */ + struct TALER_AmountNBO total; + + /** + * Wire fee that was charged. + */ + struct TALER_AmountNBO wire_fee; + + /** + * Public key of the merchant (for all aggregated transactions). + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Hash of bank account of the merchant. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Hash of the individual deposits that were aggregated, + * each in the format of a `struct TALER_WireDepositDetailP`. + */ + struct GNUNET_HashCode h_details; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_wire_deposit_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_Amount *total, + const struct TALER_Amount *wire_fee, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const char *payto, + const struct GNUNET_HashCode *h_details, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_WireDepositDataPS wdp = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT), + .purpose.size = htonl (sizeof (wdp)), + .merchant_pub = *merchant_pub, + .h_details = *h_details + }; + + TALER_amount_hton (&wdp.total, + total); + TALER_amount_hton (&wdp.wire_fee, + wire_fee); + TALER_payto_hash (payto, + &wdp.h_payto); + return scb (&wdp.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_wire_deposit_verify ( + const struct TALER_Amount *total, + const struct TALER_Amount *wire_fee, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_PaytoHashP *h_payto, + const struct GNUNET_HashCode *h_details, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_WireDepositDataPS wdp = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT), + .purpose.size = htonl (sizeof (wdp)), + .merchant_pub = *merchant_pub, + .h_details = *h_details, + .h_payto = *h_payto + }; + + TALER_amount_hton (&wdp.total, + total); + TALER_amount_hton (&wdp.wire_fee, + wire_fee); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT, + &wdp, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Details affirmed by the exchange about a wire transfer the exchange + * claims to have done with respect to a deposit operation. + */ +struct TALER_ConfirmWirePS +{ + /** + * Purpose header for the signature over the contract with + * purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the wiring information of the merchant. + */ + struct TALER_MerchantWireHashP h_wire GNUNET_PACKED; + + /** + * Hash over the contract for which this deposit is made. + */ + struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED; + + /** + * Raw value (binary encoding) of the wire transfer subject. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * The coin's public key. This is the value that must have been + * signed (blindly) by the Exchange. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * When did the exchange execute this transfer? Note that the + * timestamp may not be exactly the same on the wire, i.e. + * because the wire has a different timezone or resolution. + */ + struct GNUNET_TIME_TimestampNBO execution_time; + + /** + * The contribution of @e coin_pub to the total transfer volume. + * This is the value of the deposit minus the fee. + */ + struct TALER_AmountNBO coin_contribution; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_confirm_wire_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct GNUNET_TIME_Timestamp execution_time, + const struct TALER_Amount *coin_contribution, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) + +{ + struct TALER_ConfirmWirePS cw = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE), + .purpose.size = htonl (sizeof (cw)), + .h_wire = *h_wire, + .h_contract_terms = *h_contract_terms, + .wtid = *wtid, + .coin_pub = *coin_pub, + .execution_time = GNUNET_TIME_timestamp_hton (execution_time) + }; + + TALER_amount_hton (&cw.coin_contribution, + coin_contribution); + return scb (&cw.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_confirm_wire_verify ( + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct GNUNET_TIME_Timestamp execution_time, + const struct TALER_Amount *coin_contribution, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ConfirmWirePS cw = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE), + .purpose.size = htonl (sizeof (cw)), + .h_wire = *h_wire, + .h_contract_terms = *h_contract_terms, + .wtid = *wtid, + .coin_pub = *coin_pub, + .execution_time = GNUNET_TIME_timestamp_hton (execution_time) + }; + + TALER_amount_hton (&cw.coin_contribution, + coin_contribution); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE, + &cw, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it will + * refund a coin as part of the emergency /recoup + * protocol. The recoup will go back to the bank + * account that created the reserve. + */ +struct TALER_RecoupConfirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the exchange receive the recoup request? + * Indirectly determines when the wire transfer is (likely) + * to happen. + */ + struct GNUNET_TIME_TimestampNBO timestamp; + + /** + * How much of the coin's value will the exchange transfer? + * (Needed in case the coin was partially spent.) + */ + struct TALER_AmountNBO recoup_amount; + + /** + * Public key of the coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Public key of the reserve that will receive the recoup. + */ + struct TALER_ReservePublicKeyP reserve_pub; +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_confirm_recoup_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_Amount *recoup_amount, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_RecoupConfirmationPS pc = { + .purpose.size = htonl (sizeof (pc)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .coin_pub = *coin_pub, + .reserve_pub = *reserve_pub + }; + + TALER_amount_hton (&pc.recoup_amount, + recoup_amount); + return scb (&pc.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_confirm_recoup_verify ( + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_Amount *recoup_amount, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_RecoupConfirmationPS pc = { + .purpose.size = htonl (sizeof (pc)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .coin_pub = *coin_pub, + .reserve_pub = *reserve_pub + }; + + TALER_amount_hton (&pc.recoup_amount, + recoup_amount); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP, + &pc, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it will refund a refreshed coin + * as part of the emergency /recoup protocol. The recoup will go back to the + * old coin's balance. + */ +struct TALER_RecoupRefreshConfirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the exchange receive the recoup request? + * Indirectly determines when the wire transfer is (likely) + * to happen. + */ + struct GNUNET_TIME_TimestampNBO timestamp; + + /** + * How much of the coin's value will the exchange transfer? + * (Needed in case the coin was partially spent.) + */ + struct TALER_AmountNBO recoup_amount; + + /** + * Public key of the refreshed coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Public key of the old coin that will receive the recoup. + */ + struct TALER_CoinSpendPublicKeyP old_coin_pub; +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_confirm_recoup_refresh_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_Amount *recoup_amount, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendPublicKeyP *old_coin_pub, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_RecoupRefreshConfirmationPS pc = { + .purpose.purpose = htonl ( + TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH), + .purpose.size = htonl (sizeof (pc)), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .coin_pub = *coin_pub, + .old_coin_pub = *old_coin_pub + }; + + TALER_amount_hton (&pc.recoup_amount, + recoup_amount); + return scb (&pc.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_confirm_recoup_refresh_verify ( + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_Amount *recoup_amount, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendPublicKeyP *old_coin_pub, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_RecoupRefreshConfirmationPS pc = { + .purpose.purpose = htonl ( + TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH), + .purpose.size = htonl (sizeof (pc)), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .coin_pub = *coin_pub, + .old_coin_pub = *old_coin_pub + }; + + TALER_amount_hton (&pc.recoup_amount, + recoup_amount); + + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH, + &pc, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it does not + * currently know a denomination by the given hash. + */ +struct TALER_DenominationUnknownAffirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the exchange sign this message. + */ + struct GNUNET_TIME_TimestampNBO timestamp; + + /** + * Hash of the public denomination key we do not know. + */ + struct TALER_DenominationHashP h_denom_pub; +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_denomination_unknown_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_DenominationHashP *h_denom_pub, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_DenominationUnknownAffirmationPS dua = { + .purpose.size = htonl (sizeof (dua)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .h_denom_pub = *h_denom_pub, + }; + + return scb (&dua.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_denomination_unknown_verify ( + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_DenominationHashP *h_denom_pub, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_DenominationUnknownAffirmationPS dua = { + .purpose.size = htonl (sizeof (dua)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .h_denom_pub = *h_denom_pub, + }; + + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN, + &dua, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it does not + * currently consider the given denomination to be valid + * for the requested operation. + */ +struct TALER_DenominationExpiredAffirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the exchange sign this message. + */ + struct GNUNET_TIME_TimestampNBO timestamp; + + /** + * Name of the operation that is not allowed at this time. Might NOT be 0-terminated, but is padded with 0s. + */ + char operation[8]; + + /** + * Hash of the public denomination key we do not know. + */ + struct TALER_DenominationHashP h_denom_pub; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_denomination_expired_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_DenominationHashP *h_denom_pub, + const char *op, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_DenominationExpiredAffirmationPS dua = { + .purpose.size = htonl (sizeof (dua)), + .purpose.purpose = htonl ( + TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .h_denom_pub = *h_denom_pub, + }; + + /* strncpy would create a compiler warning */ + GNUNET_memcpy (dua.operation, + op, + GNUNET_MIN (sizeof (dua.operation), + strlen (op))); + return scb (&dua.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_denomination_expired_verify ( + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_DenominationHashP *h_denom_pub, + const char *op, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_DenominationExpiredAffirmationPS dua = { + .purpose.size = htonl (sizeof (dua)), + .purpose.purpose = htonl ( + TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED), + .timestamp = GNUNET_TIME_timestamp_hton (timestamp), + .h_denom_pub = *h_denom_pub, + }; + + /* strncpy would create a compiler warning */ + GNUNET_memcpy (dua.operation, + op, + GNUNET_MIN (sizeof (dua.operation), + strlen (op))); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED, + &dua, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it has + * closed a reserve and send back the funds. + */ +struct TALER_ReserveCloseConfirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the exchange initiate the wire transfer. + */ + struct GNUNET_TIME_TimestampNBO timestamp; + + /** + * How much did the exchange send? + */ + struct TALER_AmountNBO closing_amount; + + /** + * How much did the exchange charge for closing the reserve? + */ + struct TALER_AmountNBO closing_fee; + + /** + * Public key of the reserve that was closed. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Hash of the receiver's bank account. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Wire transfer subject. + */ + struct TALER_WireTransferIdentifierRawP wtid; +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_reserve_closed_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_Amount *closing_amount, + const struct TALER_Amount *closing_fee, + const char *payto, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ReserveCloseConfirmationPS rcc = { + .purpose.size = htonl (sizeof (rcc)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED), + .wtid = *wtid, + .reserve_pub = *reserve_pub, + .timestamp = GNUNET_TIME_timestamp_hton (timestamp) + }; + + TALER_amount_hton (&rcc.closing_amount, + closing_amount); + TALER_amount_hton (&rcc.closing_fee, + closing_fee); + TALER_payto_hash (payto, + &rcc.h_payto); + return scb (&rcc.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_reserve_closed_verify ( + struct GNUNET_TIME_Timestamp timestamp, + const struct TALER_Amount *closing_amount, + const struct TALER_Amount *closing_fee, + const char *payto, + const struct TALER_WireTransferIdentifierRawP *wtid, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ReserveCloseConfirmationPS rcc = { + .purpose.size = htonl (sizeof (rcc)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED), + .wtid = *wtid, + .reserve_pub = *reserve_pub, + .timestamp = GNUNET_TIME_timestamp_hton (timestamp) + }; + + TALER_amount_hton (&rcc.closing_amount, + closing_amount); + TALER_amount_hton (&rcc.closing_fee, + closing_fee); + TALER_payto_hash (payto, + &rcc.h_payto); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED, + &rcc, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it has + * received funds deposited into a purse. + */ +struct TALER_PurseCreateDepositConfirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the exchange receive the deposits. + */ + struct GNUNET_TIME_TimestampNBO exchange_time; + + /** + * When will the purse expire? + */ + struct GNUNET_TIME_TimestampNBO purse_expiration; + + /** + * How much should the purse ultimately contain. + */ + struct TALER_AmountNBO amount_without_fee; + + /** + * How much was deposited so far. + */ + struct TALER_AmountNBO total_deposited; + + /** + * Public key of the purse. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Hash of the contract of the purse. + */ + struct TALER_PrivateContractHashP h_contract_terms; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_purse_created_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp exchange_time, + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_Amount *amount_without_fee, + const struct TALER_Amount *total_deposited, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PrivateContractHashP *h_contract_terms, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_PurseCreateDepositConfirmationPS dc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION), + .purpose.size = htonl (sizeof (dc)), + .h_contract_terms = *h_contract_terms, + .purse_pub = *purse_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time) + }; + + TALER_amount_hton (&dc.amount_without_fee, + amount_without_fee); + TALER_amount_hton (&dc.total_deposited, + total_deposited); + return scb (&dc.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_purse_created_verify ( + struct GNUNET_TIME_Timestamp exchange_time, + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_Amount *amount_without_fee, + const struct TALER_Amount *total_deposited, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_PurseCreateDepositConfirmationPS dc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION), + .purpose.size = htonl (sizeof (dc)), + .h_contract_terms = *h_contract_terms, + .purse_pub = *purse_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time) + }; + + TALER_amount_hton (&dc.amount_without_fee, + amount_without_fee); + TALER_amount_hton (&dc.total_deposited, + total_deposited); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION, + &dc, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it has + * received funds deposited into a purse. + */ +struct TALER_CoinPurseRefundConfirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Public key of the purse. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Public key of the coin. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * How much will be refunded to the purse. + */ + struct TALER_AmountNBO refunded_amount; + + /** + * How much was the refund fee. + */ + struct TALER_AmountNBO refund_fee; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_purse_refund_sign ( + TALER_ExchangeSignCallback scb, + const struct TALER_Amount *amount_without_fee, + const struct TALER_Amount *refund_fee, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_PurseContractPublicKeyP *purse_pub, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_CoinPurseRefundConfirmationPS dc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND), + .purpose.size = htonl (sizeof (dc)), + .coin_pub = *coin_pub, + .purse_pub = *purse_pub, + }; + + TALER_amount_hton (&dc.refunded_amount, + amount_without_fee); + TALER_amount_hton (&dc.refund_fee, + refund_fee); + return scb (&dc.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_purse_refund_verify ( + const struct TALER_Amount *amount_without_fee, + const struct TALER_Amount *refund_fee, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_CoinPurseRefundConfirmationPS dc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND), + .purpose.size = htonl (sizeof (dc)), + .coin_pub = *coin_pub, + .purse_pub = *purse_pub, + }; + + TALER_amount_hton (&dc.refunded_amount, + amount_without_fee); + TALER_amount_hton (&dc.refund_fee, + refund_fee); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND, + &dc, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Response by which the exchange affirms that it has + * merged a purse into a reserve. + */ +struct TALER_PurseMergedConfirmationPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the exchange receive the deposits. + */ + struct GNUNET_TIME_TimestampNBO exchange_time; + + /** + * When will the purse expire? + */ + struct GNUNET_TIME_TimestampNBO purse_expiration; + + /** + * How much should the purse ultimately contain. + */ + struct TALER_AmountNBO amount_without_fee; + + /** + * Public key of the purse. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Public key of the reserve. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Hash of the contract of the purse. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Hash of the provider URL hosting the reserve. + */ + struct GNUNET_HashCode h_provider_url; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_purse_merged_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp exchange_time, + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_Amount *amount_without_fee, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_ReservePublicKeyP *reserve_pub, + const char *exchange_url, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_PurseMergedConfirmationPS dc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED), + .purpose.size = htonl (sizeof (dc)), + .h_contract_terms = *h_contract_terms, + .purse_pub = *purse_pub, + .reserve_pub = *reserve_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time) + }; + + TALER_amount_hton (&dc.amount_without_fee, + amount_without_fee); + GNUNET_CRYPTO_hash (exchange_url, + strlen (exchange_url) + 1, + &dc.h_provider_url); + return scb (&dc.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_purse_merged_verify ( + struct GNUNET_TIME_Timestamp exchange_time, + struct GNUNET_TIME_Timestamp purse_expiration, + const struct TALER_Amount *amount_without_fee, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_ReservePublicKeyP *reserve_pub, + const char *exchange_url, + const struct TALER_ExchangePublicKeyP *pub, + const struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_PurseMergedConfirmationPS dc = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED), + .purpose.size = htonl (sizeof (dc)), + .h_contract_terms = *h_contract_terms, + .purse_pub = *purse_pub, + .reserve_pub = *reserve_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time) + }; + + TALER_amount_hton (&dc.amount_without_fee, + amount_without_fee); + GNUNET_CRYPTO_hash (exchange_url, + strlen (exchange_url) + 1, + &dc.h_provider_url); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED, + &dc, + &sig->eddsa_signature, + &pub->eddsa_pub); +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used to generate the signature on a purse status + * from the exchange. + */ +struct TALER_PurseStatusPS +{ + /** + * Purpose must be #TALER_SIGNATURE_EXCHANGE_PURSE_STATUS. Signed + * by a `struct TALER_ExchangePublicKeyP` using EdDSA. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the purse was merged, possibly 'never'. + */ + struct GNUNET_TIME_TimestampNBO merge_timestamp; + + /** + * Time when the purse was deposited last, possibly 'never'. + */ + struct GNUNET_TIME_TimestampNBO deposit_timestamp; + + /** + * Amount deposited in total in the purse without fees. + * May be possibly less than the target amount. + */ + struct TALER_AmountNBO balance; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_purse_status_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp merge_timestamp, + struct GNUNET_TIME_Timestamp deposit_timestamp, + const struct TALER_Amount *balance, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_PurseStatusPS dcs = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_PURSE_STATUS), + .purpose.size = htonl (sizeof (dcs)), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .deposit_timestamp = GNUNET_TIME_timestamp_hton (deposit_timestamp) + }; + + TALER_amount_hton (&dcs.balance, + balance); + return scb (&dcs.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_purse_status_verify ( + struct GNUNET_TIME_Timestamp merge_timestamp, + struct GNUNET_TIME_Timestamp deposit_timestamp, + const struct TALER_Amount *balance, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const struct TALER_ExchangeSignatureP *exchange_sig) +{ + struct TALER_PurseStatusPS dcs = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_PURSE_STATUS), + .purpose.size = htonl (sizeof (dcs)), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .deposit_timestamp = GNUNET_TIME_timestamp_hton (deposit_timestamp) + }; + + TALER_amount_hton (&dcs.balance, + balance); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_PURSE_STATUS, + &dcs, + &exchange_sig->eddsa_signature, + &exchange_pub->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message signed by the exchange to affirm that the + * owner of a reserve has certain attributes. + */ +struct TALER_ExchangeAttestPS +{ + + /** + * Purpose is #TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the attestation was made. + */ + struct GNUNET_TIME_TimestampNBO attest_timestamp; + + /** + * Time when the attestation expires. + */ + struct GNUNET_TIME_TimestampNBO expiration_time; + + /** + * Public key of the reserve for which the attributes + * are attested. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Hash over the attributes. + */ + struct GNUNET_HashCode h_attributes; + +}; + +GNUNET_NETWORK_STRUCT_END + + +enum TALER_ErrorCode +TALER_exchange_online_reserve_attest_details_sign ( + TALER_ExchangeSignCallback scb, + struct GNUNET_TIME_Timestamp attest_timestamp, + struct GNUNET_TIME_Timestamp expiration_time, + const struct TALER_ReservePublicKeyP *reserve_pub, + const json_t *attributes, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ExchangeAttestPS rap = { + .purpose.size = htonl (sizeof (rap)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS), + .attest_timestamp = GNUNET_TIME_timestamp_hton (attest_timestamp), + .expiration_time = GNUNET_TIME_timestamp_hton (expiration_time), + .reserve_pub = *reserve_pub + }; + + TALER_json_hash (attributes, + &rap.h_attributes); + return scb (&rap.purpose, + pub, + sig); +} + + +enum GNUNET_GenericReturnValue +TALER_exchange_online_reserve_attest_details_verify ( + struct GNUNET_TIME_Timestamp attest_timestamp, + struct GNUNET_TIME_Timestamp expiration_time, + const struct TALER_ReservePublicKeyP *reserve_pub, + const json_t *attributes, + struct TALER_ExchangePublicKeyP *pub, + struct TALER_ExchangeSignatureP *sig) +{ + struct TALER_ExchangeAttestPS rap = { + .purpose.size = htonl (sizeof (rap)), + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS), + .attest_timestamp = GNUNET_TIME_timestamp_hton (attest_timestamp), + .expiration_time = GNUNET_TIME_timestamp_hton (expiration_time), + .reserve_pub = *reserve_pub + }; + + TALER_json_hash (attributes, + &rap.h_attributes); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS, + &rap, + &sig->eddsa_signature, + &pub->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/* end of exchange_signatures.c */ |