diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/benchmark/taler-aggregator-benchmark.c | 6 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_melt.c | 9 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_refreshes_reveal.c | 29 | ||||
| -rw-r--r-- | src/exchangedb/exchange-0001.sql | 11 | ||||
| -rw-r--r-- | src/exchangedb/irbt_callbacks.c | 2 | ||||
| -rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 48 | ||||
| -rw-r--r-- | src/include/taler_crypto_lib.h | 10 | ||||
| -rw-r--r-- | src/include/taler_exchange_service.h | 12 | ||||
| -rw-r--r-- | src/include/taler_exchangedb_plugin.h | 8 | ||||
| -rw-r--r-- | src/lib/exchange_api_common.c | 30 | ||||
| -rw-r--r-- | src/lib/exchange_api_link.c | 36 | ||||
| -rw-r--r-- | src/lib/exchange_api_melt.c | 7 | ||||
| -rw-r--r-- | src/lib/exchange_api_refresh_common.c | 38 | ||||
| -rw-r--r-- | src/lib/exchange_api_refresh_common.h | 4 | ||||
| -rw-r--r-- | src/lib/exchange_api_refreshes_reveal.c | 21 | ||||
| -rw-r--r-- | src/testing/test_exchange_api.c | 121 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_deposit.c | 14 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_refresh.c | 66 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_withdraw.c | 10 | ||||
| -rw-r--r-- | src/util/crypto.c | 102 | ||||
| -rw-r--r-- | src/util/wallet_signatures.c | 8 | 
21 files changed, 381 insertions, 211 deletions
| diff --git a/src/benchmark/taler-aggregator-benchmark.c b/src/benchmark/taler-aggregator-benchmark.c index 11ceec90..6d5df1e6 100644 --- a/src/benchmark/taler-aggregator-benchmark.c +++ b/src/benchmark/taler-aggregator-benchmark.c @@ -528,14 +528,14 @@ run (void *cls,                                             &bks);      { -      uint32_t seed; +      uint64_t seed;        struct TALER_AgeMask mask = {          .mask = 1 || 1 << 8 || 1 << 12 || 1 << 16 || 1 << 18        };        struct TALER_AgeCommitment ac = {0}; -      seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, -                                       UINT32_MAX); +      seed = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, +                                       UINT64_MAX);        GNUNET_assert (GNUNET_OK ==                       TALER_age_restriction_commit ( diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c index 03075280..049fd09a 100644 --- a/src/exchange/taler-exchange-httpd_melt.c +++ b/src/exchange/taler-exchange-httpd_melt.c @@ -425,7 +425,7 @@ TEH_handler_melt (struct MHD_Connection *connection,      GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",                                   &rmc.refresh_session.coin.denom_pub_hash),      GNUNET_JSON_spec_mark_optional ( -      GNUNET_JSON_spec_fixed_auto ("h_age_commitment", +      GNUNET_JSON_spec_fixed_auto ("age_commitment_hash",                                     &rmc.refresh_session.coin.h_age_commitment)),      GNUNET_JSON_spec_fixed_auto ("confirm_sig",                                   &rmc.refresh_session.coin_sig), @@ -440,10 +440,9 @@ TEH_handler_melt (struct MHD_Connection *connection,      GNUNET_JSON_spec_end ()    }; -  memset (&rmc, -          0, -          sizeof (rmc)); +  memset (&rmc, 0, sizeof (rmc));    rmc.refresh_session.coin.coin_pub = *coin_pub; +    {      enum GNUNET_GenericReturnValue ret;      ret = TALER_MHD_parse_json_data (connection, @@ -452,8 +451,10 @@ TEH_handler_melt (struct MHD_Connection *connection,      if (GNUNET_OK != ret)        return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;    } +    rmc.have_rms = (NULL != json_object_get (root,                                             "rms")); +    {      MHD_RESULT res; diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c index bace776d..23620f87 100644 --- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c +++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c @@ -277,7 +277,7 @@ check_commitment (struct RevealContext *rctx,            union TALER_DenominationBlindingKeyP bks;            const struct TALER_ExchangeWithdrawValues *alg_value              = &rctx->rrcs[j].exchange_vals; -          struct TALER_PlanchetDetail pd; +          struct TALER_PlanchetDetail pd = {0};            struct TALER_AgeCommitmentHash *hac = NULL;            struct TALER_CoinPubHashP c_hash;            struct TALER_PlanchetMasterSecretP ps; @@ -298,15 +298,16 @@ check_commitment (struct RevealContext *rctx,            {              struct TALER_AgeCommitment ac = {0};              struct TALER_AgeCommitmentHash h = {0}; +            uint64_t seed = (uint64_t) ts.key.bits[0] +                            | (uint64_t) ts.key.bits[1] << 32;              GNUNET_assert (GNUNET_OK ==                             TALER_age_commitment_derive (                               rctx->old_age_commitment, -                             ts.key.bits[0], +                             seed,                               &ac));              TALER_age_commitment_hash (&ac, &h); -              hac = &h;            } @@ -590,7 +591,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,    if (TEH_age_restriction_enabled &&        ((NULL == old_age_commitment_json) !=         TALER_AgeCommitmentHash_isNullOrZero ( -         &rctx->melt.session.h_age_commitment))) +         &rctx->melt.session.coin.h_age_commitment)))    {      GNUNET_break (0);      return MHD_NO; @@ -602,7 +603,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,        (NULL != old_age_commitment_json))    {      enum GNUNET_GenericReturnValue res; -    struct TALER_AgeCommitment *oac = rctx->old_age_commitment; +    struct TALER_AgeCommitment *oac;      size_t ng = json_array_size (old_age_commitment_json);      bool failed = true; @@ -610,7 +611,8 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,      GNUNET_assert (ng ==                     TALER_extensions_age_restriction_num_groups ()); -    oac = GNUNET_new (struct TALER_AgeCommitment); +    rctx->old_age_commitment = GNUNET_new (struct TALER_AgeCommitment); +    oac = rctx->old_age_commitment;      oac->mask  =  TEH_age_mask;      oac->num_pub = ng;      oac->num_priv = 0; /* no private keys are needed for the reveal phase */ @@ -630,7 +632,8 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,                                          ac_spec,                                          i,                                          -1); -      GNUNET_break (GNUNET_OK != res); + +      GNUNET_break_op (GNUNET_OK == res);        if (GNUNET_OK != res)          goto clean_age;      } @@ -640,12 +643,9 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,        struct TALER_AgeCommitmentHash hac = {0};        TALER_age_commitment_hash (oac, &hac);        if (0 != memcmp (&hac, -                       &rctx->melt.session.h_age_commitment, +                       &rctx->melt.session.coin.h_age_commitment,                         sizeof(struct TALER_AgeCommitmentHash))) -      { -        GNUNET_break (0);          goto clean_age; -      }      }      failed = false; @@ -654,7 +654,10 @@ clean_age:      if (failed)      {        TALER_age_commitment_free (oac); -      return (GNUNET_NO == res) ? MHD_YES : MHD_NO; +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_BAD_REQUEST, +                                         TALER_EC_EXCHANGE_REFRESHES_REVEAL_AGE_RESTRICTION_COMMITMENT_INVALID, +                                         "old_age_commitment");      }    } @@ -913,7 +916,7 @@ TEH_handler_reveal (struct TEH_RequestContext *rc,    json_t *transfer_privs;    json_t *link_sigs;    json_t *new_denoms_h; -  json_t *old_age_commitment = NULL; +  json_t *old_age_commitment;    struct RevealContext rctx;    struct GNUNET_JSON_Specification spec[] = {      GNUNET_JSON_spec_fixed_auto ("transfer_pub", diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql index 3f9979c0..0cef7d0d 100644 --- a/src/exchangedb/exchange-0001.sql +++ b/src/exchangedb/exchange-0001.sql @@ -311,7 +311,7 @@ CREATE TABLE IF NOT EXISTS known_coins    (known_coin_id BIGINT GENERATED BY DEFAULT AS IDENTITY -- UNIQUE    ,denominations_serial INT8 NOT NULL REFERENCES denominations (denominations_serial) ON DELETE CASCADE    ,coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (LENGTH(coin_pub)=32) -  ,age_hash BYTEA CHECK (LENGTH(age_hash)=32) +  ,age_commitment_hash BYTEA CHECK (LENGTH(age_commitment_hash)=32)    ,denom_sig BYTEA NOT NULL    ,remaining_val INT8 NOT NULL    ,remaining_frac INT4 NOT NULL @@ -325,8 +325,8 @@ COMMENT ON COLUMN known_coins.coin_pub    IS 'EdDSA public key of the coin';  COMMENT ON COLUMN known_coins.remaining_val    IS 'Value of the coin that remains to be spent'; -COMMENT ON COLUMN known_coins.age_hash -  IS 'Optional hash for age restrictions as per DD 24 (active if denom_type has the respective bit set)'; +COMMENT ON COLUMN known_coins.age_commitment_hash +  IS 'Optional hash of the age commitment for age restrictions as per DD 24 (active if denom_type has the respective bit set)';  COMMENT ON COLUMN known_coins.denom_sig    IS 'This is the signature of the exchange that affirms that the coin is a valid coin. The specific signature type depends on denom_type of the denomination.';  CREATE TABLE IF NOT EXISTS known_coins_default @@ -358,7 +358,7 @@ COMMENT ON COLUMN refresh_commitments.rc  COMMENT ON COLUMN refresh_commitments.old_coin_pub    IS 'Coin being melted in the refresh process.';  COMMENT ON COLUMN refresh_commitments.h_age_commitment -  IS '(optional) age commitment that was involved in the minting process of the coin, may be NULL.'; +  IS 'The (optional) age commitment that was involved in the minting process of the coin, may be NULL.';  CREATE TABLE IF NOT EXISTS refresh_commitments_default    PARTITION OF refresh_commitments    FOR VALUES WITH (MODULUS 1, REMAINDER 0); @@ -1259,6 +1259,7 @@ CREATE OR REPLACE FUNCTION exchange_do_melt(    IN in_old_coin_pub BYTEA,    IN in_old_coin_sig BYTEA,    IN in_known_coin_id INT8, -- not used, but that's OK +  IN in_h_age_commitment BYTEA,    IN in_noreveal_index INT4,    IN in_zombie_required BOOLEAN,    OUT out_balance_ok BOOLEAN, @@ -1281,6 +1282,7 @@ INSERT INTO refresh_commitments    ,old_coin_sig    ,amount_with_fee_val    ,amount_with_fee_frac +  ,h_age_commitment    ,noreveal_index    )    VALUES @@ -1289,6 +1291,7 @@ INSERT INTO refresh_commitments    ,in_old_coin_sig    ,in_amount_with_fee_val    ,in_amount_with_fee_frac +  ,in_h_age_commitment    ,in_noreveal_index)    ON CONFLICT DO NOTHING; diff --git a/src/exchangedb/irbt_callbacks.c b/src/exchangedb/irbt_callbacks.c index cf054942..3673c7be 100644 --- a/src/exchangedb/irbt_callbacks.c +++ b/src/exchangedb/irbt_callbacks.c @@ -406,6 +406,8 @@ irbt_cb_table_refresh_commitments (struct PostgresClosure *pg,        &td->details.refresh_commitments.noreveal_index),      GNUNET_PQ_query_param_auto_from_type (        &td->details.refresh_commitments.old_coin_pub), +    GNUNET_PQ_query_param_auto_from_type ( +      &td->details.refresh_commitments.h_age_commitment),      GNUNET_PQ_query_param_end    }; diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index b5bf71e5..2f59401c 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -611,7 +611,7 @@ prepare_statements (struct PostgresClosure *pg)        ",out_zombie_bad AS zombie_required"        ",out_noreveal_index AS noreveal_index"        " FROM exchange_do_melt" -      " ($1,$2,$3,$4,$5,$6,$7,$8,$9);", +      " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10);",        9),      /* Used in #postgres_do_refund() to refund a deposit. */      GNUNET_PQ_make_prepare ( @@ -730,7 +730,7 @@ prepare_statements (struct PostgresClosure *pg)        "get_known_coin",        "SELECT"        " denominations.denom_pub_hash" -      ",age_hash" +      ",age_commitment_hash"        ",denom_sig"        " FROM known_coins"        " JOIN denominations USING (denominations_serial)" @@ -784,7 +784,7 @@ prepare_statements (struct PostgresClosure *pg)        "  INSERT INTO known_coins "        "  (coin_pub"        "  ,denominations_serial" -      "  ,age_hash" +      "  ,age_commitment_hash"        "  ,denom_sig"        "  ,remaining_val"        "  ,remaining_frac" @@ -804,14 +804,14 @@ prepare_statements (struct PostgresClosure *pg)        "   FALSE AS existed"        "  ,known_coin_id"        "  ,NULL AS denom_pub_hash" -      "  ,NULL AS age_hash" +      "  ,NULL AS age_commitment_hash"        "  FROM ins "        "UNION ALL "        "SELECT "        "   TRUE AS existed"        "  ,known_coin_id"        "  ,denom_pub_hash" -      "  ,kc.age_hash" +      "  ,kc.age_commitment_hash"        "  FROM input_rows"        "  JOIN known_coins kc USING (coin_pub)"        "  JOIN denominations USING (denominations_serial)" @@ -873,6 +873,7 @@ prepare_statements (struct PostgresClosure *pg)        ",denoms.denom_pub_hash"        ",denoms.fee_refresh_val"        ",denoms.fee_refresh_frac" +      ",h_age_commitment"        ",melt_serial_id"        " FROM refresh_commitments"        " JOIN known_coins kc" @@ -1188,7 +1189,7 @@ prepare_statements (struct PostgresClosure *pg)        ",denoms.fee_deposit_val"        ",denoms.fee_deposit_frac"        ",denoms.denom_pub_hash" -      ",kc.age_hash" +      ",kc.age_commitment_hash"        ",wallet_timestamp"        ",refund_deadline"        ",wire_deadline" @@ -2529,8 +2530,9 @@ prepare_statements (struct PostgresClosure *pg)        ",amount_with_fee_frac"        ",noreveal_index"        ",old_coin_pub" +      ",h_age_commitment"        ") VALUES " -      "($1, $2, $3, $4, $5, $6, $7);", +      "($1, $2, $3, $4, $5, $6, $7, $8);",        7),      GNUNET_PQ_make_prepare (        "insert_into_table_refresh_revealed_coins", @@ -4593,6 +4595,7 @@ postgres_do_melt (      GNUNET_PQ_query_param_auto_from_type (&refresh->coin.coin_pub),      GNUNET_PQ_query_param_auto_from_type (&refresh->coin_sig),      GNUNET_PQ_query_param_uint64 (&known_coin_id), +    GNUNET_PQ_query_param_auto_from_type (&refresh->coin.h_age_commitment),      GNUNET_PQ_query_param_uint32 (&refresh->noreveal_index),      GNUNET_PQ_query_param_bool (*zombie_required),      GNUNET_PQ_query_param_end @@ -5646,7 +5649,7 @@ postgres_get_known_coin (void *cls,      GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",                                            &coin_info->denom_pub_hash),      GNUNET_PQ_result_spec_allow_null ( -      GNUNET_PQ_result_spec_auto_from_type ("age_hash", +      GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",                                              &coin_info->h_age_commitment),        &is_null),      TALER_PQ_result_spec_denom_sig ("denom_sig", @@ -5747,7 +5750,7 @@ postgres_count_known_coins (void *cls,   * @param[out] known_coin_id set to the unique row of the coin   * @param[out] denom_hash set to the denomination hash of the existing   *             coin (for conflict error reporting) - * @param[out] age_hash set to the conflicting age hash on conflict + * @param[out] h_age_commitment  set to the conflicting age commitment hash on conflict   * @return database transaction status, non-negative on success   */  static enum TALER_EXCHANGEDB_CoinKnownStatus @@ -5755,7 +5758,7 @@ postgres_ensure_coin_known (void *cls,                              const struct TALER_CoinPublicInfo *coin,                              uint64_t *known_coin_id,                              struct TALER_DenominationHashP *denom_hash, -                            struct TALER_AgeCommitmentHash *age_hash) +                            struct TALER_AgeCommitmentHash *h_age_commitment)  {    struct PostgresClosure *pg = cls;    enum GNUNET_DB_QueryStatus qs; @@ -5779,8 +5782,8 @@ postgres_ensure_coin_known (void *cls,                                              denom_hash),        &is_denom_pub_hash_null),      GNUNET_PQ_result_spec_allow_null ( -      GNUNET_PQ_result_spec_auto_from_type ("age_hash", -                                            age_hash), +      GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash", +                                            h_age_commitment),        &is_age_hash_null),      GNUNET_PQ_result_spec_end    }; @@ -5814,10 +5817,10 @@ postgres_ensure_coin_known (void *cls,    }    if ( (! is_age_hash_null) && -       (0 != GNUNET_memcmp (age_hash, +       (0 != GNUNET_memcmp (h_age_commitment,                              &coin->h_age_commitment)) )    { -    GNUNET_break (GNUNET_is_zero (age_hash)); +    GNUNET_break (GNUNET_is_zero (h_age_commitment));      GNUNET_break_op (0);      return TALER_EXCHANGEDB_CKS_AGE_CONFLICT;    } @@ -6066,7 +6069,7 @@ postgres_get_melt (void *cls,                                            &melt->session.coin_sig),      GNUNET_PQ_result_spec_allow_null (        GNUNET_PQ_result_spec_auto_from_type ("h_age_commitment", -                                            &melt->session.h_age_commitment), +                                            &melt->session.coin.h_age_commitment),        &h_age_commitment_is_null),      TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",                                   &melt->session.amount_with_fee), @@ -6084,9 +6087,9 @@ postgres_get_melt (void *cls,                                                   params,                                                   rs);    if (h_age_commitment_is_null) -    memset (&melt->session.h_age_commitment, +    memset (&melt->session.coin.h_age_commitment,              0, -            sizeof(melt->session.h_age_commitment)); +            sizeof(melt->session.coin.h_age_commitment));    melt->session.rc = *rc;    return qs; @@ -6600,7 +6603,7 @@ add_coin_deposit (void *cls,          GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",                                                &deposit->h_denom_pub),          GNUNET_PQ_result_spec_allow_null ( -          GNUNET_PQ_result_spec_auto_from_type ("age_hash", +          GNUNET_PQ_result_spec_auto_from_type ("age_commitment_hash",                                                  &deposit->h_age_commitment),            &is_null),          GNUNET_PQ_result_spec_timestamp ("wallet_timestamp", @@ -6668,6 +6671,7 @@ add_coin_melt (void *cls,      struct TALER_EXCHANGEDB_MeltListEntry *melt;      struct TALER_EXCHANGEDB_TransactionList *tl;      uint64_t serial_id; +    bool hac_isnull;      chc->have_deposit_or_melt = true;      melt = GNUNET_new (struct TALER_EXCHANGEDB_MeltListEntry); @@ -6684,6 +6688,10 @@ add_coin_melt (void *cls,                                       &melt->amount_with_fee),          TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refresh",                                       &melt->melt_fee), +        GNUNET_PQ_result_spec_allow_null ( +          GNUNET_PQ_result_spec_auto_from_type ("h_age_commitment", +                                                &melt->h_age_commitment), +          &hac_isnull),          GNUNET_PQ_result_spec_uint64 ("melt_serial_id",                                        &serial_id),          GNUNET_PQ_result_spec_end @@ -6699,6 +6707,10 @@ add_coin_melt (void *cls,          chc->failed = true;          return;        } + +      if (hac_isnull) +        memset (&melt->h_age_commitment, 0, sizeof(melt->h_age_commitment)); +      }      tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);      tl->next = chc->head; diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 20b9ff30..a49b9eb5 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -2419,6 +2419,7 @@ TALER_wallet_deposit_verify (   * @param melt_fee the melt fee we expect to pay   * @param rc refresh session we are committed to   * @param h_denom_pub hash of the coin denomination's public key + * @param h_age_commitment hash of the age commitment (may be NULL)   * @param coin_priv coin’s private key   * @param[out] coin_sig set to the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_MELT   */ @@ -2428,6 +2429,7 @@ TALER_wallet_melt_sign (    const struct TALER_Amount *melt_fee,    const struct TALER_RefreshCommitmentP *rc,    const struct TALER_DenominationHashP *h_denom_pub, +  const struct TALER_AgeCommitmentHash *h_age_commitment,    const struct TALER_CoinSpendPrivateKeyP *coin_priv,    struct TALER_CoinSpendSignatureP *coin_sig); @@ -3346,7 +3348,7 @@ TALER_age_commitment_hash (   *   * @param mask The age mask the defines the age groups   * @param age The actual age for which an age commitment is generated - * @param seed The seed that goes into the key generation.  MUST be choosen uniformly random. + * @param salt The salt that goes into the key generation.  MUST be choosen uniformly random.   * @param commitment[out] The generated age commitment, ->priv and ->pub allocated via GNUNET_malloc on success   * @return GNUNET_OK on success, GNUNET_SYSERR otherwise   */ @@ -3354,21 +3356,21 @@ enum GNUNET_GenericReturnValue  TALER_age_restriction_commit (    const struct TALER_AgeMask *mask,    const uint8_t age, -  const uint32_t seed, +  const uint64_t salt,    struct TALER_AgeCommitment *commitment);  /*   * @brief Derives another, equivalent age commitment for a given one.   *   * @param orig Original age commitment - * @param seed Used to move the points on the elliptic curve in order to generate another, equivalent commitment. + * @param salt Salt to randomly move the points on the elliptic curve in order to generate another, equivalent commitment.   * @param derived[out] The resulting age commitment, ->priv and ->pub allocated via GNUNET_malloc on success.   * @return GNUNET_OK on success, GNUNET_SYSERR otherwise   */  enum GNUNET_GenericReturnValue  TALER_age_commitment_derive (    const struct TALER_AgeCommitment *orig, -  const uint32_t seed, +  const uint64_t salt,    struct TALER_AgeCommitment *derived);  /* diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 92e841ef..fcb0ab7f 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -1682,9 +1682,11 @@ struct TALER_EXCHANGE_RefreshData    struct TALER_CoinSpendPrivateKeyP melt_priv;    /* -   * age commitment that went into the original coin, might be NULL +   * age commitment and its hash that went into the original coin, might be +   * NULL     */ -  struct TALER_AgeCommitment *age_commitment; +  struct TALER_AgeCommitment *melt_age_commitment; +  struct TALER_AgeCommitmentHash *melt_h_age_commitment;    /**     * amount specifying how much the coin will contribute to the melt @@ -1998,6 +2000,12 @@ struct TALER_EXCHANGE_LinkedCoinInfo    struct TALER_CoinSpendPrivateKeyP coin_priv;    /** +   * Age commitment and its hash, if applicable.  Might be NULL. +   */ +  struct TALER_AgeCommitment *age_commitment; +  struct TALER_AgeCommitmentHash *h_age_commitment; + +  /**     * Master secret of this coin.     */    struct TALER_PlanchetMasterSecretP ps; diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 10ab1ac9..529d4943 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -309,6 +309,7 @@ struct TALER_EXCHANGEDB_TableData        struct TALER_CoinSpendPublicKeyP old_coin_pub;        struct TALER_CoinSpendSignatureP old_coin_sig;        struct TALER_Amount amount_with_fee; +      struct TALER_AgeCommitmentHash h_age_commitment;        uint32_t noreveal_index;      } refresh_commitments; @@ -1269,13 +1270,6 @@ struct TALER_EXCHANGEDB_Refresh    struct TALER_CoinSpendSignatureP coin_sig;    /** -   * Hash of the age commitment used to sign the coin, if age restriction was -   * applicable to the denomination.  May be all zeroes if no age restriction -   * applies. -   */ -  struct TALER_AgeCommitmentHash h_age_commitment; - -  /**     * Refresh commitment this coin is melted into.     */    struct TALER_RefreshCommitmentP rc; diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index 17e00a81..b7a43bbc 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -585,24 +585,20 @@ TALER_EXCHANGE_verify_coin_history (          }        } -      { -        const struct TALER_AgeCommitmentHash *ahc = &h_age_commitment; - -        if (TALER_AgeCommitmentHash_isNullOrZero (ahc)) -          ahc = NULL; -        if (GNUNET_OK != -            TALER_wallet_melt_verify (&amount, -                                      &fee, -                                      &rc, -                                      h_denom_pub, -                                      ahc, -                                      coin_pub, -                                      &sig)) -        { -          GNUNET_break_op (0); -          return GNUNET_SYSERR; -        } +      if (GNUNET_OK != +          TALER_wallet_melt_verify ( +            &amount, +            &fee, +            &rc, +            h_denom_pub, +            TALER_AgeCommitmentHash_isNullOrZero (&h_age_commitment) ? +            NULL : &h_age_commitment, +            coin_pub, +            &sig)) +      { +        GNUNET_break_op (0); +        return GNUNET_SYSERR;        }        add = GNUNET_YES;      } diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c index 902f2b42..ac3fecdd 100644 --- a/src/lib/exchange_api_link.c +++ b/src/lib/exchange_api_link.c @@ -67,7 +67,8 @@ struct TALER_EXCHANGE_LinkHandle    struct TALER_CoinSpendPrivateKeyP coin_priv;    /** -   * Age commitment of the coin, might be NULL, required to re-generate age commitments +   * Age commitment of the original coin, might be NULL. +   * Required to derive the new age commitment     */    const struct TALER_AgeCommitment *age_commitment; @@ -118,7 +119,6 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,    struct TALER_TransferSecretP secret;    struct TALER_PlanchetDetail pd;    struct TALER_CoinPubHashP c_hash; -  struct TALER_AgeCommitmentHash *hac = NULL;    /* parse reply */    memset (&nonce, @@ -145,28 +145,26 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,                                           &alg_values,                                           &bks); +  lci->age_commitment = NULL; +  lci->h_age_commitment = NULL; +    /* Derive the age commitment and calculate the hash */    if (NULL != lh->age_commitment)    { -    struct TALER_AgeCommitment nac = {0}; -    struct TALER_AgeCommitmentHash h = {0}; -    uint32_t seed  = secret.key.bits[0]; +    uint64_t seed  = (uint64_t) secret.key.bits[0] +                     | (uint64_t) secret.key.bits[1] << 32; +    lci->age_commitment = GNUNET_new (struct TALER_AgeCommitment); +    lci->h_age_commitment = GNUNET_new (struct TALER_AgeCommitmentHash); -    if (GNUNET_OK != -        TALER_age_commitment_derive ( -          lh->age_commitment, -          seed, -          &nac)) -    { -      GNUNET_break_op (0); -      return GNUNET_SYSERR; -    } +    GNUNET_assert (GNUNET_OK == +                   TALER_age_commitment_derive ( +                     lh->age_commitment, +                     seed, +                     lci->age_commitment));      TALER_age_commitment_hash ( -      &nac, -      &h); - -    hac = &h; +      lci->age_commitment, +      lci->h_age_commitment);    }    if (GNUNET_OK != @@ -174,7 +172,7 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,                                &alg_values,                                &bks,                                &lci->coin_priv, -                              hac, +                              lci->h_age_commitment,                                &c_hash,                                &pd))    { diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c index f7f77027..dbe77c7e 100644 --- a/src/lib/exchange_api_melt.c +++ b/src/lib/exchange_api_melt.c @@ -478,6 +478,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)                            &mh->md.melted_coin.fee_melt,                            &mh->md.rc,                            &h_denom_pub, +                          mh->md.melted_coin.h_age_commitment,                            &mh->md.melted_coin.coin_priv,                            &confirm_sig);    GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv, @@ -494,6 +495,12 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)      GNUNET_JSON_pack_data_auto ("rc",                                  &mh->md.rc),      GNUNET_JSON_pack_allow_null ( +      mh->md.melted_coin.h_age_commitment +       ? GNUNET_JSON_pack_data_auto ("age_commitment_hash", +                                     mh->md.melted_coin.h_age_commitment) +       : GNUNET_JSON_pack_string ("age_commitment_hash", +                                  NULL)), +    GNUNET_JSON_pack_allow_null (        mh->send_rms         ? GNUNET_JSON_pack_data_auto ("rms",                                       &mh->rms) diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c index 8e9e8da3..997d1fec 100644 --- a/src/lib/exchange_api_refresh_common.c +++ b/src/lib/exchange_api_refresh_common.c @@ -78,7 +78,8 @@ TALER_EXCHANGE_get_melt_data_ (    md->melted_coin.fee_melt = rd->melt_pk.fees.refresh;    md->melted_coin.original_value = rd->melt_pk.value;    md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit; -  md->melted_coin.age_commitment = rd->age_commitment; +  md->melted_coin.age_commitment = rd->melt_age_commitment; +  md->melted_coin.h_age_commitment = rd->melt_h_age_commitment;    GNUNET_assert (GNUNET_OK ==                   TALER_amount_set_zero (rd->melt_amount.currency, @@ -184,29 +185,23 @@ TALER_EXCHANGE_get_melt_data_ (        /* Handle age commitment, if present */        if (NULL != md->melted_coin.age_commitment)        { -        struct TALER_AgeCommitment new_ac; -        struct TALER_AgeCommitmentHash hac; - -        /* We use the first 4 bytes of the trans_sec to generate a new age +        /* We use the first 8 bytes of the trans_sec to generate a new age           * commitment */ -        uint32_t age_seed = trans_sec.key.bits[0]; - -        if (GNUNET_OK != -            TALER_age_commitment_derive ( -              md->melted_coin.age_commitment, -              age_seed + j, -              &new_ac)) -        { -          GNUNET_break_op (0); -          TALER_EXCHANGE_free_melt_data_ (md); -          return GNUNET_SYSERR; -        } +        uint64_t age_seed = (uint64_t) trans_sec.key.bits[0] +                            | (uint64_t) trans_sec.key.bits[1] << 32; -        TALER_age_commitment_hash ( -          &new_ac, -          &hac); +        fcd->age_commitment[i] = GNUNET_new (struct TALER_AgeCommitment); +        ach = GNUNET_new (struct TALER_AgeCommitmentHash); + +        GNUNET_assert (GNUNET_OK == +                       TALER_age_commitment_derive ( +                         md->melted_coin.age_commitment, +                         age_seed, +                         fcd->age_commitment[i])); -        ach = &hac; +        TALER_age_commitment_hash ( +          fcd->age_commitment[i], +          ach);        }        if (TALER_DENOMINATION_CS == alg_values[j].cipher) @@ -225,7 +220,6 @@ TALER_EXCHANGE_get_melt_data_ (          TALER_EXCHANGE_free_melt_data_ (md);          return GNUNET_SYSERR;        } -        rcd->blinded_planchet = pd.blinded_planchet;        rcd->dk = &fcd->fresh_pk;      } diff --git a/src/lib/exchange_api_refresh_common.h b/src/lib/exchange_api_refresh_common.h index a3c3e2c0..8d7eb282 100644 --- a/src/lib/exchange_api_refresh_common.h +++ b/src/lib/exchange_api_refresh_common.h @@ -56,8 +56,8 @@ struct MeltedCoin     * The original age commitment and its hash.  MUST be NULL if no age     * commitment was set.     */ -  struct TALER_AgeCommitment *age_commitment; -  struct TALER_AgeCommitmentHash *h_age_commitment; +  const struct TALER_AgeCommitment *age_commitment; +  const struct TALER_AgeCommitmentHash *h_age_commitment;    /**     * Timestamp indicating when coins of this denomination become invalid. diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c index 461432db..881c7e73 100644 --- a/src/lib/exchange_api_refreshes_reveal.c +++ b/src/lib/exchange_api_refreshes_reveal.c @@ -336,6 +336,7 @@ TALER_EXCHANGE_refreshes_reveal (    json_t *coin_evs;    json_t *reveal_obj;    json_t *link_sigs; +  json_t *old_age_commitment = NULL;    CURL *eh;    struct GNUNET_CURL_Context *ctx;    struct MeltData md; @@ -427,6 +428,22 @@ TALER_EXCHANGE_refreshes_reveal (                                              &md.transfer_priv[j])));    } +  /* build array of old age commitment, if applicable */ +  GNUNET_assert ((NULL == rd->melt_age_commitment) == +                 (NULL == rd->melt_h_age_commitment)); +  if (NULL != rd->melt_age_commitment) +  { +    GNUNET_assert (NULL != (old_age_commitment = json_array ())); + +    for (size_t i = 0; i < rd->melt_age_commitment->num_pub; i++) +    { +      GNUNET_assert (0 == +                     json_array_append_new (old_age_commitment, +                                            GNUNET_JSON_from_data_auto ( +                                              &rd->melt_age_commitment->pub[i]))); +    } +  } +    /* build main JSON request */    reveal_obj = GNUNET_JSON_PACK (      GNUNET_JSON_pack_data_auto ("transfer_pub", @@ -437,6 +454,9 @@ TALER_EXCHANGE_refreshes_reveal (                                      rms)        : GNUNET_JSON_pack_string ("rms",                                   NULL)), +    GNUNET_JSON_pack_allow_null ( +      GNUNET_JSON_pack_array_steal ("old_age_commitment", +                                    old_age_commitment)),      GNUNET_JSON_pack_array_steal ("transfer_privs",                                    transfer_privs),      GNUNET_JSON_pack_array_steal ("link_sigs", @@ -480,6 +500,7 @@ TALER_EXCHANGE_refreshes_reveal (      GNUNET_free (rrh);      return NULL;    } +    eh = TALER_EXCHANGE_curl_easy_get_ (rrh->url);    if ( (NULL == eh) ||         (GNUNET_OK != diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c index 957e42e8..b6dd39c8 100644 --- a/src/testing/test_exchange_api.c +++ b/src/testing/test_exchange_api.c @@ -377,9 +377,9 @@ run (void *cls,       * Move money to the exchange's bank account.       */      CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age", -                              "EUR:5.01"), +                              "EUR:6.01"),      TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age", -                                                 "EUR:5.01", +                                                 "EUR:6.01",                                                   bc.user42_payto,                                                   bc.exchange_payto,                                                   "create-reserve-age"), @@ -475,7 +475,22 @@ run (void *cls,                                             "EUR:0.98",                                             bc.exchange_payto,                                             bc.user42_payto), -    TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c", +    TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c3", +                                           ec.exchange_url, +                                           "EUR:0.98", +                                           bc.exchange_payto, +                                           bc.user42_payto), +    TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c4", +                                           ec.exchange_url, +                                           "EUR:0.98", +                                           bc.exchange_payto, +                                           bc.user42_payto), +    TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-08c", +                                           ec.exchange_url, +                                           "EUR:0.08", +                                           bc.exchange_payto, +                                           bc.user43_payto), +    TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-08c2",                                             ec.exchange_url,                                             "EUR:0.08",                                             bc.exchange_payto, @@ -548,6 +563,104 @@ run (void *cls,      TALER_TESTING_cmd_end ()    }; +  struct TALER_TESTING_Command refresh_age[] = { +    /* Fill reserve with EUR:5, 1ct is for fees. */ +    CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-age-1", +                              "EUR:6.01"), +    TALER_TESTING_cmd_check_bank_admin_transfer ( +      "ck-refresh-create-reserve-age-1", +      "EUR:6.01", +      bc.user42_payto, +      bc.exchange_payto, +      "refresh-create-reserve-age-1"), +    /** +     * Make previous command effective. +     */ +    CMD_EXEC_WIREWATCH ("wirewatch-age-2"), +    /** +     * Withdraw EUR:7 with age restriction for age 13. +     */ +    TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-age-1", +                                       "refresh-create-reserve-age-1", +                                       "EUR:5", +                                       13, +                                       MHD_HTTP_OK), +    /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin +     * (in full) (merchant would receive EUR:0.99 due to 1 ct +     * deposit fee) */// +    TALER_TESTING_cmd_deposit ("refresh-deposit-partial-age", +                               "refresh-withdraw-coin-age-1", +                               0, +                               bc.user42_payto, +                               "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", +                               GNUNET_TIME_UNIT_ZERO, +                               "EUR:1", +                               MHD_HTTP_OK), +    /** +     * Melt the rest of the coin's value +     * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ +    TALER_TESTING_cmd_melt_double ("refresh-melt-age-1", +                                   "refresh-withdraw-coin-age-1", +                                   MHD_HTTP_OK, +                                   NULL), +    /** +     * Complete (successful) melt operation, and +     * withdraw the coins +     */ +    TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1", +                                      "refresh-melt-age-1", +                                      MHD_HTTP_OK), +    /** +     * Do it again to check idempotency +     */ +    TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1-idempotency", +                                      "refresh-melt-age-1", +                                      MHD_HTTP_OK), +    /** +     * Test that /refresh/link works +     */ +    TALER_TESTING_cmd_refresh_link ("refresh-link-age-1", +                                    "refresh-reveal-age-1", +                                    MHD_HTTP_OK), +    /** +     * Try to spend a refreshed EUR:1 coin +     */ +    TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1a", +                               "refresh-reveal-age-1-idempotency", +                               0, +                               bc.user42_payto, +                               "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", +                               GNUNET_TIME_UNIT_ZERO, +                               "EUR:1", +                               MHD_HTTP_OK), +    /** +     * Try to spend a refreshed EUR:0.1 coin +     */ +    TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1b", +                               "refresh-reveal-age-1", +                               3, +                               bc.user43_payto, +                               "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", +                               GNUNET_TIME_UNIT_ZERO, +                               "EUR:0.1", +                               MHD_HTTP_OK), +#if 0 /* FIXME oec */ +    /* Test running a failing melt operation (same operation +     * again must fail) */ +    TALER_TESTING_cmd_melt ("refresh-melt-failing-age", +                            "refresh-withdraw-coin-age-1", +                            MHD_HTTP_CONFLICT, +                            NULL), +    /* Test running a failing melt operation (on a coin that +       was itself revealed and subsequently deposited) */ +    TALER_TESTING_cmd_melt ("refresh-melt-failing-age-2", +                            "refresh-reveal-age-1", +                            MHD_HTTP_CONFLICT, +                            NULL), + +#endif +    TALER_TESTING_cmd_end () +  };    /**     * This block exercises the aggretation logic by making two payments @@ -1073,6 +1186,8 @@ run (void *cls,                                 withdraw_age),        TALER_TESTING_cmd_batch ("spend-age",                                 spend_age), +      TALER_TESTING_cmd_batch ("refresh-age", +                               refresh_age),        TALER_TESTING_cmd_batch ("track",                                 track),        TALER_TESTING_cmd_batch ("unaggregation", diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c index a241c531..ad1315b2 100644 --- a/src/testing/testing_api_cmd_deposit.c +++ b/src/testing/testing_api_cmd_deposit.c @@ -568,23 +568,23 @@ deposit_traits (void *cls,      struct TALER_TESTING_Trait traits[] = {        /* First two traits are only available if           ds->traits is #GNUNET_YES */ -      TALER_TESTING_make_trait_exchange_pub (0, &ds->exchange_pub), -      TALER_TESTING_make_trait_exchange_sig (0, &ds->exchange_sig), +      TALER_TESTING_make_trait_exchange_pub (index, &ds->exchange_pub), +      TALER_TESTING_make_trait_exchange_sig (index, &ds->exchange_sig),        /* These traits are always available */ -      TALER_TESTING_make_trait_coin_priv (0, +      TALER_TESTING_make_trait_coin_priv (index,                                            coin_spent_priv), -      TALER_TESTING_make_trait_age_commitment (0, +      TALER_TESTING_make_trait_age_commitment (index,                                                 age_commitment),        TALER_TESTING_make_trait_wire_details (ds->wire_details),        TALER_TESTING_make_trait_contract_terms (ds->contract_terms),        TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv),        TALER_TESTING_make_trait_deposit_amount (&ds->amount),        TALER_TESTING_make_trait_deposit_fee_amount (&ds->deposit_fee), -      TALER_TESTING_make_trait_timestamp (0, +      TALER_TESTING_make_trait_timestamp (index,                                            &ds->exchange_timestamp), -      TALER_TESTING_make_trait_wire_deadline (0, +      TALER_TESTING_make_trait_wire_deadline (index,                                                &ds->wire_deadline), -      TALER_TESTING_make_trait_refund_deadline (0, +      TALER_TESTING_make_trait_refund_deadline (index,                                                  &ds->refund_deadline),        TALER_TESTING_trait_end ()      }; diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c index 29ad9d2f..f287681d 100644 --- a/src/testing/testing_api_cmd_refresh.c +++ b/src/testing/testing_api_cmd_refresh.c @@ -71,9 +71,10 @@ struct TALER_TESTING_FreshCoinData    struct TALER_CoinSpendPrivateKeyP coin_priv;    /* -   * Age commitment for the coin, NULL if not applicable. +   * Fresh age commitment for the coin and its hash, NULL if not applicable.     */    struct TALER_AgeCommitment *age_commitment; +  struct TALER_AgeCommitmentHash *h_age_commitment;    /**     * The blinding key (needed for recoup operations). @@ -137,11 +138,6 @@ struct RefreshMeltState     */    const struct TALER_CoinSpendPrivateKeyP *melt_priv; -  /* -   * Age commitment for the coin, NULL if not applicable. -   */ -  struct TALER_AgeCommitment *age_commitment; -    /**     * Task scheduled to try later.     */ @@ -445,6 +441,8 @@ reveal_cb (void *cls,          return;        }        fc->coin_priv = coin->coin_priv; +      fc->age_commitment = coin->age_commitment; +      fc->h_age_commitment = coin->h_age_commitment;        TALER_denom_sig_deep_copy (&fc->sig,                                   &coin->sig); @@ -836,7 +834,7 @@ refresh_link_run (void *cls,    /* finally, use private key from withdraw sign command */    rls->rlh = TALER_EXCHANGE_link (is->exchange,                                    coin_priv, -                                  rms->age_commitment, +                                  rms->refresh_data.melt_age_commitment,                                    &link_cb,                                    rls); @@ -1046,6 +1044,8 @@ melt_run (void *cls,    {      struct TALER_Amount melt_amount;      struct TALER_Amount fresh_amount; +    struct TALER_AgeCommitment *age_commitment; +    struct TALER_AgeCommitmentHash *h_age_commitment;      const struct TALER_DenominationSignature *melt_sig;      const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;      const struct TALER_TESTING_Command *coin_command; @@ -1070,10 +1070,21 @@ melt_run (void *cls,        TALER_TESTING_interpreter_fail (rms->is);        return;      } +      if (GNUNET_OK !=          TALER_TESTING_get_trait_age_commitment (coin_command,                                                  0, -                                                &rms->age_commitment)) +                                                &age_commitment)) +    { +      GNUNET_break (0); +      TALER_TESTING_interpreter_fail (rms->is); +      return; +    } + +    if (GNUNET_OK != +        TALER_TESTING_get_trait_h_age_commitment (coin_command, +                                                  0, +                                                  &h_age_commitment))      {        GNUNET_break (0);        TALER_TESTING_interpreter_fail (rms->is); @@ -1148,31 +1159,13 @@ melt_run (void *cls,      rms->refresh_data.melt_amount = melt_amount;      rms->refresh_data.melt_sig = *melt_sig;      rms->refresh_data.melt_pk = *melt_denom_pub; +    rms->refresh_data.melt_age_commitment = age_commitment; +    rms->refresh_data.melt_h_age_commitment = h_age_commitment;      rms->refresh_data.fresh_pks = rms->fresh_pks;      rms->refresh_data.fresh_pks_len = num_fresh_coins; -    rms->refresh_data.age_commitment = NULL;      GNUNET_assert (age_restricted == -                   (NULL != rms->age_commitment)); - -    if (NULL != rms->age_commitment) -    { -      struct TALER_AgeCommitment *ac; -      uint32_t seed; - -      ac = GNUNET_new (struct TALER_AgeCommitment); -      seed  = GNUNET_CRYPTO_random_u32 ( -        GNUNET_CRYPTO_QUALITY_WEAK, -        UINT32_MAX); - -      GNUNET_assert (GNUNET_OK == -                     TALER_age_commitment_derive ( -                       rms->age_commitment, -                       seed, -                       ac)); - -      rms->refresh_data.age_commitment = ac; -    } +                   (NULL != age_commitment));      rms->rmh = TALER_EXCHANGE_melt (is->exchange,                                      &rms->rms, @@ -1256,10 +1249,14 @@ melt_traits (void *cls,      struct TALER_TESTING_Trait traits[] = {        TALER_TESTING_make_trait_denom_pub (index,                                            &rms->fresh_pks[index]), -      TALER_TESTING_make_trait_coin_priv (0, +      TALER_TESTING_make_trait_coin_priv (index,                                            rms->melt_priv), -      TALER_TESTING_make_trait_age_commitment (index, -                                               rms->age_commitment), +      TALER_TESTING_make_trait_age_commitment ( +        index, +        rms->refresh_data.melt_age_commitment), +      TALER_TESTING_make_trait_h_age_commitment ( +        index, +        rms->refresh_data.melt_h_age_commitment),        TALER_TESTING_make_trait_exchange_wd_value (index,                                                    &rms->mbds[index].alg_value),        TALER_TESTING_make_trait_refresh_secret (&rms->rms), @@ -1418,6 +1415,7 @@ refresh_reveal_traits (void *cls,    if (index >= rrs->num_fresh_coins)      return GNUNET_SYSERR; +    {      struct TALER_TESTING_Trait traits[] = {        TALER_TESTING_make_trait_coin_priv ( @@ -1426,6 +1424,9 @@ refresh_reveal_traits (void *cls,        TALER_TESTING_make_trait_age_commitment (          index,          rrs->fresh_coins[index].age_commitment), +      TALER_TESTING_make_trait_h_age_commitment ( +        index, +        rrs->fresh_coins[index].h_age_commitment),        TALER_TESTING_make_trait_denom_pub (          index,          rrs->fresh_coins[index].pk), @@ -1443,7 +1444,6 @@ refresh_reveal_traits (void *cls,                                                   &rrs->psa[index]),        TALER_TESTING_trait_end ()      }; -      return TALER_TESTING_get_trait (traits,                                      ret,                                      trait, diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c index 14015c49..3974a105 100644 --- a/src/testing/testing_api_cmd_withdraw.c +++ b/src/testing/testing_api_cmd_withdraw.c @@ -526,7 +526,7 @@ withdraw_cleanup (void *cls,    }    if (NULL != ws->age_commitment)    { -    GNUNET_free (ws->age_commitment); +    TALER_age_commitment_free (ws->age_commitment);      ws->age_commitment = NULL;    }    if (NULL != ws->h_age_commitment) @@ -569,7 +569,7 @@ withdraw_traits (void *cls,                                                  &ws->exchange_vals),      TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,                                          ws->pk), -    TALER_TESTING_make_trait_denom_sig (index /* only one coin */, +    TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,                                          &ws->sig),      TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv),      TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub), @@ -579,8 +579,8 @@ withdraw_traits (void *cls,        (const char **) &ws->reserve_payto_uri),      TALER_TESTING_make_trait_exchange_url (        (const char **) &ws->exchange_url), -    TALER_TESTING_make_trait_age_commitment (index, ws->age_commitment), -    TALER_TESTING_make_trait_h_age_commitment (index, ws->h_age_commitment), +    TALER_TESTING_make_trait_age_commitment (0, ws->age_commitment), +    TALER_TESTING_make_trait_h_age_commitment (0, ws->h_age_commitment),      TALER_TESTING_trait_end ()    }; @@ -626,7 +626,7 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,      ac = GNUNET_new (struct TALER_AgeCommitment);      hac = GNUNET_new (struct TALER_AgeCommitmentHash); -    seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); +    seed = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);      mask = TALER_extensions_age_restriction_ageMask ();      if (GNUNET_OK != diff --git a/src/util/crypto.c b/src/util/crypto.c index aced73f2..bf91b697 100644 --- a/src/util/crypto.c +++ b/src/util/crypto.c @@ -506,7 +506,7 @@ enum GNUNET_GenericReturnValue  TALER_age_restriction_commit (    const struct TALER_AgeMask *mask,    const uint8_t age, -  const uint32_t seed, +  const uint64_t salt,    struct TALER_AgeCommitment *new)  {    uint8_t num_pub = __builtin_popcount (mask->mask) - 1; @@ -517,6 +517,7 @@ TALER_age_restriction_commit (    GNUNET_assert (mask->mask & 1); /* fist bit must have been set */    GNUNET_assert (0 <= num_priv);    GNUNET_assert (31 > num_priv); +  GNUNET_assert (num_priv <= num_pub);    new->mask.mask = mask->mask;    new->num_pub = num_pub; @@ -529,32 +530,35 @@ TALER_age_restriction_commit (      num_priv,      struct TALER_AgeCommitmentPrivateKeyP); -  /* Create as many private keys as we need */ -  for (i = 0; i < num_priv; i++) +  /* Create as many private keys as we need and fill the rest of the +   * public keys with valid curve points. +   * We need to make sure that the public keys are proper points on the +   * elliptic curve, so we can't simply fill the struct with random values. */ +  for (i = 0; i < num_pub; i++)    { -    uint32_t seedBE = htonl (seed + i); +    uint64_t saltBE = htonl (salt + i); +    struct TALER_AgeCommitmentPrivateKeyP key = {0}; +    struct TALER_AgeCommitmentPrivateKeyP *priv = &key; + +    /* Only save the private keys for age groups less than num_priv */ +    if (i < num_priv) +      priv = &new->priv[i];      if  (GNUNET_OK != -         GNUNET_CRYPTO_kdf (&new->priv[i], -                            sizeof (new->priv[i]), -                            &seedBE, -                            sizeof (seedBE), +         GNUNET_CRYPTO_kdf (priv, +                            sizeof (*priv), +                            &saltBE, +                            sizeof (saltBE),                              "taler-age-commitment-derivation",                              strlen (                                "taler-age-commitment-derivation"),                              NULL, 0))        goto FAIL; -    GNUNET_CRYPTO_eddsa_key_get_public (&new->priv[i].eddsa_priv, +    GNUNET_CRYPTO_eddsa_key_get_public (&priv->eddsa_priv,                                          &new->pub[i].eddsa_pub);    } -  /* Fill the rest of the public keys with random values */ -  for (; i<num_pub; i++) -    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, -                                &new->pub[i], -                                sizeof(new->pub[i])); -    return GNUNET_OK;  FAIL: @@ -567,10 +571,24 @@ FAIL:  enum GNUNET_GenericReturnValue  TALER_age_commitment_derive (    const struct TALER_AgeCommitment *orig, -  const uint32_t seed, +  const uint64_t salt,    struct TALER_AgeCommitment *new)  { -  struct GNUNET_CRYPTO_EccScalar val; +  struct GNUNET_CRYPTO_EccScalar scalar; +  uint64_t saltBT = htonl (salt); +  int64_t factor; + +  GNUNET_assert (GNUNET_OK == +                 GNUNET_CRYPTO_kdf ( +                   &factor, +                   sizeof (factor), +                   &saltBT, +                   sizeof (saltBT), +                   "taler-age-restriction-derivation", +                   strlen ("taler-age-restriction-derivation"), +                   NULL, 0)); + +  GNUNET_CRYPTO_ecc_scalar_from_int (factor, &scalar);    /*    * age commitment consists of GNUNET_CRYPTO_Eddsa{Private,Public}Key @@ -584,7 +602,7 @@ TALER_age_commitment_derive (    * We want to multiply, both, the Private Key by an integer factor and the    * public key (point on curve) with the equivalent scalar.    * -  * From the seed we will derive +  * From the salt we will derive    *   1. a scalar to multiply the public keys with    *   2. a factor to multiply the private key with    * @@ -594,9 +612,9 @@ TALER_age_commitment_derive (    * A point on a curve is GNUNET_CRYPTO_EccPoint which is    *   unsigned char v[256 / 8];    * -  * A ECC scaler for use in point multiplications is a +  * A ECC scalar for use in point multiplications is a    * GNUNET_CRYPTO_EccScalar which is a -  *   unsigned car v[256 / 8]; +  *   unsigned char v[256 / 8];    * */    GNUNET_assert (NULL != new); @@ -613,9 +631,6 @@ TALER_age_commitment_derive (      new->num_priv,      struct TALER_AgeCommitmentPrivateKeyP); - -  GNUNET_CRYPTO_ecc_scalar_from_int (seed, &val); -    /* scalar multiply the public keys on the curve */    for (size_t i = 0; i < orig->num_pub; i++)    { @@ -627,7 +642,7 @@ TALER_age_commitment_derive (      if (GNUNET_OK !=          GNUNET_CRYPTO_ecc_pmul_mpi (            p, -          &val, +          &scalar,            np))        goto FAIL; @@ -636,47 +651,40 @@ TALER_age_commitment_derive (    /* multiply the private keys */    /* we borough ideas from GNUNET_CRYPTO_ecdsa_private_key_derive */    { -    uint32_t seedBE; -    uint8_t dc[32]; -    gcry_mpi_t f, x, d, n; -    gcry_ctx_t ctx; - -    GNUNET_assert (0==gcry_mpi_ec_new (&ctx,NULL, "Ed25519")); -    n = gcry_mpi_ec_get_mpi ("n", ctx, 1); - -    /* make the seed big endian */ -    seedBE = GNUNET_htonll (seed); - -    GNUNET_CRYPTO_mpi_scan_unsigned (&f, &seedBE, sizeof(seedBE)); -      for (size_t i = 0; i < orig->num_priv; i++)      { +      uint8_t dc[32]; +      gcry_mpi_t f, x, d, n; +      gcry_ctx_t ctx; + +      GNUNET_assert (0==gcry_mpi_ec_new (&ctx, NULL, "Ed25519")); +      n = gcry_mpi_ec_get_mpi ("n", ctx, 1); + +      GNUNET_CRYPTO_mpi_scan_unsigned (&f, (unsigned char*) &factor, +                                       sizeof(factor)); -      /* convert to big endian for libgrypt */        for (size_t j = 0; j < 32; j++)          dc[i] = orig->priv[i].eddsa_priv.d[31 - j];        GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));        d = gcry_mpi_new (256);        gcry_mpi_mulm (d, f, x, n); -      gcry_mpi_release (x); -      gcry_mpi_release (d); -      gcry_mpi_release (n); -      gcry_mpi_release (d);        GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);        for (size_t j = 0; j <32; j++)          new->priv[i].eddsa_priv.d[j] = dc[31 - 1];        sodium_memzero (dc, sizeof(dc)); +      gcry_mpi_release (d); +      gcry_mpi_release (x); +      gcry_mpi_release (n); +      gcry_mpi_release (f); +      gcry_ctx_release (ctx); -      /* TODO: -       * make sure that the calculated private key generate the same public -       * keys */ +      /* TODO: add test to make sure that the calculated private key generate +       * the same public keys */      } -    gcry_mpi_release (f); -    gcry_ctx_release (ctx);    }    return GNUNET_OK; diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c index a21c73be..7d07c9e7 100644 --- a/src/util/wallet_signatures.c +++ b/src/util/wallet_signatures.c @@ -249,6 +249,7 @@ TALER_wallet_melt_sign (    const struct TALER_Amount *melt_fee,    const struct TALER_RefreshCommitmentP *rc,    const struct TALER_DenominationHashP *h_denom_pub, +  const struct TALER_AgeCommitmentHash *h_age_commitment,    const struct TALER_CoinSpendPrivateKeyP *coin_priv,    struct TALER_CoinSpendSignatureP *coin_sig)  { @@ -256,9 +257,14 @@ TALER_wallet_melt_sign (      .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT),      .purpose.size = htonl (sizeof (melt)),      .rc = *rc, -    .h_denom_pub = *h_denom_pub +    .h_denom_pub = *h_denom_pub, +    .h_age_commitment = {{{0}}},    }; +  if (NULL != h_age_commitment) +    melt.h_age_commitment = *h_age_commitment; + +    TALER_amount_hton (&melt.amount_with_fee,                       amount_with_fee);    TALER_amount_hton (&melt.melt_fee, | 
