[age restriction] progress 16/n - refresh/reveal/link tests

Age restriction works now with withdraw, melt/refresh/reveal and link,
including tests.

However, there is still a problem with the tests:  The melting operation
"refresh-melt-failing-age" that should fail (because of conflict), but
currently fails for other reasons.  I decided to disable that particular
test (and the next) and submit the patch I have so far.
This commit is contained in:
Özgür Kesim 2022-02-22 14:27:15 +01:00
parent 0141a82161
commit 26158fc725
Signed by: oec
GPG Key ID: 3D76A56D79EDD9D7
21 changed files with 380 additions and 210 deletions

View File

@ -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 (

View File

@ -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;

View File

@ -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",

View File

@ -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;

View File

@ -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
};

View File

@ -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;

View File

@ -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 coins 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);
/*

View File

@ -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
@ -1997,6 +1999,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.
*/

View File

@ -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;
@ -1268,13 +1269,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.
*/

View File

@ -585,24 +585,20 @@ TALER_EXCHANGE_verify_coin_history (
}
}
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))
{
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;
}
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
add = GNUNET_YES;
}

View File

@ -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))
{

View File

@ -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,
@ -493,6 +494,12 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
&mh->md.melted_coin.melt_amount_with_fee),
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",

View File

@ -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];
uint64_t age_seed = (uint64_t) trans_sec.key.bits[0]
| (uint64_t) trans_sec.key.bits[1] << 32;
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;
}
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]));
TALER_age_commitment_hash (
&new_ac,
&hac);
ach = &hac;
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;
}

View File

@ -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.

View File

@ -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 !=

View File

@ -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",

View File

@ -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 ()
};

View File

@ -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,

View File

@ -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 !=

View File

@ -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;

View File

@ -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,