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