-amend missing parts to commit b20ddf0c8
- functions TALER_age_commitment_attest and TALER_age_commitment_verify implemented. - age restriction implementation moved into util/age_restriction.c
This commit is contained in:
parent
b20ddf0c8a
commit
4978b1e966
@ -869,7 +869,7 @@ struct TALER_AgeCommitmentHash
|
|||||||
*/
|
*/
|
||||||
struct TALER_AgeAttestation
|
struct TALER_AgeAttestation
|
||||||
{
|
{
|
||||||
struct GNUNET_CRYPTO_EddsaSignature attest;
|
struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct TALER_AgeCommitmentHash TALER_ZeroAgeCommitmentHash;
|
extern const struct TALER_AgeCommitmentHash TALER_ZeroAgeCommitmentHash;
|
||||||
|
@ -271,6 +271,12 @@
|
|||||||
*/
|
*/
|
||||||
#define TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH 1206
|
#define TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH 1206
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature using a age restriction key for attestation of a particular
|
||||||
|
* age/age-group.
|
||||||
|
*/
|
||||||
|
#define TALER_SIGNATURE_WALLET_AGE_ATTESTATION 1207
|
||||||
|
|
||||||
|
|
||||||
/******************************/
|
/******************************/
|
||||||
/* Security module signatures */
|
/* Security module signatures */
|
||||||
@ -1704,6 +1710,27 @@ struct TALER_MerchantPaySessionSigPS
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for attestation of a particular age
|
||||||
|
*/
|
||||||
|
struct TALER_AgeAttestationPS
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Purpose must be #TALER_SIGNATURE_WALLET_AGE_ATTESTATION.
|
||||||
|
*/
|
||||||
|
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Age mask that defines the underlying age groups
|
||||||
|
*/
|
||||||
|
struct TALER_AgeMask mask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The particular age that this attestation is for
|
||||||
|
*/
|
||||||
|
uint8_t age;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
GNUNET_NETWORK_STRUCT_END
|
GNUNET_NETWORK_STRUCT_END
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ lib_LTLIBRARIES = \
|
|||||||
libtalerutil.la
|
libtalerutil.la
|
||||||
|
|
||||||
libtalerutil_la_SOURCES = \
|
libtalerutil_la_SOURCES = \
|
||||||
|
age_restriction.c \
|
||||||
amount.c \
|
amount.c \
|
||||||
auditor_signatures.c \
|
auditor_signatures.c \
|
||||||
config.c \
|
config.c \
|
||||||
|
@ -443,317 +443,6 @@ TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TALER_age_commitment_hash (
|
|
||||||
const struct TALER_AgeCommitment *commitment,
|
|
||||||
struct TALER_AgeCommitmentHash *ahash)
|
|
||||||
{
|
|
||||||
struct GNUNET_HashContext *hash_context;
|
|
||||||
struct GNUNET_HashCode hash;
|
|
||||||
|
|
||||||
GNUNET_assert (NULL != ahash);
|
|
||||||
if (NULL == commitment)
|
|
||||||
{
|
|
||||||
memset (ahash, 0, sizeof(struct TALER_AgeCommitmentHash));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GNUNET_assert (__builtin_popcount (commitment->mask.mask) - 1 ==
|
|
||||||
commitment->num);
|
|
||||||
|
|
||||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < commitment->num; i++)
|
|
||||||
{
|
|
||||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
|
||||||
&commitment->pub[i],
|
|
||||||
sizeof(struct
|
|
||||||
GNUNET_CRYPTO_EddsaPublicKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
|
||||||
&hash);
|
|
||||||
GNUNET_memcpy (&ahash->shash.bits,
|
|
||||||
&hash.bits,
|
|
||||||
sizeof(ahash->shash.bits));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 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 uint64_t salt,
|
|
||||||
struct TALER_AgeCommitmentProof *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 (NULL != new);
|
|
||||||
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->commitment.mask.mask = mask->mask;
|
|
||||||
new->commitment.num = num_pub;
|
|
||||||
new->proof.num = num_priv;
|
|
||||||
|
|
||||||
new->commitment.pub = GNUNET_new_array (
|
|
||||||
num_pub,
|
|
||||||
struct TALER_AgeCommitmentPublicKeyP);
|
|
||||||
new->proof.priv = GNUNET_new_array (
|
|
||||||
num_priv,
|
|
||||||
struct TALER_AgeCommitmentPrivateKeyP);
|
|
||||||
|
|
||||||
/* 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++)
|
|
||||||
{
|
|
||||||
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->proof.priv[i];
|
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
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 (&priv->eddsa_priv,
|
|
||||||
&new->commitment.pub[i].eddsa_pub);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GNUNET_OK;
|
|
||||||
|
|
||||||
FAIL:
|
|
||||||
GNUNET_free (new->commitment.pub);
|
|
||||||
GNUNET_free (new->proof.priv);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue
|
|
||||||
TALER_age_commitment_derive (
|
|
||||||
const struct TALER_AgeCommitmentProof *orig,
|
|
||||||
const uint64_t salt,
|
|
||||||
struct TALER_AgeCommitmentProof *new)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
*
|
|
||||||
* 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 salt 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 scalar for use in point multiplications is a
|
|
||||||
* GNUNET_CRYPTO_EccScalar which is a
|
|
||||||
* unsigned char v[256 / 8];
|
|
||||||
* */
|
|
||||||
|
|
||||||
GNUNET_assert (NULL != new);
|
|
||||||
GNUNET_assert (orig->commitment.num== __builtin_popcount (
|
|
||||||
orig->commitment.mask.mask) - 1);
|
|
||||||
GNUNET_assert (orig->proof.num <= orig->commitment.num);
|
|
||||||
|
|
||||||
new->commitment.mask = orig->commitment.mask;
|
|
||||||
new->commitment.num = orig->commitment.num;
|
|
||||||
new->proof.num = orig->proof.num;
|
|
||||||
new->commitment.pub = GNUNET_new_array (
|
|
||||||
new->commitment.num,
|
|
||||||
struct TALER_AgeCommitmentPublicKeyP);
|
|
||||||
new->proof.priv = GNUNET_new_array (
|
|
||||||
new->proof.num,
|
|
||||||
struct TALER_AgeCommitmentPrivateKeyP);
|
|
||||||
|
|
||||||
/* scalar multiply the public keys on the curve */
|
|
||||||
for (size_t i = 0; i < orig->commitment.num; i++)
|
|
||||||
{
|
|
||||||
/* We shift all keys by the same scalar */
|
|
||||||
struct GNUNET_CRYPTO_EccPoint *p = (struct
|
|
||||||
GNUNET_CRYPTO_EccPoint *) &orig->
|
|
||||||
commitment.pub[i];
|
|
||||||
struct GNUNET_CRYPTO_EccPoint *np = (struct
|
|
||||||
GNUNET_CRYPTO_EccPoint *) &new->
|
|
||||||
commitment.pub[i];
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
GNUNET_CRYPTO_ecc_pmul_mpi (
|
|
||||||
p,
|
|
||||||
&scalar,
|
|
||||||
np))
|
|
||||||
goto FAIL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* multiply the private keys */
|
|
||||||
/* we borough ideas from GNUNET_CRYPTO_ecdsa_private_key_derive */
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < orig->proof.num; 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));
|
|
||||||
|
|
||||||
for (size_t j = 0; j < 32; j++)
|
|
||||||
dc[i] = orig->proof.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);
|
|
||||||
GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
|
|
||||||
|
|
||||||
for (size_t j = 0; j <32; j++)
|
|
||||||
new->proof.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: add test to make sure that the calculated private key generate
|
|
||||||
* the same public keys */
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return GNUNET_OK;
|
|
||||||
|
|
||||||
FAIL:
|
|
||||||
GNUNET_free (new->commitment.pub);
|
|
||||||
GNUNET_free (new->proof.priv);
|
|
||||||
return GNUNET_SYSERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TALER_age_commitment_free (
|
|
||||||
struct TALER_AgeCommitment *commitment)
|
|
||||||
{
|
|
||||||
if (NULL == commitment)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (NULL != commitment->pub)
|
|
||||||
{
|
|
||||||
GNUNET_free (commitment->pub);
|
|
||||||
commitment->pub = NULL;
|
|
||||||
}
|
|
||||||
GNUNET_free (commitment);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TALER_age_proof_free (
|
|
||||||
struct TALER_AgeProof *proof)
|
|
||||||
{
|
|
||||||
if (NULL != proof->priv)
|
|
||||||
{
|
|
||||||
GNUNET_CRYPTO_zero_keys (
|
|
||||||
proof->priv,
|
|
||||||
sizeof(*proof->priv) * proof->num);
|
|
||||||
|
|
||||||
GNUNET_free (proof->priv);
|
|
||||||
proof->priv = NULL;
|
|
||||||
}
|
|
||||||
GNUNET_free (proof);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TALER_age_commitment_proof_free (
|
|
||||||
struct TALER_AgeCommitmentProof *cp)
|
|
||||||
{
|
|
||||||
if (NULL != cp->proof.priv)
|
|
||||||
{
|
|
||||||
GNUNET_CRYPTO_zero_keys (
|
|
||||||
cp->proof.priv,
|
|
||||||
sizeof(*cp->proof.priv) * cp->proof.num);
|
|
||||||
|
|
||||||
GNUNET_free (cp->proof.priv);
|
|
||||||
cp->proof.priv = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL != cp->commitment.pub)
|
|
||||||
{
|
|
||||||
GNUNET_free (cp->commitment.pub);
|
|
||||||
cp->commitment.pub = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet,
|
TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet,
|
||||||
const struct TALER_DenominationHashP *denom_hash,
|
const struct TALER_DenominationHashP *denom_hash,
|
||||||
|
Loading…
Reference in New Issue
Block a user