gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] branch master updated (93b049ebd -> 992199ecf)


From: gnunet
Subject: [gnunet] branch master updated (93b049ebd -> 992199ecf)
Date: Wed, 28 Feb 2024 20:12:38 +0100

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a change to branch master
in repository gnunet.

    from 93b049ebd CRYPTO: Improve comments for ECC DH
     new 63c366f44 util: initial elligator implementation
     new 992199ecf util: add gmp dependency to meson

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 meson.build                          |   4 +
 src/include/gnunet_crypto_lib.h      |  97 +++++
 src/lib/util/Makefile.am             |   8 +
 src/lib/util/crypto_elligator.c      | 702 +++++++++++++++++++++++++++++++++++
 src/lib/util/meson.build             |  12 +
 src/lib/util/test_crypto_elligator.c | 334 +++++++++++++++++
 6 files changed, 1157 insertions(+)
 create mode 100644 src/lib/util/crypto_elligator.c
 create mode 100644 src/lib/util/test_crypto_elligator.c

diff --git a/meson.build b/meson.build
index 10937517f..3547d9cfa 100644
--- a/meson.build
+++ b/meson.build
@@ -178,6 +178,10 @@ gcrypt_dep = dependency('libgcrypt', required : false)
 if not gcrypt_dep.found()
   gcrypt_dep = cc.find_library('gcrypt', required : true)
 endif
+lgmp_dep = dependency('libgmp', required : false)
+if not lgmp_dep.found()
+  lgmp_dep = cc.find_library('gmp', required : true)
+endif
 gnutls_dep = dependency('libgnutls', required : false)
 if not gnutls_dep.found()
   gnutls_dep = cc.find_library('gnutls', required : false)
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h
index 2c7e92fbd..5425a18dd 100644
--- a/src/include/gnunet_crypto_lib.h
+++ b/src/include/gnunet_crypto_lib.h
@@ -348,6 +348,18 @@ struct GNUNET_CRYPTO_Edx25519Signature
   unsigned char s[256 / 8];
 };
 
+/**
+ * Elligator representative (always for Curve25519)
+ */
+struct GNUNET_CRYPTO_ElligatorRepresentative
+{
+  /**
+   * Represents an element of Curve25519 finite field.
+   * Always smaller than 2 ^ 254 - 10 -> Needs to be serialized into a 
random-looking byte stream before transmission.
+   */
+  unsigned char r[256 / 8];
+};
+
 /**
  * Key type for the generic public key union
  */
@@ -2652,6 +2664,91 @@ GNUNET_CRYPTO_edx25519_public_key_derive (
   size_t seedsize,
   struct GNUNET_CRYPTO_Edx25519PublicKey *result);
 
+/**
+ * Note: Included in header for testing purposes. 
GNUNET_CRYPTO_ecdhe_elligator_decoding will be the correct API for the direct 
map.
+ * TODO: Make static.
+ * @ingroup crypto
+ * Encodes an element of the underlying finite field, so called 
representative, of Curve25519 to a point on the curve
+ * This transformation is deterministic
+ *
+ * @param representative element of the finite field
+ * @param point destination for the calculated point on the curve
+ * @param high_y destination set to "True" if corresponding y-coordinate is > 
2 ^ 254 - 10
+ */
+bool
+GNUNET_CRYPTO_ecdhe_elligator_direct_map (uint8_t *point, bool *high_y,
+                                          uint8_t *representative);
+
+
+/**
+ * @ingroup crypto
+ * Clears the most significant bit and second most significant bit to the 
serialized representaive before applying elligator direct map.
+ *
+ * @param serialized_representative serialized version of an element of 
Curves25519's finite field
+ * @param point destination for the calculated point on the curve
+ * @param high_y destination set to "True" if corresponding y-coordinate is > 
2 ^ 254 - 10
+ */
+bool
+GNUNET_CRYPTO_ecdhe_elligator_decoding (struct
+                                        GNUNET_CRYPTO_EcdhePublicKey *point,
+                                        bool *high_y,
+                                        struct
+                                        GNUNET_CRYPTO_ElligatorRepresentative *
+                                        seriliazed_representative);
+
+/**
+ * @ingroup crypto
+ * Encodes a point on Curve25519 to a an element of the underlying finite field
+ * This transformation is deterministic
+ *
+ * @param point a point on the curve
+ * @param high_y encodes if y-coordinate is > 2 ^254 - 10, which determines 
the representative value out of two
+ * @param representative destination for the calculated element of the finite 
field
+ */
+bool
+GNUNET_CRYPTO_ecdhe_elligator_inverse_map (uint8_t *representative, const
+                                           uint8_t *point,
+                                           bool high_y);
+
+
+/**
+* Initializes the elligator library
+* THis function is thread safe
+*/
+void
+GNUNET_CRYPTO_ecdhe_elligator_initialize (void);
+
+/**
+ * @ingroup crypto
+ * Generates a valid public key for elligator's inverse map by adding a lower 
order point to a prime order point.
+ *
+ * @param pub valid public key for elligator inverse map
+ * @param pk private key for generating valid public key
+ */
+int
+  GNUNET_CRYPTO_ecdhe_elligator_generate_public_key (unsigned char
+                                                     pub[
+                                                       
crypto_scalarmult_SCALARBYTES
+                                                     ],
+                                                     struct
+                                                     
GNUNET_CRYPTO_EcdhePrivateKey
+                                                     *pk);
+
+
+/**
+ * @ingroup crypto
+ * Generates a private key for Curve25519 and the elligator representative of 
the corresponding public key
+ *
+ * @param repr representative of the public key
+ * @param pk Curve25519 private key
+ */
+int
+GNUNET_CRYPTO_ecdhe_elligator_key_create (struct
+                                          GNUNET_CRYPTO_ElligatorRepresentative
+                                          *repr,
+                                          struct GNUNET_CRYPTO_EcdhePrivateKey
+                                          *pk);
+
 
 /**
  * Output the given MPI value to the given buffer in network
diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am
index 6facc5921..f7716cd48 100644
--- a/src/lib/util/Makefile.am
+++ b/src/lib/util/Makefile.am
@@ -60,6 +60,7 @@ libgnunetutil_la_SOURCES = \
   $(DLOG) \
   crypto_ecc_setup.c \
   crypto_edx25519.c \
+  crypto_elligator.c \
   crypto_hash.c \
   crypto_hash_file.c \
   crypto_hkdf.c \
@@ -207,6 +208,7 @@ check_PROGRAMS = \
  test_crypto_ecdh_eddsa \
  test_crypto_ecdh_ecdsa \
  test_crypto_edx25519 \
+ test_crypto_elligator \
  $(DLOG_TEST) \
  test_crypto_hash \
  test_crypto_hash_context \
@@ -387,6 +389,12 @@ test_crypto_edx25519_LDADD = \
  libgnunetutil.la \
  $(LIBGCRYPT_LIBS)
 
+ test_crypto_elligator_SOURCES = \
+ test_crypto_elligator.c
+test_crypto_elligator_LDADD = \
+ libgnunetutil.la \
+ $(LIBGCRYPT_LIBS)
+
 test_crypto_ecc_dlog_SOURCES = \
  test_crypto_ecc_dlog.c
 test_crypto_ecc_dlog_LDADD = \
diff --git a/src/lib/util/crypto_elligator.c b/src/lib/util/crypto_elligator.c
new file mode 100644
index 000000000..142c0782a
--- /dev/null
+++ b/src/lib/util/crypto_elligator.c
@@ -0,0 +1,702 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2002-2013 GNUnet e.V.
+
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Affero General Public License for more details.
+
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
+
+
+    Portions of this code are derived from the Elligator-2 project,
+    which is licensed under the Creative Commons CC0 1.0 Universal Public 
Domain Dedication.
+    The Elligator-2 project can be found at: 
https://github.com/Kleshni/Elligator-2
+
+    Note that gmp is already a dependency of GnuTLS
+
+*/
+
+#include "platform.h"
+#include <gcrypt.h>
+#include <sodium.h>
+#include "gnunet_util_lib.h"
+#include "benchmark.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gmp.h>
+
+// Ed25519 subgroup of points with a low order
+static const uint8_t lookupTable[8][crypto_scalarmult_SCALARBYTES] = {
+  {
+    0x26,  0xE8,  0x95,  0x8F,  0xC2,  0xB2,  0x27,  0xB0,
+    0x45,  0xC3,  0xF4,  0x89,  0xF2,  0xEF,  0x98,  0xF0,
+    0xD5,  0xDF,  0xAC,  0x05,  0xD3,  0xC6,  0x33,  0x39,
+    0xB1,  0x38,  0x02,  0x88,  0x6D,  0x53,  0xFC,  0x05
+  },
+  {
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00
+  },
+  {
+    0xC7,  0x17,  0x6A,  0x70,  0x3D,  0x4D,  0xD8,  0x4F,
+    0xBA,  0x3C,  0x0B,  0x76,  0x0D,  0x10,  0x67,  0x0F,
+    0x2A,  0x20,  0x53,  0xFA,  0x2C,  0x39,  0xCC,  0xC6,
+    0x4E,  0xC7,  0xFD,  0x77,  0x92,  0xAC,  0x03,  0x7A
+  },
+  {
+    0xEC,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,
+    0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,
+    0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,
+    0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0xFF,  0x7F
+  },  {
+    0xC7,  0x17,  0x6A,  0x70,  0x3D,  0x4D,  0xD8,  0x4F,
+    0xBA,  0x3C,  0x0B,  0x76,  0x0D,  0x10,  0x67,  0x0F,
+    0x2A,  0x20,  0x53,  0xFA,  0x2C,  0x39,  0xCC,  0xC6,
+    0x4E,  0xC7,  0xFD,  0x77,  0x92,  0xAC,  0x03,  0xFA
+  }, {
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x80
+  }, {
+    0x26,  0xE8,  0x95,  0x8F,  0xC2,  0xB2,  0x27,  0xB0,
+    0x45,  0xC3,  0xF4,  0x89,  0xF2,  0xEF,  0x98,  0xF0,
+    0xD5,  0xDF,  0xAC,  0x05,  0xD3,  0xC6,  0x33,  0x39,
+    0xB1,  0x38,  0x02,  0x88,  0x6D,  0x53,  0xFC,  0x85
+  },{
+    0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00
+  }
+};
+
+// main.h from Kleshnis's elligator implementation
+#include <limits.h>
+
+#define P_BITS (256) // 255 significant bits + 1 for carry
+#define P_BYTES ((P_BITS + CHAR_BIT - 1) / CHAR_BIT)
+#define P_LIMBS ((P_BITS + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
+
+
+// main.c from Kleshnis's elligator implementation
+static const unsigned char p_bytes[P_BYTES] = {
+  0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f
+};
+
+static const unsigned char negative_1_bytes[P_BYTES] = {
+  0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f
+};
+
+static const unsigned char negative_2_bytes[P_BYTES] = {
+  0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f
+};
+
+static const unsigned char divide_negative_1_2_bytes[P_BYTES] = {
+  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x3f
+};
+
+static const unsigned char divide_plus_p_3_8_bytes[P_BYTES] = {
+  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x0f
+};
+
+static const unsigned char divide_minus_p_1_2_bytes[P_BYTES] = {
+  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x3f
+};
+
+static const unsigned char square_root_negative_1_bytes[P_BYTES] = {
+  0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4, 0x78, 0xe4, 0x2f, 0xad, 0x06,
+  0x18, 0x43, 0x2f,
+  0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b, 0x0b, 0xdf, 0xc1, 0x4f, 0x80,
+  0x24, 0x83, 0x2b
+};
+
+static const unsigned char A_bytes[P_BYTES] = {
+  0x06, 0x6d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00
+};
+
+static const unsigned char negative_A_bytes[P_BYTES] = {
+  0xe7, 0x92, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x7f
+};
+
+static const unsigned char u_bytes[P_BYTES] = {
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00
+};
+
+static const unsigned char inverted_u_bytes[P_BYTES] = {
+  0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff,
+  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+  0xff, 0xff, 0x3f
+};
+
+static const unsigned char d_bytes[P_BYTES] = {
+  0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 0xab, 0xd8, 0x41, 0x41, 0x4d,
+  0x0a, 0x70, 0x00,
+  0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 0x73, 0xfe, 0x6f, 0x2b, 0xee,
+  0x6c, 0x03, 0x52
+};
+
+static mp_limb_t p[P_LIMBS];
+static mp_limb_t negative_1[P_LIMBS];
+static mp_limb_t negative_2[P_LIMBS];
+static mp_limb_t divide_negative_1_2[P_LIMBS];
+static mp_limb_t divide_plus_p_3_8[P_LIMBS];
+static mp_limb_t divide_minus_p_1_2[P_LIMBS];
+static mp_limb_t square_root_negative_1[P_LIMBS];
+static mp_limb_t A[P_LIMBS];
+static mp_limb_t negative_A[P_LIMBS];
+static mp_limb_t u[P_LIMBS];
+static mp_limb_t inverted_u[P_LIMBS];
+static mp_limb_t d[P_LIMBS];
+
+static mp_size_t scratch_space_length;
+
+static void
+decode_bytes (mp_limb_t *number, const uint8_t *bytes)
+{
+  mp_limb_t scratch_space[1];
+
+  for (size_t i = 0; i < P_BYTES; ++i)
+  {
+    mpn_lshift (number, number, P_LIMBS, 8);
+    mpn_sec_add_1 (number, number, 1, bytes[P_BYTES - i - 1], scratch_space);
+  }
+}
+
+
+// Erases the number
+
+static void
+encode_bytes (uint8_t *bytes, mp_limb_t *number)
+{
+  for (size_t i = 0; i < P_BYTES; ++i)
+  {
+    bytes[P_BYTES - i - 1] = mpn_lshift (number, number, P_LIMBS, 8);
+  }
+}
+
+
+void
+GNUNET_CRYPTO_ecdhe_elligator_initialize (void)
+{
+  static bool initialized = false;
+
+  if (initialized)
+  {
+    return;
+  }
+
+  decode_bytes (p, p_bytes);
+  decode_bytes (negative_1, negative_1_bytes);
+  decode_bytes (negative_2, negative_2_bytes);
+  decode_bytes (divide_negative_1_2, divide_negative_1_2_bytes);
+  decode_bytes (divide_plus_p_3_8, divide_plus_p_3_8_bytes);
+  decode_bytes (divide_minus_p_1_2, divide_minus_p_1_2_bytes);
+  decode_bytes (square_root_negative_1, square_root_negative_1_bytes);
+  decode_bytes (A, A_bytes);
+  decode_bytes (negative_A, negative_A_bytes);
+  decode_bytes (u, u_bytes);
+  decode_bytes (inverted_u, inverted_u_bytes);
+  decode_bytes (d, d_bytes);
+
+  mp_size_t scratch_space_lengths[] = {
+    // For least_square_root
+
+    mpn_sec_powm_itch (P_LIMBS, P_BITS - 1, P_LIMBS),
+    mpn_sec_sqr_itch (P_LIMBS),
+    mpn_sec_div_r_itch (P_LIMBS + P_LIMBS, P_LIMBS),
+    mpn_sec_sub_1_itch (P_LIMBS),
+    mpn_sec_mul_itch (P_LIMBS, P_LIMBS),
+
+    // For Elligator_2_Curve25519_encode
+
+    mpn_sec_powm_itch (P_LIMBS, P_BITS - 1, P_LIMBS),
+    mpn_sec_mul_itch (P_LIMBS, P_LIMBS),
+    mpn_sec_div_r_itch (P_LIMBS + P_LIMBS, P_LIMBS),
+    mpn_sec_sqr_itch (P_LIMBS),
+    mpn_sec_sub_1_itch (P_LIMBS),
+
+    // For Elligator_2_Curve25519_decode
+
+    mpn_sec_sqr_itch (P_LIMBS),
+    mpn_sec_div_r_itch (P_LIMBS + P_LIMBS, P_LIMBS),
+    mpn_sec_div_r_itch (P_LIMBS, P_LIMBS),
+    mpn_sec_mul_itch (P_LIMBS, P_LIMBS),
+    mpn_sec_add_1_itch (P_LIMBS),
+    mpn_sec_powm_itch (P_LIMBS, P_BITS - 1, P_LIMBS),
+
+    // For Elligator_2_Curve25519_convert_from_Ed25519
+    /*
+    mpn_sec_sqr_itch (P_LIMBS),
+    mpn_sec_div_r_itch (P_LIMBS + P_LIMBS, P_LIMBS),
+    mpn_sec_mul_itch (P_LIMBS, P_LIMBS),
+    mpn_sec_add_1_itch (P_LIMBS),
+    mpn_sec_powm_itch (P_LIMBS, P_BITS - 1, P_LIMBS),
+    mpn_sec_sub_1_itch (P_LIMBS)
+    */
+  };
+
+  for (size_t i = 0; i < sizeof scratch_space_lengths
+       / sizeof *scratch_space_lengths; ++i)
+  {
+    if (scratch_space_lengths[i] > scratch_space_length)
+    {
+      scratch_space_length = scratch_space_lengths[i];
+    }
+  }
+
+  initialized = true;
+}
+
+
+// Returns trash if the number is a quadratic non-residue
+
+static void
+least_square_root (mp_limb_t *root, const mp_limb_t *number,
+                   mp_limb_t *scratch_space)
+{
+  mp_limb_t a[P_LIMBS + P_LIMBS];
+  mp_limb_t b[P_LIMBS];
+
+  // root := number ^ ((p + 3) / 8)
+
+  mpn_add_n (b, number, p, P_LIMBS); // The next function requires a nonzero 
input
+  mpn_sec_powm (root, b, P_LIMBS, divide_plus_p_3_8, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+
+  // If root ^ 2 != number, root := root * square_root(-1)
+
+  mpn_sec_sqr (a, root, P_LIMBS, scratch_space);
+  mpn_sec_div_r (a, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_sub_n (b, a, number, P_LIMBS);
+
+  mp_limb_t condition = mpn_sec_sub_1 (b, b, P_LIMBS, 1, scratch_space) ^ 1;
+
+  mpn_sec_mul (a, root, P_LIMBS, square_root_negative_1, P_LIMBS,
+               scratch_space);
+  mpn_sec_div_r (a, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+
+  mpn_cnd_swap (condition, root, a, P_LIMBS);
+
+  // If root > (p - 1) / 2, root := -root
+
+  condition = mpn_sub_n (a, divide_minus_p_1_2, root, P_LIMBS);
+
+  mpn_sub_n (a, p, root, P_LIMBS); // If root = 0, a := p
+
+  mpn_cnd_swap (condition, root, a, P_LIMBS);
+}
+
+
+bool
+GNUNET_CRYPTO_ecdhe_elligator_inverse_map (uint8_t *representative, const
+                                           uint8_t *point,
+                                           bool high_y)
+{
+  mp_limb_t scratch_space[scratch_space_length];
+
+  mp_limb_t a[P_LIMBS + P_LIMBS];
+  mp_limb_t b[P_LIMBS + P_LIMBS];
+  mp_limb_t c[P_LIMBS + P_LIMBS];
+
+  // a := point
+
+  decode_bytes (a, point);
+
+  // b := -a / (a + A), or b := p if a = 0
+
+  mpn_add_n (b, a, A, P_LIMBS);
+  mpn_sec_powm (c, b, P_LIMBS, negative_2, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+  mpn_sec_mul (b, c, P_LIMBS, a, P_LIMBS, scratch_space);
+  mpn_sec_div_r (b, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_sub_n (b, p, b, P_LIMBS);
+
+  // If high_y = true, b := 1 / b or b := 0 if it was = p
+
+  mpn_sec_powm (c, b, P_LIMBS, negative_2, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+  mpn_cnd_swap (high_y, b, c, P_LIMBS);
+
+  // c := b / u
+
+  mpn_sec_mul (c, b, P_LIMBS, inverted_u, P_LIMBS, scratch_space);
+  mpn_sec_div_r (c, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+
+  // If c is a square modulo p, b := least_square_root(c)
+
+  least_square_root (b, c, scratch_space);
+
+  // Determine, whether b ^ 2 = c
+
+  mpn_sec_sqr (a, b, P_LIMBS, scratch_space);
+  mpn_sec_div_r (a, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_sub_n (a, a, c, P_LIMBS);
+
+  bool result = mpn_sec_sub_1 (a, a, P_LIMBS, 1, scratch_space);
+
+  encode_bytes (representative, b);
+
+  return result;
+}
+
+
+bool
+GNUNET_CRYPTO_ecdhe_elligator_direct_map (uint8_t *point, bool *high_y,
+                                          uint8_t *representative)
+{
+  mp_limb_t scratch_space[scratch_space_length];
+
+  mp_limb_t a[P_LIMBS + P_LIMBS];
+  mp_limb_t b[P_LIMBS + P_LIMBS];
+  mp_limb_t c[P_LIMBS];
+  mp_limb_t e[P_LIMBS + P_LIMBS];
+
+  // a := representative
+
+  decode_bytes (a, representative);
+
+  // Determine whether a < (p - 1) / 2
+
+  bool result = mpn_sub_n (b, divide_minus_p_1_2, a, P_LIMBS) ^ 1;
+
+  // b := -A / (1 + u * a ^ 2)
+
+  mpn_sec_sqr (b, a, P_LIMBS, scratch_space);
+  mpn_sec_div_r (b, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_sec_mul (a, u, P_LIMBS, b, P_LIMBS, scratch_space);
+  mpn_sec_div_r (a, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_sec_add_1 (b, a, P_LIMBS, 1, scratch_space);
+  mpn_sec_powm (a, b, P_LIMBS, negative_2, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+  mpn_sec_mul (b, a, P_LIMBS, negative_A, P_LIMBS, scratch_space);
+  mpn_sec_div_r (b, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+
+  // a := b ^ 3 + A * b ^ 2 + b (with 1-bit overflow)
+
+  mpn_sec_sqr (a, b, P_LIMBS, scratch_space);
+  mpn_sec_div_r (a, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_add_n (c, b, A, P_LIMBS);
+  mpn_sec_mul (e, c, P_LIMBS, a, P_LIMBS, scratch_space);
+  mpn_sec_div_r (e, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_add_n (a, e, b, P_LIMBS);
+
+  // If a is a quadratic residue modulo p, point := b and high_y := 1
+  // Otherwise point := -b - A and high_y := 0
+
+  mpn_sub_n (c, p, b, P_LIMBS);
+  mpn_add_n (c, c, negative_A, P_LIMBS);
+  mpn_sec_div_r (c, P_LIMBS, p, P_LIMBS, scratch_space);
+
+  mpn_sec_powm (e, a, P_LIMBS, divide_minus_p_1_2, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+  *high_y = mpn_sub_n (e, e, divide_minus_p_1_2, P_LIMBS);
+
+  mpn_cnd_swap (*high_y, b, c, P_LIMBS);
+
+  encode_bytes (point, c);
+
+  return result;
+}
+
+
+// Removes most significant bit and second most significant bit before 
applying elligator direct map
+bool
+GNUNET_CRYPTO_ecdhe_elligator_decoding (struct
+                                        GNUNET_CRYPTO_EcdhePublicKey *point,
+                                        bool *high_y,
+                                        struct
+                                        GNUNET_CRYPTO_ElligatorRepresentative *
+                                        representative)
+{
+  representative->r[31] &= 63;
+  return GNUNET_CRYPTO_ecdhe_elligator_direct_map ((uint8_t *) point->q_y,
+                                                   high_y,
+                                                   (uint8_t *) 
representative->r);
+}
+
+
+static bool
+Elligator_2_Curve25519_convert_from_Ed25519 (uint8_t *point, const
+                                             uint8_t *source)
+{
+  mp_limb_t scratch_space[scratch_space_length];
+
+  mp_limb_t y[P_LIMBS];
+  mp_limb_t a[P_LIMBS + P_LIMBS];
+  mp_limb_t b[P_LIMBS + P_LIMBS];
+  mp_limb_t c[P_LIMBS + P_LIMBS];
+
+  uint8_t y_bytes[P_BYTES];
+
+  memcpy (y_bytes, source, 31);
+
+  y_bytes[31] = source[31] & 0x7f;
+
+  decode_bytes (y, y_bytes);
+
+  // Check if y < p
+
+  bool result = mpn_sub_n (a, y, p, P_LIMBS);
+
+  // a := (y ^ 2 - 1) / (1 + d * y ^ 2)
+
+  mpn_sec_sqr (a, y, P_LIMBS, scratch_space);
+  mpn_sec_div_r (a, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_sec_mul (b, a, P_LIMBS, d, P_LIMBS, scratch_space);
+  mpn_sec_add_1 (b, b, P_LIMBS, 1, scratch_space);
+  mpn_sec_div_r (b, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+  mpn_sec_powm (c, b, P_LIMBS, negative_2, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+  mpn_add_n (b, a, negative_1, P_LIMBS);
+  mpn_sec_mul (a, b, P_LIMBS, c, P_LIMBS, scratch_space);
+  mpn_sec_div_r (a, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+
+  // Check, whether a is a square modulo p (including a = 0)
+
+  mpn_add_n (a, a, p, P_LIMBS);
+  mpn_sec_powm (b, a, P_LIMBS, divide_negative_1_2, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+
+  result &= mpn_sub_n (c, b, divide_minus_p_1_2, P_LIMBS);
+
+  // If a = p, the parity bit must be 0
+
+  mpn_sub_n (a, a, p, P_LIMBS);
+
+  result ^= mpn_sec_sub_1 (a, a, P_LIMBS, 1, scratch_space) & source[31] >> 7;
+
+  // If y != 1, c := (1 + y) / (1 - y), otherwise c := 0
+
+  mpn_sub_n (a, p, y, P_LIMBS);
+  mpn_sec_add_1 (a, a, P_LIMBS, 1, scratch_space);
+  mpn_sec_powm (b, a, P_LIMBS, negative_2, P_BITS - 1, p, P_LIMBS,
+                scratch_space);
+  mpn_sec_add_1 (a, y, P_LIMBS, 1, scratch_space);
+  mpn_sec_mul (c, a, P_LIMBS, b, P_LIMBS, scratch_space);
+  mpn_sec_div_r (c, P_LIMBS + P_LIMBS, p, P_LIMBS, scratch_space);
+
+  encode_bytes (point, c);
+
+  return result;
+}
+
+
+// Would call GNUNET_CRYPTO_ecdhe_key_create (struct 
GNUNET_CRYPTO_EcdhePrivateKey *pk) for pk which is not clamped
+// Following Method 1 in description https://elligator.org/key-exchange 
section Step 2: Generate a “special” public key
+int
+GNUNET_CRYPTO_ecdhe_elligator_generate_public_key (unsigned char
+                                                   pub[
+                                                     
crypto_scalarmult_SCALARBYTES
+                                                   ],
+                                                   struct
+                                                   
GNUNET_CRYPTO_EcdhePrivateKey
+                                                   *pk)
+{
+  // eHigh
+  // Note crypto_scalarmult_ed25519_base clamps the scalar (here pk->d). TODO: 
test this
+  // TODO: if pk-d is zero cryto_scalarmult... return -1, otherwise 0. Problem 
if 0? Unlikely anyway
+  unsigned char eHigh[crypto_scalarmult_SCALARBYTES] = {0};
+  crypto_scalarmult_ed25519_base (eHigh, pk->d);
+
+  // eLow: choose a random point of low order
+  int sLow = (pk->d)[0] % 8;
+  unsigned char eLow[crypto_scalarmult_SCALARBYTES] = {0};
+  memcpy (eLow, lookupTable[sLow], crypto_scalarmult_SCALARBYTES);
+
+  // eHigh + eLow
+  unsigned char edPub[crypto_scalarmult_SCALARBYTES] = {0};
+  if (crypto_core_ed25519_add (edPub, eLow, eHigh) == -1)
+  {
+    return GNUNET_SYSERR;
+  }
+
+  // Convert point in Ed25519 to Montgomery point
+  // TODO: libsodium convert function doesn't work. Figure out why. Maybe 
because we work on the whole curve rather than the prime subgroup.
+  /*if (crypto_sign_ed25519_pk_to_curve25519 (pub, edPub) == -1)
+  {
+    return -1;
+  }*/
+
+  if (Elligator_2_Curve25519_convert_from_Ed25519 (pub, edPub) == false)
+  {
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+Doesn't work because crypto_scalarmult clamps the scalar. We don't want this.
+Unfortunately a "noclamp" version of multiplication is only available for 
edwards25519 in libsodium.
+We therefore can't implement the second (alternative) method for 
generate_public_key.
+Keeping this code for discussion. Delete later.
+
+// Curve25519 point (only x-coordinate) which is needed for the alternativ 
method of
+//GNUNET_CRYPTO_ecdhe_elligator_generate_public_key_alternativ
+static const unsigned char kPoint[] = {
+  0xD8, 0x86, 0x1A, 0xA2, 0x78, 0x7A, 0xD9, 0x26,
+  0x8B, 0x74, 0x74, 0xB6, 0x82, 0xE3, 0xBE, 0xC3,
+  0xCE, 0x36, 0x9A, 0x1E, 0x5E, 0x31, 0x47, 0xA2,
+  0x6D, 0x37, 0x7C, 0xFD, 0x20, 0xB5, 0xDF, 0x75
+};
+
+// Curve25519 order of prime order subgroup
+static const unsigned char L[] = {
+  0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58,
+  0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
+};
+
+static void multiplyLittleEndianArray(const unsigned char *input, int 
multiplier, unsigned char *output, int arraySize) {
+    int carry = 0;
+
+    for (int i = 0; i < arraySize; ++i) {
+        int result = input[i] * multiplier + carry;
+        output[i] = result & 0xFF;  // Store the lower 8 bits in the output 
array
+        carry = result >> 8;        // Carry the remaining bits to the next 
iteration
+    }
+}
+
+static void addLittleEndianArrays(const unsigned char *array1, const unsigned 
char *array2, unsigned char *result, int arraySize) {
+    int carry = 0;
+
+    for (int i = 0; i < arraySize; ++i) {
+        int sum = array1[i] + array2[i] + carry;
+        result[i] = sum & 0xFF;  // Store the lower 8 bits in the result array
+        carry = sum >> 8;        // Carry the remaining bits to the next 
iteration
+    }
+}
+
+Would call GNUNET_CRYPTO_ecdhe_key_create (struct 
GNUNET_CRYPTO_EcdhePrivateKey *pk) for pk which is not clamped
+Following Method 1 in description https://elligator.org/key-exchange section 
Step 2: Generate a “special” public key
+int
+GNUNET_CRYPTO_ecdhe_elligator_generate_public_key_alternativ (unsigned char
+                                                   pub[
+                                                     
crypto_scalarmult_SCALARBYTES
+                                                   ],
+                                                   struct
+                                                   
GNUNET_CRYPTO_EcdhePrivateKey
+                                                   *pk)
+{
+  unsigned char sClamp[crypto_scalarmult_BYTES] = {0};
+  memcpy(sClamp, pk->d, sizeof(sClamp));
+  sClamp[0] &= 248;
+  sClamp[31] &= 127;
+  sClamp[31] |= 64;
+
+  unsigned char sLow[crypto_scalarmult_BYTES] = {0};
+  int multiplier = (pk->d)[0] % 8;
+  multiplyLittleEndianArray(L, multiplier, sLow, 32);
+  unsigned char sDirty[crypto_scalarmult_BYTES] = {0};
+  addLittleEndianArrays(sClamp, sLow, sDirty, 32);
+
+  int check =  crypto_scalarmult(pub, sDirty,
+                      kPoint);
+
+  if (check == -1)
+  {
+    printf("crypto_scalarmult didn't work\n");
+    return -1;
+  }
+
+  return 0;
+}
+**/
+
+enum GNUNET_GenericReturnValue
+GNUNET_CRYPTO_ecdhe_elligator_key_create (struct
+                                          GNUNET_CRYPTO_ElligatorRepresentative
+                                          *
+                                          repr,
+                                          struct GNUNET_CRYPTO_EcdhePrivateKey
+                                          *pk)
+{
+  // inverse map can fail for some public keys generated by 
GNUNET_CRYPTO_ecdhe_elligator_generate_public_key
+  bool validKey = 0;
+  unsigned char pub[crypto_scalarmult_SCALARBYTES];
+  int8_t random_tweak;
+  bool high_y;
+  bool msb_set;
+  bool smsb_set;
+
+  while (! validKey)
+  {
+    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                                pk,
+                                sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+    if (GNUNET_CRYPTO_ecdhe_elligator_generate_public_key (pub, pk) ==
+        GNUNET_SYSERR)
+    {
+      return GNUNET_SYSERR;
+    }
+
+    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                                &random_tweak,
+                                sizeof(int8_t));
+    high_y = random_tweak & 1;
+
+    validKey = GNUNET_CRYPTO_ecdhe_elligator_inverse_map ((unsigned
+                                                           char*) &(repr->r),
+                                                          (unsigned char*) pub,
+                                                          high_y ?
+                                                          GNUNET_YES :
+                                                          GNUNET_NO);
+  }
+
+  // Setting most significant bit and second most significant bit randomly
+  msb_set = (random_tweak >> 1) & 1;
+  smsb_set = (random_tweak >> 2) & 1;
+  if (msb_set)
+  {
+    repr->r[31] |= 128;
+  }
+  if (smsb_set)
+  {
+    repr->r[31] |= 64;
+  }
+  return GNUNET_OK;
+}
\ No newline at end of file
diff --git a/src/lib/util/meson.build b/src/lib/util/meson.build
index c9a73bdd3..cc7c20201 100644
--- a/src/lib/util/meson.build
+++ b/src/lib/util/meson.build
@@ -27,6 +27,7 @@ libgnunetutil_src = ['bandwidth.c',
        'crypto_ecc_dlog.c',
        'crypto_ecc_setup.c',
        'crypto_edx25519.c',
+       'crypto_elligator.c',
        'crypto_hash.c',
        'crypto_hash_file.c',
        'crypto_hkdf.c',
@@ -83,6 +84,7 @@ libgnunetutil = library('gnunetutil',
         soversion: '15',
         version: '15.0.0',
         dependencies: [
+          lgmp_dep,
           mhd_dep,
           sodium_dep,
           gcrypt_dep,
@@ -331,6 +333,16 @@ test('test_crypto_ecc_dlog', testcrypto_ecc_dlog,
      workdir: meson.current_build_dir(),
      suite: ['util', 'util-crypto'])
 
+testcrypto_elligator = executable ('test_crypto_elligator',
+            ['test_crypto_elligator.c'],
+            dependencies: [gcrypt_dep, libgnunetutil_dep, lgmp_dep, 
sodium_dep],
+            include_directories: [incdir, configuration_inc],
+            build_by_default: false,
+            install: false)
+test('test_crypto_elligator', testcrypto_elligator,
+     workdir: meson.current_build_dir(),
+     suite: ['util', 'util-crypto'])
+
 testcrypto_hash = executable ('test_crypto_hash',
                               ['test_crypto_hash.c'],
                               dependencies: [gcrypt_dep, libgnunetutil_dep],
diff --git a/src/lib/util/test_crypto_elligator.c 
b/src/lib/util/test_crypto_elligator.c
new file mode 100644
index 000000000..fc541887d
--- /dev/null
+++ b/src/lib/util/test_crypto_elligator.c
@@ -0,0 +1,334 @@
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_signatures.h"
+#include <gcrypt.h>
+#include <stdio.h>
+#include <sodium.h>
+
+#define ITER 25
+
+// For debugging purposes
+static void
+printLittleEndianHex (const unsigned char *arr, size_t length)
+{
+  for (size_t i = 0; i < length; ++i)
+  {
+    printf ("%02X", arr[i]);
+  }
+  printf ("\n");
+}
+
+
+// Test vector from 
https://github.com/Kleshni/Elligator-2/blob/master/test-vectors.c
+static int
+testDirectMap (void)
+{
+  int ok = GNUNET_OK;
+
+  uint8_t repr1[32] = {
+    0x17, 0x9f, 0x24, 0x73, 0x0d, 0xed, 0x2c, 0xe3, 0x17, 0x39, 0x08, 0xec,
+    0x61, 0x96, 0x46, 0x53,
+    0xb8, 0x02, 0x7e, 0x38, 0x3f, 0x40, 0x34, 0x6c, 0x1c, 0x9b, 0x4d, 0x2b,
+    0xdb, 0x1d, 0xb7, 0x6c
+  };
+
+  uint8_t point1[32] = {
+    0x10, 0x74, 0x54, 0x97, 0xd3, 0x5c, 0x6e, 0xde, 0x6e, 0xa6, 0xb3, 0x30,
+    0x54, 0x6a, 0x6f, 0xcb,
+    0xf1, 0x5c, 0x90, 0x3a, 0x7b, 0xe2, 0x8a, 0xe6, 0x9b, 0x1c, 0xa1, 0x4e,
+    0x0b, 0xf0, 0x9b, 0x60
+  };
+
+  uint8_t pointResult[32];
+  bool highYResult;
+  bool isLeastSqrRoot = GNUNET_CRYPTO_ecdhe_elligator_direct_map (pointResult,
+                                                                  &highYResult,
+                                                                  repr1);
+
+  if (isLeastSqrRoot == false)
+  {
+    ok = GNUNET_OK;
+  }
+  if (memcmp (point1,pointResult,sizeof(point1)) != 0)
+  {
+    ok = GNUNET_SYSERR;
+  }
+
+  return ok;
+}
+
+
+// Test vector from 
https://github.com/Kleshni/Elligator-2/blob/master/test-vectors.c
+static int
+testInverseMap (void)
+{
+  int ok = GNUNET_OK;
+  uint8_t point1[32] = {
+    0x33, 0x95, 0x19, 0x64, 0x00, 0x3c, 0x94, 0x08, 0x78, 0x06, 0x3c, 0xcf,
+    0xd0, 0x34, 0x8a, 0xf4,
+    0x21, 0x50, 0xca, 0x16, 0xd2, 0x64,0x6f, 0x2c, 0x58, 0x56, 0xe8, 0x33, 
0x83,
+    0x77, 0xd8, 0x00
+  };
+
+  uint8_t repr1[32] = {
+    0x99, 0x9b, 0x59, 0x1b, 0x66, 0x97, 0xd0, 0x74, 0xf2, 0x66, 0x19, 
0x22,0x77,
+    0xd5, 0x54, 0xde,
+    0xc3, 0xc2, 0x4c, 0x2e,0xf6, 0x10, 0x81, 0x01, 0xf6, 0x3d, 0x94, 0xf7, 
0xff,
+    0xf3, 0xa0, 0x13
+  };
+
+  uint8_t reprResult1[32];
+  bool yHigh1 = false;
+  bool success = GNUNET_CRYPTO_ecdhe_elligator_inverse_map (reprResult1,
+                                                            point1,
+                                                            yHigh1);
+  if (success == false)
+  {
+    ok = GNUNET_SYSERR;
+  }
+  if (memcmp (repr1,reprResult1,sizeof(repr1)) != 0)
+  {
+    ok = GNUNET_SYSERR;
+  }
+
+  return ok;
+}
+
+
+/*
+* Test description: GNUNET_CRYPTO_ecdhe_elligator_generate_public_key() 
projects a point from the prime subgroup to the whole curve.
+* Both, the original point and the projectes point, should result in the same 
point when multiplied with a clamped scalar.
+*/
+static int
+testGeneratePkScalarMult (void)
+{
+  struct GNUNET_CRYPTO_EcdhePrivateKey pk;
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                              &pk,
+                              sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+
+  unsigned char pubWholeCurve[crypto_scalarmult_SCALARBYTES];
+  unsigned char pubPrimeCurve[crypto_scalarmult_SCALARBYTES];
+
+  if (GNUNET_CRYPTO_ecdhe_elligator_generate_public_key (pubWholeCurve, &pk) ==
+      -1)
+  {
+    return GNUNET_SYSERR;
+  }
+  crypto_scalarmult_base (pubPrimeCurve, pk.d);
+
+  // printf ("pubWholeCurve\n");
+  // printLittleEndianHex (pubWholeCurve,32);
+  // printf ("pubPrimeCurve\n");
+  // printLittleEndianHex (pubPrimeCurve,32);
+  // TODO: Currently utilizing ecdsa function for ecdhe testing, due to 
clamping. Clean this part later.
+  struct GNUNET_CRYPTO_EcdsaPrivateKey clampedPk;
+  GNUNET_CRYPTO_ecdsa_key_create (&clampedPk);
+  crypto_scalarmult_base (pubWholeCurve, clampedPk.d);
+  crypto_scalarmult_base (pubPrimeCurve, clampedPk.d);
+  if (memcmp (pubWholeCurve, pubPrimeCurve, sizeof(pubWholeCurve)) != 0)
+  {
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/*
+* Test Description: Simply testing, if function goes through.
+*/
+static int
+testKeyPairEasy (void)
+{
+  struct GNUNET_CRYPTO_ElligatorRepresentative repr;
+  struct GNUNET_CRYPTO_EcdhePrivateKey pk;
+  int i = GNUNET_CRYPTO_ecdhe_elligator_key_create (&repr, &pk);
+  if (i == GNUNET_SYSERR)
+  {
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/*
+* Test Description: After generating a valid private key and the corresponding 
representative with
+* GNUNET_CRYPTO_ecdhe_elligator_key_create(), check if using the direct map 
results in the corresponding public key.
+*/
+static int
+testInverseDirect (void)
+{
+  struct GNUNET_CRYPTO_ElligatorRepresentative repr;
+  struct GNUNET_CRYPTO_EcdhePublicKey point;
+  struct GNUNET_CRYPTO_EcdhePrivateKey pk;
+  int i = GNUNET_CRYPTO_ecdhe_elligator_key_create (&repr, &pk);
+  if (i == -1)
+  {
+    return GNUNET_SYSERR;
+  }
+
+  unsigned char pub[crypto_scalarmult_SCALARBYTES];
+  bool highY;
+  if (GNUNET_CRYPTO_ecdhe_elligator_generate_public_key (pub, &pk) == -1)
+  {
+    return GNUNET_SYSERR;
+  }
+
+  GNUNET_CRYPTO_ecdhe_elligator_decoding (&point, &highY, &repr);
+
+  if (memcmp (pub, point.q_y, sizeof(point.q_y)) != 0)
+  {
+    return GNUNET_SYSERR;
+  }
+
+  return GNUNET_OK;
+}
+
+
+/*
+* Test Description: Measuring the time it takes to generate 25 key pairs (pk, 
representative).
+* Time value can vary because GNUNET_CRYPTO_ecdhe_elligator_key_create 
generates internally random
+* public keys which are just valid 50% of the time for elligators inverse map.
+* GNUNET_CRYPTO_ecdhe_elligator_key_create will therefore generate as many 
public keys needed
+* till a valid public key is generated.
+*/
+static int
+testTimeKeyGenerate (void)
+{
+  struct GNUNET_CRYPTO_ElligatorRepresentative repr;
+  struct GNUNET_CRYPTO_EcdhePrivateKey pk;
+  struct GNUNET_TIME_Absolute start;
+  int ok = GNUNET_OK;
+
+  fprintf (stderr, "%s", "W");
+  start = GNUNET_TIME_absolute_get ();
+
+  for (unsigned int i = 0; i < ITER; i++)
+  {
+    fprintf (stderr, "%s", ".");
+    fflush (stderr);
+    if (GNUNET_SYSERR ==
+        GNUNET_CRYPTO_ecdhe_elligator_key_create (&repr, &pk))
+    {
+      fprintf (stderr,
+               "GNUNET_CRYPTO_ecdhe_elligator_key_create SYSERR\n");
+      ok = GNUNET_SYSERR;
+    }
+    // printLittleEndianHex(repr.r,32);
+  }
+  printf ("%d encoded public keys generated in %s\n",
+          ITER,
+          GNUNET_STRINGS_relative_time_to_string (
+            GNUNET_TIME_absolute_get_duration (start),
+            GNUNET_YES));
+  return ok;
+}
+
+
+static int
+testTimeDecoding (void)
+{
+  struct GNUNET_CRYPTO_EcdhePublicKey point;
+  struct GNUNET_CRYPTO_ElligatorRepresentative repr[ITER];
+  struct GNUNET_CRYPTO_EcdhePrivateKey pk;
+  bool high_y;
+  struct GNUNET_TIME_Absolute start;
+  int ok = GNUNET_OK;
+
+  for (unsigned int i = 0; i < ITER; i++)
+  {
+    if (GNUNET_SYSERR ==
+        GNUNET_CRYPTO_ecdhe_elligator_key_create (&repr[i], &pk))
+    {
+      fprintf (stderr,
+               "GNUNET_CRYPTO_ecdhe_elligator_key_create SYSERR\n");
+      ok = GNUNET_SYSERR;
+      continue;
+    }
+  }
+
+  fprintf (stderr, "%s", "W");
+  start = GNUNET_TIME_absolute_get ();
+
+  for (unsigned int i = 0; i < ITER; i++)
+  {
+    fprintf (stderr, "%s", ".");
+    fflush (stderr);
+    if (false ==
+        GNUNET_CRYPTO_ecdhe_elligator_decoding (&point, &high_y, &repr[i]))
+    {
+      fprintf (stderr,
+               "GNUNET_CRYPTO_ecdhe_elligator_decoding SYSERR\n");
+      ok = GNUNET_SYSERR;
+      continue;
+    }
+  }
+
+  printf ("%d decoded public keys generated in %s\n",
+          ITER,
+          GNUNET_STRINGS_relative_time_to_string (
+            GNUNET_TIME_absolute_get_duration (start),
+            GNUNET_YES));
+  return ok;
+}
+
+
+/*
+*More tests to implement:
+* Adding more test vectors from different sources for inverse and direct map
+  * check if inverse map rightfully fails for points which are not "encodable"
+*/
+
+
+int
+main (int argc, char *argv[])
+{
+  GNUNET_CRYPTO_ecdhe_elligator_initialize ();
+
+  int failure_count = 0;
+
+  if (GNUNET_OK != testInverseMap ())
+  {
+    printf ("inverse failed!");
+    failure_count++;
+  }
+  if (GNUNET_OK != testDirectMap ())
+  {
+    printf ("direct failed!");
+    failure_count++;
+  }
+  if (GNUNET_OK != testGeneratePkScalarMult ())
+  {
+    printf ("generate PK failed!");
+    failure_count++;
+  }
+  if (GNUNET_OK != testKeyPairEasy ())
+  {
+    printf ("key generation doesn't work!");
+    failure_count++;
+  }
+  if (GNUNET_OK != testInverseDirect ())
+  {
+    printf ("Inverse and direct map failed!");
+    failure_count++;
+  }
+  if (GNUNET_OK != testTimeKeyGenerate ())
+  {
+    printf ("Time measurement of key generation failed!");
+    failure_count++;
+  }
+  if (GNUNET_OK != testTimeDecoding ())
+  {
+    printf ("Time measurement of decoding failed!");
+    failure_count++;
+  }
+
+  if (0 != failure_count)
+  {
+    fprintf (stderr,
+             "\n\n%d TESTS FAILED!\n\n",
+             failure_count);
+    return -1;
+  }
+  return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]