2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file util/crypto_ecc.c
23 * @brief public key cryptography (ECC) with libgcrypt
24 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
30 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS
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.
38 #define CURVE "Ed25519"
40 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
42 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
44 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
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).
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)
55 * Extract values from an S-expression.
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
64 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
73 list = gcry_sexp_find_token (sexp, topname, 0);
76 l2 = gcry_sexp_cadr (list);
77 gcry_sexp_release (list);
83 for (s = elems; *s; s++, idx++)
85 l2 = gcry_sexp_find_token (list, s, 1);
88 for (i = 0; i < idx; i++)
93 gcry_sexp_release (list);
94 return 3; /* required parameter not found */
96 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
97 gcry_sexp_release (l2);
100 for (i = 0; i < idx; i++)
102 gcry_free (array[i]);
105 gcry_sexp_release (list);
106 return 4; /* required parameter is invalid */
109 gcry_sexp_release (list);
115 * If target != size, move @a target bytes to the end of the size-sized
116 * buffer and zero out the first @a target - @a size bytes.
118 * @param buf original buffer
119 * @param size number of bytes in @a buf
120 * @param target target size of the buffer
123 adjust (unsigned char *buf,
129 memmove (&buf[target - size], buf, size);
130 memset (buf, 0, target - size);
136 * Output the given MPI value to the given buffer.
138 * @param buf where to output to
139 * @param size number of bytes in @a buf
140 * @param val value to write to @a buf
143 mpi_print (unsigned char *buf,
149 if (gcry_mpi_get_flag (val, GCRYMPI_FLAG_OPAQUE))
151 /* Store opaque MPIs left aligned into the buffer. */
155 p = gcry_mpi_get_opaque (val, &nbits);
160 memcpy (buf, p, rsize);
162 memset (buf+rsize, 0, size - rsize);
166 /* Store regular MPIs as unsigned integers right aligned into
170 gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize,
172 adjust (buf, rsize, size);
178 * Convert data buffer into MPI value.
180 * @param result where to store MPI value (allocated)
181 * @param data raw data (GCRYMPI_FMT_USG)
182 * @param size number of bytes in @a data
185 mpi_scan (gcry_mpi_t *result,
186 const unsigned char *data,
191 if (0 != (rc = gcry_mpi_scan (result,
195 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
202 * Convert the given private key from the network format to the
203 * S-expression that can be used by libgcrypt.
205 * @param priv private key to decode
206 * @return NULL on error
209 decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
214 rc = gcry_sexp_build (&result, NULL,
215 "(private-key(ecc(curve \"" CURVE "\")"
217 (int)sizeof (priv->d), priv->d);
220 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
224 if (0 != (rc = gcry_pk_testkey (result)))
226 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
235 * Convert the given private key from the network format to the
236 * S-expression that can be used by libgcrypt.
238 * @param priv private key to decode
239 * @return NULL on error
242 decode_private_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
247 rc = gcry_sexp_build (&result, NULL,
248 "(private-key(ecc(curve \"" CURVE "\")"
249 "(flags eddsa)(d %b)))",
250 (int)sizeof (priv->d), priv->d);
253 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
257 if (0 != (rc = gcry_pk_testkey (result)))
259 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
268 * Convert the given private key from the network format to the
269 * S-expression that can be used by libgcrypt.
271 * @param priv private key to decode
272 * @return NULL on error
275 decode_private_ecdhe_key (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
280 rc = gcry_sexp_build (&result, NULL,
281 "(private-key(ecc(curve \"" CURVE "\")"
283 (int)sizeof (priv->d), priv->d);
286 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
290 if (0 != (rc = gcry_pk_testkey (result)))
292 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
301 * Extract the public key for the given private key.
303 * @param priv the private key
304 * @param pub where to write the public key
307 GNUNET_CRYPTO_ecdsa_key_get_public (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
308 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
314 sexp = decode_private_ecdsa_key (priv);
315 GNUNET_assert (NULL != sexp);
316 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
317 gcry_sexp_release (sexp);
318 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
320 mpi_print (pub->q_y, sizeof (pub->q_y), q);
321 gcry_mpi_release (q);
322 gcry_ctx_release (ctx);
327 * Extract the public key for the given private key.
329 * @param priv the private key
330 * @param pub where to write the public key
333 GNUNET_CRYPTO_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
334 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
340 sexp = decode_private_eddsa_key (priv);
341 GNUNET_assert (NULL != sexp);
342 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
343 gcry_sexp_release (sexp);
344 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
346 mpi_print (pub->q_y, sizeof (pub->q_y), q);
347 gcry_mpi_release (q);
348 gcry_ctx_release (ctx);
353 * Extract the public key for the given private key.
355 * @param priv the private key
356 * @param pub where to write the public key
359 GNUNET_CRYPTO_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
360 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
366 sexp = decode_private_ecdhe_key (priv);
367 GNUNET_assert (NULL != sexp);
368 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
369 gcry_sexp_release (sexp);
370 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
372 mpi_print (pub->q_y, sizeof (pub->q_y), q);
373 gcry_mpi_release (q);
374 gcry_ctx_release (ctx);
379 * Convert a public key to a string.
381 * @param pub key to convert
382 * @return string representing @a pub
385 GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
388 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
392 keylen += 5 - keylen % 5;
394 pubkeybuf = GNUNET_malloc (keylen + 1);
395 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
396 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
401 GNUNET_free (pubkeybuf);
410 * Convert a public key to a string.
412 * @param pub key to convert
413 * @return string representing @a pub
416 GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
419 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
423 keylen += 5 - keylen % 5;
425 pubkeybuf = GNUNET_malloc (keylen + 1);
426 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
427 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
432 GNUNET_free (pubkeybuf);
441 * Convert a string representing a public key to a public key.
443 * @param enc encoded public key
444 * @param enclen number of bytes in @a enc (without 0-terminator)
445 * @param pub where to store the public key
446 * @return #GNUNET_OK on success
449 GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
451 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
453 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
456 keylen += 5 - keylen % 5;
458 if (enclen != keylen)
459 return GNUNET_SYSERR;
461 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
463 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
464 return GNUNET_SYSERR;
470 * Convert a string representing a public key to a public key.
472 * @param enc encoded public key
473 * @param enclen number of bytes in @a enc (without 0-terminator)
474 * @param pub where to store the public key
475 * @return #GNUNET_OK on success
478 GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
480 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
482 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
485 keylen += 5 - keylen % 5;
487 if (enclen != keylen)
488 return GNUNET_SYSERR;
490 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
492 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
493 return GNUNET_SYSERR;
500 * Clear memory that was used to store a private key.
502 * @param pk location of the key
505 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
507 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
513 * Clear memory that was used to store a private key.
515 * @param pk location of the key
518 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
520 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
526 * Clear memory that was used to store a private key.
528 * @param pk location of the key
531 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
533 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
538 * Create a new private key. Caller must free return value.
540 * @return fresh private key
542 struct GNUNET_CRYPTO_EcdhePrivateKey *
543 GNUNET_CRYPTO_ecdhe_key_create ()
545 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
546 gcry_sexp_t priv_sexp;
547 gcry_sexp_t s_keyparam;
551 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
552 "(genkey(ecc(curve \"" CURVE "\")"
555 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
558 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
560 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
561 gcry_sexp_release (s_keyparam);
564 gcry_sexp_release (s_keyparam);
566 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
568 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
569 gcry_sexp_release (priv_sexp);
573 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
575 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
576 gcry_sexp_release (priv_sexp);
579 gcry_sexp_release (priv_sexp);
580 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
581 mpi_print (priv->d, sizeof (priv->d), d);
582 gcry_mpi_release (d);
588 * Create a new private key. Caller must free return value.
590 * @return fresh private key
592 struct GNUNET_CRYPTO_EcdsaPrivateKey *
593 GNUNET_CRYPTO_ecdsa_key_create ()
595 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
596 gcry_sexp_t priv_sexp;
597 gcry_sexp_t s_keyparam;
601 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
602 "(genkey(ecc(curve \"" CURVE "\")"
605 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
608 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
610 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
611 gcry_sexp_release (s_keyparam);
614 gcry_sexp_release (s_keyparam);
616 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
618 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
619 gcry_sexp_release (priv_sexp);
623 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
625 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
626 gcry_sexp_release (priv_sexp);
629 gcry_sexp_release (priv_sexp);
630 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
631 mpi_print (priv->d, sizeof (priv->d), d);
632 gcry_mpi_release (d);
637 * Create a new private key. Caller must free return value.
639 * @return fresh private key
641 struct GNUNET_CRYPTO_EddsaPrivateKey *
642 GNUNET_CRYPTO_eddsa_key_create ()
644 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
645 gcry_sexp_t priv_sexp;
646 gcry_sexp_t s_keyparam;
650 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
651 "(genkey(ecc(curve \"" CURVE "\")"
654 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
657 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
659 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
660 gcry_sexp_release (s_keyparam);
663 gcry_sexp_release (s_keyparam);
665 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
667 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
668 gcry_sexp_release (priv_sexp);
672 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
674 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
675 gcry_sexp_release (priv_sexp);
678 gcry_sexp_release (priv_sexp);
679 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
680 mpi_print (priv->d, sizeof (priv->d), d);
681 gcry_mpi_release (d);
687 * Get the shared private key we use for anonymous users.
689 * @return "anonymous" private key
691 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
692 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
695 * 'anonymous' pseudonym (global static, d=1, public key = G
698 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
703 mpi_print (anonymous.d,
704 sizeof (anonymous.d),
712 * Wait for a short time (we're trying to lock a file or want
713 * to give another process a shot at finishing a disk write, etc.).
714 * Sleeps for 100ms (as that should be long enough for virtually all
715 * modern systems to context switch and allow another process to do
721 struct GNUNET_TIME_Relative timeout;
723 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
724 (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
729 * Create a new private key by reading it from a file. If the
730 * files does not exist, create a new key and write it to the
731 * file. Caller must free return value. Note that this function
732 * can not guarantee that another process might not be trying
733 * the same operation on the same file at the same time.
734 * If the contents of the file
735 * are invalid the old file is deleted and a fresh key is
738 * @param filename name of file to use to store the key
739 * @return new private key, NULL on error (for example,
742 struct GNUNET_CRYPTO_EddsaPrivateKey *
743 GNUNET_CRYPTO_eddsa_key_create_from_file (const char *filename)
745 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
746 struct GNUNET_DISK_FileHandle *fd;
751 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
753 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
755 fd = GNUNET_DISK_file_open (filename,
756 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
757 | GNUNET_DISK_OPEN_FAILIFEXISTS,
758 GNUNET_DISK_PERM_USER_READ |
759 GNUNET_DISK_PERM_USER_WRITE);
764 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
766 /* must exist but not be accessible, fail for good! */
767 if (0 != ACCESS (filename, R_OK))
768 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
770 GNUNET_break (0); /* what is going on!? */
775 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
780 GNUNET_DISK_file_lock (fd, 0,
781 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
788 LOG (GNUNET_ERROR_TYPE_ERROR,
789 _("Could not acquire lock on file `%s': %s...\n"), filename,
793 LOG (GNUNET_ERROR_TYPE_INFO,
794 _("Creating a new private key. This may take a while.\n"));
795 priv = GNUNET_CRYPTO_eddsa_key_create ();
796 GNUNET_assert (NULL != priv);
797 GNUNET_assert (sizeof (*priv) ==
798 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
799 GNUNET_DISK_file_sync (fd);
801 GNUNET_DISK_file_unlock (fd, 0,
802 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
803 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
804 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
807 /* key file exists already, read it! */
808 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
809 GNUNET_DISK_PERM_NONE);
812 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
819 GNUNET_DISK_file_lock (fd, 0,
820 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
826 LOG (GNUNET_ERROR_TYPE_ERROR,
827 _("Could not acquire lock on file `%s': %s...\n"), filename,
829 LOG (GNUNET_ERROR_TYPE_ERROR,
831 ("This may be ok if someone is currently generating a private key.\n"));
836 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
838 /* eh, what!? File we opened is now gone!? */
839 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
841 GNUNET_DISK_file_unlock (fd, 0,
842 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
843 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
844 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
848 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
850 if (fs < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))
852 /* maybe we got the read lock before the key generating
853 * process had a chance to get the write lock; give it up! */
855 GNUNET_DISK_file_unlock (fd, 0,
856 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
857 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
860 LOG (GNUNET_ERROR_TYPE_ERROR,
861 _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
862 filename, (unsigned int) fs,
863 (unsigned int) sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
864 LOG (GNUNET_ERROR_TYPE_ERROR,
865 _("This may be ok if someone is currently generating a key.\n"));
867 short_wait (); /* wait a bit longer! */
872 fs = sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey);
873 priv = GNUNET_malloc (fs);
874 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
876 GNUNET_DISK_file_unlock (fd, 0,
877 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
878 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
879 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
885 * Create a new private key by reading it from a file. If the
886 * files does not exist, create a new key and write it to the
887 * file. Caller must free return value. Note that this function
888 * can not guarantee that another process might not be trying
889 * the same operation on the same file at the same time.
890 * If the contents of the file
891 * are invalid the old file is deleted and a fresh key is
894 * @param filename name of file to use to store the key
895 * @return new private key, NULL on error (for example,
898 struct GNUNET_CRYPTO_EcdsaPrivateKey *
899 GNUNET_CRYPTO_ecdsa_key_create_from_file (const char *filename)
901 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
902 struct GNUNET_DISK_FileHandle *fd;
907 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
909 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
911 fd = GNUNET_DISK_file_open (filename,
912 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
913 | GNUNET_DISK_OPEN_FAILIFEXISTS,
914 GNUNET_DISK_PERM_USER_READ |
915 GNUNET_DISK_PERM_USER_WRITE);
920 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
922 /* must exist but not be accessible, fail for good! */
923 if (0 != ACCESS (filename, R_OK))
924 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
926 GNUNET_break (0); /* what is going on!? */
931 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
936 GNUNET_DISK_file_lock (fd, 0,
937 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
944 LOG (GNUNET_ERROR_TYPE_ERROR,
945 _("Could not acquire lock on file `%s': %s...\n"), filename,
949 LOG (GNUNET_ERROR_TYPE_INFO,
950 _("Creating a new private key. This may take a while.\n"));
951 priv = GNUNET_CRYPTO_ecdsa_key_create ();
952 GNUNET_assert (NULL != priv);
953 GNUNET_assert (sizeof (*priv) ==
954 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
955 GNUNET_DISK_file_sync (fd);
957 GNUNET_DISK_file_unlock (fd, 0,
958 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
959 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
960 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
963 /* key file exists already, read it! */
964 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
965 GNUNET_DISK_PERM_NONE);
968 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
975 GNUNET_DISK_file_lock (fd, 0,
976 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
982 LOG (GNUNET_ERROR_TYPE_ERROR,
983 _("Could not acquire lock on file `%s': %s...\n"), filename,
985 LOG (GNUNET_ERROR_TYPE_ERROR,
987 ("This may be ok if someone is currently generating a private key.\n"));
992 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
994 /* eh, what!? File we opened is now gone!? */
995 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
997 GNUNET_DISK_file_unlock (fd, 0,
998 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
999 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
1000 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
1004 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
1006 if (fs < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
1008 /* maybe we got the read lock before the key generating
1009 * process had a chance to get the write lock; give it up! */
1011 GNUNET_DISK_file_unlock (fd, 0,
1012 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
1013 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
1014 if (0 == ++cnt % 10)
1016 LOG (GNUNET_ERROR_TYPE_ERROR,
1017 _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
1018 filename, (unsigned int) fs,
1019 (unsigned int) sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
1020 LOG (GNUNET_ERROR_TYPE_ERROR,
1021 _("This may be ok if someone is currently generating a key.\n"));
1023 short_wait (); /* wait a bit longer! */
1028 fs = sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1029 priv = GNUNET_malloc (fs);
1030 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
1032 GNUNET_DISK_file_unlock (fd, 0,
1033 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
1034 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
1035 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
1041 * Create a new private key by reading our peer's key from
1042 * the file specified in the configuration.
1044 * @param cfg the configuration to use
1045 * @return new private key, NULL on error (for example,
1046 * permission denied)
1048 struct GNUNET_CRYPTO_EddsaPrivateKey *
1049 GNUNET_CRYPTO_eddsa_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
1051 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1055 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
1057 priv = GNUNET_CRYPTO_eddsa_key_create_from_file (fn);
1064 * Setup a key file for a peer given the name of the
1065 * configuration file (!). This function is used so that
1066 * at a later point code can be certain that reading a
1067 * key is fast (for example in time-dependent testcases).
1069 * @param cfg_name name of the configuration file to use
1072 GNUNET_CRYPTO_eddsa_setup_key (const char *cfg_name)
1074 struct GNUNET_CONFIGURATION_Handle *cfg;
1075 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1077 cfg = GNUNET_CONFIGURATION_create ();
1078 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
1079 priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1082 GNUNET_CONFIGURATION_destroy (cfg);
1087 * Retrieve the identity of the host's peer.
1089 * @param cfg configuration to use
1090 * @param dst pointer to where to write the peer identity
1091 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
1092 * could not be retrieved
1095 GNUNET_CRYPTO_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
1096 struct GNUNET_PeerIdentity *dst)
1098 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1100 if (NULL == (priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg)))
1102 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1103 _("Could not load peer's private key\n"));
1104 return GNUNET_SYSERR;
1106 GNUNET_CRYPTO_eddsa_key_get_public (priv, &dst->public_key);
1113 * Compare two Peer Identities.
1115 * @param first first peer identity
1116 * @param second second peer identity
1117 * @return bigger than 0 if first > second,
1118 * 0 if they are the same
1119 * smaller than 0 if second > first
1122 GNUNET_CRYPTO_cmp_peer_identity (const struct GNUNET_PeerIdentity *first,
1123 const struct GNUNET_PeerIdentity *second)
1125 return memcmp (first, second, sizeof (struct GNUNET_PeerIdentity));
1130 * Convert the data specified in the given purpose argument to an
1131 * S-expression suitable for signature operations.
1133 * @param purpose data to convert
1134 * @return converted s-expression
1137 data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
1139 struct GNUNET_HashCode hc;
1143 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
1144 if (0 != (rc = gcry_sexp_build (&data, NULL,
1145 "(data(flags eddsa)(hash-algo %s)(value %b))",
1147 (int)sizeof (hc), &hc)))
1149 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1157 * Convert the data specified in the given purpose argument to an
1158 * S-expression suitable for signature operations.
1160 * @param purpose data to convert
1161 * @return converted s-expression
1164 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
1166 struct GNUNET_HashCode hc;
1170 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
1171 if (0 != (rc = gcry_sexp_build (&data, NULL,
1172 "(data(flags rfc6979)(hash %s %b))",
1174 (int)sizeof (hc), &hc)))
1176 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1184 * Sign a given block.
1186 * @param priv private key to use for the signing
1187 * @param purpose what to sign (size, purpose)
1188 * @param sig where to write the signature
1189 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1192 GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1193 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
1194 struct GNUNET_CRYPTO_EcdsaSignature *sig)
1196 gcry_sexp_t priv_sexp;
1197 gcry_sexp_t sig_sexp;
1202 priv_sexp = decode_private_ecdsa_key (priv);
1203 data = data_to_ecdsa_value (purpose);
1204 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
1206 LOG (GNUNET_ERROR_TYPE_WARNING,
1207 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
1208 __LINE__, gcry_strerror (rc));
1209 gcry_sexp_release (data);
1210 gcry_sexp_release (priv_sexp);
1211 return GNUNET_SYSERR;
1213 gcry_sexp_release (priv_sexp);
1214 gcry_sexp_release (data);
1216 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
1218 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
1221 gcry_sexp_release (sig_sexp);
1222 return GNUNET_SYSERR;
1224 gcry_sexp_release (sig_sexp);
1225 mpi_print (sig->r, sizeof (sig->r), rs[0]);
1226 mpi_print (sig->s, sizeof (sig->s), rs[1]);
1227 gcry_mpi_release (rs[0]);
1228 gcry_mpi_release (rs[1]);
1234 * Sign a given block.
1236 * @param priv private key to use for the signing
1237 * @param purpose what to sign (size, purpose)
1238 * @param sig where to write the signature
1239 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1242 GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1243 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
1244 struct GNUNET_CRYPTO_EddsaSignature *sig)
1246 gcry_sexp_t priv_sexp;
1247 gcry_sexp_t sig_sexp;
1252 priv_sexp = decode_private_eddsa_key (priv);
1253 data = data_to_eddsa_value (purpose);
1254 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
1256 LOG (GNUNET_ERROR_TYPE_WARNING,
1257 _("EdDSA signing failed at %s:%d: %s\n"), __FILE__,
1258 __LINE__, gcry_strerror (rc));
1259 gcry_sexp_release (data);
1260 gcry_sexp_release (priv_sexp);
1261 return GNUNET_SYSERR;
1263 gcry_sexp_release (priv_sexp);
1264 gcry_sexp_release (data);
1266 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
1268 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
1271 gcry_sexp_release (sig_sexp);
1272 return GNUNET_SYSERR;
1274 gcry_sexp_release (sig_sexp);
1275 mpi_print (sig->r, sizeof (sig->r), rs[0]);
1276 mpi_print (sig->s, sizeof (sig->s), rs[1]);
1277 gcry_mpi_release (rs[0]);
1278 gcry_mpi_release (rs[1]);
1286 * @param purpose what is the purpose that the signature should have?
1287 * @param validate block to validate (size, purpose, data)
1288 * @param sig signature that is being validated
1289 * @param pub public key of the signer
1290 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1293 GNUNET_CRYPTO_ecdsa_verify (uint32_t purpose,
1294 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1295 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
1296 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
1299 gcry_sexp_t sig_sexpr;
1300 gcry_sexp_t pub_sexpr;
1303 if (purpose != ntohl (validate->purpose))
1304 return GNUNET_SYSERR; /* purpose mismatch */
1306 /* build s-expression for signature */
1307 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1308 "(sig-val(ecdsa(r %b)(s %b)))",
1309 (int)sizeof (sig->r), sig->r,
1310 (int)sizeof (sig->s), sig->s)))
1312 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1313 return GNUNET_SYSERR;
1315 data = data_to_ecdsa_value (validate);
1316 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1317 "(public-key(ecc(curve " CURVE ")(q %b)))",
1318 (int)sizeof (pub->q_y), pub->q_y)))
1320 gcry_sexp_release (data);
1321 gcry_sexp_release (sig_sexpr);
1322 return GNUNET_SYSERR;
1324 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1325 gcry_sexp_release (pub_sexpr);
1326 gcry_sexp_release (data);
1327 gcry_sexp_release (sig_sexpr);
1330 LOG (GNUNET_ERROR_TYPE_INFO,
1331 _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1332 __LINE__, gcry_strerror (rc));
1333 return GNUNET_SYSERR;
1343 * @param purpose what is the purpose that the signature should have?
1344 * @param validate block to validate (size, purpose, data)
1345 * @param sig signature that is being validated
1346 * @param pub public key of the signer
1347 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1350 GNUNET_CRYPTO_eddsa_verify (uint32_t purpose,
1351 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1352 const struct GNUNET_CRYPTO_EddsaSignature *sig,
1353 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
1356 gcry_sexp_t sig_sexpr;
1357 gcry_sexp_t pub_sexpr;
1360 if (purpose != ntohl (validate->purpose))
1361 return GNUNET_SYSERR; /* purpose mismatch */
1363 /* build s-expression for signature */
1364 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1365 "(sig-val(eddsa(r %b)(s %b)))",
1366 (int)sizeof (sig->r), sig->r,
1367 (int)sizeof (sig->s), sig->s)))
1369 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1370 return GNUNET_SYSERR;
1372 data = data_to_eddsa_value (validate);
1373 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1374 "(public-key(ecc(curve " CURVE ")(q %b)))",
1375 (int)sizeof (pub->q_y), pub->q_y)))
1377 gcry_sexp_release (data);
1378 gcry_sexp_release (sig_sexpr);
1379 return GNUNET_SYSERR;
1381 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1382 gcry_sexp_release (pub_sexpr);
1383 gcry_sexp_release (data);
1384 gcry_sexp_release (sig_sexpr);
1387 LOG (GNUNET_ERROR_TYPE_INFO,
1388 _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1389 __LINE__, gcry_strerror (rc));
1390 return GNUNET_SYSERR;
1397 * Derive key material from a public and a private ECDHE key.
1399 * @param priv private key to use for the ECDH (x)
1400 * @param pub public key to use for the ECDH (yG)
1401 * @param key_material where to write the key material (xyG)
1402 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1405 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1406 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1407 struct GNUNET_HashCode *key_material)
1409 gcry_mpi_point_t result;
1413 gcry_sexp_t pub_sexpr;
1414 gcry_mpi_t result_x;
1415 unsigned char xbuf[256 / 8];
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);
1427 /* second, extract the d value from our private key */
1428 mpi_scan (&d, priv->d, sizeof (priv->d));
1430 /* then call the 'multiply' function, to compute the product */
1431 result = gcry_mpi_point_new (0);
1432 gcry_mpi_ec_mul (result, d, q, ctx);
1433 gcry_mpi_point_release (q);
1434 gcry_mpi_release (d);
1436 /* finally, convert point to string for hashing */
1437 result_x = gcry_mpi_new (256);
1438 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1440 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1441 gcry_mpi_point_release (result);
1442 gcry_ctx_release (ctx);
1443 return GNUNET_SYSERR;
1445 gcry_mpi_point_release (result);
1446 gcry_ctx_release (ctx);
1448 rsize = sizeof (xbuf);
1449 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1450 /* result_x can be negative here, so we do not use 'mpi_print'
1451 as that does not include the sign bit; x should be a 255-bit
1452 value, so with the sign it should fit snugly into the 256-bit
1455 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1457 GNUNET_CRYPTO_hash (xbuf, rsize, key_material);
1458 gcry_mpi_release (result_x);
1464 * Derive the 'h' value for key derivation, where
1467 * @param pub public key for deriviation
1468 * @param label label for deriviation
1469 * @param context additional context to use for HKDF of 'h';
1470 * typically the name of the subsystem/application
1474 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1476 const char *context)
1479 struct GNUNET_HashCode hc;
1481 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
1482 "key-derivation", strlen ("key-derivation"),
1484 label, strlen (label),
1485 context, strlen (context),
1487 mpi_scan (&h, (unsigned char *) &hc, sizeof (hc));
1493 * Derive a private key from a given private key and a label.
1494 * Essentially calculates a private key 'd = H(l,P) * x mod n'
1495 * where n is the size of the ECC group and P is the public
1496 * key associated with the private key 'd'.
1498 * @param priv original private key
1499 * @param label label to use for key deriviation
1500 * @param context additional context to use for HKDF of 'h';
1501 * typically the name of the subsystem/application
1502 * @return derived private key
1504 struct GNUNET_CRYPTO_EcdsaPrivateKey *
1505 GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1507 const char *context)
1509 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1510 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
1517 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1519 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1520 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
1522 h = derive_h (&pub, label, context);
1523 mpi_scan (&x, priv->d, sizeof (priv->d));
1524 d = gcry_mpi_new (256);
1525 gcry_mpi_mulm (d, h, x, n);
1526 gcry_mpi_release (h);
1527 gcry_mpi_release (x);
1528 gcry_mpi_release (n);
1529 gcry_ctx_release (ctx);
1530 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1531 mpi_print (ret->d, sizeof (ret->d), d);
1532 gcry_mpi_release (d);
1538 * Derive a public key from a given public key and a label.
1539 * Essentially calculates a public key 'V = H(l,P) * P'.
1541 * @param pub original public key
1542 * @param label label to use for key deriviation
1543 * @param context additional context to use for HKDF of 'h';
1544 * typically the name of the subsystem/application
1545 * @param result where to write the derived public key
1548 GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1550 const char *context,
1551 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1561 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1563 /* obtain point 'q' from original public key. The provided 'q' is
1564 compressed thus we first store it in the context and then get it
1565 back as a (decompresssed) point. */
1566 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8*sizeof (pub->q_y));
1567 GNUNET_assert (q_y);
1568 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1569 gcry_mpi_release (q_y);
1570 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1573 /* calulcate h_mod_n = h % n */
1574 h = derive_h (pub, label, context);
1575 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1576 h_mod_n = gcry_mpi_new (256);
1577 gcry_mpi_mod (h_mod_n, h, n);
1578 /* calculate v = h_mod_n * q */
1579 v = gcry_mpi_point_new (0);
1580 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1581 gcry_mpi_release (h_mod_n);
1582 gcry_mpi_release (h);
1583 gcry_mpi_release (n);
1584 gcry_mpi_point_release (q);
1586 /* convert point 'v' to public key that we return */
1587 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1588 gcry_mpi_point_release (v);
1589 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1590 GNUNET_assert (q_y);
1591 mpi_print (result->q_y, sizeof result->q_y, q_y);
1592 gcry_mpi_release (q_y);
1593 gcry_ctx_release (ctx);
1597 /* end of crypto_ecc.c */