TALER_age_restriction_{commit,derive} implemented
This commit is contained in:
parent
1b2fd76f94
commit
7b50b2d17c
@ -225,7 +225,7 @@ age_restriction_load_taler_config (
|
||||
if (GNUNET_OK == ret)
|
||||
{
|
||||
_config.mask.mask = mask.mask;
|
||||
_config.num_groups = __builtin_popcount (mask.mask);
|
||||
_config.num_groups = __builtin_popcount (mask.mask) - 1; /* no underflow, first bit always set */
|
||||
this->config = &_config;
|
||||
}
|
||||
|
||||
@ -258,9 +258,18 @@ age_restriction_load_json_config (
|
||||
if (TALER_Extension_AgeRestriction != this->type)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
|
||||
_config.mask.mask = mask.mask;
|
||||
_config.num_groups = __builtin_popcount (mask.mask);
|
||||
_config.num_groups = 0;
|
||||
|
||||
if (mask.mask > 0)
|
||||
{
|
||||
/* if the mask is not zero, the first bit MUST be set */
|
||||
if (0 == (mask.mask & 1))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
_config.num_groups = __builtin_popcount (mask.mask) - 1;
|
||||
}
|
||||
|
||||
this->config = &_config;
|
||||
|
||||
if (NULL != this->config_json)
|
||||
|
@ -2613,17 +2613,18 @@ struct TALER_AgeCommitment
|
||||
struct TALER_AgeMask mask;
|
||||
|
||||
/* The number of public keys, which must be the same as the number of
|
||||
* groups in the mask
|
||||
* groups in the mask.
|
||||
*/
|
||||
size_t num_pub_keys;
|
||||
size_t num_pub;
|
||||
|
||||
/* A NULL-terminated list of public keys.
|
||||
* The list must be exactly of length @a num_pub_keys, i. e. the same as the
|
||||
* number of age groups defined in the mask.
|
||||
/* The list of #num_pub public keys. In must have same size as the number of
|
||||
* age groups defined in the mask.
|
||||
*
|
||||
* A hash of this list is the hashed commitment that goes into FDC
|
||||
* calculation during the withdraw and refresh operations for new coins. That
|
||||
* way, the particular age commitment becomes mandatory and bound to a coin.
|
||||
*
|
||||
* The list has been allocated via GNUNET_malloc.
|
||||
*/
|
||||
struct TALER_AgeCommitmentPublicKeyP *pub;
|
||||
|
||||
@ -2631,31 +2632,19 @@ struct TALER_AgeCommitment
|
||||
* this number corresponds to the largest age group that is supported with
|
||||
* this age commitment.
|
||||
*/
|
||||
size_t num_priv_keys;
|
||||
size_t num_priv;
|
||||
|
||||
/* A NULL-terminated list of private keys.
|
||||
/* List of #num_priv private keys.
|
||||
*
|
||||
* Note that the list can be _smaller_ than the corresponding list of public
|
||||
* keys! In that case, the wallet can sign off only for a subset of the age
|
||||
* keys. In that case, the wallet can sign off only for a subset of the age
|
||||
* groups.
|
||||
*
|
||||
* The list has been allocated via GNUNET_malloc.
|
||||
*/
|
||||
struct TALER_AgeCommitmentPrivateKeyP *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Generates an age commitent for the given age.
|
||||
*
|
||||
* @param mask The age mask the defines the age groups
|
||||
* @param age The age for which an age commitment is generated
|
||||
* @param seed The seed that goes into the key generation. MUST be choosen uniformly random.
|
||||
* @param commitment[out] The generated age commitment, allocated via GNUNET_malloc
|
||||
*/
|
||||
void
|
||||
TALER_age_restriction_commit (
|
||||
const struct TALER_AgeMask *mask,
|
||||
const uint8_t age,
|
||||
const uint32_t seed,
|
||||
struct TALER_AgeCommitment *commitment);
|
||||
|
||||
/*
|
||||
* @brief Generates a hash of the public keys in the age commitment.
|
||||
*
|
||||
@ -2667,18 +2656,36 @@ TALER_age_commitment_hash (
|
||||
const struct TALER_AgeCommitment *commitment,
|
||||
struct TALER_AgeCommitmentHash *hash);
|
||||
|
||||
|
||||
/*
|
||||
* @brief Generates an age commitent for the given age.
|
||||
*
|
||||
* @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 commitment[out] The generated age commitment, allocated via GNUNET_malloc on success
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR otherwise
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_restriction_commit (
|
||||
const struct TALER_AgeMask *mask,
|
||||
const uint8_t age,
|
||||
const uint32_t seed,
|
||||
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 derived[out] The resulting age commitment, allocated via GNUNET_malloc.
|
||||
* @param derived[out] The resulting age commitment, allocated via GNUNET_malloc on success.
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR otherwise
|
||||
*/
|
||||
void
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_restriction_derive (
|
||||
const struct TALER_AgeCommitment *orig,
|
||||
const uint32_t seed,
|
||||
const struct TALER_AgeCommitment *derived);
|
||||
struct TALER_AgeCommitment **derived);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -381,12 +381,12 @@ TALER_age_commitment_hash (
|
||||
return;
|
||||
}
|
||||
|
||||
GNUNET_assert (__builtin_popcount (commitment->mask.mask) ==
|
||||
commitment->num_pub_keys);
|
||||
GNUNET_assert (__builtin_popcount (commitment->mask.mask) - 1 ==
|
||||
commitment->num_pub);
|
||||
|
||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||
|
||||
for (size_t i = 0; i < commitment->num_pub_keys; i++)
|
||||
for (size_t i = 0; i < commitment->num_pub; i++)
|
||||
{
|
||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||
&commitment->pub[i],
|
||||
@ -402,24 +402,215 @@ TALER_age_commitment_hash (
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_restriction_derive (
|
||||
const struct TALER_AgeCommitment *orig,
|
||||
const uint32_t seed,
|
||||
const struct TALER_AgeCommitment *derived)
|
||||
struct TALER_AgeCommitment **derived)
|
||||
{
|
||||
/* TODO oec */
|
||||
/*
|
||||
* age commitment consists of GNUNET_CRYPTO_Eddsa{Private,Public}Key
|
||||
*
|
||||
* GNUNET_CRYPTO_EddsaPrivateKey is a
|
||||
* unsigned char d[256 / 8];
|
||||
*
|
||||
* GNUNET_CRYPTO_EddsaPublicKey is a
|
||||
* unsigned char q_y[256 / 8];
|
||||
*
|
||||
* 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
|
||||
* 1. a scalar to multiply the public keys with
|
||||
* 2. a factor to multiply the private key with
|
||||
*
|
||||
* Invariants:
|
||||
* point*scalar == public(private*factor)
|
||||
*
|
||||
* 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
|
||||
* GNUNET_CRYPTO_EccScalar which is a
|
||||
* unsigned car v[256 / 8];
|
||||
* */
|
||||
struct GNUNET_CRYPTO_EccScalar val;
|
||||
struct TALER_AgeCommitment *new;
|
||||
|
||||
GNUNET_assert (orig->num_pub == __builtin_popcount (orig->mask.mask) -1);
|
||||
GNUNET_assert (orig->num_priv <= orig->num_pub);
|
||||
|
||||
*derived = NULL;
|
||||
|
||||
new = GNUNET_malloc (sizeof(struct TALER_AgeCommitment));
|
||||
new->mask = orig->mask;
|
||||
new->num_pub = orig->num_pub;
|
||||
new->num_priv = orig->num_priv;
|
||||
new->pub = GNUNET_new_array (
|
||||
new->num_pub,
|
||||
struct TALER_AgeCommitmentPublicKeyP);
|
||||
new->priv = GNUNET_new_array (
|
||||
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++)
|
||||
{
|
||||
/* We shift all keys by the same scalar */
|
||||
struct GNUNET_CRYPTO_EccPoint *p = (struct
|
||||
GNUNET_CRYPTO_EccPoint *) &orig->pub[i];
|
||||
struct GNUNET_CRYPTO_EccPoint *np = (struct
|
||||
GNUNET_CRYPTO_EccPoint *) &new->pub[i];
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_ecc_pmul_mpi (
|
||||
p,
|
||||
&val,
|
||||
np))
|
||||
goto FAIL;
|
||||
|
||||
}
|
||||
|
||||
/* 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++)
|
||||
{
|
||||
|
||||
/* 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));
|
||||
|
||||
/* TODO:
|
||||
* make sure that the calculated private key generate the same public
|
||||
* keys */
|
||||
}
|
||||
|
||||
gcry_mpi_release (f);
|
||||
gcry_ctx_release (ctx);
|
||||
}
|
||||
|
||||
*derived = new;
|
||||
return GNUNET_OK;
|
||||
|
||||
FAIL:
|
||||
GNUNET_free (new->pub);
|
||||
GNUNET_free (new->priv);
|
||||
GNUNET_free (new);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
/* To a given age value between 0 and 31, returns the index of the age group
|
||||
* defined by the given mask.
|
||||
*/
|
||||
static uint8_t
|
||||
get_age_group (
|
||||
const struct TALER_AgeMask *mask,
|
||||
uint8_t age)
|
||||
{
|
||||
uint32_t m = mask->mask;
|
||||
uint8_t i = 0;
|
||||
|
||||
while (m > 0)
|
||||
{
|
||||
if (0 >= age)
|
||||
break;
|
||||
m = m >> 1;
|
||||
i += m & 1;
|
||||
age--;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_restriction_commit (
|
||||
const struct TALER_AgeMask *mask,
|
||||
const uint8_t age,
|
||||
const uint32_t seed,
|
||||
struct TALER_AgeCommitment *commitment)
|
||||
struct TALER_AgeCommitment **commitment)
|
||||
{
|
||||
/* TODO oec */
|
||||
struct TALER_AgeCommitment *new;
|
||||
uint8_t num_pub = __builtin_popcount (mask->mask) - 1;
|
||||
uint8_t num_priv = get_age_group (mask, age) - 1;
|
||||
size_t i;
|
||||
|
||||
GNUNET_assert (mask->mask & 1); /* fist bit must have been set */
|
||||
GNUNET_assert (0 <= num_priv);
|
||||
GNUNET_assert (31 > num_priv);
|
||||
|
||||
new = GNUNET_malloc (sizeof(struct TALER_AgeCommitment));
|
||||
new->mask.mask = mask->mask;
|
||||
new->num_pub = num_pub;
|
||||
new->num_priv = num_priv;
|
||||
|
||||
new->pub = GNUNET_new_array (num_pub, struct TALER_AgeCommitmentPublicKeyP);
|
||||
new->priv = GNUNET_new_array (num_priv, struct TALER_AgeCommitmentPrivateKeyP);
|
||||
|
||||
/* Create as many private keys as we need */
|
||||
for (i = 0; i < num_priv; i++)
|
||||
{
|
||||
uint32_t seedBE = htonl (seed + i);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_kdf (&new->priv[i],
|
||||
sizeof (new->priv[i]),
|
||||
&seedBE,
|
||||
sizeof (seedBE),
|
||||
"taler-age-commitment-derivation",
|
||||
strlen (
|
||||
"taler-age-commitment-derivation"),
|
||||
NULL, 0))
|
||||
goto FAIL;
|
||||
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&new->priv[i].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]));
|
||||
|
||||
*commitment = new;
|
||||
return GNUNET_OK;
|
||||
|
||||
FAIL:
|
||||
GNUNET_free (new->pub);
|
||||
GNUNET_free (new->priv);
|
||||
GNUNET_free (new);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user