another issue with the #5511 patch
[oweals/gnunet.git] / src / util / crypto_ecc.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2013, 2015 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_ecc.c
23  * @brief public key cryptography (ECC) with libgcrypt
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include <gcrypt.h>
28 #include "gnunet_crypto_lib.h"
29 #include "gnunet_strings_lib.h"
30 #include "benchmark.h"
31
32 #define EXTRA_CHECKS 0
33
34 /**
35  * Name of the curve we are using.  Note that we have hard-coded
36  * structs that use 256 bits, so using a bigger curve will require
37  * changes that break stuff badly.  The name of the curve given here
38  * must be agreed by all peers and be supported by libgcrypt.
39  */
40 #define CURVE "Ed25519"
41
42 #define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
43
44 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
45
46 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
47
48 /**
49  * Log an error message at log-level 'level' that indicates
50  * a failure of the command 'cmd' with the message given
51  * by gcry_strerror(rc).
52  */
53 #define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0)
54
55
56 /**
57  * Extract values from an S-expression.
58  *
59  * @param array where to store the result(s)
60  * @param sexp S-expression to parse
61  * @param topname top-level name in the S-expression that is of interest
62  * @param elems names of the elements to extract
63  * @return 0 on success
64  */
65 static int
66 key_from_sexp (gcry_mpi_t * array,
67                gcry_sexp_t sexp,
68                const char *topname,
69                const char *elems)
70 {
71   gcry_sexp_t list;
72   gcry_sexp_t l2;
73   const char *s;
74   unsigned int i;
75   unsigned int idx;
76
77   list = gcry_sexp_find_token (sexp, topname, 0);
78   if (! list)
79     return 1;
80   l2 = gcry_sexp_cadr (list);
81   gcry_sexp_release (list);
82   list = l2;
83   if (! list)
84     return 2;
85
86   idx = 0;
87   for (s = elems; *s; s++, idx++)
88   {
89     l2 = gcry_sexp_find_token (list, s, 1);
90     if (! l2)
91     {
92       for (i = 0; i < idx; i++)
93       {
94         gcry_free (array[i]);
95         array[i] = NULL;
96       }
97       gcry_sexp_release (list);
98       return 3;                 /* required parameter not found */
99     }
100     array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
101     gcry_sexp_release (l2);
102     if (! array[idx])
103     {
104       for (i = 0; i < idx; i++)
105       {
106         gcry_free (array[i]);
107         array[i] = NULL;
108       }
109       gcry_sexp_release (list);
110       return 4;                 /* required parameter is invalid */
111     }
112   }
113   gcry_sexp_release (list);
114   return 0;
115 }
116
117
118 /**
119  * Convert the given private key from the network format to the
120  * S-expression that can be used by libgcrypt.
121  *
122  * @param priv private key to decode
123  * @return NULL on error
124  */
125 static gcry_sexp_t
126 decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
127 {
128   gcry_sexp_t result;
129   int rc;
130
131   rc = gcry_sexp_build (&result, NULL,
132                         "(private-key(ecc(curve \"" CURVE "\")"
133                         "(d %b)))",
134                         (int) sizeof (priv->d), priv->d);
135   if (0 != rc)
136   {
137     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
138     GNUNET_assert (0);
139   }
140 #if EXTRA_CHECKS
141   if (0 != (rc = gcry_pk_testkey (result)))
142   {
143     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
144     GNUNET_assert (0);
145   }
146 #endif
147   return result;
148 }
149
150
151 /**
152  * Convert the given private key from the network format to the
153  * S-expression that can be used by libgcrypt.
154  *
155  * @param priv private key to decode
156  * @return NULL on error
157  */
158 static gcry_sexp_t
159 decode_private_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
160 {
161   gcry_sexp_t result;
162   int rc;
163
164   rc = gcry_sexp_build (&result, NULL,
165                         "(private-key(ecc(curve \"" CURVE "\")"
166                         "(flags eddsa)(d %b)))",
167                         (int)sizeof (priv->d), priv->d);
168   if (0 != rc)
169   {
170     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
171     GNUNET_assert (0);
172   }
173 #if EXTRA_CHECKS
174   if (0 != (rc = gcry_pk_testkey (result)))
175   {
176     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
177     GNUNET_assert (0);
178   }
179 #endif
180   return result;
181 }
182
183
184 /**
185  * Convert the given private key from the network format to the
186  * S-expression that can be used by libgcrypt.
187  *
188  * @param priv private key to decode
189  * @return NULL on error
190  */
191 static gcry_sexp_t
192 decode_private_ecdhe_key (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
193 {
194   gcry_sexp_t result;
195   int rc;
196
197   rc = gcry_sexp_build (&result, NULL,
198                         "(private-key(ecc(curve \"" CURVE "\")"
199                         "(d %b)))",
200                         (int)sizeof (priv->d), priv->d);
201   if (0 != rc)
202   {
203     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
204     GNUNET_assert (0);
205   }
206 #if EXTRA_CHECKS
207   if (0 != (rc = gcry_pk_testkey (result)))
208   {
209     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
210     GNUNET_assert (0);
211   }
212 #endif
213   return result;
214 }
215
216
217 /**
218  * Extract the public key for the given private key.
219  *
220  * @param priv the private key
221  * @param pub where to write the public key
222  */
223 void
224 GNUNET_CRYPTO_ecdsa_key_get_public (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
225                                     struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
226 {
227   gcry_sexp_t sexp;
228   gcry_ctx_t ctx;
229   gcry_mpi_t q;
230
231   BENCHMARK_START (ecdsa_key_get_public);
232
233   sexp = decode_private_ecdsa_key (priv);
234   GNUNET_assert (NULL != sexp);
235   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
236   gcry_sexp_release (sexp);
237   q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
238   GNUNET_assert (NULL != q);
239   GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
240   gcry_mpi_release (q);
241   gcry_ctx_release (ctx);
242
243   BENCHMARK_END (ecdsa_key_get_public);
244 }
245
246
247 /**
248  * Extract the public key for the given private key.
249  *
250  * @param priv the private key
251  * @param pub where to write the public key
252  */
253 void
254 GNUNET_CRYPTO_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
255                                     struct GNUNET_CRYPTO_EddsaPublicKey *pub)
256 {
257   gcry_sexp_t sexp;
258   gcry_ctx_t ctx;
259   gcry_mpi_t q;
260
261   BENCHMARK_START (eddsa_key_get_public);
262
263   sexp = decode_private_eddsa_key (priv);
264   GNUNET_assert (NULL != sexp);
265   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
266   gcry_sexp_release (sexp);
267   q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
268   GNUNET_assert (q);
269   GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
270   gcry_mpi_release (q);
271   gcry_ctx_release (ctx);
272
273   BENCHMARK_END (eddsa_key_get_public);
274 }
275
276
277 /**
278  * Extract the public key for the given private key.
279  *
280  * @param priv the private key
281  * @param pub where to write the public key
282  */
283 void
284 GNUNET_CRYPTO_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
285                                     struct GNUNET_CRYPTO_EcdhePublicKey *pub)
286 {
287   gcry_sexp_t sexp;
288   gcry_ctx_t ctx;
289   gcry_mpi_t q;
290
291   BENCHMARK_START (ecdhe_key_get_public);
292
293   sexp = decode_private_ecdhe_key (priv);
294   GNUNET_assert (NULL != sexp);
295   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
296   gcry_sexp_release (sexp);
297   q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
298   GNUNET_assert (q);
299   GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
300   gcry_mpi_release (q);
301   gcry_ctx_release (ctx);
302
303   BENCHMARK_END (ecdhe_key_get_public);
304 }
305
306
307 /**
308  * Convert a public key to a string.
309  *
310  * @param pub key to convert
311  * @return string representing @a pub
312  */
313 char *
314 GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
315 {
316   char *pubkeybuf;
317   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
318   char *end;
319
320   if (keylen % 5 > 0)
321     keylen += 5 - keylen % 5;
322   keylen /= 5;
323   pubkeybuf = GNUNET_malloc (keylen + 1);
324   end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
325                                        sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
326                                        pubkeybuf,
327                                        keylen);
328   if (NULL == end)
329   {
330     GNUNET_free (pubkeybuf);
331     return NULL;
332   }
333   *end = '\0';
334   return pubkeybuf;
335 }
336
337
338 /**
339  * Convert a public key to a string.
340  *
341  * @param pub key to convert
342  * @return string representing @a pub
343  */
344 char *
345 GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
346 {
347   char *pubkeybuf;
348   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
349   char *end;
350
351   if (keylen % 5 > 0)
352     keylen += 5 - keylen % 5;
353   keylen /= 5;
354   pubkeybuf = GNUNET_malloc (keylen + 1);
355   end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
356                                        sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
357                                        pubkeybuf,
358                                        keylen);
359   if (NULL == end)
360   {
361     GNUNET_free (pubkeybuf);
362     return NULL;
363   }
364   *end = '\0';
365   return pubkeybuf;
366 }
367
368
369 /**
370  * Convert a private key to a string.
371  *
372  * @param priv key to convert
373  * @return string representing @a pub
374  */
375 char *
376 GNUNET_CRYPTO_eddsa_private_key_to_string (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
377 {
378   char *privkeybuf;
379   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
380   char *end;
381
382   if (keylen % 5 > 0)
383     keylen += 5 - keylen % 5;
384   keylen /= 5;
385   privkeybuf = GNUNET_malloc (keylen + 1);
386   end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
387                                        sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
388                                        privkeybuf,
389                                        keylen);
390   if (NULL == end)
391   {
392     GNUNET_free (privkeybuf);
393     return NULL;
394   }
395   *end = '\0';
396   return privkeybuf;
397 }
398
399
400 /**
401  * Convert a string representing a public key to a public key.
402  *
403  * @param enc encoded public key
404  * @param enclen number of bytes in @a enc (without 0-terminator)
405  * @param pub where to store the public key
406  * @return #GNUNET_OK on success
407  */
408 int
409 GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
410                                             size_t enclen,
411                                             struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
412 {
413   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
414
415   if (keylen % 5 > 0)
416     keylen += 5 - keylen % 5;
417   keylen /= 5;
418   if (enclen != keylen)
419     return GNUNET_SYSERR;
420
421   if (GNUNET_OK !=
422       GNUNET_STRINGS_string_to_data (enc, enclen,
423                                      pub,
424                                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
425     return GNUNET_SYSERR;
426   return GNUNET_OK;
427 }
428
429
430 /**
431  * Convert a string representing a public key to a public key.
432  *
433  * @param enc encoded public key
434  * @param enclen number of bytes in @a enc (without 0-terminator)
435  * @param pub where to store the public key
436  * @return #GNUNET_OK on success
437  */
438 int
439 GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
440                                             size_t enclen,
441                                             struct GNUNET_CRYPTO_EddsaPublicKey *pub)
442 {
443   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
444
445   if (keylen % 5 > 0)
446     keylen += 5 - keylen % 5;
447   keylen /= 5;
448   if (enclen != keylen)
449     return GNUNET_SYSERR;
450
451   if (GNUNET_OK !=
452       GNUNET_STRINGS_string_to_data (enc, enclen,
453                                      pub,
454                                      sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
455     return GNUNET_SYSERR;
456   return GNUNET_OK;
457 }
458
459
460 /**
461  * Convert a string representing a private key to a private key.
462  *
463  * @param enc encoded public key
464  * @param enclen number of bytes in @a enc (without 0-terminator)
465  * @param priv where to store the private key
466  * @return #GNUNET_OK on success
467  */
468 int
469 GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
470                                              size_t enclen,
471                                              struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
472 {
473   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
474
475   if (keylen % 5 > 0)
476     keylen += 5 - keylen % 5;
477   keylen /= 5;
478   if (enclen != keylen)
479     return GNUNET_SYSERR;
480
481   if (GNUNET_OK !=
482       GNUNET_STRINGS_string_to_data (enc, enclen,
483                                      priv,
484                                      sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
485     return GNUNET_SYSERR;
486 #if CRYPTO_BUG
487   if (GNUNET_OK !=
488       check_eddsa_key (priv))
489   {
490     GNUNET_break (0);
491     return GNUNET_OK;
492   }
493 #endif
494   return GNUNET_OK;
495 }
496
497
498 /**
499  * @ingroup crypto
500  * Clear memory that was used to store a private key.
501  *
502  * @param pk location of the key
503  */
504 void
505 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
506 {
507   memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
508 }
509
510
511 /**
512  * @ingroup crypto
513  * Clear memory that was used to store a private key.
514  *
515  * @param pk location of the key
516  */
517 void
518 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
519 {
520   memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
521 }
522
523
524 /**
525  * @ingroup crypto
526  * Clear memory that was used to store a private key.
527  *
528  * @param pk location of the key
529  */
530 void
531 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
532 {
533   memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
534 }
535
536
537 /**
538  * Create a new private key. Caller must free return value.
539  *
540  * @return fresh private key
541  */
542 struct GNUNET_CRYPTO_EcdhePrivateKey *
543 GNUNET_CRYPTO_ecdhe_key_create ()
544 {
545   struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
546
547   priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
548   if (GNUNET_OK !=
549       GNUNET_CRYPTO_ecdhe_key_create2 (priv))
550   {
551     GNUNET_free (priv);
552     return NULL;
553   }
554   return priv;
555 }
556
557
558 /**
559  * @ingroup crypto
560  * Create a new private key.  Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
561  *
562  * @param[out] pk set to fresh private key;
563  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
564  */
565 int
566 GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
567 {
568   gcry_sexp_t priv_sexp;
569   gcry_sexp_t s_keyparam;
570   gcry_mpi_t d;
571   int rc;
572
573   BENCHMARK_START (ecdhe_key_create);
574
575   /* NOTE: For libgcrypt >= 1.7, we do not need the 'eddsa' flag here,
576      but should also be harmless. For libgcrypt < 1.7, using 'eddsa'
577      disables an expensive key testing routine. We do not want to run
578      the expensive check for ECDHE, as we generate TONS of keys to
579      use for a very short time. */
580   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
581                                   "(genkey(ecc(curve \"" CURVE "\")"
582                                   "(flags eddsa no-keytest)))")))
583   {
584     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
585     return GNUNET_SYSERR;
586   }
587   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
588   {
589     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
590     gcry_sexp_release (s_keyparam);
591     return GNUNET_SYSERR;
592   }
593   gcry_sexp_release (s_keyparam);
594 #if EXTRA_CHECKS
595   if (0 != (rc = gcry_pk_testkey (priv_sexp)))
596   {
597     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
598     gcry_sexp_release (priv_sexp);
599     return GNUNET_SYSERR;
600   }
601 #endif
602   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
603   {
604     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
605     gcry_sexp_release (priv_sexp);
606     return GNUNET_SYSERR;
607   }
608   gcry_sexp_release (priv_sexp);
609   GNUNET_CRYPTO_mpi_print_unsigned (pk->d, sizeof (pk->d), d);
610   gcry_mpi_release (d);
611
612   BENCHMARK_END (ecdhe_key_create);
613
614   return GNUNET_OK;
615 }
616
617
618 /**
619  * Create a new private key. Caller must free return value.
620  *
621  * @return fresh private key
622  */
623 struct GNUNET_CRYPTO_EcdsaPrivateKey *
624 GNUNET_CRYPTO_ecdsa_key_create ()
625 {
626   struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
627   gcry_sexp_t priv_sexp;
628   gcry_sexp_t s_keyparam;
629   gcry_mpi_t d;
630   int rc;
631
632   BENCHMARK_START (ecdsa_key_create);
633
634   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
635                                   "(genkey(ecc(curve \"" CURVE "\")"
636                                   "(flags)))")))
637   {
638     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
639     return NULL;
640   }
641   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
642   {
643     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
644     gcry_sexp_release (s_keyparam);
645     return NULL;
646   }
647   gcry_sexp_release (s_keyparam);
648 #if EXTRA_CHECKS
649   if (0 != (rc = gcry_pk_testkey (priv_sexp)))
650   {
651     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
652     gcry_sexp_release (priv_sexp);
653     return NULL;
654   }
655 #endif
656   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
657   {
658     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
659     gcry_sexp_release (priv_sexp);
660     return NULL;
661   }
662   gcry_sexp_release (priv_sexp);
663   priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
664   GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
665   gcry_mpi_release (d);
666
667   BENCHMARK_END (ecdsa_key_create);
668
669   return priv;
670 }
671
672 /**
673  * Create a new private key. Caller must free return value.
674  *
675  * @return fresh private key
676  */
677 struct GNUNET_CRYPTO_EddsaPrivateKey *
678 GNUNET_CRYPTO_eddsa_key_create ()
679 {
680   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
681   gcry_sexp_t priv_sexp;
682   gcry_sexp_t s_keyparam;
683   gcry_mpi_t d;
684   int rc;
685
686   BENCHMARK_START (eddsa_key_create);
687
688 #if CRYPTO_BUG
689  again:
690 #endif
691   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
692                                   "(genkey(ecc(curve \"" CURVE "\")"
693                                   "(flags eddsa)))")))
694   {
695     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
696     return NULL;
697   }
698   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
699   {
700     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
701     gcry_sexp_release (s_keyparam);
702     return NULL;
703   }
704   gcry_sexp_release (s_keyparam);
705 #if EXTRA_CHECKS
706   if (0 != (rc = gcry_pk_testkey (priv_sexp)))
707   {
708     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
709     gcry_sexp_release (priv_sexp);
710     return NULL;
711   }
712 #endif
713   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
714   {
715     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
716     gcry_sexp_release (priv_sexp);
717     return NULL;
718   }
719   gcry_sexp_release (priv_sexp);
720   priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
721   GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
722   gcry_mpi_release (d);
723
724 #if CRYPTO_BUG
725   if (GNUNET_OK !=
726       check_eddsa_key (priv))
727   {
728     GNUNET_break (0);
729     GNUNET_free (priv);
730     goto again;
731   }
732 #endif
733
734   BENCHMARK_END (eddsa_key_create);
735
736   return priv;
737 }
738
739
740 /**
741  * Get the shared private key we use for anonymous users.
742  *
743  * @return "anonymous" private key
744  */
745 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
746 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
747 {
748   /**
749    * 'anonymous' pseudonym (global static, d=1, public key = G
750    * (generator).
751    */
752   static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
753   static int once;
754
755   if (once)
756     return &anonymous;
757   GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
758              sizeof (anonymous.d),
759              GCRYMPI_CONST_ONE);
760   once = 1;
761   return &anonymous;
762 }
763
764
765 /**
766  * Compare two Peer Identities.
767  *
768  * @param first first peer identity
769  * @param second second peer identity
770  * @return bigger than 0 if first > second,
771  *         0 if they are the same
772  *         smaller than 0 if second > first
773  */
774 int
775 GNUNET_CRYPTO_cmp_peer_identity (const struct GNUNET_PeerIdentity *first,
776                                  const struct GNUNET_PeerIdentity *second)
777 {
778   return memcmp (first, second, sizeof (struct GNUNET_PeerIdentity));
779 }
780
781
782 /**
783  * Convert the data specified in the given purpose argument to an
784  * S-expression suitable for signature operations.
785  *
786  * @param purpose data to convert
787  * @return converted s-expression
788  */
789 static gcry_sexp_t
790 data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
791 {
792   struct GNUNET_HashCode hc;
793   gcry_sexp_t data;
794   int rc;
795
796   GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
797   if (0 != (rc = gcry_sexp_build (&data, NULL,
798                                   "(data(flags eddsa)(hash-algo %s)(value %b))",
799                                   "sha512",
800                                   (int)sizeof (hc), &hc)))
801   {
802     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
803     return NULL;
804   }
805   return data;
806 }
807
808
809 /**
810  * Convert the data specified in the given purpose argument to an
811  * S-expression suitable for signature operations.
812  *
813  * @param purpose data to convert
814  * @return converted s-expression
815  */
816 static gcry_sexp_t
817 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
818 {
819   struct GNUNET_HashCode hc;
820   gcry_sexp_t data;
821   int rc;
822
823   GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
824   if (0 != (rc = gcry_sexp_build (&data, NULL,
825                                   "(data(flags rfc6979)(hash %s %b))",
826                                   "sha512",
827                                   (int)sizeof (hc), &hc)))
828   {
829     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
830     return NULL;
831   }
832   return data;
833 }
834
835
836 /**
837  * Sign a given block.
838  *
839  * @param priv private key to use for the signing
840  * @param purpose what to sign (size, purpose)
841  * @param sig where to write the signature
842  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
843  */
844 int
845 GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
846                           const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
847                           struct GNUNET_CRYPTO_EcdsaSignature *sig)
848 {
849   gcry_sexp_t priv_sexp;
850   gcry_sexp_t sig_sexp;
851   gcry_sexp_t data;
852   int rc;
853   gcry_mpi_t rs[2];
854
855   BENCHMARK_START (ecdsa_sign);
856
857   priv_sexp = decode_private_ecdsa_key (priv);
858   data = data_to_ecdsa_value (purpose);
859   if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
860   {
861     LOG (GNUNET_ERROR_TYPE_WARNING,
862          _("ECC signing failed at %s:%d: %s\n"), __FILE__,
863          __LINE__, gcry_strerror (rc));
864     gcry_sexp_release (data);
865     gcry_sexp_release (priv_sexp);
866     return GNUNET_SYSERR;
867   }
868   gcry_sexp_release (priv_sexp);
869   gcry_sexp_release (data);
870
871   /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
872      'signature' */
873   if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
874   {
875     GNUNET_break (0);
876     gcry_sexp_release (sig_sexp);
877     return GNUNET_SYSERR;
878   }
879   gcry_sexp_release (sig_sexp);
880   GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
881   GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
882   gcry_mpi_release (rs[0]);
883   gcry_mpi_release (rs[1]);
884
885   BENCHMARK_END (ecdsa_sign);
886
887   return GNUNET_OK;
888 }
889
890
891 /**
892  * Sign a given block.
893  *
894  * @param priv private key to use for the signing
895  * @param purpose what to sign (size, purpose)
896  * @param sig where to write the signature
897  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
898  */
899 int
900 GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
901                           const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
902                           struct GNUNET_CRYPTO_EddsaSignature *sig)
903 {
904   gcry_sexp_t priv_sexp;
905   gcry_sexp_t sig_sexp;
906   gcry_sexp_t data;
907   int rc;
908   gcry_mpi_t rs[2];
909
910   BENCHMARK_START (eddsa_sign);
911
912   priv_sexp = decode_private_eddsa_key (priv);
913   data = data_to_eddsa_value (purpose);
914   if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
915   {
916     LOG (GNUNET_ERROR_TYPE_WARNING,
917          _("EdDSA signing failed at %s:%d: %s\n"), __FILE__,
918          __LINE__, gcry_strerror (rc));
919     gcry_sexp_release (data);
920     gcry_sexp_release (priv_sexp);
921     return GNUNET_SYSERR;
922   }
923   gcry_sexp_release (priv_sexp);
924   gcry_sexp_release (data);
925
926   /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
927      'signature' */
928   if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
929   {
930     GNUNET_break (0);
931     gcry_sexp_release (sig_sexp);
932     return GNUNET_SYSERR;
933   }
934   gcry_sexp_release (sig_sexp);
935   GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
936   GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
937   gcry_mpi_release (rs[0]);
938   gcry_mpi_release (rs[1]);
939
940   BENCHMARK_END (eddsa_sign);
941
942   return GNUNET_OK;
943 }
944
945
946 /**
947  * Verify signature.
948  *
949  * @param purpose what is the purpose that the signature should have?
950  * @param validate block to validate (size, purpose, data)
951  * @param sig signature that is being validated
952  * @param pub public key of the signer
953  * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
954  */
955 int
956 GNUNET_CRYPTO_ecdsa_verify (uint32_t purpose,
957                             const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
958                             const struct GNUNET_CRYPTO_EcdsaSignature *sig,
959                             const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
960 {
961   gcry_sexp_t data;
962   gcry_sexp_t sig_sexpr;
963   gcry_sexp_t pub_sexpr;
964   int rc;
965
966   BENCHMARK_START (ecdsa_verify);
967
968   if (purpose != ntohl (validate->purpose))
969     return GNUNET_SYSERR;       /* purpose mismatch */
970
971   /* build s-expression for signature */
972   if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
973                                   "(sig-val(ecdsa(r %b)(s %b)))",
974                                   (int) sizeof (sig->r), sig->r,
975                                   (int) sizeof (sig->s), sig->s)))
976   {
977     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
978     return GNUNET_SYSERR;
979   }
980   data = data_to_ecdsa_value (validate);
981   if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
982                                   "(public-key(ecc(curve " CURVE ")(q %b)))",
983                                   (int) sizeof (pub->q_y), pub->q_y)))
984   {
985     gcry_sexp_release (data);
986     gcry_sexp_release (sig_sexpr);
987     return GNUNET_SYSERR;
988   }
989   rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
990   gcry_sexp_release (pub_sexpr);
991   gcry_sexp_release (data);
992   gcry_sexp_release (sig_sexpr);
993   if (0 != rc)
994   {
995     LOG (GNUNET_ERROR_TYPE_INFO,
996          _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
997          __LINE__, gcry_strerror (rc));
998     BENCHMARK_END (ecdsa_verify);
999     return GNUNET_SYSERR;
1000   }
1001   BENCHMARK_END (ecdsa_verify);
1002   return GNUNET_OK;
1003 }
1004
1005
1006
1007 /**
1008  * Verify signature.
1009  *
1010  * @param purpose what is the purpose that the signature should have?
1011  * @param validate block to validate (size, purpose, data)
1012  * @param sig signature that is being validated
1013  * @param pub public key of the signer
1014  * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1015  */
1016 int
1017 GNUNET_CRYPTO_eddsa_verify (uint32_t purpose,
1018                             const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1019                             const struct GNUNET_CRYPTO_EddsaSignature *sig,
1020                             const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
1021 {
1022   gcry_sexp_t data;
1023   gcry_sexp_t sig_sexpr;
1024   gcry_sexp_t pub_sexpr;
1025   int rc;
1026
1027   BENCHMARK_START (eddsa_verify);
1028
1029   if (purpose != ntohl (validate->purpose))
1030     return GNUNET_SYSERR;       /* purpose mismatch */
1031
1032   /* build s-expression for signature */
1033   if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1034                                   "(sig-val(eddsa(r %b)(s %b)))",
1035                                   (int)sizeof (sig->r), sig->r,
1036                                   (int)sizeof (sig->s), sig->s)))
1037   {
1038     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1039     return GNUNET_SYSERR;
1040   }
1041   data = data_to_eddsa_value (validate);
1042   if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1043                                   "(public-key(ecc(curve " CURVE ")(flags eddsa)(q %b)))",
1044                                   (int)sizeof (pub->q_y), pub->q_y)))
1045   {
1046     gcry_sexp_release (data);
1047     gcry_sexp_release (sig_sexpr);
1048     return GNUNET_SYSERR;
1049   }
1050   rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1051   gcry_sexp_release (pub_sexpr);
1052   gcry_sexp_release (data);
1053   gcry_sexp_release (sig_sexpr);
1054   if (0 != rc)
1055   {
1056     LOG (GNUNET_ERROR_TYPE_INFO,
1057          _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1058          __LINE__, gcry_strerror (rc));
1059     BENCHMARK_END (eddsa_verify);
1060     return GNUNET_SYSERR;
1061   }
1062   BENCHMARK_END (eddsa_verify);
1063   return GNUNET_OK;
1064 }
1065
1066
1067 /**
1068  * Derive key material from a public and a private ECDHE key.
1069  *
1070  * @param priv private key to use for the ECDH (x)
1071  * @param pub public key to use for the ECDH (yG)
1072  * @param key_material where to write the key material (xyG)
1073  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1074  */
1075 int
1076 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1077                         const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1078                         struct GNUNET_HashCode *key_material)
1079 {
1080   gcry_mpi_point_t result;
1081   gcry_mpi_point_t q;
1082   gcry_mpi_t d;
1083   gcry_ctx_t ctx;
1084   gcry_sexp_t pub_sexpr;
1085   gcry_mpi_t result_x;
1086   unsigned char xbuf[256 / 8];
1087   size_t rsize;
1088
1089   BENCHMARK_START (ecc_ecdh);
1090
1091   /* first, extract the q = dP value from the public key */
1092   if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1093                             "(public-key(ecc(curve " CURVE ")(q %b)))",
1094                             (int)sizeof (pub->q_y), pub->q_y))
1095     return GNUNET_SYSERR;
1096   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1097   gcry_sexp_release (pub_sexpr);
1098   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1099
1100   /* second, extract the d value from our private key */
1101   GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1102
1103   /* then call the 'multiply' function, to compute the product */
1104   result = gcry_mpi_point_new (0);
1105   gcry_mpi_ec_mul (result, d, q, ctx);
1106   gcry_mpi_point_release (q);
1107   gcry_mpi_release (d);
1108
1109   /* finally, convert point to string for hashing */
1110   result_x = gcry_mpi_new (256);
1111   if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1112   {
1113     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1114     gcry_mpi_point_release (result);
1115     gcry_ctx_release (ctx);
1116     return GNUNET_SYSERR;
1117   }
1118   gcry_mpi_point_release (result);
1119   gcry_ctx_release (ctx);
1120
1121   rsize = sizeof (xbuf);
1122   GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1123   /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1124      as that does not include the sign bit; x should be a 255-bit
1125      value, so with the sign it should fit snugly into the 256-bit
1126      xbuf */
1127   GNUNET_assert (0 ==
1128                  gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1129                                  result_x));
1130   GNUNET_CRYPTO_hash (xbuf,
1131                       rsize,
1132                       key_material);
1133   gcry_mpi_release (result_x);
1134   BENCHMARK_END (ecc_ecdh);
1135   return GNUNET_OK;
1136 }
1137
1138
1139 /**
1140  * Derive the 'h' value for key derivation, where
1141  * 'h = H(l,P)'.
1142  *
1143  * @param pub public key for deriviation
1144  * @param label label for deriviation
1145  * @param context additional context to use for HKDF of 'h';
1146  *        typically the name of the subsystem/application
1147  * @return h value
1148  */
1149 static gcry_mpi_t
1150 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1151           const char *label,
1152           const char *context)
1153 {
1154   gcry_mpi_t h;
1155   struct GNUNET_HashCode hc;
1156   static const char *const salt = "key-derivation";
1157
1158   GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
1159                      salt, strlen (salt),
1160                      pub, sizeof (*pub),
1161                      label, strlen (label),
1162                      context, strlen (context),
1163                      NULL, 0);
1164   GNUNET_CRYPTO_mpi_scan_unsigned (&h,
1165                                    (unsigned char *) &hc,
1166                                    sizeof (hc));
1167   return h;
1168 }
1169
1170
1171 /**
1172  * Derive a private key from a given private key and a label.
1173  * Essentially calculates a private key 'd = H(l,P) * x mod n'
1174  * where n is the size of the ECC group and P is the public
1175  * key associated with the private key 'd'.
1176  *
1177  * @param priv original private key
1178  * @param label label to use for key deriviation
1179  * @param context additional context to use for HKDF of 'h';
1180  *        typically the name of the subsystem/application
1181  * @return derived private key
1182  */
1183 struct GNUNET_CRYPTO_EcdsaPrivateKey *
1184 GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1185                                         const char *label,
1186                                         const char *context)
1187 {
1188   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1189   struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
1190   gcry_mpi_t h;
1191   gcry_mpi_t x;
1192   gcry_mpi_t d;
1193   gcry_mpi_t n;
1194   gcry_ctx_t ctx;
1195
1196   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1197
1198   n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1199   GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
1200
1201   h = derive_h (&pub, label, context);
1202   GNUNET_CRYPTO_mpi_scan_unsigned (&x,
1203                                    priv->d,
1204                                    sizeof (priv->d));
1205   d = gcry_mpi_new (256);
1206   gcry_mpi_mulm (d, h, x, n);
1207   gcry_mpi_release (h);
1208   gcry_mpi_release (x);
1209   gcry_mpi_release (n);
1210   gcry_ctx_release (ctx);
1211   ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1212   GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof (ret->d), d);
1213   gcry_mpi_release (d);
1214   return ret;
1215 }
1216
1217
1218 /**
1219  * Derive a public key from a given public key and a label.
1220  * Essentially calculates a public key 'V = H(l,P) * P'.
1221  *
1222  * @param pub original public key
1223  * @param label label to use for key derivation
1224  * @param context additional context to use for HKDF of 'h';
1225  *        typically the name of the subsystem/application
1226  * @param result where to write the derived public key
1227  */
1228 void
1229 GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1230                                        const char *label,
1231                                        const char *context,
1232                                        struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1233 {
1234   gcry_ctx_t ctx;
1235   gcry_mpi_t q_y;
1236   gcry_mpi_t h;
1237   gcry_mpi_t n;
1238   gcry_mpi_t h_mod_n;
1239   gcry_mpi_point_t q;
1240   gcry_mpi_point_t v;
1241
1242   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1243
1244   /* obtain point 'q' from original public key.  The provided 'q' is
1245      compressed thus we first store it in the context and then get it
1246      back as a (decompresssed) point.  */
1247   q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8*sizeof (pub->q_y));
1248   GNUNET_assert (NULL != q_y);
1249   GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1250   gcry_mpi_release (q_y);
1251   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1252   GNUNET_assert (q);
1253
1254   /* calculate h_mod_n = h % n */
1255   h = derive_h (pub, label, context);
1256   n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1257   h_mod_n = gcry_mpi_new (256);
1258   gcry_mpi_mod (h_mod_n, h, n);
1259   /* calculate v = h_mod_n * q */
1260   v = gcry_mpi_point_new (0);
1261   gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1262   gcry_mpi_release (h_mod_n);
1263   gcry_mpi_release (h);
1264   gcry_mpi_release (n);
1265   gcry_mpi_point_release (q);
1266
1267   /* convert point 'v' to public key that we return */
1268   GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1269   gcry_mpi_point_release (v);
1270   q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1271   GNUNET_assert (q_y);
1272   GNUNET_CRYPTO_mpi_print_unsigned (result->q_y,
1273                                     sizeof (result->q_y),
1274                                     q_y);
1275   gcry_mpi_release (q_y);
1276   gcry_ctx_release (ctx);
1277 }
1278
1279
1280 /**
1281  * Reverse the sequence of the bytes in @a buffer
1282  *
1283  * @param[in|out] buffer buffer to invert
1284  * @param length number of bytes in @a buffer
1285  */
1286 static void
1287 reverse_buffer (unsigned char *buffer,
1288                 size_t length)
1289 {
1290   unsigned char tmp;
1291   size_t i;
1292
1293   for (i=0; i < length/2; i++)
1294   {
1295     tmp = buffer[i];
1296     buffer[i] = buffer[length-1-i];
1297     buffer[length-1-i] = tmp;
1298   }
1299 }
1300
1301
1302 /**
1303  * Convert the secret @a d of an EdDSA key to the
1304  * value that is actually used in the EdDSA computation.
1305  *
1306  * @param d secret input
1307  * @return value used for the calculation in EdDSA
1308  */
1309 static gcry_mpi_t
1310 eddsa_d_to_a (gcry_mpi_t d)
1311 {
1312   unsigned char rawmpi[32]; /* 256-bit value */
1313   size_t rawmpilen;
1314   unsigned char digest[64]; /* 512-bit hash value */
1315   gcry_buffer_t hvec[2];
1316   unsigned int b;
1317   gcry_mpi_t a;
1318
1319   b = 256 / 8; /* number of bytes in `d` */
1320
1321   /* Note that we clear DIGEST so we can use it as input to left pad
1322      the key with zeroes for hashing.  */
1323   memset (digest, 0, sizeof digest);
1324   memset (hvec, 0, sizeof hvec);
1325   rawmpilen = sizeof (rawmpi);
1326   GNUNET_assert (0 ==
1327                  gcry_mpi_print (GCRYMPI_FMT_USG,
1328                                  rawmpi, rawmpilen, &rawmpilen,
1329                                  d));
1330   hvec[0].data = digest;
1331   hvec[0].off = 0;
1332   hvec[0].len = b > rawmpilen ? (b - rawmpilen) : 0;
1333   hvec[1].data = rawmpi;
1334   hvec[1].off = 0;
1335   hvec[1].len = rawmpilen;
1336   GNUNET_assert (0 ==
1337                  gcry_md_hash_buffers (GCRY_MD_SHA512,
1338                                        0 /* flags */,
1339                                        digest,
1340                                        hvec, 2));
1341   /* Compute the A value.  */
1342   reverse_buffer (digest, 32);  /* Only the first half of the hash.  */
1343   digest[0]   = (digest[0] & 0x7f) | 0x40;
1344   digest[31] &= 0xf8;
1345
1346   GNUNET_CRYPTO_mpi_scan_unsigned (&a,
1347                                    digest,
1348                                    32);
1349   return a;
1350 }
1351
1352
1353 /**
1354  * Take point from ECDH and convert it to key material.
1355  *
1356  * @param result point from ECDH
1357  * @param ctx ECC context
1358  * @param key_material[out] set to derived key material
1359  * @return #GNUNET_OK on success
1360  */
1361 static int
1362 point_to_hash (gcry_mpi_point_t result,
1363                gcry_ctx_t ctx,
1364                struct GNUNET_HashCode *key_material)
1365 {
1366   gcry_mpi_t result_x;
1367   unsigned char xbuf[256 / 8];
1368   size_t rsize;
1369
1370   /* finally, convert point to string for hashing */
1371   result_x = gcry_mpi_new (256);
1372   if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1373   {
1374     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1375     return GNUNET_SYSERR;
1376   }
1377
1378   rsize = sizeof (xbuf);
1379   GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1380   /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1381      as that does not include the sign bit; x should be a 255-bit
1382      value, so with the sign it should fit snugly into the 256-bit
1383      xbuf */
1384   GNUNET_assert (0 ==
1385                  gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1386                                  result_x));
1387   GNUNET_CRYPTO_hash (xbuf,
1388                       rsize,
1389                       key_material);
1390   gcry_mpi_release (result_x);
1391   return GNUNET_OK;
1392 }
1393
1394
1395 /**
1396  * @ingroup crypto
1397  * Derive key material from a ECDH public key and a private EdDSA key.
1398  * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1399  *
1400  * @param priv private key from EdDSA to use for the ECDH (x)
1401  * @param pub public key to use for the ECDH (yG)
1402  * @param key_material where to write the key material H(h(x)yG)
1403  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1404  */
1405 int
1406 GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1407                           const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1408                           struct GNUNET_HashCode *key_material)
1409 {
1410   gcry_mpi_point_t result;
1411   gcry_mpi_point_t q;
1412   gcry_mpi_t d;
1413   gcry_mpi_t a;
1414   gcry_ctx_t ctx;
1415   gcry_sexp_t pub_sexpr;
1416   int ret;
1417
1418   BENCHMARK_START (eddsa_ecdh);
1419
1420   /* first, extract the q = dP value from the public key */
1421   if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1422                             "(public-key(ecc(curve " CURVE ")(q %b)))",
1423                             (int)sizeof (pub->q_y), pub->q_y))
1424     return GNUNET_SYSERR;
1425   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1426   gcry_sexp_release (pub_sexpr);
1427   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1428
1429   /* second, extract the d value from our private key */
1430   GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1431
1432   /* NOW, because this is EdDSA, HASH 'd' first! */
1433   a = eddsa_d_to_a (d);
1434   gcry_mpi_release (d);
1435
1436   /* then call the 'multiply' function, to compute the product */
1437   result = gcry_mpi_point_new (0);
1438   gcry_mpi_ec_mul (result, a, q, ctx);
1439   gcry_mpi_point_release (q);
1440   gcry_mpi_release (a);
1441
1442   ret = point_to_hash (result,
1443                        ctx,
1444                        key_material);
1445   gcry_mpi_point_release (result);
1446   gcry_ctx_release (ctx);
1447   BENCHMARK_END (eddsa_ecdh);
1448   return ret;
1449 }
1450
1451
1452 /**
1453  * @ingroup crypto
1454  * Derive key material from a ECDH public key and a private ECDSA key.
1455  * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1456  *
1457  * @param priv private key from ECDSA to use for the ECDH (x)
1458  * @param pub public key to use for the ECDH (yG)
1459  * @param key_material where to write the key material H(h(x)yG)
1460  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1461  */
1462 int
1463 GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1464                           const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1465                           struct GNUNET_HashCode *key_material)
1466 {
1467   gcry_mpi_point_t result;
1468   gcry_mpi_point_t q;
1469   gcry_mpi_t d;
1470   gcry_ctx_t ctx;
1471   gcry_sexp_t pub_sexpr;
1472   int ret;
1473
1474   BENCHMARK_START (ecdsa_ecdh);
1475
1476   /* first, extract the q = dP value from the public key */
1477   if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1478                             "(public-key(ecc(curve " CURVE ")(q %b)))",
1479                             (int)sizeof (pub->q_y), pub->q_y))
1480     return GNUNET_SYSERR;
1481   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1482   gcry_sexp_release (pub_sexpr);
1483   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1484
1485   /* second, extract the d value from our private key */
1486   GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1487
1488   /* then call the 'multiply' function, to compute the product */
1489   result = gcry_mpi_point_new (0);
1490   gcry_mpi_ec_mul (result, d, q, ctx);
1491   gcry_mpi_point_release (q);
1492   gcry_mpi_release (d);
1493
1494   /* finally, convert point to string for hashing */
1495   ret = point_to_hash (result,
1496                        ctx,
1497                        key_material);
1498   gcry_mpi_point_release (result);
1499   gcry_ctx_release (ctx);
1500   BENCHMARK_END (ecdsa_ecdh);
1501   return ret;
1502 }
1503
1504
1505
1506 /**
1507  * @ingroup crypto
1508  * Derive key material from a EdDSA public key and a private ECDH key.
1509  * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1510  *
1511  * @param priv private key to use for the ECDH (y)
1512  * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1513  * @param key_material where to write the key material H(yX)=H(h(x)yG)
1514  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1515  */
1516 int
1517 GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1518                           const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1519                           struct GNUNET_HashCode *key_material)
1520 {
1521   gcry_mpi_point_t result;
1522   gcry_mpi_point_t q;
1523   gcry_mpi_t d;
1524   gcry_ctx_t ctx;
1525   gcry_sexp_t pub_sexpr;
1526   int ret;
1527
1528   BENCHMARK_START (ecdh_eddsa);
1529
1530   /* first, extract the q = dP value from the public key */
1531   if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1532                             "(public-key(ecc(curve " CURVE ")(q %b)))",
1533                             (int)sizeof (pub->q_y), pub->q_y))
1534     return GNUNET_SYSERR;
1535   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1536   gcry_sexp_release (pub_sexpr);
1537   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1538
1539   /* second, extract the d value from our private key */
1540   GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1541
1542   /* then call the 'multiply' function, to compute the product */
1543   result = gcry_mpi_point_new (0);
1544   gcry_mpi_ec_mul (result, d, q, ctx);
1545   gcry_mpi_point_release (q);
1546   gcry_mpi_release (d);
1547
1548   /* finally, convert point to string for hashing */
1549   ret = point_to_hash (result,
1550                        ctx,
1551                        key_material);
1552   gcry_mpi_point_release (result);
1553   gcry_ctx_release (ctx);
1554   BENCHMARK_END (ecdh_eddsa);
1555   return ret;
1556 }
1557
1558 /**
1559  * @ingroup crypto
1560  * Derive key material from a ECDSA public key and a private ECDH key.
1561  * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1562  *
1563  * @param priv private key to use for the ECDH (y)
1564  * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1565  * @param key_material where to write the key material H(yX)=H(h(x)yG)
1566  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1567  */
1568 int
1569 GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1570                           const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1571                           struct GNUNET_HashCode *key_material)
1572 {
1573   return GNUNET_CRYPTO_ecdh_eddsa (priv,
1574                                    (const struct GNUNET_CRYPTO_EddsaPublicKey *)pub,
1575                                    key_material);
1576 }
1577
1578 /* end of crypto_ecc.c */