Compare commits

...

14 Commits

Author SHA1 Message Date
9c66f27034
WiP: age-withdraw, added TALER_age_restriction_commit_from_base, 6/n
Added TALER_age_restriction_commit_from_base in util/age_restriction.c,
to create a age commitment and proof from a coin's private key as
defined in
https://docs.taler.net/core/api-exchange.html#withdraw-with-age-restriction
2023-03-12 17:21:33 +01:00
777a4c07cf
Merge branch 'master' into age-withdraw 2023-03-11 11:51:02 +01:00
ce71db2c0b
be more explicit in systemd unit file 2023-03-10 12:18:56 +01:00
4931e30948
fix typo in comment 2023-03-10 00:45:12 +01:00
Christian Grothoff
9d5549d6ba
retry on failure 2023-03-09 19:48:29 +01:00
Christian Grothoff
74facbead4
add comments 2023-03-09 19:24:04 +01:00
MS
269425672c
typo 2023-03-09 18:02:28 +01:00
Christian Grothoff
90664b555c
log URL in error message (fixes #7725) 2023-03-08 12:04:33 +01:00
Christian Grothoff
890c962817
fix #7744 2023-03-08 12:01:07 +01:00
Christian Grothoff
21c9dae382
style fix 2023-03-08 11:52:56 +01:00
b7e20eb71e
-minor refactoring in age_withdraw-reveal 2023-03-06 21:37:32 +01:00
2d1583f96b
WiP: age-withdraw implementation, part 4/n
- check dates of denominations (expiry, etc.)
- refactor denomination checks into denomination_is_valid()
2023-03-06 21:24:45 +01:00
20cd46f63d
Merge branch 'age-withdraw' 2023-03-06 20:51:11 +01:00
Christian Grothoff
e2deb89a3d
-fix missing /home/grothoff for taler-exchange-offline user 2023-03-06 20:10:07 +01:00
11 changed files with 298 additions and 115 deletions

@ -1 +1 @@
Subproject commit 02132ededc12a0a1cfd81f0ca76c384304e15259 Subproject commit 1ec4596bf4925ee24fc06d3e74d2a553b8239870

View File

@ -8,11 +8,19 @@ PartOf=taler-exchange.target
[Service] [Service]
User=taler-exchange-httpd User=taler-exchange-httpd
Type=simple Type=simple
# Depending on the configuration, the service suicides and then
# needs to be restarted. # Depending on the configuration, the service process kills itself and then
# needs to be restarted. Thus no significant delay on restarts.
Restart=always Restart=always
# Do not dally on restarts.
RestartSec=1ms RestartSec=1ms
# Disable the service if more than 5 restarts are encountered within 5s.
# These are usually the systemd defaults, but can be overwritten, thus we set
# them here explicitly, as the exchange code assumes StartLimitInterval
# to be >=5s.
StartLimitBurst=5
StartLimitInterval=5s
ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf
StandardOutput=journal StandardOutput=journal
StandardError=journal StandardError=journal

View File

@ -248,12 +248,15 @@ TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx,
{ {
if ( (0 < num_results) && if ( (0 < num_results) &&
(! GNUNET_TIME_relative_is_zero (timeout)) ) (! GNUNET_TIME_relative_is_zero (timeout)) )
/* 0 == start_row is implied, go with timeout into future */
GNUNET_snprintf (url, GNUNET_snprintf (url,
sizeof (url), sizeof (url),
"history/incoming?delta=%lld&long_poll_ms=%llu", "history/incoming?delta=%lld&long_poll_ms=%llu",
(long long) num_results, (long long) num_results,
tms); tms);
else else
/* Going back from current transaction or have no timeout;
hence timeout makes no sense */
GNUNET_snprintf (url, GNUNET_snprintf (url,
sizeof (url), sizeof (url),
"history/incoming?delta=%lld", "history/incoming?delta=%lld",
@ -263,6 +266,7 @@ TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx,
{ {
if ( (0 < num_results) && if ( (0 < num_results) &&
(! GNUNET_TIME_relative_is_zero (timeout)) ) (! GNUNET_TIME_relative_is_zero (timeout)) )
/* going forward from num_result */
GNUNET_snprintf (url, GNUNET_snprintf (url,
sizeof (url), sizeof (url),
"history/incoming?delta=%lld&start=%llu&long_poll_ms=%llu", "history/incoming?delta=%lld&start=%llu&long_poll_ms=%llu",
@ -270,6 +274,8 @@ TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx,
(unsigned long long) start_row, (unsigned long long) start_row,
tms); tms);
else else
/* going backwards or have no timeout;
hence timeout makes no sense */
GNUNET_snprintf (url, GNUNET_snprintf (url,
sizeof (url), sizeof (url),
"history/incoming?delta=%lld&start=%llu", "history/incoming?delta=%lld&start=%llu",

View File

@ -80,6 +80,11 @@
*/ */
#define UNIX_BACKLOG 50 #define UNIX_BACKLOG 50
/**
* How often will we try to connect to the database before giving up?
*/
#define MAX_DB_RETRIES 5
/** /**
* Above what request latency do we start to log? * Above what request latency do we start to log?
*/ */
@ -1965,11 +1970,20 @@ exchange_serve_process_config (void)
GNUNET_free (attr_enc_key_str); GNUNET_free (attr_enc_key_str);
} }
if (NULL == for (unsigned int i = 0; i<MAX_DB_RETRIES; i++)
(TEH_plugin = TALER_EXCHANGEDB_plugin_load (TEH_cfg))) {
TEH_plugin = TALER_EXCHANGEDB_plugin_load (TEH_cfg);
if (NULL != TEH_plugin)
break;
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to connect to DB, will try again %u times\n",
MAX_DB_RETRIES - i);
sleep (1);
}
if (NULL == TEH_plugin)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to initialize DB subsystem\n"); "Failed to initialize DB subsystem. Giving up.\n");
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
return GNUNET_OK; return GNUNET_OK;

View File

@ -28,22 +28,6 @@
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keys.h" #include "taler-exchange-httpd_keys.h"
/**
* Clients have to prove that the public keys for all age groups larger than
* the allowed maximum age group are derived by scalar multiplication from this
* Edx25519 public key (in Crockford Base32 encoding):
*
* DZJRF6HXN520505XDAWM8NMH36QV9J3VH77265WQ09EBQ76QSKCG
*
* The private key was chosen randomly and then deleted.
*/
static struct GNUNET_CRYPTO_Edx25519PublicKey publishedBaseKey = {
.q_y = { 0x6f, 0xe5, 0x87, 0x9a, 0x3d, 0xa9, 0x44, 0x20,
0x80, 0xbd, 0x6a, 0xb9, 0x44, 0x56, 0x91, 0x19,
0xaf, 0xb4, 0xc8, 0x7b, 0x89, 0xce, 0x23, 0x17,
0x97, 0x20, 0x5c, 0xbb, 0x9c, 0xd7, 0xcc, 0xd9},
};
/** /**
* State for an /age-withdraw/$ACH/reveal operation. * State for an /age-withdraw/$ACH/reveal operation.
*/ */
@ -360,17 +344,15 @@ denomination_is_valid (
connection, connection,
result); result);
/* Does the denomination exist? */
if (NULL == dks) if (NULL == dks)
{ {
/* The denomination doesn't exist */
GNUNET_assert (result != NULL); GNUNET_assert (result != NULL);
/* Note: a HTTP-response has been queued and result has been set by /* Note: a HTTP-response has been queued and result has been set by
* TEH_keys_denominations_by_hash2 */ * TEH_keys_denominations_by_hash2 */
return false; return false;
} }
/* Is the denomation still and already valid? */
if (GNUNET_TIME_absolute_is_past (dks->meta.expire_withdraw.abs_time)) if (GNUNET_TIME_absolute_is_past (dks->meta.expire_withdraw.abs_time))
{ {
/* This denomination is past the expiration time for withdraws */ /* This denomination is past the expiration time for withdraws */
@ -582,6 +564,7 @@ verify_commitment_and_max_age (
for (uint32_t i = 0; i < num_coins; i++) for (uint32_t i = 0; i < num_coins; i++)
{ {
/* FIXME:oec: Calculate new coins and blinded hashes */ /* FIXME:oec: Calculate new coins and blinded hashes */
/*TALER_age_restriction_commit_from_base(); */
} }
return GNUNET_SYSERR; return GNUNET_SYSERR;

View File

@ -234,12 +234,10 @@ TEH_handler_csr_withdraw (struct TEH_RequestContext *rc,
.cipher = TALER_DENOMINATION_CS .cipher = TALER_DENOMINATION_CS
}; };
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed ("nonce", GNUNET_JSON_spec_fixed_auto ("nonce",
&nonce, &nonce),
sizeof (struct TALER_CsNonce)), GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
GNUNET_JSON_spec_fixed ("denom_pub_hash", &denom_pub_hash),
&denom_pub_hash,
sizeof (struct TALER_DenominationHashP)),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
struct TEH_DenominationKey *dk; struct TEH_DenominationKey *dk;
@ -333,17 +331,11 @@ TEH_handler_csr_withdraw (struct TEH_RequestContext *rc,
} }
} }
{ return TALER_MHD_REPLY_JSON_PACK (
json_t *csr_obj; rc->connection,
MHD_HTTP_OK,
csr_obj = GNUNET_JSON_PACK ( TALER_JSON_pack_exchange_withdraw_values ("ewv",
TALER_JSON_pack_exchange_withdraw_values ("ewv", &ewv));
&ewv));
GNUNET_assert (NULL != csr_obj);
return TALER_MHD_reply_json_steal (rc->connection,
csr_obj,
MHD_HTTP_OK);
}
} }

View File

@ -738,7 +738,7 @@ free_denom_cb (void *cls,
* @param value the `struct HelperSignkey` to release * @param value the `struct HelperSignkey` to release
* @return #GNUNET_OK (continue to iterate) * @return #GNUNET_OK (continue to iterate)
*/ */
static int static enum GNUNET_GenericReturnValue
free_esign_cb (void *cls, free_esign_cb (void *cls,
const struct GNUNET_PeerIdentity *pid, const struct GNUNET_PeerIdentity *pid,
void *value) void *value)
@ -3616,6 +3616,7 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) && if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) &&
(GNUNET_is_zero (&denom_cs_sm_pub)) ) (GNUNET_is_zero (&denom_cs_sm_pub)) )
{ {
/* Either IPC failed, or neither helper had any denominations configured. */
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_GATEWAY, MHD_HTTP_BAD_GATEWAY,
TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE, TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
@ -3628,7 +3629,6 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE, TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
NULL); NULL);
} }
// then a secmod helper is not yet running and we should return an MHD_HTTP_BAD_GATEWAY!
GNUNET_assert (NULL != fbc.denoms); GNUNET_assert (NULL != fbc.denoms);
GNUNET_assert (NULL != fbc.signkeys); GNUNET_assert (NULL != fbc.signkeys);
GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys, GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,

View File

@ -757,7 +757,7 @@ continue_with_shard (void *cls)
shard_end - latest_row_off); shard_end - latest_row_off);
GNUNET_assert (NULL == hh); GNUNET_assert (NULL == hh);
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Requesting credit history staring from %llu\n", "Requesting credit history starting from %llu\n",
(unsigned long long) latest_row_off); (unsigned long long) latest_row_off);
hh_start_time = GNUNET_TIME_absolute_get (); hh_start_time = GNUNET_TIME_absolute_get ();
hh_returned_data = false; hh_returned_data = false;

View File

@ -18,6 +18,7 @@
* @brief taler-specific crypto functions * @brief taler-specific crypto functions
* @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Christian Grothoff <christian@grothoff.org> * @author Christian Grothoff <christian@grothoff.org>
* @author Özgür Kesim <oec-taler@kesim.org>
*/ */
#if ! defined (__TALER_UTIL_LIB_H_INSIDE__) #if ! defined (__TALER_UTIL_LIB_H_INSIDE__)
#error "Only <taler_util.h> can be included directly." #error "Only <taler_util.h> can be included directly."
@ -5926,4 +5927,42 @@ void
TALER_age_commitment_proof_free ( TALER_age_commitment_proof_free (
struct TALER_AgeCommitmentProof *p); struct TALER_AgeCommitmentProof *p);
/**
* @brief For age-withdraw, clients have to prove that the public keys for all
* age groups larger than the allowed maximum age group are derived by scalar
* multiplication from this Edx25519 public key (in Crockford Base32 encoding):
*
* DZJRF6HXN520505XDAWM8NMH36QV9J3VH77265WQ09EBQ76QSKCG
*
* Its private key was chosen randomly and then deleted.
*/
extern struct
#ifndef AGE_RESTRICTION_WITH_ECDSA
GNUNET_CRYPTO_Edx25519PublicKey
#else
GNUNET_CRYPTO_EcdsaPublicKey
#endif
TALER_age_commitment_base_public_key;
/**
* @brief Similiar to TALER_age_restriction_commit, but takes the coin's
* private key as seed input and calculates the public keys in the slots larger
* than the given age as derived from TALER_age_commitment_base_public_key.
*
* See https://docs.taler.net/core/api-exchange.html#withdraw-with-age-restriction
*
* @param mask The age mask, defining the age groups
* @param max_age The maximum age for this coin.
* @param coin_priv The private key of the coin from which we derive the age restriction
* @param[out] comm_proof The commitment and proof for age restriction for age @a max_age
*/
enum GNUNET_GenericReturnValue
TALER_age_restriction_commit_from_base (
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
const struct TALER_AgeMask *mask,
uint8_t max_age,
struct TALER_AgeCommitmentProof *comm_proof);
#endif #endif

View File

@ -168,9 +168,10 @@ handle_reserves_get_finished (void *cls,
rs.hr.ec = TALER_JSON_get_error_code (j); rs.hr.ec = TALER_JSON_get_error_code (j);
rs.hr.hint = TALER_JSON_get_error_hint (j); rs.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for reserves get\n", "Unexpected response code %u/%d for GET %s\n",
(unsigned int) response_code, (unsigned int) response_code,
(int) rs.hr.ec); (int) rs.hr.ec,
rgh->url);
break; break;
} }
if (NULL != rgh->cb) if (NULL != rgh->cb)

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2022 Taler Systems SA Copyright (C) 2022-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software
@ -24,6 +24,19 @@
#include <gnunet/gnunet_json_lib.h> #include <gnunet/gnunet_json_lib.h>
#include <gcrypt.h> #include <gcrypt.h>
struct
#ifndef AGE_RESTRICTION_WITH_ECDSA
GNUNET_CRYPTO_Edx25519PublicKey
#else
GNUNET_CRYPTO_EcdsaPublicKey
#endif
TALER_age_commitment_base_public_key = {
.q_y = { 0x6f, 0xe5, 0x87, 0x9a, 0x3d, 0xa9, 0x44, 0x20,
0x80, 0xbd, 0x6a, 0xb9, 0x44, 0x56, 0x91, 0x19,
0xaf, 0xb4, 0xc8, 0x7b, 0x89, 0xce, 0x23, 0x17,
0x97, 0x20, 0x5c, 0xbb, 0x9c, 0xd7, 0xcc, 0xd9},
};
void void
TALER_age_commitment_hash ( TALER_age_commitment_hash (
const struct TALER_AgeCommitment *commitment, const struct TALER_AgeCommitment *commitment,
@ -82,36 +95,78 @@ get_age_group (
} }
#ifdef AGE_RESTRICTION_WITH_ECDSA
/* @brief Helper function to generate a ECDSA private key
*
* @param seed Input seed
* @param size Size of the seed in bytes
* @param[out] pkey ECDSA private key
* @return GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
ecdsa_create_from_seed (
const void *seed,
size_t seed_size,
struct GNUNET_CRYPTO_EcdsaPrivateKey *key)
{
enum GNUNET_GenericReturnValue ret;
ret = GNUNET_CRYPTO_kdf (key,
sizeof (*key),
&seed,
seed_size,
"age commitment",
sizeof ("age commitment") - 1,
NULL, 0);
if (GNUNET_OK != ret)
return ret;
/* See GNUNET_CRYPTO_ecdsa_key_create */
key->d[0] &= 248;
key->d[31] &= 127;
key->d[31] |= 64;
return GNUNET_OK;
}
#endif
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_age_restriction_commit ( TALER_age_restriction_commit (
const struct TALER_AgeMask *mask, const struct TALER_AgeMask *mask,
const uint8_t age, const uint8_t age,
const struct GNUNET_HashCode *seed, const struct GNUNET_HashCode *seed,
struct TALER_AgeCommitmentProof *new) struct TALER_AgeCommitmentProof *ncp)
{ {
struct GNUNET_HashCode seed_i; struct GNUNET_HashCode seed_i;
uint8_t num_pub = __builtin_popcount (mask->bits) - 1; uint8_t num_pub;
uint8_t num_priv = get_age_group (mask, age); uint8_t num_priv;
size_t i; size_t i;
GNUNET_assert (NULL != mask);
GNUNET_assert (NULL != seed); GNUNET_assert (NULL != seed);
GNUNET_assert (NULL != new); GNUNET_assert (NULL != ncp);
GNUNET_assert (mask->bits & 1); /* fist bit must have been set */ GNUNET_assert (mask->bits & 1); /* fist bit must have been set */
num_pub = __builtin_popcount (mask->bits) - 1;
num_priv = get_age_group (mask, age);
GNUNET_assert (31 > num_priv); GNUNET_assert (31 > num_priv);
GNUNET_assert (num_priv <= num_pub); GNUNET_assert (num_priv <= num_pub);
seed_i = *seed; seed_i = *seed;
new->commitment.mask.bits = mask->bits; ncp->commitment.mask.bits = mask->bits;
new->commitment.num = num_pub; ncp->commitment.num = num_pub;
new->proof.num = num_priv; ncp->proof.num = num_priv;
new->proof.keys = NULL; ncp->proof.keys = NULL;
new->commitment.keys = GNUNET_new_array ( ncp->commitment.keys = GNUNET_new_array (
num_pub, num_pub,
struct TALER_AgeCommitmentPublicKeyP); struct TALER_AgeCommitmentPublicKeyP);
if (0 < num_priv) if (0 < num_priv)
new->proof.keys = GNUNET_new_array ( ncp->proof.keys = GNUNET_new_array (
num_priv, num_priv,
struct TALER_AgeCommitmentPrivateKeyP); struct TALER_AgeCommitmentPrivateKeyP);
@ -126,47 +181,33 @@ TALER_age_restriction_commit (
/* Only save the private keys for age groups less than num_priv */ /* Only save the private keys for age groups less than num_priv */
if (i < num_priv) if (i < num_priv)
pkey = &new->proof.keys[i]; pkey = &ncp->proof.keys[i];
#ifndef AGE_RESTRICTION_WITH_ECDSA #ifndef AGE_RESTRICTION_WITH_ECDSA
GNUNET_CRYPTO_edx25519_key_create_from_seed (&seed_i, GNUNET_CRYPTO_edx25519_key_create_from_seed (&seed_i,
sizeof(seed_i), sizeof(seed_i),
&pkey->priv); &pkey->priv);
GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv, GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv,
&new->commitment.keys[i].pub); &ncp->commitment.keys[i].pub);
#else
if (GNUNET_OK !=
ecdsa_create_from_seed (&seed_i,
sizeof(seed_i),
&pkey->priv))
{
GNUNET_free (ncp->commitment.keys);
GNUNET_free (ncp->proof.keys);
return GNUNET_SYSERR;
}
GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv,
&ncp->commitment.keys[i].pub);
#endif
seed_i.bits[0] += 1; seed_i.bits[0] += 1;
} }
return GNUNET_OK; return GNUNET_OK;
#else
if (GNUNET_OK !=
GNUNET_CRYPTO_kdf (pkey,
sizeof (*pkey),
&salti,
sizeof (salti),
"age commitment",
strlen ("age commitment"),
NULL, 0))
goto FAIL;
/* See GNUNET_CRYPTO_ecdsa_key_create */
pkey->priv.d[0] &= 248;
pkey->priv.d[31] &= 127;
pkey->priv.d[31] |= 64;
GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv,
&new->commitment.keys[i].pub);
}
return GNUNET_OK;
FAIL:
GNUNET_free (new->commitment.keys);
if (NULL != new->proof.keys)
GNUNET_free (new->proof.keys);
return GNUNET_SYSERR;
#endif
} }
@ -216,33 +257,30 @@ TALER_age_commitment_derive (
&newacp->proof.keys[i].priv); &newacp->proof.keys[i].priv);
} }
#else #else
char label[sizeof(uint64_t) + 1] = {0};
/* Because GNUNET_CRYPTO_ecdsa_public_key_derive expects char * (and calls
* strlen on it), we must avoid 0's in the label. */
uint64_t nz_salt = salt | 0x8040201008040201;
memcpy (label, &nz_salt, sizeof(nz_salt));
/* 1. Derive the public keys */
for (size_t i = 0; i < orig->commitment.num; i++)
{ {
GNUNET_CRYPTO_ecdsa_public_key_derive ( const char *label = GNUNET_h2s (salt);
&orig->commitment.keys[i].pub,
label,
"age commitment derive",
&newacp->commitment.keys[i].pub);
}
/* 2. Derive the private keys */ /* 1. Derive the public keys */
for (size_t i = 0; i < orig->proof.num; i++) for (size_t i = 0; i < orig->commitment.num; i++)
{ {
struct GNUNET_CRYPTO_EcdsaPrivateKey *priv; GNUNET_CRYPTO_ecdsa_public_key_derive (
priv = GNUNET_CRYPTO_ecdsa_private_key_derive ( &orig->commitment.keys[i].pub,
&orig->proof.keys[i].priv, label,
label, "age commitment derive",
"age commitment derive"); &newacp->commitment.keys[i].pub);
newacp->proof.keys[i].priv = *priv; }
GNUNET_free (priv);
/* 2. Derive the private keys */
for (size_t i = 0; i < orig->proof.num; i++)
{
struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
priv = GNUNET_CRYPTO_ecdsa_private_key_derive (
&orig->proof.keys[i].priv,
label,
"age commitment derive");
newacp->proof.keys[i].priv = *priv;
GNUNET_free (priv);
}
} }
#endif #endif
@ -546,4 +584,106 @@ TALER_age_mask_to_string (
} }
enum GNUNET_GenericReturnValue
TALER_age_restriction_commit_from_base (
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
const struct TALER_AgeMask *mask,
uint8_t max_age,
struct TALER_AgeCommitmentProof *ncp)
{
struct GNUNET_HashCode seed_i = {0};
uint8_t num_pub;
uint8_t num_priv;
GNUNET_assert (NULL != mask);
GNUNET_assert (NULL != coin_priv);
GNUNET_assert (NULL != ncp);
GNUNET_assert (mask->bits & 1); /* fist bit must have been set */
num_pub = __builtin_popcount (mask->bits) - 1;
num_priv = get_age_group (mask, max_age);
GNUNET_assert (31 > num_priv);
GNUNET_assert (num_priv <= num_pub);
ncp->commitment.mask.bits = mask->bits;
ncp->commitment.num = num_pub;
ncp->proof.num = num_priv;
ncp->proof.keys = NULL;
ncp->commitment.keys = GNUNET_new_array (
num_pub,
struct TALER_AgeCommitmentPublicKeyP);
if (0 < num_priv)
ncp->proof.keys = GNUNET_new_array (
num_priv,
struct TALER_AgeCommitmentPrivateKeyP);
/* Create as many private keys as allow with max_age and derive the
* corresponding public keys. The rest of the needed public keys are created
* by scalar mulitplication with the TALER_age_commitment_base_public_key. */
for (size_t i = 0; i < num_pub; i++)
{
enum GNUNET_GenericReturnValue ret;
const char *label = i < num_priv ? "age-commitment" : "age-factor";
ret = GNUNET_CRYPTO_kdf (&seed_i, sizeof(seed_i),
coin_priv, sizeof(*coin_priv),
label, strlen (label),
&i, sizeof(i),
NULL, 0);
GNUNET_assert (GNUNET_OK == ret);
/* Only generate and save the private keys and public keys for age groups
* less than num_priv */
if (i < num_priv)
{
struct TALER_AgeCommitmentPrivateKeyP *pkey = &ncp->proof.keys[i];
#ifndef AGE_RESTRICTION_WITH_ECDSA
GNUNET_CRYPTO_edx25519_key_create_from_seed (&seed_i,
sizeof(seed_i),
&pkey->priv);
GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv,
&ncp->commitment.keys[i].pub);
#else
if (GNUNET_OK != ecdsa_create_from_seed (&seed_i,
sizeof(seed_i),
&pkey->priv))
{
GNUNET_free (ncp->commitment.keys);
GNUNET_free (ncp->proof.keys);
return GNUNET_SYSERR;
}
GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv,
&ncp->commitment.keys[i].pub);
#endif
}
else
{
/* For all indices larger than num_priv, derive a public key from
* TALER_age_commitment_base_public_key by scalar multiplication */
#ifndef AGE_RESTRICTION_WITH_ECDSA
GNUNET_CRYPTO_edx25519_public_key_derive (
&TALER_age_commitment_base_public_key,
&seed_i,
sizeof(seed_i),
&ncp->commitment.keys[i].pub);
#else
GNUNET_CRYPTO_ecdsa_public_key_derive (
&TALER_age_commitment_base_public_key,
GNUNET_h2s (&seed_i),
"age withdraw",
&ncp->commitment.keys[i].pub);
#endif
}
}
return GNUNET_OK;
}
/* end util/age_restriction.c */ /* end util/age_restriction.c */