aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2022-03-27 17:12:52 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2022-03-27 17:12:52 +0200
commitce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32 (patch)
tree984ac3c3018e218acd74c5866a3df2169bfd0557 /src/util
parent1e4d6256731d69f1309ff8439569c65d2e1384a0 (diff)
downloadgnunet-ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32.tar.gz
gnunet-ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32.zip
Edx25519 implemented
Edx25519 is a variant of EdDSA on curve25519 which allows for repeated derivation of private and public keys, independently. The private keys in Edx25519 initially correspond to the data after expansion and clamping in EdDSA. However, this correspondence is lost after deriving further keys from existing ones. The public keys and signature verification are compatible with EdDSA. The ability to repeatedly derive key material is used for example in the context of age restriction in GNU Taler. The scheme that has been implemented is as follows: /* Private keys in Edx25519 are pairs (a, b) of 32 byte each. * Initially they correspond to the result of the expansion * and clamping in EdDSA. */ Edx25519_generate_private(seed) { /* EdDSA expand and clamp */ dh := SHA-512(seed) a := dh[0..31] b := dh[32..64] a[0] &= 0b11111000 a[31] &= 0b01111111 a[31] |= 0b01000000 return (a, b) } Edx25519_public_from_private(private) { /* Public keys are the same as in EdDSA */ (a, _) := private return [a] * G } Edx25519_blinding_factor(P, seed) { /* This is a helper function used in the derivation of * private/public keys from existing ones. */ h1 := HKDF_32(P, seed) /* Ensure that h == h % L */ h := h1 % L /* Optionally: Make sure that we don't create weak keys. */ P' := [h] * P if !( (h!=1) && (h!=0) && (P'!=E) ) { return Edx25519_blinding_factor(P, seed+1) } return h } Edx25519_derive_private(private, seed) { /* This is based on the definition in * GNUNET_CRYPTO_eddsa_private_key_derive. But it accepts * and returns a private pair (a, b) and allows for iteration. */ (a, b) := private P := Edx25519_public_key_from_private(private) h := Edx25519_blinding_factor(P, seed) /* Carefully calculate the new value for a */ a1 := a / 8; a2 := (h * a1) % L a' := (a2 * 8) % L /* Update b as well, binding it to h. This is an additional step compared to GNS. */ b' := SHA256(b ∥ h) return (a', b') } Edx25519_derive_public(P, seed) { h := Edx25519_blinding_factor(P, seed) return [h]*P } Edx25519_sign(private, message) { /* As in Ed25519, except for the origin of b */ (d, b) := private P := Edx25519_public_from_private(private) r := SHA-512(b ∥ message) R := [r] * G s := r + SHA-512(R ∥ P ∥ message) * d % L return (R,s) } Edx25519_verify(P, message, signature) { /* Identical to Ed25519 */ (R, s) := signature return [s] * G == R + [SHA-512(R ∥ P ∥ message)] * P }
Diffstat (limited to 'src/util')
-rw-r--r--src/util/.gitignore1
-rw-r--r--src/util/Makefile.am8
-rw-r--r--src/util/crypto_edx25519.c423
-rw-r--r--src/util/test_crypto_edx25519.c326
4 files changed, 758 insertions, 0 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 51eab71db..0e3449fed 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -36,6 +36,7 @@ test_crypto_ecdh_eddsa
36test_crypto_ecdhe 36test_crypto_ecdhe
37test_crypto_ecdsa 37test_crypto_ecdsa
38test_crypto_eddsa 38test_crypto_eddsa
39test_crypto_edx25519
39test_crypto_hash 40test_crypto_hash
40test_crypto_hash_context 41test_crypto_hash_context
41test_crypto_hkdf 42test_crypto_hkdf
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 406d42b1e..9cb7da15b 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -66,6 +66,7 @@ libgnunetutil_la_SOURCES = \
66 crypto_ecc_gnsrecord.c \ 66 crypto_ecc_gnsrecord.c \
67 $(DLOG) \ 67 $(DLOG) \
68 crypto_ecc_setup.c \ 68 crypto_ecc_setup.c \
69 crypto_edx25519.c \
69 crypto_hash.c \ 70 crypto_hash.c \
70 crypto_hash_file.c \ 71 crypto_hash_file.c \
71 crypto_hkdf.c \ 72 crypto_hkdf.c \
@@ -297,6 +298,7 @@ check_PROGRAMS = \
297 test_crypto_ecdhe \ 298 test_crypto_ecdhe \
298 test_crypto_ecdh_eddsa \ 299 test_crypto_ecdh_eddsa \
299 test_crypto_ecdh_ecdsa \ 300 test_crypto_ecdh_ecdsa \
301 test_crypto_edx25519 \
300 $(DLOG_TEST) \ 302 $(DLOG_TEST) \
301 test_crypto_hash \ 303 test_crypto_hash \
302 test_crypto_hash_context \ 304 test_crypto_hash_context \
@@ -470,6 +472,12 @@ test_crypto_eddsa_LDADD = \
470 libgnunetutil.la \ 472 libgnunetutil.la \
471 $(LIBGCRYPT_LIBS) 473 $(LIBGCRYPT_LIBS)
472 474
475test_crypto_edx25519_SOURCES = \
476 test_crypto_edx25519.c
477test_crypto_edx25519_LDADD = \
478 libgnunetutil.la \
479 $(LIBGCRYPT_LIBS)
480
473test_crypto_ecc_dlog_SOURCES = \ 481test_crypto_ecc_dlog_SOURCES = \
474 test_crypto_ecc_dlog.c 482 test_crypto_ecc_dlog.c
475test_crypto_ecc_dlog_LDADD = \ 483test_crypto_ecc_dlog_LDADD = \
diff --git a/src/util/crypto_edx25519.c b/src/util/crypto_edx25519.c
new file mode 100644
index 000000000..bb5c6d177
--- /dev/null
+++ b/src/util/crypto_edx25519.c
@@ -0,0 +1,423 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/crypto_edx25519.c
23 * @brief An variant of EdDSA which allows for iterative derivation of key pairs.
24 * @author Özgür Kesim
25 * @author Christian Grothoff
26 * @author Florian Dold
27 * @author Martin Schanzenbach
28 */
29#include "platform.h"
30#include <gcrypt.h>
31#include <sodium.h>
32#include "gnunet_crypto_lib.h"
33#include "gnunet_strings_lib.h"
34
35#define CURVE "Ed25519"
36
37void
38GNUNET_CRYPTO_edx25519_key_clear (struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
39{
40 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_Edx25519PrivateKey));
41}
42
43
44void
45GNUNET_CRYPTO_edx25519_key_create_from_seed (
46 const void *seed,
47 size_t seedsize,
48 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
49{
50
51 GNUNET_static_assert (sizeof(*pk) == sizeof(struct GNUNET_HashCode));
52 GNUNET_CRYPTO_hash (seed,
53 seedsize,
54 (struct GNUNET_HashCode *) pk);
55
56 /* Clamp the first half of the key. The second half is used in the signature
57 * process. */
58 pk->a[0] &= 248;
59 pk->a[31] &= 127;
60 pk->a[31] |= 64;
61}
62
63
64void
65GNUNET_CRYPTO_edx25519_key_create (
66 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
67{
68 char seed[256 / 8];
69 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
70 seed,
71 sizeof (seed));
72 GNUNET_CRYPTO_edx25519_key_create_from_seed (seed,
73 sizeof(seed),
74 pk);
75}
76
77
78void
79GNUNET_CRYPTO_edx25519_key_get_public (
80 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
81 struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
82{
83 crypto_scalarmult_ed25519_base_noclamp (pub->q_y,
84 priv->a);
85}
86
87
88/**
89 * This function operates the basically same way as the signature function for
90 * EdDSA. But instead of expanding a private seed (which is usually the case
91 * for crypto APIs) and using the resulting scalars, it takes the scalars
92 * directly from Edx25519PrivateKey. We require this functionality in order to
93 * use derived private keys for signatures.
94 *
95 * The resulting signature is a standard EdDSA signature
96 * which can be verified using the usual APIs.
97 *
98 * @param priv the private key (containing two scalars .a and .b)
99 * @param purp the signature purpose
100 * @param sig the resulting signature
101 */
102enum GNUNET_GenericReturnValue
103GNUNET_CRYPTO_edx25519_sign_ (
104 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
105 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
106 struct GNUNET_CRYPTO_Edx25519Signature *sig)
107{
108
109 crypto_hash_sha512_state hs;
110 unsigned char r[64];
111 unsigned char hram[64];
112 unsigned char P[32];
113 unsigned char R[32];
114 unsigned char tmp[32];
115
116 crypto_hash_sha512_init (&hs);
117
118 /**
119 * Calculate the public key P from the private scalar in the key.
120 */
121 crypto_scalarmult_ed25519_base_noclamp (P,
122 priv->a);
123
124 /**
125 * Calculate r:
126 * r = SHA512 (b ∥ M)
127 * where M is our message (purpose).
128 */
129 crypto_hash_sha512_update (&hs,
130 priv->b,
131 sizeof(priv->b));
132 crypto_hash_sha512_update (&hs,
133 (uint8_t*) purpose,
134 ntohl (purpose->size));
135 crypto_hash_sha512_final (&hs,
136 r);
137
138 /**
139 * Temporarily put P into S
140 */
141 memcpy (sig->s, P, 32);
142
143 /**
144 * Reduce the scalar value r
145 */
146 unsigned char r_mod[64];
147 crypto_core_ed25519_scalar_reduce (r_mod, r);
148
149 /**
150 * Calculate R := r * G of the signature
151 */
152 crypto_scalarmult_ed25519_base_noclamp (R, r_mod);
153 memcpy (sig->r, R, sizeof (R));
154
155 /**
156 * Calculate
157 * hram := SHA512 (R ∥ P ∥ M)
158 */
159 crypto_hash_sha512_init (&hs);
160 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
161 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
162 ntohl (purpose->size));
163 crypto_hash_sha512_final (&hs, hram);
164
165 /**
166 * Reduce the resulting scalar value
167 */
168 unsigned char hram_mod[64];
169 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
170
171 /**
172 * Calculate
173 * S := r + hram * s mod L
174 */
175 crypto_core_ed25519_scalar_mul (tmp, hram_mod, priv->a);
176 crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod);
177
178 sodium_memzero (r, sizeof (r));
179 sodium_memzero (r_mod, sizeof (r_mod));
180
181 return GNUNET_OK;
182}
183
184
185enum GNUNET_GenericReturnValue
186GNUNET_CRYPTO_edx25519_verify_ (
187 uint32_t purpose,
188 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
189 const struct GNUNET_CRYPTO_Edx25519Signature *sig,
190 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
191{
192 const unsigned char *m = (const void *) validate;
193 size_t mlen = ntohl (validate->size);
194 const unsigned char *s = (const void *) sig;
195
196 int res;
197
198 if (purpose != ntohl (validate->purpose))
199 return GNUNET_SYSERR; /* purpose mismatch */
200
201 res = crypto_sign_verify_detached (s, m, mlen, pub->q_y);
202 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
203}
204
205
206/**
207 * Derive the 'h' value for key derivation, where
208 * 'h = H(P ∥ seed) mod n' and 'n' is the size of the cyclic subroup.
209 *
210 * @param pub public key for deriviation
211 * @param seed seed for key the deriviation
212 * @param seedsize the size of the seed
213 * @param n The value for the modulus 'n'
214 * @param[out] phc if not NULL, the output of H() will be written into
215 * return h_mod_n (allocated by this function)
216 */
217static gcry_mpi_t
218derive_h_mod_n (
219 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
220 const void *seed,
221 size_t seedsize,
222 const gcry_mpi_t n,
223 struct GNUNET_HashCode *phc)
224{
225 static const char *const salt = "edx2559-derivation";
226 struct GNUNET_HashCode hc;
227 gcry_mpi_t h;
228 gcry_mpi_t h_mod_n;
229
230 if (NULL == phc)
231 phc = &hc;
232
233 GNUNET_CRYPTO_kdf (phc, sizeof(*phc),
234 salt, strlen (salt),
235 pub, sizeof(*pub),
236 seed, seedsize,
237 NULL, 0);
238
239 /* calculate h_mod_n = h % n */
240 GNUNET_CRYPTO_mpi_scan_unsigned (&h,
241 (unsigned char *) phc,
242 sizeof(*phc));
243 h_mod_n = gcry_mpi_new (256);
244 gcry_mpi_mod (h_mod_n, h, n);
245
246#ifdef CHECK_RARE_CASES
247 /**
248 * Note that the following cases would be problematic:
249 * 1.) h == 0 mod n
250 * 2.) h == 1 mod n
251 * 3.) [h] * P == E
252 * We assume that the probalities for these cases to occur are neglegible.
253 */
254 GNUNET_assert (! gcry_mpi_cmp_ui (h_mod_n, 0));
255 GNUNET_assert (! gcry_mpi_cmp_ui (h_mod_n, 1));
256#endif
257
258 return h_mod_n;
259}
260
261
262void
263GNUNET_CRYPTO_edx25519_private_key_derive (
264 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
265 const void *seed,
266 size_t seedsize,
267 struct GNUNET_CRYPTO_Edx25519PrivateKey *result)
268{
269 struct GNUNET_CRYPTO_Edx25519PublicKey pub;
270 struct GNUNET_HashCode hc;
271 uint8_t a[32];
272 unsigned char sk[64];
273 gcry_ctx_t ctx;
274 gcry_mpi_t h;
275 gcry_mpi_t h_mod_n;
276 gcry_mpi_t x;
277 gcry_mpi_t n;
278 gcry_mpi_t a1;
279 gcry_mpi_t a2;
280 gcry_mpi_t ap; // a'
281
282 GNUNET_CRYPTO_edx25519_key_get_public (priv, &pub);
283
284 /**
285 * Libsodium does not offer an API with arbitrary arithmetic.
286 * Hence we have to use libgcrypt here.
287 */
288 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
289
290 /**
291 * Get our modulo
292 */
293 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
294 GNUNET_assert (NULL != n);
295
296 /**
297 * Get h mod n
298 */
299 h_mod_n = derive_h_mod_n (&pub,
300 seed,
301 seedsize,
302 n,
303 &hc);
304
305 /* Convert priv->a scalar to big endian for libgcrypt */
306 for (size_t i = 0; i < 32; i++)
307 a[i] = priv->a[31 - i];
308
309 /**
310 * dc now contains the private scalar "a".
311 * We carefully remove the clamping and derive a'.
312 * Calculate:
313 * a1 := a / 8
314 * a2 := h * a1 mod n
315 * a' := a2 * 8 mod n
316 */
317 GNUNET_CRYPTO_mpi_scan_unsigned (&x, a, sizeof(a)); // a
318 a1 = gcry_mpi_new (256);
319 gcry_mpi_t eight = gcry_mpi_set_ui (NULL, 8);
320 gcry_mpi_div (a1, NULL, x, eight, 0); // a1 := a / 8
321 a2 = gcry_mpi_new (256);
322 gcry_mpi_mulm (a2, h_mod_n, a1, n); // a2 := h * a1 mod n
323 ap = gcry_mpi_new (256);
324 gcry_mpi_mul (ap, a2, eight); // a' := a2 * 8
325
326#ifdef CHECK_RARE_CASES
327 /* The likelihood for a' == 0 or a' == 1 is neglegible */
328 GNUNET_assert (! gcry_mpi_cmp_ui (ap, 0));
329 GNUNET_assert (! gcry_mpi_cmp_ui (ap, 1));
330#endif
331
332 gcry_mpi_release (h_mod_n);
333 gcry_mpi_release (h);
334 gcry_mpi_release (x);
335 gcry_mpi_release (n);
336 gcry_mpi_release (a1);
337 gcry_mpi_release (a2);
338 gcry_ctx_release (ctx);
339 GNUNET_CRYPTO_mpi_print_unsigned (a, sizeof(a), ap);
340 gcry_mpi_release (ap);
341
342 /**
343 * We hash the derived "h" parameter with the other half of the expanded
344 * private key (that is: priv->b). This ensures that for signature
345 * generation, the "R" is derived from the same derivation path as "h" and is
346 * not reused.
347 */
348 {
349 crypto_hash_sha256_state hs;
350 crypto_hash_sha256_init (&hs);
351 crypto_hash_sha256_update (&hs, priv->b, sizeof(priv->b));
352 crypto_hash_sha256_update (&hs, (unsigned char*) &hc, sizeof (hc));
353 crypto_hash_sha256_final (&hs, result->b);
354 }
355
356 /* Convert to little endian for libsodium */
357 for (size_t i = 0; i < 32; i++)
358 result->a[i] = a[31 - i];
359
360 sodium_memzero (a, sizeof(a));
361}
362
363
364void
365GNUNET_CRYPTO_edx25519_public_key_derive (
366 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
367 const void *seed,
368 size_t seedsize,
369 struct GNUNET_CRYPTO_Edx25519PublicKey *result)
370{
371 struct GNUNET_HashCode hc;
372 gcry_ctx_t ctx;
373 gcry_mpi_t q_y;
374 gcry_mpi_t h;
375 gcry_mpi_t n;
376 gcry_mpi_t h_mod_n;
377 gcry_mpi_point_t q;
378 gcry_mpi_point_t v;
379
380 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, "Ed25519"));
381
382 /* obtain point 'q' from original public key. The provided 'q' is
383 compressed thus we first store it in the context and then get it
384 back as a (decompresssed) point. */
385 q_y = gcry_mpi_set_opaque_copy (NULL,
386 pub->q_y,
387 8 * sizeof(pub->q_y));
388 GNUNET_assert (NULL != q_y);
389 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
390 gcry_mpi_release (q_y);
391 q = gcry_mpi_ec_get_point ("q", ctx, 0);
392 GNUNET_assert (q);
393
394 /**
395 * Get h mod n
396 */
397 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
398 GNUNET_assert (NULL != n);
399 GNUNET_assert (NULL != pub);
400 h_mod_n = derive_h_mod_n (pub,
401 seed,
402 seedsize,
403 n,
404 NULL /* We don't need hc here */);
405
406 /* calculate v = h_mod_n * q */
407 v = gcry_mpi_point_new (0);
408 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
409 gcry_mpi_release (h_mod_n);
410 gcry_mpi_release (h);
411 gcry_mpi_release (n);
412 gcry_mpi_point_release (q);
413
414 /* convert point 'v' to public key that we return */
415 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
416 gcry_mpi_point_release (v);
417 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
418 GNUNET_assert (q_y);
419 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
420 gcry_mpi_release (q_y);
421 gcry_ctx_release (ctx);
422
423}
diff --git a/src/util/test_crypto_edx25519.c b/src/util/test_crypto_edx25519.c
new file mode 100644
index 000000000..ead6f0bb9
--- /dev/null
+++ b/src/util/test_crypto_edx25519.c
@@ -0,0 +1,326 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19
20 */
21/**
22 * @file util/test_crypto_edx25519.c
23 * @brief testcase for ECC public key crypto for edx25519
24 * @author Özgür Kesim
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_signatures.h"
29#include <gcrypt.h>
30
31#define ITER 25
32
33#define KEYFILE "/tmp/test-gnunet-crypto-edx25519.key"
34
35#define PERF GNUNET_YES
36
37
38static struct GNUNET_CRYPTO_Edx25519PrivateKey key;
39
40
41static int
42testSignVerify (void)
43{
44 struct GNUNET_CRYPTO_Edx25519Signature sig;
45 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
46 struct GNUNET_CRYPTO_Edx25519PublicKey pkey;
47 struct GNUNET_TIME_Absolute start;
48 int ok = GNUNET_OK;
49
50 fprintf (stderr, "%s", "W");
51 GNUNET_CRYPTO_edx25519_key_get_public (&key,
52 &pkey);
53 start = GNUNET_TIME_absolute_get ();
54 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
55 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
56
57 for (unsigned int i = 0; i < ITER; i++)
58 {
59 fprintf (stderr, "%s", "."); fflush (stderr);
60 if (GNUNET_SYSERR == GNUNET_CRYPTO_edx25519_sign_ (&key,
61 &purp,
62 &sig))
63 {
64 fprintf (stderr,
65 "GNUNET_CRYPTO_edx25519_sign returned SYSERR\n");
66 ok = GNUNET_SYSERR;
67 continue;
68 }
69 if (GNUNET_SYSERR ==
70 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
71 &purp,
72 &sig,
73 &pkey))
74 {
75 fprintf (stderr,
76 "GNUNET_CRYPTO_edx25519_verify failed!\n");
77 ok = GNUNET_SYSERR;
78 continue;
79 }
80 if (GNUNET_SYSERR !=
81 GNUNET_CRYPTO_edx25519_verify_ (
82 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
83 &purp,
84 &sig,
85 &pkey))
86 {
87 fprintf (stderr,
88 "GNUNET_CRYPTO_edx25519_verify failed to fail!\n");
89 ok = GNUNET_SYSERR;
90 continue;
91 }
92 }
93 fprintf (stderr, "\n");
94 printf ("%d EdDSA sign/verify operations %s\n",
95 ITER,
96 GNUNET_STRINGS_relative_time_to_string (
97 GNUNET_TIME_absolute_get_duration (start),
98 GNUNET_YES));
99 return ok;
100}
101
102
103static int
104testDeriveSignVerify (void)
105{
106 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
107 struct GNUNET_CRYPTO_Edx25519Signature sig;
108 struct GNUNET_CRYPTO_Edx25519PrivateKey dkey;
109 struct GNUNET_CRYPTO_Edx25519PublicKey pub;
110 struct GNUNET_CRYPTO_Edx25519PublicKey dpub;
111 struct GNUNET_CRYPTO_Edx25519PublicKey dpub2;
112
113 GNUNET_CRYPTO_edx25519_key_get_public (&key, &pub);
114 GNUNET_CRYPTO_edx25519_private_key_derive (&key,
115 "test-derive",
116 sizeof("test-derive"),
117 &dkey);
118 GNUNET_CRYPTO_edx25519_public_key_derive (&pub,
119 "test-derive",
120 sizeof("test-derive"),
121 &dpub);
122 GNUNET_CRYPTO_edx25519_key_get_public (&dkey, &dpub2);
123
124 if (0 != GNUNET_memcmp (&dpub.q_y, &dpub2.q_y))
125 {
126 fprintf (stderr, "key deriviation failed\n");
127 return GNUNET_SYSERR;
128 }
129
130 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
131 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
132
133 GNUNET_CRYPTO_edx25519_sign_ (&dkey,
134 &purp,
135 &sig);
136
137 if (GNUNET_SYSERR ==
138 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
139 &purp,
140 &sig,
141 &dpub))
142 {
143 fprintf (stderr,
144 "GNUNET_CRYPTO_edx25519_verify failed after derivation!\n");
145 return GNUNET_SYSERR;
146 }
147
148 if (GNUNET_SYSERR !=
149 GNUNET_CRYPTO_edx25519_verify_ (GNUNET_SIGNATURE_PURPOSE_TEST,
150 &purp,
151 &sig,
152 &pub))
153 {
154 fprintf (stderr,
155 "GNUNET_CRYPTO_edx25519_verify failed to fail after derivation!\n");
156 return GNUNET_SYSERR;
157 }
158
159 if (GNUNET_SYSERR !=
160 GNUNET_CRYPTO_edx25519_verify_ (
161 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
162 &purp,
163 &sig,
164 &dpub))
165 {
166 fprintf (stderr,
167 "GNUNET_CRYPTO_edx25519_verify failed to fail after derivation!\n");
168 return GNUNET_SYSERR;
169 }
170 return GNUNET_OK;
171}
172
173
174#if PERF
175static int
176testSignPerformance ()
177{
178 struct GNUNET_CRYPTO_EccSignaturePurpose purp;
179 struct GNUNET_CRYPTO_Edx25519Signature sig;
180 struct GNUNET_CRYPTO_Edx25519PublicKey pkey;
181 struct GNUNET_TIME_Absolute start;
182 int ok = GNUNET_OK;
183
184 purp.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose));
185 purp.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
186 fprintf (stderr, "%s", "W");
187 GNUNET_CRYPTO_edx25519_key_get_public (&key,
188 &pkey);
189 start = GNUNET_TIME_absolute_get ();
190 for (unsigned int i = 0; i < ITER; i++)
191 {
192 fprintf (stderr, "%s", ".");
193 fflush (stderr);
194 if (GNUNET_SYSERR ==
195 GNUNET_CRYPTO_edx25519_sign_ (&key,
196 &purp,
197 &sig))
198 {
199 fprintf (stderr, "%s", "GNUNET_CRYPTO_edx25519_sign returned SYSERR\n");
200 ok = GNUNET_SYSERR;
201 continue;
202 }
203 }
204 fprintf (stderr, "\n");
205 printf ("%d EdDSA sign operations %s\n",
206 ITER,
207 GNUNET_STRINGS_relative_time_to_string (
208 GNUNET_TIME_absolute_get_duration (start),
209 GNUNET_YES));
210 return ok;
211}
212
213
214#endif
215
216
217#if 0 /* not implemented */
218static int
219testCreateFromFile (void)
220{
221 struct GNUNET_CRYPTO_Edx25519PublicKey p1;
222 struct GNUNET_CRYPTO_Edx25519PublicKey p2;
223
224 /* do_create == GNUNET_YES and non-existing file MUST return GNUNET_YES */
225 GNUNET_assert (0 == unlink (KEYFILE) || ENOENT == errno);
226 GNUNET_assert (GNUNET_YES ==
227 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
228 GNUNET_YES,
229 &key));
230 GNUNET_CRYPTO_edx25519_key_get_public (&key,
231 &p1);
232
233 /* do_create == GNUNET_YES and _existing_ file MUST return GNUNET_NO */
234 GNUNET_assert (GNUNET_NO ==
235 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
236 GNUNET_YES,
237 &key));
238 GNUNET_CRYPTO_edx25519_key_get_public (&key,
239 &p2);
240 GNUNET_assert (0 ==
241 GNUNET_memcmp (&p1,
242 &p2));
243
244 /* do_create == GNUNET_NO and non-existing file MUST return GNUNET_SYSERR */
245 GNUNET_assert (0 == unlink (KEYFILE));
246 GNUNET_assert (GNUNET_SYSERR ==
247 GNUNET_CRYPTO_edx25519_key_from_file (KEYFILE,
248 GNUNET_NO,
249 &key));
250 return GNUNET_OK;
251}
252
253
254#endif
255
256
257static void
258perf_keygen (void)
259{
260 struct GNUNET_TIME_Absolute start;
261 struct GNUNET_CRYPTO_Edx25519PrivateKey pk;
262
263 fprintf (stderr, "%s", "W");
264 start = GNUNET_TIME_absolute_get ();
265 for (unsigned int i = 0; i < 10; i++)
266 {
267 fprintf (stderr, ".");
268 fflush (stderr);
269 GNUNET_CRYPTO_edx25519_key_create (&pk);
270 }
271 fprintf (stderr, "\n");
272 printf ("10 EdDSA keys created in %s\n",
273 GNUNET_STRINGS_relative_time_to_string (
274 GNUNET_TIME_absolute_get_duration (start), GNUNET_YES));
275}
276
277
278int
279main (int argc, char *argv[])
280{
281 int failure_count = 0;
282
283 if (! gcry_check_version ("1.6.0"))
284 {
285 fprintf (stderr,
286 "libgcrypt has not the expected version (version %s is required).\n",
287 "1.6.0");
288 return 0;
289 }
290 if (getenv ("GNUNET_GCRYPT_DEBUG"))
291 gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
292 GNUNET_log_setup ("test-crypto-edx25519",
293 "WARNING",
294 NULL);
295 GNUNET_CRYPTO_edx25519_key_create (&key);
296 if (GNUNET_OK != testDeriveSignVerify ())
297 {
298 failure_count++;
299 fprintf (stderr,
300 "\n\n%d TESTS FAILED!\n\n", failure_count);
301 return -1;
302 }
303#if PERF
304 if (GNUNET_OK != testSignPerformance ())
305 failure_count++;
306#endif
307 if (GNUNET_OK != testSignVerify ())
308 failure_count++;
309#if 0 /* not implemented */
310 if (GNUNET_OK != testCreateFromFile ())
311 failure_count++;
312#endif
313 perf_keygen ();
314
315 if (0 != failure_count)
316 {
317 fprintf (stderr,
318 "\n\n%d TESTS FAILED!\n\n",
319 failure_count);
320 return -1;
321 }
322 return 0;
323}
324
325
326/* end of test_crypto_edx25519.c */