diff --git a/Makefile.am b/Makefile.am
index 8f4d249..d13e662 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,7 +5,9 @@ lib_LTLIBRARIES = \
libbrandt.la
libbrandt_la_SOURCES = \
- smc.c
+ crypto.c \
+ util.c
+
libbrandt_la_LIBADD = \
-lpari
diff --git a/crypto.c b/crypto.c
new file mode 100644
index 0000000..399cd21
--- /dev/null
+++ b/crypto.c
@@ -0,0 +1,343 @@
+/* This file is part of libbrandt.
+ * Copyright (C) 2016 GNUnet e.V.
+ *
+ * libbrandt is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libbrandt 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libbrandt. If not, see .
+ */
+
+/**
+ * @file crypto.c
+ * @brief Implementation of the crypto primitives.
+ */
+
+#include
+
+#include "crypto.h"
+#include "util.h"
+
+#define CURVE "Ed25519"
+
+/* --- RANDOM --- */
+
+void
+brandt_rand_poll ()
+{
+ static unsigned char rand_amount = 255;
+
+ if (!(rand_amount--))
+ gcry_fast_random_poll ();
+}
+
+/* --- HASHING --- */
+
+/**
+ * Hash block of given size.
+ *
+ * @param block the data to #brandt_hash, length is given as a second argument
+ * @param size the length of the data to #brandt_hash in @a block
+ * @param ret pointer to where to write the hashcode
+ */
+void
+brandt_hash (const void *block, size_t size, struct brandt_hash_code *ret)
+{
+ gcry_md_hash_buffer (GCRY_MD_SHA512, ret, block, size);
+}
+
+/* --- MPI --- */
+
+/**
+ * If target != size, move @a target bytes to the end of the size-sized
+ * buffer and zero out the first @a target - @a size bytes.
+ *
+ * @param buf original buffer
+ * @param size number of bytes in @a buf
+ * @param target target size of the buffer
+ */
+static void
+adjust (void *buf, size_t size, size_t target)
+{
+ char *p = buf;
+
+ if (size < target)
+ {
+ memmove (&p[target - size], buf, size);
+ memset (buf, 0, target - size);
+ }
+}
+
+/**
+ * Output the given MPI value to the given buffer in
+ * network byte order.
+ * The MPI @a val may not be negative.
+ *
+ * @param buf where to output to
+ * @param size number of bytes in @a buf
+ * @param val value to write to @a buf
+ */
+void
+brandt_mpi_print_unsigned (void *buf, size_t size, gcry_mpi_t val)
+{
+ size_t rsize;
+ gcry_error_t rc;
+
+ if (gcry_mpi_get_flag (val, GCRYMPI_FLAG_OPAQUE))
+ {
+ /* Store opaque MPIs left aligned into the buffer. */
+ unsigned int nbits;
+ const void *p;
+
+ p = gcry_mpi_get_opaque (val, &nbits);
+ brandt_assert (NULL != p);
+ rsize = (nbits + 7) / 8;
+ if (rsize > size)
+ rsize = size;
+ memcpy (buf, p, rsize);
+ if (rsize < size)
+ memset (((char *)buf) + rsize, 0, size - rsize);
+ }
+ else
+ {
+ /* Store regular MPIs as unsigned integers right aligned into the buffer. */
+ rsize = size;
+ rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize, val);
+ brandt_assert_gpgerr (rc);
+ adjust (buf, rsize, size);
+ }
+}
+
+/**
+ * Convert data buffer into MPI value.
+ * The buffer is interpreted as network
+ * byte order, unsigned integer.
+ *
+ * @param result where to store MPI value (allocated)
+ * @param data raw data (GCRYMPI_FMT_USG)
+ * @param size number of bytes in @a data
+ */
+void
+brandt_mpi_scan_unsigned (gcry_mpi_t *result, const void *data, size_t size)
+{
+ gcry_error_t rc;
+
+ rc = gcry_mpi_scan (result, GCRYMPI_FMT_USG, data, size, &size);
+ brandt_assert_gpgerr (rc);
+}
+
+/* --- ECDHE --- */
+
+/**
+ * Convert the given private key from the network format to the
+ * S-expression that can be used by libgcrypt.
+ *
+ * @param priv private key to decode
+ * @return NULL on error
+ */
+static gcry_sexp_t
+decode_private_ecdhe_key (const struct brandt_dhe_skey *priv)
+{
+ gcry_sexp_t result;
+ gcry_error_t rc;
+
+ rc = gcry_sexp_build (&result, NULL,
+ "(private-key(ecc(curve \"" CURVE "\")"
+ "(d %b)))",
+ (int)sizeof (priv->d), priv->d);
+ brandt_assert_gpgerr (rc);
+ return result;
+}
+
+/**
+ * Extract values from an S-expression.
+ *
+ * @param array where to store the result(s)
+ * @param sexp S-expression to parse
+ * @param topname top-level name in the S-expression that is of interest
+ * @param elems names of the elements to extract
+ * @return 0 on success
+ */
+static int
+key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, const char *topname,
+ const char *elems)
+{
+ gcry_sexp_t list;
+ gcry_sexp_t l2;
+ const char *s;
+ unsigned int i;
+ unsigned int idx;
+
+ list = gcry_sexp_find_token (sexp, topname, 0);
+ if (!list)
+ return 1;
+ l2 = gcry_sexp_cadr (list);
+ gcry_sexp_release (list);
+ list = l2;
+ if (!list)
+ return 2;
+ idx = 0;
+ for (s = elems; *s; s++, idx++)
+ {
+ l2 = gcry_sexp_find_token (list, s, 1);
+ if (!l2)
+ {
+ for (i = 0; i < idx; i++)
+ {
+ gcry_free (array[i]);
+ array[i] = NULL;
+ }
+ gcry_sexp_release (list);
+ return 3; /* required parameter not found */
+ }
+ array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release (l2);
+ if (!array[idx])
+ {
+ for (i = 0; i < idx; i++)
+ {
+ gcry_free (array[i]);
+ array[i] = NULL;
+ }
+ gcry_sexp_release (list);
+ return 4; /* required parameter is invalid */
+ }
+ }
+ gcry_sexp_release (list);
+ return 0;
+}
+
+/**
+ * Create a new private key.
+ *
+ * @param priv where to write the private key
+ */
+void
+brandt_ecdhe_key_create (struct brandt_dhe_skey *priv)
+{
+ gcry_sexp_t priv_sexp;
+ gcry_sexp_t s_keyparam;
+ gcry_mpi_t d;
+ gcry_error_t rc;
+
+ rc = gcry_sexp_build (&s_keyparam, NULL, "(genkey(ecc(curve \"" CURVE "\")"
+ "(flags)))")
+ brandt_assert_gpgerr (rc);
+ rc = gcry_pk_genkey (&priv_sexp, s_keyparam)
+ brandt_assert_gpgerr (rc);
+ gcry_sexp_release (s_keyparam);
+ rc = key_from_sexp (&d, priv_sexp, "private-key", "d")
+ brandt_assert_gpgerr (rc);
+ gcry_sexp_release (priv_sexp);
+ brandt_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
+ gcry_mpi_release (d);
+}
+
+/**
+ * Extract the public key for the given private key.
+ *
+ * @param priv the private key
+ * @param pub where to write the public key
+ */
+void
+brandt_ecdhe_key_get_public (const struct brandt_dhe_skey *priv,
+ struct brandt_dhe_pkey *pub)
+{
+ gcry_sexp_t sexp;
+ gcry_ctx_t ctx;
+ gcry_mpi_t q;
+ gcry_error_t rc;
+
+ sexp = decode_private_ecdhe_key (priv);
+ brandt_assert (NULL != sexp);
+ rc = gcry_mpi_ec_new (&ctx, sexp, NULL);
+ brandt_assert_gpgerr (rc);
+ gcry_sexp_release (sexp);
+ q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
+ brandt_assert (NULL != q);
+ brandt_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
+ gcry_mpi_release (q);
+ gcry_ctx_release (ctx);
+}
+
+/**
+ * Derive key material from a public and a private ECDHE key.
+ *
+ * @param priv private key to use for the ECDH (x)
+ * @param pub public key to use for the ECDH (yG)
+ * @param key_material where to write the key material (xyG)
+ * @return 0 on error, 1 on success
+ */
+int
+brandt_ecdhe (const struct brandt_dhe_skey *priv,
+ const struct brandt_dhe_pkey *pub,
+ struct brandt_hash_code *key_material)
+{
+ gcry_error_t rc;
+ int rc2;
+ gcry_mpi_point_t result;
+ gcry_mpi_point_t q;
+ gcry_mpi_t d;
+ gcry_ctx_t ctx;
+ gcry_sexp_t pub_sexpr;
+ gcry_mpi_t result_x;
+ unsigned char xbuf[256 / 8];
+ size_t rsize;
+
+ /* first, extract the q = dP value from the public key */
+ if (0 != gcry_sexp_build (&pub_sexpr, NULL,
+ "(public-key(ecc(curve " CURVE ")(q %b)))",
+ (int)sizeof (pub->q_y), pub->q_y))
+ return 0;
+ rc = gcry_mpi_ec_new (&ctx, pub_sexpr, NULL);
+ brandt_assert_gpgerr (rc);
+ gcry_sexp_release (pub_sexpr);
+ q = gcry_mpi_ec_get_point ("q", ctx, 0);
+
+ /* second, extract the d value from our private key */
+ brandt_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
+
+ /* then call the 'multiply' function, to compute the product */
+ result = gcry_mpi_point_new (0);
+ gcry_mpi_ec_mul (result, d, q, ctx);
+ gcry_mpi_point_release (q);
+ gcry_mpi_release (d);
+
+ /* finally, convert point to string for hashing */
+ result_x = gcry_mpi_new (256);
+ rc = gcry_mpi_ec_get_affine (result_x, NULL, result, ctx);
+ brandt_assert (0 == rc);
+ gcry_mpi_point_release (result);
+ gcry_ctx_release (ctx);
+
+ rsize = sizeof (xbuf);
+ rc2 = gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE);
+ brandt_assert (0 == rc2);
+ /* result_x can be negative here, so we do not use 'brandt_mpi_print_unsigned'
+ * as that does not include the sign bit; x should be a 255-bit
+ * value, so with the sign it should fit snugly into the 256-bit
+ * xbuf */
+ rc = gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize, result_x);
+ brandt_assert_gpgerr (rc);
+ brandt_hash (xbuf, rsize, key_material);
+ gcry_mpi_release (result_x);
+ return 1;
+}
+
+/**
+ * @ingroup crypto
+ * Clear memory that was used to store a private key.
+ *
+ * @param pk location of the key
+ */
+void
+brandt_ecdhe_key_clear (struct brandt_dhe_skey *pk)
+{
+ memset (pk, 0, sizeof (struct brandt_dhe_skey));
+}
diff --git a/crypto.h b/crypto.h
new file mode 100644
index 0000000..c7ba816
--- /dev/null
+++ b/crypto.h
@@ -0,0 +1,71 @@
+/* This file is part of libbrandt.
+ * Copyright (C) 2016 GNUnet e.V.
+ *
+ * libbrandt is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libbrandt 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libbrandt. If not, see .
+ */
+
+/**
+ * @file crypto.h
+ * @brief Interface of the crypto primitives.
+ */
+
+#ifndef _BRANDT_CRYPTO_H
+#define _BRANDT_CRYPTO_H
+
+#include
+#include
+
+/* --- RANDOM --- */
+
+
+void brandt_rand_poll ();
+
+
+
+/* --- HASHING --- */
+
+struct brandt_hash_code {
+ uint32_t bits[512 / 8 / sizeof (uint32_t)]; /* = 16 */
+};
+
+void brandt_hash (const void *block, size_t size, struct brandt_hash_code *ret);
+
+
+
+/* --- MPI --- */
+
+void brandt_mpi_print_unsigned (void *buf, size_t size, gcry_mpi_t val);
+void brandt_mpi_scan_unsigned (gcry_mpi_t *result, const void *data,
+ size_t size);
+
+
+
+/* --- ECDHE --- */
+
+struct brandt_dhe_skey {
+ unsigned char d[256 / 8];
+};
+
+struct brandt_dhe_pkey {
+ unsigned char q_y[256 / 8];
+};
+
+void brandt_ecdhe_key_create (struct brandt_dhe_skey *priv);
+void brandt_ecdhe_key_get_public (const struct brandt_dhe_skey *priv,
+ struct brandt_dhe_pkey *pub);
+int brandt_ecdhe (const struct brandt_dhe_skey *priv,
+ const struct brandt_dhe_pkey *pub,
+ struct brandt_hash_code *key_material);
+void brandt_ecdhe_key_clear (struct brandt_dhe_skey *priv);
+
+#endif /* ifndef _BRANDT_CRYPTO_H */