diff --git a/.travis-tests.sh b/.travis-tests.sh index 95b5326f0..c410e2fd3 100755 --- a/.travis-tests.sh +++ b/.travis-tests.sh @@ -18,6 +18,10 @@ if [[ ${ENABLE_NTRU} == 1 ]];then enable_disable_str+=" --enable-ntru" fi +if [[ ${ENABLE_SIDH_IQC_REF} == 1 ]];then + enable_disable_str+=" --enable-sidhiqc" +fi + ./configure --enable-silent-rules ${enable_disable_str} make clean make diff --git a/.travis.yml b/.travis.yml index 98434d5ea..afd829cff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,13 +6,14 @@ matrix: include: - os: linux compiler: gcc - env: CC_OQS=gcc-4.8 + env: CC_OQS=gcc-4.8 ENABLE_SIDH_IQC_REF=1 addons: apt: sources: - ubuntu-toolchain-r-test packages: - gcc-4.8 + - libgmp-dev before_install: - sh .travis/install-clang-format-linux.sh - os: linux @@ -52,9 +53,9 @@ matrix: - bash download-and-build-ntru.sh - os: osx compiler: clang - env: CC_OQS=clang AES_NI=0 USE_OPENSSL=1 ENABLE_CODE_MCBITS=1 ENABLE_NTRU=1 - before_install: - - brew install clang-format openssl libsodium + env: CC_OQS=clang AES_NI=0 USE_OPENSSL=1 ENABLE_CODE_MCBITS=1 ENABLE_NTRU=1 ENABLE_SIDH_IQC_REF=1 +before_install: + - brew install clang-format openssl libsodium gmp - bash download-and-build-ntru.sh script: diff --git a/Makefile.am b/Makefile.am index 05c6fe85b..f3aa9a5c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,6 +30,10 @@ liboqs_la_LIBADD += src/kex_ntru/libntru.la liboqs_la_LIBADD += external/NTRUEncrypt-master/.libs/libntruencrypt.la endif +if USE_SIDH_IQC +liboqs_la_LIBADD += src/kex_sidh_iqc_ref/libsidhiqc.la +endif + noinst_bin_PROGRAMS = test_rand test_kex test_aes noinst_bindir=$(prefix)/tests test_kex_LDADD = liboqs.la -lm @@ -42,6 +46,9 @@ endif if USE_MCBITS test_kex_LDADD += -lsodium endif +if USE_SIDH_IQC +test_kex_LDADD += -lgmp +endif test_aes_LDADD = liboqs.la -lm test_aes_SOURCES = src/crypto/aes/test_aes.c @@ -101,6 +108,10 @@ endif if USE_NTRU $(LN_S) -f ../../src/kex_ntru/kex_ntru.h include/oqs endif +if USE_SIDH_IQC + $(LN_S) -f ../../src/kex_sidh_iqc_ref/kex_sidh_iqc_ref.h include/oqs + $(LN_S) -f src/kex_sidh_iqc_ref/sample_params +endif clean-local: rm -f liboqs.a diff --git a/configure.ac b/configure.ac index c6a770ac2..769425c40 100644 --- a/configure.ac +++ b/configure.ac @@ -69,14 +69,19 @@ ARG_ENABL_SET([ntru], [enable NTRU.]) AM_CONDITIONAL([ntru], [test "x$ntru" = xtrue]) AM_CONDITIONAL([USE_NTRU], [test "x$ntru" = xtrue]) +ARG_ENABL_SET([sidhiqc], [enable SIDH-IQC.]) +AM_CONDITIONAL([sidhiqc], [test "x$sidhiqc" = xtrue]) +AM_CONDITIONAL([USE_SIDH_IQC], [test "x$sidhiqc" = xtrue]) -AM_CPPFLAGS="-O3 -std=gnu11 -Wpedantic -Wall -Wextra -DCONSTANT_TIME" + +AM_CPPFLAGS="-g -std=gnu11 -Wpedantic -Wall -Wextra -DCONSTANT_TIME" AC_CANONICAL_HOST # Check for which host we are on and setup a few things # specifically based on the host case $host_os in darwin* ) OPENSSL_DIR=/usr/local/opt/openssl + GMP_DIR=/usr/local/opt/include AM_CONDITIONAL([ON_DARWIN], [test xtrue = xtrue]) ;; linux*) @@ -92,7 +97,6 @@ case $host_os in ;; esac - SRCDIR=" src/common src/crypto/aes src/kex src/crypto/rand src/crypto/sha3" SRCDIR=${SRCDIR}" src/crypto/rand_urandom_aesctr src/crypto/rand_urandom_chacha20" SRCDIR=${SRCDIR}" src/kex_rlwe_bcns15/" @@ -101,8 +105,6 @@ SRCDIR=${SRCDIR}" src/kex_lwe_frodo" SRCDIR=${SRCDIR}" src/kex_rlwe_msrln16" SRCDIR=${SRCDIR}" src/kex_sidh_cln16" - - if test x"$ntru" = x"true"; then AM_CPPFLAGS=${AM_CPPFLAGS}" -DENABLE_NTRU" SRCDIR=${SRCDIR}" src/kex_ntru" @@ -121,6 +123,12 @@ if test x"$openssl" = x"true"; then AM_CPPFLAGS=${AM_CPPFLAGS}" -DUSE_OPENSSL" fi +if test x"$sidhiqc" = x"true"; then + AM_CPPFLAGS=${AM_CPPFLAGS}" -DENABLE_SIDH_IQC_REF" + SRCDIR=${SRCDIR}" src/kex_sidh_iqc_ref" +fi + + AC_SUBST(AM_CPPFLAGS) AC_SUBST(SRCDIR) AC_SUBST(OPENSSL_DIR) @@ -128,7 +136,9 @@ AC_SUBST(USE_OPENSSL) AC_SUBST(USE_AES_NI) AC_SUBST(USE_NTRU) AC_SUBST(USE_MCBITS) +AC_SUBST(USE_SIDH_IQC) AC_SUBST(ON_DARWIN) +AC_SUBST(GMP_DIR) AC_CONFIG_FILES([Makefile @@ -145,6 +155,7 @@ AC_CONFIG_FILES([Makefile src/kex_sidh_cln16/Makefile src/kex_code_mcbits/Makefile src/kex_ntru/Makefile + src/kex_sidh_iqc_ref/Makefile src/kex_lwe_frodo/Makefile]) AC_OUTPUT diff --git a/src/kex/kex.c b/src/kex/kex.c index be468c27b..703bbde9f 100644 --- a/src/kex/kex.c +++ b/src/kex/kex.c @@ -14,6 +14,7 @@ #ifdef ENABLE_NTRU #include #endif +#include OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8_t *seed, const size_t seed_len, const char *named_parameters) { switch (alg_name) { @@ -43,6 +44,12 @@ OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8 #else assert(0); #endif + case OQS_KEX_alg_sidh_iqc_ref: +#ifdef ENABLE_SIDH_IQC_REF + return OQS_KEX_sidh_iqc_ref_new(rand); +#else + assert(0); +#endif default: assert(0); diff --git a/src/kex/kex.h b/src/kex/kex.h index 996917d48..82249d899 100644 --- a/src/kex/kex.h +++ b/src/kex/kex.h @@ -20,6 +20,7 @@ enum OQS_KEX_alg_name { OQS_KEX_alg_sidh_cln16, OQS_KEX_alg_code_mcbits, OQS_KEX_alg_ntru, + OQS_KEX_alg_sidh_iqc_ref, }; typedef struct OQS_KEX OQS_KEX; diff --git a/src/kex/test_kex.c b/src/kex/test_kex.c index b2daa838d..2a61aa69f 100644 --- a/src/kex/test_kex.c +++ b/src/kex/test_kex.c @@ -25,6 +25,9 @@ struct kex_testcase kex_testcases[] = { {OQS_KEX_alg_rlwe_msrln16, NULL, 0, NULL, "rlwe_msrln16", 0, 100}, {OQS_KEX_alg_lwe_frodo, (unsigned char *) "01234567890123456", 16, "recommended", "lwe_frodo_recommended", 0, 100}, {OQS_KEX_alg_sidh_cln16, NULL, 0, NULL, "sidh_cln16", 0, 10}, +#ifdef ENABLE_SIDH_IQC_REF + {OQS_KEX_alg_sidh_iqc_ref, NULL, 0, NULL, "sidh_iqc_ref", 0, 10}, +#endif #ifdef ENABLE_CODE_MCBITS {OQS_KEX_alg_code_mcbits, NULL, 0, NULL, "code_mcbits", 0, 25}, #endif diff --git a/src/kex_sidh_iqc_ref/Makefile.am b/src/kex_sidh_iqc_ref/Makefile.am new file mode 100644 index 000000000..90c0d281b --- /dev/null +++ b/src/kex_sidh_iqc_ref/Makefile.am @@ -0,0 +1,10 @@ +AUTOMAKE_OPTIONS = foreign +noinst_LTLIBRARIES = libsidhiqc.la + + +libsidhiqc_la_SOURCES = kex_sidh_iqc_ref.c sidh_elliptic_curve.c sidh_elliptic_curve_dlp.c sidh_isogeny.c +libsidhiqc_la_SOURCES += sidh_private_key.c sidh_public_key.c sidh_public_key_encryption.c sidh_public_key_validation.c +libsidhiqc_la_SOURCES += sidh_public_param.c sidh_quadratic_ext.c sidh_shared_key.c sidh_util.c +libsidhiqc_la_CPPFLAGS = -I../../include -I.-fPIC +libsidhiqc_la_CPPFLAGS += $(AM_CPPFLAGS) -I$(GMP_DIR) + diff --git a/src/kex_sidh_iqc_ref/kex_sidh_iqc_ref.c b/src/kex_sidh_iqc_ref/kex_sidh_iqc_ref.c new file mode 100644 index 000000000..a7cbb68b7 --- /dev/null +++ b/src/kex_sidh_iqc_ref/kex_sidh_iqc_ref.c @@ -0,0 +1,208 @@ +#if defined(WINDOWS) +#define UNUSED +#else +#define UNUSED __attribute__((unused)) +#endif + +#include +#include +#include +#include "sidh_elliptic_curve.h" +#include "sidh_public_param.h" +#include "sidh_isogeny.h" +#include "sidh_private_key.h" +#include "sidh_public_key.h" +#include "sidh_shared_key.h" +#include "kex_sidh_iqc_ref.h" + +OQS_KEX *OQS_KEX_sidh_iqc_ref_new(OQS_RAND *rand) { + + OQS_KEX *k = malloc(sizeof(OQS_KEX)); + if (k == NULL) { + return NULL; + } + + // initialize + // char *input_params = "sample_params/public_params_771"; + public_params_t *params = + (public_params_t *) malloc(2 * sizeof(public_params_t)); + oqs_sidh_iqc_ref_public_params_init(params[0]); + oqs_sidh_iqc_ref_public_params_init(params[1]); + + if (!oqs_sidh_iqc_ref_public_params_read(params[0], params[1], "sample_params/public_params_771")) + return NULL; + + oqs_sidh_iqc_ref_fp_init_chararacteristic(params[0]->characteristic); + + k->rand = rand; + k->method_name = strdup("SIDH IQC REFERENCE"); + k->estimated_classical_security = 192; + k->estimated_quantum_security = 128; + k->seed = NULL; + k->seed_len = 0; + k->named_parameters = strdup("sample_params/public_params_771"); + k->params = params; + k->ctx = NULL; + k->alice_0 = &OQS_KEX_sidh_iqc_ref_alice_0; + k->bob = &OQS_KEX_sidh_iqc_ref_bob; + k->alice_1 = &OQS_KEX_sidh_iqc_ref_alice_1; + k->alice_priv_free = &OQS_KEX_sidh_iqc_ref_alice_priv_free; + k->free = &OQS_KEX_sidh_iqc_ref_free; + + return k; +} + +int OQS_KEX_sidh_iqc_ref_alice_0(OQS_KEX *k, void **alice_priv, + uint8_t **alice_msg, size_t *alice_msg_len) { + + public_params_t *params = (public_params_t *) k->params; + private_key_t Alice_private_key; + oqs_sidh_iqc_ref_private_key_init(Alice_private_key); + oqs_sidh_iqc_ref_private_key_generate(Alice_private_key, params[0]); + + public_key_t Alice_public_key; + oqs_sidh_iqc_ref_public_key_init(Alice_public_key); + point_t kernel_gen; + oqs_sidh_iqc_ref_point_init(kernel_gen); + oqs_sidh_iqc_ref_private_key_compute_kernel_gen(kernel_gen, Alice_private_key, + params[0]->P, params[0]->Q, + params[0]->le, params[0]->E); + oqs_sidh_iqc_ref_public_key_generate(Alice_public_key, kernel_gen, params[0], + params[1]); + + // sizes in bytes + uint32_t prime_size = (mpz_sizeinbase(characteristic, 2) + 7) / 8; + uint32_t private_key_size = 2 * prime_size; + uint32_t public_key_size = 12 * prime_size; + + *alice_priv = NULL; + *alice_msg = NULL; + *alice_priv = malloc(private_key_size); + *alice_msg = malloc(public_key_size); + *alice_msg_len = public_key_size; + + oqs_sidh_iqc_ref_private_key_to_bytes((uint8_t *) *alice_priv, + Alice_private_key, prime_size); + oqs_sidh_iqc_ref_public_key_to_bytes((uint8_t *) *alice_msg, Alice_public_key, + prime_size); + + oqs_sidh_iqc_ref_private_key_clear(Alice_private_key); + oqs_sidh_iqc_ref_public_key_clear(Alice_public_key); + oqs_sidh_iqc_ref_point_clear(kernel_gen); + + return 1; +} + +int OQS_KEX_sidh_iqc_ref_bob(OQS_KEX *k, const uint8_t *alice_msg, + UNUSED const size_t alice_msg_len, + uint8_t **bob_msg, size_t *bob_msg_len, + uint8_t **key, size_t *key_len) { + + public_params_t *params = (public_params_t *) k->params; + + private_key_t Bob_private_key; + oqs_sidh_iqc_ref_private_key_init(Bob_private_key); + oqs_sidh_iqc_ref_private_key_generate(Bob_private_key, params[1]); + + public_key_t Bob_public_key; + oqs_sidh_iqc_ref_public_key_init(Bob_public_key); + point_t kernel_gen; + oqs_sidh_iqc_ref_point_init(kernel_gen); + oqs_sidh_iqc_ref_private_key_compute_kernel_gen(kernel_gen, Bob_private_key, + params[1]->P, params[1]->Q, + params[1]->le, params[1]->E); + oqs_sidh_iqc_ref_public_key_generate(Bob_public_key, kernel_gen, params[1], + params[0]); + + // sizes in bytes + uint32_t prime_size = (mpz_sizeinbase(characteristic, 2) + 7) / 8; + uint32_t public_key_size = 12 * prime_size; + uint32_t shared_key_size = 2 * prime_size; + + *bob_msg = NULL; + *key = NULL; + *bob_msg = malloc(public_key_size); + *key = malloc(shared_key_size); + *bob_msg_len = public_key_size; + *key_len = shared_key_size; + + oqs_sidh_iqc_ref_public_key_to_bytes((uint8_t *) *bob_msg, Bob_public_key, + prime_size); + + public_key_t Alice_public_key; + oqs_sidh_iqc_ref_public_key_init(Alice_public_key); + oqs_sidh_iqc_ref_bytes_to_public_key(Alice_public_key, alice_msg, prime_size); + + fp2_element_t Bob_shared_key; + oqs_sidh_iqc_ref_fp2_init(Bob_shared_key); + oqs_sidh_iqc_ref_shared_key_generate(Bob_shared_key, Alice_public_key, + Bob_private_key, params[1]); + + oqs_sidh_iqc_ref_fp2_to_bytes((uint8_t *) *key, Bob_shared_key, prime_size); + + oqs_sidh_iqc_ref_public_key_clear(Alice_public_key); + oqs_sidh_iqc_ref_private_key_clear(Bob_private_key); + oqs_sidh_iqc_ref_public_key_clear(Bob_public_key); + oqs_sidh_iqc_ref_point_clear(kernel_gen); + oqs_sidh_iqc_ref_fp2_clear(Bob_shared_key); + + return 1; +} + +int OQS_KEX_sidh_iqc_ref_alice_1(OQS_KEX *k, const void *alice_priv, + const uint8_t *bob_msg, + UNUSED const size_t bob_msg_len, uint8_t **key, + size_t *key_len) { + + public_params_t *params = (public_params_t *) k->params; + + // sizes in bytes + uint32_t prime_size = (mpz_sizeinbase(characteristic, 2) + 7) / 8; + uint32_t shared_key_size = 2 * prime_size; + + *key = NULL; + *key_len = shared_key_size; + *key = malloc(shared_key_size); + + private_key_t Alice_private_key; + oqs_sidh_iqc_ref_private_key_init(Alice_private_key); + oqs_sidh_iqc_ref_bytes_to_private_key(Alice_private_key, alice_priv, + prime_size); + + public_key_t Bob_public_key; + oqs_sidh_iqc_ref_public_key_init(Bob_public_key); + oqs_sidh_iqc_ref_bytes_to_public_key(Bob_public_key, bob_msg, prime_size); + + fp2_element_t Alice_shared_key; + oqs_sidh_iqc_ref_fp2_init(Alice_shared_key); + oqs_sidh_iqc_ref_shared_key_generate(Alice_shared_key, Bob_public_key, + Alice_private_key, params[0]); + + oqs_sidh_iqc_ref_fp2_to_bytes((uint8_t *) *key, Alice_shared_key, prime_size); + + oqs_sidh_iqc_ref_private_key_clear(Alice_private_key); + oqs_sidh_iqc_ref_public_key_clear(Bob_public_key); + oqs_sidh_iqc_ref_fp2_clear(Alice_shared_key); + + return 1; +} + +void OQS_KEX_sidh_iqc_ref_alice_priv_free(UNUSED OQS_KEX *k, void *alice_priv) { + if (alice_priv) { + free(alice_priv); + } +} + +void OQS_KEX_sidh_iqc_ref_free(OQS_KEX *k) { + if (!k) { + return; + } + + oqs_sidh_iqc_ref_public_params_clear(((public_params_t *) (k->params))[0]); + oqs_sidh_iqc_ref_public_params_clear(((public_params_t *) (k->params))[1]); + free(k->params); + k->ctx = NULL; + free(k->method_name); + k->method_name = NULL; + free(k); +} diff --git a/src/kex_sidh_iqc_ref/kex_sidh_iqc_ref.h b/src/kex_sidh_iqc_ref/kex_sidh_iqc_ref.h new file mode 100644 index 000000000..a839c76b2 --- /dev/null +++ b/src/kex_sidh_iqc_ref/kex_sidh_iqc_ref.h @@ -0,0 +1,28 @@ + +#ifndef KEX_SIDH_IQC_REF_H +#define KEX_SIDH_IQC_REF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include +#include + +OQS_KEX *OQS_KEX_sidh_iqc_ref_new(OQS_RAND *rand); + +int OQS_KEX_sidh_iqc_ref_alice_0(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len); +int OQS_KEX_sidh_iqc_ref_bob(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len); +int OQS_KEX_sidh_iqc_ref_alice_1(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len); + +void OQS_KEX_sidh_iqc_ref_alice_priv_free(OQS_KEX *k, void *alice_priv); +void OQS_KEX_sidh_iqc_ref_free(OQS_KEX *k); + +#ifdef __cplusplus +} +#endif + +#endif /* KEX_SIDH_IQC_REF_H */ diff --git a/src/kex_sidh_iqc_ref/sample_params/public_params_263 b/src/kex_sidh_iqc_ref/sample_params/public_params_263 new file mode 100644 index 000000000..1df47abe1 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sample_params/public_params_263 @@ -0,0 +1,10 @@ +p : 13278338917780691403163453935679248163066204141424819568321422575495838416502783 +E : y^2 = x^3 + (10146232096640085910917654383121220722483913358884738813297160334128811466415525*i+12561065565697579851239386918801659303795666601356542822684985096240783059294353)*x + (5173097881985929355869345579251684505584624561073144550698251610858120795396524*i+7107679418274528586696192790945059679329002947961173384005281572895084003568218) +lA: 2 +eA: 130 +PA: (1195124728519659060317276132092013999345554256425666367370465963951595701748339*i + 12098972036709468461769702810131237350914726908853501736574286596252384974205652, 9783772475920257416467468866150378267376245694752823265285613818169901942309758*i + 11347159712348451494564706572599934965946403356550033502368700150470499448870987) +QA: (13205817885805264818436305084890835188490919868599289846511015770901764583677253*i + 5747572646648472262100078852868099320898697620053049578554081522615552834142382, 11801682343040573989191884352262922625922977024975963745404870899756844108073781*i + 995065035530346107238957276796927946979246210950956147759509023538740100220494) +lB: 3 +eB: 81 +PB: (5344800255669587458309912385997503623935901519546261901204157001079956379346933*i + 4377688844822469620769951245537289173274736372423169606270308984109645753298367, 6652276474756696057821879367411351758786745790244544252917780253177388224676512*i + 6708409928090950067466623637647088247028372838873736207829979327577754417492323) +QB: (5394161621076087291764603321428338049084294313968048256313378341079709241759382*i + 11839282739753708776384780179031575074752559110018400195581350405443930573103478, 13250321748367194013481592159238890438519376028036613608154243555537109237538486*i + 5018156126061581597984382235576466750307112019427938373002833669914648135622879) diff --git a/src/kex_sidh_iqc_ref/sample_params/public_params_46 b/src/kex_sidh_iqc_ref/sample_params/public_params_46 new file mode 100644 index 000000000..b6dbc7bd1 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sample_params/public_params_46 @@ -0,0 +1,10 @@ +p : 60183678025727 +E : y^2 = x^3 + (33377407586757 * i + 44218433491776) * x + (14267804413813 * i + 34113052821919) +lA: 2 +eA: 22 +PA: (3621292231555 * i + 37993208494088, 7444041801194 * i + 49342879615307) +QA: (42474562877393 * i + 53371276514445, 2096833973245 * i + 34935006825293) +lB: 3 +eB: 15 +PB: (15834791163149 * i + 48632673242917, 26787723276578 * i + 2080970701160) +QB: (41347477823487 * i + 16893996428645, 16353006256863 * i + 58871308637793) diff --git a/src/kex_sidh_iqc_ref/sample_params/public_params_521 b/src/kex_sidh_iqc_ref/sample_params/public_params_521 new file mode 100644 index 000000000..8f927ed07 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sample_params/public_params_521 @@ -0,0 +1,10 @@ +p : 5646428529833603710854376801719732121889771686125102421349898409102848702003905102057129871853579459735758942656769724874115169484320460874488881525976727551 +E : y^2 = x^3 + (749284552715987846148963973296050195126229569341142224654666772427960869882697237787535113296933915107646826510805251959952317725821624926383192023779227916*i+4450862168665197219135947325665108840719206715065697554561201799074300990784248608236935291171911258967881216685164820345027022153809546719817771293646383402)*x + (2090701186560231235295975659537182225064154823783034367876346818451609525370628921026656891712603865222854303410638520367213822274197422708317359681412801686*i+928331116130151780314451251635374082476545231185861659046556547242876069870814548070746611568992085667981514874929668958586384832118048434225604407758374282) +lA: 2 +eA: 258 +PA: (4099566244205693793351119863629118684504739011975746402268940060566068632610815266810397027797757094816929218567651253950072216325440815687610023993835084896*i + 1558017772998619899443036875935946235185689333987633624537644882488763783158554538347022310514300405167644627965823931934377803788161014061154800653636626931, 4309963503463625615680726988334053841208952164733703323705989592325431854359074218382917880219717866947948218257035199142577782828393068620191995480863080814*i + 371139087724151319343471759858355552237686119972572871121509307705868621618190178855645217401101942092226237837619601742237974591506374361483536984282167861) +QA: (1068668697541208179714192612921089347931894414290359842562082470165052062241629674686530102495737378212525479245784252461983051355518227298502808569246918728*i + 3439758296201500299118396242846510199830393172149382335887091564620130903972985332523718369650346601985540123834734249105539074407495456634862920938577617312, 1377114633894100174167466575056453645918713530999472681191914854993325497527119824352424425031078252594689770391880104513192317018010057467691025379460070671*i + 4932622986840321005380766859714312144000718130204073302754586852541324804616229501269099878044960212632820224170853684078869359092914886360672352750928115581) +lB: 3 +eB: 161 +PB: (1873601143875829767876930991819826178988629054425671567488176037109831662817961473686026144306947256312476316751547084289880741326649856082832561714610850944*i + 1560175318533519875886314144935322002014985257654221707041583923868859979591849198401249634353361077499233198751747045058302746944304448268907689086502178616, 4982994975025169124121736752171094366264972439763192439008272414941290947933013927951198144521578535758162978083130741822789277050594650669549067865269480720*i + 5276260709601376725929198456951440724276715138987805447686932240717621617089316893818094566900580557346731678327745302440662762271627385800896501795127323769) +QB: (697646709404910236660735870475422491121726200391885074740251760174191839071888445718446637282034941836922171390196797602747505117748596104805560163856490804*i + 3625576702015594834652275264908614642470435266304155762812699923280767886451566560460365242828862442624975825786369269113406701427398318872227046324990780609, 4066773540363717441440268891591433184568174886592697891244632377954091519594774358483000191238791345767299029423088482812653880802118173619454377886226640626*i + 4190003034380720563592676434553383980850520959077934081654167677748426947392920518786394581045699661017779519240551462796264093681413592624709890262004623150) diff --git a/src/kex_sidh_iqc_ref/sample_params/public_params_771 b/src/kex_sidh_iqc_ref/sample_params/public_params_771 new file mode 100644 index 000000000..88def0999 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sample_params/public_params_771 @@ -0,0 +1,11 @@ +p : 9161191555982008052298538759697325872858383005444503030763917191888120427263653604739574602371851919945332710234806205297475768266460658683484318356498713773944703702864057467786913144364234277796785269800198817400814717913480036351 +E : y^2 = x^3 + (834414288954992257633455994192711449929625512434805347027412475310171948875352369017186937444645005409828817983476510572586689796723205608064400704385270116308944492168385499542550868452776212626111499661118550170888024552876875729*i+6422246000772528873002015578224375300444670334298744905928223359513938843110113655634334268879522218663819121887750824098836054966064056104287198717041277477329053582144813207672147369924203318339728355843554541603191165928512397074)*x + (6952862402661321818296934608460489441319492072429008834217170925899505712694617760090534612163651714423387662001257443691685988562319647888954263195545834510820670121276853179853453135161349568882745925527747286264586000816122662211*i+1801461307959256058754493292728237821856779795303869606357346421878164668617118529630863155614277813374785952465141324739461376333648338471745996274618770379494305097783365807731152848487472399799827998470890201827624741461111844749) +lA: 2 +eA: 386 +PA: (8104593598414300086705087098908311675030394399959710332294184564762361863835814307651327024806690095568546280563692186849608460564606528773115207348687739021740029922619947714003573784888374548470687911506820492526985145356335776446*i + 632723349492681895135768435670357424582748082370711990704098097526814363254991414123449305576539513413267774301605548017161074510859073483979044361740779150098452314120335316096416597425252882878881588818896781804191220848731008911, 6034454472695438020325443031188950458345445112930585331722482288319997086142640364760979210290700670085317874428427766978327706213014073448960161802245001428613528860063394247112544226096847944993689243523414240839321526974724280084*i + 3376800547075148066131970733541260743185153743453912100162319249600572606491084521062090319658073231669236186390422247468127880255567740549554667385892315318084299520660699776774656198376921140804260118165199828142540405774846853362) +QA: (2765053530820933445180998871832795313413946616218824127593215418859013295660994609348273546952174346166291903038023352135058779784133949653750586420316372475215070348272866065120539728715859798970386824706592072979142529191135265323*i + 4732630024306258879927225136904171174931421517225731042645253305380470569884989406374249571295113204909266761424593068942210539695621294791558555039840356194123377363470161894673618251481432584334320864233790205509164494505329331140, 4708584843807409676003733183136845288008597122413250473476957203240325041335536376819164132204831789648003763063194049792870695914267484368767687682889171445457695974399304884657394666807097601382128550039198416659937221320896980595*i + 6104437072476030203734870744361913380396342850775889826642334399814339224961644051070388756974954400647041041004040997989961961816982978689836414675142946310418861822777207486737128660492374354598010889893873060781304652392500710082) +lB: 3 +eB: 242 +PB: (3723895349260758944309889666952259909100424286764560948312844268916772080039091215194337476636106420561414206591006321840112505108525982835492286766266110460566937541551059011352798312867785900902951383836578444811900436603779674156*i + 8743733696371247709279217014221258693400652288884395784267041686740452975091187425123471886102340505926375682973850553993788314479705338557349284829716634286210825839825870379330100097103593148671390855900137936801780665161878467993, 8424241650394632026078421716292833598872223719053431149109783663376931645995151278886785513466077121063748132909299925706619410172763350254899661370368971798311266097772796416940961537063436478392108549760549489321636110323643921123*i + 5374610701506876802640722880318277643810083668249556787469960695884056089879250039154916755196748541850985290281804798435130927222521567170894905772855374873224510597225929994186728464447646660504589278345473514974074045904197344273) +QB: (7981195513789185488304157075392399068225052449489399943063249773724560281912789833792310612686835775356813196319643714519912123781500389027567621573946130157326769787082613646934296091151487953874493791717298439146548339580934348575*i + 6959299245778867305112554827985507377113662771316265280990751282080086185858550157506531552361757479904416443825479048359163719118671413144273420888615839877660288012435298448942304481059091585291706567711227879486375625133765783910, 4336888647745442057861067196613721067586889048321014506728806821392030059558638097842307835657146159647787621123250859783441147632121339894258934458102109985684014691372520469809743302874968486912740925764328254939284436994206821845*i + 219245698132319235934495637714582743670714862281024333766283207034829039474459867538486706426384326703893620364910932534607493596118208826082598798090838576408297983032654112984263431060439529497966028364279027386883785406090014775) + diff --git a/src/kex_sidh_iqc_ref/sidh_elliptic_curve.c b/src/kex_sidh_iqc_ref/sidh_elliptic_curve.c new file mode 100644 index 000000000..47b8daaae --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_elliptic_curve.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include + +#include "sidh_elliptic_curve.h" +#include "sidh_util.h" +#include + +void oqs_sidh_iqc_ref_elliptic_curve_init(elliptic_curve_t E) { + oqs_sidh_iqc_ref_fp2_init_set_si(E->a, 0, 1); + oqs_sidh_iqc_ref_fp2_init_set_si(E->b, 0, 1); +} + +void oqs_sidh_iqc_ref_elliptic_curve_set(elliptic_curve_t E, + const elliptic_curve_t T) { + oqs_sidh_iqc_ref_fp2_set(E->a, T->a); + oqs_sidh_iqc_ref_fp2_set(E->b, T->b); +} + +void oqs_sidh_iqc_ref_elliptic_curve_set_coeffs(elliptic_curve_t E, + const fp2_element_t a, + const fp2_element_t b) { + oqs_sidh_iqc_ref_fp2_set(E->a, a); + oqs_sidh_iqc_ref_fp2_set(E->b, b); +} + +void oqs_sidh_iqc_ref_point_init(point_t P) { + oqs_sidh_iqc_ref_fp2_init(P->x); + oqs_sidh_iqc_ref_fp2_init(P->y); + oqs_sidh_iqc_ref_point_zero(P); +} + +void oqs_sidh_iqc_ref_point_set_coordinates(point_t P, + const fp2_element_t x, + const fp2_element_t y, + int z) { + oqs_sidh_iqc_ref_fp2_set(P->x, x); + oqs_sidh_iqc_ref_fp2_set(P->y, y); + P->z = z; +} + +void oqs_sidh_iqc_ref_point_set(point_t P, + const point_t Q) { + oqs_sidh_iqc_ref_point_set_coordinates(P, Q->x, Q->y, Q->z); +} + +void oqs_sidh_iqc_ref_point_zero(point_t P) { + oqs_sidh_iqc_ref_fp2_zero(P->x); + oqs_sidh_iqc_ref_fp2_one(P->y); + P->z = 0; +} + +int oqs_sidh_iqc_ref_point_is_zero(const point_t P) { + return P->z == 0; +} + +void oqs_sidh_iqc_ref_point_negate(point_t P, + const point_t Q) { + oqs_sidh_iqc_ref_point_set(P, Q); + oqs_sidh_iqc_ref_fp2_negate(P->y, P->y); +} + +int oqs_sidh_iqc_ref_point_has_order_2(const point_t P) { + return oqs_sidh_iqc_ref_fp2_is_zero(P->y); +} + +void oqs_sidh_iqc_ref_elliptic_curve_clear(elliptic_curve_t E) { + oqs_sidh_iqc_ref_fp2_clear(E->a); + oqs_sidh_iqc_ref_fp2_clear(E->b); +} + +void oqs_sidh_iqc_ref_point_clear(point_t P) { + oqs_sidh_iqc_ref_fp2_clear(P->x); + oqs_sidh_iqc_ref_fp2_clear(P->y); +} + +int oqs_sidh_iqc_ref_point_equals(const point_t P, + const point_t Q) { + return oqs_sidh_iqc_ref_fp2_equals(P->x, Q->x) && + oqs_sidh_iqc_ref_fp2_equals(P->y, Q->y) && + (P->z == Q->z); +} + +char *oqs_sidh_iqc_ref_elliptic_curve_get_str(const elliptic_curve_t E) { + char *result = ""; + result = oqs_sidh_iqc_ref_concat(result, "y^2 = x^3"); + if (!oqs_sidh_iqc_ref_fp2_is_zero(E->a)) { + result = oqs_sidh_iqc_ref_concat(result, " + ("); + result = oqs_sidh_iqc_ref_concat(result, oqs_sidh_iqc_ref_fp2_get_str(E->a)); + result = oqs_sidh_iqc_ref_concat(result, ")"); + result = oqs_sidh_iqc_ref_concat(result, " * x"); + } + + if (!oqs_sidh_iqc_ref_fp2_is_zero(E->b)) { + result = oqs_sidh_iqc_ref_concat(result, " + ("); + result = oqs_sidh_iqc_ref_concat(result, oqs_sidh_iqc_ref_fp2_get_str(E->b)); + result = oqs_sidh_iqc_ref_concat(result, ")"); + } + + return result; +} + +char *oqs_sidh_iqc_ref_point_get_str(const point_t P) { + char *result = ""; + result = oqs_sidh_iqc_ref_concat(result, "("); + result = oqs_sidh_iqc_ref_concat(result, oqs_sidh_iqc_ref_fp2_get_str(P->x)); + result = oqs_sidh_iqc_ref_concat(result, " : "); + result = oqs_sidh_iqc_ref_concat(result, oqs_sidh_iqc_ref_fp2_get_str(P->y)); + result = oqs_sidh_iqc_ref_concat(result, " : "); + result = oqs_sidh_iqc_ref_concat(result, (P->z == 1 ? "1" : "0")); + result = oqs_sidh_iqc_ref_concat(result, ")"); + + return result; +} + +void oqs_sidh_iqc_ref_point_add_with_lambda(point_t R, + const point_t P, + const point_t Q, + const fp2_element_t lambda) { + point_t result; + oqs_sidh_iqc_ref_point_init(result); + result->z = 1; + + // x_R = lambda^2 - x_P - x_Q + oqs_sidh_iqc_ref_fp2_square(result->x, lambda); + oqs_sidh_iqc_ref_fp2_sub(result->x, result->x, P->x); + oqs_sidh_iqc_ref_fp2_sub(result->x, result->x, Q->x); + + // y_R = lambda * (x_P - x_R) - y_P + oqs_sidh_iqc_ref_fp2_sub(result->y, P->x, result->x); + oqs_sidh_iqc_ref_fp2_mul(result->y, result->y, lambda); + oqs_sidh_iqc_ref_fp2_sub(result->y, result->y, P->y); + oqs_sidh_iqc_ref_point_set(R, result); + + oqs_sidh_iqc_ref_point_clear(result); +} + +void oqs_sidh_iqc_ref_point_double(point_t R, + const point_t P, + const elliptic_curve_t E) { + if (oqs_sidh_iqc_ref_point_is_zero(P)) { + oqs_sidh_iqc_ref_point_zero(R); + return; + } + + // check if the point is of order 2 + if (oqs_sidh_iqc_ref_point_has_order_2(P)) { + oqs_sidh_iqc_ref_point_zero(R); + return; + } + + fp2_element_t temp; + fp2_element_t lambda; + + oqs_sidh_iqc_ref_fp2_init(temp); + oqs_sidh_iqc_ref_fp2_init(lambda); + + // lambda = (3(x_P)^2 + a) / (2y_p) + oqs_sidh_iqc_ref_fp2_square(lambda, P->x); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(lambda, lambda, 3); + oqs_sidh_iqc_ref_fp2_add(lambda, lambda, E->a); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(temp, P->y, 2); + oqs_sidh_iqc_ref_fp2_div(lambda, lambda, temp); + + oqs_sidh_iqc_ref_point_add_with_lambda(R, P, P, lambda); + + oqs_sidh_iqc_ref_fp2_clear(temp); + oqs_sidh_iqc_ref_fp2_clear(lambda); +} + +void oqs_sidh_iqc_ref_point_add(point_t R, + const point_t P, + const point_t Q, + const elliptic_curve_t E) { + if (oqs_sidh_iqc_ref_point_is_zero(P)) { + oqs_sidh_iqc_ref_point_set(R, Q); + return; + } + + if (oqs_sidh_iqc_ref_point_is_zero(Q)) { + oqs_sidh_iqc_ref_point_set(R, P); + return; + } + + if (oqs_sidh_iqc_ref_fp2_equals(P->x, Q->x)) { + if (oqs_sidh_iqc_ref_fp2_equals(P->y, Q->y)) { + oqs_sidh_iqc_ref_point_double(R, P, E); + return; + } + + oqs_sidh_iqc_ref_point_zero(R); + return; + } + + fp2_element_t temp; + fp2_element_t lambda; + + oqs_sidh_iqc_ref_fp2_init(temp); + oqs_sidh_iqc_ref_fp2_init(lambda); + + // lambda = (y_Q - y_P) / (x_Q - x_P) + oqs_sidh_iqc_ref_fp2_sub(lambda, Q->y, P->y); + oqs_sidh_iqc_ref_fp2_sub(temp, Q->x, P->x); + oqs_sidh_iqc_ref_fp2_div(lambda, lambda, temp); + + oqs_sidh_iqc_ref_point_add_with_lambda(R, P, Q, lambda); + + oqs_sidh_iqc_ref_fp2_clear(temp); + oqs_sidh_iqc_ref_fp2_clear(lambda); +} + +void oqs_sidh_iqc_ref_point_sub(point_t R, + const point_t P, + const point_t Q, + const elliptic_curve_t E) { + point_t temp; + oqs_sidh_iqc_ref_point_init(temp); + oqs_sidh_iqc_ref_point_negate(temp, Q); + oqs_sidh_iqc_ref_point_add(R, P, temp, E); + oqs_sidh_iqc_ref_point_clear(temp); +} + +void oqs_sidh_iqc_ref_point_mul_scaler(point_t R, + const point_t P, + const mpz_t scaler, + const elliptic_curve_t E) { + if (mpz_cmp_ui(scaler, 0) == 0) { + oqs_sidh_iqc_ref_point_zero(R); + return; + } + + if (mpz_cmp_ui(scaler, 1) == 0) { + oqs_sidh_iqc_ref_point_set(R, P); + return; + } + + point_t R0; + point_t R1; + + oqs_sidh_iqc_ref_point_init(R0); + oqs_sidh_iqc_ref_point_init(R1); + oqs_sidh_iqc_ref_point_set(R1, P); + + long num_bits = mpz_sizeinbase(scaler, 2); + for (long i = 0; i < num_bits; i++) { + if (mpz_tstbit(scaler, i) == 1) + oqs_sidh_iqc_ref_point_add(R0, R0, R1, E); + oqs_sidh_iqc_ref_point_double(R1, R1, E); + } + + if (mpz_sgn(scaler) < 0) + oqs_sidh_iqc_ref_point_negate(R0, R0); + + oqs_sidh_iqc_ref_point_set(R, R0); + oqs_sidh_iqc_ref_point_clear(R0); + oqs_sidh_iqc_ref_point_clear(R1); +} + +void oqs_sidh_iqc_ref_point_mul_scaler_si(point_t R, + const point_t P, + long scaler, + const elliptic_curve_t E) { + mpz_t temp; + mpz_init_set_si(temp, scaler); + oqs_sidh_iqc_ref_point_mul_scaler(R, P, temp, E); + mpz_clear(temp); +} + +void oqs_sidh_iqc_ref_elliptic_curve_compute_j_inv(fp2_element_t j_inv, + const elliptic_curve_t E) { + fp2_element_t result; + fp2_element_t temp; + oqs_sidh_iqc_ref_fp2_init(result); + oqs_sidh_iqc_ref_fp2_init(temp); + + oqs_sidh_iqc_ref_fp2_pow_ui(temp, E->a, 3); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(temp, temp, 4); + oqs_sidh_iqc_ref_fp2_square(result, E->b); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(result, result, 27); + oqs_sidh_iqc_ref_fp2_add(result, result, temp); + oqs_sidh_iqc_ref_fp2_inv(result, result); + oqs_sidh_iqc_ref_fp2_mul(result, result, temp); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(result, result, 1728); + oqs_sidh_iqc_ref_fp2_set(j_inv, result); + + oqs_sidh_iqc_ref_fp2_clear(result); + oqs_sidh_iqc_ref_fp2_clear(temp); +} + +int oqs_sidh_iqc_ref_point_is_on_curve(const point_t P, + const elliptic_curve_t E) { + + if (oqs_sidh_iqc_ref_point_is_zero(P)) + return 1; + + fp2_element_t temp_x; + oqs_sidh_iqc_ref_fp2_init(temp_x); + + // compute x^3 + a * x + b = x * (x^2 + a) + b + oqs_sidh_iqc_ref_fp2_square(temp_x, P->x); + oqs_sidh_iqc_ref_fp2_add(temp_x, temp_x, E->a); + oqs_sidh_iqc_ref_fp2_mul(temp_x, temp_x, P->x); + oqs_sidh_iqc_ref_fp2_add(temp_x, temp_x, E->b); + + fp2_element_t temp_y; + oqs_sidh_iqc_ref_fp2_init(temp_y); + oqs_sidh_iqc_ref_fp2_square(temp_y, P->y); + + int result = oqs_sidh_iqc_ref_fp2_equals(temp_y, temp_x); + + oqs_sidh_iqc_ref_fp2_clear(temp_x); + oqs_sidh_iqc_ref_fp2_clear(temp_y); + + return result; +} + +void oqs_sidh_iqc_ref_elliptic_curve_random_point(point_t P, + const elliptic_curve_t E) { + point_t result; + oqs_sidh_iqc_ref_point_init(result); + result->z = 1; + + fp2_element_t temp_x; + oqs_sidh_iqc_ref_fp2_init(temp_x); + + fp2_element_t temp_y; + oqs_sidh_iqc_ref_fp2_init(temp_y); + + gmp_randstate_t randstate; + gmp_randinit_default(randstate); + + while (1) { + oqs_sidh_iqc_ref_fp2_random(result->x, randstate); + + // compute x^3 + a * x + b = x * (x^2 + a) + b + oqs_sidh_iqc_ref_fp2_square(temp_x, result->x); + oqs_sidh_iqc_ref_fp2_add(temp_x, temp_x, E->a); + oqs_sidh_iqc_ref_fp2_mul(temp_x, temp_x, result->x); + oqs_sidh_iqc_ref_fp2_add(temp_x, temp_x, E->b); + + if (oqs_sidh_iqc_ref_fp2_is_square(temp_x)) { + oqs_sidh_iqc_ref_fp2_sqrt(result->y, temp_x); + break; + } + } + + oqs_sidh_iqc_ref_point_set(P, result); + + oqs_sidh_iqc_ref_point_clear(result); + oqs_sidh_iqc_ref_fp2_clear(temp_x); + oqs_sidh_iqc_ref_fp2_clear(temp_y); + gmp_randclear(randstate); +} diff --git a/src/kex_sidh_iqc_ref/sidh_elliptic_curve.h b/src/kex_sidh_iqc_ref/sidh_elliptic_curve.h new file mode 100644 index 000000000..5ba1a2f8a --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_elliptic_curve.h @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef CURVE_H +#define CURVE_H + +#include "sidh_quadratic_ext.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Representation of the elliptic curve y^2 = x^3 + a * x^2 + b * x + */ +typedef struct { + fp2_element_t a; + fp2_element_t b; +} elliptic_curve_struct; + +typedef elliptic_curve_struct elliptic_curve_t[1]; + +/** + * Representation of a point in the standard affine D+(z) of the + * plain projective projective space + */ +typedef struct { + fp2_element_t x; + fp2_element_t y; + int z; +} point_struct; + +typedef point_struct point_t[1]; + +/** + * Initializes the input curve to y^2 = x^3 + x + 1. + * @param E + */ +void oqs_sidh_iqc_ref_elliptic_curve_init(elliptic_curve_t E); + +/** + * Copies T into E + * @param E + * @param T + */ +void oqs_sidh_iqc_ref_elliptic_curve_set(elliptic_curve_t E, + const elliptic_curve_t T); + +/** + * Sets the coefficients of E: y^2 = x^3 + a * x^2 + b * x. + * @param E + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_elliptic_curve_set_coeffs(elliptic_curve_t E, + const fp2_element_t a, + const fp2_element_t b); + +/** + * Initializes the point {@code P} to the zero point (0 : 1 : 0). + * @param P + */ +void oqs_sidh_iqc_ref_point_init(point_t P); + +/** + * Sets the coordinates of the point {@code P}. + * @param P + * @param x + * @param y + * @param z + */ +void oqs_sidh_iqc_ref_point_set_coordinates(point_t P, + const fp2_element_t x, + const fp2_element_t y, + int z); + +/** + * Copies {@code Q} into {@code P} + * @param P + * @param Q + */ +void oqs_sidh_iqc_ref_point_set(point_t P, + const point_t Q); + +/** + * Sets the given point to zero. + * @param P + */ +void oqs_sidh_iqc_ref_point_zero(point_t P); + +/** + * Checks if a given point is zero. + * @param P + * @return + */ +int oqs_sidh_iqc_ref_point_is_zero(const point_t P); + +/** + * Sets {@code P} to {@code -Q} as a group element. + * @param P + * @param Q + */ +void oqs_sidh_iqc_ref_point_negate(point_t P, + const point_t Q); + +/** + * Checks if 2 * {@code P} = 0. + * @param P + * @return + */ +int oqs_sidh_iqc_ref_point_has_order_2(const point_t P); + +/** + * Frees the memory allocated to {@code E}. + * @param E + */ +void oqs_sidh_iqc_ref_elliptic_curve_clear(elliptic_curve_t E); + +/** + * Frees the memory allocated to {@code P}. + * @param P + */ +void oqs_sidh_iqc_ref_point_clear(point_t P); + +/** + * Checks if {@code P = Q}. + * @param P + * @param Q + * @return 1 if the points are equal, 0 otherwise + */ +int oqs_sidh_iqc_ref_point_equals(const point_t P, + const point_t Q); + +/** + * @param E + * @return A string representation of {@code E} + */ +char *oqs_sidh_iqc_ref_elliptic_curve_get_str(const elliptic_curve_t E); + +/** + * @param P + * @return A string representation of {@code P} + */ +char *oqs_sidh_iqc_ref_point_get_str(const point_t P); + +/** + * Sets {@code R = P + Q} on {@code E}. + * @param R + * @param P + * @param Q + * @param E + */ +void oqs_sidh_iqc_ref_point_add(point_t R, + const point_t P, + const point_t Q, + const elliptic_curve_t E); + +/** + * Sets {@code R = P - Q}. + * @param R + * @param P + * @param Q + * @param E + */ +void oqs_sidh_iqc_ref_point_sub(point_t R, + const point_t P, + const point_t Q, + const elliptic_curve_t E); + +/** + * Sets {@code R = P + Q} on {@code E}. + * @param R + * @param P + * @param Q + * @param lambda The slope of the line passing through {@code P, Q} + */ +void oqs_sidh_iqc_ref_point_add_with_lambda(point_t R, + const point_t P, + const point_t Q, + const fp2_element_t lambda); + +/** + * Sets {@code R = 2 * P} on {@code E}. + * @param R + * @param P + * @param E + */ +void oqs_sidh_iqc_ref_point_double(point_t R, + const point_t P, + const elliptic_curve_t E); + +/** + * Sets {@code R = scaler * P} on {@code E}. + * @param R + * @param P + * @param scaler + * @param E + */ +void oqs_sidh_iqc_ref_point_mul_scaler(point_t R, + const point_t P, + const mpz_t scaler, + const elliptic_curve_t E); + +/** + * {@link oqs_sidh_iqc_ref_point_mul_scaler} + * @param R + * @param P + * @param scaler + * @param E + */ +void oqs_sidh_iqc_ref_point_mul_scaler_si(point_t R, + const point_t P, + long scaler, + const elliptic_curve_t E); + +/** + * Computes the j-invariant of {@code E}. + * @param j_inv + * @param E + */ +void oqs_sidh_iqc_ref_elliptic_curve_compute_j_inv(fp2_element_t j_inv, + const elliptic_curve_t E); + +/** + * Checks if the point {@code P} is on the curve {@code E}. + * @param P + * @param E + * @return 1 if the point is on the curve, 0 otherwise + */ +int oqs_sidh_iqc_ref_point_is_on_curve(const point_t P, + const elliptic_curve_t E); + +/** + * Generates a random point on the curve {@code E}. + * @param P the generated random point. + * @param E + */ +void oqs_sidh_iqc_ref_elliptic_curve_random_point(point_t P, + const elliptic_curve_t E); + +#ifdef __cplusplus +} +#endif + +#endif /* CURVE_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_elliptic_curve_dlp.c b/src/kex_sidh_iqc_ref/sidh_elliptic_curve_dlp.c new file mode 100644 index 000000000..0dc495a57 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_elliptic_curve_dlp.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "sidh_elliptic_curve_dlp.h" +#include + +void oqs_sidh_iqc_ref_elliptic_curve_prime_power_dlp(mpz_t x, + const point_t P, + const point_t Q, + const elliptic_curve_t E, + long l, + long e) { + mpz_t exponent1; + mpz_t exponent2; + point_t temp_P; + point_t temp_Q; + point_t temp_R; + point_t PP; + + mpz_init(exponent1); + mpz_init(exponent2); + oqs_sidh_iqc_ref_point_init(temp_P); + oqs_sidh_iqc_ref_point_init(temp_Q); + oqs_sidh_iqc_ref_point_init(temp_R); + oqs_sidh_iqc_ref_point_init(PP); + + int ladic_rep[e]; + mpz_ui_pow_ui(exponent1, l, e - 1); + + // PP = l^(e - 1) * P once and for all + oqs_sidh_iqc_ref_point_mul_scaler(PP, P, exponent1, E); + + // compute the first ladic coefficient + oqs_sidh_iqc_ref_point_mul_scaler(temp_Q, Q, exponent1, E); + long ladic_coeff = oqs_sidh_iqc_ref_elliptic_curve_prime_dlp(PP, temp_Q, E, l); + + for (int j = 1; j < e; j++) { + if (ladic_coeff >= 0) { + ladic_rep[j - 1] = ladic_coeff; + } else { + break; + } + + mpz_ui_pow_ui(exponent2, l, j - 1); + mpz_mul_ui(exponent2, exponent2, ladic_rep[j - 1]); + mpz_divexact_ui(exponent1, exponent1, l); + oqs_sidh_iqc_ref_point_mul_scaler(temp_P, P, exponent2, E); + oqs_sidh_iqc_ref_point_add(temp_R, temp_R, temp_P, E); + oqs_sidh_iqc_ref_point_sub(temp_Q, Q, temp_R, E); + oqs_sidh_iqc_ref_point_mul_scaler(temp_Q, temp_Q, exponent1, E); + ladic_coeff = oqs_sidh_iqc_ref_elliptic_curve_prime_dlp(PP, temp_Q, E, l); + } + + if (ladic_coeff >= 0) { + ladic_rep[e - 1] = ladic_coeff; + + // set x = l_{e - 1}l^{e - 1} + ... + l_1l + l_0 + mpz_set_ui(x, ladic_rep[e - 1]); + for (long i = e - 2; i >= 0; i--) { + mpz_mul_ui(x, x, l); + mpz_add_ui(x, x, ladic_rep[i]); + } + } else { + mpz_set_si(x, -1); + } + + mpz_clear(exponent1); + mpz_clear(exponent2); + oqs_sidh_iqc_ref_point_clear(temp_P); + oqs_sidh_iqc_ref_point_clear(temp_Q); + oqs_sidh_iqc_ref_point_clear(temp_R); + oqs_sidh_iqc_ref_point_clear(PP); +} + +long oqs_sidh_iqc_ref_elliptic_curve_prime_dlp(const point_t P, + const point_t Q, + const elliptic_curve_t E, + long l) { + if (oqs_sidh_iqc_ref_point_is_zero(Q)) + return 0; + + if (oqs_sidh_iqc_ref_point_equals(P, Q)) + return 1; + + point_t temp; + oqs_sidh_iqc_ref_point_init(temp); + oqs_sidh_iqc_ref_point_set(temp, P); + + long result = -1; + for (long i = 2; i < l; i++) { + oqs_sidh_iqc_ref_point_add(temp, temp, P, E); + if (oqs_sidh_iqc_ref_point_equals(temp, Q)) { + result = i; + break; + } + } + + oqs_sidh_iqc_ref_point_clear(temp); + return result; +} \ No newline at end of file diff --git a/src/kex_sidh_iqc_ref/sidh_elliptic_curve_dlp.h b/src/kex_sidh_iqc_ref/sidh_elliptic_curve_dlp.h new file mode 100644 index 000000000..1850da664 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_elliptic_curve_dlp.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef ELLIPTIC_CURVE_DLP_H +#define ELLIPTIC_CURVE_DLP_H + +#include "sidh_elliptic_curve.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Computes the discrete logarithm {@code P = x * Q} in a group of order + * {@code l^e} generated by {@code P}. The Pohlig–Hellman algorithm is used. + * @param x the discrete logarithm if it exists, or -1 otherwise + * @param P the generator of the cyclic group + * @param Q an element in the the group generated by {@code P} + * @param E + * @param l a prime number + * @param e a positive integer + */ +void oqs_sidh_iqc_ref_elliptic_curve_prime_power_dlp(mpz_t x, + const point_t P, + const point_t Q, + const elliptic_curve_t E, + long l, + long e); + +/** + * Computes the discrete logarithm {@code P = x * Q} in a group of order + * {@code l} generated by {@code P}. + * @param P the generator of the cyclic group + * @param Q an element in the the group generated by {@code P} + * @param E + * @param l a prime number + * @return the discrete logarithm if it exists, or -1 otherwise + */ +long oqs_sidh_iqc_ref_elliptic_curve_prime_dlp(const point_t P, + const point_t Q, + const elliptic_curve_t E, + long l); + +#ifdef __cplusplus +} +#endif + +#endif /* ELLIPTIC_CURVE_DLP_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_isogeny.c b/src/kex_sidh_iqc_ref/sidh_isogeny.c new file mode 100644 index 000000000..a10910306 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_isogeny.c @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include +#include +#include "sidh_isogeny.h" +#include + +void oqs_sidh_iqc_ref_isogeny_init(isogeny_t isogeny, + long kernel_size) { + isogeny->kernel_size = 0; + isogeny->partition_size = 0; + oqs_sidh_iqc_ref_isogeny_set_kernel_size(isogeny, kernel_size); + long size = isogeny->partition_size; + isogeny->partition = (point_t *) malloc(size * sizeof(point_t)); + isogeny->gx = (fp2_element_t *) malloc(size * sizeof(fp2_element_t)); + isogeny->gy = (fp2_element_t *) malloc(size * sizeof(fp2_element_t)); + isogeny->u = (fp2_element_t *) malloc(size * sizeof(fp2_element_t)); + isogeny->v = (fp2_element_t *) malloc(size * sizeof(fp2_element_t)); + + oqs_sidh_iqc_ref_elliptic_curve_init(isogeny->domain); + oqs_sidh_iqc_ref_elliptic_curve_init(isogeny->codomain); + + for (long i = 0; i < size; i++) { + oqs_sidh_iqc_ref_point_init(isogeny->partition[i]); + oqs_sidh_iqc_ref_fp2_init(isogeny->gx[i]); + oqs_sidh_iqc_ref_fp2_init(isogeny->gy[i]); + oqs_sidh_iqc_ref_fp2_init(isogeny->u[i]); + oqs_sidh_iqc_ref_fp2_init(isogeny->v[i]); + } +} + +void oqs_sidh_iqc_ref_isogeny_clear(isogeny_t isogeny) { + oqs_sidh_iqc_ref_elliptic_curve_clear(isogeny->domain); + oqs_sidh_iqc_ref_elliptic_curve_clear(isogeny->codomain); + + for (long i = 0; i < isogeny->partition_size; i++) { + oqs_sidh_iqc_ref_point_clear(isogeny->partition[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->gx[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->gy[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->u[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->v[i]); + } + + free(isogeny->partition); + free(isogeny->gx); + free(isogeny->gy); + free(isogeny->u); + free(isogeny->v); +} + +void oqs_sidh_iqc_ref_isogeny_compute(isogeny_t isogeny, + const point_t kernel_gen) { + oqs_sidh_iqc_ref_isogeny_partition_kernel(isogeny->partition, + isogeny->partition_size, + kernel_gen, + isogeny->domain); + long size = isogeny->partition_size; + + // compute gx_P = 3 * x_P^2 + a + for (long i = 0; i < size; i++) { + oqs_sidh_iqc_ref_fp2_square(isogeny->gx[i], isogeny->partition[i]->x); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(isogeny->gx[i], isogeny->gx[i], 3); + oqs_sidh_iqc_ref_fp2_add(isogeny->gx[i], isogeny->gx[i], isogeny->domain->a); + } + + // compute gy_P = -2y_P + for (long i = 0; i < size; i++) { + oqs_sidh_iqc_ref_fp2_mul_scaler_si(isogeny->gy[i], isogeny->partition[i]->y, -2); + } + + // compute v_P = gx_P or 2gx_P + for (long i = 0; i < size; i++) { + if (oqs_sidh_iqc_ref_point_has_order_2(isogeny->partition[i])) + oqs_sidh_iqc_ref_fp2_set(isogeny->v[i], isogeny->gx[i]); + else + oqs_sidh_iqc_ref_fp2_mul_scaler_si(isogeny->v[i], isogeny->gx[i], 2); + } + + // compute u_P = gy_P^2 + for (long i = 0; i < size; i++) { + oqs_sidh_iqc_ref_fp2_square(isogeny->u[i], isogeny->gy[i]); + } + + // compute the codomain curve + fp2_element_t v; + fp2_element_t w; + fp2_element_t temp; + oqs_sidh_iqc_ref_fp2_init(v); + oqs_sidh_iqc_ref_fp2_init(w); + oqs_sidh_iqc_ref_fp2_init(temp); + + for (long i = 0; i < size; i++) { + oqs_sidh_iqc_ref_fp2_add(v, v, isogeny->v[i]); + oqs_sidh_iqc_ref_fp2_mul(temp, isogeny->v[i], isogeny->partition[i]->x); + oqs_sidh_iqc_ref_fp2_add(temp, isogeny->u[i], temp); + oqs_sidh_iqc_ref_fp2_add(w, w, temp); + } + + oqs_sidh_iqc_ref_fp2_mul_scaler_si(v, v, 5); + oqs_sidh_iqc_ref_fp2_sub(v, isogeny->domain->a, v); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(w, w, 7); + oqs_sidh_iqc_ref_fp2_sub(w, isogeny->domain->b, w); + oqs_sidh_iqc_ref_elliptic_curve_set_coeffs(isogeny->codomain, v, w); + + oqs_sidh_iqc_ref_fp2_clear(v); + oqs_sidh_iqc_ref_fp2_clear(w); + oqs_sidh_iqc_ref_fp2_clear(temp); +} + +void oqs_sidh_iqc_ref_isogeny_partition_kernel(point_t *partition, + long partition_size, + const point_t kernel_gen, + const elliptic_curve_t E) { + oqs_sidh_iqc_ref_point_set(partition[0], kernel_gen); + for (long i = 1; i < partition_size; i++) { + oqs_sidh_iqc_ref_point_add(partition[i], partition[i - 1], kernel_gen, E); + } +} + +void oqs_sidh_iqc_ref_isogeny_set_kernel_size(isogeny_t isogeny, + long kernel_size) { + long current_size = isogeny->kernel_size; + if (current_size != 0 && current_size <= kernel_size) + return; + + current_size = isogeny->partition_size; + isogeny->kernel_size = kernel_size; + + if (kernel_size % 2 == 0) + isogeny->partition_size = kernel_size / 2; + else + isogeny->partition_size = (kernel_size - 1) / 2; + + // clear the the unused memory after shrinking + for (long i = isogeny->partition_size; i < current_size; i++) { + oqs_sidh_iqc_ref_point_clear(isogeny->partition[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->gx[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->gy[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->u[i]); + oqs_sidh_iqc_ref_fp2_clear(isogeny->v[i]); + } +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_velu(point_t Q, + const isogeny_t isogeny, + const point_t P) { + + if (oqs_sidh_iqc_ref_point_is_zero(P)) { + oqs_sidh_iqc_ref_point_zero(Q); + return; + } + + long size = isogeny->partition_size; + + fp2_element_t temp1; + fp2_element_t temp2; + fp2_element_t temp3; + oqs_sidh_iqc_ref_fp2_init(temp1); + oqs_sidh_iqc_ref_fp2_init(temp2); + oqs_sidh_iqc_ref_fp2_init(temp3); + + point_t result; + oqs_sidh_iqc_ref_point_init(result); + oqs_sidh_iqc_ref_point_set(result, P); + + for (long i = 0; i < size; i++) { + oqs_sidh_iqc_ref_fp2_sub(temp1, P->x, isogeny->partition[i]->x); + + // check if the point is in the kernel + if (oqs_sidh_iqc_ref_fp2_is_zero(temp1)) { + oqs_sidh_iqc_ref_point_zero(result); + break; + } + + // 1 / (x - x_P) + oqs_sidh_iqc_ref_fp2_inv(temp1, temp1); + + // add 1 / (x - x_P) * (v_P + u_P / (x - x_P)) to x + oqs_sidh_iqc_ref_fp2_mul(temp2, isogeny->u[i], temp1); + oqs_sidh_iqc_ref_fp2_add(temp2, temp2, isogeny->v[i]); + oqs_sidh_iqc_ref_fp2_mul(temp2, temp2, temp1); + oqs_sidh_iqc_ref_fp2_add(result->x, result->x, temp2); + + // v_P * (y - y_P) - gx_P * gy_P + oqs_sidh_iqc_ref_fp2_sub(temp2, P->y, isogeny->partition[i]->y); + oqs_sidh_iqc_ref_fp2_mul(temp2, temp2, isogeny->v[i]); + oqs_sidh_iqc_ref_fp2_mul(temp3, isogeny->gx[i], isogeny->gy[i]); + oqs_sidh_iqc_ref_fp2_sub(temp2, temp2, temp3); + + // 2 * u_P * y / (x - x_P) + oqs_sidh_iqc_ref_fp2_mul(temp3, isogeny->u[i], P->y); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(temp3, temp3, 2); + oqs_sidh_iqc_ref_fp2_mul(temp3, temp3, temp1); + + oqs_sidh_iqc_ref_fp2_add(temp3, temp3, temp2); + oqs_sidh_iqc_ref_fp2_square(temp1, temp1); + oqs_sidh_iqc_ref_fp2_mul(temp3, temp3, temp1); + oqs_sidh_iqc_ref_fp2_sub(result->y, result->y, temp3); + } + + oqs_sidh_iqc_ref_point_set(Q, result); + + oqs_sidh_iqc_ref_point_clear(result); + oqs_sidh_iqc_ref_fp2_clear(temp1); + oqs_sidh_iqc_ref_fp2_clear(temp2); + oqs_sidh_iqc_ref_fp2_clear(temp3); +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_kohel(point_t Q, + const isogeny_t isogeny, + const point_t P) { + fp2_element_t ix1; + fp2_element_t ix2; + fp2_element_t ix3; + fp2_element_t temp1; + fp2_element_t temp2; + fp2_element_t temp3; + fp2_element_t sigma1; + + oqs_sidh_iqc_ref_fp2_init(ix1); + oqs_sidh_iqc_ref_fp2_init(ix2); + oqs_sidh_iqc_ref_fp2_init(ix3); + oqs_sidh_iqc_ref_fp2_init(temp1); + oqs_sidh_iqc_ref_fp2_init(temp2); + oqs_sidh_iqc_ref_fp2_init(temp3); + oqs_sidh_iqc_ref_fp2_init(sigma1); + + point_t result; + oqs_sidh_iqc_ref_point_init(result); + oqs_sidh_iqc_ref_point_set(result, P); + + long size = isogeny->partition_size; + + for (long i = 0; i < size; i++) { + oqs_sidh_iqc_ref_fp2_add(sigma1, sigma1, isogeny->partition[i]->x); + oqs_sidh_iqc_ref_fp2_sub(temp1, P->x, isogeny->partition[i]->x); + + // check if the point is in the kernel + if (oqs_sidh_iqc_ref_fp2_is_zero(temp1)) { + oqs_sidh_iqc_ref_point_zero(result); + break; + } + + // 1 / (x - x_P) + oqs_sidh_iqc_ref_fp2_inv(temp1, temp1); + + // 1 / (x - x_P)^2 + oqs_sidh_iqc_ref_fp2_square(temp2, temp1); + + // 1 / (x - x_P)^3 + oqs_sidh_iqc_ref_fp2_mul(temp3, temp2, temp1); + + if (!oqs_sidh_iqc_ref_point_has_order_2(isogeny->partition[i])) { + oqs_sidh_iqc_ref_fp2_add(temp1, temp1, temp1); + oqs_sidh_iqc_ref_fp2_add(temp2, temp2, temp2); + oqs_sidh_iqc_ref_fp2_add(temp3, temp3, temp3); + oqs_sidh_iqc_ref_fp2_add(sigma1, sigma1, isogeny->partition[i]->x); + } + + oqs_sidh_iqc_ref_fp2_add(ix1, ix1, temp1); + oqs_sidh_iqc_ref_fp2_add(ix2, ix2, temp2); + oqs_sidh_iqc_ref_fp2_add(ix3, ix3, temp3); + } + + if (!oqs_sidh_iqc_ref_point_is_zero(result)) { + fp2_element_t u1; + fp2_element_t u2; + + oqs_sidh_iqc_ref_fp2_init(u1); + oqs_sidh_iqc_ref_fp2_init(u2); + + // 3 * x^2 + a + oqs_sidh_iqc_ref_fp2_square(u1, P->x); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(u1, u1, 3); + oqs_sidh_iqc_ref_fp2_add(u1, u1, isogeny->domain->a); + + // 2 * y^2 + oqs_sidh_iqc_ref_fp2_square(u2, P->y); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(u2, u2, 2); + + // compute the first coordinate + oqs_sidh_iqc_ref_fp2_mul_scaler_si(result->x, P->x, isogeny->kernel_size); + oqs_sidh_iqc_ref_fp2_sub(result->x, result->x, sigma1); + oqs_sidh_iqc_ref_fp2_mul(temp1, u1, ix1); + oqs_sidh_iqc_ref_fp2_sub(result->x, result->x, temp1); + oqs_sidh_iqc_ref_fp2_mul(temp1, u2, ix2); + oqs_sidh_iqc_ref_fp2_add(result->x, result->x, temp1); + + // compute the second coordinate + oqs_sidh_iqc_ref_fp2_mul_scaler_si(temp1, P->x, -6); + oqs_sidh_iqc_ref_fp2_mul(result->y, temp1, ix1); + oqs_sidh_iqc_ref_fp2_add_ui(result->y, result->y, isogeny->kernel_size); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(temp1, u1, 3); + oqs_sidh_iqc_ref_fp2_mul(temp1, temp1, ix2); + oqs_sidh_iqc_ref_fp2_add(result->y, result->y, temp1); + oqs_sidh_iqc_ref_fp2_mul_scaler_si(temp1, u2, -2); + oqs_sidh_iqc_ref_fp2_mul(temp1, temp1, ix3); + oqs_sidh_iqc_ref_fp2_add(result->y, result->y, temp1); + oqs_sidh_iqc_ref_fp2_mul(result->y, result->y, P->y); + + oqs_sidh_iqc_ref_fp2_clear(u1); + oqs_sidh_iqc_ref_fp2_clear(u2); + } + + oqs_sidh_iqc_ref_point_set(Q, result); + + oqs_sidh_iqc_ref_point_clear(result); + oqs_sidh_iqc_ref_fp2_clear(ix1); + oqs_sidh_iqc_ref_fp2_clear(ix2); + oqs_sidh_iqc_ref_fp2_clear(ix3); + oqs_sidh_iqc_ref_fp2_clear(temp1); + oqs_sidh_iqc_ref_fp2_clear(temp2); + oqs_sidh_iqc_ref_fp2_clear(temp3); + oqs_sidh_iqc_ref_fp2_clear(sigma1); +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_naive(elliptic_curve_t E, + point_t *points, + long num_points, + const point_t kernel_gen, + long l, + long e, + long isogeny_jump) { + + point_t temp_gen; + oqs_sidh_iqc_ref_point_init(temp_gen); + oqs_sidh_iqc_ref_point_set(temp_gen, kernel_gen); + + mpz_t le; + mpz_init(le); + mpz_ui_pow_ui(le, l, e); + + long kernel_size = 0; + if (e <= isogeny_jump) + kernel_size = mpz_get_si(le); + else + kernel_size = (long) pow(l, isogeny_jump); + + isogeny_t isogeny; + oqs_sidh_iqc_ref_isogeny_init(isogeny, kernel_size); + oqs_sidh_iqc_ref_elliptic_curve_set(isogeny->domain, E); + + long i = 0; + while (i < e) { + mpz_divexact_ui(le, le, kernel_size); + oqs_sidh_iqc_ref_isogeny_evaluate_naive_helper(isogeny, + E, + points, + num_points, + temp_gen, + le); + i += isogeny_jump; + + if ((e - i > 0) && (e - i) < isogeny_jump) { + kernel_size = (long) pow(l, e - i); + oqs_sidh_iqc_ref_isogeny_set_kernel_size(isogeny, kernel_size); + } + } + + oqs_sidh_iqc_ref_point_clear(temp_gen); + mpz_clear(le); + oqs_sidh_iqc_ref_isogeny_clear(isogeny); +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_naive_curve(elliptic_curve_t E, + const point_t kernel_gen, + long l, + long e, + long isogeny_jump) { + oqs_sidh_iqc_ref_isogeny_evaluate_naive(E, NULL, 0, kernel_gen, l, e, isogeny_jump); +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_naive_helper(isogeny_t isogeny, + elliptic_curve_t E, + point_t *points, + long num_points, + point_t kernel_gen, + const mpz_t le) { + point_t K; + oqs_sidh_iqc_ref_point_init(K); + + oqs_sidh_iqc_ref_point_mul_scaler(K, kernel_gen, le, E); + oqs_sidh_iqc_ref_isogeny_compute(isogeny, K); + oqs_sidh_iqc_ref_isogeny_evaluate_kohel(kernel_gen, isogeny, kernel_gen); + + for (long i = 0; i < num_points; i++) { + oqs_sidh_iqc_ref_isogeny_evaluate_kohel(points[i], isogeny, points[i]); + } + + oqs_sidh_iqc_ref_elliptic_curve_set(E, isogeny->codomain); + oqs_sidh_iqc_ref_elliptic_curve_set(isogeny->domain, isogeny->codomain); + + oqs_sidh_iqc_ref_point_clear(K); +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_strategy_rec(elliptic_curve_t E, + point_t *points, + long num_points, + point_t *kernel_gens, + long num_gens, + long l, + long e, + float ratio) { + + if (e == 1) { + isogeny_t isogeny; + + long kernel_size = (long) pow(l, e); + oqs_sidh_iqc_ref_isogeny_init(isogeny, kernel_size); + oqs_sidh_iqc_ref_elliptic_curve_set(isogeny->domain, E); + oqs_sidh_iqc_ref_isogeny_compute(isogeny, kernel_gens[num_gens - 1]); + oqs_sidh_iqc_ref_elliptic_curve_set(E, isogeny->codomain); + + for (long i = 0; i < num_points; i++) { + oqs_sidh_iqc_ref_isogeny_evaluate_velu(points[i], isogeny, points[i]); + } + + for (long i = 0; i < num_gens - 1; i++) { + oqs_sidh_iqc_ref_isogeny_evaluate_velu(kernel_gens[i], + isogeny, + kernel_gens[i]); + } + + oqs_sidh_iqc_ref_isogeny_clear(isogeny); + return; + } + + long r = (long) (ratio * e); + + mpz_t exponent; + mpz_init(exponent); + mpz_ui_pow_ui(exponent, l, r); + + oqs_sidh_iqc_ref_point_mul_scaler(kernel_gens[num_gens], + kernel_gens[num_gens - 1], + exponent, E); + + oqs_sidh_iqc_ref_isogeny_evaluate_strategy_rec(E, points, num_points, kernel_gens, + num_gens + 1, l, e - r, ratio); + oqs_sidh_iqc_ref_isogeny_evaluate_strategy_rec(E, points, num_points, kernel_gens, + num_gens, l, r, ratio); + mpz_clear(exponent); +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_strategy(elliptic_curve_t E, + point_t *points, + long num_points, + const point_t kernel_gen, + long l, + long e, + float ratio) { + + point_t *kernel_gens = (point_t *) malloc(e * sizeof(point_t)); + for (long i = 0; i < e; i++) + oqs_sidh_iqc_ref_point_init(kernel_gens[i]); + oqs_sidh_iqc_ref_point_set(kernel_gens[0], kernel_gen); + + oqs_sidh_iqc_ref_isogeny_evaluate_strategy_rec(E, points, num_points, + kernel_gens, 1, l, e, ratio); + + for (long i = 0; i < e; i++) + oqs_sidh_iqc_ref_point_clear(kernel_gens[i]); + free(kernel_gens); +} + +void oqs_sidh_iqc_ref_isogeny_evaluate_strategy_curve(elliptic_curve_t E, + const point_t kernel_gen, + long l, + long e, + float ratio) { + oqs_sidh_iqc_ref_isogeny_evaluate_strategy(E, NULL, 0, kernel_gen, l, e, ratio); +} diff --git a/src/kex_sidh_iqc_ref/sidh_isogeny.h b/src/kex_sidh_iqc_ref/sidh_isogeny.h new file mode 100644 index 000000000..6b01efcf9 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_isogeny.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef ISOGENY_H +#define ISOGENY_H + +#include "sidh_elliptic_curve.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Representation of an isogeny between two elliptic curve + */ +typedef struct { + // Let the kernel K of the isogeny (excluding the zero point) be the union + // of F and G such that R \in F if and only if -R \in G for all points + // R \in K. Then the partition is F. + point_t *partition; + fp2_element_t *gx; + fp2_element_t *gy; + fp2_element_t *u; + fp2_element_t *v; + elliptic_curve_t domain; + elliptic_curve_t codomain; + long partition_size; + long kernel_size; +} isogeny_struct; + +typedef isogeny_struct isogeny_t[1]; + +/** + * Initializes the isogeny {@code isogeny}. + * @param isogeny + * @param kernel_size + */ +void oqs_sidh_iqc_ref_isogeny_init(isogeny_t isogeny, + long kernel_size); + +/** + * Frees the memory allocated to {@code isogeny}. + * @param isogeny + */ +void oqs_sidh_iqc_ref_isogeny_clear(isogeny_t isogeny); + +/** + * Computes the isogeny from the kernel generated by {@code kernel_gen}. + * @param isogeny + * @param kernel_gen + */ +void oqs_sidh_iqc_ref_isogeny_compute(isogeny_t isogeny, + const point_t kernel_gen); + +/** + * Evaluates {@code isogeny} at the point {@code P}, using Velu's formulas. + * @param Q The result of the evaluation {@code isogeny(P)} + * @param isogeny + * @param P + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_velu(point_t Q, + const isogeny_t isogeny, + const point_t P); + +/** + * Evaluates {@code isogeny} at the point {@code P}, using Kohel's formulas. + * @param Q The result of the evaluation {@code isogeny(P)} + * @param isogeny + * @param P + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_kohel(point_t Q, + const isogeny_t isogeny, + const point_t P); + +/** + * Computes the partition for the isogeny generated by {@code kernel_gen}. + * @see isogeny_struct. + * @param partition + * @param partition_size + * @param kernel_gen + * @param E + */ +void oqs_sidh_iqc_ref_isogeny_partition_kernel(point_t *partition, + long partition_size, + const point_t kernel_gen, + const elliptic_curve_t E); + +/** + * Sets the kernel size for {@code isogeny}. The new kernel size is assumed + * to be smaller than the current kernel size. + * @param isogeny + * @param kernel_size + */ +void oqs_sidh_iqc_ref_isogeny_set_kernel_size(isogeny_t isogeny, + long kernel_size); + +/** + * Computes the images of the elliptic curve {@code E} and the points + * {@code points} through the isogeny with kernel generated by the point + * {@code kernel_gen}. The size of the kernel is {@code l^e}. + * @param E + * @param points + * @param num_points + * @param kernel_gen + * @param l + * @param e the length of the chain of l-isogenies + * @param isogeny_jump the number of successive l-isogenies that should + * be computed at once. For example, if {@code isogeny_jump = 2} then a + * chain of l-isogenies of length e is computed by doing e / 2 {l^2-isogenies}. + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_naive(elliptic_curve_t E, + point_t *points, + long num_points, + const point_t kernel_gen, + long l, + long e, + long isogeny_jump); + +/** + * Computes the images of the elliptic curve {@code E} through the isogeny + * with kernel generated by the point {@code kernel_gen}. + * {@link oqs_sidh_iqc_ref_isogeny_evaluate_naive} + * @param E + * @param kernel_gen + * @param l + * @param e + * @param isogeny_jump + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_naive_curve(elliptic_curve_t E, + const point_t kernel_gen, + long l, + long e, + long isogeny_jump); + +/** + * A helper method for {@link oqs_sidh_iqc_ref_isogeny_evaluate_naive}. All the arguments except + * {@code num_points, le} will be pushed through the isogeny. For example + * {@code E} will be the codomain of the isogeny. This method should not be + * called directly. + * @param isogeny + * @param E + * @param points + * @param num_points + * @param kernel_gen + * @param le + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_naive_helper(isogeny_t isogeny, + elliptic_curve_t E, + point_t *points, + long num_points, + point_t kernel_gen, + const mpz_t le); + +/** + * The recursion for {@link oqs_sidh_iqc_ref_isogeny_evaluate_strategy}. + * @param E + * @param points see {@link oqs_sidh_iqc_ref_isogeny_evaluate_strategy} + * @param num_points see {@link oqs_sidh_iqc_ref_isogeny_evaluate_strategy} + * @param kernel_gens contains the previous kernels computed while going down + * the recursion tree. + * @param num_gens number of elements in {@code kernel_gens} + * @param l + * @param e + * @param ratio see {@link oqs_sidh_iqc_ref_isogeny_evaluate_strategy} + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_strategy_rec(elliptic_curve_t E, + point_t *points, + long num_points, + point_t *kernel_gens, + long num_gens, + long l, + long e, + float ratio); + +/** + * This method implements the optimal strategy approach proposed in the paper + * De Feo, Luca, David Jao, and JĂ©rĂ´me PlĂ»t. "Towards quantum-resistant + * cryptosystems from supersingular elliptic curve isogenies". + * @param E + * @param points the points to be evaluated through the isogeny + * @param num_points number of points in {@code points} + * @param kernel_gen the generator of the kernel of the isogeny + * @param l + * @param e + * @param ratio a float in the range (0, 1). This indicates the portions of + * the computation that is done through point multiplication and isogeny + * evaluation. The larger values of {@code ratio} means more multiplication + * and less isogeny evaluation. + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_strategy(elliptic_curve_t E, + point_t *points, + long num_points, + const point_t kernel_gen, + long l, + long e, + float ratio); + +/** + * The same as {@link oqs_sidh_iqc_ref_isogeny_evaluate_strategy} except there is no point + * to evaluate through the isogeny. This method simply calls + * {@link oqs_sidh_iqc_ref_isogeny_evaluate_strategy} with {@code points = NULL, num_points = 0}. + * @param E + * @param kernel_gen + * @param l + * @param e + * @param ratio + */ +void oqs_sidh_iqc_ref_isogeny_evaluate_strategy_curve(elliptic_curve_t E, + const point_t kernel_gen, + long l, + long e, + float ratio); + +#ifdef __cplusplus +} +#endif + +#endif /* ISOGENY_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_private_key.c b/src/kex_sidh_iqc_ref/sidh_private_key.c new file mode 100644 index 000000000..ceea53ac7 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_private_key.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "sidh_private_key.h" +#include "sidh_util.h" +#include "sidh_public_param.h" +#include + +void oqs_sidh_iqc_ref_private_key_init(private_key_t private_key) { + mpz_inits(private_key->m, private_key->n, NULL); +} + +void oqs_sidh_iqc_ref_private_key_clear(private_key_t private_key) { + mpz_clears(private_key->m, private_key->n, NULL); +} + +void oqs_sidh_iqc_ref_private_key_generate(private_key_t private_key, + const public_params_t params) { + gmp_randstate_t randstate; + gmp_randinit_default(randstate); + mpz_t seed; + mpz_init(seed); + oqs_sidh_iqc_ref_get_random_mpz(seed); + gmp_randseed(randstate, seed); + + while (1) { + mpz_urandomm(private_key->m, randstate, params->le); + mpz_urandomm(private_key->n, randstate, params->le); + + if (!mpz_divisible_ui_p(private_key->m, params->l)) + break; + + if (!mpz_divisible_ui_p(private_key->n, params->l)) { + mpz_swap(private_key->m, private_key->n); + break; + } + } + + gmp_randclear(randstate); + mpz_clear(seed); +} + +void oqs_sidh_iqc_ref_private_key_compute_kernel_gen( + point_t gen, const private_key_t private_key, const point_t P, + const point_t Q, const mpz_t le, const elliptic_curve_t E) { + mpz_t temp_m; + mpz_t temp_n; + mpz_init_set(temp_m, private_key->m); + mpz_init_set(temp_n, private_key->n); + + point_t result; + oqs_sidh_iqc_ref_point_init(result); + + mpz_invert(temp_m, temp_m, le); + mpz_mul(temp_n, temp_m, temp_n); + mpz_mod(temp_n, temp_n, le); + + oqs_sidh_iqc_ref_point_mul_scaler(result, Q, temp_n, E); + oqs_sidh_iqc_ref_point_add(result, result, P, E); + oqs_sidh_iqc_ref_point_set(gen, result); + + mpz_clears(temp_m, temp_n, NULL); + oqs_sidh_iqc_ref_point_clear(result); +} + +void oqs_sidh_iqc_ref_private_key_print(const private_key_t private_key) { + printf("m: %s\n", mpz_get_str(NULL, 10, private_key->m)); + printf("n: %s\n", mpz_get_str(NULL, 10, private_key->n)); +} + +void oqs_sidh_iqc_ref_private_key_to_bytes(uint8_t *bytes, + const private_key_t private_key, + long prime_size) { + for (long i = 0; i < 2 * prime_size; i++) + bytes[i] = 0; + + mpz_export(bytes, NULL, -1, 1, 0, 0, private_key->m); + mpz_export(bytes + prime_size, NULL, -1, 1, 0, 0, private_key->n); +} + +void oqs_sidh_iqc_ref_bytes_to_private_key(private_key_t private_key, + const uint8_t *bytes, + long prime_size) { + mpz_set_ui(private_key->m, 0); + mpz_set_ui(private_key->n, 0); + mpz_import(private_key->m, prime_size, -1, 1, 0, 0, bytes); + mpz_import(private_key->n, prime_size, -1, 1, 0, 0, bytes + prime_size); +} diff --git a/src/kex_sidh_iqc_ref/sidh_private_key.h b/src/kex_sidh_iqc_ref/sidh_private_key.h new file mode 100644 index 000000000..e1806f93f --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_private_key.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef PRIVATE_KEY_H +#define PRIVATE_KEY_H + +#include "sidh_elliptic_curve.h" +#include "sidh_public_param.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Representation of the private key in oqs_sidh_iqc_ref + */ +typedef struct { + mpz_t m; + mpz_t n; +} private_key_struct; + +typedef private_key_struct private_key_t[1]; + +/** + * Initializes the private-key. + * @param private_key + */ +void oqs_sidh_iqc_ref_private_key_init(private_key_t private_key); + +/** + * Frees the memory allocated to the private-key. + * @param private_key + */ +void oqs_sidh_iqc_ref_private_key_clear(private_key_t private_key); + +/** + * Generates the private-key. It is guaranteed that {@code private_key->m} + * is comprime to {@code params->l}. + * @param private_key + * @param params + */ +void oqs_sidh_iqc_ref_private_key_generate(private_key_t private_key, + const public_params_t params); + +/** + * Computes a generator for th kernel generated by {@code gen = m * P + n * Q}. + * It is assumed that {@code m} is invertible modulo {@code le}. + * @param gen + * @param P one of the generators of the l^e torsion. + * @param Q one of the generators of the l^e torsion. + * @param private_key + * @param le + * @param E + */ +void oqs_sidh_iqc_ref_private_key_compute_kernel_gen(point_t gen, + const private_key_t private_key, + const point_t P, + const point_t Q, + const mpz_t le, + const elliptic_curve_t E); + +/** + * Converts a private-key to an array of bytes. + * @param bytes + * @param private_key + * @param prime_size + */ +void oqs_sidh_iqc_ref_private_key_to_bytes(uint8_t *bytes, + const private_key_t private_key, + long prime_size); + +/** + * Converts an array of bytes to a private-key. + * @param private_key + * @param bytes + * @param prime_size + */ +void oqs_sidh_iqc_ref_bytes_to_private_key(private_key_t private_key, + const uint8_t *bytes, + long prime_size); + +/** + * Prints {@code private_key} to the standard output. + * @param private_key + */ +void oqs_sidh_iqc_ref_private_key_print(const private_key_t private_key); + +#ifdef __cplusplus +} +#endif + +#endif /* PRIVATE_KEY_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_public_key.c b/src/kex_sidh_iqc_ref/sidh_public_key.c new file mode 100644 index 000000000..9cd5caa82 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_key.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "sidh_public_key.h" +#include "sidh_isogeny.h" +#include "sidh_private_key.h" +#include +#include + +void oqs_sidh_iqc_ref_public_key_init(public_key_t public_key) { + oqs_sidh_iqc_ref_elliptic_curve_init(public_key->E); + oqs_sidh_iqc_ref_point_init(public_key->P); + oqs_sidh_iqc_ref_point_init(public_key->Q); +} + +void oqs_sidh_iqc_ref_public_key_clear(public_key_t public_key) { + oqs_sidh_iqc_ref_elliptic_curve_clear(public_key->E); + oqs_sidh_iqc_ref_point_clear(public_key->P); + oqs_sidh_iqc_ref_point_clear(public_key->Q); +} + +void oqs_sidh_iqc_ref_public_key_generate(public_key_t public_key, + const point_t kernel_gen, + const public_params_t paramsA, + const public_params_t paramsB) { + + point_t points[2]; + oqs_sidh_iqc_ref_point_init(points[0]); + oqs_sidh_iqc_ref_point_init(points[1]); + + oqs_sidh_iqc_ref_elliptic_curve_set(public_key->E, paramsA->E); + oqs_sidh_iqc_ref_point_set(points[0], paramsB->P); + oqs_sidh_iqc_ref_point_set(points[1], paramsB->Q); + + oqs_sidh_iqc_ref_isogeny_evaluate_strategy(public_key->E, + points, + 2, + kernel_gen, + paramsA->l, + paramsA->e, + 0.5); + + // oqs_sidh_iqc_ref_isogeny_evaluate_naive(public_key->E, + // points, + // 2, + // kernel_gen, + // paramsA->l, + // paramsA->e, + // 10); + + oqs_sidh_iqc_ref_point_set(public_key->P, points[0]); + oqs_sidh_iqc_ref_point_set(public_key->Q, points[1]); + + oqs_sidh_iqc_ref_point_clear(points[0]); + oqs_sidh_iqc_ref_point_clear(points[1]); +} + +void oqs_sidh_iqc_ref_public_key_print(const public_key_t public_key) { + printf("E: %s\n", oqs_sidh_iqc_ref_elliptic_curve_get_str(public_key->E)); + printf("P: %s\n", oqs_sidh_iqc_ref_point_get_str(public_key->P)); + printf("Q: %s\n", oqs_sidh_iqc_ref_point_get_str(public_key->Q)); +} + +void oqs_sidh_iqc_ref_public_key_to_bytes(uint8_t *bytes, + const public_key_t public_key, + long prime_size) { + long index = 0; + oqs_sidh_iqc_ref_fp2_to_bytes(bytes + index, public_key->E->a, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_fp2_to_bytes(bytes + index, public_key->E->b, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_fp2_to_bytes(bytes + index, public_key->P->x, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_fp2_to_bytes(bytes + index, public_key->P->y, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_fp2_to_bytes(bytes + index, public_key->Q->x, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_fp2_to_bytes(bytes + index, public_key->Q->y, prime_size); +} + +void oqs_sidh_iqc_ref_bytes_to_public_key(public_key_t public_key, + const uint8_t *bytes, + long prime_size) { + long index = 0; + oqs_sidh_iqc_ref_bytes_to_fp2(public_key->E->a, bytes + index, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_bytes_to_fp2(public_key->E->b, bytes + index, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_bytes_to_fp2(public_key->P->x, bytes + index, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_bytes_to_fp2(public_key->P->y, bytes + index, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_bytes_to_fp2(public_key->Q->x, bytes + index, prime_size); + index += 2 * prime_size; + oqs_sidh_iqc_ref_bytes_to_fp2(public_key->Q->y, bytes + index, prime_size); + + public_key->P->z = 1; + public_key->Q->z = 1; +} diff --git a/src/kex_sidh_iqc_ref/sidh_public_key.h b/src/kex_sidh_iqc_ref/sidh_public_key.h new file mode 100644 index 000000000..8a6634584 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_key.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef PUBLIC_KEY_H +#define PUBLIC_KEY_H + +#include "sidh_public_param.h" +#include "sidh_private_key.h" +#include "sidh_isogeny.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Representation of the public key in oqs_sidh_iqc_ref + */ +typedef struct { + elliptic_curve_t E; + point_t P; + point_t Q; +} public_key_struct; + +typedef public_key_struct public_key_t[1]; + +/** + * Initializes the public-key. + * @param public_key + */ +void oqs_sidh_iqc_ref_public_key_init(public_key_t public_key); + +/** + * Frees the memory allocated to the public-key. + * @param public_key + */ +void oqs_sidh_iqc_ref_public_key_clear(public_key_t public_key); + +/** + * Generates the public-key + * @param public_key + * @param kernel_gen a generator for the kernel of the isogeny + * @param paramsA own params + * @param paramsB other's params + */ +void oqs_sidh_iqc_ref_public_key_generate(public_key_t public_key, + const point_t kernel_gen, + const public_params_t paramsA, + const public_params_t paramsB); + +/** + * Prints {@code public_key} to the standard output. + * @param public_key + */ +void oqs_sidh_iqc_ref_public_key_print(const public_key_t public_key); + +/** + * Converts a public-key to a byte array. + * @param bytes + * @param public_key + * @param prime_size + */ +void oqs_sidh_iqc_ref_public_key_to_bytes(uint8_t *bytes, + const public_key_t public_key, + long prime_size); + +/** + * Converts a byte array to a public-key. + * @param public_key + * @param bytes + * @param prime_size + */ +void oqs_sidh_iqc_ref_bytes_to_public_key(public_key_t public_key, + const uint8_t *bytes, + long prime_size); + +#ifdef __cplusplus +} +#endif + +#endif /* PUBLIC_KEY_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_public_key_encryption.c b/src/kex_sidh_iqc_ref/sidh_public_key_encryption.c new file mode 100644 index 000000000..717e2c270 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_key_encryption.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "sidh_public_key_encryption.h" +#include "sidh_public_key.h" +#include "sidh_util.h" +#include "sidh_shared_key.h" +#include +#include +#include + +void oqs_sidh_iqc_ref_public_key_ciphertext_init(ciphertext_t ciphertext) { + oqs_sidh_iqc_ref_elliptic_curve_init(ciphertext->E); + oqs_sidh_iqc_ref_point_init(ciphertext->P); + oqs_sidh_iqc_ref_point_init(ciphertext->Q); + ciphertext->size = 0; +} + +void oqs_sidh_iqc_ref_public_key_ciphertext_clear(ciphertext_t ciphertext) { + oqs_sidh_iqc_ref_elliptic_curve_clear(ciphertext->E); + oqs_sidh_iqc_ref_point_clear(ciphertext->P); + oqs_sidh_iqc_ref_point_clear(ciphertext->Q); + free(ciphertext->content); + ciphertext->size = 0; +} + +void oqs_sidh_iqc_ref_public_key_plaintext_init(plaintext_t plaintext) { + plaintext->size = 0; +} + +void oqs_sidh_iqc_ref_public_key_plaintext_clear(plaintext_t plaintext) { + plaintext->size = 0; +} + +int oqs_sidh_iqc_ref_public_key_pad_plaintext(plaintext_t result, + const plaintext_t raw) { + long key_size = public_key_get_key_size(); + long max_msg_size = key_size - 1; + + if (raw->size > key_size) { + printf("\nMessage too large. It should be less than %ld bytes.\n", + max_msg_size); + return -1; + } + + // pad the message + char *new_content = (char *) malloc(max_msg_size); + memset(new_content, 0, max_msg_size); + memcpy(new_content, raw->content, raw->size); + + result->content = new_content; + result->size = max_msg_size; + + return 1; +} + +void oqs_sidh_iqc_ref_public_key_encrypt(ciphertext_t ciphertext, + const plaintext_t plaintext, + const public_key_t public_keyA, + const public_params_t paramsA, + const public_params_t paramsB) { + + private_key_t private_key_temp; + oqs_sidh_iqc_ref_private_key_init(private_key_temp); + oqs_sidh_iqc_ref_private_key_generate(private_key_temp, paramsB); + + point_t kernel_gen; + oqs_sidh_iqc_ref_point_init(kernel_gen); + oqs_sidh_iqc_ref_private_key_compute_kernel_gen(kernel_gen, + private_key_temp, + paramsB->P, + paramsB->Q, + paramsB->le, + paramsB->E); + + public_key_t public_key_temp; + oqs_sidh_iqc_ref_public_key_init(public_key_temp); + oqs_sidh_iqc_ref_public_key_generate(public_key_temp, kernel_gen, paramsB, paramsA); + + fp2_element_t shared_key; + oqs_sidh_iqc_ref_fp2_init(shared_key); + oqs_sidh_iqc_ref_shared_key_generate(shared_key, public_keyA, private_key_temp, paramsB); + char *hash = oqs_sidh_iqc_ref_public_key_encryption_hash(shared_key, plaintext->size); + + ciphertext->content = oqs_sidh_iqc_ref_array_xor(plaintext->content, + hash, plaintext->size); + ciphertext->size = plaintext->size; + oqs_sidh_iqc_ref_elliptic_curve_set(ciphertext->E, public_key_temp->E); + oqs_sidh_iqc_ref_point_set(ciphertext->P, public_key_temp->P); + oqs_sidh_iqc_ref_point_set(ciphertext->Q, public_key_temp->Q); + + oqs_sidh_iqc_ref_private_key_clear(private_key_temp); + oqs_sidh_iqc_ref_point_clear(kernel_gen); + oqs_sidh_iqc_ref_public_key_clear(public_key_temp); + oqs_sidh_iqc_ref_fp2_clear(shared_key); + free(hash); +} + +void oqs_sidh_iqc_ref_public_key_decrypt(plaintext_t plaintext, + const ciphertext_t ciphertext, + const private_key_t private_keyA, + const public_params_t paramsA) { + + public_key_t public_key_temp; + oqs_sidh_iqc_ref_public_key_init(public_key_temp); + oqs_sidh_iqc_ref_elliptic_curve_set(public_key_temp->E, ciphertext->E); + oqs_sidh_iqc_ref_point_set(public_key_temp->P, ciphertext->P); + oqs_sidh_iqc_ref_point_set(public_key_temp->Q, ciphertext->Q); + + fp2_element_t shared_key; + oqs_sidh_iqc_ref_fp2_init(shared_key); + oqs_sidh_iqc_ref_shared_key_generate(shared_key, public_key_temp, private_keyA, paramsA); + char *hash = oqs_sidh_iqc_ref_public_key_encryption_hash(shared_key, ciphertext->size); + + plaintext->content = oqs_sidh_iqc_ref_array_xor(ciphertext->content, hash, + ciphertext->size); + plaintext->size = ciphertext->size; + + oqs_sidh_iqc_ref_public_key_clear(public_key_temp); + oqs_sidh_iqc_ref_fp2_clear(shared_key); + free(hash); +} + +const mp_limb_t *mpz_limbs_read(const mpz_t x); + +char *oqs_sidh_iqc_ref_public_key_encryption_hash(const fp2_element_t value, + long size) { + // compute the size of value in chars + long size_a = labs(mpz_size(value->a)) * sizeof(mp_limb_t); + long size_b = labs(mpz_size(value->b)) * sizeof(mp_limb_t); + + char *hash = (char *) malloc(size); + + memcpy(hash, (char *) mpz_limbs_read(value->a), size_a); + memcpy(hash + size_a, (char *) mpz_limbs_read(value->b), size_b); + + return hash; +} + +long public_key_get_key_size() { + // the key size is twice as large as the base prime. + long key_size = 2 * labs(mpz_size(characteristic)) * sizeof(mp_limb_t); + return key_size; +} diff --git a/src/kex_sidh_iqc_ref/sidh_public_key_encryption.h b/src/kex_sidh_iqc_ref/sidh_public_key_encryption.h new file mode 100644 index 000000000..5cb593537 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_key_encryption.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef PUBLIC_KEY_ENCRYPTION_H +#define PUBLIC_KEY_ENCRYPTION_H + +#include "sidh_elliptic_curve.h" +#include "sidh_public_key.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Representation of ciphertext in oqs_sidh_iqc_ref + */ +typedef struct { + elliptic_curve_t E; + point_t P; + point_t Q; + char *content; + + // size of the content field + long size; +} ciphertext_struct; + +/** + * Representation of plaintext in oqs_sidh_iqc_ref + */ +typedef struct { + char *content; + + // size of the content field + long size; +} plaintext_struct; + +typedef ciphertext_struct ciphertext_t[1]; +typedef plaintext_struct plaintext_t[1]; + +/** + * Initializes the ciphertext. + * @param ciphertext + */ +void oqs_sidh_iqc_ref_public_key_ciphertext_init(ciphertext_t ciphertext); + +/** + * Frees the memory allocated to {@code ciphertext}. + * @param ciphertext + */ +void oqs_sidh_iqc_ref_public_key_ciphertext_clear(ciphertext_t ciphertext); + +/** + * Initializes the plaintext. + * @param plaintext + */ +void oqs_sidh_iqc_ref_public_key_plaintext_init(plaintext_t plaintext); + +/** + * Frees the memory allocated to {@code plaintext}. + * @param plaintext + */ +void oqs_sidh_iqc_ref_public_key_plaintext_clear(plaintext_t plaintext); + +/** + * Pads a given plain text for encryption. + * @param result the prepared plaintext + * @param raw the given plaintext + * @return 1 if successful, and -1 otherwise + */ +int oqs_sidh_iqc_ref_public_key_pad_plaintext(plaintext_t result, + const plaintext_t raw); + +/** + * Encrypts the {@code plaintext} using {@code public_key}. + * @param ciphertext the generated cipher + * @param plaintext + * @param public_keyA other's public-key + * @param paramsA other's public params + * @param paramsB own pubic params + */ +void oqs_sidh_iqc_ref_public_key_encrypt(ciphertext_t ciphertext, + const plaintext_t plaintext, + const public_key_t public_keyA, + const public_params_t paramsA, + const public_params_t paramsB); + +/** + * Decrypts the {@code ciphertext} using {@code private_key}. + * @param plaintext the result + * @param ciphertext the given ciphertext + * @param private_keyA + * @param paramsA the public parameters associated to the owner of + * the private-key + */ +void oqs_sidh_iqc_ref_public_key_decrypt(plaintext_t plaintext, + const ciphertext_t ciphertext, + const private_key_t private_keyA, + const public_params_t paramsA); + +/** + * Computes the hash of {@code value} + * @param value + * @param size size of the output hash + * @return the hash + */ +char *oqs_sidh_iqc_ref_public_key_encryption_hash(const fp2_element_t value, + long size); + +/** + * @return the key-size in bytes + */ +long public_key_get_key_size(); + +#ifdef __cplusplus +} +#endif + +#endif /* PUBLIC_KEY_ENCRYPTION_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_public_key_validation.c b/src/kex_sidh_iqc_ref/sidh_public_key_validation.c new file mode 100644 index 000000000..e1944b8dc --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_key_validation.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "sidh_public_key_validation.h" +#include "sidh_elliptic_curve_dlp.h" +#include + +int oqs_sidh_iqc_ref_public_key_is_valid(const public_key_t public_key, + const public_params_t params) { + if (!oqs_sidh_iqc_ref_public_key_check_order(public_key->P, public_key->E, params)) + return 0; + + if (!oqs_sidh_iqc_ref_public_key_check_order(public_key->Q, public_key->E, params)) + return 0; + + if (!oqs_sidh_iqc_ref_public_key_check_dependency(public_key, params)) + return 0; + + if (!oqs_sidh_iqc_ref_public_key_check_curve(public_key->E)) + return 0; + + return 1; +} + +int oqs_sidh_iqc_ref_public_key_check_order(const point_t P, + const elliptic_curve_t E, + const public_params_t params) { + mpz_t order; + point_t temp; + + mpz_init_set(order, params->le); + oqs_sidh_iqc_ref_point_init(temp); + + int result = 0; + mpz_divexact_ui(order, order, params->l); + oqs_sidh_iqc_ref_point_mul_scaler(temp, P, order, E); + if (!oqs_sidh_iqc_ref_point_is_zero(temp)) { + oqs_sidh_iqc_ref_point_mul_scaler_si(temp, temp, params->l, E); + if (oqs_sidh_iqc_ref_point_is_zero(temp)) + result = 1; + } + + mpz_clear(order); + oqs_sidh_iqc_ref_point_clear(temp); + return result; +} + +int oqs_sidh_iqc_ref_public_key_check_dependency(const public_key_t public_key, + const public_params_t params) { + mpz_t x; + mpz_init(x); + + int result = 0; + oqs_sidh_iqc_ref_elliptic_curve_prime_power_dlp(x, + public_key->P, + public_key->Q, + public_key->E, + params->l, + params->e); + + if (mpz_cmp_si(x, -1) == 0) { + oqs_sidh_iqc_ref_elliptic_curve_prime_power_dlp(x, + public_key->Q, + public_key->P, + public_key->E, + params->l, + params->e); + if (mpz_cmp_si(x, -1) == 0) + result = 1; + } + + mpz_clear(x); + return result; +} + +int oqs_sidh_iqc_ref_public_key_check_curve(const elliptic_curve_t E) { + point_t temp; + mpz_t exponent; + + oqs_sidh_iqc_ref_point_init(temp); + mpz_init_set(exponent, characteristic); + mpz_add_ui(exponent, exponent, 1); + + oqs_sidh_iqc_ref_elliptic_curve_random_point(temp, E); + oqs_sidh_iqc_ref_point_mul_scaler(temp, temp, exponent, E); + int result = oqs_sidh_iqc_ref_point_is_zero(temp); + + oqs_sidh_iqc_ref_point_clear(temp); + mpz_clear(exponent); + + return result; +} \ No newline at end of file diff --git a/src/kex_sidh_iqc_ref/sidh_public_key_validation.h b/src/kex_sidh_iqc_ref/sidh_public_key_validation.h new file mode 100644 index 000000000..067233e83 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_key_validation.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef PUBLIC_KEY_VALIDATION_H +#define PUBLIC_KEY_VALIDATION_H + +#include "sidh_elliptic_curve.h" +#include "sidh_public_key.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Check if a given public-key is valid. + * @param public_key + * @param params the other party's public parameters from which + * the public-key is generated. + * @return 1 if the public-key is valid, 0 otherwise + */ +int oqs_sidh_iqc_ref_public_key_is_valid(const public_key_t public_key, + const public_params_t params); + +/** + * Checks if {@code P} has the exact order l^e where l, e are given in + * {@code params}. + * @param P + * @param E + * @param params + * @return 1 if {@code P} has order l^e, 0 otherwise + */ +int oqs_sidh_iqc_ref_public_key_check_order(const point_t P, + const elliptic_curve_t E, + const public_params_t params); + +/** + * Checks if the two point in {@code public-key} are linearly independent. + * @param public_key + * @param params + * @return 1 if the points are linearly independent, 0 otherwise + */ +int oqs_sidh_iqc_ref_public_key_check_dependency(const public_key_t public_key, + const public_params_t params); + +/** + * Checks if a given is valid supersingular curve. A curve is considered + * valid if it has order (p + 1)^2 where p is the characteristic. The test + * is done probabilistically. + * @param E + * @return 1 if the curve is valid, 0 otherwise. + */ +int oqs_sidh_iqc_ref_public_key_check_curve(const elliptic_curve_t E); + +#ifdef __cplusplus +} +#endif + +#endif /* PUBLIC_KEY_VALIDATION_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_public_param.c b/src/kex_sidh_iqc_ref/sidh_public_param.c new file mode 100644 index 000000000..6d0249cc5 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_param.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include +#include "sidh_public_param.h" + +void oqs_sidh_iqc_ref_public_params_init(public_params_t params) { + mpz_init(params->characteristic); + oqs_sidh_iqc_ref_elliptic_curve_init(params->E); + oqs_sidh_iqc_ref_point_init(params->P); + oqs_sidh_iqc_ref_point_init(params->Q); + mpz_init(params->le); +} + +int oqs_sidh_iqc_ref_public_params_read(public_params_t paramsA, + public_params_t paramsB, + const char *file_name) { + FILE *input; + input = fopen(file_name, "r"); + if (!input) { + printf("No such file!\n"); + return 0; + } + + fp2_element_t a; + fp2_element_t b; + oqs_sidh_iqc_ref_fp2_init(a); + oqs_sidh_iqc_ref_fp2_init(b); + + gmp_fscanf(input, "p : %Zd \n", paramsA->characteristic); + mpz_set(paramsB->characteristic, paramsA->characteristic); + gmp_fscanf(input, + "E : y^2 = x^3 + (%Zd * i + %Zd) * x + (%Zd * i + %Zd) \n", + a->a, a->b, b->a, b->b); + oqs_sidh_iqc_ref_elliptic_curve_set_coeffs(paramsA->E, a, b); + oqs_sidh_iqc_ref_elliptic_curve_set(paramsB->E, paramsA->E); + gmp_fscanf(input, "lA: %ld \n", ¶msA->l); + gmp_fscanf(input, "eA: %ld \n", ¶msA->e); + mpz_ui_pow_ui(paramsA->le, paramsA->l, paramsA->e); + gmp_fscanf(input, + "PA: (%Zd * i + %Zd, %Zd * i + %Zd) \n", + a->a, a->b, b->a, b->b); + oqs_sidh_iqc_ref_point_set_coordinates(paramsA->P, a, b, 1); + gmp_fscanf(input, + "QA: (%Zd * i + %Zd, %Zd * i + %Zd) \n", + a->a, a->b, b->a, b->b); + oqs_sidh_iqc_ref_point_set_coordinates(paramsA->Q, a, b, 1); + gmp_fscanf(input, "lB: %ld \n", ¶msB->l); + gmp_fscanf(input, "eB: %ld \n", ¶msB->e); + mpz_ui_pow_ui(paramsB->le, paramsB->l, paramsB->e); + gmp_fscanf(input, + "PB: (%Zd * i + %Zd, %Zd * i + %Zd) \n", + a->a, a->b, b->a, b->b); + oqs_sidh_iqc_ref_point_set_coordinates(paramsB->P, a, b, 1); + gmp_fscanf(input, + "QB: (%Zd * i + %Zd, %Zd * i + %Zd) \n", + a->a, a->b, b->a, b->b); + oqs_sidh_iqc_ref_point_set_coordinates(paramsB->Q, a, b, 1); + + fclose(input); + oqs_sidh_iqc_ref_fp2_clear(a); + oqs_sidh_iqc_ref_fp2_clear(b); + + return 1; +} + +void oqs_sidh_iqc_ref_public_params_print(const public_params_t params, + int print_torsion) { + if (print_torsion != 1) { + printf("p : %s\n", mpz_get_str(NULL, 10, params->characteristic)); + printf("E : %s\n", oqs_sidh_iqc_ref_elliptic_curve_get_str(params->E)); + } + + printf("lA: %ld\n", params->l); + printf("eA: %ld\n", params->e); + printf("PA: %s\n", oqs_sidh_iqc_ref_point_get_str(params->P)); + printf("QA: %s\n", oqs_sidh_iqc_ref_point_get_str(params->Q)); +} + +void oqs_sidh_iqc_ref_public_params_clear(public_params_t params) { + mpz_clear(params->characteristic); + oqs_sidh_iqc_ref_elliptic_curve_clear(params->E); + oqs_sidh_iqc_ref_point_clear(params->P); + oqs_sidh_iqc_ref_point_clear(params->Q); + mpz_clear(params->le); +} \ No newline at end of file diff --git a/src/kex_sidh_iqc_ref/sidh_public_param.h b/src/kex_sidh_iqc_ref/sidh_public_param.h new file mode 100644 index 000000000..8ffd57feb --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_public_param.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef PUBLIC_PARAM_H +#define PUBLIC_PARAM_H + +#include "sidh_elliptic_curve.h" +#include "sidh_quadratic_ext.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Representation of the public parameters in oqs_sidh_iqc_ref + */ +typedef struct { + // the characteristic + mpz_t characteristic; + + elliptic_curve_t E; + unsigned long l; + unsigned long e; + + // a generator for the l^e torsion subgroup of E + point_t P; + point_t Q; + + // l^e, precomputed + mpz_t le; + +} public_params_struct; + +typedef public_params_struct public_params_t[1]; + +/** + * Initializes the public parameters. + * @param params + */ +void oqs_sidh_iqc_ref_public_params_init(public_params_t params); + +/** + * Reads the public parameters from file named {@code file_name}. + * @param paramsA + * @param paramsB + * @param file_name + * @return 1 if the parameters are read successfully, and 0 otherwise. + */ +int oqs_sidh_iqc_ref_public_params_read(public_params_t paramsA, + public_params_t paramsB, + const char *file_name); + +/** + * Prints the public parameters to the standard output. + * @param params + * @param torsion if it is 1 only the torsion parameters are printed + */ +void oqs_sidh_iqc_ref_public_params_print(const public_params_t params, + int print_torsion); + +/** + * Frees the memory allocated to {@code params}. + * @param params + */ +void oqs_sidh_iqc_ref_public_params_clear(public_params_t params); + +#ifdef __cplusplus +} +#endif + +#endif /* PUBLIC_PARAM_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_quadratic_ext.c b/src/kex_sidh_iqc_ref/sidh_quadratic_ext.c new file mode 100644 index 000000000..1256fbb8c --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_quadratic_ext.c @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "sidh_quadratic_ext.h" +#include "sidh_util.h" +#include +#include +#include + +void oqs_sidh_iqc_ref_fp_init_chararacteristic_ui(long p) { + mpz_init_set_ui(characteristic, p); +} + +void oqs_sidh_iqc_ref_fp_init_chararacteristic_str(const char *value) { + mpz_init_set_str(characteristic, value, 10); +} + +void oqs_sidh_iqc_ref_fp_init_chararacteristic(const mpz_t p) { + mpz_init_set(characteristic, p); +} + +void oqs_sidh_iqc_ref_fp_set(mpz_t x, const mpz_t a) { + mpz_mod(x, a, characteristic); +} + +void oqs_sidh_iqc_ref_fp_add(mpz_t x, const mpz_t a, const mpz_t b) { + mpz_add(x, a, b); + mpz_mod(x, x, characteristic); +} + +void oqs_sidh_iqc_ref_fp_add_ui(mpz_t x, const mpz_t a, unsigned long b) { + mpz_add_ui(x, a, b); + mpz_mod(x, x, characteristic); +} + +void oqs_sidh_iqc_ref_fp_sub(mpz_t x, const mpz_t a, const mpz_t b) { + mpz_sub(x, a, b); + mpz_mod(x, x, characteristic); +} + +void oqs_sidh_iqc_ref_fp_sub_ui(mpz_t x, const mpz_t a, unsigned long b) { + mpz_sub_ui(x, a, b); + mpz_mod(x, x, characteristic); +} + +void oqs_sidh_iqc_ref_fp_mul(mpz_t x, const mpz_t a, const mpz_t b) { + mpz_mul(x, a, b); + mpz_mod(x, x, characteristic); +} + +void oqs_sidh_iqc_ref_fp_mul_si(mpz_t x, const mpz_t a, long b) { + mpz_mul_si(x, a, b); + mpz_mod(x, x, characteristic); +} + +void oqs_sidh_iqc_ref_fp_inv(mpz_t x, const mpz_t a) { + mpz_invert(x, a, characteristic); +} + +void oqs_sidh_iqc_ref_fp_div(mpz_t x, const mpz_t a, const mpz_t b) { + oqs_sidh_iqc_ref_fp_inv(x, b); + oqs_sidh_iqc_ref_fp_mul(x, a, x); +} + +void oqs_sidh_iqc_ref_fp_neg(mpz_t x, const mpz_t a) { + oqs_sidh_iqc_ref_fp_sub(x, characteristic, a); +} + +void oqs_sidh_iqc_ref_fp_sqrt(mpz_t x, const mpz_t a) { + mpz_t exponent; + mpz_init(exponent); + + // compute (p + 1) / 4 + mpz_add_ui(exponent, characteristic, 1); + mpz_divexact_ui(exponent, exponent, 4); + + mpz_powm(x, a, exponent, characteristic); + mpz_clear(exponent); +} + +//////////////// fp2 methods ////////////////////////// + +void oqs_sidh_iqc_ref_fp2_init(fp2_element_t x) { mpz_inits(x->a, x->b, NULL); } + +void oqs_sidh_iqc_ref_fp2_init_set_si(fp2_element_t x, long a, long b) { + mpz_init_set_si(x->a, a); + mpz_init_set_si(x->b, b); +} + +void oqs_sidh_iqc_ref_fp2_init_set_str(fp2_element_t x, const char *a, + const char *b) { + mpz_init_set_str(x->a, a, 10); + mpz_init_set_str(x->b, b, 10); +} + +void oqs_sidh_iqc_ref_fp2_init_set(fp2_element_t x, const fp2_element_t a) { + mpz_init_set(x->a, a->a); + mpz_init_set(x->b, a->b); +} + +void oqs_sidh_iqc_ref_fp2_clear(fp2_element_t x) { + mpz_clears(x->a, x->b, NULL); +} + +void oqs_sidh_iqc_ref_fp2_set(fp2_element_t x, const fp2_element_t b) { + mpz_set(x->a, b->a); + mpz_set(x->b, b->b); +} + +void oqs_sidh_iqc_ref_fp2_zero(fp2_element_t x) { + mpz_set_si(x->a, 0); + mpz_set_si(x->b, 0); +} + +void oqs_sidh_iqc_ref_fp2_one(fp2_element_t x) { + mpz_set_si(x->a, 0); + mpz_set_si(x->b, 1); +} + +char *oqs_sidh_iqc_ref_fp2_get_str(const fp2_element_t a) { + + if (mpz_cmp_si(a->a, 0) == 0 && mpz_cmp_si(a->b, 0) == 0) { + return "0"; + } + + if (mpz_cmp_si(a->a, 0) == 0) { + return mpz_get_str(NULL, 10, a->b); + } + + char *result = ""; + + if (mpz_cmp_si(a->b, 0) == 0) { + result = oqs_sidh_iqc_ref_concat(result, mpz_get_str(NULL, 10, a->a)); + result = oqs_sidh_iqc_ref_concat(result, " * i"); + return result; + } + + result = oqs_sidh_iqc_ref_concat(result, mpz_get_str(NULL, 10, a->a)); + result = oqs_sidh_iqc_ref_concat(result, " * i + "); + result = oqs_sidh_iqc_ref_concat(result, mpz_get_str(NULL, 10, a->b)); + + return result; +} + +void oqs_sidh_iqc_ref_fp2_add(fp2_element_t x, const fp2_element_t a, + const fp2_element_t b) { + oqs_sidh_iqc_ref_fp_add(x->a, a->a, b->a); + oqs_sidh_iqc_ref_fp_add(x->b, a->b, b->b); +} + +void oqs_sidh_iqc_ref_fp2_add_ui(fp2_element_t x, const fp2_element_t a, + unsigned long b) { + oqs_sidh_iqc_ref_fp_add_ui(x->b, a->b, b); + oqs_sidh_iqc_ref_fp_set(x->a, a->a); +} + +void oqs_sidh_iqc_ref_fp2_sub(fp2_element_t x, const fp2_element_t a, + const fp2_element_t b) { + oqs_sidh_iqc_ref_fp_sub(x->a, a->a, b->a); + oqs_sidh_iqc_ref_fp_sub(x->b, a->b, b->b); +} + +void oqs_sidh_iqc_ref_fp2_sub_ui(fp2_element_t x, const fp2_element_t a, + unsigned long b) { + oqs_sidh_iqc_ref_fp_sub_ui(x->b, a->b, b); + oqs_sidh_iqc_ref_fp_set(x->a, a->a); +} + +void oqs_sidh_iqc_ref_fp2_mul(fp2_element_t x, const fp2_element_t a, + const fp2_element_t b) { + mpz_t temp1; + mpz_t temp2; + + mpz_init(temp1); + mpz_init(temp2); + + fp2_element_t result; + oqs_sidh_iqc_ref_fp2_init(result); + + // (a + b) * (c + d) + oqs_sidh_iqc_ref_fp_add(temp1, a->a, a->b); + oqs_sidh_iqc_ref_fp_add(temp2, b->a, b->b); + oqs_sidh_iqc_ref_fp_mul(result->a, temp1, temp2); + + // a * c + oqs_sidh_iqc_ref_fp_mul(temp1, a->a, b->a); + // b * d + oqs_sidh_iqc_ref_fp_mul(temp2, a->b, b->b); + + oqs_sidh_iqc_ref_fp_sub(result->a, result->a, temp1); + oqs_sidh_iqc_ref_fp_sub(result->a, result->a, temp2); + oqs_sidh_iqc_ref_fp_sub(result->b, temp2, temp1); + oqs_sidh_iqc_ref_fp2_set(x, result); + + mpz_clear(temp1); + mpz_clear(temp2); + oqs_sidh_iqc_ref_fp2_clear(result); +} + +void oqs_sidh_iqc_ref_fp2_square(fp2_element_t x, const fp2_element_t a) { + mpz_t temp1; + mpz_t temp2; + + mpz_init(temp1); + mpz_init(temp2); + + fp2_element_t result; + oqs_sidh_iqc_ref_fp2_init(result); + + // (b + a) * (b - a) + oqs_sidh_iqc_ref_fp_add(temp1, a->a, a->b); + oqs_sidh_iqc_ref_fp_sub(temp2, a->b, a->a); + oqs_sidh_iqc_ref_fp_mul(result->b, temp1, temp2); + + // 2 * a * b + oqs_sidh_iqc_ref_fp_mul(result->a, a->a, a->b); + oqs_sidh_iqc_ref_fp_mul_si(result->a, result->a, 2); + + oqs_sidh_iqc_ref_fp2_set(x, result); + + mpz_clear(temp1); + mpz_clear(temp2); + oqs_sidh_iqc_ref_fp2_clear(result); +} + +void oqs_sidh_iqc_ref_fp2_pow_ui(fp2_element_t x, const fp2_element_t a, + unsigned long n) { + mpz_t temp_n; + mpz_init_set_ui(temp_n, n); + oqs_sidh_iqc_ref_fp2_pow(x, a, temp_n); + mpz_clear(temp_n); +} + +void oqs_sidh_iqc_ref_fp2_pow(fp2_element_t x, const fp2_element_t a, + const mpz_t n) { + if (mpz_cmp_ui(n, 0) == 0) { + oqs_sidh_iqc_ref_fp2_one(x); + return; + } + + fp2_element_t temp1; + fp2_element_t temp2; + oqs_sidh_iqc_ref_fp2_init_set_si(temp1, 0, 1); + oqs_sidh_iqc_ref_fp2_init_set(temp2, a); + + long num_bits = mpz_sizeinbase(n, 2); + for (long i = 0; i < num_bits; i++) { + if (mpz_tstbit(n, i) == 1) + oqs_sidh_iqc_ref_fp2_mul(temp1, temp1, temp2); + oqs_sidh_iqc_ref_fp2_square(temp2, temp2); + } + + oqs_sidh_iqc_ref_fp2_set(x, temp1); + + oqs_sidh_iqc_ref_fp2_clear(temp1); + oqs_sidh_iqc_ref_fp2_clear(temp2); +} + +void oqs_sidh_iqc_ref_fp2_conjugate(fp2_element_t x, const fp2_element_t a) { + oqs_sidh_iqc_ref_fp2_set(x, a); + oqs_sidh_iqc_ref_fp_neg(x->a, x->a); +} + +void oqs_sidh_iqc_ref_fp2_negate(fp2_element_t x, const fp2_element_t a) { + oqs_sidh_iqc_ref_fp2_set(x, a); + oqs_sidh_iqc_ref_fp_neg(x->a, x->a); + oqs_sidh_iqc_ref_fp_neg(x->b, x->b); +} + +void oqs_sidh_iqc_ref_fp2_mul_scaler(fp2_element_t x, const fp2_element_t a, + const mpz_t scaler) { + oqs_sidh_iqc_ref_fp_mul(x->a, a->a, scaler); + oqs_sidh_iqc_ref_fp_mul(x->b, a->b, scaler); +} + +void oqs_sidh_iqc_ref_fp2_mul_scaler_si(fp2_element_t x, const fp2_element_t a, + long scaler) { + oqs_sidh_iqc_ref_fp_mul_si(x->a, a->a, scaler); + oqs_sidh_iqc_ref_fp_mul_si(x->b, a->b, scaler); +} + +void oqs_sidh_iqc_ref_fp2_inv(fp2_element_t x, const fp2_element_t a) { + mpz_t temp; + fp2_element_t result; + + mpz_init(temp); + oqs_sidh_iqc_ref_fp2_init(result); + + oqs_sidh_iqc_ref_fp2_conjugate(result, a); + oqs_sidh_iqc_ref_fp2_norm(temp, a); + oqs_sidh_iqc_ref_fp_inv(temp, temp); + oqs_sidh_iqc_ref_fp2_mul_scaler(result, result, temp); + oqs_sidh_iqc_ref_fp2_set(x, result); + + mpz_clear(temp); + oqs_sidh_iqc_ref_fp2_clear(result); +} + +void oqs_sidh_iqc_ref_fp2_div(fp2_element_t x, const fp2_element_t a, + const fp2_element_t b) { + fp2_element_t result; + oqs_sidh_iqc_ref_fp2_init(result); + + oqs_sidh_iqc_ref_fp2_inv(result, b); + oqs_sidh_iqc_ref_fp2_mul(result, a, result); + oqs_sidh_iqc_ref_fp2_set(x, result); + + oqs_sidh_iqc_ref_fp2_clear(result); +} + +int oqs_sidh_iqc_ref_fp2_is_zero(const fp2_element_t a) { + return !mpz_cmp_si(a->a, 0) && !mpz_cmp_si(a->b, 0); +} + +int oqs_sidh_iqc_ref_fp2_is_one(const fp2_element_t a) { + return !mpz_cmp_si(a->a, 0) && !mpz_cmp_si(a->b, 1); +} + +int oqs_sidh_iqc_ref_fp2_equals(const fp2_element_t a, const fp2_element_t b) { + return (mpz_cmp(a->a, b->a) == 0) && (mpz_cmp(a->b, b->b) == 0); +} + +void oqs_sidh_iqc_ref_fp2_random(fp2_element_t x, gmp_randstate_t randstate) { + mpz_urandomm(x->a, randstate, characteristic); + mpz_urandomm(x->b, randstate, characteristic); +} + +void oqs_sidh_iqc_ref_fp2_sqrt(fp2_element_t x, const fp2_element_t a) { + mpz_t exponent; + fp2_element_t temp_a; + fp2_element_t b; + fp2_element_t c; + fp2_element_t beta; + mpz_t base_root; + gmp_randstate_t randstate; + + mpz_init(exponent); + oqs_sidh_iqc_ref_fp2_init(temp_a); + oqs_sidh_iqc_ref_fp2_init(b); + oqs_sidh_iqc_ref_fp2_init(c); + oqs_sidh_iqc_ref_fp2_init(beta); + mpz_init(base_root); + gmp_randinit_default(randstate); + + // compute (p - 1) / 2 + mpz_sub_ui(exponent, characteristic, 1); + mpz_divexact_ui(exponent, exponent, 2); + + while (oqs_sidh_iqc_ref_fp2_is_zero(b)) { + oqs_sidh_iqc_ref_fp2_random(c, randstate); + oqs_sidh_iqc_ref_fp2_square(temp_a, c); + oqs_sidh_iqc_ref_fp2_mul(temp_a, temp_a, a); + + // compute 1 + temp_a^((p - 1) / 2) + oqs_sidh_iqc_ref_fp2_pow(b, temp_a, exponent); + oqs_sidh_iqc_ref_fp2_add_ui(b, b, 1); + } + + // compute temp_a * b^2 + oqs_sidh_iqc_ref_fp2_square(beta, b); + oqs_sidh_iqc_ref_fp2_mul(beta, beta, temp_a); + + // beta is now in the prime field + oqs_sidh_iqc_ref_fp_sqrt(base_root, beta->b); + oqs_sidh_iqc_ref_fp2_inv(b, b); + oqs_sidh_iqc_ref_fp2_mul_scaler(b, b, base_root); + oqs_sidh_iqc_ref_fp2_div(x, b, c); + + mpz_clear(exponent); + oqs_sidh_iqc_ref_fp2_clear(temp_a); + oqs_sidh_iqc_ref_fp2_clear(b); + oqs_sidh_iqc_ref_fp2_clear(c); + oqs_sidh_iqc_ref_fp2_clear(beta); + mpz_clear(base_root); + gmp_randclear(randstate); +} + +int oqs_sidh_iqc_ref_fp2_is_square(const fp2_element_t a) { + mpz_t exponent; + mpz_t norm; + fp2_element_t temp; + + mpz_init(exponent); + mpz_init(norm); + oqs_sidh_iqc_ref_fp2_init(temp); + + // a^((p - 1) / 2) + mpz_sub_ui(exponent, characteristic, 1); + mpz_divexact_ui(exponent, exponent, 2); + oqs_sidh_iqc_ref_fp2_pow(temp, a, exponent); + + oqs_sidh_iqc_ref_fp2_norm(norm, temp); + int result = (mpz_cmp_si(norm, 1) == 0); + + mpz_clear(exponent); + mpz_clear(norm); + oqs_sidh_iqc_ref_fp2_clear(temp); + + return result; +} + +void oqs_sidh_iqc_ref_fp2_norm(mpz_t x, const fp2_element_t a) { + mpz_t temp1; + mpz_t temp2; + mpz_inits(temp1, temp2, NULL); + + oqs_sidh_iqc_ref_fp_mul(temp1, a->a, a->a); + oqs_sidh_iqc_ref_fp_mul(temp2, a->b, a->b); + oqs_sidh_iqc_ref_fp_add(temp1, temp1, temp2); + + mpz_set(x, temp1); + mpz_clears(temp1, temp2, NULL); +} + +void oqs_sidh_iqc_ref_fp2_to_bytes(uint8_t *bytes, const fp2_element_t a, + long prime_size) { + for (long i = 0; i < 2 * prime_size; i++) + bytes[i] = 0; + + mpz_export(bytes, NULL, -1, 1, 0, 0, a->a); + mpz_export(bytes + prime_size, NULL, -1, 1, 0, 0, a->b); +} + +void oqs_sidh_iqc_ref_bytes_to_fp2(fp2_element_t a, const uint8_t *bytes, + long prime_size) { + oqs_sidh_iqc_ref_fp2_zero(a); + mpz_import(a->a, prime_size, -1, 1, 0, 0, bytes); + mpz_import(a->b, prime_size, -1, 1, 0, 0, bytes + prime_size); +} diff --git a/src/kex_sidh_iqc_ref/sidh_quadratic_ext.h b/src/kex_sidh_iqc_ref/sidh_quadratic_ext.h new file mode 100644 index 000000000..b481c92ac --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_quadratic_ext.h @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef FP2_H +#define FP2_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +mpz_t characteristic; + +/** + * Representation of elements of the quadratic extension F_(p^2) + * of F_p. We assume F_(p^2) is represented by the quotient + * F_p[X] / (X^2 + 1) which requires X^2 + 1 to be irreducible over F_p. + * The elements are therefore of the form a * i + b where i^2 = -1. + */ +typedef struct { + mpz_t a; + mpz_t b; +} fp2_element_struct; + +typedef fp2_element_struct fp2_element_t[1]; + +//////////////// fp methods ////////////////////////// + +/** + * {@link oqs_sidh_iqc_ref_init_chararacteristic} + * @param p + */ +void oqs_sidh_iqc_ref_fp_init_chararacteristic_ui(long p); + +/** + * {@link oqs_sidh_iqc_ref_init_chararacteristic} + * @param value + */ +void oqs_sidh_iqc_ref_fp_init_chararacteristic_str(const char *value); + +/** + * Initializes the characteristic to {@code p}. + * @param p + */ +void oqs_sidh_iqc_ref_fp_init_chararacteristic(const mpz_t p); + +/** + * Sets {@code x = a}. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp_set(mpz_t x, const mpz_t a); + +/** + * Sets {@code x = a + b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp_add(mpz_t x, + const mpz_t a, + const mpz_t b); + +/** + * {@link oqs_sidh_iqc_ref_fp_add}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp_add_ui(mpz_t x, + const mpz_t a, + unsigned long b); + +/** + * Sets {@code x = a - b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp_sub(mpz_t x, + const mpz_t a, + const mpz_t b); + +/** + * {@link oqs_sidh_iqc_ref_fp_sub} + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp_sub_ui(mpz_t x, + const mpz_t a, + unsigned long b); + +/** + * Sets {@code x = a * b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp_mul(mpz_t x, + const mpz_t a, + const mpz_t b); + +/** + * {@link oqs_sidh_iqc_ref_fp_mul} + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp_mul_si(mpz_t x, + const mpz_t a, + long b); + +/** + * Sets {@code x = 1 / a}. This is possible only if {@code a} is + * prime to the characteristic. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp_inv(mpz_t x, + const mpz_t a); + +/** + * Sets {x = a / b}. @see fp_inv. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp_div(mpz_t x, + const mpz_t a, + const mpz_t b); + +/** + * Sets {@code x = -a}. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp_neg(mpz_t x, + const mpz_t a); + +/** + * Computes the square root of {@code a}. + * This method works only for p = 3 mod 4. + * @param x the square root + * @param a + */ +void oqs_sidh_iqc_ref_fp_sqrt(mpz_t x, + const mpz_t a); + +//////////////// fp2 methods ////////////////////////// + +/** + * Initializes {@code x} to zero. + * @param x + */ +void oqs_sidh_iqc_ref_fp2_init(fp2_element_t x); + +/** + * Initializes {@code x} to {@code a * i + b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_init_set_si(fp2_element_t x, + long a, + long b); + +/** + * {@link oqs_sidh_iqc_ref_fp2_init_set_si}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_init_set_str(fp2_element_t x, + const char *a, + const char *b); + +/** + * Initializes {@code x} to {@code a}. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp2_init_set(fp2_element_t x, + const fp2_element_t a); + +/** + * Frees the memory allocated to {@code x}. + * @param x + */ +void oqs_sidh_iqc_ref_fp2_clear(fp2_element_t x); + +/** + * Copies {@code a} into {@code x}. + * @param x + * @param b + */ +void oqs_sidh_iqc_ref_fp2_set(fp2_element_t x, + const fp2_element_t b); + +/** + * Sets {@code a = 0} + * @param x + */ +void oqs_sidh_iqc_ref_fp2_zero(fp2_element_t x); + +/** + * Sets {@code x = 1}. + * @param x + */ +void oqs_sidh_iqc_ref_fp2_one(fp2_element_t x); + +/** + * @param a + * @return the string representation of {@code a} + */ +char *oqs_sidh_iqc_ref_fp2_get_str(const fp2_element_t a); + +/** + * Sets {@code x = a + b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_add(fp2_element_t x, + const fp2_element_t a, + const fp2_element_t b); + +/** + * {@link oqs_sidh_iqc_ref_fp2_add} + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_add_ui(fp2_element_t x, + const fp2_element_t a, + unsigned long b); + +/** + * Sets {@code x = a - b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_sub(fp2_element_t x, + const fp2_element_t a, + const fp2_element_t b); + +/** + * {@link oqs_sidh_iqc_ref_fp2_sub} + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_sub_ui(fp2_element_t x, + const fp2_element_t a, + unsigned long b); + +/** + * Sets {@code x = a * b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_mul(fp2_element_t x, + const fp2_element_t a, + const fp2_element_t b); + +/** + * Sets {@code x = a^2}. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp2_square(fp2_element_t x, + const fp2_element_t a); + +/** + * {@link oqs_sidh_iqc_ref_fp2_pow} + */ +void oqs_sidh_iqc_ref_fp2_pow_ui(fp2_element_t x, + const fp2_element_t a, + unsigned long n); + +/** + * Sets {@code x = a^n}. + * @param x + * @param a + * @param n + */ +void oqs_sidh_iqc_ref_fp2_pow(fp2_element_t x, + const fp2_element_t a, + const mpz_t n); + +/** + * Sets {@code x = 1 / a}. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp2_inv(fp2_element_t x, + const fp2_element_t a); + +/** + * Sets {@code x = a / b}. + * @param x + * @param a + * @param b + */ +void oqs_sidh_iqc_ref_fp2_div(fp2_element_t x, + const fp2_element_t a, + const fp2_element_t b); + +/** + * Sets {@code x = -u * i + v} where {@code a = u * i + v}. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp2_conjugate(fp2_element_t x, + const fp2_element_t a); + +/** + * Sets {@code x = -a}. + * @param x + * @param a + */ +void oqs_sidh_iqc_ref_fp2_negate(fp2_element_t x, + const fp2_element_t a); + +/** + * Sets {@code x = a * scaler}. + * @param x + * @param a + * @param scaler + */ +void oqs_sidh_iqc_ref_fp2_mul_scaler(fp2_element_t x, + const fp2_element_t a, + const mpz_t scaler); + +/** + * {@link oqs_sidh_iqc_ref_fp2_mul_scaler} + * @param x + * @param a + * @param scaler + */ +void oqs_sidh_iqc_ref_fp2_mul_scaler_si(fp2_element_t x, + const fp2_element_t a, + long scaler); + +/** + * Checks if {@code a} is zero. + * @param a + * @return 1 if {@code a == 0}, and 0 otherwise + */ +int oqs_sidh_iqc_ref_fp2_is_zero(const fp2_element_t a); + +/** + * Checks if {@code a} is one. + * @param a + * @return 1 if {@code a == 1}, and 0 otherwise + */ +int oqs_sidh_iqc_ref_fp2_is_one(const fp2_element_t a); + +/** + * Checks if {@code a == b}. + * @param a + * @param b + * @return 1 if {@code a == b}, and 0 otherwise. + */ +int oqs_sidh_iqc_ref_fp2_equals(const fp2_element_t a, + const fp2_element_t b); + +/** + * Generates a random element in the quadratic extension. + * @param x the generated random element + * @param randstate + */ +void oqs_sidh_iqc_ref_fp2_random(fp2_element_t x, + gmp_randstate_t randstate); + +/** + * Computes the square root of {@code a}. + * The algorithm is based on + * Doliskani & Schost, Taking Roots over High Extensions of Finite Fields, 2011. + * It works for any characteristic, but since it uses {@link oqs_sidh_iqc_ref_fp_sqrt} for + * base-case square root, it is limited to p = 3 mod 4. + * @param x the square root + * @param a + */ +void oqs_sidh_iqc_ref_fp2_sqrt(fp2_element_t x, + const fp2_element_t a); + +/** + * Checks if {@code a} is a square. + * @param a + * @return 1 if {@code a} is a square, 0 otherwise + */ +int oqs_sidh_iqc_ref_fp2_is_square(const fp2_element_t a); + +/** + * Computes the norm of {@code x = b * i + c} which is b^2 + c^2. + * @param x the computed norm + * @param a + */ +void oqs_sidh_iqc_ref_fp2_norm(mpz_t x, + const fp2_element_t a); + +/** + * Converts bytes an fp2 element to a byte array. + * @param bytes + * @param a + * @param prime_size + */ +void oqs_sidh_iqc_ref_fp2_to_bytes(uint8_t *bytes, + const fp2_element_t a, + long prime_size); + +/** + * Converts a byte array to an fp2 element. + * @param a + * @param bytes + * @param prime_size + */ +void oqs_sidh_iqc_ref_bytes_to_fp2(fp2_element_t a, + const uint8_t *bytes, + long prime_size); + +#ifdef __cplusplus +} +#endif + +#endif /* FP2_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_shared_key.c b/src/kex_sidh_iqc_ref/sidh_shared_key.c new file mode 100644 index 000000000..9b095ed23 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_shared_key.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "sidh_shared_key.h" +#include "sidh_isogeny.h" + +void oqs_sidh_iqc_ref_shared_key_generate(fp2_element_t shared_key, + const public_key_t public_key, + const private_key_t private_key, + const public_params_t params) { + + point_t kernel_gen; + oqs_sidh_iqc_ref_point_init(kernel_gen); + + // compute a generator for the kernel of the isogeny + oqs_sidh_iqc_ref_private_key_compute_kernel_gen(kernel_gen, + private_key, + public_key->P, + public_key->Q, + params->le, + public_key->E); + elliptic_curve_t E; + oqs_sidh_iqc_ref_elliptic_curve_init(E); + oqs_sidh_iqc_ref_elliptic_curve_set(E, public_key->E); + + oqs_sidh_iqc_ref_isogeny_evaluate_strategy_curve(E, kernel_gen, params->l, params->e, 0.5); + // oqs_sidh_iqc_ref_isogeny_evaluate_naive_curve(E, kernel_gen, params->l, params->e, 3); + + oqs_sidh_iqc_ref_elliptic_curve_compute_j_inv(shared_key, E); + + oqs_sidh_iqc_ref_point_clear(kernel_gen); + oqs_sidh_iqc_ref_elliptic_curve_clear(E); +} \ No newline at end of file diff --git a/src/kex_sidh_iqc_ref/sidh_shared_key.h b/src/kex_sidh_iqc_ref/sidh_shared_key.h new file mode 100644 index 000000000..279975cae --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_shared_key.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef SHARED_KEY_H +#define SHARED_KEY_H + +#include "sidh_private_key.h" +#include "sidh_public_key.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generates the shared-key. + * @param shared_key the generated shared-key + * @param public_key other's public-key + * @param private_key own private-key + * @param params own parameters + */ +void oqs_sidh_iqc_ref_shared_key_generate(fp2_element_t shared_key, + const public_key_t public_key, + const private_key_t private_key, + const public_params_t params); + +#ifdef __cplusplus +} +#endif + +#endif /* SHARED_KEY_H */ diff --git a/src/kex_sidh_iqc_ref/sidh_util.c b/src/kex_sidh_iqc_ref/sidh_util.c new file mode 100644 index 000000000..7e8eed127 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_util.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "sidh_util.h" + +char *oqs_sidh_iqc_ref_concat(char *str1, const char *str2) { + char *temp = (char *) malloc(strlen(str1) + strlen(str2) + 1); + strcpy(temp, str1); + strcat(temp, str2); + return temp; +} + +char *oqs_sidh_iqc_ref_get_random_str(int num_bytes) { + char *rand_value = (char *) malloc(num_bytes); + OQS_RAND *rand = OQS_RAND_new(OQS_RAND_alg_urandom_chacha20); + OQS_RAND_n(rand, (uint8_t *) rand_value, num_bytes); + + return rand_value; +} + +void oqs_sidh_iqc_ref_get_random_mpz(mpz_t x) { + int num_bytes = 20; + char *a = oqs_sidh_iqc_ref_get_random_str(num_bytes); + mpz_import(x, num_bytes, 1, sizeof(char), 0, 0, a); +} + +char *oqs_sidh_iqc_ref_array_xor(const char *array1, const char *array2, + long lenght) { + char *result = (char *) malloc(lenght); + for (long i = 0; i < lenght; i++) + result[i] = array1[i] ^ array2[i]; + + return result; +} \ No newline at end of file diff --git a/src/kex_sidh_iqc_ref/sidh_util.h b/src/kex_sidh_iqc_ref/sidh_util.h new file mode 100644 index 000000000..5a4b72ac4 --- /dev/null +++ b/src/kex_sidh_iqc_ref/sidh_util.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Javad Doliskani, javad.doliskani@uwaterloo.ca + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef UTIL_H +#define UTIL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Concatenates two strings. + * @param str1 + * @param str2 + * @return the concatenation of {@code str1, str2} + */ +char *oqs_sidh_iqc_ref_concat(char *str1, + const char *str2); + +/** + * Generates a random char array of length {@code num_bytes}. + * @param num_bytes + * @return a random char array of length {@code num_bytes} + */ +char *oqs_sidh_iqc_ref_get_random_str(int num_bytes); + +/** + * @param x a randomly generated 160bit integer + */ +void oqs_sidh_iqc_ref_get_random_mpz(mpz_t x); + +/** + * @param array1 + * @param array2 + * @param lenght + * @return the bitwise xor of the two arrays + */ +char *oqs_sidh_iqc_ref_array_xor(const char *array1, + const char *array2, + long lenght); + +#ifdef __cplusplus +} +#endif + +#endif /* UTIL_H */