aboutsummaryrefslogtreecommitdiff
path: root/libcmix-crypto
diff options
context:
space:
mode:
Diffstat (limited to 'libcmix-crypto')
-rw-r--r--libcmix-crypto/CMakeLists.txt9
-rw-r--r--libcmix-crypto/api.h28
-rw-r--r--libcmix-crypto/curve25519/curve25519.c38
-rw-r--r--libcmix-crypto/curve25519/curve25519.h14
-rw-r--r--libcmix-crypto/curve25519/null/CMakeLists.txt2
-rw-r--r--libcmix-crypto/curve25519/null/null_curve25519.c2
-rw-r--r--libcmix-crypto/curve25519/sodium/CMakeLists.txt2
-rw-r--r--libcmix-crypto/curve25519/sodium/libsodium_curve25519.c3
-rw-r--r--libcmix-crypto/ed25519/CMakeLists.txt32
-rw-r--r--libcmix-crypto/ed25519/ed25519.c36
-rw-r--r--libcmix-crypto/ed25519/ed25519.h71
-rw-r--r--libcmix-crypto/ed25519/gcrypt/CMakeLists.txt46
-rw-r--r--libcmix-crypto/ed25519/gcrypt/gcrypt_ed25519.c526
-rw-r--r--libcmix-crypto/elgamal/elgamal.c5
-rw-r--r--libcmix-crypto/elgamal/elgamal.h8
-rw-r--r--libcmix-crypto/elgamal/gcrypt/CMakeLists.txt2
-rw-r--r--libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c38
-rw-r--r--libcmix-crypto/elgamal/null/CMakeLists.txt2
-rw-r--r--libcmix-crypto/elgamal/null/null_elgamal.c2
-rw-r--r--libcmix-crypto/impl_macros.h65
20 files changed, 891 insertions, 40 deletions
diff --git a/libcmix-crypto/CMakeLists.txt b/libcmix-crypto/CMakeLists.txt
index 56dd553..3a4b2db 100644
--- a/libcmix-crypto/CMakeLists.txt
+++ b/libcmix-crypto/CMakeLists.txt
@@ -10,14 +10,15 @@ set(interface_sources
${CMAKE_CURRENT_SOURCE_DIR}/keypair.h
${CMAKE_CURRENT_SOURCE_DIR}/sharedkey.h
${CMAKE_CURRENT_SOURCE_DIR}/groupelement.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/impl_macros.h
)
target_sources(cmix-crypto-interface
INTERFACE ${interface_sources}
)
-include(curve25519_implementations)
-add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/curve25519/)
+include(ed25519_implementations)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ed25519/)
include(elgamal_implementations)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/elgamal)
@@ -32,11 +33,11 @@ target_sources(cmix-crypto
INTERFACE ${interface_sources}
)
-option(UseEC "Use curve25519 instead of elgamal in a multiplicative group" OFF)
+option(UseEC "Use ed25519 instead of elgamal in a multiplicative group" OFF)
if(UseEC)
target_link_libraries(cmix-crypto
- INTERFACE curve25519-implementation
+ INTERFACE ed25519-implementation
)
else(UseEC)
target_link_libraries(cmix-crypto
diff --git a/libcmix-crypto/api.h b/libcmix-crypto/api.h
index 0fa4916..8279dbb 100644
--- a/libcmix-crypto/api.h
+++ b/libcmix-crypto/api.h
@@ -63,6 +63,16 @@ typedef GroupElement(*ArrayToElement)(char const*, size_t size, bool);
/*!
*
*/
+typedef GroupElement(*MessageToElement)(char const*, size_t size, bool);
+
+/*!
+ *
+ */
+typedef void(*ElementToMessage)(unsigned char** message, const GroupElement element);
+
+/*!
+ *
+ */
typedef void(*PubKeyHashGetter)(char** buffer, size_t* len, GroupElement const pub);
/*!
@@ -88,7 +98,12 @@ typedef GroupElement(*KeyExchangeValueGetter)(GroupElement);
/*!
*
*/
-typedef GroupElement(*GroupElementMultiplier)(GroupElement, GroupElement, bool);
+typedef GroupElement(*GroupElementCombiner)(GroupElement, GroupElement, bool);
+
+/*!
+ *
+ */
+typedef GroupElement(*GroupElementUncombiner)(GroupElement, GroupElement, bool);
/*!
*
@@ -98,6 +113,11 @@ typedef size_t(*GroupElementArraySizeGetter)();
/*!
*
*/
+typedef size_t(*MessageSizeGetter)();
+
+/*!
+ *
+ */
typedef void(*GroupElementDeleter)(GroupElement);
/*!
@@ -130,13 +150,17 @@ struct Api {
ElementToArray element_to_array; ///< Get the array representation of a public key
BufferDeleter free_buffer; ///< frees library allocated buffers.
ArrayToElement array_to_element; ///< The the GroupElement representation of this array.
+ MessageToElement message_to_element; ///< Convert Message to element.
+ ElementToMessage element_to_message; ///< Convert Element to message.
PubKeyHashGetter get_pub_key_hash; ///< Get the hash of the public key.
PubKeyHashLengthGetter get_pub_key_hash_length; ///< Get the length of the pubkey hash.
GroupElementGetter get_group_element; ///< get group element
GroupElementArraySizeGetter get_group_element_array_size; ///< Return the size required to store a groupelement in an array;
+ MessageSizeGetter get_message_size; ///< Retrieve how large a message can be.
GroupElementDeleter free_group_element; ///< frees a base type of the cryptolibrary.
KeyExchangeValueGetter get_key_exchange_value; ///< get generator *op* group element.
- GroupElementMultiplier multiply; ///< Multiplies two groupelements modulo group.
+ GroupElementCombiner combine; ///< Combines two groupelements modulo group.
+ GroupElementUncombiner uncombine; ///< Uncombines two groupelements;
DecryptionShareGetter get_decryption_share; ///< calculates the first argument to the power of Inverse second argument;
PublicShareAdder add_public_share; ///< Adds the public key stored in void* to the existing share.
SharedKeyDeriver derive_shared_key; ///< Pointer to shared key derivation function
diff --git a/libcmix-crypto/curve25519/curve25519.c b/libcmix-crypto/curve25519/curve25519.c
index a963840..2fb99c3 100644
--- a/libcmix-crypto/curve25519/curve25519.c
+++ b/libcmix-crypto/curve25519/curve25519.c
@@ -5,23 +5,29 @@ struct Api get_curve25519_implementation()
{
curve25519_initialize();
return (struct Api) {
- .initialize = curve25519_initialize,
- .create_keypair = curve25519_create_keypair,
- .free_keypair = curve25519_delete_keypair,
- .element_to_array = curve25519_element_to_array,
- .free_buffer = curve25519_free_buffer,
- .array_to_element = curve25519_array_to_element,
- .get_group_element = curve25519_get_group_element,
+ .initialize = curve25519_initialize,
+ .create_keypair = curve25519_create_keypair,
+ .free_keypair = curve25519_delete_keypair,
+ .element_to_array = curve25519_element_to_array,
+ .free_buffer = curve25519_free_buffer,
+ .array_to_element = curve25519_array_to_element,
+ .message_to_element = curve25519_message_to_element,
+ .get_pub_key_hash = curve25519_get_pub_key_hash,
+ .get_pub_key_hash_length = curve25519_get_pub_key_hash_length,
+ .get_group_element = curve25519_get_group_element,
.get_group_element_array_size = curve25519_get_group_element_array_size,
- .free_group_element = curve25519_delete_group_element,
- .get_key_exchange_value = curve25519_get_key_exchange_value,
- .multiply = curve25519_multiply,
- .get_decryption_share = curve25519_get_decryption_share,
- .add_public_share = curve25519_add_public_share,
- .derive_shared_key = curve25519_derive_shared_key,
- .free_shared_key = curve25519_delete_shared_key,
- .encrypt = curve25519_encrypt,
- .deinitialize = curve25519_deinitialize
+ .free_group_element = curve25519_delete_group_element,
+ .get_key_exchange_value = curve25519_get_key_exchange_value,
+ .combine = curve25519_combine,
+ .uncombine = curve25519_uncombine,
+ .get_decryption_share = curve25519_get_decryption_share,
+ .add_public_share = curve25519_add_public_share,
+ .derive_shared_key = curve25519_derive_shared_key,
+ .free_shared_key = curve25519_delete_shared_key,
+ .encrypt = curve25519_encrypt,
+ .invert = curve25519_invert,
+ .get_uniform_int = curve25519_get_uniform_int,
+ .deinitialize = curve25519_deinitialize
};
}
diff --git a/libcmix-crypto/curve25519/curve25519.h b/libcmix-crypto/curve25519/curve25519.h
index 5f30915..f424144 100644
--- a/libcmix-crypto/curve25519/curve25519.h
+++ b/libcmix-crypto/curve25519/curve25519.h
@@ -22,13 +22,21 @@ extern BufferDeleter curve25519_free_buffer;
extern ArrayToElement curve25519_array_to_element;
+extern MessageToElement curve25519_message_to_element;
+
+extern PubKeyHashGetter curve25519_get_pub_key_hash;
+
+extern PubKeyHashLengthGetter curve25519_get_pub_key_hash_length;
+
extern GroupElementGetter curve25519_get_group_element;
extern GroupElementDeleter curve25519_delete_group_element;
extern KeyExchangeValueGetter curve25519_get_key_exchange_value;
-extern GroupElementMultiplier curve25519_multiply;
+extern GroupElementCombiner curve25519_combine;
+
+extern GroupElementUncombiner curve25519_uncombine;
extern DecryptionShareGetter curve25519_get_decryption_share;
@@ -42,6 +50,10 @@ extern SharedKeyDeleter curve25519_delete_shared_key;
extern Encrypter curve25519_encrypt;
+extern Inverter curve25519_invert;
+
+extern UniformIntGetter curve25519_get_uniform_int;
+
extern Deinitializer curve25519_deinitialize;
/*!
diff --git a/libcmix-crypto/curve25519/null/CMakeLists.txt b/libcmix-crypto/curve25519/null/CMakeLists.txt
index eb13fdf..94dac1b 100644
--- a/libcmix-crypto/curve25519/null/CMakeLists.txt
+++ b/libcmix-crypto/curve25519/null/CMakeLists.txt
@@ -1,6 +1,6 @@
include(get_target_name)
-get_target_name(target_name)
+get_target_name(target_name algo api)
add_library(${target_name} SHARED
null_curve25519.c
diff --git a/libcmix-crypto/curve25519/null/null_curve25519.c b/libcmix-crypto/curve25519/null/null_curve25519.c
index d261791..19c52f4 100644
--- a/libcmix-crypto/curve25519/null/null_curve25519.c
+++ b/libcmix-crypto/curve25519/null/null_curve25519.c
@@ -37,7 +37,7 @@ ArrayToElement curve25519_array_to_element = NULL;//&null_curve25519_array_to_el
GroupElementGetter curve25519_get_group_element = NULL;//&null_curve25519_get_group_element;
GroupElementDeleter curve25519_delete_group_element = NULL;//&null_curve25519_delete_group_element;
KeyExchangeValueGetter curve25519_get_key_exchange_value = NULL;//&null_curve25519_get_key_exchange_value;
-GroupElementMultiplier curve25519_multiply = NULL;//&null_curve25519_multiply;
+GroupElementCombiner curve25519_multiply = NULL;//&null_curve25519_multiply;
DecryptionShareGetter curve25519_get_decryption_share = NULL;//&null_curve25519_get_decryption_share;
GroupElementArraySizeGetter curve25519_get_group_element_array_size = NULL;//&null_curve25519_get_group_element_array_size;
PublicShareAdder curve25519_add_public_share = NULL;//&null_curve25519_add_public_share;
diff --git a/libcmix-crypto/curve25519/sodium/CMakeLists.txt b/libcmix-crypto/curve25519/sodium/CMakeLists.txt
index fbbedb1..f93abb4 100644
--- a/libcmix-crypto/curve25519/sodium/CMakeLists.txt
+++ b/libcmix-crypto/curve25519/sodium/CMakeLists.txt
@@ -1,6 +1,6 @@
include(get_target_name)
-get_target_name(target_name)
+get_target_name(target_name algo api)
find_package(sodium REQUIRED CONFIG)
diff --git a/libcmix-crypto/curve25519/sodium/libsodium_curve25519.c b/libcmix-crypto/curve25519/sodium/libsodium_curve25519.c
index 1bad378..b8ed4c2 100644
--- a/libcmix-crypto/curve25519/sodium/libsodium_curve25519.c
+++ b/libcmix-crypto/curve25519/sodium/libsodium_curve25519.c
@@ -93,7 +93,8 @@ ArrayToElement curve25519_array_to_element = NULL;//&sodium_curve25519_array_to_
GroupElementGetter curve25519_get_group_element = NULL;//&sodium_curve25519_get_group_element;
GroupElementDeleter curve25519_delete_group_element = NULL;//&sodium_curve25519_delete_group_element;
KeyExchangeValueGetter curve25519_get_key_exchange_value = NULL;//&sodium_curve25519_get_key_exchange_value;
-GroupElementMultiplier curve25519_multiply = NULL;//&sodium_curve25519_multiply;
+GroupElementCombiner curve25519_combine = NULL;//&sodium_curve25519_multiply;
+GroupElementUncombiner curve25519_uncombine = NULL;
DecryptionShareGetter curve25519_get_decryption_share = NULL;//&sodium_curve25519_get_decryption_share;
GroupElementArraySizeGetter curve25519_get_group_element_array_size = NULL;//&sodium_curve25519_get_group_element_array_size;
PublicShareAdder curve25519_add_public_share = NULL;//&sodium_curve25519_add_public_share;
diff --git a/libcmix-crypto/ed25519/CMakeLists.txt b/libcmix-crypto/ed25519/CMakeLists.txt
new file mode 100644
index 0000000..3aae9fe
--- /dev/null
+++ b/libcmix-crypto/ed25519/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_library(ed25519-interface INTERFACE)
+
+target_include_directories(ed25519-interface
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+target_sources(ed25519-interface
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/ed25519.h
+)
+
+target_link_libraries(ed25519-interface
+ INTERFACE cmix-crypto-interface
+)
+
+foreach(impl ${libcmix_crypto_ed25519_implementations})
+ add_subdirectory(${impl})
+endforeach()
+
+add_library(ed25519-implementation
+ ed25519.h ed25519.c
+)
+
+target_include_directories(ed25519-implementation
+ PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+target_link_libraries(ed25519-implementation
+ PUBLIC ed25519-interface
+ PUBLIC ed25519-${libcmix_crypto_ed25519_implementation}
+)
+
+
diff --git a/libcmix-crypto/ed25519/ed25519.c b/libcmix-crypto/ed25519/ed25519.c
new file mode 100644
index 0000000..835edfa
--- /dev/null
+++ b/libcmix-crypto/ed25519/ed25519.c
@@ -0,0 +1,36 @@
+
+#include "ed25519.h"
+
+struct Api get_ed25519_implementation()
+{
+ ed25519_initialize();
+ return (struct Api) {
+ .initialize = ed25519_initialize,
+ .create_keypair = ed25519_create_keypair,
+ .free_keypair = ed25519_delete_keypair,
+ .element_to_array = ed25519_element_to_array,
+ .free_buffer = ed25519_free_buffer,
+ .array_to_element = ed25519_array_to_element,
+ .message_to_element = ed25519_message_to_element,
+ .element_to_message = ed25519_element_to_message,
+ .get_pub_key_hash = ed25519_get_pub_key_hash,
+ .get_pub_key_hash_length = ed25519_get_pub_key_hash_length,
+ .get_group_element = ed25519_get_group_element,
+ .get_group_element_array_size = ed25519_get_group_element_array_size,
+ .get_message_size = ed25519_get_message_size,
+ .free_group_element = ed25519_delete_group_element,
+ .get_key_exchange_value = ed25519_get_key_exchange_value,
+ .combine = ed25519_combine,
+ .uncombine = ed25519_uncombine,
+ .get_decryption_share = ed25519_get_decryption_share,
+ .add_public_share = ed25519_add_public_share,
+ .derive_shared_key = ed25519_derive_shared_key,
+ .free_shared_key = ed25519_delete_shared_key,
+ .encrypt = ed25519_encrypt,
+ .invert = ed25519_invert,
+ .get_uniform_int = ed25519_get_uniform_int,
+ .deinitialize = ed25519_deinitialize
+ };
+}
+
+ImplementationGetter get_implementation = &get_ed25519_implementation;
diff --git a/libcmix-crypto/ed25519/ed25519.h b/libcmix-crypto/ed25519/ed25519.h
new file mode 100644
index 0000000..1cd9e66
--- /dev/null
+++ b/libcmix-crypto/ed25519/ed25519.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * \file
+ */
+
+extern Initializer ed25519_initialize;
+
+extern KeyPairCreator ed25519_create_keypair;
+
+extern KeyPairDeleter ed25519_delete_keypair;
+
+extern ElementToArray ed25519_element_to_array;
+
+extern BufferDeleter ed25519_free_buffer;
+
+extern ArrayToElement ed25519_array_to_element;
+
+extern MessageToElement ed25519_message_to_element;
+
+extern ElementToMessage ed25519_element_to_message;
+
+extern PubKeyHashGetter ed25519_get_pub_key_hash;
+
+extern PubKeyHashLengthGetter ed25519_get_pub_key_hash_length;
+
+extern GroupElementGetter ed25519_get_group_element;
+
+extern GroupElementDeleter ed25519_delete_group_element;
+
+extern KeyExchangeValueGetter ed25519_get_key_exchange_value;
+
+extern GroupElementCombiner ed25519_combine;
+
+extern GroupElementUncombiner ed25519_uncombine;
+
+extern DecryptionShareGetter ed25519_get_decryption_share;
+
+extern GroupElementArraySizeGetter ed25519_get_group_element_array_size;
+
+extern MessageSizeGetter ed25519_get_message_size;
+
+extern PublicShareAdder ed25519_add_public_share;
+
+extern SharedKeyDeriver ed25519_derive_shared_key;
+
+extern SharedKeyDeleter ed25519_delete_shared_key;
+
+extern Encrypter ed25519_encrypt;
+
+extern Inverter ed25519_invert;
+
+extern UniformIntGetter ed25519_get_uniform_int;
+
+extern Deinitializer ed25519_deinitialize;
+
+/*!
+ * \brief get_ed25519_implementation
+ * \return An Api struct filled with a ed25519 implementation.
+ */
+struct Api get_ed25519_implementation();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libcmix-crypto/ed25519/gcrypt/CMakeLists.txt b/libcmix-crypto/ed25519/gcrypt/CMakeLists.txt
new file mode 100644
index 0000000..d020e4b
--- /dev/null
+++ b/libcmix-crypto/ed25519/gcrypt/CMakeLists.txt
@@ -0,0 +1,46 @@
+include(get_target_name)
+
+get_target_name(target_name algo api)
+
+find_package(Gcrypt REQUIRED)
+
+option(trace_pointers "trace alloced pointers by gcrypt" OFF)
+
+add_library(${target_name} SHARED
+ gcrypt_ed25519.c
+)
+
+set_property(SOURCE gcrypt_ed25519.c PROPERTY COMPILE_DEFINITIONS
+ API=${api};ALGORITHM=${algo}
+)
+
+if(trace_pointers)
+ target_compile_definitions(${target_name}
+ PRIVATE "POINTER_TRACING"
+ )
+endif(trace_pointers)
+
+if(NOT Gcrypt_CFLAGS STREQUAL "")
+ IF(WIN32)
+ separate_arguments(flags WINDOWS_COMMAND ${Gcrypt_CFLAGS})
+ else(WIN32)
+ separate_arguments(flags UNIX_COMMAND ${Gcrypt_CFLAGS})
+ endif(WIN32)
+
+ foreach(flag ${flags})
+ target_compile_options(${target_name}
+ PUBLIC ${flag}
+ )
+ endforeach(flag)
+endif(NOT Gcrypt_CFLAGS STREQUAL "")
+
+if(UNIX)
+ target_link_libraries(${target_name}
+ PRIVATE m
+ )
+endif(UNIX)
+
+target_link_libraries(${target_name}
+ PRIVATE ed25519-interface
+ PUBLIC ${Gcrypt_LIBRARIES}
+)
diff --git a/libcmix-crypto/ed25519/gcrypt/gcrypt_ed25519.c b/libcmix-crypto/ed25519/gcrypt/gcrypt_ed25519.c
new file mode 100644
index 0000000..54202be
--- /dev/null
+++ b/libcmix-crypto/ed25519/gcrypt/gcrypt_ed25519.c
@@ -0,0 +1,526 @@
+#include "ed25519.h"
+
+#include "api.h"
+#include "impl_macros.h"
+
+#include "gcrypt.h"
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <math.h>
+
+#ifdef POINTER_TRACING
+ #define TRACE(FILE, LINE, PTR) \
+ fprintf(stderr, "%s %d %p\n", FILE, LINE, PTR);
+#else
+ #define TRACE(FILE, LINE, PTR)
+#endif
+
+static gcry_ctx_t ctx;
+
+static gcry_mpi_point_t g;
+static gcry_mpi_t p;
+
+static unsigned int nr_bits = 256;
+static unsigned int nr_point_bits = 256 * 2;
+static unsigned int nr_bytes = 256 / 8;
+static unsigned int stride = 16;
+
+void check(gcry_error_t error) {
+ if (error) {
+ fprintf (stderr, "Error: %s/%s\n", gcry_strsource (error), gcry_strerror (error));
+ exit(1);
+ }
+}
+
+void print_sexp(gcry_sexp_t exp) {
+ size_t required_size = gcry_sexp_sprint(exp, GCRYSEXP_FMT_ADVANCED, NULL, 0); //passing NULL as the buffer will return the size needed.
+
+ char* str = (char *) malloc(sizeof(char)*required_size);
+
+ gcry_sexp_sprint(exp, GCRYSEXP_FMT_ADVANCED, str, required_size); //So we ignore the size here.
+
+ printf("size = %zu\n", required_size);
+ for(size_t i = 0; i < required_size; i++)
+ printf("%c", str[i]);
+ printf("\n");
+
+ free(str);
+}
+
+void DEF(initialize)(void) {
+ if (!gcry_check_version (GCRYPT_VERSION)) {
+ fprintf(stderr, "libgcrypt version mismatch\n");
+ exit(-1);
+ }
+
+ gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+ gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
+ gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+ gcry_error_t error;
+
+ error = gcry_mpi_ec_new(&ctx, NULL, "Ed25519");
+ check(error);
+
+ g = gcry_mpi_ec_get_point("g", ctx, false);
+ p = gcry_mpi_ec_get_mpi("p", ctx, false);
+}
+
+struct KeyPair DEF(create_keypair)(void) {
+ size_t parse_error_offset;
+ gcry_error_t error;
+
+ gcry_sexp_t key_gen_sexp;
+ error = gcry_sexp_build(&key_gen_sexp, &parse_error_offset, "(genkey (ecc (curve Ed25519)))", NULL);
+ check(error);
+
+ gcry_sexp_t key_pair;
+ error = gcry_pk_genkey(&key_pair, key_gen_sexp);
+ check(error);
+
+ gcry_mpi_t d;
+ gcry_mpi_t q_mpi;
+
+ gcry_sexp_extract_param(key_pair, "key-data!private-key", "q d", &q_mpi, &d, NULL);
+
+ gcry_mpi_point_t q = gcry_mpi_point_new(nr_point_bits);
+ error = gcry_mpi_ec_decode_point(q, q_mpi, ctx);
+ check(error);
+
+ assert(gcry_mpi_ec_curve_point(q, ctx));
+
+ gcry_mpi_release(q_mpi);
+ gcry_sexp_release(key_gen_sexp);
+ gcry_sexp_release(key_pair);
+
+ return (struct KeyPair) {
+ .sec = d,
+ .pub = q
+ };
+}
+
+void DEF(delete_keypair)(struct KeyPair* pair) {
+ gcry_mpi_release((gcry_mpi_t)pair->sec);
+ gcry_mpi_point_release((gcry_mpi_point_t)pair->pub);
+ pair->sec = NULL;
+ pair->pub = NULL;
+}
+
+void DEF(element_to_array)(unsigned char** buffer, size_t* len, GroupElement element) {
+ gcry_error_t error;
+
+ gcry_mpi_t x = gcry_mpi_new(nr_bits);
+ gcry_mpi_t y = gcry_mpi_new(nr_bits);
+
+ int ret = gcry_mpi_ec_get_affine(x, y, (gcry_mpi_point_t) element, ctx);
+
+ if(ret != 0) {
+ abort();
+ }
+
+ *len = nr_bytes * 2;
+ *buffer = (unsigned char*) calloc(*len, sizeof(unsigned char));
+
+ unsigned char* temp = (unsigned char*) calloc(nr_bytes, sizeof(unsigned char));
+ size_t nwritten = 0;
+
+ error = gcry_mpi_print(GCRYMPI_FMT_USG, temp, nr_bytes, &nwritten, (gcry_mpi_t) x);
+ check(error);
+ memcpy(*buffer + (nr_bytes - nwritten), temp, nwritten);
+
+ memset(temp, '\0', nr_bytes);
+ error = gcry_mpi_print(GCRYMPI_FMT_USG, temp, nr_bytes, &nwritten, (gcry_mpi_t) y);
+ check(error);
+ memcpy(*buffer + nr_bytes + (nr_bytes - nwritten), temp, nwritten);
+
+ free(temp);
+ gcry_mpi_release(y);
+ gcry_mpi_release(x);
+}
+
+GroupElement DEF(message_to_element)(char const* buffer, size_t len, bool secure) {
+ (void) secure;
+ gcry_error_t error;
+
+ assert(len == 31);
+
+ gcry_mpi_t mpi;
+ gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, buffer, len, NULL);
+
+ //mpi * stride
+ gcry_mpi_dump(mpi);
+ printf("\n");
+ gcry_mpi_lshift(mpi, mpi, (unsigned) lround(log2(stride)));
+ gcry_mpi_dump(mpi);
+ printf("\n");
+
+ char* encoded_point = (char*) calloc(nr_bytes+1, sizeof(char));
+ gcry_mpi_point_t point = gcry_mpi_point_new(0);
+ unsigned int count = 0;
+ do {
+ encoded_point[0] = 0x40;
+
+ unsigned int byte_size = (unsigned) ceil(gcry_mpi_get_nbits(mpi) / 8.0);
+ printf("byte_size: %i\n", byte_size);
+ //gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char*) encoded_point + 1 + (32 - byte_size), byte_size, NULL, mpi);
+ gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char*) encoded_point + 1, 32, NULL, mpi);
+
+ for(int i = 0; i < 16; i++) {
+ char temp = encoded_point[i+1];
+ encoded_point[i+1] = encoded_point[32-i];
+ encoded_point[32-i] = temp;
+ }
+
+ for(int i = 0; i < nr_bytes+1; i++) {
+ printf("%02x", 0xFF & (unsigned) encoded_point[i]);
+ }
+ printf("\n");
+
+ gcry_mpi_t encoded_mpi = gcry_mpi_new(0);
+ gcry_mpi_set_opaque_copy(encoded_mpi, encoded_point, (nr_bytes + 1) * sizeof(char) * 8);
+
+ error = gcry_mpi_ec_decode_point(point, encoded_mpi, ctx);
+ check(error);
+
+ gcry_mpi_t x = gcry_mpi_new(0);
+ gcry_mpi_t y = gcry_mpi_new(0);
+ gcry_mpi_ec_get_affine(x, y, point, ctx);
+
+ gcry_mpi_release(encoded_mpi);
+
+ printf("%i %i\n", count, stride);
+ gcry_mpi_dump(x);
+ printf(",\n");
+ gcry_mpi_dump(y);
+ printf("\n");
+ gcry_mpi_dump(mpi);
+ printf("\n");
+ gcry_mpi_dump(encoded_mpi);
+ printf("\n");
+ gcry_mpi_dump(p);
+ printf("\n");
+ assert(gcry_mpi_cmp(mpi, p) == -1);
+ assert(count < stride);
+ gcry_mpi_add_ui(mpi, mpi, 1);
+ count++;
+
+ if(!gcry_mpi_ec_curve_point(point, ctx)) {
+ gcry_mpi_point_release(point);
+ point = gcry_mpi_point_new(0);
+ }
+
+ } while(!gcry_mpi_ec_curve_point(point, ctx));
+
+ gcry_mpi_release(mpi);
+ free(encoded_point);
+
+ return point;
+}
+
+void DEF(element_to_message)(unsigned char** buffer, const GroupElement el) {
+ gcry_mpi_t y = gcry_mpi_new(0);
+ gcry_mpi_ec_get_affine(NULL, y, (gcry_mpi_point_t) el, ctx);
+
+ gcry_mpi_rshift(y, y, (unsigned) lround(log2(stride)));
+
+ size_t nr_written;
+ gcry_mpi_aprint(GCRYMPI_FMT_USG, buffer, &nr_written, y);
+
+ gcry_mpi_dump(y);
+ printf("\n");
+
+ assert(nr_written == 31);
+
+ gcry_mpi_release(y);
+}
+
+void DEF(free_buffer)(void* buffer) {
+ gcry_free(buffer);
+}
+
+GroupElement DEF(array_to_element)(char const* buffer, size_t len, bool secure) {
+ (void) secure;
+ size_t error_pos;
+ gcry_error_t error;
+
+ printf("%i\n", len);
+ for(int i = 0; i < len; i++) {
+ if(i == 32) { printf("\n"); }
+ printf("%02x", 0xFF & buffer[i]);
+ }
+ printf("\n");
+
+ gcry_mpi_t x;
+ error = gcry_mpi_scan(&x, GCRYMPI_FMT_USG, buffer, len/2, &error_pos);
+ check(error);
+
+ gcry_mpi_t y;
+ error = gcry_mpi_scan(&y, GCRYMPI_FMT_USG, buffer + len/2, len/2, &error_pos);
+
+ gcry_mpi_dump(y);
+ printf("\n");
+
+ gcry_mpi_point_t point = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_point_set(point, x, y, GCRYMPI_CONST_ONE);
+
+ gcry_mpi_release(x);
+ gcry_mpi_release(y);
+
+ return point;
+}
+
+size_t DEF(get_pub_key_hash_length)(void) {
+ return 20;
+}
+
+//TODO: fix this up
+void DEF(get_pub_key_hash)(char** buffer, size_t* len, GroupElement const pub) {
+ (void)pub;
+ //gcry_sexp_t pubkey;
+ //gcry_error_t error;
+ //size_t err_off;
+
+ //error = gcry_sexp_build(&pubkey, &err_off, "(public-key (ecc (curve Curve25519) (flags eddsa) (q %M)))", (gcry_mpi_point_t) pub);
+ //check(error);
+
+ //*buffer = (char*) gcry_pk_get_keygrip(pubkey, NULL);
+ //TODO: see if we can instantiate a public key sexp;
+
+ gcry_mpi_t x = gcry_mpi_new(0);
+ gcry_mpi_t y = gcry_mpi_new(0);
+
+ gcry_mpi_point_get(x, y, NULL, (gcry_mpi_point_t)pub);
+
+ printf("pub: %p\n", pub);
+
+ fprintf(stderr, "lel1: ");
+ gcry_mpi_dump(x);
+ printf("\n");
+ fprintf(stderr, "lel2: ");
+ gcry_mpi_dump(y);
+ printf("\n");
+
+ *len = DEF(get_pub_key_hash_length)();
+ *buffer = (char*) calloc(*len, sizeof(char));
+
+ unsigned char* temp;
+ size_t len2;
+ DEF(element_to_array(&temp, &len2, pub));
+
+ if(len2 < *len) {
+ memcpy((*buffer) + (*len - len2), temp, len2);
+ } else {
+ memcpy(*buffer, temp, *len);
+ }
+ gcry_free(temp);
+
+ TRACE(__FILE__, __LINE__, *buffer);
+ //gcry_sexp_release(pubkey);
+}
+
+GroupElement DEF(get_group_element)(bool secure) {
+ (void) secure;
+ size_t parse_error_offset;
+ gcry_error_t error;
+
+ gcry_mpi_t a = NULL;
+ void* bytes = NULL;
+ do {
+ gcry_free(bytes);
+ gcry_mpi_release(a);
+ bytes = gcry_random_bytes_secure(nr_bytes, GCRY_VERY_STRONG_RANDOM);
+ TRACE(__FILE__, __LINE__, bytes);
+ error = gcry_mpi_scan(&a, GCRYMPI_FMT_USG, bytes, nr_bytes, &parse_error_offset);
+ check(error);
+ } while(gcry_mpi_cmp_ui(a, 0) == 0 || gcry_mpi_cmp(a, p) != -1);
+
+ char* encoded_point = (char*) calloc(nr_bytes+1, sizeof(char));
+ gcry_mpi_point_t point = gcry_mpi_point_new(0);
+ do {
+ encoded_point[0] = 0x40;
+
+ unsigned int byte_size = (unsigned) ceil(gcry_mpi_get_nbits(a) / 8.0);
+ gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char*) encoded_point + 1, 32, NULL, a);
+
+ for(int i = 0; i < 16; i++) {
+ char temp = encoded_point[i+1];
+ encoded_point[i+1] = encoded_point[32-i];
+ encoded_point[32-i] = temp;
+ }
+
+ gcry_mpi_t encoded_mpi = gcry_mpi_new(0);
+ gcry_mpi_set_opaque_copy(encoded_mpi, encoded_point, (nr_bytes + 1) * sizeof(char) * 8);
+
+ error = gcry_mpi_ec_decode_point(point, encoded_mpi, ctx);
+ check(error);
+
+ gcry_mpi_release(encoded_mpi);
+
+ if(!gcry_mpi_ec_curve_point(point, ctx)) {
+ gcry_mpi_point_release(point);
+ point = gcry_mpi_point_new(0);
+
+ gcry_mpi_add_ui(a, a, 1);
+ }
+
+ } while(!gcry_mpi_ec_curve_point(point, ctx));
+
+ gcry_mpi_release(a);
+ gcry_free(bytes);
+
+ return point;
+}
+
+GroupElement DEF(get_key_exchange_value)(GroupElement group_el) {
+ gcry_mpi_t x = gcry_mpi_new(nr_bits);
+ gcry_mpi_point_get(x, NULL, NULL, (gcry_mpi_point_t) group_el);
+
+ gcry_mpi_point_t mult = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_ec_mul(mult, x, g, ctx);
+
+ gcry_mpi_release(x);
+
+ return mult;
+}
+
+GroupElement DEF(combine)(GroupElement lh, GroupElement rh, bool secure) {
+ (void) secure;
+ gcry_mpi_point_t addition = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_ec_add(addition, (gcry_mpi_point_t)lh, (gcry_mpi_point_t)rh, ctx);
+ return addition;
+}
+
+GroupElement DEF(invert)(GroupElement const el) {
+ gcry_mpi_t x = gcry_mpi_new(nr_bits);
+ gcry_mpi_t y = gcry_mpi_new(nr_bits);
+
+ gcry_mpi_ec_get_affine(x, y, (gcry_mpi_point_t) el, ctx);
+
+ gcry_mpi_t neg_x = gcry_mpi_new(nr_bits);
+ gcry_mpi_subm(neg_x, p, x, p);
+
+ gcry_mpi_point_t point = gcry_mpi_point_set(NULL, neg_x, y, GCRYMPI_CONST_ONE);
+
+ gcry_mpi_release(neg_x);
+ gcry_mpi_release(x);
+ gcry_mpi_release(y);
+
+ return point;
+}
+
+void DEF(delete_group_element)(GroupElement element) {
+ gcry_mpi_point_release((gcry_mpi_point_t)element);
+}
+
+GroupElement DEF(uncombine)(GroupElement lh, GroupElement rh, bool secure) {
+ (void) secure;
+
+ gcry_mpi_point_t inv_rh = DEF(invert)(rh);
+ gcry_mpi_point_t ret = DEF(combine)(lh, inv_rh, secure);
+
+ //gcry_mpi_point_t ret = gcry_mpi_point_new(0);
+ //gcry_mpi_ec_sub(ret, (gcry_mpi_point_t)lh, (gcry_mpi_point_t)rh, ctx);
+ return ret;
+}
+
+GroupElement DEF(get_decryption_share)(GroupElement r, GroupElement e) {
+ gcry_mpi_point_t inv_d = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_ec_mul(inv_d, (gcry_mpi_t)e, (gcry_mpi_point_t) r, ctx);
+
+ GroupElement d = DEF(invert)(inv_d);
+ gcry_mpi_point_release(inv_d);
+
+ return d;
+}
+
+size_t DEF(get_group_element_array_size)(void) {
+ return nr_bytes*2;
+}
+
+size_t DEF(get_message_size)(void) {
+ return nr_bytes-1;
+}
+
+void DEF(add_public_share)(GroupElement* el, char const* share, size_t in_len, GroupElement pubkey) {
+ GroupElement share_el = DEF(array_to_element)(share, in_len, false);
+ *el = DEF(combine)(share_el, pubkey, false);
+ gcry_mpi_point_release((gcry_mpi_point_t)share_el);
+}
+
+GroupElement DEF(derive_shared_key)(struct KeyPair keypair, unsigned char const* other_pub, size_t pub_len, unsigned char const* value, size_t value_len, void* priv_value, bool swap) {
+ (void)keypair;
+ (void)other_pub;
+ (void)pub_len;
+ (void)swap;
+
+ GroupElement ga = DEF(array_to_element)((const char*) value, value_len, false);
+
+ gcry_mpi_point_t gab = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_ec_mul(gab, (gcry_mpi_t) priv_value, (gcry_mpi_point_t) ga, ctx);
+
+ gcry_mpi_point_release((gcry_mpi_point_t) ga);
+
+ return gab;
+}
+
+void DEF(delete_shared_key)(struct SharedKey* s) {
+ gcry_mpi_point_release((gcry_mpi_point_t)s->shared);
+ s->shared = NULL;
+}
+
+void DEF(encrypt)(GroupElement* random_element, GroupElement* message_element, GroupElement value, GroupElement key) {
+ GroupElement random = DEF(get_group_element)(true);
+
+ gcry_mpi_t random_mpi = gcry_mpi_new(nr_bits);
+ gcry_mpi_ec_get_affine(random_mpi, NULL, (gcry_mpi_point_t)random, ctx);
+
+ *random_element = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_ec_mul((gcry_mpi_point_t)*random_element, random_mpi, g, ctx);
+
+ gcry_mpi_point_t c2 = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_ec_mul(c2, random_mpi, (gcry_mpi_point_t) key, ctx);
+
+ *message_element = gcry_mpi_point_new(nr_point_bits);
+ gcry_mpi_ec_add((gcry_mpi_point_t)* message_element, c2, (gcry_mpi_point_t) value, ctx);
+
+ gcry_mpi_release(random_mpi);
+ gcry_mpi_point_release(c2);
+}
+
+unsigned int DEF(get_uniform_int)(unsigned int upper) {
+ unsigned int random_value;
+
+ if(upper == 0) {
+ void* buffer = gcry_random_bytes_secure(sizeof(unsigned int), GCRY_STRONG_RANDOM);
+ TRACE(__FILE__, __LINE__, buffer);
+ memcpy(&random_value, buffer, sizeof(unsigned int));
+ gcry_free(buffer);
+
+ return random_value;
+ }
+
+ unsigned int lower = -upper % upper;
+ do {
+ void* buffer = gcry_random_bytes_secure(sizeof(unsigned int), GCRY_STRONG_RANDOM);
+ TRACE(__FILE__, __LINE__, buffer);
+ memcpy(&random_value, buffer, sizeof(unsigned int));
+ gcry_free(buffer);
+
+ if (random_value >= lower)
+ return random_value % upper;
+
+
+ } while(true);
+}
+
+void DEF(deinitialize)(void) {
+ gcry_mpi_point_release(g);
+ gcry_mpi_release(p);
+ gcry_ctx_release(ctx);
+}
+
+LINK_IMPLEMENTATION \ No newline at end of file
diff --git a/libcmix-crypto/elgamal/elgamal.c b/libcmix-crypto/elgamal/elgamal.c
index 399d952..d103230 100644
--- a/libcmix-crypto/elgamal/elgamal.c
+++ b/libcmix-crypto/elgamal/elgamal.c
@@ -10,13 +10,16 @@ struct Api get_elgamal_implementation()
.element_to_array = elgamal_element_to_array,
.free_buffer = elgamal_free_buffer,
.array_to_element = elgamal_array_to_element,
+ .message_to_element = elgamal_message_to_element,
.get_pub_key_hash = elgamal_get_pub_key_hash,
.get_pub_key_hash_length = elgamal_get_pub_key_hash_length,
.get_group_element = elgamal_get_group_element,
.get_group_element_array_size = elgamal_get_group_element_array_size,
+ .get_message_size = elgamal_get_message_size,
.free_group_element = elgamal_delete_group_element,
.get_key_exchange_value = elgamal_get_key_exchange_value,
- .multiply = elgamal_multiply,
+ .combine = elgamal_combine,
+ .uncombine = elgamal_uncombine,
.get_decryption_share = elgamal_get_decryption_share,
.add_public_share = elgamal_add_public_share,
.derive_shared_key = elgamal_derive_shared_key,
diff --git a/libcmix-crypto/elgamal/elgamal.h b/libcmix-crypto/elgamal/elgamal.h
index 1fe4447..4cc3013 100644
--- a/libcmix-crypto/elgamal/elgamal.h
+++ b/libcmix-crypto/elgamal/elgamal.h
@@ -22,6 +22,8 @@ extern BufferDeleter elgamal_free_buffer;
extern ArrayToElement elgamal_array_to_element;
+extern MessageToElement elgamal_message_to_element;
+
extern PubKeyHashGetter elgamal_get_pub_key_hash;
extern PubKeyHashLengthGetter elgamal_get_pub_key_hash_length;
@@ -32,12 +34,16 @@ extern GroupElementDeleter elgamal_delete_group_element;
extern KeyExchangeValueGetter elgamal_get_key_exchange_value;
-extern GroupElementMultiplier elgamal_multiply;
+extern GroupElementCombiner elgamal_combine;
+
+extern GroupElementUncombiner elgamal_uncombine;
extern DecryptionShareGetter elgamal_get_decryption_share;
extern GroupElementArraySizeGetter elgamal_get_group_element_array_size;
+extern MessageSizeGetter elgamal_get_message_size;
+
extern PublicShareAdder elgamal_add_public_share;
extern SharedKeyDeriver elgamal_derive_shared_key;
diff --git a/libcmix-crypto/elgamal/gcrypt/CMakeLists.txt b/libcmix-crypto/elgamal/gcrypt/CMakeLists.txt
index d8c19b8..6dfdc74 100644
--- a/libcmix-crypto/elgamal/gcrypt/CMakeLists.txt
+++ b/libcmix-crypto/elgamal/gcrypt/CMakeLists.txt
@@ -1,6 +1,6 @@
include(get_target_name)
-get_target_name(target_name)
+get_target_name(target_name algo api)
find_package(Gcrypt REQUIRED)
diff --git a/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c b/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c
index ec993a6..dff75b1 100644
--- a/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c
+++ b/libcmix-crypto/elgamal/gcrypt/gcrypt_elgamal.c
@@ -31,7 +31,7 @@ void print_sexp(gcry_sexp_t exp) {
char* str = (char *) malloc(sizeof(char)*required_size);
- gcry_sexp_sprint(exp, GCRYSEXP_FMT_ADVANCED, str, 2000); //So we ignore the size here.
+ gcry_sexp_sprint(exp, GCRYSEXP_FMT_ADVANCED, str, required_size); //So we ignore the size here.
printf("size = %zu\n", required_size);
for(size_t i = 0; i < required_size; i++)
@@ -113,11 +113,11 @@ struct KeyPair gcrypt_elgamal_create_keypair() {
};
}
-void gcrypt_elgamal_delete_keypair(struct KeyPair* p) {
- gcry_mpi_release((gcry_mpi_t) p->sec);
- gcry_mpi_release((gcry_mpi_t) p->pub);
- p->sec = NULL;
- p->pub = NULL;
+void gcrypt_elgamal_delete_keypair(struct KeyPair* pair) {
+ gcry_mpi_release((gcry_mpi_t) pair->sec);
+ gcry_mpi_release((gcry_mpi_t) pair->pub);
+ pair->sec = NULL;
+ pair->pub = NULL;
}
void gcrypt_elgamal_element_to_array(unsigned char** buffer, size_t* len, void* key) {
@@ -145,6 +145,10 @@ void* gcrypt_elgamal_array_to_element(char const* buffer, size_t len, bool secur
return mpi;
}
+GroupElement gcrypt_elgamal_message_to_element(char const* buffer, size_t len, bool secure) {
+ return gcrypt_elgamal_array_to_element(buffer, len, secure);
+}
+
void gcrypt_elgamal_get_pub_key_hash(char** buffer, size_t* len, GroupElement const pub) {
gcry_sexp_t pubkey;
gcry_error_t error;
@@ -192,13 +196,24 @@ GroupElement gcrypt_elgamal_get_key_exchange_value(GroupElement group_el) {
return val;
}
-GroupElement gcrypt_elgamal_multiply(GroupElement lh, GroupElement rh, bool secure) {
+GroupElement gcrypt_elgamal_invert(GroupElement const el);
+void gcrypt_elgamal_delete_group_element(GroupElement el);
+
+GroupElement gcrypt_elgamal_combine(GroupElement lh, GroupElement rh, bool secure) {
gcry_mpi_t ret = secure ? gcry_mpi_snew(0) : gcry_mpi_new(0);
TRACE(__FILE__, __LINE__, ret);
gcry_mpi_mulm(ret, (gcry_mpi_t) lh, (gcry_mpi_t) rh, p);
return ret;
}
+GroupElement gcrypt_elgamal_uncombine(GroupElement lh, GroupElement rh, bool secure) {
+ (void) secure;
+ GroupElement inv_rh = gcrypt_elgamal_invert(rh);
+ GroupElement ret = gcrypt_elgamal_combine(lh, inv_rh, true);
+ gcrypt_elgamal_delete_group_element(inv_rh);
+ return ret;
+}
+
GroupElement gcrypt_elgamal_get_decryption_share(GroupElement r, GroupElement e) {
gcry_mpi_t inv_d = gcry_mpi_snew(nr_bits);
gcry_mpi_powm(inv_d, (gcry_mpi_t)r, (gcry_mpi_t)e, p);
@@ -217,6 +232,10 @@ size_t gcrypt_elgamal_get_group_element_array_size() {
return nr_bytes;
}
+size_t gcrypt_elgamal_get_message_size() {
+ return nr_bytes - 1;
+}
+
void gcrypt_elgamal_delete_group_element(void* el) {
gcry_mpi_release((gcry_mpi_t) el);
}
@@ -346,14 +365,17 @@ KeyPairDeleter elgamal_delete_keypair = &gcrypt_elgamal_delete_keypair;
ElementToArray elgamal_element_to_array = &gcrypt_elgamal_element_to_array;
BufferDeleter elgamal_free_buffer = &gcrypt_elgamal_free_buffer;
ArrayToElement elgamal_array_to_element = &gcrypt_elgamal_array_to_element;
+MessageToElement elgamal_message_to_element = &gcrypt_elgamal_message_to_element;
PubKeyHashGetter elgamal_get_pub_key_hash = &gcrypt_elgamal_get_pub_key_hash;
PubKeyHashLengthGetter elgamal_get_pub_key_hash_length = &gcrypt_elgamal_get_pub_key_hash_length;
GroupElementGetter elgamal_get_group_element = &gcrypt_elgamal_get_group_element;
GroupElementDeleter elgamal_delete_group_element = &gcrypt_elgamal_delete_group_element;
KeyExchangeValueGetter elgamal_get_key_exchange_value = &gcrypt_elgamal_get_key_exchange_value;
-GroupElementMultiplier elgamal_multiply = &gcrypt_elgamal_multiply;
+GroupElementCombiner elgamal_combine = &gcrypt_elgamal_combine;
+GroupElementUncombiner elgamal_uncombine = &gcrypt_elgamal_uncombine;
DecryptionShareGetter elgamal_get_decryption_share = &gcrypt_elgamal_get_decryption_share;
GroupElementArraySizeGetter elgamal_get_group_element_array_size = &gcrypt_elgamal_get_group_element_array_size;
+MessageSizeGetter elgamal_get_message_size = &gcrypt_elgamal_get_message_size;
PublicShareAdder elgamal_add_public_share = &gcrypt_elgamal_add_public_share;
SharedKeyDeriver elgamal_derive_shared_key = &gcrypt_elgamal_derive_shared_key;
SharedKeyDeleter elgamal_delete_shared_key = &gcrypt_elgamal_delete_shared_key;
diff --git a/libcmix-crypto/elgamal/null/CMakeLists.txt b/libcmix-crypto/elgamal/null/CMakeLists.txt
index a866428..c017bdc 100644
--- a/libcmix-crypto/elgamal/null/CMakeLists.txt
+++ b/libcmix-crypto/elgamal/null/CMakeLists.txt
@@ -1,6 +1,6 @@
include(get_target_name)
-get_target_name(target_name)
+get_target_name(target_name algo api)
add_library(${target_name} SHARED
null_elgamal.c
diff --git a/libcmix-crypto/elgamal/null/null_elgamal.c b/libcmix-crypto/elgamal/null/null_elgamal.c
index 2b5c43b..c626e63 100644
--- a/libcmix-crypto/elgamal/null/null_elgamal.c
+++ b/libcmix-crypto/elgamal/null/null_elgamal.c
@@ -36,7 +36,7 @@ ArrayToElement elgamal_array_to_element = NULL;//&null_elgamal_array_to_element;
GroupElementGetter elgamal_get_group_element = NULL;//&null_elgamal_get_group_element;
GroupElementDeleter elgamal_delete_group_element = NULL;//&null_elgamal_delete_group_element;
KeyExchangeValueGetter elgamal_get_key_exchange_value = NULL;//&null_elgamal_get_key_exchange_value;
-GroupElementMultiplier elgamal_multiply = NULL;//&null_elgamal_multiply;
+GroupElementCombiner elgamal_multiply = NULL;//&null_elgamal_multiply;
DecryptionShareGetter elgamal_get_decryption_share = NULL;//&null_elgamal_get_decryption_share;
GroupElementArraySizeGetter elgamal_get_group_element_array_size = NULL;//&null_elgamal_get_group_element_array_size;
PublicShareAdder elgamal_add_public_share = NULL;//&null_elgamal_add_public_share;
diff --git a/libcmix-crypto/impl_macros.h b/libcmix-crypto/impl_macros.h
new file mode 100644
index 0000000..15d8ddf
--- /dev/null
+++ b/libcmix-crypto/impl_macros.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#define VAR_IN_(x, y) x ## _ ## y
+#define VAR_IN(x, y) VAR_IN_(x, y)
+#define VAR(y) VAR_IN(ALGORITHM, y)
+#define DEF_IN_(x, y, z) x ## _ ## y ## _ ## z
+#define DEF_IN(x, y, z) DEF_IN_(x, y, z)
+#define DEF(z) DEF_IN(API, ALGORITHM, z)
+
+#define LINK_IMPLEMENTATION \
+Initializer VAR(initialize) = &DEF(initialize); \
+KeyPairCreator VAR(create_keypair) = &DEF(create_keypair); \
+KeyPairDeleter VAR(delete_keypair) = &DEF(delete_keypair); \
+ElementToArray VAR(element_to_array) = &DEF(element_to_array); \
+BufferDeleter VAR(free_buffer) = &DEF(free_buffer); \
+ArrayToElement VAR(array_to_element) = &DEF(array_to_element); \
+MessageToElement VAR(message_to_element) = &DEF(message_to_element); \
+ElementToMessage VAR(element_to_message) = &DEF(element_to_message); \
+PubKeyHashGetter VAR(get_pub_key_hash) = &DEF(get_pub_key_hash); \
+PubKeyHashLengthGetter VAR(get_pub_key_hash_length) = &DEF(get_pub_key_hash_length); \
+GroupElementGetter VAR(get_group_element) = &DEF(get_group_element); \
+GroupElementDeleter VAR(delete_group_element) = &DEF(delete_group_element); \
+KeyExchangeValueGetter VAR(get_key_exchange_value) = &DEF(get_key_exchange_value); \
+GroupElementCombiner VAR(combine) = &DEF(combine); \
+GroupElementUncombiner VAR(uncombine) = &DEF(uncombine); \
+DecryptionShareGetter VAR(get_decryption_share) = &DEF(get_decryption_share); \
+GroupElementArraySizeGetter VAR(get_group_element_array_size) = &DEF(get_group_element_array_size); \
+MessageSizeGetter VAR(get_message_size) = &DEF(get_message_size); \
+PublicShareAdder VAR(add_public_share) = &DEF(add_public_share); \
+SharedKeyDeriver VAR(derive_shared_key) = &DEF(derive_shared_key); \
+SharedKeyDeleter VAR(delete_shared_key) = &DEF(delete_shared_key); \
+Encrypter VAR(encrypt) = &DEF(encrypt); \
+Inverter VAR(invert) = &DEF(invert); \
+UniformIntGetter VAR(get_uniform_int) = &DEF(get_uniform_int); \
+Deinitializer VAR(deinitialize) = &DEF(deinitialize);
+
+//before expanding LINK_IMPLEMENTATION in your crypto api implementation file you need to define the following functions
+
+/*
+void DEF(initialize)(void) {}
+struct KeyPair DEF(create_keypair)(void) {}
+void DEF(delete_keypair)(struct KeyPair* pair) {}
+void DEF(element_to_array)(unsigned char** buffer, size_t* len, GroupElement element) {}
+void DEF(free_buffer)(void* buffer) {}
+GroupElement DEF(array_to_element)(char const* buffer, size_t len, bool secure) {}
+GroupElement DEF(message_to_element)(char const* buffer, size_t len, bool secure) {}
+void DEF(element_to_message)(char** buffer, const GroupElement el);
+size_t DEF(get_pub_key_hash_length)(void) {}
+void DEF(get_pub_key_hash)(char** buffer, size_t* len, GroupElement const pub) {}
+GroupElement DEF(get_group_element)(bool secure) {}
+GroupElement DEF(get_key_exchange_value)(GroupElement group_el) {}
+GroupElement DEF(combine)(GroupElement lh, GroupElement rh, bool secure) {}
+GroupElement DEF(uncombine)(GroupElement lh, GroupElement rh, bool secure) {}
+GroupElement DEF(get_decryption_share)(GroupElement r, GroupElement e) {}
+size_t DEF(get_group_element_array_size)(void) {}
+size_t DEF(get_message_size)(void) {}
+void DEF(delete_group_element)(GroupElement element) {}
+void DEF(add_public_share)(GroupElement* el, char const* share, size_t in_len, GroupElement pubkey) {}
+GroupElement DEF(derive_shared_key)(struct KeyPair keypair, unsigned char const* other_pub, size_t pub_len, unsigned char const* value, size_t value_len, void* priv_value, bool swap) {}
+void DEF(delete_shared_key)(struct SharedKey* s) {}
+void DEF(encrypt)(GroupElement* random_element, GroupElement* message_element, GroupElement value, GroupElement key) }
+GroupElement DEF(invert)(GroupElement const x) {}
+unsigned int DEF(get_uniform_int)(unsigned int upper) {}
+void DEF(deinitialize)(void) {}
+*/ \ No newline at end of file