2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file util/crypto_ecc.c
23 * @brief public key cryptography (ECC) with libgcrypt
24 * @author Christian Grothoff
25 * @author Florian Dold
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_strings_lib.h"
31 #include "benchmark.h"
32 #include "tweetnacl-gnunet.h"
34 #define EXTRA_CHECKS 0
38 * Name of the curve we are using. Note that we have hard-coded
39 * structs that use 256 bits, so using a bigger curve will require
40 * changes that break stuff badly. The name of the curve given here
41 * must be agreed by all peers and be supported by libgcrypt.
43 #define CURVE "Ed25519"
45 #define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
47 #define LOG_STRERROR(kind, syscall) \
48 GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
50 #define LOG_STRERROR_FILE(kind, syscall, filename) \
51 GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
54 * Log an error message at log-level 'level' that indicates
55 * a failure of the command 'cmd' with the message given
56 * by gcry_strerror(rc).
58 #define LOG_GCRY(level, cmd, rc) \
62 _ ("`%s' failed at %s:%d with error: %s\n"), \
66 gcry_strerror (rc)); \
71 * Extract values from an S-expression.
73 * @param array where to store the result(s)
74 * @param sexp S-expression to parse
75 * @param topname top-level name in the S-expression that is of interest
76 * @param elems names of the elements to extract
77 * @return 0 on success
80 key_from_sexp (gcry_mpi_t *array,
89 list = gcry_sexp_find_token (sexp, topname, 0);
92 l2 = gcry_sexp_cadr (list);
93 gcry_sexp_release (list);
99 for (const char *s = elems; *s; s++, idx++)
101 l2 = gcry_sexp_find_token (list, s, 1);
104 for (unsigned int i = 0; i < idx; i++)
106 gcry_free (array[i]);
109 gcry_sexp_release (list);
110 return 3; /* required parameter not found */
112 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
113 gcry_sexp_release (l2);
116 for (unsigned int i = 0; i < idx; i++)
118 gcry_free (array[i]);
121 gcry_sexp_release (list);
122 return 4; /* required parameter is invalid */
125 gcry_sexp_release (list);
131 * Convert the given private key from the network format to the
132 * S-expression that can be used by libgcrypt.
134 * @param priv private key to decode
135 * @return NULL on error
138 decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
143 rc = gcry_sexp_build (&result,
145 "(private-key(ecc(curve \"" CURVE "\")"
147 (int) sizeof(priv->d),
151 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
155 if (0 != (rc = gcry_pk_testkey (result)))
157 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
166 * Extract the public key for the given private key.
168 * @param priv the private key
169 * @param pub where to write the public key
172 GNUNET_CRYPTO_ecdsa_key_get_public (
173 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
174 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
176 BENCHMARK_START (ecdsa_key_get_public);
177 GNUNET_TWEETNACL_scalarmult_gnunet_ecdsa (pub->q_y, priv->d);
178 BENCHMARK_END (ecdsa_key_get_public);
183 * Extract the public key for the given private key.
185 * @param priv the private key
186 * @param pub where to write the public key
189 GNUNET_CRYPTO_eddsa_key_get_public (
190 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
191 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
193 BENCHMARK_START (eddsa_key_get_public);
194 GNUNET_TWEETNACL_sign_pk_from_seed (pub->q_y, priv->d);
195 BENCHMARK_END (eddsa_key_get_public);
200 * Extract the public key for the given private key.
202 * @param priv the private key
203 * @param pub where to write the public key
206 GNUNET_CRYPTO_ecdhe_key_get_public (
207 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
208 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
210 BENCHMARK_START (ecdhe_key_get_public);
211 GNUNET_TWEETNACL_scalarmult_curve25519_base (pub->q_y, priv->d);
212 BENCHMARK_END (ecdhe_key_get_public);
217 * Convert a public key to a string.
219 * @param pub key to convert
220 * @return string representing @a pub
223 GNUNET_CRYPTO_ecdsa_public_key_to_string (
224 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
227 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
231 keylen += 5 - keylen % 5;
233 pubkeybuf = GNUNET_malloc (keylen + 1);
235 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
236 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
241 GNUNET_free (pubkeybuf);
250 * Convert a public key to a string.
252 * @param pub key to convert
253 * @return string representing @a pub
256 GNUNET_CRYPTO_eddsa_public_key_to_string (
257 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
260 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
264 keylen += 5 - keylen % 5;
266 pubkeybuf = GNUNET_malloc (keylen + 1);
268 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
269 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
274 GNUNET_free (pubkeybuf);
283 * Convert a private key to a string.
285 * @param priv key to convert
286 * @return string representing @a pub
289 GNUNET_CRYPTO_eddsa_private_key_to_string (
290 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
293 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
297 keylen += 5 - keylen % 5;
299 privkeybuf = GNUNET_malloc (keylen + 1);
300 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
302 struct GNUNET_CRYPTO_EddsaPrivateKey),
307 GNUNET_free (privkeybuf);
316 * Convert a private key to a string.
318 * @param priv key to convert
319 * @return string representing @a priv
322 GNUNET_CRYPTO_ecdsa_private_key_to_string (
323 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
326 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)) * 8;
330 keylen += 5 - keylen % 5;
332 privkeybuf = GNUNET_malloc (keylen + 1);
333 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
335 struct GNUNET_CRYPTO_EcdsaPrivateKey),
340 GNUNET_free (privkeybuf);
349 * Convert a string representing a public key to a public key.
351 * @param enc encoded public key
352 * @param enclen number of bytes in @a enc (without 0-terminator)
353 * @param pub where to store the public key
354 * @return #GNUNET_OK on success
357 GNUNET_CRYPTO_ecdsa_public_key_from_string (
360 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
362 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
365 keylen += 5 - keylen % 5;
367 if (enclen != keylen)
368 return GNUNET_SYSERR;
371 GNUNET_STRINGS_string_to_data (enc,
375 struct GNUNET_CRYPTO_EcdsaPublicKey)))
376 return GNUNET_SYSERR;
382 * Convert a string representing a public key to a public key.
384 * @param enc encoded public key
385 * @param enclen number of bytes in @a enc (without 0-terminator)
386 * @param pub where to store the public key
387 * @return #GNUNET_OK on success
390 GNUNET_CRYPTO_eddsa_public_key_from_string (
393 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
395 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
398 keylen += 5 - keylen % 5;
400 if (enclen != keylen)
401 return GNUNET_SYSERR;
404 GNUNET_STRINGS_string_to_data (enc,
408 struct GNUNET_CRYPTO_EddsaPublicKey)))
409 return GNUNET_SYSERR;
415 * Convert a string representing a private key to a private key.
417 * @param enc encoded public key
418 * @param enclen number of bytes in @a enc (without 0-terminator)
419 * @param priv where to store the private key
420 * @return #GNUNET_OK on success
423 GNUNET_CRYPTO_eddsa_private_key_from_string (
426 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
428 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
431 keylen += 5 - keylen % 5;
433 if (enclen != keylen)
434 return GNUNET_SYSERR;
437 GNUNET_STRINGS_string_to_data (enc,
441 struct GNUNET_CRYPTO_EddsaPrivateKey)))
442 return GNUNET_SYSERR;
444 if (GNUNET_OK != check_eddsa_key (priv))
456 * Clear memory that was used to store a private key.
458 * @param pk location of the key
461 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
463 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
469 * Clear memory that was used to store a private key.
471 * @param pk location of the key
474 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
476 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey));
482 * Clear memory that was used to store a private key.
484 * @param pk location of the key
487 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
489 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey));
494 * Create a new private key. Caller must free return value.
496 * @return fresh private key
498 struct GNUNET_CRYPTO_EcdhePrivateKey *
499 GNUNET_CRYPTO_ecdhe_key_create ()
501 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
503 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
504 if (GNUNET_OK != GNUNET_CRYPTO_ecdhe_key_create2 (priv))
515 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
517 * @param[out] pk set to fresh private key;
518 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
521 GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
523 BENCHMARK_START (ecdhe_key_create);
524 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
526 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
527 BENCHMARK_END (ecdhe_key_create);
533 * Create a new private key. Caller must free return value.
535 * @return fresh private key
537 struct GNUNET_CRYPTO_EcdsaPrivateKey *
538 GNUNET_CRYPTO_ecdsa_key_create ()
540 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
541 gcry_sexp_t priv_sexp;
542 gcry_sexp_t s_keyparam;
546 BENCHMARK_START (ecdsa_key_create);
548 if (0 != (rc = gcry_sexp_build (&s_keyparam,
550 "(genkey(ecc(curve \"" CURVE "\")"
553 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
556 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
558 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
559 gcry_sexp_release (s_keyparam);
562 gcry_sexp_release (s_keyparam);
564 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
566 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
567 gcry_sexp_release (priv_sexp);
571 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
573 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
574 gcry_sexp_release (priv_sexp);
577 gcry_sexp_release (priv_sexp);
578 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
579 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof(priv->d), d);
580 gcry_mpi_release (d);
582 BENCHMARK_END (ecdsa_key_create);
589 * Create a new private key. Caller must free return value.
591 * @return fresh private key
593 struct GNUNET_CRYPTO_EddsaPrivateKey *
594 GNUNET_CRYPTO_eddsa_key_create ()
596 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
598 BENCHMARK_START (eddsa_key_create);
599 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
600 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
602 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
603 BENCHMARK_END (eddsa_key_create);
610 * Get the shared private key we use for anonymous users.
612 * @return "anonymous" private key
614 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
615 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
618 * 'anonymous' pseudonym (global static, d=1, public key = G
621 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
626 GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
635 * Convert the data specified in the given purpose argument to an
636 * S-expression suitable for signature operations.
638 * @param purpose data to convert
639 * @return converted s-expression
642 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
649 struct GNUNET_HashCode hc;
651 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
652 if (0 != (rc = gcry_sexp_build (&data,
654 "(data(flags rfc6979)(hash %s %b))",
659 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
663 if (0 != (rc = gcry_sexp_build (&data,
665 "(data(flags rfc6979)(hash %s %b))",
667 ntohl (purpose->size),
670 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
679 * Sign a given block.
681 * @param priv private key to use for the signing
682 * @param purpose what to sign (size, purpose)
683 * @param sig where to write the signature
684 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
687 GNUNET_CRYPTO_ecdsa_sign (
688 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
689 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
690 struct GNUNET_CRYPTO_EcdsaSignature *sig)
692 gcry_sexp_t priv_sexp;
693 gcry_sexp_t sig_sexp;
698 BENCHMARK_START (ecdsa_sign);
700 priv_sexp = decode_private_ecdsa_key (priv);
701 data = data_to_ecdsa_value (purpose);
702 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
704 LOG (GNUNET_ERROR_TYPE_WARNING,
705 _ ("ECC signing failed at %s:%d: %s\n"),
709 gcry_sexp_release (data);
710 gcry_sexp_release (priv_sexp);
711 return GNUNET_SYSERR;
713 gcry_sexp_release (priv_sexp);
714 gcry_sexp_release (data);
716 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
718 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
721 gcry_sexp_release (sig_sexp);
722 return GNUNET_SYSERR;
724 gcry_sexp_release (sig_sexp);
725 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof(sig->r), rs[0]);
726 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof(sig->s), rs[1]);
727 gcry_mpi_release (rs[0]);
728 gcry_mpi_release (rs[1]);
730 BENCHMARK_END (ecdsa_sign);
737 * Sign a given block.
739 * @param priv private key to use for the signing
740 * @param purpose what to sign (size, purpose)
741 * @param sig where to write the signature
742 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
745 GNUNET_CRYPTO_eddsa_sign (
746 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
747 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
748 struct GNUNET_CRYPTO_EddsaSignature *sig)
751 size_t mlen = ntohl (purpose->size);
752 unsigned char sk[GNUNET_TWEETNACL_SIGN_SECRETKEYBYTES];
755 BENCHMARK_START (eddsa_sign);
756 GNUNET_TWEETNACL_sign_sk_from_seed (sk, priv->d);
757 res = GNUNET_TWEETNACL_sign_detached ((uint8_t *) sig,
761 BENCHMARK_END (eddsa_sign);
762 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
769 * @param purpose what is the purpose that the signature should have?
770 * @param validate block to validate (size, purpose, data)
771 * @param sig signature that is being validated
772 * @param pub public key of the signer
773 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
776 GNUNET_CRYPTO_ecdsa_verify (
778 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
779 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
780 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
783 gcry_sexp_t sig_sexpr;
784 gcry_sexp_t pub_sexpr;
787 BENCHMARK_START (ecdsa_verify);
789 if (purpose != ntohl (validate->purpose))
790 return GNUNET_SYSERR; /* purpose mismatch */
792 /* build s-expression for signature */
793 if (0 != (rc = gcry_sexp_build (&sig_sexpr,
795 "(sig-val(ecdsa(r %b)(s %b)))",
796 (int) sizeof(sig->r),
798 (int) sizeof(sig->s),
801 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
802 return GNUNET_SYSERR;
804 data = data_to_ecdsa_value (validate);
805 if (0 != (rc = gcry_sexp_build (&pub_sexpr,
807 "(public-key(ecc(curve " CURVE ")(q %b)))",
808 (int) sizeof(pub->q_y),
811 gcry_sexp_release (data);
812 gcry_sexp_release (sig_sexpr);
813 return GNUNET_SYSERR;
815 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
816 gcry_sexp_release (pub_sexpr);
817 gcry_sexp_release (data);
818 gcry_sexp_release (sig_sexpr);
821 LOG (GNUNET_ERROR_TYPE_INFO,
822 _ ("ECDSA signature verification failed at %s:%d: %s\n"),
826 BENCHMARK_END (ecdsa_verify);
827 return GNUNET_SYSERR;
829 BENCHMARK_END (ecdsa_verify);
837 * @param purpose what is the purpose that the signature should have?
838 * @param validate block to validate (size, purpose, data)
839 * @param sig signature that is being validated
840 * @param pub public key of the signer
841 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
844 GNUNET_CRYPTO_eddsa_verify (
846 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
847 const struct GNUNET_CRYPTO_EddsaSignature *sig,
848 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
850 unsigned char *m = (void *) validate;
851 size_t mlen = ntohl (validate->size);
852 unsigned char *s = (void *) sig;
856 if (purpose != ntohl (validate->purpose))
857 return GNUNET_SYSERR; /* purpose mismatch */
859 BENCHMARK_START (eddsa_verify);
860 res = GNUNET_TWEETNACL_sign_detached_verify (s, m, mlen, pub->q_y);
861 BENCHMARK_END (eddsa_verify);
862 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
867 * Derive key material from a public and a private ECDHE key.
869 * @param priv private key to use for the ECDH (x)
870 * @param pub public key to use for the ECDH (yG)
871 * @param key_material where to write the key material (xyG)
872 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
875 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
876 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
877 struct GNUNET_HashCode *key_material)
879 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
880 GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, pub->q_y);
881 GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material);
887 * Derive the 'h' value for key derivation, where
890 * @param pub public key for deriviation
891 * @param label label for deriviation
892 * @param context additional context to use for HKDF of 'h';
893 * typically the name of the subsystem/application
897 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
902 struct GNUNET_HashCode hc;
903 static const char *const salt = "key-derivation";
905 GNUNET_CRYPTO_kdf (&hc,
917 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
923 * Derive a private key from a given private key and a label.
924 * Essentially calculates a private key 'd = H(l,P) * x mod n'
925 * where n is the size of the ECC group and P is the public
926 * key associated with the private key 'd'.
928 * @param priv original private key
929 * @param label label to use for key deriviation
930 * @param context additional context to use for HKDF of 'h';
931 * typically the name of the subsystem/application
932 * @return derived private key
934 struct GNUNET_CRYPTO_EcdsaPrivateKey *
935 GNUNET_CRYPTO_ecdsa_private_key_derive (
936 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
940 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
941 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
948 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
950 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
951 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
953 h = derive_h (&pub, label, context);
954 GNUNET_CRYPTO_mpi_scan_unsigned (&x, priv->d, sizeof(priv->d));
955 d = gcry_mpi_new (256);
956 gcry_mpi_mulm (d, h, x, n);
957 gcry_mpi_release (h);
958 gcry_mpi_release (x);
959 gcry_mpi_release (n);
960 gcry_ctx_release (ctx);
961 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
962 GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof(ret->d), d);
963 gcry_mpi_release (d);
969 * Derive a public key from a given public key and a label.
970 * Essentially calculates a public key 'V = H(l,P) * P'.
972 * @param pub original public key
973 * @param label label to use for key derivation
974 * @param context additional context to use for HKDF of 'h';
975 * typically the name of the subsystem/application
976 * @param result where to write the derived public key
979 GNUNET_CRYPTO_ecdsa_public_key_derive (
980 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
983 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
993 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
995 /* obtain point 'q' from original public key. The provided 'q' is
996 compressed thus we first store it in the context and then get it
997 back as a (decompresssed) point. */
998 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
999 GNUNET_assert (NULL != q_y);
1000 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1001 gcry_mpi_release (q_y);
1002 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1005 /* calculate h_mod_n = h % n */
1006 h = derive_h (pub, label, context);
1007 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1008 h_mod_n = gcry_mpi_new (256);
1009 gcry_mpi_mod (h_mod_n, h, n);
1010 /* calculate v = h_mod_n * q */
1011 v = gcry_mpi_point_new (0);
1012 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1013 gcry_mpi_release (h_mod_n);
1014 gcry_mpi_release (h);
1015 gcry_mpi_release (n);
1016 gcry_mpi_point_release (q);
1018 /* convert point 'v' to public key that we return */
1019 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1020 gcry_mpi_point_release (v);
1021 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1022 GNUNET_assert (q_y);
1023 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
1024 gcry_mpi_release (q_y);
1025 gcry_ctx_release (ctx);
1031 * Derive key material from a ECDH public key and a private EdDSA key.
1032 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1034 * @param priv private key from EdDSA to use for the ECDH (x)
1035 * @param pub public key to use for the ECDH (yG)
1036 * @param key_material where to write the key material H(h(x)yG)
1037 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1040 GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1041 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1042 struct GNUNET_HashCode *key_material)
1044 struct GNUNET_HashCode hc;
1045 uint8_t a[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1046 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1048 GNUNET_CRYPTO_hash (priv,
1049 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
1051 memcpy (a, &hc, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1052 GNUNET_TWEETNACL_scalarmult_curve25519 (p, a, pub->q_y);
1053 GNUNET_CRYPTO_hash (p,
1054 GNUNET_TWEETNACL_SCALARMULT_BYTES,
1062 * Derive key material from a ECDH public key and a private ECDSA key.
1063 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1065 * @param priv private key from ECDSA to use for the ECDH (x)
1066 * @param pub public key to use for the ECDH (yG)
1067 * @param key_material where to write the key material H(h(x)yG)
1068 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1071 GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1072 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1073 struct GNUNET_HashCode *key_material)
1075 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1076 uint8_t d_rev[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1078 BENCHMARK_START (ecdsa_ecdh);
1079 for (size_t i = 0; i < 32; i++)
1080 d_rev[i] = priv->d[31 - i];
1081 GNUNET_TWEETNACL_scalarmult_curve25519 (p, d_rev, pub->q_y);
1082 GNUNET_CRYPTO_hash (p,
1083 GNUNET_TWEETNACL_SCALARMULT_BYTES,
1085 BENCHMARK_END (ecdsa_ecdh);
1092 * Derive key material from a EdDSA public key and a private ECDH key.
1093 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1095 * @param priv private key to use for the ECDH (y)
1096 * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1097 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1098 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1101 GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1102 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1103 struct GNUNET_HashCode *key_material)
1105 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1106 uint8_t curve25510_pk[GNUNET_TWEETNACL_SIGN_PUBLICBYTES];
1108 GNUNET_TWEETNACL_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y);
1109 GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, curve25510_pk);
1110 GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material);
1117 * Derive key material from a ECDSA public key and a private ECDH key.
1118 * Dual to #GNUNET_CRYPTO_ecdsa_ecdh.
1120 * @param priv private key to use for the ECDH (y)
1121 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1122 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1123 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1126 GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1127 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1128 struct GNUNET_HashCode *key_material)
1130 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1131 uint8_t curve25510_pk[GNUNET_TWEETNACL_SIGN_PUBLICBYTES];
1133 GNUNET_TWEETNACL_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y);
1134 GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, curve25510_pk);
1135 GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material);
1140 /* end of crypto_ecc.c */