LCOV - code coverage report
Current view: top level - lib - test_coin_conflict.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 98.2 % 113 111
Test Date: 2026-10-17 15:46:49 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2026 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 lib/test_coin_conflict.c
      18              :  * @brief test the client-side checks of coin conflict proofs
      19              :  *        (#TALER_EXCHANGE_check_coin_denomination_conflict_() and
      20              :  *        #TALER_EXCHANGE_check_coin_age_commitment_conflict_())
      21              :  *        against replies built the way the exchange builds them
      22              :  * @author Özgür Kesim
      23              :  */
      24              : #include "platform.h"
      25              : #include "taler/taler_util.h"
      26              : #include "taler/taler_json_lib.h"
      27              : #include "taler/taler_exchange_service.h"
      28              : #include "exchange_api_common.h"
      29              : 
      30              : 
      31              : /**
      32              :  * Age mask of the age-restricted test denomination.
      33              :  */
      34              : static const struct TALER_AgeMask age_mask = {
      35              :   .bits = 1 | 1 << 8 | 1 << 10 | 1 << 12
      36              :           | 1 << 14 | 1 << 16 | 1 << 18 | 1 << 21
      37              : };
      38              : 
      39              : 
      40              : /**
      41              :  * A test denomination.
      42              :  */
      43              : struct Denom
      44              : {
      45              :   struct TALER_DenominationPrivateKey priv;
      46              :   struct TALER_DenominationPublicKey pub;
      47              :   struct TALER_DenominationHashP h;
      48              : };
      49              : 
      50              : 
      51              : /**
      52              :  * A coin issued by a test denomination.
      53              :  */
      54              : struct Coin
      55              : {
      56              :   struct TALER_CoinSpendPublicKeyP pub;
      57              :   struct TALER_DenominationSignature sig;
      58              : };
      59              : 
      60              : 
      61              : /**
      62              :  * Create an RSA test denomination.
      63              :  *
      64              :  * @param age_restricted whether the denomination has an age mask
      65              :  * @param[out] d the denomination
      66              :  */
      67              : static void
      68            2 : make_denom (bool age_restricted,
      69              :             struct Denom *d)
      70              : {
      71            2 :   GNUNET_assert (GNUNET_OK ==
      72              :                  TALER_denom_priv_create (&d->priv,
      73              :                                           &d->pub,
      74              :                                           GNUNET_CRYPTO_BSA_RSA,
      75              :                                           1024));
      76            2 :   if (age_restricted)
      77            1 :     d->pub.age_mask = age_mask;
      78            2 :   TALER_denom_pub_hash (&d->pub,
      79              :                         &d->h);
      80            2 : }
      81              : 
      82              : 
      83              : /**
      84              :  * Issue a coin: a fresh key, blinded, signed by @a d and unblinded.
      85              :  *
      86              :  * @param d the issuing denomination
      87              :  * @param ach age commitment hash to bind into the coin, NULL for none
      88              :  * @param[out] c the coin
      89              :  */
      90              : static void
      91            4 : make_coin (const struct Denom *d,
      92              :            const struct TALER_AgeCommitmentHashP *ach,
      93              :            struct Coin *c)
      94              : {
      95              :   struct TALER_PlanchetMasterSecretP ps;
      96              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
      97              :   union GNUNET_CRYPTO_BlindingSecretP bks;
      98              :   const struct TALER_ExchangeBlindingValues *alg_values;
      99              :   struct TALER_PlanchetDetail pd;
     100              :   struct TALER_BlindedDenominationSignature blind_sig;
     101              :   struct TALER_FreshCoin coin;
     102              :   struct TALER_CoinPubHashP c_hash;
     103              : 
     104            4 :   alg_values = TALER_denom_ewv_rsa_singleton ();
     105            4 :   GNUNET_CRYPTO_random_block (&ps,
     106              :                               sizeof (ps));
     107            4 :   TALER_planchet_setup_coin_priv (&ps,
     108              :                                   alg_values,
     109              :                                   &coin_priv);
     110            4 :   TALER_planchet_blinding_secret_create (&ps,
     111              :                                          alg_values,
     112              :                                          &bks);
     113            4 :   GNUNET_assert (GNUNET_OK ==
     114              :                  TALER_planchet_prepare (&d->pub,
     115              :                                          alg_values,
     116              :                                          &bks,
     117              :                                          NULL,
     118              :                                          &coin_priv,
     119              :                                          ach,
     120              :                                          &c_hash,
     121              :                                          &pd));
     122            4 :   GNUNET_assert (GNUNET_OK ==
     123              :                  TALER_denom_sign_blinded (&blind_sig,
     124              :                                            &d->priv,
     125              :                                            false,
     126              :                                            &pd.blinded_planchet));
     127            4 :   TALER_planchet_detail_free (&pd);
     128            4 :   GNUNET_assert (GNUNET_OK ==
     129              :                  TALER_planchet_to_coin (&d->pub,
     130              :                                          &blind_sig,
     131              :                                          &bks,
     132              :                                          &coin_priv,
     133              :                                          ach,
     134              :                                          &c_hash,
     135              :                                          alg_values,
     136              :                                          &coin));
     137            4 :   TALER_blinded_denom_sig_free (&blind_sig);
     138            4 :   GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
     139              :                                       &c->pub.eddsa_pub);
     140            4 :   c->sig = coin.sig;
     141            4 : }
     142              : 
     143              : 
     144              : /**
     145              :  * Build a denomination conflict reply as the exchange does.
     146              :  *
     147              :  * @param c the coin
     148              :  * @param prev the denomination the exchange knows the coin under
     149              :  * @param prev_ach age commitment hash stored for the coin, NULL for none
     150              :  * @return the reply body
     151              :  */
     152              : static json_t *
     153            9 : denom_conflict_reply (const struct Coin *c,
     154              :                       const struct Denom *prev,
     155              :                       const struct TALER_AgeCommitmentHashP *prev_ach)
     156              : {
     157              :   json_t *j;
     158              : 
     159            9 :   j = GNUNET_JSON_PACK (
     160              :     TALER_JSON_pack_ec (
     161              :       TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY),
     162              :     GNUNET_JSON_pack_data_auto ("coin_pub",
     163              :                                 &c->pub),
     164              :     TALER_JSON_pack_denom_pub ("prev_denom_pub",
     165              :                                &prev->pub),
     166              :     TALER_JSON_pack_denom_sig ("prev_denom_sig",
     167              :                                &c->sig),
     168              :     GNUNET_JSON_pack_allow_null (
     169              :       GNUNET_JSON_pack_data_auto ("prev_h_age_commitment",
     170              :                                   prev_ach)));
     171            9 :   GNUNET_assert (NULL != j);
     172            9 :   return j;
     173              : }
     174              : 
     175              : 
     176              : /**
     177              :  * Build an age commitment conflict reply as the exchange does.
     178              :  *
     179              :  * @param c the coin
     180              :  * @param d the denomination of the coin
     181              :  * @param expected age commitment hash stored for the coin, NULL for none
     182              :  * @return the reply body
     183              :  */
     184              : static json_t *
     185            8 : age_conflict_reply (const struct Coin *c,
     186              :                     const struct Denom *d,
     187              :                     const struct TALER_AgeCommitmentHashP *expected)
     188              : {
     189              :   json_t *j;
     190              : 
     191            8 :   j = GNUNET_JSON_PACK (
     192              :     TALER_JSON_pack_ec (
     193              :       TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH),
     194              :     GNUNET_JSON_pack_data_auto ("coin_pub",
     195              :                                 &c->pub),
     196              :     GNUNET_JSON_pack_data_auto ("h_denom_pub",
     197              :                                 &d->h),
     198              :     GNUNET_JSON_pack_allow_null (
     199              :       GNUNET_JSON_pack_data_auto ("expected_age_commitment_hash",
     200              :                                   expected)),
     201              :     GNUNET_JSON_pack_string ("conflict_detail",
     202              :                              "test"),
     203              :     TALER_JSON_pack_denom_sig ("prev_denom_sig",
     204              :                                &c->sig));
     205            8 :   GNUNET_assert (NULL != j);
     206            8 :   return j;
     207              : }
     208              : 
     209              : 
     210              : /**
     211              :  * Run the denomination conflict check on @a j for a client that used
     212              :  * @a used.
     213              :  *
     214              :  * @param keys exchange keys
     215              :  * @param j reply to check
     216              :  * @param used denomination hash the client used
     217              :  * @param[out] verified set to the verified flag of the parsed reply
     218              :  * @return result of the check, #GNUNET_SYSERR also if parsing failed
     219              :  */
     220              : static enum GNUNET_GenericReturnValue
     221            9 : run_denom_check (const struct TALER_EXCHANGE_Keys *keys,
     222              :                  json_t *j,
     223              :                  const struct TALER_DenominationHashP *used,
     224              :                  bool *verified)
     225              : {
     226              :   struct TALER_EXCHANGE_CoinDenominationConflict cdc;
     227              :   enum GNUNET_GenericReturnValue ret;
     228              : 
     229            9 :   *verified = false;
     230            9 :   if (GNUNET_OK !=
     231            9 :       TALER_EXCHANGE_parse_coin_denomination_conflict_ (j,
     232              :                                                         &cdc))
     233              :   {
     234            1 :     json_decref (j);
     235            1 :     return GNUNET_SYSERR;
     236              :   }
     237            8 :   ret = TALER_EXCHANGE_check_coin_denomination_conflict_ (keys,
     238              :                                                           used,
     239              :                                                           &cdc);
     240            8 :   *verified = cdc.verified;
     241            8 :   TALER_EXCHANGE_free_coin_denomination_conflict_ (&cdc);
     242            8 :   json_decref (j);
     243            8 :   return ret;
     244              : }
     245              : 
     246              : 
     247              : /**
     248              :  * Run the age commitment conflict check on @a j for a client that
     249              :  * used @a used_denom and @a used_ach.
     250              :  *
     251              :  * @param keys exchange keys
     252              :  * @param j reply to check
     253              :  * @param used_denom denomination hash the client used
     254              :  * @param used_ach age commitment hash the client used, NULL for none
     255              :  * @param[out] verified set to the verified flag of the parsed reply
     256              :  * @return result of the check, #GNUNET_SYSERR also if parsing failed
     257              :  */
     258              : static enum GNUNET_GenericReturnValue
     259            8 : run_age_check (const struct TALER_EXCHANGE_Keys *keys,
     260              :                json_t *j,
     261              :                const struct TALER_DenominationHashP *used_denom,
     262              :                const struct TALER_AgeCommitmentHashP *used_ach,
     263              :                bool *verified)
     264              : {
     265              :   struct TALER_EXCHANGE_CoinAgeCommitmentConflict cac;
     266              :   enum GNUNET_GenericReturnValue ret;
     267              : 
     268            8 :   *verified = false;
     269            8 :   if (GNUNET_OK !=
     270            8 :       TALER_EXCHANGE_parse_coin_age_commitment_conflict_ (j,
     271              :                                                           &cac))
     272              :   {
     273            0 :     json_decref (j);
     274            0 :     return GNUNET_SYSERR;
     275              :   }
     276            8 :   ret = TALER_EXCHANGE_check_coin_age_commitment_conflict_ (keys,
     277              :                                                             used_denom,
     278              :                                                             used_ach,
     279              :                                                             &cac);
     280            8 :   *verified = cac.verified;
     281            8 :   TALER_EXCHANGE_free_coin_age_commitment_conflict_ (&cac);
     282            8 :   json_decref (j);
     283            8 :   return ret;
     284              : }
     285              : 
     286              : 
     287              : #define CHECK(cond) do {                                        \
     288              :           if (! (cond))                                         \
     289              :           {                                                     \
     290              :             fprintf (stderr,                                    \
     291              :                      "FAILED: %s at %s:%u\n",                   \
     292              :                      #cond, __FILE__, __LINE__);                \
     293              :             return 1;                                           \
     294              :           }                                                     \
     295              : } while (0)
     296              : 
     297              : 
     298              : /**
     299              :  * Denomination conflicts: a coin issued by @a plain is claimed under
     300              :  * @a aged (valid proof), under @a plain itself (no conflict), by an
     301              :  * exchange we do not know the denomination of (unverifiable), with a
     302              :  * tampered coin key (bad signature), and the age hash consistency
     303              :  * check for a coin issued by @a aged.
     304              :  *
     305              :  * @param keys keys listing both denominations
     306              :  * @param keys_aged keys listing only @a aged
     307              :  * @param plain denomination without age restriction
     308              :  * @param aged age-restricted denomination
     309              :  * @return 0 on success
     310              :  */
     311              : static int
     312            1 : test_denomination_conflicts (const struct TALER_EXCHANGE_Keys *keys,
     313              :                              const struct TALER_EXCHANGE_Keys *keys_aged,
     314              :                              const struct Denom *plain,
     315              :                              const struct Denom *aged)
     316              : {
     317              :   struct Coin c;
     318              :   struct Coin ca;
     319              :   struct TALER_AgeCommitmentHashP ach;
     320              :   struct TALER_AgeCommitmentHashP other;
     321              :   bool verified;
     322              :   json_t *j;
     323              : 
     324            1 :   GNUNET_CRYPTO_random_block (&ach,
     325              :                               sizeof (ach));
     326            1 :   GNUNET_CRYPTO_random_block (&other,
     327              :                               sizeof (other));
     328            1 :   make_coin (plain,
     329              :              NULL,
     330              :              &c);
     331            1 :   make_coin (aged,
     332              :              &ach,
     333              :              &ca);
     334              : 
     335              :   /* valid proof: known under 'plain', client used 'aged' */
     336            1 :   CHECK (GNUNET_OK ==
     337              :          run_denom_check (keys,
     338              :                           denom_conflict_reply (&c,
     339              :                                                 plain,
     340              :                                                 NULL),
     341              :                           &aged->h,
     342              :                           &verified));
     343            1 :   CHECK (verified);
     344              :   /* same denomination: not a conflict */
     345            1 :   CHECK (GNUNET_SYSERR ==
     346              :          run_denom_check (keys,
     347              :                           denom_conflict_reply (&c,
     348              :                                                 plain,
     349              :                                                 NULL),
     350              :                           &plain->h,
     351              :                           &verified));
     352              :   /* 'plain' is not in our keys: accepted, unverifiable */
     353            1 :   CHECK (GNUNET_NO ==
     354              :          run_denom_check (keys_aged,
     355              :                           denom_conflict_reply (&c,
     356              :                                                 plain,
     357              :                                                 NULL),
     358              :                           &aged->h,
     359              :                           &verified));
     360            1 :   CHECK (! verified);
     361              :   /* tampered coin key: signature does not verify */
     362            1 :   j = denom_conflict_reply (&c,
     363              :                             plain,
     364              :                             NULL);
     365            1 :   GNUNET_assert (0 ==
     366              :                  json_object_set_new (j,
     367              :                                       "coin_pub",
     368              :                                       GNUNET_JSON_from_data_auto (&ca.pub)));
     369            1 :   CHECK (GNUNET_SYSERR ==
     370              :          run_denom_check (keys,
     371              :                           j,
     372              :                           &aged->h,
     373              :                           &verified));
     374              :   /* age hash claimed for a denomination without age restriction */
     375            1 :   CHECK (GNUNET_SYSERR ==
     376              :          run_denom_check (keys,
     377              :                           denom_conflict_reply (&c,
     378              :                                                 plain,
     379              :                                                 &ach),
     380              :                           &aged->h,
     381              :                           &verified));
     382              :   /* valid proof with age hash: known under 'aged', client used 'plain' */
     383            1 :   CHECK (GNUNET_OK ==
     384              :          run_denom_check (keys,
     385              :                           denom_conflict_reply (&ca,
     386              :                                                 aged,
     387              :                                                 &ach),
     388              :                           &plain->h,
     389              :                           &verified));
     390            1 :   CHECK (verified);
     391              :   /* age hash missing for an age-restricted denomination */
     392            1 :   CHECK (GNUNET_SYSERR ==
     393              :          run_denom_check (keys,
     394              :                           denom_conflict_reply (&ca,
     395              :                                                 aged,
     396              :                                                 NULL),
     397              :                           &plain->h,
     398              :                           &verified));
     399              :   /* wrong age hash: signature does not verify */
     400            1 :   CHECK (GNUNET_SYSERR ==
     401              :          run_denom_check (keys,
     402              :                           denom_conflict_reply (&ca,
     403              :                                                 aged,
     404              :                                                 &other),
     405              :                           &plain->h,
     406              :                           &verified));
     407              :   /* malformed: prev_denom_sig missing */
     408            1 :   j = denom_conflict_reply (&c,
     409              :                             plain,
     410              :                             NULL);
     411            1 :   GNUNET_assert (0 ==
     412              :                  json_object_del (j,
     413              :                                   "prev_denom_sig"));
     414            1 :   CHECK (GNUNET_SYSERR ==
     415              :          run_denom_check (keys,
     416              :                           j,
     417              :                           &aged->h,
     418              :                           &verified));
     419            1 :   TALER_denom_sig_free (&c.sig);
     420            1 :   TALER_denom_sig_free (&ca.sig);
     421            1 :   return 0;
     422              : }
     423              : 
     424              : 
     425              : /**
     426              :  * Age commitment conflicts: a coin issued by @a aged with hash X is
     427              :  * claimed with hash Y (valid), with X (no conflict), without a hash
     428              :  * (valid), under another denomination (invalid), by an exchange we do
     429              :  * not know the denomination of (unverifiable), with a wrong stored
     430              :  * hash (bad signature); and a coin issued by @a plain without a hash
     431              :  * claimed with one.
     432              :  *
     433              :  * @param keys keys listing both denominations
     434              :  * @param keys_plain keys listing only @a plain
     435              :  * @param plain denomination without age restriction
     436              :  * @param aged age-restricted denomination
     437              :  * @return 0 on success
     438              :  */
     439              : static int
     440            1 : test_age_conflicts (const struct TALER_EXCHANGE_Keys *keys,
     441              :                     const struct TALER_EXCHANGE_Keys *keys_plain,
     442              :                     const struct Denom *plain,
     443              :                     const struct Denom *aged)
     444              : {
     445              :   struct Coin c;
     446              :   struct Coin ca;
     447              :   struct TALER_AgeCommitmentHashP x;
     448              :   struct TALER_AgeCommitmentHashP y;
     449              :   bool verified;
     450              : 
     451            1 :   GNUNET_CRYPTO_random_block (&x,
     452              :                               sizeof (x));
     453            1 :   GNUNET_CRYPTO_random_block (&y,
     454              :                               sizeof (y));
     455            1 :   make_coin (aged,
     456              :              &x,
     457              :              &ca);
     458            1 :   make_coin (plain,
     459              :              NULL,
     460              :              &c);
     461              : 
     462              :   /* valid: stored X, client used Y */
     463            1 :   CHECK (GNUNET_OK ==
     464              :          run_age_check (keys,
     465              :                         age_conflict_reply (&ca,
     466              :                                             aged,
     467              :                                             &x),
     468              :                         &aged->h,
     469              :                         &y,
     470              :                         &verified));
     471            1 :   CHECK (verified);
     472              :   /* same hash: not a conflict */
     473            1 :   CHECK (GNUNET_SYSERR ==
     474              :          run_age_check (keys,
     475              :                         age_conflict_reply (&ca,
     476              :                                             aged,
     477              :                                             &x),
     478              :                         &aged->h,
     479              :                         &x,
     480              :                         &verified));
     481              :   /* valid: stored X, client used none */
     482            1 :   CHECK (GNUNET_OK ==
     483              :          run_age_check (keys,
     484              :                         age_conflict_reply (&ca,
     485              :                                             aged,
     486              :                                             &x),
     487              :                         &aged->h,
     488              :                         NULL,
     489              :                         &verified));
     490            1 :   CHECK (verified);
     491              :   /* different denomination: that would be a denomination conflict */
     492            1 :   CHECK (GNUNET_SYSERR ==
     493              :          run_age_check (keys,
     494              :                         age_conflict_reply (&ca,
     495              :                                             aged,
     496              :                                             &x),
     497              :                         &plain->h,
     498              :                         &y,
     499              :                         &verified));
     500              :   /* 'aged' is not in our keys: accepted, unverifiable */
     501            1 :   CHECK (GNUNET_NO ==
     502              :          run_age_check (keys_plain,
     503              :                         age_conflict_reply (&ca,
     504              :                                             aged,
     505              :                                             &x),
     506              :                         &aged->h,
     507              :                         &y,
     508              :                         &verified));
     509            1 :   CHECK (! verified);
     510              :   /* stored hash claimed to be Y: signature does not verify */
     511            1 :   CHECK (GNUNET_SYSERR ==
     512              :          run_age_check (keys,
     513              :                         age_conflict_reply (&ca,
     514              :                                             aged,
     515              :                                             &y),
     516              :                         &aged->h,
     517              :                         &x,
     518              :                         &verified));
     519              :   /* valid: stored none, client used Y */
     520            1 :   CHECK (GNUNET_OK ==
     521              :          run_age_check (keys,
     522              :                         age_conflict_reply (&c,
     523              :                                             plain,
     524              :                                             NULL),
     525              :                         &plain->h,
     526              :                         &y,
     527              :                         &verified));
     528            1 :   CHECK (verified);
     529              :   /* stored none, client used none: not a conflict */
     530            1 :   CHECK (GNUNET_SYSERR ==
     531              :          run_age_check (keys,
     532              :                         age_conflict_reply (&c,
     533              :                                             plain,
     534              :                                             NULL),
     535              :                         &plain->h,
     536              :                         NULL,
     537              :                         &verified));
     538            1 :   TALER_denom_sig_free (&c.sig);
     539            1 :   TALER_denom_sig_free (&ca.sig);
     540            1 :   return 0;
     541              : }
     542              : 
     543              : 
     544              : int
     545            1 : main (int argc,
     546              :       const char *const argv[])
     547              : {
     548              :   struct Denom plain;
     549              :   struct Denom aged;
     550              :   struct TALER_EXCHANGE_DenomPublicKey dks[2];
     551            1 :   struct TALER_EXCHANGE_Keys keys = {
     552              :     .denom_keys = dks,
     553              :     .num_denom_keys = 2
     554              :   };
     555            1 :   struct TALER_EXCHANGE_Keys keys_plain = {
     556              :     .denom_keys = &dks[0],
     557              :     .num_denom_keys = 1
     558              :   };
     559            1 :   struct TALER_EXCHANGE_Keys keys_aged = {
     560              :     .denom_keys = &dks[1],
     561              :     .num_denom_keys = 1
     562              :   };
     563              :   int ret;
     564              : 
     565              :   (void) argc;
     566              :   (void) argv;
     567            1 :   GNUNET_log_setup ("test-coin-conflict",
     568              :                     "WARNING",
     569              :                     NULL);
     570            1 :   make_denom (false,
     571              :               &plain);
     572            1 :   make_denom (true,
     573              :               &aged);
     574            1 :   memset (dks,
     575              :           0,
     576              :           sizeof (dks));
     577            1 :   dks[0].key = plain.pub;
     578            1 :   dks[0].h_key = plain.h;
     579            1 :   dks[1].key = aged.pub;
     580            1 :   dks[1].h_key = aged.h;
     581              : 
     582            1 :   ret = test_denomination_conflicts (&keys,
     583              :                                      &keys_aged,
     584              :                                      &plain,
     585              :                                      &aged);
     586            1 :   if (0 == ret)
     587            1 :     ret = test_age_conflicts (&keys,
     588              :                               &keys_plain,
     589              :                               &plain,
     590              :                               &aged);
     591            1 :   TALER_denom_priv_free (&plain.priv);
     592            1 :   TALER_denom_pub_free (&plain.pub);
     593            1 :   TALER_denom_priv_free (&aged.priv);
     594            1 :   TALER_denom_pub_free (&aged.pub);
     595            1 :   return ret;
     596              : }
     597              : 
     598              : 
     599              : /* end of test_coin_conflict.c */
        

Generated by: LCOV version 2.0-1