summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/exchange/taler-exchange-httpd_refreshes_reveal.c4
-rw-r--r--src/include/taler_crypto_lib.h14
-rw-r--r--src/lib/exchange_api_refreshes_reveal.c9
-rw-r--r--src/util/Makefile.am6
-rw-r--r--src/util/age_restriction.c229
-rw-r--r--src/util/test_age_restriction.c135
7 files changed, 235 insertions, 163 deletions
diff --git a/.gitignore b/.gitignore
index 9fbf5b058..ace3682e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,6 +88,7 @@ src/wire-plugins/test_wire_plugin
src/wire-plugins/test_wire_plugin_transactions_taler_bank
src/pq/test_pq
src/sq/test_sq
+src/util/test_age_restriction
src/util/test_amount
src/util/test_crypto
src/util/test_json
diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
index caba557c5..d5cb2e476 100644
--- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
@@ -620,14 +620,14 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
oac = rctx->old_age_commitment;
oac->mask = TEH_age_mask;
oac->num = ng;
- oac->pub = GNUNET_new_array (ng, struct TALER_AgeCommitmentPublicKeyP);
+ oac->keys = GNUNET_new_array (ng, struct TALER_AgeCommitmentPublicKeyP);
/* Extract old age commitment */
for (unsigned int i = 0; i< ng; i++)
{
struct GNUNET_JSON_Specification ac_spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL,
- &oac->pub[i]),
+ &oac->keys[i]),
GNUNET_JSON_spec_end ()
};
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index ea1a73af5..e114ef83a 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -339,9 +339,9 @@ struct TALER_CoinSpendPrivateKeyP
struct TALER_AgeCommitmentPrivateKeyP
{
/**
- * Taler uses EdDSA for coins when signing age verification attestation.
+ * Taler uses EcDSA for coins when signing age verification attestation.
*/
- struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
+ struct GNUNET_CRYPTO_EcdsaPrivateKey priv;
};
@@ -351,9 +351,9 @@ struct TALER_AgeCommitmentPrivateKeyP
struct TALER_AgeCommitmentPublicKeyP
{
/**
- * Taler uses EdDSA for coins when signing age verification attestation.
+ * Taler uses EcDSA for coins when signing age verification attestation.
*/
- struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pub;
};
@@ -869,7 +869,7 @@ struct TALER_AgeCommitmentHash
*/
struct TALER_AgeAttestation
{
- struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
+ struct GNUNET_CRYPTO_EcdsaSignature signature;
};
extern const struct TALER_AgeCommitmentHash TALER_ZeroAgeCommitmentHash;
@@ -3326,7 +3326,7 @@ struct TALER_AgeCommitment
*
* The list has been allocated via GNUNET_malloc.
*/
- struct TALER_AgeCommitmentPublicKeyP *pub;
+ struct TALER_AgeCommitmentPublicKeyP *keys;
};
struct TALER_AgeProof
@@ -3347,7 +3347,7 @@ struct TALER_AgeProof
*
* The list has been allocated via GNUNET_malloc.
*/
- struct TALER_AgeCommitmentPrivateKeyP *priv;
+ struct TALER_AgeCommitmentPrivateKeyP *keys;
};
struct TALER_AgeCommitmentProof
diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c
index 6427c637b..cd2a1d1f4 100644
--- a/src/lib/exchange_api_refreshes_reveal.c
+++ b/src/lib/exchange_api_refreshes_reveal.c
@@ -438,10 +438,11 @@ TALER_EXCHANGE_refreshes_reveal (
for (size_t i = 0; i < rd->melt_age_commitment_proof->commitment.num; i++)
{
GNUNET_assert (0 ==
- json_array_append_new (old_age_commitment,
- GNUNET_JSON_from_data_auto (
- &rd->melt_age_commitment_proof->
- commitment.pub[i])));
+ json_array_append_new (
+ old_age_commitment,
+ GNUNET_JSON_from_data_auto (
+ &rd->melt_age_commitment_proof->
+ commitment.keys[i])));
}
}
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 022d0611c..a24f081b5 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -116,6 +116,7 @@ libtalerutil_la_LDFLAGS = \
AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
check_PROGRAMS = \
+ test_age_restriction \
test_amount \
test_crypto \
test_helper_eddsa \
@@ -127,6 +128,11 @@ check_PROGRAMS = \
TESTS = \
$(check_PROGRAMS)
+test_age_restriction_SOURCES = \
+ test_age_restriction.c
+test_age_restriction_LDADD = \
+ -lgnunetutil \
+ libtalerutil.la
test_amount_SOURCES = \
test_amount.c
diff --git a/src/util/age_restriction.c b/src/util/age_restriction.c
index 8e088a408..58db23413 100644
--- a/src/util/age_restriction.c
+++ b/src/util/age_restriction.c
@@ -46,9 +46,9 @@ TALER_age_commitment_hash (
for (size_t i = 0; i < commitment->num; i++)
{
GNUNET_CRYPTO_hash_context_read (hash_context,
- &commitment->pub[i],
+ &commitment->keys[i],
sizeof(struct
- GNUNET_CRYPTO_EddsaPublicKey));
+ GNUNET_CRYPTO_EcdsaPublicKey));
}
GNUNET_CRYPTO_hash_context_finish (hash_context,
@@ -62,7 +62,7 @@ TALER_age_commitment_hash (
/* To a given age value between 0 and 31, returns the index of the age group
* defined by the given mask.
*/
-static uint8_t
+uint8_t
get_age_group (
const struct TALER_AgeMask *mask,
uint8_t age)
@@ -102,14 +102,14 @@ TALER_age_restriction_commit (
new->commitment.mask.bits = mask->bits;
new->commitment.num = num_pub;
new->proof.num = num_priv;
- new->proof.priv = NULL;
+ new->proof.keys = NULL;
- new->commitment.pub = GNUNET_new_array (
+ new->commitment.keys = GNUNET_new_array (
num_pub,
struct TALER_AgeCommitmentPublicKeyP);
if (0 < num_priv)
- new->proof.priv = GNUNET_new_array (
+ new->proof.keys = GNUNET_new_array (
num_priv,
struct TALER_AgeCommitmentPrivateKeyP);
@@ -119,35 +119,40 @@ TALER_age_restriction_commit (
* 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);
+ uint64_t salti = salt + i;
struct TALER_AgeCommitmentPrivateKeyP key = {0};
- struct TALER_AgeCommitmentPrivateKeyP *priv = &key;
+ struct TALER_AgeCommitmentPrivateKeyP *pkey = &key;
+
/* Only save the private keys for age groups less than num_priv */
if (i < num_priv)
- priv = &new->proof.priv[i];
+ pkey = &new->proof.keys[i];
if (GNUNET_OK !=
- GNUNET_CRYPTO_kdf (priv,
- sizeof (*priv),
- &saltBE,
- sizeof (saltBE),
- "taler-age-commitment-derivation",
- strlen (
- "taler-age-commitment-derivation"),
+ GNUNET_CRYPTO_kdf (pkey,
+ sizeof (*pkey),
+ &salti,
+ sizeof (salti),
+ "age commitment",
+ strlen ("age derivation"),
NULL, 0))
goto FAIL;
- GNUNET_CRYPTO_eddsa_key_get_public (&priv->eddsa_priv,
- &new->commitment.pub[i].eddsa_pub);
+ /* 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.pub);
- if (NULL != new->proof.priv)
- GNUNET_free (new->proof.priv);
+ GNUNET_free (new->commitment.keys);
+ if (NULL != new->proof.keys)
+ GNUNET_free (new->proof.keys);
return GNUNET_SYSERR;
}
@@ -158,128 +163,52 @@ TALER_age_commitment_derive (
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];
- * */
+ char label[sizeof(uint64_t) + 1] = {0};
GNUNET_assert (NULL != new);
- GNUNET_assert (orig->commitment.num== __builtin_popcount (
- orig->commitment.mask.bits) - 1);
- GNUNET_assert (orig->proof.num <= orig->commitment.num);
+ GNUNET_assert (orig->proof.num <=
+ orig->commitment.num);
+ GNUNET_assert (orig->commitment.num ==
+ __builtin_popcount (orig->commitment.mask.bits) - 1);
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.keys = 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 */
+ new->proof.num = orig->proof.num;
+ new->proof.keys = NULL;
+ if (0 != new->proof.num)
+ new->proof.keys = GNUNET_new_array (
+ new->proof.num,
+ struct TALER_AgeCommitmentPrivateKeyP);
+
+ memcpy (label, &salt, sizeof(salt));
+
+ /* 1. Derive the public keys */
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;
-
+ GNUNET_CRYPTO_ecdsa_public_key_derive (
+ &orig->commitment.keys[i].pub,
+ label,
+ "age commitment derive",
+ &new->commitment.keys[i].pub);
}
- /* multiply the private keys */
- /* we borough ideas from GNUNET_CRYPTO_ecdsa_private_key_derive */
+ /* 2. Derive the private keys */
+ for (size_t i = 0; i < orig->proof.num; i++)
{
- 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 */
- }
-
+ struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
+ priv = GNUNET_CRYPTO_ecdsa_private_key_derive (
+ &orig->proof.keys[i].priv,
+ label,
+ "age commitment derive");
+ new->proof.keys[i].priv = *priv;
+ GNUNET_free (priv);
}
return GNUNET_OK;
-
-FAIL:
- GNUNET_free (new->commitment.pub);
- GNUNET_free (new->proof.priv);
- return GNUNET_SYSERR;
}
@@ -309,7 +238,7 @@ TALER_age_commitment_attest (
return GNUNET_OK;
}
- if (group >= cp->proof.num)
+ if (group > cp->proof.num)
return GNUNET_NO;
{
@@ -320,9 +249,9 @@ TALER_age_commitment_attest (
.age = age
};
- GNUNET_CRYPTO_eddsa_sign (&cp->proof.priv[group - 1].eddsa_priv,
+ GNUNET_CRYPTO_ecdsa_sign (&cp->proof.keys[group - 1].priv,
&at,
- &attest->eddsa_signature);
+ &attest->signature);
}
return GNUNET_OK;
@@ -349,7 +278,7 @@ TALER_age_commitment_verify (
if (0 == group)
return GNUNET_OK;
- if (group >= comm->num)
+ if (group > comm->num)
return GNUNET_NO;
{
@@ -361,10 +290,10 @@ TALER_age_commitment_verify (
};
return
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_AGE_ATTESTATION,
+ GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_WALLET_AGE_ATTESTATION,
&at,
- &attest->eddsa_signature,
- &comm->pub[group - 1].eddsa_pub);
+ &attest->signature,
+ &comm->keys[group - 1].pub);
}
}
@@ -376,10 +305,10 @@ TALER_age_commitment_free (
if (NULL == commitment)
return;
- if (NULL != commitment->pub)
+ if (NULL != commitment->keys)
{
- GNUNET_free (commitment->pub);
- commitment->pub = NULL;
+ GNUNET_free (commitment->keys);
+ commitment->keys = NULL;
}
GNUNET_free (commitment);
}
@@ -389,14 +318,14 @@ void
TALER_age_proof_free (
struct TALER_AgeProof *proof)
{
- if (NULL != proof->priv)
+ if (NULL != proof->keys)
{
GNUNET_CRYPTO_zero_keys (
- proof->priv,
- sizeof(*proof->priv) * proof->num);
+ proof->keys,
+ sizeof(*proof->keys) * proof->num);
- GNUNET_free (proof->priv);
- proof->priv = NULL;
+ GNUNET_free (proof->keys);
+ proof->keys = NULL;
}
GNUNET_free (proof);
}
@@ -406,19 +335,19 @@ void
TALER_age_commitment_proof_free (
struct TALER_AgeCommitmentProof *cp)
{
- if (NULL != cp->proof.priv)
+ if (NULL != cp->proof.keys)
{
GNUNET_CRYPTO_zero_keys (
- cp->proof.priv,
- sizeof(*cp->proof.priv) * cp->proof.num);
+ cp->proof.keys,
+ sizeof(*cp->proof.keys) * cp->proof.num);
- GNUNET_free (cp->proof.priv);
- cp->proof.priv = NULL;
+ GNUNET_free (cp->proof.keys);
+ cp->proof.keys = NULL;
}
- if (NULL != cp->commitment.pub)
+ if (NULL != cp->commitment.keys)
{
- GNUNET_free (cp->commitment.pub);
- cp->commitment.pub = NULL;
+ GNUNET_free (cp->commitment.keys);
+ cp->commitment.keys = NULL;
}
}
diff --git a/src/util/test_age_restriction.c b/src/util/test_age_restriction.c
new file mode 100644
index 000000000..a047714f7
--- /dev/null
+++ b/src/util/test_age_restriction.c
@@ -0,0 +1,135 @@
+/*
+ This file is part of TALER
+ (C) 2022 Taler Systems SA
+
+ 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file util/test_age_restriction.c
+ * @brief Tests for age restriction specific logic
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_crypto_lib.h"
+
+static struct TALER_AgeMask age_mask = {
+ .bits = 1 | 1 << 8 | 1 << 10 | 1 << 12 | 1 << 14 | 1 << 16 | 1 << 18 | 1 << 21
+};
+
+extern uint8_t
+get_age_group (
+ const struct TALER_AgeMask *mask,
+ uint8_t age);
+
+enum GNUNET_GenericReturnValue
+test_attestation (void)
+{
+ uint8_t age;
+ for (age = 0; age < 35; age++)
+ {
+ enum GNUNET_GenericReturnValue ret;
+ struct TALER_AgeCommitmentProof acp[3] = {0};
+ struct TALER_AgeAttestation at = {0};
+ uint8_t age_group = get_age_group (&age_mask, age);
+ uint64_t salt = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT64_MAX);
+
+ ret = TALER_age_restriction_commit (&age_mask,
+ age,
+ salt,
+ &acp[0]);
+
+ printf (
+ "commit(age:%d) == %d; proof.num: %ld; age_group: %d\n",
+ age,
+ ret,
+ acp[0].proof.num,
+ age_group);
+
+ for (uint8_t i = 0; i<2; i++)
+ {
+ /* Also derive another commitment right away */
+ salt = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT64_MAX);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_age_commitment_derive (&acp[i],
+ salt,
+ &acp[i + 1]));
+ }
+
+ for (uint8_t i = 0; i < 3; i++)
+ {
+ for (uint8_t min = 0; min < 22; min++)
+ {
+ uint8_t min_group = get_age_group (&age_mask, min);
+
+ ret = TALER_age_commitment_attest (&acp[i],
+ min,
+ &at);
+
+ printf (
+ "[%s]: attest(min:%d, age:%d) == %d; age_group: %d, min_group: %d\n",
+ i == 0 ? "commit" : "derive",
+ min,
+ age,
+ ret,
+ age_group,
+ min_group);
+
+ if (min_group <= age_group &&
+ GNUNET_OK != ret)
+ return GNUNET_SYSERR;
+
+ if (min_group > age_group &&
+ GNUNET_NO != ret)
+ return GNUNET_SYSERR;
+
+ if (min_group > age_group)
+ continue;
+
+ ret = TALER_age_commitment_verify (&acp[i].commitment,
+ min,
+ &at);
+
+ printf (
+ "[%s]: verify(min:%d, age:%d) == %d; age_group:%d, min_group: %d\n",
+ i == 0 ? "commit" : "derive",
+ min,
+ age,
+ ret,
+ age_group,
+ min_group);
+
+ if (GNUNET_OK != ret)
+ return ret;
+ }
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+int
+main (int argc,
+ const char *const argv[])
+{
+ (void) argc;
+ (void) argv;
+ if (GNUNET_OK != test_attestation ())
+ return 1;
+ return 0;
+}
+
+
+/* end of test_age_restriction.c */