exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_signatures.c (53438B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2021-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file exchange_signatures.c
     18  * @brief Utility functions for Taler security module signatures
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/platform.h"
     22 #include "taler/taler_util.h"
     23 #include "taler/taler_signatures.h"
     24 
     25 
     26 GNUNET_NETWORK_STRUCT_BEGIN
     27 
     28 /**
     29  * @brief Format used to generate the signature on a confirmation
     30  * from the exchange that a deposit request succeeded.
     31  */
     32 struct TALER_DepositConfirmationPS
     33 {
     34   /**
     35    * Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT.  Signed
     36    * by a `struct TALER_ExchangePublicKeyP` using EdDSA.
     37    */
     38   struct GNUNET_CRYPTO_SignaturePurpose purpose;
     39 
     40   /**
     41    * Hash over the contract for which this deposit is made.
     42    */
     43   struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED;
     44 
     45   /**
     46    * Hash over the wiring information of the merchant.
     47    */
     48   struct TALER_MerchantWireHashP h_wire GNUNET_PACKED;
     49 
     50   /**
     51    * Hash over the optional policy extension of the deposit, 0 if there
     52    * was no policy.
     53    */
     54   struct TALER_ExtensionPolicyHashP h_policy GNUNET_PACKED;
     55 
     56   /**
     57    * Time when this confirmation was generated / when the exchange received
     58    * the deposit request.
     59    */
     60   struct GNUNET_TIME_TimestampNBO exchange_timestamp;
     61 
     62   /**
     63    * By when does the exchange expect to pay the merchant
     64    * (as per the merchant's request).
     65    */
     66   struct GNUNET_TIME_TimestampNBO wire_deadline;
     67 
     68   /**
     69    * How much time does the @e merchant have to issue a refund
     70    * request?  Zero if refunds are not allowed.  After this time, the
     71    * coin cannot be refunded.  Note that the wire transfer will not be
     72    * performed by the exchange until the refund deadline.  This value
     73    * is taken from the original deposit request.
     74    */
     75   struct GNUNET_TIME_TimestampNBO refund_deadline;
     76 
     77   /**
     78    * Amount to be deposited, excluding fee.  Calculated from the
     79    * amount with fee and the fee from the deposit request.
     80    */
     81   struct TALER_AmountNBO total_without_fee;
     82 
     83   /**
     84    * Hash over all of the coin signatures.
     85    */
     86   struct GNUNET_HashCode h_coin_sigs;
     87 
     88   /**
     89    * The Merchant's public key.  Allows the merchant to later refund
     90    * the transaction or to inquire about the wire transfer identifier.
     91    */
     92   struct TALER_MerchantPublicKeyP merchant_pub;
     93 
     94 };
     95 
     96 GNUNET_NETWORK_STRUCT_END
     97 
     98 
     99 enum TALER_ErrorCode
    100 TALER_exchange_online_deposit_confirmation_sign (
    101   TALER_ExchangeSignCallback scb,
    102   const struct TALER_PrivateContractHashP *h_contract_terms,
    103   const struct TALER_MerchantWireHashP *h_wire,
    104   const struct TALER_ExtensionPolicyHashP *h_policy,
    105   struct GNUNET_TIME_Timestamp exchange_timestamp,
    106   struct GNUNET_TIME_Timestamp wire_deadline,
    107   struct GNUNET_TIME_Timestamp refund_deadline,
    108   const struct TALER_Amount *total_without_fee,
    109   unsigned int num_coins,
    110   const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins],
    111   const struct TALER_MerchantPublicKeyP *merchant_pub,
    112   struct TALER_ExchangePublicKeyP *pub,
    113   struct TALER_ExchangeSignatureP *sig)
    114 {
    115   struct TALER_DepositConfirmationPS dcs = {
    116     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT),
    117     .purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)),
    118     .h_contract_terms = *h_contract_terms,
    119     .h_wire = *h_wire,
    120     .exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp),
    121     .wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline),
    122     .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline),
    123     .merchant_pub = *merchant_pub,
    124     .h_policy = {{{0}}}
    125   };
    126   struct GNUNET_HashContext *hc;
    127 
    128   hc = GNUNET_CRYPTO_hash_context_start ();
    129   for (unsigned int i = 0; i<num_coins; i++)
    130     GNUNET_CRYPTO_hash_context_read (hc,
    131                                      coin_sigs[i],
    132                                      sizeof (*coin_sigs[i]));
    133   GNUNET_CRYPTO_hash_context_finish (hc,
    134                                      &dcs.h_coin_sigs);
    135   if (NULL != h_policy)
    136     dcs.h_policy = *h_policy;
    137   TALER_amount_hton (&dcs.total_without_fee,
    138                      total_without_fee);
    139   return scb (&dcs.purpose,
    140               pub,
    141               sig);
    142 }
    143 
    144 
    145 enum GNUNET_GenericReturnValue
    146 TALER_exchange_online_deposit_confirmation_verify (
    147   const struct TALER_PrivateContractHashP *h_contract_terms,
    148   const struct TALER_MerchantWireHashP *h_wire,
    149   const struct TALER_ExtensionPolicyHashP *h_policy,
    150   struct GNUNET_TIME_Timestamp exchange_timestamp,
    151   struct GNUNET_TIME_Timestamp wire_deadline,
    152   struct GNUNET_TIME_Timestamp refund_deadline,
    153   const struct TALER_Amount *total_without_fee,
    154   unsigned int num_coins,
    155   const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins],
    156   const struct TALER_MerchantPublicKeyP *merchant_pub,
    157   const struct TALER_ExchangePublicKeyP *exchange_pub,
    158   const struct TALER_ExchangeSignatureP *exchange_sig)
    159 {
    160   struct TALER_DepositConfirmationPS dcs = {
    161     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT),
    162     .purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)),
    163     .h_contract_terms = *h_contract_terms,
    164     .h_wire = *h_wire,
    165     .exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp),
    166     .wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline),
    167     .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline),
    168     .merchant_pub = *merchant_pub
    169   };
    170   struct GNUNET_HashContext *hc;
    171 
    172   hc = GNUNET_CRYPTO_hash_context_start ();
    173   for (unsigned int i = 0; i<num_coins; i++)
    174     GNUNET_CRYPTO_hash_context_read (hc,
    175                                      coin_sigs[i],
    176                                      sizeof (*coin_sigs[i]));
    177   GNUNET_CRYPTO_hash_context_finish (hc,
    178                                      &dcs.h_coin_sigs);
    179   if (NULL != h_policy)
    180     dcs.h_policy = *h_policy;
    181   TALER_amount_hton (&dcs.total_without_fee,
    182                      total_without_fee);
    183   if (GNUNET_OK !=
    184       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT,
    185                                   &dcs,
    186                                   &exchange_sig->eddsa_signature,
    187                                   &exchange_pub->eddsa_pub))
    188   {
    189     GNUNET_break_op (0);
    190     return GNUNET_SYSERR;
    191   }
    192   return GNUNET_OK;
    193 }
    194 
    195 
    196 GNUNET_NETWORK_STRUCT_BEGIN
    197 
    198 /**
    199  * @brief Format used to generate the signature on a request to refund
    200  * a coin into the account of the customer.
    201  */
    202 struct TALER_RefundConfirmationPS
    203 {
    204   /**
    205    * Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND.
    206    */
    207   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    208 
    209   /**
    210    * Hash over the proposal data to identify the contract
    211    * which is being refunded.
    212    */
    213   struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED;
    214 
    215   /**
    216    * The coin's public key.  This is the value that must have been
    217    * signed (blindly) by the Exchange.
    218    */
    219   struct TALER_CoinSpendPublicKeyP coin_pub;
    220 
    221   /**
    222    * The Merchant's public key.  Allows the merchant to later refund
    223    * the transaction or to inquire about the wire transfer identifier.
    224    */
    225   struct TALER_MerchantPublicKeyP merchant;
    226 
    227   /**
    228    * Merchant-generated transaction ID for the refund.
    229    */
    230   uint64_t rtransaction_id GNUNET_PACKED;
    231 
    232   /**
    233    * Amount to be refunded, including refund fee charged by the
    234    * exchange to the customer.
    235    */
    236   struct TALER_AmountNBO refund_amount;
    237 };
    238 
    239 GNUNET_NETWORK_STRUCT_END
    240 
    241 
    242 enum TALER_ErrorCode
    243 TALER_exchange_online_refund_confirmation_sign (
    244   TALER_ExchangeSignCallback scb,
    245   const struct TALER_PrivateContractHashP *h_contract_terms,
    246   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    247   const struct TALER_MerchantPublicKeyP *merchant,
    248   uint64_t rtransaction_id,
    249   const struct TALER_Amount *refund_amount,
    250   struct TALER_ExchangePublicKeyP *pub,
    251   struct TALER_ExchangeSignatureP *sig)
    252 {
    253   struct TALER_RefundConfirmationPS rc = {
    254     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND),
    255     .purpose.size = htonl (sizeof (rc)),
    256     .h_contract_terms = *h_contract_terms,
    257     .coin_pub = *coin_pub,
    258     .merchant = *merchant,
    259     .rtransaction_id = GNUNET_htonll (rtransaction_id)
    260   };
    261 
    262   TALER_amount_hton (&rc.refund_amount,
    263                      refund_amount);
    264   return scb (&rc.purpose,
    265               pub,
    266               sig);
    267 }
    268 
    269 
    270 enum GNUNET_GenericReturnValue
    271 TALER_exchange_online_refund_confirmation_verify (
    272   const struct TALER_PrivateContractHashP *h_contract_terms,
    273   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    274   const struct TALER_MerchantPublicKeyP *merchant,
    275   uint64_t rtransaction_id,
    276   const struct TALER_Amount *refund_amount,
    277   const struct TALER_ExchangePublicKeyP *pub,
    278   const struct TALER_ExchangeSignatureP *sig)
    279 {
    280   struct TALER_RefundConfirmationPS rc = {
    281     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND),
    282     .purpose.size = htonl (sizeof (rc)),
    283     .h_contract_terms = *h_contract_terms,
    284     .coin_pub = *coin_pub,
    285     .merchant = *merchant,
    286     .rtransaction_id = GNUNET_htonll (rtransaction_id)
    287   };
    288 
    289   TALER_amount_hton (&rc.refund_amount,
    290                      refund_amount);
    291   if (GNUNET_OK !=
    292       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND,
    293                                   &rc,
    294                                   &sig->eddsa_signature,
    295                                   &pub->eddsa_pub))
    296   {
    297     GNUNET_break_op (0);
    298     return GNUNET_SYSERR;
    299   }
    300   return GNUNET_OK;
    301 }
    302 
    303 
    304 GNUNET_NETWORK_STRUCT_BEGIN
    305 
    306 /**
    307  * @brief Format of the block signed by the Exchange in response to a successful
    308  * "/refresh/melt" request.  Hereby the exchange affirms that all of the
    309  * coins were successfully melted.  This also commits the exchange to a
    310  * particular index to not be revealed during the refresh.
    311  */
    312 struct TALER_RefreshMeltConfirmationPS
    313 {
    314   /**
    315    * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT.   Signed
    316    * by a `struct TALER_ExchangePublicKeyP` using EdDSA.
    317    */
    318   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    319 
    320   /**
    321    * Commitment made in the /refresh/melt.
    322    */
    323   struct TALER_RefreshCommitmentP rc GNUNET_PACKED;
    324 
    325   /**
    326    * Index that the client will not have to reveal, in NBO.
    327    * Must be smaller than #TALER_CNC_KAPPA.
    328    */
    329   uint32_t noreveal_index GNUNET_PACKED;
    330 
    331 };
    332 
    333 GNUNET_NETWORK_STRUCT_END
    334 
    335 
    336 enum TALER_ErrorCode
    337 TALER_exchange_online_melt_confirmation_sign (
    338   TALER_ExchangeSignCallback scb,
    339   const struct TALER_RefreshCommitmentP *rc,
    340   uint32_t noreveal_index,
    341   struct TALER_ExchangePublicKeyP *pub,
    342   struct TALER_ExchangeSignatureP *sig)
    343 {
    344   struct TALER_RefreshMeltConfirmationPS confirm = {
    345     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT),
    346     .purpose.size = htonl (sizeof (confirm)),
    347     .rc = *rc,
    348     .noreveal_index = htonl (noreveal_index)
    349   };
    350 
    351   return scb (&confirm.purpose,
    352               pub,
    353               sig);
    354 }
    355 
    356 
    357 enum GNUNET_GenericReturnValue
    358 TALER_exchange_online_melt_confirmation_verify (
    359   const struct TALER_RefreshCommitmentP *rc,
    360   uint32_t noreveal_index,
    361   const struct TALER_ExchangePublicKeyP *exchange_pub,
    362   const struct TALER_ExchangeSignatureP *exchange_sig)
    363 {
    364   struct TALER_RefreshMeltConfirmationPS confirm = {
    365     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT),
    366     .purpose.size = htonl (sizeof (confirm)),
    367     .rc = *rc,
    368     .noreveal_index = htonl (noreveal_index)
    369   };
    370 
    371   return
    372     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT,
    373                                 &confirm,
    374                                 &exchange_sig->eddsa_signature,
    375                                 &exchange_pub->eddsa_pub);
    376 }
    377 
    378 
    379 GNUNET_NETWORK_STRUCT_BEGIN
    380 
    381 /**
    382  * @brief Format of the block signed by the Exchange in response to a
    383  * successful "/withdraw" request.
    384  * If age restriction is set, the exchange hereby also
    385  * affirms that the commitment along with the maximum age group and
    386  * the amount were accepted.  This also commits the exchange to a particular
    387  * index to not be revealed during the reveal.
    388  */
    389 struct TALER_WithdrawConfirmationPS
    390 {
    391   /**
    392    * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW.   Signed by a
    393    * `struct TALER_ExchangePublicKeyP` using EdDSA.
    394    */
    395   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    396 
    397   /**
    398    * Commitment made in the /withdraw call.
    399    */
    400   struct TALER_HashBlindedPlanchetsP h_planchets GNUNET_PACKED;
    401 
    402   /**
    403    * If age restriction does not apply to this withdrawal,
    404    * (i.e. max_age was not set during the request)
    405    * MUST be 0xFFFFFFFF.
    406    * Otherwise (i.e. age restriction applies):
    407    * index that the client will not have to reveal, in NBO,
    408    * MUST be smaller than #TALER_CNC_KAPPA.
    409    */
    410   uint32_t noreveal_index GNUNET_PACKED;
    411 
    412 };
    413 
    414 GNUNET_NETWORK_STRUCT_END
    415 
    416 enum TALER_ErrorCode
    417 TALER_exchange_online_withdraw_age_confirmation_sign (
    418   TALER_ExchangeSignCallback scb,
    419   const struct TALER_HashBlindedPlanchetsP *h_planchets,
    420   uint32_t noreveal_index,
    421   struct TALER_ExchangePublicKeyP *pub,
    422   struct TALER_ExchangeSignatureP *sig)
    423 {
    424 
    425   struct TALER_WithdrawConfirmationPS confirm = {
    426     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW),
    427     .purpose.size = htonl (sizeof (confirm)),
    428     .h_planchets = *h_planchets,
    429     .noreveal_index = htonl (noreveal_index)
    430   };
    431 
    432   return scb (&confirm.purpose,
    433               pub,
    434               sig);
    435 }
    436 
    437 
    438 enum TALER_ErrorCode
    439 TALER_exchange_online_withdraw_confirmation_sign (
    440   TALER_ExchangeSignCallback scb,
    441   const struct TALER_HashBlindedPlanchetsP *h_planchets,
    442   struct TALER_ExchangePublicKeyP *pub,
    443   struct TALER_ExchangeSignatureP *sig)
    444 {
    445 
    446   struct TALER_WithdrawConfirmationPS confirm = {
    447     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW),
    448     .purpose.size = htonl (sizeof (confirm)),
    449     .h_planchets = *h_planchets,
    450     .noreveal_index = htonl (0xFFFFFFFF)
    451   };
    452 
    453   return scb (&confirm.purpose,
    454               pub,
    455               sig);
    456 }
    457 
    458 
    459 enum GNUNET_GenericReturnValue
    460 TALER_exchange_online_withdraw_age_confirmation_verify (
    461   const struct TALER_HashBlindedPlanchetsP *h_planchets,
    462   uint32_t noreveal_index,
    463   const struct TALER_ExchangePublicKeyP *exchange_pub,
    464   const struct TALER_ExchangeSignatureP *exchange_sig)
    465 {
    466   struct TALER_WithdrawConfirmationPS confirm = {
    467     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW),
    468     .purpose.size = htonl (sizeof (confirm)),
    469     .h_planchets = *h_planchets,
    470     .noreveal_index = htonl (noreveal_index)
    471   };
    472 
    473   if (GNUNET_OK !=
    474       GNUNET_CRYPTO_eddsa_verify (
    475         TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW,
    476         &confirm,
    477         &exchange_sig->eddsa_signature,
    478         &exchange_pub->eddsa_pub))
    479   {
    480     GNUNET_break_op (0);
    481     return GNUNET_SYSERR;
    482   }
    483   return GNUNET_OK;
    484 }
    485 
    486 
    487 enum GNUNET_GenericReturnValue
    488 TALER_exchange_online_withdraw_confirmation_verify (
    489   const struct TALER_HashBlindedPlanchetsP *h_planchets,
    490   const struct TALER_ExchangePublicKeyP *exchange_pub,
    491   const struct TALER_ExchangeSignatureP *exchange_sig)
    492 {
    493   struct TALER_WithdrawConfirmationPS confirm = {
    494     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW),
    495     .purpose.size = htonl (sizeof (confirm)),
    496     .h_planchets = *h_planchets,
    497     .noreveal_index = htonl (0xFFFFFFFF)
    498   };
    499 
    500   if (GNUNET_OK !=
    501       GNUNET_CRYPTO_eddsa_verify (
    502         TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW,
    503         &confirm,
    504         &exchange_sig->eddsa_signature,
    505         &exchange_pub->eddsa_pub))
    506   {
    507     GNUNET_break_op (0);
    508     return GNUNET_SYSERR;
    509   }
    510   return GNUNET_OK;
    511 }
    512 
    513 
    514 GNUNET_NETWORK_STRUCT_BEGIN
    515 
    516 /**
    517  * @brief Signature made by the exchange over the full set of keys, used
    518  * to detect cheating exchanges that give out different sets to
    519  * different users.
    520  */
    521 struct TALER_ExchangeKeySetPS
    522 {
    523 
    524   /**
    525    * Purpose is #TALER_SIGNATURE_EXCHANGE_KEY_SET.   Signed
    526    * by a `struct TALER_ExchangePublicKeyP` using EdDSA.
    527    */
    528   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    529 
    530   /**
    531    * Time of the key set issue.
    532    */
    533   struct GNUNET_TIME_TimestampNBO list_issue_date;
    534 
    535   /**
    536    * Hash over the various denomination signing keys returned.
    537    */
    538   struct GNUNET_HashCode hc GNUNET_PACKED;
    539 };
    540 
    541 GNUNET_NETWORK_STRUCT_END
    542 
    543 
    544 enum TALER_ErrorCode
    545 TALER_exchange_online_key_set_sign (
    546   TALER_ExchangeSignCallback2 scb,
    547   void *cls,
    548   struct GNUNET_TIME_Timestamp timestamp,
    549   const struct GNUNET_HashCode *hc,
    550   struct TALER_ExchangePublicKeyP *pub,
    551   struct TALER_ExchangeSignatureP *sig)
    552 {
    553   struct TALER_ExchangeKeySetPS ks = {
    554     .purpose.size = htonl (sizeof (ks)),
    555     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET),
    556     .list_issue_date = GNUNET_TIME_timestamp_hton (timestamp),
    557     .hc = *hc
    558   };
    559 
    560   return scb (cls,
    561               &ks.purpose,
    562               pub,
    563               sig);
    564 }
    565 
    566 
    567 enum GNUNET_GenericReturnValue
    568 TALER_exchange_online_key_set_verify (
    569   struct GNUNET_TIME_Timestamp timestamp,
    570   const struct GNUNET_HashCode *hc,
    571   const struct TALER_ExchangePublicKeyP *pub,
    572   const struct TALER_ExchangeSignatureP *sig)
    573 {
    574   struct TALER_ExchangeKeySetPS ks = {
    575     .purpose.size = htonl (sizeof (ks)),
    576     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET),
    577     .list_issue_date = GNUNET_TIME_timestamp_hton (timestamp),
    578     .hc = *hc
    579   };
    580 
    581   return
    582     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET,
    583                                 &ks,
    584                                 &sig->eddsa_signature,
    585                                 &pub->eddsa_pub);
    586 }
    587 
    588 
    589 GNUNET_NETWORK_STRUCT_BEGIN
    590 
    591 /**
    592  * @brief Format internally used for packing the detailed information
    593  * to generate the signature for /track/transfer signatures.
    594  */
    595 struct TALER_WireDepositDetailP
    596 {
    597 
    598   /**
    599    * Hash of the contract
    600    */
    601   struct TALER_PrivateContractHashP h_contract_terms;
    602 
    603   /**
    604    * Time when the wire transfer was performed by the exchange.
    605    */
    606   struct GNUNET_TIME_TimestampNBO execution_time;
    607 
    608   /**
    609    * Coin's public key.
    610    */
    611   struct TALER_CoinSpendPublicKeyP coin_pub;
    612 
    613   /**
    614    * Total value of the coin.
    615    */
    616   struct TALER_AmountNBO deposit_value;
    617 
    618   /**
    619    * Fees charged by the exchange for the deposit.
    620    */
    621   struct TALER_AmountNBO deposit_fee;
    622 
    623 };
    624 
    625 GNUNET_NETWORK_STRUCT_END
    626 
    627 
    628 void
    629 TALER_exchange_online_wire_deposit_append (
    630   struct GNUNET_HashContext *hash_context,
    631   const struct TALER_PrivateContractHashP *h_contract_terms,
    632   struct GNUNET_TIME_Timestamp execution_time,
    633   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    634   const struct TALER_Amount *deposit_value,
    635   const struct TALER_Amount *deposit_fee)
    636 {
    637   struct TALER_WireDepositDetailP dd = {
    638     .h_contract_terms = *h_contract_terms,
    639     .execution_time = GNUNET_TIME_timestamp_hton (execution_time),
    640     .coin_pub = *coin_pub
    641   };
    642   TALER_amount_hton (&dd.deposit_value,
    643                      deposit_value);
    644   TALER_amount_hton (&dd.deposit_fee,
    645                      deposit_fee);
    646   GNUNET_CRYPTO_hash_context_read (hash_context,
    647                                    &dd,
    648                                    sizeof (dd));
    649 }
    650 
    651 
    652 GNUNET_NETWORK_STRUCT_BEGIN
    653 
    654 /**
    655  * @brief Format used to generate the signature for /wire/deposit
    656  * replies.
    657  */
    658 struct TALER_WireDepositDataPS
    659 {
    660   /**
    661    * Purpose header for the signature over the contract with
    662    * purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT.
    663    */
    664   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    665 
    666   /**
    667    * Total amount that was transferred.
    668    */
    669   struct TALER_AmountNBO total;
    670 
    671   /**
    672    * Wire fee that was charged.
    673    */
    674   struct TALER_AmountNBO wire_fee;
    675 
    676   /**
    677    * Public key of the merchant (for all aggregated transactions).
    678    */
    679   struct TALER_MerchantPublicKeyP merchant_pub;
    680 
    681   /**
    682    * Hash of bank account of the merchant.
    683    */
    684   struct TALER_FullPaytoHashP h_payto;
    685 
    686   /**
    687    * Hash of the individual deposits that were aggregated,
    688    * each in the format of a `struct TALER_WireDepositDetailP`.
    689    */
    690   struct GNUNET_HashCode h_details;
    691 
    692 };
    693 
    694 GNUNET_NETWORK_STRUCT_END
    695 
    696 
    697 enum TALER_ErrorCode
    698 TALER_exchange_online_wire_deposit_sign (
    699   TALER_ExchangeSignCallback scb,
    700   const struct TALER_Amount *total,
    701   const struct TALER_Amount *wire_fee,
    702   const struct TALER_MerchantPublicKeyP *merchant_pub,
    703   const struct TALER_FullPayto payto,
    704   const struct GNUNET_HashCode *h_details,
    705   struct TALER_ExchangePublicKeyP *pub,
    706   struct TALER_ExchangeSignatureP *sig)
    707 {
    708   struct TALER_WireDepositDataPS wdp = {
    709     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT),
    710     .purpose.size = htonl (sizeof (wdp)),
    711     .merchant_pub = *merchant_pub,
    712     .h_details = *h_details
    713   };
    714 
    715   TALER_amount_hton (&wdp.total,
    716                      total);
    717   TALER_amount_hton (&wdp.wire_fee,
    718                      wire_fee);
    719   TALER_full_payto_hash (payto,
    720                          &wdp.h_payto);
    721   return scb (&wdp.purpose,
    722               pub,
    723               sig);
    724 }
    725 
    726 
    727 enum GNUNET_GenericReturnValue
    728 TALER_exchange_online_wire_deposit_verify (
    729   const struct TALER_Amount *total,
    730   const struct TALER_Amount *wire_fee,
    731   const struct TALER_MerchantPublicKeyP *merchant_pub,
    732   const struct TALER_FullPaytoHashP *h_payto,
    733   const struct GNUNET_HashCode *h_details,
    734   const struct TALER_ExchangePublicKeyP *pub,
    735   const struct TALER_ExchangeSignatureP *sig)
    736 {
    737   struct TALER_WireDepositDataPS wdp = {
    738     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT),
    739     .purpose.size = htonl (sizeof (wdp)),
    740     .merchant_pub = *merchant_pub,
    741     .h_details = *h_details,
    742     .h_payto = *h_payto
    743   };
    744 
    745   TALER_amount_hton (&wdp.total,
    746                      total);
    747   TALER_amount_hton (&wdp.wire_fee,
    748                      wire_fee);
    749   return GNUNET_CRYPTO_eddsa_verify (
    750     TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT,
    751     &wdp,
    752     &sig->eddsa_signature,
    753     &pub->eddsa_pub);
    754 }
    755 
    756 
    757 GNUNET_NETWORK_STRUCT_BEGIN
    758 
    759 /**
    760  * Details affirmed by the exchange about a wire transfer the exchange
    761  * claims to have done with respect to a deposit operation.
    762  */
    763 struct TALER_ConfirmWirePS
    764 {
    765   /**
    766    * Purpose header for the signature over the contract with
    767    * purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE.
    768    */
    769   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    770 
    771   /**
    772    * Hash over the wiring information of the merchant.
    773    */
    774   struct TALER_MerchantWireHashP h_wire GNUNET_PACKED;
    775 
    776   /**
    777    * Hash over the contract for which this deposit is made.
    778    */
    779   struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED;
    780 
    781   /**
    782    * Raw value (binary encoding) of the wire transfer subject.
    783    */
    784   struct TALER_WireTransferIdentifierRawP wtid;
    785 
    786   /**
    787    * The coin's public key.  This is the value that must have been
    788    * signed (blindly) by the Exchange.
    789    */
    790   struct TALER_CoinSpendPublicKeyP coin_pub;
    791 
    792   /**
    793    * When did the exchange execute this transfer? Note that the
    794    * timestamp may not be exactly the same on the wire, i.e.
    795    * because the wire has a different timezone or resolution.
    796    */
    797   struct GNUNET_TIME_TimestampNBO execution_time;
    798 
    799   /**
    800    * The contribution of @e coin_pub to the total transfer volume.
    801    * This is the value of the deposit minus the fee.
    802    */
    803   struct TALER_AmountNBO coin_contribution;
    804 
    805 };
    806 
    807 GNUNET_NETWORK_STRUCT_END
    808 
    809 
    810 enum TALER_ErrorCode
    811 TALER_exchange_online_confirm_wire_sign (
    812   TALER_ExchangeSignCallback scb,
    813   const struct TALER_MerchantWireHashP *h_wire,
    814   const struct TALER_PrivateContractHashP *h_contract_terms,
    815   const struct TALER_WireTransferIdentifierRawP *wtid,
    816   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    817   struct GNUNET_TIME_Timestamp execution_time,
    818   const struct TALER_Amount *coin_contribution,
    819   struct TALER_ExchangePublicKeyP *pub,
    820   struct TALER_ExchangeSignatureP *sig)
    821 
    822 {
    823   struct TALER_ConfirmWirePS cw = {
    824     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE),
    825     .purpose.size = htonl (sizeof (cw)),
    826     .h_wire = *h_wire,
    827     .h_contract_terms = *h_contract_terms,
    828     .wtid = *wtid,
    829     .coin_pub = *coin_pub,
    830     .execution_time = GNUNET_TIME_timestamp_hton (execution_time)
    831   };
    832 
    833   TALER_amount_hton (&cw.coin_contribution,
    834                      coin_contribution);
    835   return scb (&cw.purpose,
    836               pub,
    837               sig);
    838 }
    839 
    840 
    841 enum GNUNET_GenericReturnValue
    842 TALER_exchange_online_confirm_wire_verify (
    843   const struct TALER_MerchantWireHashP *h_wire,
    844   const struct TALER_PrivateContractHashP *h_contract_terms,
    845   const struct TALER_WireTransferIdentifierRawP *wtid,
    846   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    847   struct GNUNET_TIME_Timestamp execution_time,
    848   const struct TALER_Amount *coin_contribution,
    849   const struct TALER_ExchangePublicKeyP *pub,
    850   const struct TALER_ExchangeSignatureP *sig)
    851 {
    852   struct TALER_ConfirmWirePS cw = {
    853     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE),
    854     .purpose.size = htonl (sizeof (cw)),
    855     .h_wire = *h_wire,
    856     .h_contract_terms = *h_contract_terms,
    857     .wtid = *wtid,
    858     .coin_pub = *coin_pub,
    859     .execution_time = GNUNET_TIME_timestamp_hton (execution_time)
    860   };
    861 
    862   TALER_amount_hton (&cw.coin_contribution,
    863                      coin_contribution);
    864   return
    865     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE,
    866                                 &cw,
    867                                 &sig->eddsa_signature,
    868                                 &pub->eddsa_pub);
    869 }
    870 
    871 
    872 GNUNET_NETWORK_STRUCT_BEGIN
    873 
    874 /**
    875  * Response by which the exchange affirms that it will
    876  * refund a coin as part of the emergency /recoup
    877  * protocol.  The recoup will go back to the bank
    878  * account that created the reserve.
    879  */
    880 struct TALER_RecoupConfirmationPS
    881 {
    882 
    883   /**
    884    * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP
    885    */
    886   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    887 
    888   /**
    889    * When did the exchange receive the recoup request?
    890    * Indirectly determines when the wire transfer is (likely)
    891    * to happen.
    892    */
    893   struct GNUNET_TIME_TimestampNBO timestamp;
    894 
    895   /**
    896    * How much of the coin's value will the exchange transfer?
    897    * (Needed in case the coin was partially spent.)
    898    */
    899   struct TALER_AmountNBO recoup_amount;
    900 
    901   /**
    902    * Public key of the coin.
    903    */
    904   struct TALER_CoinSpendPublicKeyP coin_pub;
    905 
    906   /**
    907    * Public key of the reserve that will receive the recoup.
    908    */
    909   struct TALER_ReservePublicKeyP reserve_pub;
    910 };
    911 
    912 GNUNET_NETWORK_STRUCT_END
    913 
    914 
    915 enum TALER_ErrorCode
    916 TALER_exchange_online_confirm_recoup_sign (
    917   TALER_ExchangeSignCallback scb,
    918   struct GNUNET_TIME_Timestamp timestamp,
    919   const struct TALER_Amount *recoup_amount,
    920   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    921   const struct TALER_ReservePublicKeyP *reserve_pub,
    922   struct TALER_ExchangePublicKeyP *pub,
    923   struct TALER_ExchangeSignatureP *sig)
    924 {
    925   struct TALER_RecoupConfirmationPS pc = {
    926     .purpose.size = htonl (sizeof (pc)),
    927     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),
    928     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
    929     .coin_pub = *coin_pub,
    930     .reserve_pub = *reserve_pub
    931   };
    932 
    933   TALER_amount_hton (&pc.recoup_amount,
    934                      recoup_amount);
    935   return scb (&pc.purpose,
    936               pub,
    937               sig);
    938 }
    939 
    940 
    941 enum GNUNET_GenericReturnValue
    942 TALER_exchange_online_confirm_recoup_verify (
    943   struct GNUNET_TIME_Timestamp timestamp,
    944   const struct TALER_Amount *recoup_amount,
    945   const struct TALER_CoinSpendPublicKeyP *coin_pub,
    946   const struct TALER_ReservePublicKeyP *reserve_pub,
    947   const struct TALER_ExchangePublicKeyP *pub,
    948   const struct TALER_ExchangeSignatureP *sig)
    949 {
    950   struct TALER_RecoupConfirmationPS pc = {
    951     .purpose.size = htonl (sizeof (pc)),
    952     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),
    953     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
    954     .coin_pub = *coin_pub,
    955     .reserve_pub = *reserve_pub
    956   };
    957 
    958   TALER_amount_hton (&pc.recoup_amount,
    959                      recoup_amount);
    960   return
    961     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP,
    962                                 &pc,
    963                                 &sig->eddsa_signature,
    964                                 &pub->eddsa_pub);
    965 }
    966 
    967 
    968 GNUNET_NETWORK_STRUCT_BEGIN
    969 
    970 /**
    971  * Response by which the exchange affirms that it will refund a refreshed coin
    972  * as part of the emergency /recoup protocol.  The recoup will go back to the
    973  * old coin's balance.
    974  */
    975 struct TALER_RecoupRefreshConfirmationPS
    976 {
    977 
    978   /**
    979    * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH
    980    */
    981   struct GNUNET_CRYPTO_SignaturePurpose purpose;
    982 
    983   /**
    984    * When did the exchange receive the recoup request?
    985    * Indirectly determines when the wire transfer is (likely)
    986    * to happen.
    987    */
    988   struct GNUNET_TIME_TimestampNBO timestamp;
    989 
    990   /**
    991    * How much of the coin's value will the exchange transfer?
    992    * (Needed in case the coin was partially spent.)
    993    */
    994   struct TALER_AmountNBO recoup_amount;
    995 
    996   /**
    997    * Public key of the refreshed coin.
    998    */
    999   struct TALER_CoinSpendPublicKeyP coin_pub;
   1000 
   1001   /**
   1002    * Public key of the old coin that will receive the recoup.
   1003    */
   1004   struct TALER_CoinSpendPublicKeyP old_coin_pub;
   1005 };
   1006 
   1007 GNUNET_NETWORK_STRUCT_END
   1008 
   1009 
   1010 enum TALER_ErrorCode
   1011 TALER_exchange_online_confirm_recoup_refresh_sign (
   1012   TALER_ExchangeSignCallback scb,
   1013   struct GNUNET_TIME_Timestamp timestamp,
   1014   const struct TALER_Amount *recoup_amount,
   1015   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   1016   const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
   1017   struct TALER_ExchangePublicKeyP *pub,
   1018   struct TALER_ExchangeSignatureP *sig)
   1019 {
   1020   struct TALER_RecoupRefreshConfirmationPS pc = {
   1021     .purpose.purpose = htonl (
   1022       TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),
   1023     .purpose.size = htonl (sizeof (pc)),
   1024     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
   1025     .coin_pub = *coin_pub,
   1026     .old_coin_pub = *old_coin_pub
   1027   };
   1028 
   1029   TALER_amount_hton (&pc.recoup_amount,
   1030                      recoup_amount);
   1031   return scb (&pc.purpose,
   1032               pub,
   1033               sig);
   1034 }
   1035 
   1036 
   1037 enum GNUNET_GenericReturnValue
   1038 TALER_exchange_online_confirm_recoup_refresh_verify (
   1039   struct GNUNET_TIME_Timestamp timestamp,
   1040   const struct TALER_Amount *recoup_amount,
   1041   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   1042   const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
   1043   const struct TALER_ExchangePublicKeyP *pub,
   1044   const struct TALER_ExchangeSignatureP *sig)
   1045 {
   1046   struct TALER_RecoupRefreshConfirmationPS pc = {
   1047     .purpose.purpose = htonl (
   1048       TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),
   1049     .purpose.size = htonl (sizeof (pc)),
   1050     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
   1051     .coin_pub = *coin_pub,
   1052     .old_coin_pub = *old_coin_pub
   1053   };
   1054 
   1055   TALER_amount_hton (&pc.recoup_amount,
   1056                      recoup_amount);
   1057 
   1058   return
   1059     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH,
   1060                                 &pc,
   1061                                 &sig->eddsa_signature,
   1062                                 &pub->eddsa_pub);
   1063 }
   1064 
   1065 
   1066 GNUNET_NETWORK_STRUCT_BEGIN
   1067 
   1068 /**
   1069  * Response by which the exchange affirms that it does not
   1070  * currently know a denomination by the given hash.
   1071  */
   1072 struct TALER_DenominationUnknownAffirmationPS
   1073 {
   1074 
   1075   /**
   1076    * Purpose is #TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN
   1077    */
   1078   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1079 
   1080   /**
   1081    * When did the exchange sign this message.
   1082    */
   1083   struct GNUNET_TIME_TimestampNBO timestamp;
   1084 
   1085   /**
   1086    * Hash of the public denomination key we do not know.
   1087    */
   1088   struct TALER_DenominationHashP h_denom_pub;
   1089 };
   1090 
   1091 GNUNET_NETWORK_STRUCT_END
   1092 
   1093 
   1094 enum TALER_ErrorCode
   1095 TALER_exchange_online_denomination_unknown_sign (
   1096   TALER_ExchangeSignCallback scb,
   1097   struct GNUNET_TIME_Timestamp timestamp,
   1098   const struct TALER_DenominationHashP *h_denom_pub,
   1099   struct TALER_ExchangePublicKeyP *pub,
   1100   struct TALER_ExchangeSignatureP *sig)
   1101 {
   1102   struct TALER_DenominationUnknownAffirmationPS dua = {
   1103     .purpose.size = htonl (sizeof (dua)),
   1104     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN),
   1105     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
   1106     .h_denom_pub = *h_denom_pub,
   1107   };
   1108 
   1109   return scb (&dua.purpose,
   1110               pub,
   1111               sig);
   1112 }
   1113 
   1114 
   1115 enum GNUNET_GenericReturnValue
   1116 TALER_exchange_online_denomination_unknown_verify (
   1117   struct GNUNET_TIME_Timestamp timestamp,
   1118   const struct TALER_DenominationHashP *h_denom_pub,
   1119   const struct TALER_ExchangePublicKeyP *pub,
   1120   const struct TALER_ExchangeSignatureP *sig)
   1121 {
   1122   struct TALER_DenominationUnknownAffirmationPS dua = {
   1123     .purpose.size = htonl (sizeof (dua)),
   1124     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN),
   1125     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
   1126     .h_denom_pub = *h_denom_pub,
   1127   };
   1128 
   1129   return
   1130     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN,
   1131                                 &dua,
   1132                                 &sig->eddsa_signature,
   1133                                 &pub->eddsa_pub);
   1134 }
   1135 
   1136 
   1137 GNUNET_NETWORK_STRUCT_BEGIN
   1138 
   1139 /**
   1140  * Response by which the exchange affirms that it does not
   1141  * currently consider the given denomination to be valid
   1142  * for the requested operation.
   1143  */
   1144 struct TALER_DenominationExpiredAffirmationPS
   1145 {
   1146 
   1147   /**
   1148    * Purpose is #TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED
   1149    */
   1150   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1151 
   1152   /**
   1153    * When did the exchange sign this message.
   1154    */
   1155   struct GNUNET_TIME_TimestampNBO timestamp;
   1156 
   1157   /**
   1158    * Name of the operation that is not allowed at this time.  Might NOT be 0-terminated, but is padded with 0s.
   1159    */
   1160   char operation[8];
   1161 
   1162   /**
   1163    * Hash of the public denomination key we do not know.
   1164    */
   1165   struct TALER_DenominationHashP h_denom_pub;
   1166 
   1167 };
   1168 
   1169 GNUNET_NETWORK_STRUCT_END
   1170 
   1171 
   1172 enum TALER_ErrorCode
   1173 TALER_exchange_online_denomination_expired_sign (
   1174   TALER_ExchangeSignCallback scb,
   1175   struct GNUNET_TIME_Timestamp timestamp,
   1176   const struct TALER_DenominationHashP *h_denom_pub,
   1177   const char *op,
   1178   struct TALER_ExchangePublicKeyP *pub,
   1179   struct TALER_ExchangeSignatureP *sig)
   1180 {
   1181   struct TALER_DenominationExpiredAffirmationPS dua = {
   1182     .purpose.size = htonl (sizeof (dua)),
   1183     .purpose.purpose = htonl (
   1184       TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED),
   1185     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
   1186     .h_denom_pub = *h_denom_pub,
   1187   };
   1188 
   1189   /* strncpy would create a compiler warning */
   1190   GNUNET_memcpy (dua.operation,
   1191                  op,
   1192                  GNUNET_MIN (sizeof (dua.operation),
   1193                              strlen (op)));
   1194   return scb (&dua.purpose,
   1195               pub,
   1196               sig);
   1197 }
   1198 
   1199 
   1200 enum GNUNET_GenericReturnValue
   1201 TALER_exchange_online_denomination_expired_verify (
   1202   struct GNUNET_TIME_Timestamp timestamp,
   1203   const struct TALER_DenominationHashP *h_denom_pub,
   1204   const char *op,
   1205   const struct TALER_ExchangePublicKeyP *pub,
   1206   const struct TALER_ExchangeSignatureP *sig)
   1207 {
   1208   struct TALER_DenominationExpiredAffirmationPS dua = {
   1209     .purpose.size = htonl (sizeof (dua)),
   1210     .purpose.purpose = htonl (
   1211       TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED),
   1212     .timestamp = GNUNET_TIME_timestamp_hton (timestamp),
   1213     .h_denom_pub = *h_denom_pub,
   1214   };
   1215 
   1216   /* strncpy would create a compiler warning */
   1217   GNUNET_memcpy (dua.operation,
   1218                  op,
   1219                  GNUNET_MIN (sizeof (dua.operation),
   1220                              strlen (op)));
   1221   return
   1222     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED,
   1223                                 &dua,
   1224                                 &sig->eddsa_signature,
   1225                                 &pub->eddsa_pub);
   1226 }
   1227 
   1228 
   1229 GNUNET_NETWORK_STRUCT_BEGIN
   1230 
   1231 /**
   1232  * Response by which the exchange affirms that it has
   1233  * closed a reserve and send back the funds.
   1234  */
   1235 struct TALER_ReserveCloseConfirmationPS
   1236 {
   1237 
   1238   /**
   1239    * Purpose is #TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED
   1240    */
   1241   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1242 
   1243   /**
   1244    * When did the exchange initiate the wire transfer.
   1245    */
   1246   struct GNUNET_TIME_TimestampNBO timestamp;
   1247 
   1248   /**
   1249    * How much did the exchange send?
   1250    */
   1251   struct TALER_AmountNBO closing_amount;
   1252 
   1253   /**
   1254    * How much did the exchange charge for closing the reserve?
   1255    */
   1256   struct TALER_AmountNBO closing_fee;
   1257 
   1258   /**
   1259    * Public key of the reserve that was closed.
   1260    */
   1261   struct TALER_ReservePublicKeyP reserve_pub;
   1262 
   1263   /**
   1264    * Hash of the receiver's bank account.
   1265    */
   1266   struct TALER_FullPaytoHashP h_payto;
   1267 
   1268   /**
   1269    * Wire transfer subject.
   1270    */
   1271   struct TALER_WireTransferIdentifierRawP wtid;
   1272 };
   1273 
   1274 GNUNET_NETWORK_STRUCT_END
   1275 
   1276 
   1277 enum TALER_ErrorCode
   1278 TALER_exchange_online_reserve_closed_sign (
   1279   TALER_ExchangeSignCallback scb,
   1280   struct GNUNET_TIME_Timestamp timestamp,
   1281   const struct TALER_Amount *closing_amount,
   1282   const struct TALER_Amount *closing_fee,
   1283   const struct TALER_FullPayto payto,
   1284   const struct TALER_WireTransferIdentifierRawP *wtid,
   1285   const struct TALER_ReservePublicKeyP *reserve_pub,
   1286   struct TALER_ExchangePublicKeyP *pub,
   1287   struct TALER_ExchangeSignatureP *sig)
   1288 {
   1289   struct TALER_ReserveCloseConfirmationPS rcc = {
   1290     .purpose.size = htonl (sizeof (rcc)),
   1291     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED),
   1292     .wtid = *wtid,
   1293     .reserve_pub = *reserve_pub,
   1294     .timestamp = GNUNET_TIME_timestamp_hton (timestamp)
   1295   };
   1296 
   1297   TALER_amount_hton (&rcc.closing_amount,
   1298                      closing_amount);
   1299   TALER_amount_hton (&rcc.closing_fee,
   1300                      closing_fee);
   1301   TALER_full_payto_hash (payto,
   1302                          &rcc.h_payto);
   1303   return scb (&rcc.purpose,
   1304               pub,
   1305               sig);
   1306 }
   1307 
   1308 
   1309 enum GNUNET_GenericReturnValue
   1310 TALER_exchange_online_reserve_closed_verify (
   1311   struct GNUNET_TIME_Timestamp timestamp,
   1312   const struct TALER_Amount *closing_amount,
   1313   const struct TALER_Amount *closing_fee,
   1314   const struct TALER_FullPayto payto,
   1315   const struct TALER_WireTransferIdentifierRawP *wtid,
   1316   const struct TALER_ReservePublicKeyP *reserve_pub,
   1317   const struct TALER_ExchangePublicKeyP *pub,
   1318   const struct TALER_ExchangeSignatureP *sig)
   1319 {
   1320   struct TALER_ReserveCloseConfirmationPS rcc = {
   1321     .purpose.size = htonl (sizeof (rcc)),
   1322     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED),
   1323     .wtid = *wtid,
   1324     .reserve_pub = *reserve_pub,
   1325     .timestamp = GNUNET_TIME_timestamp_hton (timestamp)
   1326   };
   1327 
   1328   TALER_amount_hton (&rcc.closing_amount,
   1329                      closing_amount);
   1330   TALER_amount_hton (&rcc.closing_fee,
   1331                      closing_fee);
   1332   TALER_full_payto_hash (payto,
   1333                          &rcc.h_payto);
   1334   return GNUNET_CRYPTO_eddsa_verify (
   1335     TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED,
   1336     &rcc,
   1337     &sig->eddsa_signature,
   1338     &pub->eddsa_pub);
   1339 }
   1340 
   1341 
   1342 GNUNET_NETWORK_STRUCT_BEGIN
   1343 
   1344 /**
   1345  * Response by which the exchange affirms that it has
   1346  * received funds deposited into a purse.
   1347  */
   1348 struct TALER_PurseCreateDepositConfirmationPS
   1349 {
   1350 
   1351   /**
   1352    * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION
   1353    */
   1354   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1355 
   1356   /**
   1357    * When did the exchange receive the deposits.
   1358    */
   1359   struct GNUNET_TIME_TimestampNBO exchange_time;
   1360 
   1361   /**
   1362    * When will the purse expire?
   1363    */
   1364   struct GNUNET_TIME_TimestampNBO purse_expiration;
   1365 
   1366   /**
   1367    * How much should the purse ultimately contain.
   1368    */
   1369   struct TALER_AmountNBO amount_without_fee;
   1370 
   1371   /**
   1372    * How much was deposited so far.
   1373    */
   1374   struct TALER_AmountNBO total_deposited;
   1375 
   1376   /**
   1377    * Public key of the purse.
   1378    */
   1379   struct TALER_PurseContractPublicKeyP purse_pub;
   1380 
   1381   /**
   1382    * Hash of the contract of the purse.
   1383    */
   1384   struct TALER_PrivateContractHashP h_contract_terms;
   1385 
   1386 };
   1387 
   1388 GNUNET_NETWORK_STRUCT_END
   1389 
   1390 
   1391 enum TALER_ErrorCode
   1392 TALER_exchange_online_purse_created_sign (
   1393   TALER_ExchangeSignCallback scb,
   1394   struct GNUNET_TIME_Timestamp exchange_time,
   1395   struct GNUNET_TIME_Timestamp purse_expiration,
   1396   const struct TALER_Amount *amount_without_fee,
   1397   const struct TALER_Amount *total_deposited,
   1398   const struct TALER_PurseContractPublicKeyP *purse_pub,
   1399   const struct TALER_PrivateContractHashP *h_contract_terms,
   1400   struct TALER_ExchangePublicKeyP *pub,
   1401   struct TALER_ExchangeSignatureP *sig)
   1402 {
   1403   struct TALER_PurseCreateDepositConfirmationPS dc = {
   1404     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION),
   1405     .purpose.size = htonl (sizeof (dc)),
   1406     .h_contract_terms = *h_contract_terms,
   1407     .purse_pub = *purse_pub,
   1408     .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
   1409     .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time)
   1410   };
   1411 
   1412   TALER_amount_hton (&dc.amount_without_fee,
   1413                      amount_without_fee);
   1414   TALER_amount_hton (&dc.total_deposited,
   1415                      total_deposited);
   1416   return scb (&dc.purpose,
   1417               pub,
   1418               sig);
   1419 }
   1420 
   1421 
   1422 enum GNUNET_GenericReturnValue
   1423 TALER_exchange_online_purse_created_verify (
   1424   struct GNUNET_TIME_Timestamp exchange_time,
   1425   struct GNUNET_TIME_Timestamp purse_expiration,
   1426   const struct TALER_Amount *amount_without_fee,
   1427   const struct TALER_Amount *total_deposited,
   1428   const struct TALER_PurseContractPublicKeyP *purse_pub,
   1429   const struct TALER_PrivateContractHashP *h_contract_terms,
   1430   const struct TALER_ExchangePublicKeyP *pub,
   1431   const struct TALER_ExchangeSignatureP *sig)
   1432 {
   1433   struct TALER_PurseCreateDepositConfirmationPS dc = {
   1434     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION),
   1435     .purpose.size = htonl (sizeof (dc)),
   1436     .h_contract_terms = *h_contract_terms,
   1437     .purse_pub = *purse_pub,
   1438     .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
   1439     .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time)
   1440   };
   1441 
   1442   TALER_amount_hton (&dc.amount_without_fee,
   1443                      amount_without_fee);
   1444   TALER_amount_hton (&dc.total_deposited,
   1445                      total_deposited);
   1446   return GNUNET_CRYPTO_eddsa_verify (
   1447     TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION,
   1448     &dc,
   1449     &sig->eddsa_signature,
   1450     &pub->eddsa_pub);
   1451 }
   1452 
   1453 
   1454 GNUNET_NETWORK_STRUCT_BEGIN
   1455 
   1456 /**
   1457  * Response by which the exchange affirms that it has
   1458  * received funds deposited into a purse.
   1459  */
   1460 struct TALER_CoinPurseRefundConfirmationPS
   1461 {
   1462 
   1463   /**
   1464    * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND
   1465    */
   1466   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1467 
   1468   /**
   1469    * Public key of the purse.
   1470    */
   1471   struct TALER_PurseContractPublicKeyP purse_pub;
   1472 
   1473   /**
   1474    * Public key of the coin.
   1475    */
   1476   struct TALER_CoinSpendPublicKeyP coin_pub;
   1477 
   1478   /**
   1479    * How much will be refunded to the purse.
   1480    */
   1481   struct TALER_AmountNBO refunded_amount;
   1482 
   1483   /**
   1484    * How much was the refund fee.
   1485    */
   1486   struct TALER_AmountNBO refund_fee;
   1487 
   1488 };
   1489 
   1490 GNUNET_NETWORK_STRUCT_END
   1491 
   1492 
   1493 enum TALER_ErrorCode
   1494 TALER_exchange_online_purse_refund_sign (
   1495   TALER_ExchangeSignCallback scb,
   1496   const struct TALER_Amount *amount_without_fee,
   1497   const struct TALER_Amount *refund_fee,
   1498   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   1499   const struct TALER_PurseContractPublicKeyP *purse_pub,
   1500   struct TALER_ExchangePublicKeyP *pub,
   1501   struct TALER_ExchangeSignatureP *sig)
   1502 {
   1503   struct TALER_CoinPurseRefundConfirmationPS dc = {
   1504     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND),
   1505     .purpose.size = htonl (sizeof (dc)),
   1506     .coin_pub = *coin_pub,
   1507     .purse_pub = *purse_pub,
   1508   };
   1509 
   1510   TALER_amount_hton (&dc.refunded_amount,
   1511                      amount_without_fee);
   1512   TALER_amount_hton (&dc.refund_fee,
   1513                      refund_fee);
   1514   return scb (&dc.purpose,
   1515               pub,
   1516               sig);
   1517 }
   1518 
   1519 
   1520 enum GNUNET_GenericReturnValue
   1521 TALER_exchange_online_purse_refund_verify (
   1522   const struct TALER_Amount *amount_without_fee,
   1523   const struct TALER_Amount *refund_fee,
   1524   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   1525   const struct TALER_PurseContractPublicKeyP *purse_pub,
   1526   const struct TALER_ExchangePublicKeyP *pub,
   1527   const struct TALER_ExchangeSignatureP *sig)
   1528 {
   1529   struct TALER_CoinPurseRefundConfirmationPS dc = {
   1530     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND),
   1531     .purpose.size = htonl (sizeof (dc)),
   1532     .coin_pub = *coin_pub,
   1533     .purse_pub = *purse_pub,
   1534   };
   1535 
   1536   TALER_amount_hton (&dc.refunded_amount,
   1537                      amount_without_fee);
   1538   TALER_amount_hton (&dc.refund_fee,
   1539                      refund_fee);
   1540   return GNUNET_CRYPTO_eddsa_verify (
   1541     TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND,
   1542     &dc,
   1543     &sig->eddsa_signature,
   1544     &pub->eddsa_pub);
   1545 }
   1546 
   1547 
   1548 GNUNET_NETWORK_STRUCT_BEGIN
   1549 
   1550 /**
   1551  * Response by which the exchange affirms that it has
   1552  * merged a purse into a reserve.
   1553  */
   1554 struct TALER_PurseMergedConfirmationPS
   1555 {
   1556 
   1557   /**
   1558    * Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED
   1559    */
   1560   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1561 
   1562   /**
   1563    * When did the exchange receive the deposits.
   1564    */
   1565   struct GNUNET_TIME_TimestampNBO exchange_time;
   1566 
   1567   /**
   1568    * When will the purse expire?
   1569    */
   1570   struct GNUNET_TIME_TimestampNBO purse_expiration;
   1571 
   1572   /**
   1573    * How much should the purse ultimately contain.
   1574    */
   1575   struct TALER_AmountNBO amount_without_fee;
   1576 
   1577   /**
   1578    * Public key of the purse.
   1579    */
   1580   struct TALER_PurseContractPublicKeyP purse_pub;
   1581 
   1582   /**
   1583    * Public key of the reserve.
   1584    */
   1585   struct TALER_ReservePublicKeyP reserve_pub;
   1586 
   1587   /**
   1588    * Hash of the contract of the purse.
   1589    */
   1590   struct TALER_PrivateContractHashP h_contract_terms;
   1591 
   1592   /**
   1593    * Hash of the provider URL hosting the reserve.
   1594    */
   1595   struct GNUNET_HashCode h_provider_url;
   1596 
   1597 };
   1598 
   1599 GNUNET_NETWORK_STRUCT_END
   1600 
   1601 
   1602 enum TALER_ErrorCode
   1603 TALER_exchange_online_purse_merged_sign (
   1604   TALER_ExchangeSignCallback scb,
   1605   struct GNUNET_TIME_Timestamp exchange_time,
   1606   struct GNUNET_TIME_Timestamp purse_expiration,
   1607   const struct TALER_Amount *amount_without_fee,
   1608   const struct TALER_PurseContractPublicKeyP *purse_pub,
   1609   const struct TALER_PrivateContractHashP *h_contract_terms,
   1610   const struct TALER_ReservePublicKeyP *reserve_pub,
   1611   const char *exchange_url,
   1612   struct TALER_ExchangePublicKeyP *pub,
   1613   struct TALER_ExchangeSignatureP *sig)
   1614 {
   1615   struct TALER_PurseMergedConfirmationPS dc = {
   1616     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED),
   1617     .purpose.size = htonl (sizeof (dc)),
   1618     .h_contract_terms = *h_contract_terms,
   1619     .purse_pub = *purse_pub,
   1620     .reserve_pub = *reserve_pub,
   1621     .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
   1622     .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time)
   1623   };
   1624 
   1625   TALER_amount_hton (&dc.amount_without_fee,
   1626                      amount_without_fee);
   1627   GNUNET_CRYPTO_hash (exchange_url,
   1628                       strlen (exchange_url) + 1,
   1629                       &dc.h_provider_url);
   1630   return scb (&dc.purpose,
   1631               pub,
   1632               sig);
   1633 }
   1634 
   1635 
   1636 enum GNUNET_GenericReturnValue
   1637 TALER_exchange_online_purse_merged_verify (
   1638   struct GNUNET_TIME_Timestamp exchange_time,
   1639   struct GNUNET_TIME_Timestamp purse_expiration,
   1640   const struct TALER_Amount *amount_without_fee,
   1641   const struct TALER_PurseContractPublicKeyP *purse_pub,
   1642   const struct TALER_PrivateContractHashP *h_contract_terms,
   1643   const struct TALER_ReservePublicKeyP *reserve_pub,
   1644   const char *exchange_url,
   1645   const struct TALER_ExchangePublicKeyP *pub,
   1646   const struct TALER_ExchangeSignatureP *sig)
   1647 {
   1648   struct TALER_PurseMergedConfirmationPS dc = {
   1649     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED),
   1650     .purpose.size = htonl (sizeof (dc)),
   1651     .h_contract_terms = *h_contract_terms,
   1652     .purse_pub = *purse_pub,
   1653     .reserve_pub = *reserve_pub,
   1654     .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration),
   1655     .exchange_time = GNUNET_TIME_timestamp_hton (exchange_time)
   1656   };
   1657 
   1658   TALER_amount_hton (&dc.amount_without_fee,
   1659                      amount_without_fee);
   1660   GNUNET_CRYPTO_hash (exchange_url,
   1661                       strlen (exchange_url) + 1,
   1662                       &dc.h_provider_url);
   1663   return
   1664     GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_MERGED,
   1665                                 &dc,
   1666                                 &sig->eddsa_signature,
   1667                                 &pub->eddsa_pub);
   1668 }
   1669 
   1670 
   1671 GNUNET_NETWORK_STRUCT_BEGIN
   1672 
   1673 /**
   1674  * @brief Format used to generate the signature on a purse status
   1675  * from the exchange.
   1676  */
   1677 struct TALER_PurseStatusPS
   1678 {
   1679   /**
   1680    * Purpose must be #TALER_SIGNATURE_EXCHANGE_PURSE_STATUS.  Signed
   1681    * by a `struct TALER_ExchangePublicKeyP` using EdDSA.
   1682    */
   1683   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1684 
   1685   /**
   1686    * Time when the purse was merged, possibly 'never'.
   1687    */
   1688   struct GNUNET_TIME_TimestampNBO merge_timestamp;
   1689 
   1690   /**
   1691    * Time when the purse was deposited last, possibly 'never'.
   1692    */
   1693   struct GNUNET_TIME_TimestampNBO deposit_timestamp;
   1694 
   1695   /**
   1696    * Amount deposited in total in the purse without fees.
   1697    * May be possibly less than the target amount.
   1698    */
   1699   struct TALER_AmountNBO balance;
   1700 
   1701 };
   1702 
   1703 GNUNET_NETWORK_STRUCT_END
   1704 
   1705 
   1706 enum TALER_ErrorCode
   1707 TALER_exchange_online_purse_status_sign (
   1708   TALER_ExchangeSignCallback scb,
   1709   struct GNUNET_TIME_Timestamp merge_timestamp,
   1710   struct GNUNET_TIME_Timestamp deposit_timestamp,
   1711   const struct TALER_Amount *balance,
   1712   struct TALER_ExchangePublicKeyP *pub,
   1713   struct TALER_ExchangeSignatureP *sig)
   1714 {
   1715   struct TALER_PurseStatusPS dcs = {
   1716     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_PURSE_STATUS),
   1717     .purpose.size = htonl (sizeof (dcs)),
   1718     .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp),
   1719     .deposit_timestamp = GNUNET_TIME_timestamp_hton (deposit_timestamp)
   1720   };
   1721 
   1722   TALER_amount_hton (&dcs.balance,
   1723                      balance);
   1724   return scb (&dcs.purpose,
   1725               pub,
   1726               sig);
   1727 }
   1728 
   1729 
   1730 enum GNUNET_GenericReturnValue
   1731 TALER_exchange_online_purse_status_verify (
   1732   struct GNUNET_TIME_Timestamp merge_timestamp,
   1733   struct GNUNET_TIME_Timestamp deposit_timestamp,
   1734   const struct TALER_Amount *balance,
   1735   const struct TALER_ExchangePublicKeyP *exchange_pub,
   1736   const struct TALER_ExchangeSignatureP *exchange_sig)
   1737 {
   1738   struct TALER_PurseStatusPS dcs = {
   1739     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_PURSE_STATUS),
   1740     .purpose.size = htonl (sizeof (dcs)),
   1741     .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp),
   1742     .deposit_timestamp = GNUNET_TIME_timestamp_hton (deposit_timestamp)
   1743   };
   1744 
   1745   TALER_amount_hton (&dcs.balance,
   1746                      balance);
   1747   if (GNUNET_OK !=
   1748       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_PURSE_STATUS,
   1749                                   &dcs,
   1750                                   &exchange_sig->eddsa_signature,
   1751                                   &exchange_pub->eddsa_pub))
   1752   {
   1753     GNUNET_break_op (0);
   1754     return GNUNET_SYSERR;
   1755   }
   1756   return GNUNET_OK;
   1757 }
   1758 
   1759 
   1760 GNUNET_NETWORK_STRUCT_BEGIN
   1761 
   1762 /**
   1763  * Message signed by the exchange to affirm that the
   1764  * owner of a reserve has certain attributes.
   1765  */
   1766 struct TALER_ExchangeAttestPS
   1767 {
   1768 
   1769   /**
   1770    * Purpose is #TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS
   1771    */
   1772   struct GNUNET_CRYPTO_SignaturePurpose purpose;
   1773 
   1774   /**
   1775    * Time when the attestation was made.
   1776    */
   1777   struct GNUNET_TIME_TimestampNBO attest_timestamp;
   1778 
   1779   /**
   1780    * Time when the attestation expires.
   1781    */
   1782   struct GNUNET_TIME_TimestampNBO expiration_time;
   1783 
   1784   /**
   1785    * Public key of the reserve for which the attributes
   1786    * are attested.
   1787    */
   1788   struct TALER_ReservePublicKeyP reserve_pub;
   1789 
   1790   /**
   1791    * Hash over the attributes.
   1792    */
   1793   struct GNUNET_HashCode h_attributes;
   1794 
   1795 };
   1796 
   1797 GNUNET_NETWORK_STRUCT_END
   1798 
   1799 
   1800 enum TALER_ErrorCode
   1801 TALER_exchange_online_reserve_attest_details_sign (
   1802   TALER_ExchangeSignCallback scb,
   1803   struct GNUNET_TIME_Timestamp attest_timestamp,
   1804   struct GNUNET_TIME_Timestamp expiration_time,
   1805   const struct TALER_ReservePublicKeyP *reserve_pub,
   1806   const json_t *attributes,
   1807   struct TALER_ExchangePublicKeyP *pub,
   1808   struct TALER_ExchangeSignatureP *sig)
   1809 {
   1810   struct TALER_ExchangeAttestPS rap = {
   1811     .purpose.size = htonl (sizeof (rap)),
   1812     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS),
   1813     .attest_timestamp = GNUNET_TIME_timestamp_hton (attest_timestamp),
   1814     .expiration_time = GNUNET_TIME_timestamp_hton (expiration_time),
   1815     .reserve_pub = *reserve_pub
   1816   };
   1817 
   1818   TALER_json_hash (attributes,
   1819                    &rap.h_attributes);
   1820   return scb (&rap.purpose,
   1821               pub,
   1822               sig);
   1823 }
   1824 
   1825 
   1826 enum GNUNET_GenericReturnValue
   1827 TALER_exchange_online_reserve_attest_details_verify (
   1828   struct GNUNET_TIME_Timestamp attest_timestamp,
   1829   struct GNUNET_TIME_Timestamp expiration_time,
   1830   const struct TALER_ReservePublicKeyP *reserve_pub,
   1831   const json_t *attributes,
   1832   struct TALER_ExchangePublicKeyP *pub,
   1833   struct TALER_ExchangeSignatureP *sig)
   1834 {
   1835   struct TALER_ExchangeAttestPS rap = {
   1836     .purpose.size = htonl (sizeof (rap)),
   1837     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS),
   1838     .attest_timestamp = GNUNET_TIME_timestamp_hton (attest_timestamp),
   1839     .expiration_time = GNUNET_TIME_timestamp_hton (expiration_time),
   1840     .reserve_pub = *reserve_pub
   1841   };
   1842 
   1843   TALER_json_hash (attributes,
   1844                    &rap.h_attributes);
   1845   if (GNUNET_OK !=
   1846       GNUNET_CRYPTO_eddsa_verify (
   1847         TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS,
   1848         &rap,
   1849         &sig->eddsa_signature,
   1850         &pub->eddsa_pub))
   1851   {
   1852     GNUNET_break_op (0);
   1853     return GNUNET_SYSERR;
   1854   }
   1855   return GNUNET_OK;
   1856 }
   1857 
   1858 
   1859 /* end of exchange_signatures.c */