diff --git a/CMakeLists.txt b/CMakeLists.txt
index 96431d56b..dc41cbc8d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.5)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
cmake_policy(SET CMP0054 NEW)
endif()
diff --git a/bench/bench_ep.c b/bench/bench_ep.c
index 04ccdfc83..54b36f890 100644
--- a/bench/bench_ep.c
+++ b/bench/bench_ep.c
@@ -394,6 +394,11 @@ static void arith(void) {
BENCH_ADD(ep_mul_gen(q, k));
} BENCH_END;
+ BENCH_RUN("ep_mul_cof") {
+ ep_rand(p);
+ BENCH_ADD(ep_mul_cof(q, p));
+ } BENCH_END;
+
BENCH_RUN("ep_mul_dig") {
bn_rand(k, RLC_POS, RLC_DIG);
bn_rand_mod(k, n);
@@ -575,6 +580,32 @@ static void arith(void) {
BENCH_ADD(ep_map(p, msg, 5));
} BENCH_END;
+#if EP_MAP == BASIC || !defined(STRIP)
+ BENCH_RUN("ep_map_basic") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep_map_basic(p, msg, 5));
+ } BENCH_END;
+#endif
+
+#if EP_MAP == SSWUM || !defined(STRIP)
+ BENCH_RUN("ep_map_sswum") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep_map_sswum(p, msg, 5));
+ } BENCH_END;
+#endif
+
+#if EP_MAP == SWIFT || !defined(STRIP)
+ if (ep_curve_opt_a() == RLC_ZERO || ep_curve_opt_b() == RLC_ZERO) {
+ BENCH_RUN("ep_map_swift") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep_map_swift(p, msg, 5));
+ } BENCH_END;
+ }
+#endif
+
BENCH_RUN("ep_pck") {
ep_rand(p);
BENCH_ADD(ep_pck(q, p));
diff --git a/bench/bench_epx.c b/bench/bench_epx.c
index 9df560f20..46e054db7 100644
--- a/bench/bench_epx.c
+++ b/bench/bench_epx.c
@@ -362,10 +362,15 @@ static void arith2(void) {
BENCH_ADD(ep2_mul_gen(q, k));
} BENCH_END;
+ BENCH_RUN("ep2_mul_cof") {
+ ep2_rand(p);
+ BENCH_ADD(ep2_mul_cof(q, p));
+ } BENCH_END;
+
BENCH_RUN("ep2_mul_dig") {
bn_rand(k, RLC_POS, RLC_DIG);
- bn_rand_mod(k, n);
- BENCH_ADD(ep2_mul_dig(p, q, k->dp[0]));
+ ep2_rand(p);
+ BENCH_ADD(ep2_mul_dig(q, p, k->dp[0]));
}
BENCH_END;
@@ -549,6 +554,24 @@ static void arith2(void) {
BENCH_ADD(ep2_map(p, msg, 5));
} BENCH_END;
+ BENCH_RUN("ep2_map_basic") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep2_map_basic(p, msg, 5));
+ } BENCH_END;
+
+ BENCH_RUN("ep2_map_sswum") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep2_map_sswum(p, msg, 5));
+ } BENCH_END;
+
+ BENCH_RUN("ep2_map_swift") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep2_map_swift(p, msg, 5));
+ } BENCH_END;
+
BENCH_RUN("ep2_pck") {
ep2_rand(p);
BENCH_ADD(ep2_pck(q, p));
@@ -569,464 +592,963 @@ static void arith2(void) {
fp2_free(s);
}
-static void memory4(void) {
- ep4_t a[BENCH];
+static void memory3(void) {
+ ep3_t a[BENCH];
- BENCH_FEW("ep4_null", ep4_null(a[i]), 1);
+ BENCH_FEW("ep3_null", ep3_null(a[i]), 1);
- BENCH_FEW("ep4_new", ep4_new(a[i]), 1);
+ BENCH_FEW("ep3_new", ep3_new(a[i]), 1);
for (int i = 0; i < BENCH; i++) {
- ep4_free(a[i]);
+ ep3_free(a[i]);
}
for (int i = 0; i < BENCH; i++) {
- ep4_new(a[i]);
+ ep3_new(a[i]);
}
- BENCH_FEW("ep4_free", ep4_free(a[i]), 1);
+ BENCH_FEW("ep3_free", ep3_free(a[i]), 1);
(void)a;
}
-static void util4(void) {
- ep4_t p, q, t[2];
+static void util3(void) {
+ ep3_t p, q, t[2];
uint8_t bin[8 * RLC_FP_BYTES + 1];
int l;
- ep4_null(p);
- ep4_null(q);
- ep4_null(t[0]);
- ep4_null(t[1]);
+ ep3_null(p);
+ ep3_null(q);
+ ep3_null(t[0]);
+ ep3_null(t[1]);
- ep4_new(p);
- ep4_new(q);
- ep4_new(t[0]);
- ep4_new(t[1]);
+ ep3_new(p);
+ ep3_new(q);
+ ep3_new(t[0]);
+ ep3_new(t[1]);
- BENCH_RUN("ep4_is_infty") {
- ep4_rand(p);
- BENCH_ADD(ep4_is_infty(p));
+ BENCH_RUN("ep3_is_infty") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_is_infty(p));
}
BENCH_END;
- BENCH_RUN("ep4_set_infty") {
- ep4_rand(p);
- BENCH_ADD(ep4_set_infty(p));
+ BENCH_RUN("ep3_set_infty") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_set_infty(p));
}
BENCH_END;
- BENCH_RUN("ep4_copy") {
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_copy(p, q));
+ BENCH_RUN("ep3_copy") {
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_copy(p, q));
}
BENCH_END;
- BENCH_RUN("ep4_cmp") {
- ep4_rand(p);
- ep4_dbl(p, p);
- ep4_rand(q);
- ep4_dbl(q, q);
- BENCH_ADD(ep4_cmp(p, q));
+ BENCH_RUN("ep3_cmp") {
+ ep3_rand(p);
+ ep3_dbl(p, p);
+ ep3_rand(q);
+ ep3_dbl(q, q);
+ BENCH_ADD(ep3_cmp(p, q));
} BENCH_END;
- BENCH_RUN("ep4_norm") {
- ep4_rand(p);
- ep4_dbl(p, p);
- BENCH_ADD(ep4_norm(p, p));
+ BENCH_RUN("ep3_norm") {
+ ep3_rand(p);
+ ep3_dbl(p, p);
+ BENCH_ADD(ep3_norm(p, p));
} BENCH_END;
- BENCH_RUN("ep4_norm_sim (2)") {
- ep4_rand(t[0]);
- ep4_rand(t[1]);
- ep4_dbl(t[0], t[0]);
- ep4_dbl(t[1], t[1]);
- BENCH_ADD(ep4_norm_sim(t, t, 2));
+ BENCH_RUN("ep3_norm_sim (2)") {
+ ep3_rand(t[0]);
+ ep3_rand(t[1]);
+ ep3_dbl(t[0], t[0]);
+ ep3_dbl(t[1], t[1]);
+ BENCH_ADD(ep3_norm_sim(t, t, 2));
} BENCH_END;
- BENCH_RUN("ep4_cmp (1 norm)") {
- ep4_rand(p);
- ep4_dbl(p, p);
- ep4_rand(q);
- BENCH_ADD(ep4_cmp(p, q));
+ BENCH_RUN("ep3_cmp (1 norm)") {
+ ep3_rand(p);
+ ep3_dbl(p, p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_cmp(p, q));
} BENCH_END;
- BENCH_RUN("ep4_cmp (2 norm)") {
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_cmp(p, q));
+ BENCH_RUN("ep3_cmp (2 norm)") {
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_cmp(p, q));
} BENCH_END;
- BENCH_RUN("ep4_rand") {
- BENCH_ADD(ep4_rand(p));
+ BENCH_RUN("ep3_rand") {
+ BENCH_ADD(ep3_rand(p));
}
BENCH_END;
- BENCH_RUN("ep4_blind") {
- BENCH_ADD(ep4_blind(p, p));
+ BENCH_RUN("ep3_blind") {
+ BENCH_ADD(ep3_blind(p, p));
}
BENCH_END;
- BENCH_RUN("ep4_on_curve") {
- ep4_rand(p);
- BENCH_ADD(ep4_on_curve(p));
+ BENCH_RUN("ep3_on_curve") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_on_curve(p));
} BENCH_END;
- BENCH_RUN("ep4_size_bin") {
- ep4_rand(p);
- BENCH_ADD(ep4_size_bin(p, 0));
+ BENCH_RUN("ep3_size_bin") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_size_bin(p, 0));
} BENCH_END;
- BENCH_RUN("ep4_write_bin") {
- ep4_rand(p);
- l = ep4_size_bin(p, 0);
- BENCH_ADD(ep4_write_bin(bin, l, p, 0));
+ BENCH_RUN("ep3_write_bin") {
+ ep3_rand(p);
+ l = ep3_size_bin(p, 0);
+ BENCH_ADD(ep3_write_bin(bin, l, p, 0));
} BENCH_END;
- BENCH_RUN("ep4_read_bin") {
- ep4_rand(p);
- l = ep4_size_bin(p, 0);
- ep4_write_bin(bin, l, p, 0);
- BENCH_ADD(ep4_read_bin(p, bin, l));
+ BENCH_RUN("ep3_read_bin") {
+ ep3_rand(p);
+ l = ep3_size_bin(p, 0);
+ ep3_write_bin(bin, l, p, 0);
+ BENCH_ADD(ep3_read_bin(p, bin, l));
} BENCH_END;
- ep4_free(p);
- ep4_free(q);
- ep4_free(t[0]);
- ep4_free(t[1]);
+ ep3_free(p);
+ ep3_free(q);
+ ep3_free(t[0]);
+ ep3_free(t[1]);
}
-static void arith4(void) {
- ep4_t p, q, r, t[RLC_EPX_TABLE_MAX];
+static void arith3(void) {
+ ep3_t p, q, r, t[RLC_EPX_TABLE_MAX];
bn_t k, n, l;
- fp4_t s;
+ fp3_t s;
- ep4_null(p);
- ep4_null(q);
- ep4_null(r);
+ ep3_null(p);
+ ep3_null(q);
+ ep3_null(r);
bn_null(k);
bn_null(n);
- fp4_null(s);
+ fp3_null(s);
for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
- ep4_null(t[i]);
+ ep3_null(t[i]);
}
- ep4_new(p);
- ep4_new(q);
- ep4_new(r);
+ ep3_new(p);
+ ep3_new(q);
+ ep3_new(r);
bn_new(k);
bn_new(n);
bn_new(l);
- fp4_new(s);
+ fp3_new(s);
- ep4_curve_get_ord(n);
+ ep3_curve_get_ord(n);
- BENCH_RUN("ep4_add") {
- ep4_rand(p);
- ep4_rand(q);
- ep4_add(p, p, q);
- ep4_rand(q);
- ep4_rand(p);
- ep4_add(q, q, p);
- BENCH_ADD(ep4_add(r, p, q));
+ BENCH_RUN("ep3_add") {
+ ep3_rand(p);
+ ep3_rand(q);
+ ep3_add(p, p, q);
+ ep3_rand(q);
+ ep3_rand(p);
+ ep3_add(q, q, p);
+ BENCH_ADD(ep3_add(r, p, q));
}
BENCH_END;
#if EP_ADD == BASIC || !defined(STRIP)
- BENCH_RUN("ep4_add_basic") {
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_add_basic(r, p, q));
+ BENCH_RUN("ep3_add_basic") {
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_add_basic(r, p, q));
}
BENCH_END;
- BENCH_RUN("ep4_add_slp_basic") {
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_add_slp_basic(r, s, p, q));
+ BENCH_RUN("ep3_add_slp_basic") {
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_add_slp_basic(r, s, p, q));
}
BENCH_END;
#endif
#if EP_ADD == PROJC || !defined(STRIP)
- BENCH_RUN("ep4_add_projc") {
- ep4_rand(p);
- ep4_rand(q);
- ep4_add_projc(p, p, q);
- ep4_rand(q);
- ep4_rand(p);
- ep4_add_projc(q, q, p);
- BENCH_ADD(ep4_add_projc(r, p, q));
+ BENCH_RUN("ep3_add_projc") {
+ ep3_rand(p);
+ ep3_rand(q);
+ ep3_add_projc(p, p, q);
+ ep3_rand(q);
+ ep3_rand(p);
+ ep3_add_projc(q, q, p);
+ BENCH_ADD(ep3_add_projc(r, p, q));
}
BENCH_END;
- BENCH_RUN("ep4_add_projc (z2 = 1)") {
- ep4_rand(p);
- ep4_rand(q);
- ep4_add_projc(p, p, q);
- ep4_rand(q);
- ep4_norm(q, q);
- BENCH_ADD(ep4_add_projc(r, p, q));
+ BENCH_RUN("ep3_add_projc (z2 = 1)") {
+ ep3_rand(p);
+ ep3_rand(q);
+ ep3_add_projc(p, p, q);
+ ep3_rand(q);
+ ep3_norm(q, q);
+ BENCH_ADD(ep3_add_projc(r, p, q));
}
BENCH_END;
- BENCH_RUN("ep4_add_projc (z1,z2 = 1)") {
- ep4_rand(p);
- ep4_norm(p, p);
- ep4_rand(q);
- ep4_norm(q, q);
- BENCH_ADD(ep4_add_projc(r, p, q));
+ BENCH_RUN("ep3_add_projc (z1,z2 = 1)") {
+ ep3_rand(p);
+ ep3_norm(p, p);
+ ep3_rand(q);
+ ep3_norm(q, q);
+ BENCH_ADD(ep3_add_projc(r, p, q));
}
BENCH_END;
#endif
- BENCH_RUN("ep4_sub") {
- ep4_rand(p);
- ep4_rand(q);
- ep4_add(p, p, q);
- ep4_rand(q);
- ep4_rand(p);
- ep4_add(q, q, p);
- BENCH_ADD(ep4_sub(r, p, q));
+ BENCH_RUN("ep3_sub") {
+ ep3_rand(p);
+ ep3_rand(q);
+ ep3_add(p, p, q);
+ ep3_rand(q);
+ ep3_rand(p);
+ ep3_add(q, q, p);
+ BENCH_ADD(ep3_sub(r, p, q));
}
BENCH_END;
- BENCH_RUN("ep4_dbl") {
- ep4_rand(p);
- ep4_rand(q);
- ep4_add(p, p, q);
- BENCH_ADD(ep4_dbl(r, p));
+ BENCH_RUN("ep3_dbl") {
+ ep3_rand(p);
+ ep3_rand(q);
+ ep3_add(p, p, q);
+ BENCH_ADD(ep3_dbl(r, p));
}
BENCH_END;
#if EP_ADD == BASIC || !defined(STRIP)
- BENCH_RUN("ep4_dbl_basic") {
- ep4_rand(p);
- BENCH_ADD(ep4_dbl_basic(r, p));
+ BENCH_RUN("ep3_dbl_basic") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_dbl_basic(r, p));
}
BENCH_END;
- BENCH_RUN("ep4_dbl_slp_basic") {
- ep4_rand(p);
- BENCH_ADD(ep4_dbl_slp_basic(r, s, p));
+ BENCH_RUN("ep3_dbl_slp_basic") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_dbl_slp_basic(r, s, p));
}
BENCH_END;
#endif
#if EP_ADD == PROJC || !defined(STRIP)
- BENCH_RUN("ep4_dbl_projc") {
- ep4_rand(p);
- ep4_rand(q);
- ep4_add_projc(p, p, q);
- BENCH_ADD(ep4_dbl_projc(r, p));
+ BENCH_RUN("ep3_dbl_projc") {
+ ep3_rand(p);
+ ep3_rand(q);
+ ep3_add_projc(p, p, q);
+ BENCH_ADD(ep3_dbl_projc(r, p));
}
BENCH_END;
- BENCH_RUN("ep4_dbl_projc (z1 = 1)") {
- ep4_rand(p);
- ep4_norm(p, p);
- BENCH_ADD(ep4_dbl_projc(r, p));
+ BENCH_RUN("ep3_dbl_projc (z1 = 1)") {
+ ep3_rand(p);
+ ep3_norm(p, p);
+ BENCH_ADD(ep3_dbl_projc(r, p));
}
BENCH_END;
#endif
- BENCH_RUN("ep4_neg") {
- ep4_rand(p);
- ep4_rand(q);
- ep4_add(p, p, q);
- BENCH_ADD(ep4_neg(r, p));
+ BENCH_RUN("ep3_neg") {
+ ep3_rand(p);
+ ep3_rand(q);
+ ep3_add(p, p, q);
+ BENCH_ADD(ep3_neg(r, p));
}
BENCH_END;
- BENCH_RUN("ep4_mul") {
+ BENCH_RUN("ep3_mul") {
bn_rand_mod(k, n);
- BENCH_ADD(ep4_mul(q, p, k));
+ BENCH_ADD(ep3_mul(q, p, k));
} BENCH_END;
#if EP_MUL == BASIC || !defined(STRIP)
- BENCH_RUN("ep4_mul_basic") {
+ BENCH_RUN("ep3_mul_basic") {
bn_rand_mod(k, n);
- BENCH_ADD(ep4_mul_basic(q, p, k));
+ BENCH_ADD(ep3_mul_basic(q, p, k));
} BENCH_END;
#endif
#if EP_MUL == SLIDE || !defined(STRIP)
- BENCH_RUN("ep4_mul_slide") {
+ BENCH_RUN("ep3_mul_slide") {
bn_rand_mod(k, n);
- ep4_rand(p);
- BENCH_ADD(ep4_mul_slide(q, p, k));
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_slide(q, p, k));
} BENCH_END;
#endif
#if EP_MUL == MONTY || !defined(STRIP)
- BENCH_RUN("ep4_mul_monty") {
+ BENCH_RUN("ep3_mul_monty") {
bn_rand_mod(k, n);
- ep4_rand(p);
- BENCH_ADD(ep4_mul_monty(q, p, k));
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_monty(q, p, k));
} BENCH_END;
#endif
#if EP_MUL == LWNAF || !defined(STRIP)
- BENCH_RUN("ep4_mul_lwnaf") {
+ BENCH_RUN("ep3_mul_lwnaf") {
bn_rand_mod(k, n);
- ep4_rand(p);
- BENCH_ADD(ep4_mul_lwnaf(q, p, k));
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_lwnaf(q, p, k));
} BENCH_END;
#endif
- BENCH_RUN("ep4_mul_gen") {
+ BENCH_RUN("ep3_mul_gen") {
bn_rand_mod(k, n);
- BENCH_ADD(ep4_mul_gen(q, k));
+ BENCH_ADD(ep3_mul_gen(q, k));
} BENCH_END;
- BENCH_RUN("ep4_mul_dig") {
+ BENCH_RUN("ep3_mul_cof") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_cof(q, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep3_mul_dig") {
bn_rand(k, RLC_POS, RLC_DIG);
- bn_rand_mod(k, n);
- BENCH_ADD(ep4_mul_dig(p, q, k->dp[0]));
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_dig(q, p, k->dp[0]));
}
BENCH_END;
for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
- ep4_new(t[i]);
+ ep3_new(t[i]);
}
- BENCH_RUN("ep4_mul_pre") {
- ep4_rand(p);
- BENCH_ADD(ep4_mul_pre(t, p));
+ BENCH_RUN("ep3_mul_pre") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_pre(t, p));
} BENCH_END;
- BENCH_RUN("ep4_mul_fix") {
+ BENCH_RUN("ep3_mul_fix") {
bn_rand_mod(k, n);
- ep4_rand(p);
- ep4_mul_pre(t, p);
- BENCH_ADD(ep4_mul_fix(q, t, k));
+ ep3_rand(p);
+ ep3_mul_pre(t, p);
+ BENCH_ADD(ep3_mul_fix(q, t, k));
} BENCH_END;
for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
- ep4_free(t[i]);
+ ep3_free(t[i]);
}
#if EP_FIX == BASIC || !defined(STRIP)
for (int i = 0; i < RLC_EPX_TABLE_BASIC; i++) {
- ep4_new(t[i]);
+ ep3_new(t[i]);
}
- BENCH_RUN("ep4_mul_pre_basic") {
- ep4_rand(p);
- BENCH_ADD(ep4_mul_pre_basic(t, p));
+ BENCH_RUN("ep3_mul_pre_basic") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_pre_basic(t, p));
} BENCH_END;
- BENCH_RUN("ep4_mul_fix_basic") {
+ BENCH_RUN("ep3_mul_fix_basic") {
bn_rand_mod(k, n);
- ep4_rand(p);
- ep4_mul_pre_basic(t, p);
- BENCH_ADD(ep4_mul_fix_basic(q, t, k));
+ ep3_rand(p);
+ ep3_mul_pre_basic(t, p);
+ BENCH_ADD(ep3_mul_fix_basic(q, t, k));
} BENCH_END;
for (int i = 0; i < RLC_EPX_TABLE_BASIC; i++) {
- ep4_free(t[i]);
+ ep3_free(t[i]);
}
#endif
#if EP_FIX == COMBS || !defined(STRIP)
for (int i = 0; i < RLC_EPX_TABLE_COMBS; i++) {
- ep4_new(t[i]);
+ ep3_new(t[i]);
}
- BENCH_RUN("ep4_mul_pre_combs") {
- ep4_rand(p);
- BENCH_ADD(ep4_mul_pre_combs(t, p));
+ BENCH_RUN("ep3_mul_pre_combs") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_pre_combs(t, p));
} BENCH_END;
- BENCH_RUN("ep4_mul_fix_combs") {
+ BENCH_RUN("ep3_mul_fix_combs") {
bn_rand_mod(k, n);
- ep4_rand(p);
- ep4_mul_pre_combs(t, p);
- BENCH_ADD(ep4_mul_fix_combs(q, t, k));
+ ep3_rand(p);
+ ep3_mul_pre_combs(t, p);
+ BENCH_ADD(ep3_mul_fix_combs(q, t, k));
} BENCH_END;
for (int i = 0; i < RLC_EPX_TABLE_COMBS; i++) {
- ep4_free(t[i]);
+ ep3_free(t[i]);
}
#endif
#if EP_FIX == COMBD || !defined(STRIP)
for (int i = 0; i < RLC_EPX_TABLE_COMBD; i++) {
- ep4_new(t[i]);
+ ep3_new(t[i]);
}
- BENCH_RUN("ep4_mul_pre_combd") {
- BENCH_ADD(ep4_mul_pre_combd(t, p));
+ BENCH_RUN("ep3_mul_pre_combd") {
+ BENCH_ADD(ep3_mul_pre_combd(t, p));
} BENCH_END;
- BENCH_RUN("ep4_mul_fix_combd") {
+ BENCH_RUN("ep3_mul_fix_combd") {
bn_rand_mod(k, n);
- ep4_mul_pre_combd(t, p);
- BENCH_ADD(ep4_mul_fix_combd(q, t, k));
+ ep3_mul_pre_combd(t, p);
+ BENCH_ADD(ep3_mul_fix_combd(q, t, k));
} BENCH_END;
for (int i = 0; i < RLC_EPX_TABLE_COMBD; i++) {
- ep4_free(t[i]);
+ ep3_free(t[i]);
}
#endif
#if EP_FIX == LWNAF || !defined(STRIP)
for (int i = 0; i < RLC_EPX_TABLE_LWNAF; i++) {
- ep4_new(t[i]);
+ ep3_new(t[i]);
}
- BENCH_RUN("ep4_mul_pre_lwnaf") {
- ep4_rand(p);
- BENCH_ADD(ep4_mul_pre_lwnaf(t, p));
+ BENCH_RUN("ep3_mul_pre_lwnaf") {
+ ep3_rand(p);
+ BENCH_ADD(ep3_mul_pre_lwnaf(t, p));
} BENCH_END;
- BENCH_RUN("ep4_mul_fix_lwnaf") {
+ BENCH_RUN("ep3_mul_fix_lwnaf") {
bn_rand_mod(k, n);
- ep4_rand(p);
- ep4_mul_pre_lwnaf(t, p);
- BENCH_ADD(ep4_mul_fix_lwnaf(q, t, k));
+ ep3_rand(p);
+ ep3_mul_pre_lwnaf(t, p);
+ BENCH_ADD(ep3_mul_fix_lwnaf(q, t, k));
} BENCH_END;
for (int i = 0; i < RLC_EPX_TABLE_LWNAF; i++) {
- ep4_free(t[i]);
+ ep3_free(t[i]);
}
#endif
- BENCH_RUN("ep4_mul_sim") {
+ BENCH_RUN("ep3_mul_sim") {
bn_rand_mod(k, n);
bn_rand_mod(l, n);
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_mul_sim(r, p, k, q, l));
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_mul_sim(r, p, k, q, l));
} BENCH_END;
#if EP_SIM == BASIC || !defined(STRIP)
- BENCH_RUN("ep4_mul_sim_basic") {
+ BENCH_RUN("ep3_mul_sim_basic") {
bn_rand_mod(k, n);
bn_rand_mod(l, n);
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_mul_sim_basic(r, p, k, q, l));
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_mul_sim_basic(r, p, k, q, l));
} BENCH_END;
#endif
#if EP_SIM == TRICK || !defined(STRIP)
- BENCH_RUN("ep4_mul_sim_trick") {
+ BENCH_RUN("ep3_mul_sim_trick") {
bn_rand_mod(k, n);
bn_rand_mod(l, n);
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_mul_sim_trick(r, p, k, q, l));
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_mul_sim_trick(r, p, k, q, l));
} BENCH_END;
#endif
#if EP_SIM == INTER || !defined(STRIP)
- BENCH_RUN("ep4_mul_sim_inter") {
+ BENCH_RUN("ep3_mul_sim_inter") {
bn_rand_mod(k, n);
bn_rand_mod(l, n);
- ep4_rand(p);
- ep4_rand(q);
- BENCH_ADD(ep4_mul_sim_inter(r, p, k, q, l));
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_mul_sim_inter(r, p, k, q, l));
} BENCH_END;
#endif
#if EP_SIM == JOINT || !defined(STRIP)
- BENCH_RUN("ep4_mul_sim_joint") {
+ BENCH_RUN("ep3_mul_sim_joint") {
bn_rand_mod(k, n);
bn_rand_mod(l, n);
- ep4_rand(p);
- ep4_rand(q);
+ ep3_rand(p);
+ ep3_rand(q);
+ BENCH_ADD(ep3_mul_sim_joint(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+ BENCH_RUN("ep3_mul_sim_gen") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep3_rand(q);
+ BENCH_ADD(ep3_mul_sim_gen(r, k, q, l));
+ } BENCH_END;
+
+ BENCH_RUN("ep3_frb") {
+ ep3_rand(q);
+ BENCH_ADD(ep3_frb(r, q, 1));
+ } BENCH_END;
+
+ BENCH_RUN("ep3_map") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep3_map(p, msg, 5));
+ } BENCH_END;
+
+ ep3_free(p);
+ ep3_free(q);
+ ep3_free(r);
+ bn_free(k);
+ bn_free(n);
+ bn_free(l);
+ fp3_free(s);
+}
+
+static void memory4(void) {
+ ep4_t a[BENCH];
+
+ BENCH_FEW("ep4_null", ep4_null(a[i]), 1);
+
+ BENCH_FEW("ep4_new", ep4_new(a[i]), 1);
+ for (int i = 0; i < BENCH; i++) {
+ ep4_free(a[i]);
+ }
+
+ for (int i = 0; i < BENCH; i++) {
+ ep4_new(a[i]);
+ }
+ BENCH_FEW("ep4_free", ep4_free(a[i]), 1);
+
+ (void)a;
+}
+
+static void util4(void) {
+ ep4_t p, q, t[2];
+ uint8_t bin[8 * RLC_FP_BYTES + 1];
+ int l;
+
+ ep4_null(p);
+ ep4_null(q);
+ ep4_null(t[0]);
+ ep4_null(t[1]);
+
+ ep4_new(p);
+ ep4_new(q);
+ ep4_new(t[0]);
+ ep4_new(t[1]);
+
+ BENCH_RUN("ep4_is_infty") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_is_infty(p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_set_infty") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_set_infty(p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_copy") {
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_copy(p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_cmp") {
+ ep4_rand(p);
+ ep4_dbl(p, p);
+ ep4_rand(q);
+ ep4_dbl(q, q);
+ BENCH_ADD(ep4_cmp(p, q));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_norm") {
+ ep4_rand(p);
+ ep4_dbl(p, p);
+ BENCH_ADD(ep4_norm(p, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_norm_sim (2)") {
+ ep4_rand(t[0]);
+ ep4_rand(t[1]);
+ ep4_dbl(t[0], t[0]);
+ ep4_dbl(t[1], t[1]);
+ BENCH_ADD(ep4_norm_sim(t, t, 2));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_cmp (1 norm)") {
+ ep4_rand(p);
+ ep4_dbl(p, p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_cmp(p, q));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_cmp (2 norm)") {
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_cmp(p, q));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_rand") {
+ BENCH_ADD(ep4_rand(p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_blind") {
+ BENCH_ADD(ep4_blind(p, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_on_curve") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_on_curve(p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_size_bin") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_size_bin(p, 0));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_write_bin") {
+ ep4_rand(p);
+ l = ep4_size_bin(p, 0);
+ BENCH_ADD(ep4_write_bin(bin, l, p, 0));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_read_bin") {
+ ep4_rand(p);
+ l = ep4_size_bin(p, 0);
+ ep4_write_bin(bin, l, p, 0);
+ BENCH_ADD(ep4_read_bin(p, bin, l));
+ } BENCH_END;
+
+ ep4_free(p);
+ ep4_free(q);
+ ep4_free(t[0]);
+ ep4_free(t[1]);
+}
+
+static void arith4(void) {
+ ep4_t p, q, r, t[RLC_EPX_TABLE_MAX];
+ bn_t k, n, l;
+ fp4_t s;
+
+ ep4_null(p);
+ ep4_null(q);
+ ep4_null(r);
+ bn_null(k);
+ bn_null(n);
+ fp4_null(s);
+ for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
+ ep4_null(t[i]);
+ }
+
+ ep4_new(p);
+ ep4_new(q);
+ ep4_new(r);
+ bn_new(k);
+ bn_new(n);
+ bn_new(l);
+ fp4_new(s);
+
+ ep4_curve_get_ord(n);
+
+ BENCH_RUN("ep4_add") {
+ ep4_rand(p);
+ ep4_rand(q);
+ ep4_add(p, p, q);
+ ep4_rand(q);
+ ep4_rand(p);
+ ep4_add(q, q, p);
+ BENCH_ADD(ep4_add(r, p, q));
+ }
+ BENCH_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ BENCH_RUN("ep4_add_basic") {
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_add_basic(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_add_slp_basic") {
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_add_slp_basic(r, s, p, q));
+ }
+ BENCH_END;
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+ BENCH_RUN("ep4_add_projc") {
+ ep4_rand(p);
+ ep4_rand(q);
+ ep4_add_projc(p, p, q);
+ ep4_rand(q);
+ ep4_rand(p);
+ ep4_add_projc(q, q, p);
+ BENCH_ADD(ep4_add_projc(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_add_projc (z2 = 1)") {
+ ep4_rand(p);
+ ep4_rand(q);
+ ep4_add_projc(p, p, q);
+ ep4_rand(q);
+ ep4_norm(q, q);
+ BENCH_ADD(ep4_add_projc(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_add_projc (z1,z2 = 1)") {
+ ep4_rand(p);
+ ep4_norm(p, p);
+ ep4_rand(q);
+ ep4_norm(q, q);
+ BENCH_ADD(ep4_add_projc(r, p, q));
+ }
+ BENCH_END;
+#endif
+
+ BENCH_RUN("ep4_sub") {
+ ep4_rand(p);
+ ep4_rand(q);
+ ep4_add(p, p, q);
+ ep4_rand(q);
+ ep4_rand(p);
+ ep4_add(q, q, p);
+ BENCH_ADD(ep4_sub(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_dbl") {
+ ep4_rand(p);
+ ep4_rand(q);
+ ep4_add(p, p, q);
+ BENCH_ADD(ep4_dbl(r, p));
+ }
+ BENCH_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ BENCH_RUN("ep4_dbl_basic") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_dbl_basic(r, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_dbl_slp_basic") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_dbl_slp_basic(r, s, p));
+ }
+ BENCH_END;
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+ BENCH_RUN("ep4_dbl_projc") {
+ ep4_rand(p);
+ ep4_rand(q);
+ ep4_add_projc(p, p, q);
+ BENCH_ADD(ep4_dbl_projc(r, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_dbl_projc (z1 = 1)") {
+ ep4_rand(p);
+ ep4_norm(p, p);
+ BENCH_ADD(ep4_dbl_projc(r, p));
+ }
+ BENCH_END;
+#endif
+
+ BENCH_RUN("ep4_neg") {
+ ep4_rand(p);
+ ep4_rand(q);
+ ep4_add(p, p, q);
+ BENCH_ADD(ep4_neg(r, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep4_mul") {
+ bn_rand_mod(k, n);
+ BENCH_ADD(ep4_mul(q, p, k));
+ } BENCH_END;
+
+#if EP_MUL == BASIC || !defined(STRIP)
+ BENCH_RUN("ep4_mul_basic") {
+ bn_rand_mod(k, n);
+ BENCH_ADD(ep4_mul_basic(q, p, k));
+ } BENCH_END;
+#endif
+
+#if EP_MUL == SLIDE || !defined(STRIP)
+ BENCH_RUN("ep4_mul_slide") {
+ bn_rand_mod(k, n);
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_slide(q, p, k));
+ } BENCH_END;
+#endif
+
+#if EP_MUL == MONTY || !defined(STRIP)
+ BENCH_RUN("ep4_mul_monty") {
+ bn_rand_mod(k, n);
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_monty(q, p, k));
+ } BENCH_END;
+#endif
+
+#if EP_MUL == LWNAF || !defined(STRIP)
+ BENCH_RUN("ep4_mul_lwnaf") {
+ bn_rand_mod(k, n);
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_lwnaf(q, p, k));
+ } BENCH_END;
+#endif
+
+ BENCH_RUN("ep4_mul_gen") {
+ bn_rand_mod(k, n);
+ BENCH_ADD(ep4_mul_gen(q, k));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_mul_cof") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_cof(q, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_mul_dig") {
+ bn_rand(k, RLC_POS, RLC_DIG);
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_dig(q, p, k->dp[0]));
+ }
+ BENCH_END;
+
+ for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
+ ep4_new(t[i]);
+ }
+
+ BENCH_RUN("ep4_mul_pre") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_pre(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_mul_fix") {
+ bn_rand_mod(k, n);
+ ep4_rand(p);
+ ep4_mul_pre(t, p);
+ BENCH_ADD(ep4_mul_fix(q, t, k));
+ } BENCH_END;
+
+ for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
+ ep4_free(t[i]);
+ }
+
+#if EP_FIX == BASIC || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_BASIC; i++) {
+ ep4_new(t[i]);
+ }
+ BENCH_RUN("ep4_mul_pre_basic") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_pre_basic(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_mul_fix_basic") {
+ bn_rand_mod(k, n);
+ ep4_rand(p);
+ ep4_mul_pre_basic(t, p);
+ BENCH_ADD(ep4_mul_fix_basic(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_BASIC; i++) {
+ ep4_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == COMBS || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_COMBS; i++) {
+ ep4_new(t[i]);
+ }
+ BENCH_RUN("ep4_mul_pre_combs") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_pre_combs(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_mul_fix_combs") {
+ bn_rand_mod(k, n);
+ ep4_rand(p);
+ ep4_mul_pre_combs(t, p);
+ BENCH_ADD(ep4_mul_fix_combs(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_COMBS; i++) {
+ ep4_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == COMBD || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_COMBD; i++) {
+ ep4_new(t[i]);
+ }
+ BENCH_RUN("ep4_mul_pre_combd") {
+ BENCH_ADD(ep4_mul_pre_combd(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_mul_fix_combd") {
+ bn_rand_mod(k, n);
+ ep4_mul_pre_combd(t, p);
+ BENCH_ADD(ep4_mul_fix_combd(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_COMBD; i++) {
+ ep4_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == LWNAF || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_LWNAF; i++) {
+ ep4_new(t[i]);
+ }
+ BENCH_RUN("ep4_mul_pre_lwnaf") {
+ ep4_rand(p);
+ BENCH_ADD(ep4_mul_pre_lwnaf(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep4_mul_fix_lwnaf") {
+ bn_rand_mod(k, n);
+ ep4_rand(p);
+ ep4_mul_pre_lwnaf(t, p);
+ BENCH_ADD(ep4_mul_fix_lwnaf(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_LWNAF; i++) {
+ ep4_free(t[i]);
+ }
+#endif
+
+ BENCH_RUN("ep4_mul_sim") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_mul_sim(r, p, k, q, l));
+ } BENCH_END;
+
+#if EP_SIM == BASIC || !defined(STRIP)
+ BENCH_RUN("ep4_mul_sim_basic") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_mul_sim_basic(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+#if EP_SIM == TRICK || !defined(STRIP)
+ BENCH_RUN("ep4_mul_sim_trick") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_mul_sim_trick(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+#if EP_SIM == INTER || !defined(STRIP)
+ BENCH_RUN("ep4_mul_sim_inter") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep4_rand(p);
+ ep4_rand(q);
+ BENCH_ADD(ep4_mul_sim_inter(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+#if EP_SIM == JOINT || !defined(STRIP)
+ BENCH_RUN("ep4_mul_sim_joint") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep4_rand(p);
+ ep4_rand(q);
BENCH_ADD(ep4_mul_sim_joint(r, p, k, q, l));
} BENCH_END;
#endif
@@ -1058,8 +1580,502 @@ static void arith4(void) {
fp4_free(s);
}
+static void memory8(void) {
+ ep8_t a[BENCH];
+
+ BENCH_FEW("ep8_null", ep8_null(a[i]), 1);
+
+ BENCH_FEW("ep8_new", ep8_new(a[i]), 1);
+ for (int i = 0; i < BENCH; i++) {
+ ep8_free(a[i]);
+ }
+
+ for (int i = 0; i < BENCH; i++) {
+ ep8_new(a[i]);
+ }
+ BENCH_FEW("ep8_free", ep8_free(a[i]), 1);
+
+ (void)a;
+}
+
+static void util8(void) {
+ ep8_t p, q, t[2];
+ uint8_t bin[16 * RLC_FP_BYTES + 1];
+ int l;
+
+ ep8_null(p);
+ ep8_null(q);
+ ep8_null(t[0]);
+ ep8_null(t[1]);
+
+ ep8_new(p);
+ ep8_new(q);
+ ep8_new(t[0]);
+ ep8_new(t[1]);
+
+ BENCH_RUN("ep8_is_infty") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_is_infty(p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_set_infty") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_set_infty(p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_copy") {
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_copy(p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_cmp") {
+ ep8_rand(p);
+ ep8_dbl(p, p);
+ ep8_rand(q);
+ ep8_dbl(q, q);
+ BENCH_ADD(ep8_cmp(p, q));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_norm") {
+ ep8_rand(p);
+ ep8_dbl(p, p);
+ BENCH_ADD(ep8_norm(p, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_norm_sim (2)") {
+ ep8_rand(t[0]);
+ ep8_rand(t[1]);
+ ep8_dbl(t[0], t[0]);
+ ep8_dbl(t[1], t[1]);
+ BENCH_ADD(ep8_norm_sim(t, t, 2));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_cmp (1 norm)") {
+ ep8_rand(p);
+ ep8_dbl(p, p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_cmp(p, q));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_cmp (2 norm)") {
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_cmp(p, q));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_rand") {
+ BENCH_ADD(ep8_rand(p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_blind") {
+ BENCH_ADD(ep8_blind(p, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_on_curve") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_on_curve(p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_size_bin") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_size_bin(p, 0));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_write_bin") {
+ ep8_rand(p);
+ l = ep8_size_bin(p, 0);
+ BENCH_ADD(ep8_write_bin(bin, l, p, 0));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_read_bin") {
+ ep8_rand(p);
+ l = ep8_size_bin(p, 0);
+ ep8_write_bin(bin, l, p, 0);
+ BENCH_ADD(ep8_read_bin(p, bin, l));
+ } BENCH_END;
+
+ ep8_free(p);
+ ep8_free(q);
+ ep8_free(t[0]);
+ ep8_free(t[1]);
+}
+
+static void arith8(void) {
+ ep8_t p, q, r, t[RLC_EPX_TABLE_MAX];
+ bn_t k, n, l;
+ fp8_t s;
+
+ ep8_null(p);
+ ep8_null(q);
+ ep8_null(r);
+ bn_null(k);
+ bn_null(n);
+ fp8_null(s);
+ for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
+ ep8_null(t[i]);
+ }
+
+ ep8_new(p);
+ ep8_new(q);
+ ep8_new(r);
+ bn_new(k);
+ bn_new(n);
+ bn_new(l);
+ fp8_new(s);
+
+ ep8_curve_get_ord(n);
+
+ BENCH_RUN("ep8_add") {
+ ep8_rand(p);
+ ep8_rand(q);
+ ep8_add(p, p, q);
+ ep8_rand(q);
+ ep8_rand(p);
+ ep8_add(q, q, p);
+ BENCH_ADD(ep8_add(r, p, q));
+ }
+ BENCH_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ BENCH_RUN("ep8_add_basic") {
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_add_basic(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_add_slp_basic") {
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_add_slp_basic(r, s, p, q));
+ }
+ BENCH_END;
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+ BENCH_RUN("ep8_add_projc") {
+ ep8_rand(p);
+ ep8_rand(q);
+ ep8_add_projc(p, p, q);
+ ep8_rand(q);
+ ep8_rand(p);
+ ep8_add_projc(q, q, p);
+ BENCH_ADD(ep8_add_projc(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_add_projc (z2 = 1)") {
+ ep8_rand(p);
+ ep8_rand(q);
+ ep8_add_projc(p, p, q);
+ ep8_rand(q);
+ ep8_norm(q, q);
+ BENCH_ADD(ep8_add_projc(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_add_projc (z1,z2 = 1)") {
+ ep8_rand(p);
+ ep8_norm(p, p);
+ ep8_rand(q);
+ ep8_norm(q, q);
+ BENCH_ADD(ep8_add_projc(r, p, q));
+ }
+ BENCH_END;
+#endif
+
+ BENCH_RUN("ep8_sub") {
+ ep8_rand(p);
+ ep8_rand(q);
+ ep8_add(p, p, q);
+ ep8_rand(q);
+ ep8_rand(p);
+ ep8_add(q, q, p);
+ BENCH_ADD(ep8_sub(r, p, q));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_dbl") {
+ ep8_rand(p);
+ ep8_rand(q);
+ ep8_add(p, p, q);
+ BENCH_ADD(ep8_dbl(r, p));
+ }
+ BENCH_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ BENCH_RUN("ep8_dbl_basic") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_dbl_basic(r, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_dbl_slp_basic") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_dbl_slp_basic(r, s, p));
+ }
+ BENCH_END;
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+ BENCH_RUN("ep8_dbl_projc") {
+ ep8_rand(p);
+ ep8_rand(q);
+ ep8_add_projc(p, p, q);
+ BENCH_ADD(ep8_dbl_projc(r, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_dbl_projc (z1 = 1)") {
+ ep8_rand(p);
+ ep8_norm(p, p);
+ BENCH_ADD(ep8_dbl_projc(r, p));
+ }
+ BENCH_END;
+#endif
+
+ BENCH_RUN("ep8_neg") {
+ ep8_rand(p);
+ ep8_rand(q);
+ ep8_add(p, p, q);
+ BENCH_ADD(ep8_neg(r, p));
+ }
+ BENCH_END;
+
+ BENCH_RUN("ep8_mul") {
+ bn_rand_mod(k, n);
+ BENCH_ADD(ep8_mul(q, p, k));
+ } BENCH_END;
+
+#if EP_MUL == BASIC || !defined(STRIP)
+ BENCH_RUN("ep8_mul_basic") {
+ bn_rand_mod(k, n);
+ BENCH_ADD(ep8_mul_basic(q, p, k));
+ } BENCH_END;
+#endif
+
+#if EP_MUL == SLIDE || !defined(STRIP)
+ BENCH_RUN("ep8_mul_slide") {
+ bn_rand_mod(k, n);
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_slide(q, p, k));
+ } BENCH_END;
+#endif
+
+#if EP_MUL == MONTY || !defined(STRIP)
+ BENCH_RUN("ep8_mul_monty") {
+ bn_rand_mod(k, n);
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_monty(q, p, k));
+ } BENCH_END;
+#endif
+
+#if EP_MUL == LWNAF || !defined(STRIP)
+ BENCH_RUN("ep8_mul_lwnaf") {
+ bn_rand_mod(k, n);
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_lwnaf(q, p, k));
+ } BENCH_END;
+#endif
+
+ BENCH_RUN("ep8_mul_gen") {
+ bn_rand_mod(k, n);
+ BENCH_ADD(ep8_mul_gen(q, k));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_mul_cof") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_cof(q, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_mul_dig") {
+ bn_rand(k, RLC_POS, RLC_DIG);
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_dig(q, p, k->dp[0]));
+ }
+ BENCH_END;
+
+ for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
+ ep8_new(t[i]);
+ }
+
+ BENCH_RUN("ep8_mul_pre") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_pre(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_mul_fix") {
+ bn_rand_mod(k, n);
+ ep8_rand(p);
+ ep8_mul_pre(t, p);
+ BENCH_ADD(ep8_mul_fix(q, t, k));
+ } BENCH_END;
+
+ for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
+ ep8_free(t[i]);
+ }
+
+#if EP_FIX == BASIC || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_BASIC; i++) {
+ ep8_new(t[i]);
+ }
+ BENCH_RUN("ep8_mul_pre_basic") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_pre_basic(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_mul_fix_basic") {
+ bn_rand_mod(k, n);
+ ep8_rand(p);
+ ep8_mul_pre_basic(t, p);
+ BENCH_ADD(ep8_mul_fix_basic(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_BASIC; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == COMBS || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_COMBS; i++) {
+ ep8_new(t[i]);
+ }
+ BENCH_RUN("ep8_mul_pre_combs") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_pre_combs(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_mul_fix_combs") {
+ bn_rand_mod(k, n);
+ ep8_rand(p);
+ ep8_mul_pre_combs(t, p);
+ BENCH_ADD(ep8_mul_fix_combs(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_COMBS; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == COMBD || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_COMBD; i++) {
+ ep8_new(t[i]);
+ }
+ BENCH_RUN("ep8_mul_pre_combd") {
+ BENCH_ADD(ep8_mul_pre_combd(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_mul_fix_combd") {
+ bn_rand_mod(k, n);
+ ep8_mul_pre_combd(t, p);
+ BENCH_ADD(ep8_mul_fix_combd(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_COMBD; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == LWNAF || !defined(STRIP)
+ for (int i = 0; i < RLC_EPX_TABLE_LWNAF; i++) {
+ ep8_new(t[i]);
+ }
+ BENCH_RUN("ep8_mul_pre_lwnaf") {
+ ep8_rand(p);
+ BENCH_ADD(ep8_mul_pre_lwnaf(t, p));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_mul_fix_lwnaf") {
+ bn_rand_mod(k, n);
+ ep8_rand(p);
+ ep8_mul_pre_lwnaf(t, p);
+ BENCH_ADD(ep8_mul_fix_lwnaf(q, t, k));
+ } BENCH_END;
+ for (int i = 0; i < RLC_EPX_TABLE_LWNAF; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+
+ BENCH_RUN("ep8_mul_sim") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_mul_sim(r, p, k, q, l));
+ } BENCH_END;
+
+#if EP_SIM == BASIC || !defined(STRIP)
+ BENCH_RUN("ep8_mul_sim_basic") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_mul_sim_basic(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+#if EP_SIM == TRICK || !defined(STRIP)
+ BENCH_RUN("ep8_mul_sim_trick") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_mul_sim_trick(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+#if EP_SIM == INTER || !defined(STRIP)
+ BENCH_RUN("ep8_mul_sim_inter") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_mul_sim_inter(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+#if EP_SIM == JOINT || !defined(STRIP)
+ BENCH_RUN("ep8_mul_sim_joint") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep8_rand(p);
+ ep8_rand(q);
+ BENCH_ADD(ep8_mul_sim_joint(r, p, k, q, l));
+ } BENCH_END;
+#endif
+
+ BENCH_RUN("ep8_mul_sim_gen") {
+ bn_rand_mod(k, n);
+ bn_rand_mod(l, n);
+ ep8_rand(q);
+ BENCH_ADD(ep8_mul_sim_gen(r, k, q, l));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_frb") {
+ ep8_rand(q);
+ BENCH_ADD(ep8_frb(r, q, 1));
+ } BENCH_END;
+
+ BENCH_RUN("ep8_map") {
+ uint8_t msg[5];
+ rand_bytes(msg, 5);
+ BENCH_ADD(ep8_map(p, msg, 5));
+ } BENCH_END;
+
+ ep8_free(p);
+ ep8_free(q);
+ ep8_free(r);
+ bn_free(k);
+ bn_free(n);
+ bn_free(l);
+ fp8_free(s);
+}
+
int main(void) {
- int r0, r1;
+ int r0, r1, r2, r3;
if (core_init() != RLC_OK) {
core_clean();
return 1;
@@ -1086,7 +2102,18 @@ int main(void) {
arith2();
}
- if ((r1 = ep4_curve_is_twist())) {
+ if ((r1 = ep3_curve_is_twist())) {
+ ep_param_print();
+
+ util_banner("Utilities:", 1);
+ memory3();
+ util3();
+
+ util_banner("Arithmetic:", 1);
+ arith3();
+ }
+
+ if ((r2 = ep4_curve_is_twist())) {
ep_param_print();
util_banner("Utilities:", 1);
@@ -1097,7 +2124,18 @@ int main(void) {
arith4();
}
- if (!r0 && !r1) {
+ if ((r3 = ep8_curve_is_twist())) {
+ ep_param_print();
+
+ util_banner("Utilities:", 1);
+ memory8();
+ util8();
+
+ util_banner("Arithmetic:", 1);
+ arith8();
+ }
+
+ if (!r0 && !r2 && !r1 && !r3) {
RLC_THROW(ERR_NO_CURVE);
core_clean();
return 0;
diff --git a/bench/bench_fp.c b/bench/bench_fp.c
index 39204de2f..ea3f576c2 100644
--- a/bench/bench_fp.c
+++ b/bench/bench_fp.c
@@ -81,6 +81,12 @@ static void util(void) {
}
BENCH_END;
+ BENCH_RUN("fp_is_even") {
+ fp_rand(a);
+ BENCH_ADD(fp_is_even(a));
+ }
+ BENCH_END;
+
BENCH_RUN("fp_get_bit") {
fp_rand(a);
BENCH_ADD(fp_get_bit(a, RLC_DIG / 2));
@@ -626,6 +632,19 @@ static void arith(void) {
BENCH_END;
#endif
+ BENCH_RUN("fp_exp_dig") {
+ fp_rand(a);
+ bn_rand(e, RLC_POS, RLC_DIG);
+ BENCH_ADD(fp_exp_dig(b, a, e->dp[0]));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp_is_sqr") {
+ fp_rand(a);
+ BENCH_ADD(fp_is_sqr(a));
+ }
+ BENCH_END;
+
BENCH_RUN("fp_srt") {
fp_rand(a);
fp_sqr(a, a);
@@ -633,6 +652,20 @@ static void arith(void) {
}
BENCH_END;
+ BENCH_RUN("fp_is_cub") {
+ fp_rand(a);
+ BENCH_ADD(fp_is_cub(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp_crt") {
+ fp_rand(a);
+ fp_sqr(b, a);
+ fp_mul(b, b, a);
+ BENCH_ADD(fp_crt(c, a));
+ }
+ BENCH_END;
+
BENCH_RUN("fp_prime_conv") {
bn_rand(e, RLC_POS, RLC_FP_BITS);
BENCH_ADD(fp_prime_conv(a, e));
diff --git a/bench/bench_fpx.c b/bench/bench_fpx.c
index 1ee0c9830..18ad1e8e3 100644
--- a/bench/bench_fpx.c
+++ b/bench/bench_fpx.c
@@ -380,13 +380,18 @@ static void arith2(void) {
BENCH_RUN("fp2_mul_frb") {
fp2_rand(a);
- BENCH_ADD(fp2_mul_frb(c, a, 1, 0));
+ BENCH_ADD(fp2_mul_frb(c, a, 1, 1));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp2_is_sqr") {
+ fp2_rand(a);
+ BENCH_ADD(fp2_is_sqr(a));
}
BENCH_END;
BENCH_RUN("fp2_srt") {
fp2_rand(a);
- fp2_sqr(a, a);
BENCH_ADD(fp2_srt(c, a));
}
BENCH_END;
@@ -694,6 +699,18 @@ static void arith3(void) {
}
BENCH_END;
+ BENCH_RUN("fp3_is_sqr") {
+ fp3_rand(a);
+ BENCH_ADD(fp3_is_sqr(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp3_srt") {
+ fp2_rand(a);
+ BENCH_ADD(fp3_srt(c, a));
+ }
+ BENCH_END;
+
fp3_free(a);
fp3_free(b);
fp3_free(c);
@@ -909,6 +926,12 @@ static void arith4(void) {
}
BENCH_END;
+ BENCH_RUN("fp4_is_sqr") {
+ fp4_rand(a);
+ BENCH_ADD(fp4_is_sqr(a));
+ }
+ BENCH_END;
+
BENCH_RUN("fp4_srt") {
fp4_rand(a);
fp4_sqr(a, a);
@@ -1405,6 +1428,19 @@ static void arith8(void) {
}
BENCH_END;
+ BENCH_RUN("fp8_is_sqr") {
+ fp8_rand(a);
+ BENCH_ADD(fp8_is_sqr(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp8_srt") {
+ fp8_rand(a);
+ fp8_sqr(a, a);
+ BENCH_ADD(fp8_srt(c, a));
+ }
+ BENCH_END;
+
fp8_free(a);
fp8_free(b);
fp8_free(c);
@@ -2014,6 +2050,230 @@ static void arith12(void) {
bn_free(e);
}
+static void memory16(void) {
+ fp16_t a[BENCH];
+
+ BENCH_FEW("fp16_null", fp16_null(a[i]), 1);
+
+ BENCH_FEW("fp16_new", fp16_new(a[i]), 1);
+ for (int i = 0; i < BENCH; i++) {
+ fp16_free(a[i]);
+ }
+
+ for (int i = 0; i < BENCH; i++) {
+ fp16_new(a[i]);
+ }
+ BENCH_FEW("fp16_free", fp16_free(a[i]), 1);
+
+ (void)a;
+}
+
+static void util16(void) {
+ fp16_t a, b;
+
+ fp16_null(a);
+ fp16_null(b);
+
+ fp16_new(a);
+ fp16_new(b);
+
+ BENCH_RUN("fp16_copy") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_copy(b, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_neg") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_neg(b, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_zero") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_zero(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_is_zero") {
+ fp16_rand(a);
+ BENCH_ADD((void)fp16_is_zero(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_set_dig (1)") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_set_dig(a, 1));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_set_dig") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_set_dig(a, a[0][0][0][0][0]));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_rand") {
+ BENCH_ADD(fp16_rand(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_cmp") {
+ fp16_rand(a);
+ fp16_rand(b);
+ BENCH_ADD(fp16_cmp(b, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_cmp_dig") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_cmp_dig(a, (dig_t)0));
+ }
+ BENCH_END;
+
+ fp16_free(a);
+ fp16_free(b);
+}
+
+static void arith16(void) {
+ fp16_t a, b, c;
+ bn_t e;
+
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+ bn_new(e);
+
+ BENCH_RUN("fp16_add") {
+ fp16_rand(a);
+ fp16_rand(b);
+ BENCH_ADD(fp16_add(c, a, b));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_sub") {
+ fp16_rand(a);
+ fp16_rand(b);
+ BENCH_ADD(fp16_sub(c, a, b));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_mul") {
+ fp16_rand(a);
+ fp16_rand(b);
+ BENCH_ADD(fp16_mul(c, a, b));
+ }
+ BENCH_END;
+
+#if FPX_RDC == BASIC || !defined(STRIP)
+ BENCH_RUN("fp16_mul_basic") {
+ fp16_rand(a);
+ fp16_rand(b);
+ BENCH_ADD(fp16_mul_basic(c, a, b));
+ }
+ BENCH_END;
+#endif
+
+#if FPX_RDC == LAZYR || !defined(STRIP)
+ BENCH_RUN("fp16_mul_lazyr") {
+ fp16_rand(a);
+ fp16_rand(b);
+ BENCH_ADD(fp16_mul_lazyr(c, a, b));
+ }
+ BENCH_END;
+#endif
+
+ BENCH_RUN("fp16_sqr") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_sqr(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_sqr_cyc") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_sqr_cyc(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_test_cyc") {
+ fp16_rand(a);
+ fp16_conv_cyc(a, a);
+ BENCH_ADD(fp16_test_cyc(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_conv_cyc") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_conv_cyc(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_conv_cyc") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_conv_cyc(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_inv") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_inv(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_inv_cyc") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_inv_cyc(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_exp") {
+ fp16_rand(a);
+ bn_rand(e, RLC_POS, RLC_FP_BITS);
+ BENCH_ADD(fp16_exp(c, a, e));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_exp (cyc)") {
+ fp16_rand(a);
+ fp16_conv_cyc(a, a);
+ bn_rand(e, RLC_POS, RLC_FP_BITS);
+ BENCH_ADD(fp16_exp(c, a, e));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_exp_cyc (param or sparse)") {
+ fp16_rand(a);
+ fp16_conv_cyc(a, a);
+ bn_zero(e);
+ fp_prime_get_par(e);
+ if (bn_is_zero(e)) {
+ bn_set_2b(e, RLC_FP_BITS - 1);
+ bn_set_bit(e, RLC_FP_BITS / 2, 1);
+ bn_set_bit(e, 0, 1);
+ }
+ BENCH_ADD(fp16_exp_cyc(c, a, e));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_exp_dig") {
+ fp16_rand(a);
+ bn_rand(e, RLC_POS, RLC_DIG);
+ BENCH_ADD(fp16_exp_dig(c, a, e->dp[0]));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp16_frb") {
+ fp16_rand(a);
+ BENCH_ADD(fp16_frb(c, a, 1));
+ }
+ BENCH_END;
+
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ bn_free(e);
+}
+
static void memory18(void) {
fp18_t a[BENCH];
@@ -2034,6 +2294,7 @@ static void memory18(void) {
static void util18(void) {
fp18_t a, b;
+ uint8_t bin[18 * RLC_FP_BYTES];
fp18_null(a);
fp18_null(b);
@@ -2082,6 +2343,47 @@ static void util18(void) {
}
BENCH_END;
+ BENCH_RUN("fp18_size_bin (0)") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_size_bin(a, 0));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_size_bin (1)") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ BENCH_ADD(fp18_size_bin(a, 1));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_write_bin (0)") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_write_bin(bin, sizeof(bin), a, 0));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_write_bin (1)") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ BENCH_ADD(fp18_write_bin(bin, 8 * RLC_FP_BYTES, a, 1));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_read_bin (0)") {
+ fp18_rand(a);
+ fp18_write_bin(bin, sizeof(bin), a, 0);
+ BENCH_ADD(fp18_read_bin(a, bin, sizeof(bin)));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_read_bin (1)") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ fp18_write_bin(bin, fp18_size_bin(a, 1), a, 1);
+ BENCH_ADD(fp18_read_bin(a, bin, 8 * RLC_FP_BYTES));
+ }
+ BENCH_END;
+
BENCH_RUN("fp18_cmp") {
fp18_rand(a);
fp18_rand(b);
@@ -2100,12 +2402,14 @@ static void util18(void) {
}
static void arith18(void) {
- fp18_t a, b, c;
+ fp18_t a, b, c, d[2];
bn_t e;
fp18_new(a);
fp18_new(b);
fp18_new(c);
+ fp18_new(d[0]);
+ fp18_new(d[1]);
bn_new(e);
BENCH_RUN("fp18_add") {
@@ -2147,51 +2451,200 @@ static void arith18(void) {
BENCH_END;
#endif
+ BENCH_RUN("fp18_mul_dxs") {
+ fp18_rand(a);
+ fp18_rand(b);
+ BENCH_ADD(fp18_mul_dxs(c, a, b));
+ }
+ BENCH_END;
+
+#if FPX_RDC == BASIC || !defined(STRIP)
+ BENCH_RUN("fp18_mul_dxs_basic") {
+ fp18_rand(a);
+ fp18_rand(b);
+ BENCH_ADD(fp18_mul_dxs_basic(c, a, b));
+ }
+ BENCH_END;
+#endif
+
+#if FPX_RDC == LAZYR || !defined(STRIP)
+ BENCH_RUN("fp18_mul_dxs_lazyr") {
+ fp18_rand(a);
+ fp18_rand(b);
+ BENCH_ADD(fp18_mul_dxs_lazyr(c, a, b));
+ }
+ BENCH_END;
+#endif
+
BENCH_RUN("fp18_sqr") {
fp18_rand(a);
BENCH_ADD(fp18_sqr(c, a));
}
BENCH_END;
+ BENCH_RUN("fp18_sqr_cyc") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_sqr_cyc(c, a));
+ }
+ BENCH_END;
+
+#if FPX_RDC == BASIC || !defined(STRIP)
+ BENCH_RUN("fp18_sqr_cyc_basic") {
+ fp18_rand(a);
+ fp18_rand(b);
+ BENCH_ADD(fp18_sqr_cyc_basic(c, a));
+ }
+ BENCH_END;
+#endif
+
+#if FPX_RDC == LAZYR || !defined(STRIP)
+ BENCH_RUN("fp18_sqr_cyc_lazyr") {
+ fp18_rand(a);
+ fp18_rand(b);
+ BENCH_ADD(fp18_sqr_cyc_lazyr(c, a));
+ }
+ BENCH_END;
+#endif
+
+ BENCH_RUN("fp18_sqr_pck") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_sqr_pck(c, a));
+ }
+ BENCH_END;
+
#if FPX_RDC == BASIC || !defined(STRIP)
- BENCH_RUN("fp18_sqr_basic") {
+ BENCH_RUN("fp18_sqr_pck_basic") {
fp18_rand(a);
- BENCH_ADD(fp18_sqr_basic(c, a));
+ fp18_rand(b);
+ BENCH_ADD(fp18_sqr_pck_basic(c, a));
}
BENCH_END;
#endif
#if FPX_RDC == LAZYR || !defined(STRIP)
- BENCH_RUN("fp18_sqr_lazyr") {
+ BENCH_RUN("fp18_sqr_pck_lazyr") {
fp18_rand(a);
- BENCH_ADD(fp18_sqr_lazyr(c, a));
+ fp18_rand(b);
+ BENCH_ADD(fp18_sqr_pck_lazyr(c, a));
}
BENCH_END;
#endif
+ BENCH_RUN("fp18_test_cyc") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ BENCH_ADD(fp18_test_cyc(a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_conv_cyc") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_conv_cyc(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_back_cyc") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_back_cyc(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_back_cyc (2)") {
+ fp18_rand(d[0]);
+ fp18_rand(d[1]);
+ BENCH_ADD(fp18_back_cyc_sim(d, d, 2));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_conv_cyc") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_conv_cyc(c, a));
+ }
+ BENCH_END;
+
BENCH_RUN("fp18_inv") {
fp18_rand(a);
BENCH_ADD(fp18_inv(c, a));
}
BENCH_END;
+ BENCH_RUN("fp18_inv_cyc") {
+ fp18_rand(a);
+ BENCH_ADD(fp18_inv_cyc(c, a));
+ }
+ BENCH_END;
+
BENCH_RUN("fp18_exp") {
fp18_rand(a);
- e->used = RLC_FP_DIGS;
- dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
+ bn_rand(e, RLC_POS, RLC_FP_BITS);
BENCH_ADD(fp18_exp(c, a, e));
}
BENCH_END;
+ BENCH_RUN("fp18_exp (cyc)") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ bn_rand(e, RLC_POS, RLC_FP_BITS);
+ BENCH_ADD(fp18_exp(c, a, e));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_exp_cyc (param or sparse)") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ bn_zero(e);
+ fp_prime_get_par(e);
+ if (bn_is_zero(e)) {
+ bn_set_2b(e, RLC_FP_BITS - 1);
+ bn_set_bit(e, RLC_FP_BITS / 2, 1);
+ bn_set_bit(e, 0, 1);
+ }
+ BENCH_ADD(fp18_exp_cyc(c, a, e));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_exp_cyc_sps (param)") {
+ const int *k;
+ int l;
+ k = fp_prime_get_par_sps(&l);
+ fp18_rand(a);
+ BENCH_ADD(fp18_exp_cyc_sps(c, a, k, l, RLC_POS));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_exp_dig") {
+ fp18_rand(a);
+ bn_rand(e, RLC_POS, RLC_DIG);
+ BENCH_ADD(fp18_exp_dig(c, a, e->dp[0]));
+ }
+ BENCH_END;
+
BENCH_RUN("fp18_frb") {
fp18_rand(a);
BENCH_ADD(fp18_frb(c, a, 1));
}
BENCH_END;
+ BENCH_RUN("fp18_pck") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ BENCH_ADD(fp18_pck(c, a));
+ }
+ BENCH_END;
+
+ BENCH_RUN("fp18_upk") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ fp18_pck(a, a);
+ BENCH_ADD(fp18_upk(c, a));
+ }
+ BENCH_END;
+
fp18_free(a);
fp18_free(b);
fp18_free(c);
+ fp18_free(d[0]);
+ fp18_free(d[1]);
bn_free(e);
}
@@ -3293,7 +3746,7 @@ int main(void) {
arith9();
}
- if (fp_prime_get_qnr() && (ep_param_embed() >= 12)) {
+ if (fp_prime_get_qnr() && fp_prime_get_cnr() && (ep_param_embed() >= 12)) {
util_banner("Dodecic extension:", 0);
util_banner("Utilities:", 1);
memory12();
@@ -3302,6 +3755,16 @@ int main(void) {
arith12();
}
+ if (fp_prime_get_qnr() && (ep_param_embed() >= 16)) {
+ util_banner("Sextadecic extension:", 0);
+ util_banner("Utilities:", 1);
+ memory16();
+ util16();
+
+ util_banner("Arithmetic:", 1);
+ arith16();
+ }
+
if (fp_prime_get_cnr() && (ep_param_embed() >= 18)) {
util_banner("Octdecic extension:", 0);
util_banner("Utilities:", 1);
diff --git a/bench/bench_pc.c b/bench/bench_pc.c
index cb5bebf45..b161cb91a 100755
--- a/bench/bench_pc.c
+++ b/bench/bench_pc.c
@@ -303,7 +303,7 @@ static void memory2(void) {
static void util2(void) {
g2_t p, q;
- uint8_t bin[8 * RLC_PC_BYTES + 1];
+ uint8_t bin[16 * RLC_PC_BYTES + 1];
int l;
g2_null(p);
@@ -519,13 +519,11 @@ static void arith2(void) {
}
BENCH_END;
-#if FP_PRIME != 509
BENCH_RUN("g2_map") {
uint8_t msg[5];
rand_bytes(msg, 5);
BENCH_ADD(g2_map(p, msg, 5));
} BENCH_END;
-#endif
g2_free(p);
g2_free(q);
@@ -557,7 +555,7 @@ static void memory(void) {
static void util(void) {
gt_t a, b;
- uint8_t bin[24 * RLC_PC_BYTES];
+ uint8_t bin[48 * RLC_PC_BYTES];
int l;
gt_null(a);
@@ -602,11 +600,6 @@ static void util(void) {
}
BENCH_END;
- BENCH_RUN("gt_size_bin (0)") {
- gt_rand(a);
- BENCH_ADD(gt_size_bin(a, 0));
- } BENCH_END;
-
BENCH_RUN("gt_write_bin (0)") {
gt_rand(a);
l = gt_size_bin(a, 0);
@@ -621,11 +614,6 @@ static void util(void) {
} BENCH_END;
if (ep_param_embed() == 12) {
- BENCH_RUN("gt_size_bin (1)") {
- gt_rand(a);
- BENCH_ADD(gt_size_bin(a, 1));
- } BENCH_END;
-
BENCH_RUN("gt_write_bin (1)") {
gt_rand(a);
l = gt_size_bin(a, 1);
diff --git a/bench/bench_pp.c b/bench/bench_pp.c
index 01bb27e77..47b55c2d5 100644
--- a/bench/bench_pp.c
+++ b/bench/bench_pp.c
@@ -550,83 +550,214 @@ static void pairing12(void) {
}
}
+static void pairing24(void) {
+ bn_t k, n, l;
+ ep4_t p[2], r;
+ ep_t q[2];
+ fp24_t e;
+ int j;
+
+ bn_null(k);
+ bn_null(n);
+ bn_null(l);
+ ep4_null(r);
+ fp24_null(e);
+
+ bn_new(k);
+ bn_new(n);
+ bn_new(l);
+ ep4_new(r);
+ fp24_new(e);
+
+ for (j = 0; j < 2; j++) {
+ ep4_null(p[j]);
+ ep_null(q[j]);
+ ep4_new(p[j]);
+ ep_new(q[j]);
+ }
+
+ ep4_curve_get_ord(n);
+
+ BENCH_RUN("pp_add_k24") {
+ ep4_rand(p[0]);
+ ep4_dbl(r, p[0]);
+ ep4_norm(r, r);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_add_k24(e, r, p[0], q[0]));
+ }
+ BENCH_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ BENCH_RUN("pp_add_k24_basic") {
+ ep4_rand(p[0]);
+ ep4_dbl(r, p[0]);
+ ep4_norm(r, r);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_add_k24_basic(e, r, p[0], q[0]));
+ }
+ BENCH_END;
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+
+ BENCH_RUN("pp_add_k24_projc") {
+ ep4_rand(p[0]);
+ ep4_dbl(r, p[0]);
+ ep4_norm(r, r);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_add_k24_projc(e, r, p[0], q[0]));
+ }
+ BENCH_END;
+
+#endif
+
+ BENCH_RUN("pp_dbl_k24") {
+ ep4_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_dbl_k24(e, p[0], p[0], q[0]));
+ }
+ BENCH_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ BENCH_RUN("pp_dbl_k24_basic") {
+ ep4_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_dbl_k24_basic(e, p[0], p[0], q[0]));
+ }
+ BENCH_END;
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+
+ BENCH_RUN("pp_dbl_k24_projc") {
+ ep4_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_dbl_k24_projc(e, p[0], p[0], q[0]));
+ }
+ BENCH_END;
+
+#endif
+
+ BENCH_RUN("pp_exp_k24") {
+ fp24_rand(e);
+ BENCH_ADD(pp_exp_k24(e, e));
+ }
+ BENCH_END;
+
+ BENCH_RUN("pp_map_k24") {
+ ep4_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_map_k24(e, q[0], p[0]));
+ }
+ BENCH_END;
+
+ BENCH_RUN("pp_map_sim_k24 (2)") {
+ ep4_rand(p[0]);
+ ep_rand(q[0]);
+ ep4_rand(p[1]);
+ ep_rand(q[1]);
+ BENCH_ADD(pp_map_sim_k24(e, q, p, 2));
+ }
+ BENCH_END;
+
+ bn_free(k);
+ bn_free(n);
+ bn_free(l);
+ fp24_free(e);
+ ep4_free(r);
+ for (j = 0; j < 2; j++) {
+ ep4_free(p[j]);
+ ep_free(q[j]);
+ }
+}
+
static void pairing48(void) {
- ep_t p;
- fp8_t qx, qy, qz;
+ bn_t k, n, l;
+ ep8_t p[2], r;
+ ep_t q[2];
fp48_t e;
+ int j;
- ep_null(p);
- fp8_null(qx);
- fp8_null(qy);
- fp8_null(qz);
+ bn_null(k);
+ bn_null(n);
+ bn_null(l);
+ ep8_null(r);
fp48_null(e);
- ep_new(p);
- fp8_new(qx);
- fp8_new(qy);
- fp8_new(qz);
+ bn_new(k);
+ bn_new(n);
+ bn_new(l);
+ ep8_new(r);
fp48_new(e);
+ for (j = 0; j < 2; j++) {
+ ep8_null(p[j]);
+ ep_null(q[j]);
+ ep8_new(p[j]);
+ ep_new(q[j]);
+ }
+
+ ep8_curve_get_ord(n);
+
BENCH_RUN("pp_add_k48") {
- fp8_rand(qx);
- fp8_rand(qy);
- fp8_rand(qz);
- ep_rand(p);
- BENCH_ADD(pp_add_k48(e, qx, qy, qz, qy, qx, p));
+ ep8_rand(p[0]);
+ ep8_dbl(r, p[0]);
+ ep8_norm(r, r);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_add_k48(e, r, p[0], q[0]));
}
BENCH_END;
#if EP_ADD == BASIC || !defined(STRIP)
BENCH_RUN("pp_add_k48_basic") {
- fp8_rand(qx);
- fp8_rand(qy);
- fp8_rand(qz);
- ep_rand(p);
- BENCH_ADD(pp_add_k48_basic(e, qx, qy, qy, qx, p));
+ ep8_rand(p[0]);
+ ep8_dbl(r, p[0]);
+ ep8_norm(r, r);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_add_k48_basic(e, r, p[0], q[0]));
}
BENCH_END;
#endif
#if EP_ADD == PROJC || !defined(STRIP)
+
BENCH_RUN("pp_add_k48_projc") {
- fp8_rand(qx);
- fp8_rand(qy);
- fp8_rand(qz);
- ep_rand(p);
- BENCH_ADD(pp_add_k48_projc(e, qx, qy, qz, qx, qy, p));
+ ep8_rand(p[0]);
+ ep8_dbl(r, p[0]);
+ ep8_norm(r, r);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_add_k48_projc(e, r, p[0], q[0]));
}
BENCH_END;
+
#endif
BENCH_RUN("pp_dbl_k48") {
- fp8_rand(qx);
- fp8_rand(qy);
- fp8_rand(qz);
- ep_rand(p);
- BENCH_ADD(pp_dbl_k48(e, qx, qy, qz, p));
+ ep8_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_dbl_k48(e, p[0], p[0], q[0]));
}
BENCH_END;
- #if EP_ADD == BASIC || !defined(STRIP)
- BENCH_RUN("pp_dbl_k48_basic") {
- fp8_rand(qx);
- fp8_rand(qy);
- ep_rand(p);
- BENCH_ADD(pp_dbl_k48_basic(e, qx, qy, p));
- }
- BENCH_END;
- #endif
+#if EP_ADD == BASIC || !defined(STRIP)
+ BENCH_RUN("pp_dbl_k48_basic") {
+ ep8_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_dbl_k48_basic(e, p[0], p[0], q[0]));
+ }
+ BENCH_END;
+#endif
- #if EP_ADD == PROJC || !defined(STRIP)
- BENCH_RUN("pp_dbl_k48_projc") {
- fp8_rand(qx);
- fp8_rand(qy);
- fp8_rand(qz);
- ep_rand(p);
- BENCH_ADD(pp_dbl_k48_projc(e, qx, qy, qz, p));
- }
- BENCH_END;
- #endif
+#if EP_ADD == PROJC || !defined(STRIP)
+
+ BENCH_RUN("pp_dbl_k48_projc") {
+ ep8_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_dbl_k48_projc(e, p[0], p[0], q[0]));
+ }
+ BENCH_END;
+
+#endif
BENCH_RUN("pp_exp_k48") {
fp48_rand(e);
@@ -635,19 +766,30 @@ static void pairing48(void) {
BENCH_END;
BENCH_RUN("pp_map_k48") {
- fp8_rand(qx);
- fp8_rand(qy);
- fp8_rand(qz);
- ep_rand(p);
- BENCH_ADD(pp_map_k48(e, p, qx, qy));
+ ep8_rand(p[0]);
+ ep_rand(q[0]);
+ BENCH_ADD(pp_map_k48(e, q[0], p[0]));
}
BENCH_END;
- ep_free(p);
- fp8_free(qx);
- fp8_free(qy);
- fp8_free(qz);
+ BENCH_RUN("pp_map_sim_k48 (2)") {
+ ep8_rand(p[0]);
+ ep_rand(q[0]);
+ ep8_rand(p[1]);
+ ep_rand(q[1]);
+ BENCH_ADD(pp_map_sim_k48(e, q, p, 2));
+ }
+ BENCH_END;
+
+ bn_free(k);
+ bn_free(n);
+ bn_free(l);
fp48_free(e);
+ ep8_free(r);
+ for (j = 0; j < 2; j++) {
+ ep8_free(p[j]);
+ ep_free(q[j]);
+ }
}
static void pairing54(void) {
@@ -781,6 +923,10 @@ int main(void) {
pairing12();
}
+ if (ep_param_embed() == 48) {
+ pairing24();
+ }
+
if (ep_param_embed() == 48) {
pairing48();
}
diff --git a/cmake/ep.cmake b/cmake/ep.cmake
index d0cd6deb7..14a36921f 100644
--- a/cmake/ep.cmake
+++ b/cmake/ep.cmake
@@ -11,7 +11,7 @@ message(" EP_CTMAP=[off|on] Use contant-time SSWU and isogeny map for hashi
message(" EP_PRECO=[off|on] Build precomputation table for generator.")
message(" RLC_DEPTH=w Width w in [2,8] of precomputation table for fixed point methods.")
-message(" ** Available prime elliptic curve methods (default = PROJC;LWNAF;COMBS;INTER):\n")
+message(" ** Available prime elliptic curve methods (default = PROJC;LWNAF;COMBS;INTER;SSWUM):\n")
message(" Point representation:")
message(" EP_METHD=BASIC Affine coordinates.")
@@ -19,6 +19,7 @@ message(" EP_METHD=PROJC Homogeneous projective coordinates (complete fo
message(" EP_METHD=JACOB Jacobian projective coordinates.\n")
message(" Variable-base scalar multiplication:")
+message(" EB_METHD=BASIC Binary double-and-add method.")
message(" EP_METHD=SLIDE Sliding window method.")
message(" EP_METHD=MONTY Montgomery ladder method.")
message(" EP_METHD=LWNAF Left-to-right window NAF method.")
@@ -36,6 +37,11 @@ message(" EP_METHD=TRICK Shamir's trick for simultaneous multiplication.
message(" EP_METHD=INTER Interleaving of window NAFs (GLV for Koblitz curves).")
message(" EP_METHD=JOINT Joint sparse form.\n")
+message(" Hash to point on the elliptic curve:")
+message(" EP_METHD=BASIC Hash to x-coordinate and increment.")
+message(" EP_METHD=SSWUM Simplified Shallue-van de Woestijne-Ulas method.")
+message(" EP_METHD=SWIFT SwiftEC hashing method.\n")
+
option(EP_PLAIN "Support for ordinary curves without endomorphisms" on)
option(EP_SUPER "Support for supersingular curves" on)
option(EP_MIXED "Use mixed coordinates" on)
@@ -45,15 +51,16 @@ option(EP_CTMAP "Use contant-time SSWU and isogeny map for hashing" on)
# Choose the arithmetic methods.
if (NOT EP_METHD)
- set(EP_METHD "PROJC;LWNAF;COMBS;INTER")
+ set(EP_METHD "PROJC;LWNAF;COMBS;INTER;SSWUM")
endif(NOT EP_METHD)
list(LENGTH EP_METHD EP_LEN)
-if (EP_LEN LESS 4)
+if (EP_LEN LESS 5)
message(FATAL_ERROR "Incomplete EP_METHD specification: ${EP_METHD}")
-endif(EP_LEN LESS 4)
+endif(EP_LEN LESS 5)
list(GET EP_METHD 0 EP_ADD)
list(GET EP_METHD 1 EP_MUL)
list(GET EP_METHD 2 EP_FIX)
list(GET EP_METHD 3 EP_SIM)
+list(GET EP_METHD 4 EP_MAP)
set(EP_METHD ${EP_METHD} CACHE STRING "Method for prime elliptic curve arithmetic.")
diff --git a/cmake/fp.cmake b/cmake/fp.cmake
index 4636a948a..44648fb2c 100644
--- a/cmake/fp.cmake
+++ b/cmake/fp.cmake
@@ -39,7 +39,6 @@ message(" FP_METHD=LOWER Pass inversion to the lower level.\n")
message(" Legendre symbol:")
message(" FP_METHD=BASIC Computation by Fermat's Little Theorem.")
-message(" FP_METHD=BINAR Binary algorithm.")
message(" FP_METHD=DIVST Constant-time method by division steps.")
message(" FP_METHD=JMPDS Constant-time method by jump division steps.")
message(" FP_METHD=LOWER Pass call to the lower level.\n")
diff --git a/demo/cert-input/Makefile b/demo/cert-input/Makefile
index 25f24241c..acad9b177 100644
--- a/demo/cert-input/Makefile
+++ b/demo/cert-input/Makefile
@@ -7,7 +7,7 @@ all: lib
lib:
mkdir -p target
- cd target; ${RELIC_ROOT}/../preset/x64-pbc-bls12-381.sh ${RELIC_ROOT}/../; cmake -DEP_METHD='JACOB;LWNAF;COMBS;INTER' .; make
+ cd target; ${RELIC_ROOT}/../preset/x64-pbc-bls12-381.sh ${RELIC_ROOT}/../; cmake -DEP_METHD='JACOB;LWNAF;COMBS;INTER;SSWUM' .; make
clean:
rm -rf target *.o test-bench
diff --git a/demo/ers-etrs/Makefile b/demo/ers-etrs/Makefile
index 16d60bad2..af1dca7e7 100644
--- a/demo/ers-etrs/Makefile
+++ b/demo/ers-etrs/Makefile
@@ -7,7 +7,7 @@ all: lib
lib:
mkdir -p target
- cd target; ${RELIC_ROOT}/../preset/x64-ecc-128.sh ${RELIC_ROOT}/../; cmake -DED_METHD='EXTND;LWNAF;COMBS;INTER' -DEP_ENDOM=off -DBN_METHD='COMBA;COMBA;MONTY;SLIDE;LEHME;BASIC' -DWITH="MD;BC;DV;BN;FP;EP;ED;EC;CP" .; make
+ cd target; ${RELIC_ROOT}/../preset/x64-ecc-128.sh ${RELIC_ROOT}/../; cmake -DEP_METHD='JACOB;LWNAF;COMBS;INTER;SSWUM' -DEP_ENDOM=off -DBN_METHD=' COMBA;COMBA;MONTY;SLIDE;LEHME;BASIC' -DWITH="MD;BC;DV;BN;FP;EP;ED;EC;CP" .; make
clean:
rm -rf target *.o test-bench
diff --git a/demo/psi-client-server/Makefile b/demo/psi-client-server/Makefile
index 1b3fc7f1a..4c1ea6c27 100644
--- a/demo/psi-client-server/Makefile
+++ b/demo/psi-client-server/Makefile
@@ -9,7 +9,7 @@ all: lib
lib:
mkdir -p target
- cd target; ${RELIC_ROOT}/../preset/x64-pbc-bls12-381.sh ${RELIC_ROOT}/../; cmake -DTIMER=HREAL -DBN_PRECI=3072 -DBENCH=1 -DMULTI=PTHREAD -DEP_METHD='JACOB;LWNAF;COMBS;INTER' .; make
+ cd target; ${RELIC_ROOT}/../preset/x64-pbc-bls12-381.sh ${RELIC_ROOT}/../; cmake -DTIMER=HREAL -DBN_PRECI=3072 -DBENCH=1 -DMULTI=PTHREAD -DEP_METHD='JACOB;LWNAF;COMBS;INTER;SSWUM' .; make
clean:
rm -rf target *.o test-bench receiver sender
diff --git a/demo/public-stats/Makefile b/demo/public-stats/Makefile
index f52bd9ab9..0fcc9bc36 100644
--- a/demo/public-stats/Makefile
+++ b/demo/public-stats/Makefile
@@ -8,7 +8,7 @@ all: lib data.csv
lib:
mkdir -p target
- cd target; ${RELIC_ROOT}/../preset/x64-pbc-bls12-381.sh ${RELIC_ROOT}/../; cmake -DEP_METHD='JACOB;LWNAF;COMBS;INTER' .; make
+ cd target; ${RELIC_ROOT}/../preset/x64-pbc-bls12-381.sh ${RELIC_ROOT}/../; cmake -DEP_METHD='JACOB;LWNAF;COMBS;INTER;SSWUM' .; make
data.csv:
wget -c https://raw.githubusercontent.com/TheEconomist/covid-19-excess-deaths-tracker/master/source-data/spain/archive/spain_total_source_2020_04_13.csv
diff --git a/demo/tweedledum/Makefile b/demo/tweedledum/Makefile
index c5e31f030..f7a1fb08c 100644
--- a/demo/tweedledum/Makefile
+++ b/demo/tweedledum/Makefile
@@ -7,7 +7,7 @@ all: lib
lib:
mkdir -p target
- cd target; ${RELIC_ROOT}/../preset/gmp-ecc-tweedledum.sh ${RELIC_ROOT}/../; cmake -DEP_METHD='JACOB;LWNAF;COMBS;INTER' .; make
+ cd target; ${RELIC_ROOT}/../preset/gmp-ecc-tweedledum.sh ${RELIC_ROOT}/../; cmake -DEP_METHD='JACOB;LWNAF;COMBS;INTER;SSWUM' .; make
clean:
rm -rf target *.o main
diff --git a/include/relic_conf.h.in b/include/relic_conf.h.in
index b865495c8..e11eb7a44 100644
--- a/include/relic_conf.h.in
+++ b/include/relic_conf.h.in
@@ -266,8 +266,6 @@
/** Legendre by Fermat's Little Theorem. */
#define BASIC 1
-/** Binary method. */
-#define BINAR 2
/** Constant-time inversion by Bernstein-Yang division steps. */
#define DIVST 5
/** Constant-time inversion by Bernstein-Yang jump division steps. */
@@ -465,6 +463,15 @@
/** Chosen prime elliptic curve simulteanous point multiplication method. */
#define EP_SIM @EP_SIM@
+/** Basic hash to x-coordinate and increment. */
+#define BASIC 1
+/** (Simplified) Shallue-van de Woestijne-Ulas map. */
+#define SSWUM 2
+/** SwiftEC method. */
+#define SWIFT 3
+/** Chosen prime elliptic curve hashing method. */
+#define EP_MAP @EP_MAP@
+
/** Prime elliptic curve arithmetic method. */
#define EP_METHD "@EP_METHD@"
diff --git a/include/relic_core.h b/include/relic_core.h
index 4b7c92152..5ad5b357f 100644
--- a/include/relic_core.h
+++ b/include/relic_core.h
@@ -232,9 +232,13 @@ typedef struct _ctx_t {
/** Value of constant for divstep-based inversion. */
bn_st inv;
#endif /* FP_INV */
+ /** Square root of unity for square root extraction. */
+ bn_st srt;
+ /** Cube root of unity for square root extraction. */
+ bn_st crt;
/** Prime modulus modulo 8. */
dig_t mod8;
- /** Prime modulus modulo 8. */
+ /** Prime modulus modulo 18. */
dig_t mod18;
/** Value derived from the prime used for modular reduction. */
dig_t u;
@@ -270,7 +274,7 @@ typedef struct _ctx_t {
/** The distinguished non-square used by the mapping function */
fp_st ep_map_u;
/** Precomputed constants for hashing. */
- fp_st ep_map_c[4];
+ fp_st ep_map_c[7];
#ifdef EP_ENDOM
#if EP_MUL == LWNAF || EP_FIX == COMBS || EP_FIX == LWNAF || EP_SIM == INTER || !defined(STRIP)
/** Parameters required by the GLV method. @{ */
@@ -386,6 +390,28 @@ typedef struct _ctx_t {
ep4_st ep4_pre[RLC_EP_TABLE];
/** Array of pointers to the precomputation table. */
ep4_st *ep4_ptr[RLC_EP_TABLE];
+#endif /* EP_PRECO */
+ /** The generator of the elliptic curve. */
+ ep8_t ep8_g;
+ /** The 'a' coefficient of the curve. */
+ fp8_t ep8_a;
+ /** The 'b' coefficient of the curve. */
+ fp8_t ep8_b;
+ /** The order of the group of points in the elliptic curve. */
+ bn_st ep8_r;
+ /** The cofactor of the group order in the elliptic curve. */
+ bn_st ep8_h;
+ /** Optimization identifier for the a-coefficient. */
+ int ep8_opt_a;
+ /** Optimization identifier for the b-coefficient. */
+ int ep8_opt_b;
+ /** Flag that stores if the prime curve is a twist. */
+ int ep8_is_twist;
+#ifdef EP_PRECO
+ /** Precomputation table for generator multiplication.*/
+ ep8_st ep8_pre[RLC_EP_TABLE];
+ /** Array of pointers to the precomputation table. */
+ ep8_st *ep8_ptr[RLC_EP_TABLE];
#endif /* EP_PRECO */
#endif /* WITH_EPX */
@@ -414,19 +440,21 @@ typedef struct _ctx_t {
#endif
#if defined(WITH_FPX) || defined(WITH_PP)
- /** Integer part of the quadratic non-residue. */
+ /** Integer part of the quadratic non-residue in the quadratic extension. */
dis_t qnr2;
/** Constants for computing Frobenius maps in higher extensions. @{ */
fp2_st fp2_p1[5];
- fp2_st fp2_p2[3];
- int frb4;
- fp2_st fp4_p1;
- /** @} */
- /** Constants for computing Frobenius maps in higher extensions. @{ */
+ fp2_st fp2_p2[4];
int frb3[3];
+ /** Integer part of the cubic non-residue in the cubic extension. */
+ dis_t cnr3;
fp_st fp3_p0[2];
fp3_st fp3_p1[5];
fp3_st fp3_p2[2];
+ int frb4;
+ fp2_st fp4_p1;
+ int frb8;
+ fp2_st fp8_p1;
/** @} */
#endif /* WITH_PP */
diff --git a/include/relic_ep.h b/include/relic_ep.h
index 8bbb06bf2..d4a1416d6 100644
--- a/include/relic_ep.h
+++ b/include/relic_ep.h
@@ -53,20 +53,18 @@
* Pairing-friendly elliptic curve identifiers.
*/
enum {
- /** Supersingular curves with embedding degree 1. */
- EP_SS1 = 1,
+ /** Ordinary curves with embedding degree 1. */
+ EP_K1 = 1,
/** Supersingular curves with embedding degree 2. */
EP_SS2,
/** Barreto-Naehrig. */
EP_BN,
- /* Optimal TNFS-secure. */
- EP_OT8,
/* Cocks-Pinch family discovered by Guillevic, Masson and Thomé (GMT). */
EP_GMT8,
/* Barreto-Lynn-Scott family with embedding degree 12. */
EP_B12,
- /* Fotiadis-Martindale family with embedding degree 16. */
- EP_FM16,
+ /* New family from Fotiadis-Martindale family with embedding degree 16. */
+ EP_N16,
/* Kachisa-Schaefer-Scott family with embedding degree 16. */
EP_K16,
/* Fotiadis-Martindale family with embedding degree 18. */
@@ -139,6 +137,8 @@ enum {
B24_P315,
/** Barreto-Lynn-Scott curve with embedding degree 24 (SNARK curve). */
B24_P317,
+ /** Kachisa-Schaefer-Scott with embedding degree 16. */
+ K16_P330,
/** Barreto-Lynn-Scott curve with embedding degree 12 (SNARK curve). */
B12_P377,
/** Barreto-Lynn-Scott curve with embedding degree 12 (ZCash curve). */
@@ -154,7 +154,7 @@ enum {
/** Barreto-Lynn-Scott curve with embedding degree 12. */
B12_P455,
/** Kachisa-Schaefer-Scott with negative x. */
- KSS_P508,
+ K18_P508,
/** Barreto-Lynn-Scott curve with embedding degree 24. */
B24_P509,
/** Optimal TNFS-secure curve with embedding degree 8. */
@@ -173,10 +173,14 @@ enum {
K18_P638,
/** Scott-Guillevic curve with embedding degree 18. */
SG18_P638,
+ /** New family with embeeding degree 16. */
+ N16_P765,
+ /** Kachisa-Schaefer-Scott with embedding degree 16. */
+ K16_P766,
/** 1536-bit supersingular curve. */
SS_P1536,
/** 3072-bit supersingular curve. */
- SS_P3072,
+ K1_P3072,
};
/*============================================================================*/
@@ -455,6 +459,22 @@ typedef iso_st *iso_t;
#define ep_mul_sim(R, P, K, Q, M) ep_mul_sim_joint(R, P, K, Q, M)
#endif
+/**
+ * Hashes a byte string to a prime elliptic point or the right order.
+ * Computes R = H(s).
+ *
+ * @param[out] R - the result.
+ * @param[in] S - the string to hash.
+ * @param[in] L - the string length.
+ */
+#if EP_MAP == BASIC
+#define ep_map(R, S, L) ep_map_basic(R, S, L)
+#elif EP_MAP == SSWUM
+#define ep_map(R, S, L) ep_map_sswum(R, S, L)
+#elif EP_MAP == SWIFT
+#define ep_map(R, S, L) ep_map_swift(R, S, L)
+#endif
+
/*============================================================================*/
/* Function prototypes */
/*============================================================================*/
@@ -620,11 +640,10 @@ iso_t ep_curve_get_iso(void);
* @param[in] g - the generator.
* @param[in] r - the order of the group of points.
* @param[in] h - the cofactor of the group order.
- * @param[in] u - the non-square used for hashing to this curve.
* @param[in] ctmap - true if this curve will use an isogeny for mapping.
*/
void ep_curve_set_plain(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
- const bn_t h, const fp_t u, int ctmap);
+ const bn_t h, int ctmap);
/**
* Configures a supersingular prime elliptic curve by its coefficients and
@@ -635,11 +654,10 @@ void ep_curve_set_plain(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
* @param[in] g - the generator.
* @param[in] r - the order of the group of points.
* @param[in] h - the cofactor of the group order.
- * @param[in] u - the non-square used for hashing to this curve.
* @param[in] ctmap - true if this curve will use an isogeny for mapping.
*/
void ep_curve_set_super(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
- const bn_t h, const fp_t u, int ctmap);
+ const bn_t h, int ctmap);
/**
* Configures a prime elliptic curve with endomorphisms by its coefficients and
@@ -652,11 +670,10 @@ void ep_curve_set_super(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
* @param[in] beta - the constant associated with the endomorphism.
* @param[in] l - the exponent corresponding to the endomorphism.
* @param[in] h - the cofactor of the group order.
- * @param[in] u - the non-square used for hashing to this curve.
* @param[in] ctmap - true if this curve will use an isogeny for mapping.
*/
void ep_curve_set_endom(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
- const bn_t h, const fp_t beta, const bn_t l, const fp_t u, int ctmap);
+ const bn_t h, const fp_t beta, const bn_t l, int ctmap);
/**
* Configures a prime elliptic curve by its parameter identifier.
@@ -1001,6 +1018,15 @@ void ep_mul_gen(ep_t r, const bn_t k);
*/
void ep_mul_dig(ep_t r, const ep_t p, dig_t k);
+/**
+ * Multiplies a point in an elliptic curve over by the curve cofactor.
+ * In short, it takes a point in the curve to the large prime-order subgroup.
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the point to multiply.
+ */
+void ep_mul_cof(ep_t r, const ep_t p);
+
/**
* Builds a precomputation table for multiplying a fixed prime elliptic point
* using the binary method.
@@ -1218,38 +1244,33 @@ void ep_norm(ep_t r, const ep_t p);
void ep_norm_sim(ep_t *r, const ep_t *t, int n);
/**
- * Maps an array of uniformly random bytes to a point in a prime elliptic
- * curve.
- * That array is expected to have a length suitable for two field elements plus
- * extra bytes for uniformity.
- *
+ * Maps a byte array to a point in a prime elliptic curve using the hash and
+ * increment approach.
* @param[out] p - the result.
- * @param[in] uniform_bytes - the array of uniform bytes to map.
+ * @param[in] msg - the byte array to map.
* @param[in] len - the array length in bytes.
*/
-void ep_map_from_field(ep_t p, const uint8_t *uniform_bytes, size_t len);
+void ep_map_basic(ep_t p, const uint8_t *msg, size_t len);
/**
- * Maps a byte array to a point in a prime elliptic curve.
+ * Maps a byte array to a point in a prime elliptic curve using the
+ * (Simplified) Shallue-van de Woestijne-Ulas map.
*
* @param[out] p - the result.
* @param[in] msg - the byte array to map.
* @param[in] len - the array length in bytes.
*/
-void ep_map(ep_t p, const uint8_t *msg, size_t len);
+void ep_map_sswum(ep_t p, const uint8_t *msg, size_t len);
/**
- * Maps a byte array to a point in a prime elliptic curve with specified
- * domain separation tag (aka personalization string).
+ * Maps a byte array to a point in a prime elliptic curve using the
+ * SwiftEC approach.
*
* @param[out] p - the result.
* @param[in] msg - the byte array to map.
* @param[in] len - the array length in bytes.
- * @param[in] dst - the domain separation tag.
- * @param[in] dst_len - the domain separation tag length in bytes.
*/
-void ep_map_dst(ep_t p, const uint8_t *msg, size_t len, const uint8_t *dst,
- size_t dst_len);
+void ep_map_swift(ep_t p, const uint8_t *msg, size_t len);
/**
* Compresses a point.
diff --git a/include/relic_epx.h b/include/relic_epx.h
index 72436397b..17177b4fa 100644
--- a/include/relic_epx.h
+++ b/include/relic_epx.h
@@ -117,7 +117,7 @@ typedef struct {
} ep2_st;
/**
- * Pointer to an elliptic curve point.
+ * Pointer to an elliptic curve point over a quadratic extension field.
*/
#if ALLOC == AUTO
typedef ep2_st ep2_t[1];
@@ -141,7 +141,7 @@ typedef struct {
} ep3_st;
/**
- * Pointer to an elliptic curve point.
+ * Pointer to an elliptic curve point over a cubic extension field.
*/
#if ALLOC == AUTO
typedef ep3_st ep3_t[1];
@@ -150,7 +150,7 @@ typedef ep3_st *ep3_t;
#endif
/**
- * Represents an elliptic curve point over a quartic extension over a prime
+ * Represents an elliptic curve point over a octic extension over a prime
* field.
*/
typedef struct {
@@ -165,7 +165,7 @@ typedef struct {
} ep4_st;
/**
- * Pointer to an elliptic curve point.
+ * Pointer to an elliptic curve point over a octic extension field.
*/
#if ALLOC == AUTO
typedef ep4_st ep4_t[1];
@@ -173,6 +173,30 @@ typedef ep4_st ep4_t[1];
typedef ep4_st *ep4_t;
#endif
+/**
+ * Represents an elliptic curve point over an octic extension over a prime
+ * field.
+ */
+typedef struct {
+ /** The first coordinate. */
+ fp8_t x;
+ /** The second coordinate. */
+ fp8_t y;
+ /** The third coordinate (projective representation). */
+ fp8_t z;
+ /** Flag to indicate the coordinate system of this point. */
+ int coord;
+} ep8_st;
+
+/**
+ * Pointer to an elliptic curve point over an octic extension field.
+ */
+#if ALLOC == AUTO
+typedef ep8_st ep8_t[1];
+#else
+typedef ep8_st *ep8_t;
+#endif
+
/**
* Coefficients of an isogeny map for a curve over a quadratic extension.
*/
@@ -358,6 +382,56 @@ typedef iso2_st *iso2_t;
#define ep4_free(A) /* empty */
#endif
+/**
+ * Initializes a point on an elliptic curve with a null value.
+ *
+ * @param[out] A - the point to initialize.
+ */
+#define ep8_null(A) RLC_NULL(A)
+
+/**
+ * Calls a function to allocate a point on an elliptic curve.
+ *
+ * @param[out] A - the new point.
+ * @throw ERR_NO_MEMORY - if there is no available memory.
+ */
+#if ALLOC == DYNAMIC
+#define ep8_new(A) \
+ A = (ep8_t)calloc(1, sizeof(ep8_st)); \
+ if (A == NULL) { \
+ RLC_THROW(ERR_NO_MEMORY); \
+ } \
+ fp8_null((A)->x); \
+ fp8_null((A)->y); \
+ fp8_null((A)->z); \
+ fp8_new((A)->x); \
+ fp8_new((A)->y); \
+ fp8_new((A)->z); \
+
+#elif ALLOC == AUTO
+#define ep8_new(A) /* empty */
+
+#endif
+
+/**
+ * Calls a function to clean and free a point on an elliptic curve.
+ *
+ * @param[out] A - the point to free.
+ */
+#if ALLOC == DYNAMIC
+#define ep8_free(A) \
+ if (A != NULL) { \
+ fp8_free((A)->x); \
+ fp8_free((A)->y); \
+ fp8_free((A)->z); \
+ free(A); \
+ A = NULL; \
+ } \
+
+#elif ALLOC == AUTO
+#define ep8_free(A) /* empty */
+#endif
+
/**
* Adds two points in an elliptic curve over a quadratic extension field.
* Computes R = P + Q.
@@ -470,6 +544,22 @@ typedef iso2_st *iso2_t;
#define ep2_mul_sim(R, P, K, Q, M) ep2_mul_sim_joint(R, P, K, Q, M)
#endif
+/**
+ * Hashes a byte string to a prime elliptic point or the right order.
+ * Computes R = H(s).
+ *
+ * @param[out] R - the result.
+ * @param[in] S - the string to hash.
+ * @param[in] L - the string length.
+ */
+#if EP_MAP == BASIC
+#define ep2_map(R, S, L) ep2_map_basic(R, S, L)
+#elif EP_MAP == SSWUM
+#define ep2_map(R, S, L) ep2_map_sswum(R, S, L)
+#elif EP_MAP == SWIFT
+#define ep2_map(R, S, L) ep2_map_swift(R, S, L)
+#endif
+
/**
* Adds two points in an elliptic curve over a cubic extension field.
* Computes R = P + Q.
@@ -497,16 +587,6 @@ typedef iso2_st *iso2_t;
#define ep3_dbl(R, P) ep3_dbl_projc(R, P);
#endif
-/**
- * Multiplies a point in an elliptic curve over a cubic extension field by
- * an unrestricted integer scalar. Computes R = [k]P.
- *
- * @param[out] R - the result.
- * @param[in] P - the point to multiply.
- * @param[in] K - the integer.
- */
-#define ep3_mul_big(R, P, K) ep3_mul_basic(R, P, K)
-
/**
* Multiplies a point in an elliptic curve over a cubic extension field.
* Computes R = [k]P.
@@ -583,7 +663,7 @@ typedef iso2_st *iso2_t;
#endif
/**
- * Adds two points in an elliptic curve over a quadratic extension field.
+ * Adds two points in an elliptic curve over a octic extension field.
* Computes R = P + Q.
*
* @param[out] R - the result.
@@ -597,7 +677,7 @@ typedef iso2_st *iso2_t;
#endif
/**
- * Doubles a point in an elliptic curve over a quadratic extension field.
+ * Doubles a point in an elliptic curve over a octic extension field.
* Computes R = 2P.
*
* @param[out] R - the result.
@@ -610,7 +690,7 @@ typedef iso2_st *iso2_t;
#endif
/**
- * Multiplies a point in an elliptic curve over a quadratic extension field by
+ * Multiplies a point in an elliptic curve over a octic extension field by
* an unrestricted integer scalar. Computes R = [k]P.
*
* @param[out] R - the result.
@@ -620,7 +700,7 @@ typedef iso2_st *iso2_t;
#define ep4_mul_big(R, P, K) ep4_mul_basic(R, P, K)
/**
- * Multiplies a point in an elliptic curve over a quadratic extension field.
+ * Multiplies a point in an elliptic curve over a octic extension field.
* Computes R = [k]P.
*
* @param[out] R - the result.
@@ -639,7 +719,7 @@ typedef iso2_st *iso2_t;
/**
* Builds a precomputation table for multiplying a fixed prime elliptic point
- * over a quadratic extension.
+ * over a octic extension.
*
* @param[out] T - the precomputation table.
* @param[in] P - the point to multiply.
@@ -656,7 +736,7 @@ typedef iso2_st *iso2_t;
#endif
/**
- * Multiplies a fixed prime elliptic point over a quadratic extension using a
+ * Multiplies a fixed prime elliptic point over a octic extension using a
* precomputation table. Computes R = [k]P.
*
* @param[out] R - the result.
@@ -694,6 +774,118 @@ typedef iso2_st *iso2_t;
#define ep4_mul_sim(R, P, K, Q, M) ep4_mul_sim_joint(R, P, K, Q, M)
#endif
+/**
+ * Adds two points in an elliptic curve over a octic extension field.
+ * Computes R = P + Q.
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the first point to add.
+ * @param[in] Q - the second point to add.
+ */
+#if EP_ADD == BASIC
+#define ep8_add(R, P, Q) ep8_add_basic(R, P, Q);
+#elif EP_ADD == PROJC || EP_ADD == JACOB
+#define ep8_add(R, P, Q) ep8_add_projc(R, P, Q);
+#endif
+
+/**
+ * Doubles a point in an elliptic curve over a octic extension field.
+ * Computes R = 2P.
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the point to double.
+ */
+#if EP_ADD == BASIC
+#define ep8_dbl(R, P) ep8_dbl_basic(R, P);
+#elif EP_ADD == PROJC || EP_ADD == JACOB
+#define ep8_dbl(R, P) ep8_dbl_projc(R, P);
+#endif
+
+/**
+ * Multiplies a point in an elliptic curve over a octic extension field by
+ * an unrestricted integer scalar. Computes R = [k]P.
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the point to multiply.
+ * @param[in] K - the integer.
+ */
+#define ep8_mul_big(R, P, K) ep8_mul_basic(R, P, K)
+
+/**
+ * Multiplies a point in an elliptic curve over a octic extension field.
+ * Computes R = [k]P.
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the point to multiply.
+ * @param[in] K - the integer.
+ */
+#if EP_MUL == BASIC
+#define ep8_mul(R, P, K) ep8_mul_basic(R, P, K)
+#elif EP_MUL == SLIDE
+#define ep8_mul(R, P, K) ep8_mul_slide(R, P, K)
+#elif EP_MUL == MONTY
+#define ep8_mul(R, P, K) ep8_mul_monty(R, P, K)
+#elif EP_MUL == LWNAF || EP_MUL == LWREG
+#define ep8_mul(R, P, K) ep8_mul_lwnaf(R, P, K)
+#endif
+
+/**
+ * Builds a precomputation table for multiplying a fixed prime elliptic point
+ * over a octic extension.
+ *
+ * @param[out] T - the precomputation table.
+ * @param[in] P - the point to multiply.
+ */
+#if EP_FIX == BASIC
+#define ep8_mul_pre(T, P) ep8_mul_pre_basic(T, P)
+#elif EP_FIX == COMBS
+#define ep8_mul_pre(T, P) ep8_mul_pre_combs(T, P)
+#elif EP_FIX == COMBD
+#define ep8_mul_pre(T, P) ep8_mul_pre_combd(T, P)
+#elif EP_FIX == LWNAF
+//TODO: implement ep8_mul_pre_glv
+#define ep8_mul_pre(T, P) ep8_mul_pre_lwnaf(T, P)
+#endif
+
+/**
+ * Multiplies a fixed prime elliptic point over a octic extension using a
+ * precomputation table. Computes R = [k]P.
+ *
+ * @param[out] R - the result.
+ * @param[in] T - the precomputation table.
+ * @param[in] K - the integer.
+ */
+#if EP_FIX == BASIC
+#define ep8_mul_fix(R, T, K) ep8_mul_fix_basic(R, T, K)
+#elif EP_FIX == COMBS
+#define ep8_mul_fix(R, T, K) ep8_mul_fix_combs(R, T, K)
+#elif EP_FIX == COMBD
+#define ep8_mul_fix(R, T, K) ep8_mul_fix_combd(R, T, K)
+#elif EP_FIX == LWNAF
+//TODO: implement ep8_mul_fix_glv
+#define ep8_mul_fix(R, T, K) ep8_mul_fix_lwnaf(R, T, K)
+#endif
+
+/**
+ * Multiplies and adds two prime elliptic curve points simultaneously. Computes
+ * R = [k]P + [l]Q.
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the first point to multiply.
+ * @param[in] K - the first integer.
+ * @param[in] Q - the second point to multiply.
+ * @param[in] M - the second integer,
+ */
+#if EP_SIM == BASIC
+#define ep8_mul_sim(R, P, K, Q, M) ep8_mul_sim_basic(R, P, K, Q, M)
+#elif EP_SIM == TRICK
+#define ep8_mul_sim(R, P, K, Q, M) ep8_mul_sim_trick(R, P, K, Q, M)
+#elif EP_SIM == INTER
+#define ep8_mul_sim(R, P, K, Q, M) ep8_mul_sim_inter(R, P, K, Q, M)
+#elif EP_SIM == JOINT
+#define ep8_mul_sim(R, P, K, Q, M) ep8_mul_sim_joint(R, P, K, Q, M)
+#endif
+
/*============================================================================*/
/* Function prototypes */
/*============================================================================*/
@@ -722,13 +914,6 @@ fp_t *ep2_curve_get_a(void);
*/
fp_t *ep2_curve_get_b(void);
-/**
- * Returns the vector of coefficients required to perform GLV method.
- *
- * @param[out] b - the vector of coefficients.
- */
-void ep2_curve_get_vs(bn_t *v);
-
/**
* Returns a optimization identifier based on the 'a' coefficient of the curve.
*
@@ -799,7 +984,8 @@ iso2_t ep2_curve_get_iso(void);
* @param[in] r - the order of the group of points.
* @param[in] h - the cofactor of the group order.
*/
-void ep2_curve_set(const fp2_t a, const fp2_t b, const ep2_t g, const bn_t r, const bn_t h);
+void ep2_curve_set(const fp2_t a, const fp2_t b, const ep2_t g, const bn_t r,
+ const bn_t h);
/**
* Configures an elliptic curve by twisting the curve over the base prime field.
@@ -962,7 +1148,7 @@ void ep2_add_slp_basic(ep2_t r, fp2_t s, const ep2_t p, const ep2_t q);
void ep2_add_projc(ep2_t r, const ep2_t p, const ep2_t q);
/**
- * Subtracts a point i an elliptic curve over a quadratic extension from
+ * Subtracts a point in an elliptic curve over a quadratic extension from
* another.
*
* @param[out] r - the result.
@@ -1289,38 +1475,33 @@ void ep2_norm(ep2_t r, const ep2_t p);
void ep2_norm_sim(ep2_t *r, const ep2_t *t, int n);
/**
- * Maps an array of uniformly random bytes to a point in a prime elliptic
- * curve.
- * That array is expected to have a length suitable for four field elements plus
- * extra bytes for uniformity.
- *
+ * Maps a byte array to a point in a prime elliptic curve using the hash and
+ * increment approach.
* @param[out] p - the result.
- * @param[in] uniform_bytes - the array of uniform bytes to map.
+ * @param[in] msg - the byte array to map.
* @param[in] len - the array length in bytes.
*/
-void ep2_map_from_field(ep2_t p, const uint8_t *uniform_bytes, size_t len);
+void ep2_map_basic(ep2_t p, const uint8_t *msg, size_t len);
/**
- * Maps a byte array to a point in an elliptic curve over a quadratic extension.
+ * Maps a byte array to a point in a prime elliptic curve using the
+ * (Simplified) Shallue-van de Woestijne-Ulas map.
*
* @param[out] p - the result.
* @param[in] msg - the byte array to map.
* @param[in] len - the array length in bytes.
*/
-void ep2_map(ep2_t p, const uint8_t *msg, size_t len);
+void ep2_map_sswum(ep2_t p, const uint8_t *msg, size_t len);
/**
- * Maps a byte array to a point in an elliptic curve over a quadratic extension
- * using an explicit domain separation tag.
+ * Maps a byte array to a point in a prime elliptic curve using the
+ * SwiftEC approach.
*
* @param[out] p - the result.
* @param[in] msg - the byte array to map.
* @param[in] len - the array length in bytes.
- * @param[in] dst - the domain separatoin tag.
- * @param[in] dst_len - the domain separation tag length in bytes.
*/
-void ep2_map_dst(ep2_t p, const uint8_t *msg, size_t len, const uint8_t *dst,
- size_t dst_len);
+void ep2_map_swift(ep2_t p, const uint8_t *msg, size_t len);
/**
* Computes a power of the Gailbraith-Lin-Scott homomorphism of a point
@@ -1354,12 +1535,12 @@ void ep2_pck(ep2_t r, const ep2_t p);
int ep2_upk(ep2_t r, const ep2_t p);
/**
- * Initializes the elliptic curve over quartic extension.
+ * Initializes the elliptic curve over octic extension.
*/
void ep3_curve_init(void);
/**
- * Finalizes the elliptic curve over quartic extension.
+ * Finalizes the elliptic curve over octic extension.
*/
void ep3_curve_clean(void);
@@ -1377,13 +1558,6 @@ void ep3_curve_get_a(fp3_t a);
*/
void ep3_curve_get_b(fp3_t b);
-/**
- * Returns the vector of coefficients required to perform GLV method.
- *
- * @param[out] b - the vector of coefficients.
- */
-void ep3_curve_get_vs(bn_t *v);
-
/**
* Returns a optimization identifier based on the 'a' coefficient of the curve.
*
@@ -1434,7 +1608,7 @@ void ep3_curve_get_ord(bn_t n);
void ep3_curve_get_cof(bn_t h);
/**
- * Configures an elliptic curve over a quartic extension by its coefficients.
+ * Configures an elliptic curve over a octic extension by its coefficients.
*
* @param[in] a - the 'a' coefficient of the curve.
* @param[in] b - the 'b' coefficient of the curve.
@@ -1442,7 +1616,8 @@ void ep3_curve_get_cof(bn_t h);
* @param[in] r - the order of the group of points.
* @param[in] h - the cofactor of the group order.
*/
-void ep3_curve_set(const fp3_t a, const fp3_t b, const ep3_t g, const bn_t r, const bn_t h);
+void ep3_curve_set(const fp3_t a, const fp3_t b, const ep3_t g, const bn_t r,
+ const bn_t h);
/**
* Configures an elliptic curve by twisting the curve over the base prime field.
@@ -1532,7 +1707,7 @@ void ep3_print(const ep3_t p);
/**
* Returns the number of bytes necessary to store a prime elliptic curve point
- * over a quartic extension with optional point compression.
+ * over a octic extension with optional point compression.
*
* @param[in] a - the prime field element.
* @param[in] pack - the flag to indicate compression.
@@ -1541,7 +1716,7 @@ void ep3_print(const ep3_t p);
int ep3_size_bin(const ep3_t a, int pack);
/**
- * Reads a prime elliptic curve point over a quartic extension from a byte
+ * Reads a prime elliptic curve point over a octic extension from a byte
* vector in big-endian format.
*
* @param[out] a - the result.
@@ -1550,10 +1725,10 @@ int ep3_size_bin(const ep3_t a, int pack);
* @throw ERR_NO_VALID - if the encoded point is invalid.
* @throw ERR_NO_BUFFER - if the buffer capacity is invalid.
*/
-void ep3_read_bin(ep3_t a, const uint8_t *bin, int len);
+void ep3_read_bin(ep3_t a, const uint8_t *bin, size_t len);
/**
- * Writes a prime elliptic curve pointer over a quartic extension to a byte
+ * Writes a prime elliptic curve pointer over a octic extension to a byte
* vector in big-endian format with optional point compression.
*
* @param[out] bin - the byte vector.
@@ -1562,11 +1737,11 @@ void ep3_read_bin(ep3_t a, const uint8_t *bin, int len);
* @param[in] pack - the flag to indicate compression.
* @throw ERR_NO_BUFFER - if the buffer capacity is invalid.
*/
-void ep3_write_bin(uint8_t *bin, int len, const ep3_t a, int pack);
+void ep3_write_bin(uint8_t *bin, size_t len, const ep3_t a, int pack);
/**
* Negates a point represented in affine coordinates in an elliptic curve over
- * a quartic extension.
+ * a octic extension.
*
* @param[out] r - the result.
* @param[out] p - the point to negate.
@@ -1575,7 +1750,7 @@ void ep3_neg(ep3_t r, const ep3_t p);
/**
* Adds to points represented in affine coordinates in an elliptic curve over a
- * quartic extension.
+ * octic extension.
*
* @param[out] r - the result.
* @param[in] p - the first point to add.
@@ -1585,7 +1760,7 @@ void ep3_add_basic(ep3_t r, const ep3_t p, const ep3_t q);
/**
* Adds to points represented in affine coordinates in an elliptic curve over a
- * quartic extension and returns the computed slope.
+ * octic extension and returns the computed slope.
*
* @param[out] r - the result.
* @param[out] s - the slope.
@@ -1596,7 +1771,7 @@ void ep3_add_slp_basic(ep3_t r, fp3_t s, const ep3_t p, const ep3_t q);
/**
* Adds two points represented in projective coordinates in an elliptic curve
- * over a quartic extension.
+ * over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the first point to add.
@@ -1605,7 +1780,7 @@ void ep3_add_slp_basic(ep3_t r, fp3_t s, const ep3_t p, const ep3_t q);
void ep3_add_projc(ep3_t r, const ep3_t p, const ep3_t q);
/**
- * Subtracts a point i an elliptic curve over a quartic extension from
+ * Subtracts a point in an elliptic curve over a octic extension from
* another.
*
* @param[out] r - the result.
@@ -1616,7 +1791,7 @@ void ep3_sub(ep3_t r, const ep3_t p, const ep3_t q);
/**
* Doubles a points represented in affine coordinates in an elliptic curve over
- * a quartic extension.
+ * a octic extension.
*
* @param[out] r - the result.
* @param[int] p - the point to double.
@@ -1625,7 +1800,7 @@ void ep3_dbl_basic(ep3_t r, const ep3_t p);
/**
* Doubles a points represented in affine coordinates in an elliptic curve over
- * a quartic extension and returns the computed slope.
+ * a octic extension and returns the computed slope.
*
* @param[out] r - the result.
* @param[out] s - the slope.
@@ -1635,7 +1810,7 @@ void ep3_dbl_slp_basic(ep3_t r, fp3_t s, const ep3_t p);
/**
* Doubles a points represented in projective coordinates in an elliptic curve
- * over a quartic extension.
+ * over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the point to double.
@@ -1706,9 +1881,8 @@ void ep3_mul_gen(ep3_t r, const bn_t k);
*/
void ep3_mul_dig(ep3_t r, const ep3_t p, const dig_t k);
-
/**
- * Multiplies a point in an elliptic curve over a quartic extension field by
+ * Multiplies a point in an elliptic curve over a octic extension field by
* the curve cofactor or a small multiple for which a short vector exists.
* In short, it takes a point in the curve to the large prime-order subgroup.
*
@@ -1910,7 +2084,7 @@ void ep3_mul_sim_gen(ep3_t r, const bn_t k, const ep3_t q, const bn_t m);
* @param[in] k - the small scalars.
* @param[in] len - the number of points to multiply.
*/
-void ep3_mul_sim_dig(ep3_t r, const ep3_t p[], const dig_t k[], int len);
+void ep3_mul_sim_dig(ep3_t r, const ep3_t p[], const dig_t k[], size_t len);
/**
* Converts a point to affine coordinates.
@@ -1930,33 +2104,21 @@ void ep3_norm(ep3_t r, const ep3_t p);
void ep3_norm_sim(ep3_t *r, const ep3_t *t, int n);
/**
- * Maps a byte array to a point in an elliptic curve over a quartic extension.
- *
- * @param[out] p - the result.
- * @param[in] msg - the byte array to map.
- * @param[in] len - the array length in bytes.
- */
-void ep3_map(ep3_t p, const uint8_t *msg, int len);
-
-/**
- * Maps a byte array to a point in an elliptic curve over a quartic extension
- * using an explicit domain separation tag.
+ * Maps a byte array to a point in an elliptic curve over a cubic extension.
*
* @param[out] p - the result.
* @param[in] msg - the byte array to map.
* @param[in] len - the array length in bytes.
- * @param[in] dst - the domain separatoin tag.
- * @param[in] dst_len - the domain separation tag length in bytes.
*/
-void ep3_map_dst(ep3_t p, const uint8_t *msg, int len, const uint8_t *dst, int dst_len);
+void ep3_map(ep3_t p, const uint8_t *msg, size_t len);
/**
* Computes a power of the Gailbraith-Lin-Scott homomorphism of a point
* represented in affine coordinates on a twisted elliptic curve over a
- * quartic exension. That is, Psi^i(P) = Twist(P)(Frob^i(unTwist(P)).
- * On the trace-zero group of a quartic twist, consists of a power of the
+ * octic exension. That is, Psi^i(P) = Twist(P)(Frob^i(unTwist(P)).
+ * On the trace-zero group of a octic twist, consists of a power of the
* Frobenius map of a point represented in affine coordinates in an elliptic
- * curve over a quartic exension. Computes Frob^i(P) = (p^i)P.
+ * curve over a octic exension. Computes Frob^i(P) = (p^i)P.
*
* @param[out] r - the result in affine coordinates.
* @param[in] p - a point in affine coordinates.
@@ -1965,7 +2127,7 @@ void ep3_map_dst(ep3_t p, const uint8_t *msg, int len, const uint8_t *dst, int d
void ep3_frb(ep3_t r, const ep3_t p, int i);
/**
- * Compresses a point in an elliptic curve over a quartic extension.
+ * Compresses a point in an elliptic curve over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the point to compress.
@@ -1973,7 +2135,7 @@ void ep3_frb(ep3_t r, const ep3_t p, int i);
void ep3_pck(ep3_t r, const ep3_t p);
/**
- * Decompresses a point in an elliptic curve over a quartic extension.
+ * Decompresses a point in an elliptic curve over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the point to decompress.
@@ -1982,12 +2144,12 @@ void ep3_pck(ep3_t r, const ep3_t p);
int ep3_upk(ep3_t r, const ep3_t p);
/**
- * Initializes the elliptic curve over quartic extension.
+ * Initializes the elliptic curve over octic extension.
*/
void ep4_curve_init(void);
/**
- * Finalizes the elliptic curve over quartic extension.
+ * Finalizes the elliptic curve over octic extension.
*/
void ep4_curve_clean(void);
@@ -2005,13 +2167,6 @@ void ep4_curve_get_a(fp4_t a);
*/
void ep4_curve_get_b(fp4_t b);
-/**
- * Returns the vector of coefficients required to perform GLV method.
- *
- * @param[out] b - the vector of coefficients.
- */
-void ep4_curve_get_vs(bn_t *v);
-
/**
* Returns a optimization identifier based on the 'a' coefficient of the curve.
*
@@ -2062,7 +2217,7 @@ void ep4_curve_get_ord(bn_t n);
void ep4_curve_get_cof(bn_t h);
/**
- * Configures an elliptic curve over a quartic extension by its coefficients.
+ * Configures an elliptic curve over a octic extension by its coefficients.
*
* @param[in] a - the 'a' coefficient of the curve.
* @param[in] b - the 'b' coefficient of the curve.
@@ -2070,7 +2225,8 @@ void ep4_curve_get_cof(bn_t h);
* @param[in] r - the order of the group of points.
* @param[in] h - the cofactor of the group order.
*/
-void ep4_curve_set(const fp4_t a, const fp4_t b, const ep4_t g, const bn_t r, const bn_t h);
+void ep4_curve_set(const fp4_t a, const fp4_t b, const ep4_t g, const bn_t r,
+ const bn_t h);
/**
* Configures an elliptic curve by twisting the curve over the base prime field.
@@ -2160,7 +2316,7 @@ void ep4_print(const ep4_t p);
/**
* Returns the number of bytes necessary to store a prime elliptic curve point
- * over a quartic extension with optional point compression.
+ * over a octic extension with optional point compression.
*
* @param[in] a - the prime field element.
* @param[in] pack - the flag to indicate compression.
@@ -2169,7 +2325,7 @@ void ep4_print(const ep4_t p);
int ep4_size_bin(const ep4_t a, int pack);
/**
- * Reads a prime elliptic curve point over a quartic extension from a byte
+ * Reads a prime elliptic curve point over a octic extension from a byte
* vector in big-endian format.
*
* @param[out] a - the result.
@@ -2181,7 +2337,7 @@ int ep4_size_bin(const ep4_t a, int pack);
void ep4_read_bin(ep4_t a, const uint8_t *bin, size_t len);
/**
- * Writes a prime elliptic curve pointer over a quartic extension to a byte
+ * Writes a prime elliptic curve pointer over a octic extension to a byte
* vector in big-endian format with optional point compression.
*
* @param[out] bin - the byte vector.
@@ -2194,7 +2350,7 @@ void ep4_write_bin(uint8_t *bin, size_t len, const ep4_t a, int pack);
/**
* Negates a point represented in affine coordinates in an elliptic curve over
- * a quartic extension.
+ * a octic extension.
*
* @param[out] r - the result.
* @param[out] p - the point to negate.
@@ -2203,7 +2359,7 @@ void ep4_neg(ep4_t r, const ep4_t p);
/**
* Adds to points represented in affine coordinates in an elliptic curve over a
- * quartic extension.
+ * octic extension.
*
* @param[out] r - the result.
* @param[in] p - the first point to add.
@@ -2213,7 +2369,7 @@ void ep4_add_basic(ep4_t r, const ep4_t p, const ep4_t q);
/**
* Adds to points represented in affine coordinates in an elliptic curve over a
- * quartic extension and returns the computed slope.
+ * octic extension and returns the computed slope.
*
* @param[out] r - the result.
* @param[out] s - the slope.
@@ -2224,7 +2380,7 @@ void ep4_add_slp_basic(ep4_t r, fp4_t s, const ep4_t p, const ep4_t q);
/**
* Adds two points represented in projective coordinates in an elliptic curve
- * over a quartic extension.
+ * over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the first point to add.
@@ -2233,7 +2389,7 @@ void ep4_add_slp_basic(ep4_t r, fp4_t s, const ep4_t p, const ep4_t q);
void ep4_add_projc(ep4_t r, const ep4_t p, const ep4_t q);
/**
- * Subtracts a point i an elliptic curve over a quartic extension from
+ * Subtracts a point in an elliptic curve over a octic extension from
* another.
*
* @param[out] r - the result.
@@ -2244,7 +2400,7 @@ void ep4_sub(ep4_t r, const ep4_t p, const ep4_t q);
/**
* Doubles a points represented in affine coordinates in an elliptic curve over
- * a quartic extension.
+ * a octic extension.
*
* @param[out] r - the result.
* @param[int] p - the point to double.
@@ -2253,7 +2409,7 @@ void ep4_dbl_basic(ep4_t r, const ep4_t p);
/**
* Doubles a points represented in affine coordinates in an elliptic curve over
- * a quartic extension and returns the computed slope.
+ * a octic extension and returns the computed slope.
*
* @param[out] r - the result.
* @param[out] s - the slope.
@@ -2263,7 +2419,7 @@ void ep4_dbl_slp_basic(ep4_t r, fp4_t s, const ep4_t p);
/**
* Doubles a points represented in projective coordinates in an elliptic curve
- * over a quartic extension.
+ * over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the point to double.
@@ -2336,7 +2492,7 @@ void ep4_mul_dig(ep4_t r, const ep4_t p, const dig_t k);
/**
- * Multiplies a point in an elliptic curve over a quartic extension field by
+ * Multiplies a point in an elliptic curve over a octic extension field by
* the curve cofactor or a small multiple for which a short vector exists.
* In short, it takes a point in the curve to the large prime-order subgroup.
*
@@ -2558,7 +2714,7 @@ void ep4_norm(ep4_t r, const ep4_t p);
void ep4_norm_sim(ep4_t *r, const ep4_t *t, int n);
/**
- * Maps a byte array to a point in an elliptic curve over a quartic extension.
+ * Maps a byte array to a point in an elliptic curve over a octic extension.
*
* @param[out] p - the result.
* @param[in] msg - the byte array to map.
@@ -2566,26 +2722,13 @@ void ep4_norm_sim(ep4_t *r, const ep4_t *t, int n);
*/
void ep4_map(ep4_t p, const uint8_t *msg, size_t len);
-/**
- * Maps a byte array to a point in an elliptic curve over a quartic extension
- * using an explicit domain separation tag.
- *
- * @param[out] p - the result.
- * @param[in] msg - the byte array to map.
- * @param[in] len - the array length in bytes.
- * @param[in] dst - the domain separatoin tag.
- * @param[in] dst_len - the domain separation tag length in bytes.
- */
-void ep4_map_dst(ep4_t p, const uint8_t *msg, size_t len, const uint8_t *dst,
- size_t dst_len);
-
/**
* Computes a power of the Gailbraith-Lin-Scott homomorphism of a point
* represented in affine coordinates on a twisted elliptic curve over a
- * quartic exension. That is, Psi^i(P) = Twist(P)(Frob^i(unTwist(P)).
- * On the trace-zero group of a quartic twist, consists of a power of the
+ * octic exension. That is, Psi^i(P) = Twist(P)(Frob^i(unTwist(P)).
+ * On the trace-zero group of a octic twist, consists of a power of the
* Frobenius map of a point represented in affine coordinates in an elliptic
- * curve over a quartic exension. Computes Frob^i(P) = (p^i)P.
+ * curve over a octic exension. Computes Frob^i(P) = (p^i)P.
*
* @param[out] r - the result in affine coordinates.
* @param[in] p - a point in affine coordinates.
@@ -2594,7 +2737,7 @@ void ep4_map_dst(ep4_t p, const uint8_t *msg, size_t len, const uint8_t *dst,
void ep4_frb(ep4_t r, const ep4_t p, int i);
/**
- * Compresses a point in an elliptic curve over a quartic extension.
+ * Compresses a point in an elliptic curve over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the point to compress.
@@ -2602,7 +2745,7 @@ void ep4_frb(ep4_t r, const ep4_t p, int i);
void ep4_pck(ep4_t r, const ep4_t p);
/**
- * Decompresses a point in an elliptic curve over a quartic extension.
+ * Decompresses a point in an elliptic curve over a octic extension.
*
* @param[out] r - the result.
* @param[in] p - the point to decompress.
@@ -2610,4 +2753,614 @@ void ep4_pck(ep4_t r, const ep4_t p);
*/
int ep4_upk(ep4_t r, const ep4_t p);
+/**
+ * Initializes the elliptic curve over octic extension.
+ */
+void ep8_curve_init(void);
+
+/**
+ * Finalizes the elliptic curve over octic extension.
+ */
+void ep8_curve_clean(void);
+
+/**
+ * Returns the 'a' coefficient of the currently configured elliptic curve.
+ *
+ * @return the 'a' coefficient of the elliptic curve.
+ */
+void ep8_curve_get_a(fp8_t a);
+
+/**
+ * Returns the 'b' coefficient of the currently configured elliptic curve.
+ *
+ * @param[out] b - the 'b' coefficient of the elliptic curve.
+ */
+void ep8_curve_get_b(fp8_t b);
+
+/**
+ * Returns a optimization identifier based on the 'a' coefficient of the curve.
+ *
+ * @return the optimization identifier.
+ */
+int ep8_curve_opt_a(void);
+
+/**
+ * Returns b optimization identifier based on the 'b' coefficient of the curve.
+ *
+ * @return the optimization identifier.
+ */
+int ep8_curve_opt_b(void);
+
+/**
+ * Tests if the configured elliptic curve is a twist.
+ *
+ * @return the type of the elliptic curve twist, 0 if non-twisted curve.
+ */
+int ep8_curve_is_twist(void);
+
+/**
+ * Returns the generator of the group of points in the elliptic curve.
+ *
+ * @param[out] g - the returned generator.
+ */
+void ep8_curve_get_gen(ep8_t g);
+
+/**
+ * Returns the precomputation table for the generator.
+ *
+ * @return the table.
+ */
+ep8_t *ep8_curve_get_tab(void);
+
+/**
+ * Returns the order of the group of points in the elliptic curve.
+ *
+ * @param[out] n - the returned order.
+ */
+void ep8_curve_get_ord(bn_t n);
+
+/**
+ * Returns the cofactor of the group order in the elliptic curve.
+ *
+ * @param[out] h - the returned cofactor.
+ */
+void ep8_curve_get_cof(bn_t h);
+
+/**
+ * Configures an elliptic curve over a octic extension by its coefficients.
+ *
+ * @param[in] a - the 'a' coefficient of the curve.
+ * @param[in] b - the 'b' coefficient of the curve.
+ * @param[in] g - the generator.
+ * @param[in] r - the order of the group of points.
+ * @param[in] h - the cofactor of the group order.
+ */
+void ep8_curve_set(const fp8_t a, const fp8_t b, const ep8_t g, const bn_t r,
+ const bn_t h);
+
+/**
+ * Configures an elliptic curve by twisting the curve over the base prime field.
+ *
+ * @param - the type of twist (multiplicative or divisive)
+ */
+void ep8_curve_set_twist(int type);
+
+/**
+ * Tests if a point on an elliptic curve is at the infinity.
+ *
+ * @param[in] p - the point to test.
+ * @return 1 if the point is at infinity, 0 otherise.
+ */
+int ep8_is_infty(const ep8_t p);
+
+/**
+ * Assigns an elliptic curve point to the point at infinity.
+ *
+ * @param[out] p - the point to assign.
+ */
+void ep8_set_infty(ep8_t p);
+
+/**
+ * Copies the second argument to the first argument.
+ *
+ * @param[out] q - the result.
+ * @param[in] p - the elliptic curve point to copy.
+ */
+void ep8_copy(ep8_t r, const ep8_t p);
+
+/**
+ * Compares two elliptic curve points.
+ *
+ * @param[in] p - the first elliptic curve point.
+ * @param[in] q - the second elliptic curve point.
+ * @return RLC_EQ if p == q and RLC_NE if p != q.
+ */
+int ep8_cmp(const ep8_t p, const ep8_t q);
+
+/**
+ * Assigns a random value to an elliptic curve point.
+ *
+ * @param[out] p - the elliptic curve point to assign.
+ */
+void ep8_rand(ep8_t p);
+
+/**
+ * Randomizes coordinates of an elliptic curve point.
+ *
+ * @param[out] r - the blinded prime elliptic curve point.
+ * @param[in] p - the prime elliptic curve point to blind.
+ */
+void ep8_blind(ep8_t r, const ep8_t p);
+
+/**
+ * Computes the right-hand side of the elliptic curve equation at a certain
+ * elliptic curve point.
+ *
+ * @param[out] rhs - the result.
+ * @param[in] p - the point.
+ */
+void ep8_rhs(fp8_t rhs, const ep8_t p);
+
+/**
+ * Tests if a point is in the curve.
+ *
+ * @param[in] p - the point to test.
+ */
+int ep8_on_curve(const ep8_t p);
+
+/**
+ * Builds a precomputation table for multiplying a random prime elliptic point.
+ *
+ * @param[out] t - the precomputation table.
+ * @param[in] p - the point to multiply.
+ * @param[in] w - the window width.
+ */
+void ep8_tab(ep8_t *t, const ep8_t p, int w);
+
+/**
+ * Prints an elliptic curve point.
+ *
+ * @param[in] p - the elliptic curve point to print.
+ */
+void ep8_print(const ep8_t p);
+
+/**
+ * Returns the number of bytes necessary to store a prime elliptic curve point
+ * over a octic extension with optional point compression.
+ *
+ * @param[in] a - the prime field element.
+ * @param[in] pack - the flag to indicate compression.
+ * @return the number of bytes.
+ */
+int ep8_size_bin(const ep8_t a, int pack);
+
+/**
+ * Reads a prime elliptic curve point over a octic extension from a byte
+ * vector in big-endian format.
+ *
+ * @param[out] a - the result.
+ * @param[in] bin - the byte vector.
+ * @param[in] len - the buffer capacity.
+ * @throw ERR_NO_VALID - if the encoded point is invalid.
+ * @throw ERR_NO_BUFFER - if the buffer capacity is invalid.
+ */
+void ep8_read_bin(ep8_t a, const uint8_t *bin, size_t len);
+
+/**
+ * Writes a prime elliptic curve pointer over a octic extension to a byte
+ * vector in big-endian format with optional point compression.
+ *
+ * @param[out] bin - the byte vector.
+ * @param[in] len - the buffer capacity.
+ * @param[in] a - the prime elliptic curve point to write.
+ * @param[in] pack - the flag to indicate compression.
+ * @throw ERR_NO_BUFFER - if the buffer capacity is invalid.
+ */
+void ep8_write_bin(uint8_t *bin, size_t len, const ep8_t a, int pack);
+
+/**
+ * Negates a point represented in affine coordinates in an elliptic curve over
+ * a octic extension.
+ *
+ * @param[out] r - the result.
+ * @param[out] p - the point to negate.
+ */
+void ep8_neg(ep8_t r, const ep8_t p);
+
+/**
+ * Adds to points represented in affine coordinates in an elliptic curve over a
+ * octic extension.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point to add.
+ * @param[in] q - the second point to add.
+ */
+void ep8_add_basic(ep8_t r, const ep8_t p, const ep8_t q);
+
+/**
+ * Adds to points represented in affine coordinates in an elliptic curve over a
+ * octic extension and returns the computed slope.
+ *
+ * @param[out] r - the result.
+ * @param[out] s - the slope.
+ * @param[in] p - the first point to add.
+ * @param[in] q - the second point to add.
+ */
+void ep8_add_slp_basic(ep8_t r, fp8_t s, const ep8_t p, const ep8_t q);
+
+/**
+ * Adds two points represented in projective coordinates in an elliptic curve
+ * over a octic extension.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point to add.
+ * @param[in] q - the second point to add.
+ */
+void ep8_add_projc(ep8_t r, const ep8_t p, const ep8_t q);
+
+ /**
+ * Subtracts a point in an elliptic curve over a octic extension from
+ * another.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point.
+ * @param[in] q - the point to subtract.
+ */
+void ep8_sub(ep8_t r, const ep8_t p, const ep8_t q);
+
+/**
+ * Doubles a points represented in affine coordinates in an elliptic curve over
+ * a octic extension.
+ *
+ * @param[out] r - the result.
+ * @param[int] p - the point to double.
+ */
+void ep8_dbl_basic(ep8_t r, const ep8_t p);
+
+/**
+ * Doubles a points represented in affine coordinates in an elliptic curve over
+ * a octic extension and returns the computed slope.
+ *
+ * @param[out] r - the result.
+ * @param[out] s - the slope.
+ * @param[in] p - the point to double.
+ */
+void ep8_dbl_slp_basic(ep8_t r, fp8_t s, const ep8_t p);
+
+/**
+ * Doubles a points represented in projective coordinates in an elliptic curve
+ * over a octic extension.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to double.
+ */
+void ep8_dbl_projc(ep8_t r, const ep8_t p);
+
+/**
+ * Multiplies a prime elliptic point by an integer using the binary method.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_basic(ep8_t r, const ep8_t p, const bn_t k);
+
+/**
+ * Multiplies a prime elliptic point by an integer using the sliding window
+ * method.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_slide(ep8_t r, const ep8_t p, const bn_t k);
+
+/**
+ * Multiplies a prime elliptic point by an integer using the constant-time
+ * Montgomery ladder point multiplication method.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_monty(ep8_t r, const ep8_t p, const bn_t k);
+
+/**
+ * Multiplies a prime elliptic point by an integer using the w-NAF method.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_lwnaf(ep8_t r, const ep8_t p, const bn_t k);
+
+/**
+ * Multiplies a prime elliptic point by an integer using a regular method.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_lwreg(ep8_t r, const ep8_t p, const bn_t k);
+
+/**
+ * Multiplies the generator of an elliptic curve over a qaudratic extension.
+ *
+ * @param[out] r - the result.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_gen(ep8_t r, const bn_t k);
+
+/**
+ * Multiplies a prime elliptic point by a small integer.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_dig(ep8_t r, const ep8_t p, const dig_t k);
+
+
+/**
+ * Multiplies a point in an elliptic curve over a octic extension field by
+ * the curve cofactor or a small multiple for which a short vector exists.
+ * In short, it takes a point in the curve to the large prime-order subgroup.
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the point to multiply.
+ */
+void ep8_mul_cof(ep8_t r, const ep8_t p);
+
+/**
+ * Builds a precomputation table for multiplying a fixed prime elliptic point
+ * using the binary method.
+ *
+ * @param[out] t - the precomputation table.
+ * @param[in] p - the point to multiply.
+ */
+void ep8_mul_pre_basic(ep8_t *t, const ep8_t p);
+
+/**
+ * Builds a precomputation table for multiplying a fixed prime elliptic point
+ * using Yao's windowing method.
+ *
+ * @param[out] t - the precomputation table.
+ * @param[in] p - the point to multiply.
+ */
+void ep8_mul_pre_yaowi(ep8_t *t, const ep8_t p);
+
+/**
+ * Builds a precomputation table for multiplying a fixed prime elliptic point
+ * using the NAF windowing method.
+ *
+ * @param[out] t - the precomputation table.
+ * @param[in] p - the point to multiply.
+ */
+void ep8_mul_pre_nafwi(ep8_t *t, const ep8_t p);
+
+/**
+ * Builds a precomputation table for multiplying a fixed prime elliptic point
+ * using the single-table comb method.
+ *
+ * @param[out] t - the precomputation table.
+ * @param[in] p - the point to multiply.
+ */
+void ep8_mul_pre_combs(ep8_t *t, const ep8_t p);
+
+/**
+ * Builds a precomputation table for multiplying a fixed prime elliptic point
+ * using the double-table comb method.
+ *
+ * @param[out] t - the precomputation table.
+ * @param[in] p - the point to multiply.
+ */
+void ep8_mul_pre_combd(ep8_t *t, const ep8_t p);
+
+/**
+ * Builds a precomputation table for multiplying a fixed prime elliptic point
+ * using the w-(T)NAF method.
+ *
+ * @param[out] t - the precomputation table.
+ * @param[in] p - the point to multiply.
+ */
+void ep8_mul_pre_lwnaf(ep8_t *t, const ep8_t p);
+
+/**
+ * Multiplies a fixed prime elliptic point using a precomputation table and
+ * the binary method.
+ *
+ * @param[out] r - the result.
+ * @param[in] t - the precomputation table.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_fix_basic(ep8_t r, const ep8_t *t, const bn_t k);
+
+/**
+ * Multiplies a fixed prime elliptic point using a precomputation table and
+ * Yao's windowing method
+ *
+ * @param[out] r - the result.
+ * @param[in] t - the precomputation table.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_fix_yaowi(ep8_t r, const ep8_t *t, const bn_t k);
+
+/**
+ * Multiplies a fixed prime elliptic point using a precomputation table and
+ * the w-(T)NAF method.
+ *
+ * @param[out] r - the result.
+ * @param[in] t - the precomputation table.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_fix_nafwi(ep8_t r, const ep8_t *t, const bn_t k);
+
+/**
+ * Multiplies a fixed prime elliptic point using a precomputation table and
+ * the single-table comb method.
+ *
+ * @param[out] r - the result.
+ * @param[in] t - the precomputation table.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_fix_combs(ep8_t r, const ep8_t *t, const bn_t k);
+
+/**
+ * Multiplies a fixed prime elliptic point using a precomputation table and
+ * the double-table comb method.
+ *
+ * @param[out] r - the result.
+ * @param[in] t - the precomputation table.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_fix_combd(ep8_t r, const ep8_t *t, const bn_t k);
+
+/**
+ * Multiplies a fixed prime elliptic point using a precomputation table and
+ * the w-(T)NAF method.
+ *
+ * @param[out] r - the result.
+ * @param[in] t - the precomputation table.
+ * @param[in] k - the integer.
+ */
+void ep8_mul_fix_lwnaf(ep8_t r, const ep8_t *t, const bn_t k);
+
+/**
+ * Multiplies and adds two prime elliptic curve points simultaneously using
+ * scalar multiplication and point addition.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point to multiply.
+ * @param[in] k - the first integer.
+ * @param[in] q - the second point to multiply.
+ * @param[in] m - the second integer,
+ */
+void ep8_mul_sim_basic(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q, const bn_t m);
+
+/**
+ * Multiplies and adds two prime elliptic curve points simultaneously using
+ * shamir's trick.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point to multiply.
+ * @param[in] k - the first integer.
+ * @param[in] q - the second point to multiply.
+ * @param[in] m - the second integer,
+ */
+void ep8_mul_sim_trick(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q, const bn_t m);
+
+/**
+ * Multiplies and adds two prime elliptic curve points simultaneously using
+ * interleaving of NAFs.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point to multiply.
+ * @param[in] k - the first integer.
+ * @param[in] q - the second point to multiply.
+ * @param[in] m - the second integer,
+ */
+void ep8_mul_sim_inter(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q, const bn_t m);
+
+/**
+ * Multiplies and adds two prime elliptic curve points simultaneously using
+ * Solinas' Joint Sparse Form.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point to multiply.
+ * @param[in] k - the first integer.
+ * @param[in] q - the second point to multiply.
+ * @param[in] m - the second integer,
+ */
+void ep8_mul_sim_joint(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q, const bn_t m);
+
+/**
+ * Multiplies simultaneously elements from a prime elliptic curve.
+ * Computes R = \Sum_i=0..n k_iP_i.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the points to multiply.
+ * @param[in] k - the integer scalars.
+ * @param[in] n - the number of elements to multiply.
+ */
+void ep8_mul_sim_lot(ep8_t r, const ep8_t p[], const bn_t k[], size_t n);
+
+/**
+ * Multiplies and adds the generator and a prime elliptic curve point
+ * simultaneously. Computes R = [k]G + [l]Q.
+ *
+ * @param[out] r - the result.
+ * @param[in] k - the first integer.
+ * @param[in] q - the second point to multiply.
+ * @param[in] m - the second integer,
+ */
+void ep8_mul_sim_gen(ep8_t r, const bn_t k, const ep8_t q, const bn_t m);
+
+/**
+ * Multiplies prime elliptic curve points by small scalars.
+ * Computes R = \sum k_iP_i.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the points to multiply.
+ * @param[in] k - the small scalars.
+ * @param[in] len - the number of points to multiply.
+ */
+void ep8_mul_sim_dig(ep8_t r, const ep8_t p[], const dig_t k[], size_t len);
+
+/**
+ * Converts a point to affine coordinates.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to convert.
+ */
+void ep8_norm(ep8_t r, const ep8_t p);
+
+/**
+ * Converts multiple points to affine coordinates.
+ *
+ * @param[out] r - the result.
+ * @param[in] t - the points to convert.
+ * @param[in] n - the number of points.
+ */
+void ep8_norm_sim(ep8_t *r, const ep8_t *t, int n);
+
+/**
+ * Maps a byte array to a point in an elliptic curve over a octic extension.
+ *
+ * @param[out] p - the result.
+ * @param[in] msg - the byte array to map.
+ * @param[in] len - the array length in bytes.
+ */
+void ep8_map(ep8_t p, const uint8_t *msg, size_t len);
+
+/**
+ * Computes a power of the Gailbraith-Lin-Scott homomorphism of a point
+ * represented in affine coordinates on a twisted elliptic curve over a
+ * octic exension. That is, Psi^i(P) = Twist(P)(Frob^i(unTwist(P)).
+ * On the trace-zero group of a octic twist, consists of a power of the
+ * Frobenius map of a point represented in affine coordinates in an elliptic
+ * curve over a octic exension. Computes Frob^i(P) = (p^i)P.
+ *
+ * @param[out] r - the result in affine coordinates.
+ * @param[in] p - a point in affine coordinates.
+ * @param[in] i - the power of the Frobenius map.
+ */
+void ep8_frb(ep8_t r, const ep8_t p, int i);
+
+/**
+ * Compresses a point in an elliptic curve over a octic extension.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to compress.
+ */
+void ep8_pck(ep8_t r, const ep8_t p);
+
+/**
+ * Decompresses a point in an elliptic curve over a octic extension.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to decompress.
+ * @return if the decompression was successful
+ */
+int ep8_upk(ep8_t r, const ep8_t p);
+
#endif /* !RLC_EPX_H */
diff --git a/include/relic_fp.h b/include/relic_fp.h
index 83bda0ea9..e5bf72632 100644
--- a/include/relic_fp.h
+++ b/include/relic_fp.h
@@ -64,8 +64,10 @@
* Finite field identifiers.
*/
enum {
+ /** Mersenne prime with 127 bits. */
+ MP_127 = 1,
/** SECG 160-bit fast reduction prime. */
- SECG_160 = 1,
+ SECG_160,
/** SECG 160-bit denser reduction prime. */
SECG_160D,
/** NIST 192-bit fast reduction prime. */
@@ -102,6 +104,8 @@ enum {
NIST_384,
/** Curve448 prime. */
PRIME_448,
+ /** 511-bit prime for CTIDH. */
+ CTIDH_511,
/** Curve511187 511-bit prime modulus. */
PRIME_511187,
/** NIST 521-bit fast reduction polynomial. */
@@ -118,6 +122,8 @@ enum {
B24_315,
/** 317-bit prime for BLS curve of embedding degree 24 (SNARKs). */
B24_317,
+ /** 330-bit prime for KSS curve with embedding degree 16. */
+ K16_330,
/** 381-bit prime for BLS curve of embedding degree 12 (SNARKs). */
B12_377,
/** 381-bit prime for BLS curve of embedding degree 12 (Zcash). */
@@ -135,9 +141,7 @@ enum {
/** 477-bit prime for BLS curve of embedding degree 24. */
B24_509,
/** 508-bit prime for KSS16 curve. */
- KSS_508,
- /** 511-bit prime for Optimal TNFS-secure curve. */
- OT_511,
+ K18_508,
/** Random 544-bit prime for Cocks-Pinch curve with embedding degree 8. */
GMT8_544,
/** 569-bit prime for SG curve with embedding degree 54. */
@@ -152,10 +156,20 @@ enum {
K18_638,
/** 638-bit prime for SG curve with embedding degree 18. */
SG18_638,
+ /** 765-bit prime for new family with embedding degree 16. */
+ N16_765,
+ /** 766-bit prime for KSS curve with embedding degree 16. */
+ K16_766,
+ /** 1024-bit prime for CTIDH. */
+ CTIDH_1024,
/** 1536-bit prime for supersingular curve with embedding degree k = 2. */
SS_1536,
+ /** 2048-bit prime for CTDIH. */
+ CTIDH_2048,
/** 3072-bit prime for supersingular curve with embedding degree k = 1. */
- SS_3072,
+ K1_3072,
+ /** 4096-bit prime for SQALE. */
+ SQALE_4096,
};
/**
@@ -386,8 +400,6 @@ typedef rlc_align dig_t fp_st[RLC_FP_DIGS + RLC_PAD(RLC_FP_BYTES)/(RLC_DIG / 8)]
*/
#if FP_SMB == BASIC
#define fp_smb(A) fp_smb_basic(A)
-#elif FP_SMB == BINAR
-#define fp_smb(A) fp_smb_binar(A)
#elif FP_SMB == DIVST
#define fp_smb(A) fp_smb_divst(A)
#elif FP_SMB == JMPDS
@@ -447,6 +459,22 @@ const dig_t *fp_prime_get_rdc(void);
*/
const dig_t *fp_prime_get_conv(void);
+/**
+ * Returns a 2^f-root of unity modulo the prime field modulus, for the maximum f
+ * such that 2^f divides (p-1).
+ *
+ * @return the root of unity.
+ */
+const dig_t *fp_prime_get_srt(void);
+
+/**
+ * Returns a 3^f-root of unity modulo the prime field modulus, for the maximum f
+ * such that 3^f divides (p-1).
+ *
+ * @return the root of unity.
+ */
+const dig_t *fp_prime_get_crt(void);
+
/**
* Returns the result of prime order mod 8.
*
@@ -1112,14 +1140,6 @@ void fp_inv_sim(fp_t *c, const fp_t *a, int n);
*/
int fp_smb_basic(const fp_t a);
-/**
- * Computes Legendre symbol of a prime field element using the binary method.
- *
- * @param[in] a - the prime field element to compute.
- * @return the result.
- */
-int fp_smb_binar(const fp_t a);
-
/**
* Computes Legendre symbol of a prime field element using the constant-time
* division step approach by Bernstein and Bo-Yin Yang.
@@ -1176,6 +1196,23 @@ void fp_exp_slide(fp_t c, const fp_t a, const bn_t b);
*/
void fp_exp_monty(fp_t c, const fp_t a, const bn_t b);
+/**
+ * Computes a power of a field element by a small exponent.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the basis.
+ * @param[in] b - the exponent.
+ */
+void fp_exp_dig(fp_t c, const fp_t a, dig_t b);
+
+/**
+ * Tests if a prime field element is a quadratic residue.
+ *
+ * @param[in] a - the prime field element to test.
+ * @return 1 if the argument is even, 0 otherwise.
+ */
+int fp_is_sqr(const fp_t a);
+
/**
* Extracts the square root of a prime field element. Computes c = sqrt(a). The
* other square root is the negation of c.
@@ -1186,4 +1223,22 @@ void fp_exp_monty(fp_t c, const fp_t a, const bn_t b);
*/
int fp_srt(fp_t c, const fp_t a);
+/**
+ * Tests if a prime field element is a cubic residue.
+ *
+ * @param[in] a - the prime field element to test.
+ * @return 1 if the argument is even, 0 otherwise.
+ */
+int fp_is_cub(const fp_t a);
+
+/**
+ * Extracts the cube root of a prime field element. Computes c = crt(a). The
+ * other cube root is the square of c.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the prime field element.
+ * @return - 1 if there is a cube root, 0 otherwise.
+ */
+int fp_crt(fp_t c, const fp_t a);
+
#endif /* !RLC_FP_H */
diff --git a/include/relic_fpx.h b/include/relic_fpx.h
index cfb6dfcd5..f410903f2 100644
--- a/include/relic_fpx.h
+++ b/include/relic_fpx.h
@@ -169,11 +169,30 @@ typedef fp6_t fp12_t[2];
*/
typedef dv6_t dv12_t[2];
+/**
+ * Represents an octic extension prime field element.
+ *
+ * This extension is constructed with the basis {1, w}, where v^2 = v is an
+ * adjoined root in the underlying octic extension.
+ */
+typedef fp8_t fp16_t[2];
+
+/**
+ * Represents a double-precision octic extension field element.
+ */
+typedef dv8_t dv16_t[2];
+
+/**
+ * Represents an octic extension field element with automatic memory
+ * allocation.
+ */
+typedef fp8_st fp16_st[2];
+
/**
* Represents an octdecic extension field element.
*
* This extension is constructed with the basis {1, w}, where w^2 = v is an
- * adjoined root in the underlying sextic extension.
+ * adjoined root in the underlying nonic extension.
*/
typedef fp9_t fp18_t[2];
@@ -185,8 +204,8 @@ typedef dv9_t dv18_t[2];
/**
* Represents a 24-degree extension field element.
*
- * This extension is constructed with the basis {1, t, t^2}, where t^3 = w is an
- * adjoined root in the underlying dodecic extension.
+ * This extension is constructed with the basis {1, t, t^2}, where t^3 = v is an
+ * adjoined root in the underlying octic extension.
*/
typedef fp8_t fp24_t[3];
@@ -199,7 +218,7 @@ typedef dv8_t dv24_t[3];
* Represents a 48-degree extension field element.
*
* This extension is constructed with the basis {1, u}, where u^2 = t is an
- * adjoined root in the underlying dodecic extension.
+ * adjoined root in the underlying extension of degree 24.
*/
typedef fp24_t fp48_t[2];
@@ -207,7 +226,7 @@ typedef fp24_t fp48_t[2];
* Represents a 54-degree extension field element.
*
* This extension is constructed with the basis {1, u, u^2}, where u^3 = t is an
- * adjoined root in the underlying dodecic extension.
+ * adjoined root in the underlying octdecic extension.
*/
typedef fp18_t fp54_t[3];
@@ -291,7 +310,7 @@ typedef fp18_t fp54_t[3];
#define fp2_sub(C, A, B) fp2_sub_integ(C, A, B)
#endif
-/**
+/**ffp8
* Doubles a quadratic extension field element. Computes C = A + A.
*
* @param[out] C - the result.
@@ -860,6 +879,93 @@ typedef fp18_t fp54_t[3];
#define fp12_sqr_pck(C, A) fp12_sqr_pck_lazyr(C, A)
#endif
+/**
+ * Initializes a double-precision sextadecic extension field with null.
+ *
+ * @param[out] A - the sextadecic extension element to initialize.
+ */
+#define dv16_null(A) \
+ dv8_null(A[0]); dv8_null(A[1]); \
+
+/**
+ * Allocates a double-precision sextadecic extension field element.
+ *
+ * @param[out] A - the new sextadecic extension field element.
+ */
+#define dv16_new(A) \
+ dv8_new(A[0]); dv8_new(A[1]); \
+
+/**
+ * Frees a double-precision sextadecic extension field element.
+ *
+ * @param[out] A - the sextadecic extension field element to free.
+ */
+#define dv16_free(A) \
+ dv8_free(A[0]); dv8_free(A[1]); \
+
+/**
+ * Initializes an sextadecic extension field with null.
+ *
+ * @param[out] A - the sextadecic extension element to initialize.
+ */
+#define fp16_null(A) \
+ fp8_null(A[0]); fp8_null(A[1]); \
+
+/**
+ * Allocates an sextadecic extension field element.
+ *
+ * @param[out] A - the new sextadecic extension field element.
+ */
+#define fp16_new(A) \
+ fp8_new(A[0]); fp8_new(A[1]); \
+
+/**
+ * Frees an sextadecic extension field element.
+ *
+ * @param[out] A - the sextadecic extension field element to free.
+ */
+#define fp16_free(A) \
+ fp8_free(A[0]); fp8_free(A[1]); \
+
+/**
+ * Multiplies two sextadecic extension field elements. Computes C = A * B.
+ *
+ * @param[out] C - the result.
+ * @param[in] A - the first sextadecic extension field element.
+ * @param[in] B - the second sextadecic extension field element.
+ */
+#if FPX_RDC == BASIC
+#define fp16_mul(C, A, B) fp16_mul_basic(C, A, B)
+#elif FPX_RDC == LAZYR
+#define fp16_mul(C, A, B) fp16_mul_lazyr(C, A, B)
+#endif
+
+/**
+ * Multiplies a dense and a sparse sextic extension field elements. Computes
+ * C = A * B.
+ *
+ * @param[out] C - the result.
+ * @param[in] A - the dense dodecic extension field element.
+ * @param[in] B - the sparse dodecic extension field element.
+ */
+#if FPX_RDC == BASIC
+#define fp16_mul_dxs(C, A, B) fp16_mul_dxs_basic(C, A, B)
+#elif FPX_RDC == LAZYR
+#define fp16_mul_dxs(C, A, B) fp16_mul_dxs_lazyr(C, A, B)
+#endif
+
+/**
+ * Squares an sextadecic extension field element. Computes C = A * A.
+ *
+ * @param[out] C - the result.
+ * @param[in] A - the sextadecic extension field element to square.
+ */
+#if FPX_RDC == BASIC
+#define fp16_sqr(C, A) fp16_sqr_basic(C, A)
+#elif FPX_RDC == LAZYR
+#define fp16_sqr(C, A) fp16_sqr_lazyr(C, A)
+#endif
+
/**
* Initializes a double-precision sextic extension field with null.
*
@@ -1641,6 +1747,14 @@ void fp2_exp_cyc_sim(fp2_t e, const fp2_t a, const bn_t b, const fp2_t c,
*/
void fp2_frb(fp2_t c, const fp2_t a, int i);
+/**
+ * Tests if a quadratic extension field element is a quadratic residue.
+ *
+ * @param[in] a - the prime field element to test.
+ * @return 1 if the argument is even, 0 otherwise.
+ */
+int fp2_is_sqr(const fp2_t a);
+
/**
* Extracts the square root of a quadratic extension field element. Computes
* c = sqrt(a). The other square root is the negation of c.
@@ -1966,6 +2080,14 @@ void fp3_exp(fp3_t c, const fp3_t a, const bn_t b);
*/
void fp3_frb(fp3_t c, const fp3_t a, int i);
+/**
+ * Tests if a cubic extension field element is a quadratic residue.
+ *
+ * @param[in] a - the prime field element to test.
+ * @return 1 if the argument is even, 0 otherwise.
+ */
+int fp3_is_sqr(const fp3_t a);
+
/**
* Extracts the square root of a cubic extension field element. Computes
* c = sqrt(a). The other square root is the negation of c.
@@ -2269,6 +2391,14 @@ void fp4_exp(fp4_t c, const fp4_t a, const bn_t b);
*/
void fp4_frb(fp4_t c, const fp4_t a, int i);
+/**
+ * Tests if a quartic extension field element is a quadratic residue.
+ *
+ * @param[in] a - the prime field element to test.
+ * @return 1 if the argument is even, 0 otherwise.
+ */
+int fp4_is_sqr(const fp4_t a);
+
/**
* Extracts the square root of a quartic extension field element. Computes
* c = sqrt(a). The other square root is the negation of c.
@@ -2508,6 +2638,11 @@ void fp6_exp(fp6_t c, const fp6_t a, const bn_t b);
*/
void fp6_frb(fp6_t c, const fp6_t a, int i);
+/**
+ * Initializes the octic extension field arithmetic module.
+ */
+void fp8_field_init(void);
+
/**
* Copies the second argument to the first argument.
*
@@ -2676,6 +2811,17 @@ void fp8_mul_lazyr(fp8_t c, const fp8_t a, const fp8_t b);
*/
void fp8_mul_art(fp8_t c, const fp8_t a);
+/**
+ * Multiplies an octic extension field element by a power of the constant
+ * needed to compute a power of the Frobenius map.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the field element to multiply.
+ * @param[in] i - the power of the Frobenius map.
+ * @param[in] j - the power of the constant.
+ */
+void fp8_mul_frb(fp8_t c, const fp8_t a, int i, int j);
+
/**
* Multiples a dense octic extension field element by a sparse element.
*
@@ -2773,6 +2919,15 @@ void fp8_conv_cyc(fp8_t c, const fp8_t a);
*/
void fp8_exp(fp8_t c, const fp8_t a, const bn_t b);
+/**
+ * Computes a power of an octic extension field element by a small exponent.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the basis.
+ * @param[in] b - the exponent.
+ */
+void fp8_exp_dig(fp8_t c, const fp8_t a, dig_t b);
+
/**
* Computes a power of a cyclotomic octic extension field element.
*
@@ -2792,6 +2947,24 @@ void fp8_exp_cyc(fp8_t c, const fp8_t a, const bn_t b);
*/
void fp8_frb(fp8_t c, const fp8_t a, int i);
+/**
+ * Tests if an octic extension field element is a quadratic residue.
+ *
+ * @param[in] a - the prime field element to test.
+ * @return 1 if the argument is even, 0 otherwise.
+ */
+int fp8_is_sqr(const fp8_t a);
+
+/**
+ * Extracts the square root of an octic extension field element. Computes
+ * c = sqrt(a). The other square root is the negation of c.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element.
+ * @return - 1 if there is a square root, 0 otherwise.
+ */
+int fp8_srt(fp8_t c, const fp8_t a);
+
/**
* Copies the second argument to the first argument.
*
@@ -3432,6 +3605,337 @@ void fp12_pck_max(fp12_t c, const fp12_t a);
*/
int fp12_upk_max(fp12_t c, const fp12_t a);
+
+/**
+ * Initializes the sextadecic extension field arithmetic module.
+ */
+void fp16_field_init(void);
+
+/**
+ * Copies the second argument to the first argument.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to copy.
+ */
+void fp16_copy(fp16_t c, const fp16_t a);
+
+/**
+ * Assigns zero to an sextadecic extension field element.
+ *
+ * @param[out] a - the sextadecic extension field element to zero.
+ */
+void fp16_zero(fp16_t a);
+
+/**
+ * Tests if an sextadecic extension field element is zero or not.
+ *
+ * @param[in] a - the sextadecic extension field element to test.
+ * @return 1 if the argument is zero, 0 otherwise.
+ */
+int fp16_is_zero(const fp16_t a);
+
+/**
+ * Assigns a random value to an sextadecic extension field element.
+ *
+ * @param[out] a - the sextadecic extension field element to assign.
+ */
+void fp16_rand(fp16_t a);
+
+/**
+ * Prints an sextadecic extension field element to standard output.
+ *
+ * @param[in] a - the sextadecic extension field element to print.
+ */
+void fp16_print(const fp16_t a);
+
+/**
+ * Returns the number of bytes necessary to store an sextadecic extension field
+ * element.
+ *
+ * @param[in] a - the extension field element.
+ * @param[in] pack - the flag to indicate compression.
+ * @return the number of bytes.
+ */
+int fp16_size_bin(fp16_t a, int pack);
+
+/**
+ * Reads an sextadecic extension field element from a byte vector in big-endian
+ * format.
+ *
+ * @param[out] a - the result.
+ * @param[in] bin - the byte vector.
+ * @param[in] len - the buffer capacity.
+ * @throw ERR_NO_BUFFER - if the buffer capacity is not correct.
+ */
+void fp16_read_bin(fp16_t a, const uint8_t *bin, size_t len);
+
+/**
+ * Writes an sextadecic extension field element to a byte vector in big-endian
+ * format.
+ *
+ * @param[out] bin - the byte vector.
+ * @param[in] len - the buffer capacity.
+ * @param[in] a - the extension field element to write.
+ * @param[in] pack - the flag to indicate compression.
+ * @throw ERR_NO_BUFFER - if the buffer capacity is not correct.
+ */
+void fp16_write_bin(uint8_t *bin, size_t len, const fp16_t a, int pack);
+
+/**
+ * Returns the result of a comparison between two sextadecic extension field
+ * elements.
+ *
+ * @param[in] a - the first sextadecic extension field element.
+ * @param[in] b - the second sextadecic extension field element.
+ * @return RLC_EQ if a == b, and RLC_NE otherwise.
+ */
+int fp16_cmp(const fp16_t a, const fp16_t b);
+
+/**
+ * Returns the result of a signed comparison between an sextadecic extension
+ * field element and a digit.
+ *
+ * @param[in] a - the sextadecic extension field element.
+ * @param[in] b - the digit.
+ * @return RLC_EQ if a == b, and RLC_NE otherwise.
+ */
+int fp16_cmp_dig(const fp16_t a, const dig_t b);
+
+/**
+ * Assigns an sextadecic extension field element to a digit.
+ *
+ * @param[in] a - the sextadecic extension field element.
+ * @param[in] b - the digit.
+ */
+void fp16_set_dig(fp16_t a, const dig_t b);
+
+/**
+ * Adds two sextadecic extension field elements. Computes c = a + b.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the first sextadecic extension field element.
+ * @param[in] b - the second sextadecic extension field element.
+ */
+void fp16_add(fp16_t c, const fp16_t a, const fp16_t b);
+
+/**
+ * Subtracts an sextadecic extension field element from another. Computes
+ * c = a - b.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element.
+ * @param[in] b - the sextadecic extension field element.
+ */
+void fp16_sub(fp16_t c, const fp16_t a, const fp16_t b);
+
+/**
+ * Negates an sextadecic extension field element. Computes c = -a.
+ *
+ * @param[out] c - the result.
+ * @param[out] a - the sextadecic extension field element to negate.
+ */
+void fp16_neg(fp16_t c, const fp16_t a);
+
+/**
+ * Doubles an sextadecic extension field element. Computes c = 2 * a.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to double.
+ */
+void fp16_dbl(fp16_t c, const fp16_t a);
+
+/**
+ * Multiples two sextadecic extension field elements without performing modular
+ * reduction.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element.
+ * @param[in] b - the sextadecic extension field element.
+ */
+void fp16_mul_unr(dv16_t c, const fp16_t a, const fp16_t b);
+
+/**
+ * Multiples two sextadecic extension field elements.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element.
+ * @param[in] b - the sextadecic extension field element.
+ */
+void fp16_mul_basic(fp16_t c, const fp16_t a, const fp16_t b);
+
+/**
+ * Multiples two sextadecic extension field elements using lazy reduction.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element.
+ * @param[in] b - the sextadecic extension field element.
+ */
+void fp16_mul_lazyr(fp16_t c, const fp16_t a, const fp16_t b);
+
+/**
+ * Multiplies an sextadecic extension field element by the adjoined root.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to multiply.
+ */
+void fp16_mul_art(fp16_t c, const fp16_t a);
+
+/**
+ * Multiplies an sextadecic extension field element by a power of the constant
+ * needed to compute a power of the Frobenius map.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the field element to multiply.
+ * @param[in] i - the power of the Frobenius map.
+ * @param[in] j - the power of the constant.
+ */
+void fp16_mul_frb(fp16_t c, const fp16_t a, int i, int j);
+
+/**
+ * Multiples a dense sextadecic extension field element by a sparse element.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - an sextadecic extension field element.
+ * @param[in] b - a sparse sextadecic extension field element.
+ */
+void fp16_mul_dxs(fp16_t c, const fp16_t a, const fp16_t b);
+
+/**
+ * Computes the square of an sextadecic extension field element without
+ * performing modular reduction.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to square.
+ */
+void fp16_sqr_unr(dv16_t c, const fp16_t a);
+
+/**
+ * Computes the squares of an sextadecic extension field element using basic
+ * arithmetic.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to square.
+ */
+void fp16_sqr_basic(fp16_t c, const fp16_t a);
+
+/**
+ * Computes the square of an sextadecic extension field element using lazy
+ * reduction.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to square.
+ */
+void fp16_sqr_lazyr(fp16_t c, const fp16_t a);
+
+/**
+ * Computes the square of a cyclotomic sextadecic extension field element.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the cyclotomic extension element to square.
+ */
+void fp16_sqr_cyc(fp16_t c, const fp16_t a);
+
+/**
+ * Inverts an sextadecic extension field element. Computes c = 1/a.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to invert.
+ */
+void fp16_inv(fp16_t c, const fp16_t a);
+
+/**
+ * Computes the inverse of a cyclotomic sextadecic extension field element.
+ *
+ * For cyclotomic elements, this is equivalent to computing the conjugate.
+ * A cyclotomic element is one previously raised to the (p^4 - 1)-th power.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element to invert.
+ */
+void fp16_inv_cyc(fp16_t c, const fp16_t a);
+
+/**
+ * Inverts multiple sextadecic extension field elements simultaneously.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field elements to invert.
+ * @param[in] n - the number of elements.
+ */
+void fp16_inv_sim(fp16_t *c, const fp16_t *a, int n);
+
+/**
+ * Tests if an sextadecic extension field element is cyclotomic.
+ *
+ * @param[in] a - the sextadecic extension field element to test.
+ * @return 1 if the extension field element is cyclotomic, 0 otherwise.
+ */
+int fp16_test_cyc(const fp16_t a);
+
+/**
+ * Converts an sextadecic extension field element to a cyclotomic element.
+ * Computes c = a^(p^8 - 1).
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension field element.
+ */
+void fp16_conv_cyc(fp16_t c, const fp16_t a);
+
+/**
+ * Computes a power of an sextadecic extension field element. Computes c = a^b.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the sextadecic extension element to exponentiate.
+ * @param[in] b - the exponent.
+ */
+void fp16_exp(fp16_t c, const fp16_t a, const bn_t b);
+
+/**
+ * Computes a power of a sextic extension field element by a small exponent.
+ * Faster formulas are used if the extension field element is cyclotomic.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the basis.
+ * @param[in] b - the exponent.
+ */
+void fp16_exp_dig(fp16_t c, const fp16_t a, dig_t b);
+
+/**
+ * Computes a power of a cyclotomic sextadecic extension field element.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the basis.
+ * @param[in] b - the exponent.
+ */
+void fp16_exp_cyc(fp16_t c, const fp16_t a, const bn_t b);
+
+/**
+ * Computes a power of the Frobenius endomorphism of an sextadecic extension
+ * field element. Computes c = a^p^i.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - an sextadecic extension field element.
+ * @param[in] i - the power of the Frobenius map.
+ */
+void fp16_frb(fp16_t c, const fp16_t a, int i);
+
+/**
+ * Tests if an sextadecic extension field element is a quadratic residue.
+ *
+ * @param[in] a - the prime field element to test.
+ * @return 1 if the argument is even, 0 otherwise.
+ */
+int fp16_is_sqr(const fp16_t a);
+
+/**
+ * Extracts the square root of an sextadecic extension field element. Computes
+ * c = sqrt(a). The other square root is the negation of c.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element.
+ * @return - 1 if there is a square root, 0 otherwise.
+ */
+int fp16_srt(fp16_t c, const fp16_t a);
+
/**
* Copies the second argument to the first argument.
*
@@ -3759,7 +4263,7 @@ void fp18_frb(fp18_t c, const fp18_t a, int i);
void fp18_exp(fp18_t c, const fp18_t a, const bn_t b);
/**
- * Computes a power of a dodecic extension field element by a small exponent.
+ * Computes a power of a octdecic extension field element by a small exponent.
* Faster formulas are used if the extension field element is cyclotomic.
*
* @param[out] c - the result.
diff --git a/include/relic_label.h b/include/relic_label.h
index f3850f24a..6abb25b5e 100644
--- a/include/relic_label.h
+++ b/include/relic_label.h
@@ -462,6 +462,8 @@
#undef fp_prime_get
#undef fp_prime_get_rdc
#undef fp_prime_get_conv
+#undef fp_prime_get_srt
+#undef fp_prime_get_crt
#undef fp_prime_get_mod8
#undef fp_prime_get_mod18
#undef fp_prime_get_sps
@@ -495,6 +497,7 @@
#undef fp_set_dig
#undef fp_bits
#undef fp_rand
+#undef fp_norm
#undef fp_print
#undef fp_size_str
#undef fp_read_str
@@ -539,20 +542,24 @@
#undef fp_inv_lower
#undef fp_inv_sim
#undef fp_smb_basic
-#undef fp_smb_binar
#undef fp_smb_divst
#undef fp_smb_jmpds
#undef fp_smb_lower
#undef fp_exp_basic
#undef fp_exp_slide
#undef fp_exp_monty
+#undef fp_is_sqr
#undef fp_srt
+#undef fp_is_cub
+#undef fp_crt
#define fp_prime_init RLC_PREFIX(fp_prime_init)
#define fp_prime_clean RLC_PREFIX(fp_prime_clean)
#define fp_prime_get RLC_PREFIX(fp_prime_get)
#define fp_prime_get_rdc RLC_PREFIX(fp_prime_get_rdc)
#define fp_prime_get_conv RLC_PREFIX(fp_prime_get_conv)
+#define fp_prime_get_srt RLC_PREFIX(fp_prime_get_srt)
+#define fp_prime_get_crt RLC_PREFIX(fp_prime_get_crt)
#define fp_prime_get_mod8 RLC_PREFIX(fp_prime_get_mod8)
#define fp_prime_get_mod18 RLC_PREFIX(fp_prime_get_mod18)
#define fp_prime_get_sps RLC_PREFIX(fp_prime_get_sps)
@@ -586,6 +593,7 @@
#define fp_set_dig RLC_PREFIX(fp_set_dig)
#define fp_bits RLC_PREFIX(fp_bits)
#define fp_rand RLC_PREFIX(fp_rand)
+#define fp_norm RLC_PREFIX(fp_norm)
#define fp_print RLC_PREFIX(fp_print)
#define fp_size_str RLC_PREFIX(fp_size_str)
#define fp_read_str RLC_PREFIX(fp_read_str)
@@ -630,14 +638,16 @@
#define fp_inv_lower RLC_PREFIX(fp_inv_lower)
#define fp_inv_sim RLC_PREFIX(fp_inv_sim)
#define fp_smb_basic RLC_PREFIX(fp_smb_basic)
-#define fp_smb_binar RLC_PREFIX(fp_smb_binar)
#define fp_smb_divst RLC_PREFIX(fp_smb_divst)
#define fp_smb_jmpds RLC_PREFIX(fp_smb_jmpds)
#define fp_smb_lower RLC_PREFIX(fp_smb_lower)
#define fp_exp_basic RLC_PREFIX(fp_exp_basic)
#define fp_exp_slide RLC_PREFIX(fp_exp_slide)
#define fp_exp_monty RLC_PREFIX(fp_exp_monty)
+#define fp_is_sqr RLC_PREFIX(fp_is_sqr)
#define fp_srt RLC_PREFIX(fp_srt)
+#define fp_is_cub RLC_PREFIX(fp_is_cub)
+#define fp_crt RLC_PREFIX(fp_crt)
#undef fp_add1_low
#undef fp_addn_low
@@ -964,6 +974,7 @@
#undef ep_mul_lwreg
#undef ep_mul_gen
#undef ep_mul_dig
+#undef ep_mul_cof
#undef ep_mul_pre_basic
#undef ep_mul_pre_yaowi
#undef ep_mul_pre_nafwi
@@ -985,9 +996,9 @@
#undef ep_mul_sim_dig
#undef ep_norm
#undef ep_norm_sim
-#undef ep_map_from_field
-#undef ep_map
-#undef ep_map_dst
+#undef ep_map_basic
+#undef ep_map_sswum
+#undef ep_map_swift
#undef ep_pck
#undef ep_upk
@@ -1058,6 +1069,7 @@
#define ep_mul_lwreg RLC_PREFIX(ep_mul_lwreg)
#define ep_mul_gen RLC_PREFIX(ep_mul_gen)
#define ep_mul_dig RLC_PREFIX(ep_mul_dig)
+#define ep_mul_cof RLC_PREFIX(ep_mul_cof)
#define ep_mul_pre_basic RLC_PREFIX(ep_mul_pre_basic)
#define ep_mul_pre_yaowi RLC_PREFIX(ep_mul_pre_yaowi)
#define ep_mul_pre_nafwi RLC_PREFIX(ep_mul_pre_nafwi)
@@ -1079,9 +1091,9 @@
#define ep_mul_sim_dig RLC_PREFIX(ep_mul_sim_dig)
#define ep_norm RLC_PREFIX(ep_norm)
#define ep_norm_sim RLC_PREFIX(ep_norm_sim)
-#define ep_map_from_field RLC_PREFIX(ep_map_from_field)
-#define ep_map RLC_PREFIX(ep_map)
-#define ep_map_dst RLC_PREFIX(ep_map_dst)
+#define ep_map_basic RLC_PREFIX(ep_map_basic)
+#define ep_map_sswum RLC_PREFIX(ep_map_sswum)
+#define ep_map_swift RLC_PREFIX(ep_map_swift)
#define ep_pck RLC_PREFIX(ep_pck)
#define ep_upk RLC_PREFIX(ep_upk)
@@ -1386,7 +1398,6 @@
#undef ep2_curve_clean
#undef ep2_curve_get_a
#undef ep2_curve_get_b
-#undef ep2_curve_get_vs
#undef ep2_curve_opt_a
#undef ep2_curve_opt_b
#undef ep2_curve_is_twist
@@ -1448,9 +1459,9 @@
#undef ep2_mul_sim_dig
#undef ep2_norm
#undef ep2_norm_sim
-#undef ep2_map_from_field
-#undef ep2_map
-#undef ep2_map_dst
+#undef ep2_map_basic
+#undef ep2_map_sswum
+#undef ep2_map_swift
#undef ep2_frb
#undef ep2_pck
#undef ep2_upk
@@ -1459,7 +1470,6 @@
#define ep2_curve_clean RLC_PREFIX(ep2_curve_clean)
#define ep2_curve_get_a RLC_PREFIX(ep2_curve_get_a)
#define ep2_curve_get_b RLC_PREFIX(ep2_curve_get_b)
-#define ep2_curve_get_vs RLC_PREFIX(ep2_curve_get_vs)
#define ep2_curve_opt_a RLC_PREFIX(ep2_curve_opt_a)
#define ep2_curve_opt_b RLC_PREFIX(ep2_curve_opt_b)
#define ep2_curve_is_twist RLC_PREFIX(ep2_curve_is_twist)
@@ -1521,9 +1531,9 @@
#define ep2_mul_sim_dig RLC_PREFIX(ep2_mul_sim_dig)
#define ep2_norm RLC_PREFIX(ep2_norm)
#define ep2_norm_sim RLC_PREFIX(ep2_norm_sim)
-#define ep2_map_from_field RLC_PREFIX(ep2_map_from_field)
-#define ep2_map RLC_PREFIX(ep2_map)
-#define ep2_map_dst RLC_PREFIX(ep2_map_dst)
+#define ep2_map_basic RLC_PREFIX(ep2_map_basic)
+#define ep2_map_sswum RLC_PREFIX(ep2_map_sswum)
+#define ep2_map_swift RLC_PREFIX(ep2_map_swift)
#define ep2_frb RLC_PREFIX(ep2_frb)
#define ep2_pck RLC_PREFIX(ep2_pck)
#define ep2_upk RLC_PREFIX(ep2_upk)
@@ -1537,7 +1547,6 @@
#undef ep3_curve_clean
#undef ep3_curve_get_a
#undef ep3_curve_get_b
-#undef ep3_curve_get_vs
#undef ep3_curve_opt_a
#undef ep3_curve_opt_b
#undef ep3_curve_is_twist
@@ -1598,7 +1607,6 @@
#undef ep3_norm
#undef ep3_norm_sim
#undef ep3_map
-#undef ep3_map_dst
#undef ep3_frb
#undef ep3_pck
#undef ep3_upk
@@ -1607,7 +1615,6 @@
#define ep3_curve_clean RLC_PREFIX(ep3_curve_clean)
#define ep3_curve_get_a RLC_PREFIX(ep3_curve_get_a)
#define ep3_curve_get_b RLC_PREFIX(ep3_curve_get_b)
-#define ep3_curve_get_vs RLC_PREFIX(ep3_curve_get_vs)
#define ep3_curve_opt_a RLC_PREFIX(ep3_curve_opt_a)
#define ep3_curve_opt_b RLC_PREFIX(ep3_curve_opt_b)
#define ep3_curve_is_twist RLC_PREFIX(ep3_curve_is_twist)
@@ -1668,7 +1675,6 @@
#define ep3_norm RLC_PREFIX(ep3_norm)
#define ep3_norm_sim RLC_PREFIX(ep3_norm_sim)
#define ep3_map RLC_PREFIX(ep3_map)
-#define ep3_map_dst RLC_PREFIX(ep3_map_dst)
#define ep3_frb RLC_PREFIX(ep3_frb)
#define ep3_pck RLC_PREFIX(ep3_pck)
#define ep3_upk RLC_PREFIX(ep3_upk)
@@ -1682,7 +1688,6 @@
#undef ep4_curve_clean
#undef ep4_curve_get_a
#undef ep4_curve_get_b
-#undef ep4_curve_get_vs
#undef ep4_curve_opt_a
#undef ep4_curve_opt_b
#undef ep4_curve_is_twist
@@ -1743,7 +1748,6 @@
#undef ep4_norm
#undef ep4_norm_sim
#undef ep4_map
-#undef ep4_map_dst
#undef ep4_frb
#undef ep4_pck
#undef ep4_upk
@@ -1752,7 +1756,6 @@
#define ep4_curve_clean RLC_PREFIX(ep4_curve_clean)
#define ep4_curve_get_a RLC_PREFIX(ep4_curve_get_a)
#define ep4_curve_get_b RLC_PREFIX(ep4_curve_get_b)
-#define ep4_curve_get_vs RLC_PREFIX(ep4_curve_get_vs)
#define ep4_curve_opt_a RLC_PREFIX(ep4_curve_opt_a)
#define ep4_curve_opt_b RLC_PREFIX(ep4_curve_opt_b)
#define ep4_curve_is_twist RLC_PREFIX(ep4_curve_is_twist)
@@ -1813,11 +1816,151 @@
#define ep4_norm RLC_PREFIX(ep4_norm)
#define ep4_norm_sim RLC_PREFIX(ep4_norm_sim)
#define ep4_map RLC_PREFIX(ep4_map)
-#define ep4_map_dst RLC_PREFIX(ep4_map_dst)
#define ep4_frb RLC_PREFIX(ep4_frb)
#define ep4_pck RLC_PREFIX(ep4_pck)
#define ep4_upk RLC_PREFIX(ep4_upk)
+#undef ep8_st
+#undef ep8_t
+#define ep8_st RLC_PREFIX(ep8_st)
+#define ep8_t RLC_PREFIX(ep8_t)
+
+#undef ep8_curve_init
+#undef ep8_curve_clean
+#undef ep8_curve_get_a
+#undef ep8_curve_get_b
+#undef ep8_curve_opt_a
+#undef ep8_curve_opt_b
+#undef ep8_curve_is_twist
+#undef ep8_curve_get_gen
+#undef ep8_curve_get_tab
+#undef ep8_curve_get_ord
+#undef ep8_curve_get_cof
+#undef ep8_curve_set
+#undef ep8_curve_set_twist
+#undef ep8_is_infty
+#undef ep8_set_infty
+#undef ep8_copy
+#undef ep8_cmp
+#undef ep8_rand
+#undef ep8_blind
+#undef ep8_rhs
+#undef ep8_on_curve
+#undef ep8_tab
+#undef ep8_print
+#undef ep8_size_bin
+#undef ep8_read_bin
+#undef ep8_write_bin
+#undef ep8_neg
+#undef ep8_add_basic
+#undef ep8_add_slp_basic
+#undef ep8_add_projc
+#undef ep8_sub
+#undef ep8_dbl_basic
+#undef ep8_dbl_slp_basic
+#undef ep8_dbl_projc
+#undef ep8_mul_basic
+#undef ep8_mul_slide
+#undef ep8_mul_monty
+#undef ep8_mul_lwnaf
+#undef ep8_mul_lwreg
+#undef ep8_mul_gen
+#undef ep8_mul_dig
+#undef ep8_mul_cof
+#undef ep8_mul_pre_basic
+#undef ep8_mul_pre_yaowi
+#undef ep8_mul_pre_nafwi
+#undef ep8_mul_pre_combs
+#undef ep8_mul_pre_combd
+#undef ep8_mul_pre_lwnaf
+#undef ep8_mul_fix_basic
+#undef ep8_mul_fix_yaowi
+#undef ep8_mul_fix_nafwi
+#undef ep8_mul_fix_combs
+#undef ep8_mul_fix_combd
+#undef ep8_mul_fix_lwnaf
+#undef ep8_mul_sim_basic
+#undef ep8_mul_sim_trick
+#undef ep8_mul_sim_inter
+#undef ep8_mul_sim_joint
+#undef ep8_mul_sim_lot
+#undef ep8_mul_sim_gen
+#undef ep8_mul_sim_dig
+#undef ep8_norm
+#undef ep8_norm_sim
+#undef ep8_map
+#undef ep8_frb
+#undef ep8_pck
+#undef ep8_upk
+
+#define ep8_curve_init RLC_PREFIX(ep8_curve_init)
+#define ep8_curve_clean RLC_PREFIX(ep8_curve_clean)
+#define ep8_curve_get_a RLC_PREFIX(ep8_curve_get_a)
+#define ep8_curve_get_b RLC_PREFIX(ep8_curve_get_b)
+#define ep8_curve_opt_a RLC_PREFIX(ep8_curve_opt_a)
+#define ep8_curve_opt_b RLC_PREFIX(ep8_curve_opt_b)
+#define ep8_curve_is_twist RLC_PREFIX(ep8_curve_is_twist)
+#define ep8_curve_get_gen RLC_PREFIX(ep8_curve_get_gen)
+#define ep8_curve_get_tab RLC_PREFIX(ep8_curve_get_tab)
+#define ep8_curve_get_ord RLC_PREFIX(ep8_curve_get_ord)
+#define ep8_curve_get_cof RLC_PREFIX(ep8_curve_get_cof)
+#define ep8_curve_set RLC_PREFIX(ep8_curve_set)
+#define ep8_curve_set_twist RLC_PREFIX(ep8_curve_set_twist)
+#define ep8_is_infty RLC_PREFIX(ep8_is_infty)
+#define ep8_set_infty RLC_PREFIX(ep8_set_infty)
+#define ep8_copy RLC_PREFIX(ep8_copy)
+#define ep8_cmp RLC_PREFIX(ep8_cmp)
+#define ep8_rand RLC_PREFIX(ep8_rand)
+#define ep8_blind RLC_PREFIX(ep8_blind)
+#define ep8_rhs RLC_PREFIX(ep8_rhs)
+#define ep8_on_curve RLC_PREFIX(ep8_on_curve)
+#define ep8_tab RLC_PREFIX(ep8_tab)
+#define ep8_print RLC_PREFIX(ep8_print)
+#define ep8_size_bin RLC_PREFIX(ep8_size_bin)
+#define ep8_read_bin RLC_PREFIX(ep8_read_bin)
+#define ep8_write_bin RLC_PREFIX(ep8_write_bin)
+#define ep8_neg RLC_PREFIX(ep8_neg)
+#define ep8_add_basic RLC_PREFIX(ep8_add_basic)
+#define ep8_add_slp_basic RLC_PREFIX(ep8_add_slp_basic)
+#define ep8_add_projc RLC_PREFIX(ep8_add_projc)
+#define ep8_sub RLC_PREFIX(ep8_sub)
+#define ep8_dbl_basic RLC_PREFIX(ep8_dbl_basic)
+#define ep8_dbl_slp_basic RLC_PREFIX(ep8_dbl_slp_basic)
+#define ep8_dbl_projc RLC_PREFIX(ep8_dbl_projc)
+#define ep8_mul_basic RLC_PREFIX(ep8_mul_basic)
+#define ep8_mul_slide RLC_PREFIX(ep8_mul_slide)
+#define ep8_mul_monty RLC_PREFIX(ep8_mul_monty)
+#define ep8_mul_lwnaf RLC_PREFIX(ep8_mul_lwnaf)
+#define ep8_mul_lwreg RLC_PREFIX(ep8_mul_lwreg)
+#define ep8_mul_gen RLC_PREFIX(ep8_mul_gen)
+#define ep8_mul_dig RLC_PREFIX(ep8_mul_dig)
+#define ep8_mul_cof RLC_PREFIX(ep8_mul_cof)
+#define ep8_mul_pre_basic RLC_PREFIX(ep8_mul_pre_basic)
+#define ep8_mul_pre_yaowi RLC_PREFIX(ep8_mul_pre_yaowi)
+#define ep8_mul_pre_nafwi RLC_PREFIX(ep8_mul_pre_nafwi)
+#define ep8_mul_pre_combs RLC_PREFIX(ep8_mul_pre_combs)
+#define ep8_mul_pre_combd RLC_PREFIX(ep8_mul_pre_combd)
+#define ep8_mul_pre_lwnaf RLC_PREFIX(ep8_mul_pre_lwnaf)
+#define ep8_mul_fix_basic RLC_PREFIX(ep8_mul_fix_basic)
+#define ep8_mul_fix_yaowi RLC_PREFIX(ep8_mul_fix_yaowi)
+#define ep8_mul_fix_nafwi RLC_PREFIX(ep8_mul_fix_nafwi)
+#define ep8_mul_fix_combs RLC_PREFIX(ep8_mul_fix_combs)
+#define ep8_mul_fix_combd RLC_PREFIX(ep8_mul_fix_combd)
+#define ep8_mul_fix_lwnaf RLC_PREFIX(ep8_mul_fix_lwnaf)
+#define ep8_mul_sim_basic RLC_PREFIX(ep8_mul_sim_basic)
+#define ep8_mul_sim_trick RLC_PREFIX(ep8_mul_sim_trick)
+#define ep8_mul_sim_inter RLC_PREFIX(ep8_mul_sim_inter)
+#define ep8_mul_sim_joint RLC_PREFIX(ep8_mul_sim_joint)
+#define ep8_mul_sim_lot RLC_PREFIX(ep8_mul_sim_lot)
+#define ep8_mul_sim_gen RLC_PREFIX(ep8_mul_sim_gen)
+#define ep8_mul_sim_dig RLC_PREFIX(ep8_mul_sim_dig)
+#define ep8_norm RLC_PREFIX(ep8_norm)
+#define ep8_norm_sim RLC_PREFIX(ep8_norm_sim)
+#define ep8_map RLC_PREFIX(ep8_map)
+#define ep8_frb RLC_PREFIX(ep8_frb)
+#define ep8_pck RLC_PREFIX(ep8_pck)
+#define ep8_upk RLC_PREFIX(ep8_upk)
+
#undef fp2_st
#undef fp2_t
#undef dv2_t
@@ -1879,8 +2022,6 @@
#define fp54_t RLC_PREFIX(fp54_t)
#define dv54_t RLC_PREFIX(dv54_t)
-#undef fp2_add_dig
-#undef fp2_sub_dig
#undef fp2_field_init
#undef fp2_field_get_qnr
#undef fp2_copy
@@ -1896,8 +2037,10 @@
#undef fp2_set_dig
#undef fp2_add_basic
#undef fp2_add_integ
+#undef fp2_add_dig
#undef fp2_sub_basic
#undef fp2_sub_integ
+#undef fp2_sub_dig
#undef fp2_neg
#undef fp2_dbl_basic
#undef fp2_dbl_integ
@@ -1920,12 +2063,11 @@
#undef fp2_exp_cyc
#undef fp2_exp_cyc_sim
#undef fp2_frb
+#undef fp2_is_sqr
#undef fp2_srt
#undef fp2_pck
#undef fp2_upk
-#define fp2_add_dig RLC_PREFIX(fp2_add_dig)
-#define fp2_sub_dig RLC_PREFIX(fp2_sub_dig)
#define fp2_field_init RLC_PREFIX(fp2_field_init)
#define fp2_field_get_qnr RLC_PREFIX(fp2_field_get_qnr)
#define fp2_copy RLC_PREFIX(fp2_copy)
@@ -1941,8 +2083,10 @@
#define fp2_set_dig RLC_PREFIX(fp2_set_dig)
#define fp2_add_basic RLC_PREFIX(fp2_add_basic)
#define fp2_add_integ RLC_PREFIX(fp2_add_integ)
+#define fp2_add_dig RLC_PREFIX(fp2_add_dig)
#define fp2_sub_basic RLC_PREFIX(fp2_sub_basic)
#define fp2_sub_integ RLC_PREFIX(fp2_sub_integ)
+#define fp2_sub_dig RLC_PREFIX(fp2_sub_dig)
#define fp2_neg RLC_PREFIX(fp2_neg)
#define fp2_dbl_basic RLC_PREFIX(fp2_dbl_basic)
#define fp2_dbl_integ RLC_PREFIX(fp2_dbl_integ)
@@ -1965,6 +2109,7 @@
#define fp2_exp_cyc RLC_PREFIX(fp2_exp_cyc)
#define fp2_exp_cyc_sim RLC_PREFIX(fp2_exp_cyc_sim)
#define fp2_frb RLC_PREFIX(fp2_frb)
+#define fp2_is_sqr RLC_PREFIX(fp2_is_sqr)
#define fp2_srt RLC_PREFIX(fp2_srt)
#define fp2_pck RLC_PREFIX(fp2_pck)
#define fp2_upk RLC_PREFIX(fp2_upk)
@@ -2022,8 +2167,10 @@
#undef fp3_set_dig
#undef fp3_add_basic
#undef fp3_add_integ
+#undef fp3_add_dig
#undef fp3_sub_basic
#undef fp3_sub_integ
+#undef fp3_sub_dig
#undef fp3_neg
#undef fp3_dbl_basic
#undef fp3_dbl_integ
@@ -2032,12 +2179,14 @@
#undef fp3_mul_art
#undef fp3_mul_nor
#undef fp3_mul_frb
+#undef fp3_mul_dig
#undef fp3_sqr_basic
#undef fp3_sqr_integ
#undef fp3_inv
#undef fp3_inv_sim
#undef fp3_exp
#undef fp3_frb
+#undef fp3_is_sqr
#undef fp3_srt
#define fp3_field_init RLC_PREFIX(fp3_field_init)
@@ -2055,8 +2204,10 @@
#define fp3_set_dig RLC_PREFIX(fp3_set_dig)
#define fp3_add_basic RLC_PREFIX(fp3_add_basic)
#define fp3_add_integ RLC_PREFIX(fp3_add_integ)
+#define fp3_add_dig RLC_PREFIX(fp3_add_dig)
#define fp3_sub_basic RLC_PREFIX(fp3_sub_basic)
#define fp3_sub_integ RLC_PREFIX(fp3_sub_integ)
+#define fp3_sub_dig RLC_PREFIX(fp3_sub_dig)
#define fp3_neg RLC_PREFIX(fp3_neg)
#define fp3_dbl_basic RLC_PREFIX(fp3_dbl_basic)
#define fp3_dbl_integ RLC_PREFIX(fp3_dbl_integ)
@@ -2065,12 +2216,14 @@
#define fp3_mul_art RLC_PREFIX(fp3_mul_art)
#define fp3_mul_nor RLC_PREFIX(fp3_mul_nor)
#define fp3_mul_frb RLC_PREFIX(fp3_mul_frb)
+#define fp3_mul_dig RLC_PREFIX(fp3_mul_dig)
#define fp3_sqr_basic RLC_PREFIX(fp3_sqr_basic)
#define fp3_sqr_integ RLC_PREFIX(fp3_sqr_integ)
#define fp3_inv RLC_PREFIX(fp3_inv)
#define fp3_inv_sim RLC_PREFIX(fp3_inv_sim)
#define fp3_exp RLC_PREFIX(fp3_exp)
#define fp3_frb RLC_PREFIX(fp3_frb)
+#define fp3_is_sqr RLC_PREFIX(fp3_is_sqr)
#define fp3_srt RLC_PREFIX(fp3_srt)
#undef fp3_addn_low
@@ -2122,7 +2275,9 @@
#undef fp4_cmp_dig
#undef fp4_set_dig
#undef fp4_add
+#undef fp4_add_dig
#undef fp4_sub
+#undef fp4_sub_dig
#undef fp4_neg
#undef fp4_dbl
#undef fp4_mul_unr
@@ -2130,6 +2285,7 @@
#undef fp4_mul_lazyr
#undef fp4_mul_art
#undef fp4_mul_frb
+#undef fp4_mul_dig
#undef fp4_mul_dxs
#undef fp4_sqr_unr
#undef fp4_sqr_basic
@@ -2139,6 +2295,7 @@
#undef fp4_inv_cyc
#undef fp4_exp
#undef fp4_frb
+#undef fp4_is_sqr
#undef fp4_srt
#define fp4_field_init RLC_PREFIX(fp4_field_init)
@@ -2154,7 +2311,9 @@
#define fp4_cmp_dig RLC_PREFIX(fp4_cmp_dig)
#define fp4_set_dig RLC_PREFIX(fp4_set_dig)
#define fp4_add RLC_PREFIX(fp4_add)
+#define fp4_add_dig RLC_PREFIX(fp4_add_dig)
#define fp4_sub RLC_PREFIX(fp4_sub)
+#define fp4_sub_dig RLC_PREFIX(fp4_sub_dig)
#define fp4_neg RLC_PREFIX(fp4_neg)
#define fp4_dbl RLC_PREFIX(fp4_dbl)
#define fp4_mul_unr RLC_PREFIX(fp4_mul_unr)
@@ -2162,6 +2321,7 @@
#define fp4_mul_lazyr RLC_PREFIX(fp4_mul_lazyr)
#define fp4_mul_art RLC_PREFIX(fp4_mul_art)
#define fp4_mul_frb RLC_PREFIX(fp4_mul_frb)
+#define fp4_mul_dig RLC_PREFIX(fp4_mul_dig)
#define fp4_mul_dxs RLC_PREFIX(fp4_mul_dxs)
#define fp4_sqr_unr RLC_PREFIX(fp4_sqr_unr)
#define fp4_sqr_basic RLC_PREFIX(fp4_sqr_basic)
@@ -2171,6 +2331,7 @@
#define fp4_inv_cyc RLC_PREFIX(fp4_inv_cyc)
#define fp4_exp RLC_PREFIX(fp4_exp)
#define fp4_frb RLC_PREFIX(fp4_frb)
+#define fp4_is_sqr RLC_PREFIX(fp4_is_sqr)
#define fp4_srt RLC_PREFIX(fp4_srt)
#undef fp6_copy
@@ -2227,6 +2388,7 @@
#define fp6_exp RLC_PREFIX(fp6_exp)
#define fp6_frb RLC_PREFIX(fp6_frb)
+#undef fp8_field_init
#undef fp8_copy
#undef fp8_zero
#undef fp8_is_zero
@@ -2246,6 +2408,7 @@
#undef fp8_mul_basic
#undef fp8_mul_lazyr
#undef fp8_mul_art
+#undef fp8_mul_frb
#undef fp8_mul_dxs
#undef fp8_sqr_unr
#undef fp8_sqr_basic
@@ -2259,7 +2422,10 @@
#undef fp8_exp
#undef fp8_exp_cyc
#undef fp8_frb
+#undef fp8_is_sqr
+#undef fp8_srt
+#define fp8_field_init RLC_PREFIX(fp8_field_init)
#define fp8_copy RLC_PREFIX(fp8_copy)
#define fp8_zero RLC_PREFIX(fp8_zero)
#define fp8_is_zero RLC_PREFIX(fp8_is_zero)
@@ -2279,6 +2445,7 @@
#define fp8_mul_basic RLC_PREFIX(fp8_mul_basic)
#define fp8_mul_lazyr RLC_PREFIX(fp8_mul_lazyr)
#define fp8_mul_art RLC_PREFIX(fp8_mul_art)
+#define fp8_mul_frb RLC_PREFIX(fp8_mul_frb)
#define fp8_mul_dxs RLC_PREFIX(fp8_mul_dxs)
#define fp8_sqr_unr RLC_PREFIX(fp8_sqr_unr)
#define fp8_sqr_basic RLC_PREFIX(fp8_sqr_basic)
@@ -2292,6 +2459,8 @@
#define fp8_exp RLC_PREFIX(fp8_exp)
#define fp8_exp_cyc RLC_PREFIX(fp8_exp_cyc)
#define fp8_frb RLC_PREFIX(fp8_frb)
+#define fp8_is_sqr RLC_PREFIX(fp8_is_sqr)
+#define fp8_srt RLC_PREFIX(fp8_srt)
#undef fp9_copy
#undef fp9_zero
@@ -2785,6 +2954,8 @@
#undef pp_map_init
#undef pp_map_clean
+#undef pp_add_k1_basic
+#undef pp_add_k1_projc
#undef pp_add_k2_basic
#undef pp_add_k2_projc_basic
#undef pp_add_k2_projc_lazyr
@@ -2805,6 +2976,8 @@
#undef pp_add_k48_projc
#undef pp_add_k54_basic
#undef pp_add_k54_projc
+#undef pp_dbl_k1_basic
+#undef pp_dbl_k1_projc
#undef pp_dbl_k2_basic
#undef pp_dbl_k2_projc_basic
#undef pp_dbl_k2_projc_lazyr
@@ -2825,6 +2998,7 @@
#undef pp_dbl_k54_projc
#undef pp_dbl_lit_k12
#undef pp_dbl_lit_k18
+#undef pp_exp_k1
#undef pp_exp_k2
#undef pp_exp_k8
#undef pp_exp_k12
@@ -2832,16 +3006,22 @@
#undef pp_exp_k24
#undef pp_exp_k48
#undef pp_exp_k54
+#undef pp_norm_k1
#undef pp_norm_k2
#undef pp_norm_k8
#undef pp_norm_k12
#undef pp_norm_k18
#undef pp_norm_k24
+#undef pp_norm_k48
+#undef pp_map_tatep_k1
+#undef pp_map_sim_tatep_k1
#undef pp_map_tatep_k2
#undef pp_map_sim_tatep_k2
+#undef pp_map_weilp_k1
+#undef pp_map_sim_weilp_k1
#undef pp_map_weilp_k2
-#undef pp_map_oatep_k8
#undef pp_map_sim_weilp_k2
+#undef pp_map_oatep_k8
#undef pp_map_tatep_k12
#undef pp_map_sim_tatep_k12
#undef pp_map_weilp_k12
@@ -2857,10 +3037,13 @@
#undef pp_map_k24
#undef pp_map_sim_k24
#undef pp_map_k48
+#undef pp_map_sim_k48
#undef pp_map_k54
#define pp_map_init RLC_PREFIX(pp_map_init)
#define pp_map_clean RLC_PREFIX(pp_map_clean)
+#define pp_add_k1_basic RLC_PREFIX(pp_add_k1_basic)
+#define pp_add_k1_projc RLC_PREFIX(pp_add_k1_projc)
#define pp_add_k2_basic RLC_PREFIX(pp_add_k2_basic)
#define pp_add_k2_projc_basic RLC_PREFIX(pp_add_k2_projc_basic)
#define pp_add_k2_projc_lazyr RLC_PREFIX(pp_add_k2_projc_lazyr)
@@ -2881,6 +3064,8 @@
#define pp_add_k48_projc RLC_PREFIX(pp_add_k48_projc)
#define pp_add_k54_basic RLC_PREFIX(pp_add_k54_basic)
#define pp_add_k54_projc RLC_PREFIX(pp_add_k54_projc)
+#define pp_dbl_k1_basic RLC_PREFIX(pp_dbl_k1_basic)
+#define pp_dbl_k1_projc RLC_PREFIX(pp_dbl_k1_projc)
#define pp_dbl_k2_basic RLC_PREFIX(pp_dbl_k2_basic)
#define pp_dbl_k2_projc_basic RLC_PREFIX(pp_dbl_k2_projc_basic)
#define pp_dbl_k2_projc_lazyr RLC_PREFIX(pp_dbl_k2_projc_lazyr)
@@ -2901,6 +3086,7 @@
#define pp_dbl_k54_projc RLC_PREFIX(pp_dbl_k54_projc)
#define pp_dbl_lit_k12 RLC_PREFIX(pp_dbl_lit_k12)
#define pp_dbl_lit_k18 RLC_PREFIX(pp_dbl_lit_k18)
+#define pp_exp_k1 RLC_PREFIX(pp_exp_k1)
#define pp_exp_k2 RLC_PREFIX(pp_exp_k2)
#define pp_exp_k8 RLC_PREFIX(pp_exp_k8)
#define pp_exp_k12 RLC_PREFIX(pp_exp_k12)
@@ -2908,16 +3094,22 @@
#define pp_exp_k24 RLC_PREFIX(pp_exp_k24)
#define pp_exp_k48 RLC_PREFIX(pp_exp_k48)
#define pp_exp_k54 RLC_PREFIX(pp_exp_k54)
+#define pp_norm_k1 RLC_PREFIX(pp_norm_k1)
#define pp_norm_k2 RLC_PREFIX(pp_norm_k2)
#define pp_norm_k8 RLC_PREFIX(pp_norm_k8)
#define pp_norm_k12 RLC_PREFIX(pp_norm_k12)
#define pp_norm_k18 RLC_PREFIX(pp_norm_k18)
#define pp_norm_k24 RLC_PREFIX(pp_norm_k24)
+#define pp_norm_k48 RLC_PREFIX(pp_norm_k48)
+#define pp_map_tatep_k1 RLC_PREFIX(pp_map_tatep_k1)
+#define pp_map_sim_tatep_k1 RLC_PREFIX(pp_map_sim_tatep_k1)
#define pp_map_tatep_k2 RLC_PREFIX(pp_map_tatep_k2)
#define pp_map_sim_tatep_k2 RLC_PREFIX(pp_map_sim_tatep_k2)
+#define pp_map_weilp_k1 RLC_PREFIX(pp_map_weilp_k1)
+#define pp_map_sim_weilp_k1 RLC_PREFIX(pp_map_sim_weilp_k1)
#define pp_map_weilp_k2 RLC_PREFIX(pp_map_weilp_k2)
-#define pp_map_oatep_k8 RLC_PREFIX(pp_map_oatep_k8)
#define pp_map_sim_weilp_k2 RLC_PREFIX(pp_map_sim_weilp_k2)
+#define pp_map_oatep_k8 RLC_PREFIX(pp_map_oatep_k8)
#define pp_map_tatep_k12 RLC_PREFIX(pp_map_tatep_k12)
#define pp_map_sim_tatep_k12 RLC_PREFIX(pp_map_sim_tatep_k12)
#define pp_map_weilp_k12 RLC_PREFIX(pp_map_weilp_k12)
@@ -2933,6 +3125,7 @@
#define pp_map_k24 RLC_PREFIX(pp_map_k24)
#define pp_map_sim_k24 RLC_PREFIX(pp_map_sim_k24)
#define pp_map_k48 RLC_PREFIX(pp_map_k48)
+#define pp_map_sim_k48 RLC_PREFIX(pp_map_sim_k48)
#define pp_map_k54 RLC_PREFIX(pp_map_k54)
#undef pc_core_init
diff --git a/include/relic_pc.h b/include/relic_pc.h
index e804be31b..d4c7850fc 100644
--- a/include/relic_pc.h
+++ b/include/relic_pc.h
@@ -36,9 +36,7 @@
#ifndef RLC_PC_H
#define RLC_PC_H
-#include "relic_fbx.h"
#include "relic_ep.h"
-#include "relic_eb.h"
#include "relic_pp.h"
#include "relic_bn.h"
#include "relic_util.h"
@@ -58,33 +56,52 @@
#define RLC_G1_LOWER ep_
#define RLC_G1_UPPER EP
-#if FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
+#if FP_PRIME == 575
+#define RLC_G2_LOWER ep8_
+#define RLC_G2_BASEF(A) A[0][0][0]
+#elif FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 330 || FP_PRIME == 509 || FP_PRIME == 765 || FP_PRIME == 766
#define RLC_G2_LOWER ep4_
-#elif FP_PRIME == 638 && !defined(FP_QNRES)
-#define RLC_G2_LOWER ep3_
+#define RLC_G2_BASEF(A) A[0][0]
+#elif FP_PRIME == 508 || FP_PRIME == 638 && !defined(FP_QNRES)
+#define RLC_G2_LOWER ep3_
+#define RLC_G2_BASEF(A) A[0]
#else
#define RLC_G2_LOWER ep2_
+#define RLC_G2_BASEF(A) A[0]
#endif
#define RLC_G2_UPPER EP
-#if FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
+#if FP_PRIME == 575
+#define RLC_GT_LOWER fp48_
+#define RLC_GT_EMBED 48
+#elif FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
#define RLC_GT_LOWER fp24_
-#elif FP_PRIME == 638 && !defined(FP_QNRES)
-#define RLC_GT_LOWER fp18_
+#define RLC_GT_EMBED 24
+#elif FP_PRIME == 508 || FP_PRIME == 638 && !defined(FP_QNRES)
+#define RLC_GT_LOWER fp18_
+#define RLC_GT_EMBED 18
+#elif FP_PRIME == 330 || FP_PRIME == 765 || FP_PRIME == 766
+#define RLC_GT_LOWER fp16_
+#define RLC_GT_EMBED 16
#else
#define RLC_GT_LOWER fp12_
+#define RLC_GT_EMBED 12
#endif
-#define RLC_PC_LOWER pp_
-
#else
#define RLC_G1_LOWER ep_
#define RLC_G1_UPPER EP
#define RLC_G2_LOWER ep_
#define RLC_G2_UPPER EP
+#define RLC_G2_BASEF(A) A
+#if FP_PRIME == 1536
#define RLC_GT_LOWER fp2_
-#define RLC_PC_LOWER pp_
+#define RLC_GT_EMBED 2
+#else
+#define RLC_GT_LOWER fp_
+#define RLC_GT_EMBED 1
+#endif
#endif
/** @} */
@@ -202,8 +219,6 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
*/
#define gt_free(A) RLC_CAT(RLC_GT_LOWER, free)(A)
-
-
/**
* Returns the generator of the group G_1.
*
@@ -246,12 +261,22 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* Returns the type of the configured pairing.
* @{
*/
-#if FP_PRIME < 1536
#define pc_map_is_type1() (0)
+#define pc_map_is_type2() (0)
+#define pc_map_is_type3() (0)
+#define pc_map_is_type4() (0)
+#define pc_map_is_typea() (0)
+#define pc_map_is_typeb() (0)
+#define pc_map_is_typec() (0)
+#if FP_PRIME == 3072
+#undef pc_map_is_typeb
+#define pc_map_is_typeb() (1)
+#elif FP_PRIME < 1536
+#undef pc_map_is_type3
#define pc_map_is_type3() (1)
#else
+#undef pc_map_is_type1
#define pc_map_is_type1() (1)
-#define pc_map_is_type3() (0)
#endif
/**
* @}
@@ -308,19 +333,41 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
#define gt_is_unity(A) (RLC_CAT(RLC_GT_LOWER, cmp_dig)(A, 1) == RLC_EQ)
/**
- * Assigns a G_1 element to the unity.
+ * Assigns a G_1 element to the identity.
*
* @param[out] P - the element to assign.
*/
#define g1_set_infty(P) RLC_CAT(RLC_G1_LOWER, set_infty)(P)
/**
- * Assigns a G_2 element to the unity.
+ * Assigns a G_2 element to the identity.
*
* @param[out] P - the element to assign.
*/
#define g2_set_infty(P) RLC_CAT(RLC_G2_LOWER, set_infty)(P)
+/**
+ * Assigns a G_1 element to a pair of coordinates in the extension field.
+ *
+ * @param[out] P - the element to assign.
+ * @param[out] Q - the G_2 element storing the coordinates.
+ */
+#define g1_set_g2(P, Q) \
+ fp_copy((P)->x, RLC_G2_BASEF((Q)->x)); \
+ fp_copy((P)->y, RLC_G2_BASEF((Q)->y)); \
+ fp_copy((P)->z, RLC_G2_BASEF((Q)->z)); \
+
+/**
+ * Assigns a G_2 element to a pair of coordinates in the base field.
+ *
+ * @param[out] Q - the element to assign.
+ * @param[out] P - the G_1 element storing the coordinates.
+ */
+#define g2_set_g1(Q, P) \
+ fp_copy(RLC_G2_BASEF((Q)->x), (P)->x); \
+ fp_copy(RLC_G2_BASEF((Q)->y), (P)->y); \
+ fp_copy(RLC_G2_BASEF((Q)->z), (P)->z); \
+
/**
* Assigns a G_T element to zero.
*
@@ -329,7 +376,7 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
#define gt_zero(A) RLC_CAT(RLC_GT_LOWER, zero)(A)
/**
- * Assigns a G_T element to the unity.
+ * Assigns a G_T element to the identity.
*
* @param[out] A - the element to assign.
*/
@@ -415,7 +462,7 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[out] R - the blinded G_1 element.
* @param[in] P - the G_1 element to blind.
*/
- #define g1_blind(R, P) RLC_CAT(RLC_G1_LOWER, blind)(R, P)
+#define g1_blind(R, P) RLC_CAT(RLC_G1_LOWER, blind)(R, P)
/**
* Randomizes coordinates of a G_2 element.
@@ -468,7 +515,11 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[in] A - the element of G_T.
* @param[in] C - the flag to indicate compression.
*/
+#if FP_PRIME <= 1536
#define gt_size_bin(A, C) RLC_CAT(RLC_GT_LOWER, size_bin)(A, C)
+#else
+#define gt_size_bin(A, C) RLC_FP_BYTES
+#endif
/**
* Reads a G_1 element from a byte vector in big-endian format.
@@ -534,7 +585,11 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[in] C - the flag to indicate point compression.
* @throw ERR_NO_BUFFER - if the buffer capacity is not sufficient.
*/
+#if FP_PRIME <= 1536
#define gt_write_bin(B, L, A, C) RLC_CAT(RLC_GT_LOWER, write_bin)(B, L, A, C)
+#else
+#define gt_write_bin(B, L, A, C) RLC_CAT(RLC_GT_LOWER, write_bin)(B, L, A)
+#endif
/**
* Negates a element from G_1. Computes R = -P.
@@ -558,7 +613,11 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[out] C - the result.
* @param[in] A - the element to invert.
*/
+#if FP_PRIME <= 1536
#define gt_inv(C, A) RLC_CAT(RLC_GT_LOWER, inv_cyc)(C, A)
+#else
+#define gt_inv(C, A) RLC_CAT(RLC_GT_LOWER, inv)(C, A)
+#endif
/**
* Adds two elliptic elements from G_1. Computes R = P + Q.
@@ -848,7 +907,11 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[in] A - the element to exponentiate.
* @param[in] I - the power of the Frobenius map.
*/
+#if FP_PRIME <= 1536
#define gt_frb(C, A, I) RLC_CAT(RLC_GT_LOWER, frb)(C, A, I)
+#else
+#define gt_frb(C, A, I) (A)
+#endif
/**
* Maps a byte array to an element in G_1.
@@ -857,7 +920,7 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[in] M - the byte array to map.
* @param[in] L - the array length in bytes.
*/
-#define g1_map(P, M, L); RLC_CAT(RLC_G1_LOWER, map)(P, M, L)
+#define g1_map(P, M, L) RLC_CAT(RLC_G1_LOWER, map)(P, M, L)
/**
* Maps a byte array to an element in G_2.
@@ -866,7 +929,7 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[in] M - the byte array to map.
* @param[in] L - the array length in bytes.
*/
-#define g2_map(P, M, L); RLC_CAT(RLC_G2_LOWER, map)(P, M, L)
+#define g2_map(P, M, L) RLC_CAT(RLC_G2_LOWER, map)(P, M, L)
/**
* Computes the bilinear pairing of a G_1 element and a G_2 element. Computes
@@ -876,21 +939,7 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[in] P - the first element.
* @param[in] Q - the second element.
*/
-#if FP_PRIME < 1536
-
-#if FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
-#define pc_map(R, P, Q); RLC_CAT(RLC_PC_LOWER, map_k24)(R, P, Q)
-#elif FP_PRIME == 638 && !defined(FP_QNRES)
-#define pc_map(R, P, Q); RLC_CAT(RLC_PC_LOWER, map_k18)(R, P, Q)
-#else
-#define pc_map(R, P, Q); RLC_CAT(RLC_PC_LOWER, map_k12)(R, P, Q)
-#endif
-
-#else
-
-#define pc_map(R, P, Q); RLC_CAT(RLC_PC_LOWER, map_k2)(R, P, Q)
-
-#endif
+#define pc_map(R, P, Q) RLC_CAT(pp_map_k, RLC_GT_EMBED)(R, P, Q)
/**
* Computes the multi-pairing of G_1 elements and G_2 elements. Computes
@@ -901,19 +950,7 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[in] Q - the second pairing arguments.
* @param[in] M - the number of pairing arguments.
*/
-#if FP_PRIME < 1536
-
-#if FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
-#define pc_map_sim(R, P, Q, M); RLC_CAT(RLC_PC_LOWER, map_sim_k24)(R, P, Q, M)
-#elif FP_PRIME == 638 && !defined(FP_QNRES)
-#define pc_map_sim(R, P, Q, M); RLC_CAT(RLC_PC_LOWER, map_sim_k18)(R, P, Q, M)
-#else
-#define pc_map_sim(R, P, Q, M); RLC_CAT(RLC_PC_LOWER, map_sim_k12)(R, P, Q, M)
-#endif
-
-#else
-#define pc_map_sim(R, P, Q, M); RLC_CAT(RLC_PC_LOWER, map_sim_k2)(R, P, Q, M)
-#endif
+#define pc_map_sim(R, P, Q, M) RLC_CAT(pp_map_sim_k, RLC_GT_EMBED)(R, P, Q, M)
/**
* Computes the final exponentiation of the pairing.
@@ -921,19 +958,7 @@ typedef RLC_CAT(RLC_GT_LOWER, t) gt_t;
* @param[out] C - the result.
* @param[in] A - the field element to exponentiate.
*/
-#if FP_PRIME < 1536
-
-#if FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
-#define pc_exp(C, A); RLC_CAT(RLC_PC_LOWER, exp_k24)(C, A)
-#elif FP_PRIME == 638 && !defined(FP_QNRES)
-#define pc_exp(C, A); RLC_CAT(RLC_PC_LOWER, exp_k18)(C, A)
-#else
-#define pc_exp(C, A); RLC_CAT(RLC_PC_LOWER, exp_k12)(C, A)
-#endif
-
-#else
-#define pc_exp(C, A); RLC_CAT(RLC_PC_LOWER, exp_k2)(C, A)
-#endif
+#define pc_exp(C, A); RLC_CAT(pp_exp_k, RLC_GT_EMBED)(C, A)
/*============================================================================*/
/* Function prototypes */
diff --git a/include/relic_pp.h b/include/relic_pp.h
index b2bdb9a31..2077bb691 100644
--- a/include/relic_pp.h
+++ b/include/relic_pp.h
@@ -45,6 +45,22 @@
/* Macro definitions */
/*============================================================================*/
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 1.
+ *
+ * @param[out] L - the numerator of the result of the evaluation.
+ * @param[out] M - the denominator of the result of the evaluation.
+ * @param[in, out] R - the resulting point and first point to add.
+ * @param[in] P - the second point to add.
+ * @param[in] Q - the affine point to evaluate the line function.
+ */
+#if EP_ADD == BASIC
+#define pp_add_k1(L, M, R, P, Q) pp_add_k1_basic(L, M, R, P, Q)
+#else
+#define pp_add_k1(L, M, R, P, Q) pp_add_k1_projc(L, M, R, P, Q)
+#endif
+
/**
* Adds two points and evaluates the corresponding line function at another
* point on an elliptic curve with embedding degree 2 using projective
@@ -56,9 +72,9 @@
* @param[in] Q - the affine point to evaluate the line function.
*/
#if PP_EXT == BASIC
-#define pp_add_k2_projc(L, R, P, Q) pp_add_k2_projc_basic(L, R, P, Q)
+#define pp_add_k2_projc(L, R, P, Q) pp_add_k2_projc_basic(L, R, P, Q)
#else
-#define pp_add_k2_projc(L, R, P, Q) pp_add_k2_projc_lazyr(L, R, P, Q)
+#define pp_add_k2_projc(L, R, P, Q) pp_add_k2_projc_lazyr(L, R, P, Q)
#endif
/**
@@ -138,6 +154,37 @@
#define pp_add_k12(L, R, Q, P) pp_add_k12_projc(L, R, Q, P)
#endif
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using projective
+ * coordinates.
+ *
+ * @param[out] L - the result of the evaluation.
+ * @param[in, out] R - the resulting point and first point to add.
+ * @param[in] Q - the second point to add.
+ * @param[in] P - the affine point to evaluate the line function.
+ */
+#if PP_EXT == BASIC
+#define pp_add_k16_projc(L, R, Q, P) pp_add_k16_projc_basic(L, R, Q, P)
+#elif PP_EXT == LAZYR
+#define pp_add_k16_projc(L, R, Q, P) pp_add_k16_projc_lazyr(L, R, Q, P)
+#endif
+
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16.
+ *
+ * @param[out] L - the result of the evaluation.
+ * @param[in, out] R - the resulting point and first point to add.
+ * @param[in] Q - the second point to add.
+ * @param[in] P - the affine point to evaluate the line function.
+ */
+#if EP_ADD == BASIC
+#define pp_add_k16(L, R, Q, P) pp_add_k16_basic(L, R, Q, P)
+#else
+#define pp_add_k16(L, R, Q, P) pp_add_k16_projc(L, R, Q, P)
+#endif
+
/**
* Adds two points and evaluates the corresponding line function at another
* point on an elliptic curve with embedding degree 18 using projective
@@ -194,9 +241,9 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if EP_ADD == BASIC
-#define pp_add_k48(L, RX, RY, RZ, QX, QY, P) pp_add_k48_basic(L, RX, RY, QX, QY, P)
+#define pp_add_k48(L, R, Q, P) pp_add_k48_basic(L, R, Q, P)
#else
-#define pp_add_k48(L, RX, RY, RZ, QX, QY, P) pp_add_k48_projc(L, RX, RY, RZ, QX, QY, P)
+#define pp_add_k48(L, R, Q, P) pp_add_k48_projc(L, R, Q, P)
#endif
/**
@@ -214,6 +261,22 @@
#define pp_add_k54(L, RX, RY, RZ, QX, QY, P) pp_add_k54_projc(L, RX, RY, RZ, QX, QY, P)
#endif
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 1.
+ *
+ * @param[out] L - the numerator of the result of the evaluation.
+ * @param[out] M - the denominator of the result of the evaluation.
+ * @param[out] R - the resulting point.
+ * @param[in] P - the point to double.
+ * @param[in] Q - the affine point to evaluate the line function.
+ */
+#if EP_ADD == BASIC
+#define pp_dbl_k1(L, M, R, P, Q) pp_dbl_k1_basic(L, M, R, P, Q)
+#else
+#define pp_dbl_k1(L, M, R, P, Q) pp_dbl_k1_projc(L, M, R, P, Q)
+#endif
+
/**
* Doubles a point and evaluates the corresponding line function at another
* point on an elliptic curve with embedding degree 2 using projective
@@ -225,9 +288,9 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if PP_EXT == BASIC
-#define pp_dbl_k2_projc(L, R, P, Q) pp_dbl_k2_projc_basic(L, R, P, Q)
+#define pp_dbl_k2_projc(L, R, P, Q) pp_dbl_k2_projc_basic(L, R, P, Q)
#elif PP_EXT == LAZYR
-#define pp_dbl_k2_projc(L, R, P, Q) pp_dbl_k2_projc_lazyr(L, R, P, Q)
+#define pp_dbl_k2_projc(L, R, P, Q) pp_dbl_k2_projc_lazyr(L, R, P, Q)
#endif
/**
@@ -240,9 +303,9 @@
* @param[in] Q - the affine point to evaluate the line function.
*/
#if EP_ADD == BASIC
-#define pp_dbl_k2(L, R, P, Q) pp_dbl_k2_basic(L, R, P, Q)
+#define pp_dbl_k2(L, R, P, Q) pp_dbl_k2_basic(L, R, P, Q)
#else
-#define pp_dbl_k2(L, R, P, Q) pp_dbl_k2_projc(L, R, P, Q)
+#define pp_dbl_k2(L, R, P, Q) pp_dbl_k2_projc(L, R, P, Q)
#endif
/**
@@ -256,9 +319,9 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if PP_EXT == BASIC
-#define pp_dbl_k8_projc(L, R, Q, P) pp_dbl_k8_projc_basic(L, R, Q, P)
+#define pp_dbl_k8_projc(L, R, Q, P) pp_dbl_k8_projc_basic(L, R, Q, P)
#elif PP_EXT == LAZYR
-#define pp_dbl_k8_projc(L, R, Q, P) pp_dbl_k8_projc_lazyr(L, R, Q, P)
+#define pp_dbl_k8_projc(L, R, Q, P) pp_dbl_k8_projc_lazyr(L, R, Q, P)
#endif
/**
@@ -271,9 +334,9 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if EP_ADD == BASIC
-#define pp_dbl_k8(L, R, Q, P) pp_dbl_k8_basic(L, R, Q, P)
+#define pp_dbl_k8(L, R, Q, P) pp_dbl_k8_basic(L, R, Q, P)
#else
-#define pp_dbl_k8(L, R, Q, P) pp_dbl_k8_projc(L, R, Q, P)
+#define pp_dbl_k8(L, R, Q, P) pp_dbl_k8_projc(L, R, Q, P)
#endif
/**
@@ -302,9 +365,40 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if EP_ADD == BASIC
-#define pp_dbl_k12(L, R, Q, P) pp_dbl_k12_basic(L, R, Q, P)
+#define pp_dbl_k12(L, R, Q, P) pp_dbl_k12_basic(L, R, Q, P)
#else
-#define pp_dbl_k12(L, R, Q, P) pp_dbl_k12_projc(L, R, Q, P)
+#define pp_dbl_k12(L, R, Q, P) pp_dbl_k12_projc(L, R, Q, P)
+#endif
+
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using projective
+ * coordinates.
+ *
+ * @param[out] L - the result of the evaluation.
+ * @param[in, out] R - the resulting point.
+ * @param[in] Q - the point to double.
+ * @param[in] P - the affine point to evaluate the line function.
+ */
+#if PP_EXT == BASIC
+#define pp_dbl_k16_projc(L, R, Q, P) pp_dbl_k16_projc_basic(L, R, Q, P)
+#elif PP_EXT == LAZYR
+#define pp_dbl_k16_projc(L, R, Q, P) pp_dbl_k16_projc_lazyr(L, R, Q, P)
+#endif
+
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16.
+ *
+ * @param[out] L - the result of the evaluation.
+ * @param[out] R - the resulting point.
+ * @param[in] Q - the point to double.
+ * @param[in] P - the affine point to evaluate the line function.
+ */
+#if EP_ADD == BASIC
+#define pp_dbl_k16(L, R, Q, P) pp_dbl_k16_basic(L, R, Q, P)
+#else
+#define pp_dbl_k16(L, R, Q, P) pp_dbl_k16_projc(L, R, Q, P)
#endif
/**
@@ -333,9 +427,9 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if EP_ADD == BASIC
-#define pp_dbl_k18(L, R, Q, P) pp_dbl_k18_basic(L, R, Q, P)
+#define pp_dbl_k18(L, R, Q, P) pp_dbl_k18_basic(L, R, Q, P)
#else
-#define pp_dbl_k18(L, R, Q, P) pp_dbl_k18_projc(L, R, Q, P)
+#define pp_dbl_k18(L, R, Q, P) pp_dbl_k18_projc(L, R, Q, P)
#endif
/**
@@ -348,9 +442,9 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if EP_ADD == BASIC
-#define pp_dbl_k24(L, R, Q, P) pp_dbl_k24_basic(L, R, Q, P)
+#define pp_dbl_k24(L, R, Q, P) pp_dbl_k24_basic(L, R, Q, P)
#else
-#define pp_dbl_k24(L, R, Q, P) pp_dbl_k24_projc(L, R, Q, P)
+#define pp_dbl_k24(L, R, Q, P) pp_dbl_k24_projc(L, R, Q, P)
#endif
/**
@@ -363,9 +457,9 @@
* @param[in] P - the affine point to evaluate the line function.
*/
#if EP_ADD == BASIC
-#define pp_dbl_k48(L, RX, RY, RZ, P) pp_dbl_k48_basic(L, RX, RY, P)
+#define pp_dbl_k48(L, R, Q, P) pp_dbl_k48_basic(L, R, Q, P)
#else
-#define pp_dbl_k48(L, RX, RY, RZ, P) pp_dbl_k48_projc(L, RX, RY, RZ, P)
+#define pp_dbl_k48(L, R, Q, P) pp_dbl_k48_projc(L, R, Q, P)
#endif
/**
@@ -384,6 +478,22 @@
#endif
/**
+ * Computes a pairing of two prime elliptic curve points defined on an elliptic
+ * curves of embedding degree 1. Computes e(P, Q).
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the first elliptic curve point.
+ * @param[in] Q - the second elliptic curve point.
+ */
+#if PP_MAP == TATEP
+#define pp_map_k1(R, P, Q) pp_map_tatep_k1(R, P, Q)
+#elif PP_MAP == WEILP
+#define pp_map_k1(R, P, Q) pp_map_weilp_k1(R, P, Q)
+#elif PP_MAP == OATEP
+#define pp_map_k1(R, P, Q) pp_map_tatep_k1(R, P, Q)
+#endif
+
+/**pp_map
* Computes a pairing of two prime elliptic curve points defined on an elliptic
* curves of embedding degree 2. Computes e(P, Q).
*
@@ -392,11 +502,11 @@
* @param[in] Q - the second elliptic curve point.
*/
#if PP_MAP == TATEP
-#define pp_map_k2(R, P, Q) pp_map_tatep_k2(R, P, Q)
+#define pp_map_k2(R, P, Q) pp_map_tatep_k2(R, P, Q)
#elif PP_MAP == WEILP
-#define pp_map_k2(R, P, Q) pp_map_weilp_k2(R, P, Q)
+#define pp_map_k2(R, P, Q) pp_map_weilp_k2(R, P, Q)
#elif PP_MAP == OATEP
-#define pp_map_k2(R, P, Q) pp_map_tatep_k2(R, P, Q)
+#define pp_map_k2(R, P, Q) pp_map_tatep_k2(R, P, Q)
#endif
/**
@@ -408,11 +518,27 @@
* @param[in] Q - the second elliptic curve point.
*/
#if PP_MAP == TATEP
-#define pp_map_k12(R, P, Q) pp_map_tatep_k12(R, P, Q)
+#define pp_map_k12(R, P, Q) pp_map_tatep_k12(R, P, Q)
+#elif PP_MAP == WEILP
+#define pp_map_k12(R, P, Q) pp_map_weilp_k12(R, P, Q)
+#elif PP_MAP == OATEP
+#define pp_map_k12(R, P, Q) pp_map_oatep_k12(R, P, Q)
+#endif
+
+/**
+ * Computes a pairing of two prime elliptic curve points defined on an elliptic
+ * curve of embedding degree 16. Computes e(P, Q).
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the first elliptic curve point.
+ * @param[in] Q - the second elliptic curve point.
+ */
+#if PP_MAP == TATEP
+#define pp_map_k16(R, P, Q) pp_map_tatep_k16(R, P, Q)
#elif PP_MAP == WEILP
-#define pp_map_k12(R, P, Q) pp_map_weilp_k12(R, P, Q)
+#define pp_map_k16(R, P, Q) pp_map_weilp_k16(R, P, Q)
#elif PP_MAP == OATEP
-#define pp_map_k12(R, P, Q) pp_map_oatep_k12(R, P, Q)
+#define pp_map_k16(R, P, Q) pp_map_oatep_k16(R, P, Q)
#endif
/**
@@ -424,16 +550,16 @@
* @param[in] Q - the second elliptic curve point.
*/
#if PP_MAP == TATEP
-#define pp_map_k18(R, P, Q) pp_map_tatep_k18(R, P, Q)
+#define pp_map_k18(R, P, Q) pp_map_tatep_k18(R, P, Q)
#elif PP_MAP == WEILP
-#define pp_map_k18(R, P, Q) pp_map_weilp_k18(R, P, Q)
+#define pp_map_k18(R, P, Q) pp_map_weilp_k18(R, P, Q)
#elif PP_MAP == OATEP
-#define pp_map_k18(R, P, Q) pp_map_oatep_k18(R, P, Q)
+#define pp_map_k18(R, P, Q) pp_map_oatep_k18(R, P, Q)
#endif
/**
* Computes a multi-pairing of elliptic curve points defined on an elliptic
- * curve of embedding degree 2. Computes \prod e(P_i, Q_i).
+ * curve of embedding degree 1. Computes \prod e(P_i, Q_i).
*
* @param[out] R - the result.
* @param[in] P - the first pairing arguments.
@@ -441,11 +567,25 @@
* @param[in] M - the number of pairings to evaluate.
*/
#if PP_MAP == WEILP
-#define pp_map_sim_k2(R, P, Q, M) pp_map_sim_weilp_k2(R, P, Q, M)
+#define pp_map_sim_k1(R, P, Q, M) pp_map_sim_weilp_k1(R, P, Q, M)
#elif PP_MAP == TATEP || PP_MAP == OATEP
-#define pp_map_sim_k2(R, P, Q, M) pp_map_sim_tatep_k2(R, P, Q, M)
+#define pp_map_sim_k1(R, P, Q, M) pp_map_sim_tatep_k1(R, P, Q, M)
#endif
+/**
+ * Computes a multi-pairing of elliptic curve points defined on an elliptic
+ * curve of embedding degree 2. Computes \prod e(P_i, Q_i).
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the first pairing arguments.
+ * @param[in] Q - the second pairing arguments.
+ * @param[in] M - the number of pairings to evaluate.
+ */
+#if PP_MAP == WEILP
+#define pp_map_sim_k2(R, P, Q, M) pp_map_sim_weilp_k2(R, P, Q, M)
+#elif PP_MAP == TATEP || PP_MAP == OATEP
+#define pp_map_sim_k2(R, P, Q, M) pp_map_sim_tatep_k2(R, P, Q, M)
+#endif
/**
* Computes a multi-pairing of elliptic curve points defined on an elliptic
@@ -457,11 +597,28 @@
* @param[in] M - the number of pairings to evaluate.
*/
#if PP_MAP == TATEP
-#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_tatep_k12(R, P, Q, M)
+#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_tatep_k12(R, P, Q, M)
#elif PP_MAP == WEILP
-#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_weilp_k12(R, P, Q, M)
+#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_weilp_k12(R, P, Q, M)
#elif PP_MAP == OATEP
-#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_oatep_k12(R, P, Q, M)
+#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_oatep_k12(R, P, Q, M)
+#endif
+
+/**
+ * Computes a multi-pairing of elliptic curve points defined on an elliptic
+ * curve of embedding degree 16. Computes \prod e(P_i, Q_i).
+ *
+ * @param[out] R - the result.
+ * @param[in] P - the first pairing arguments.
+ * @param[in] Q - the second pairing arguments.
+ * @param[in] M - the number of pairings to evaluate.
+ */
+#if PP_MAP == TATEP
+#define pp_map_sim_k16(R, P, Q, M) pp_map_sim_tatep_k16(R, P, Q, M)
+#elif PP_MAP == WEILP
+#define pp_map_sim_k16(R, P, Q, M) pp_map_sim_weilp_k16(R, P, Q, M)
+#elif PP_MAP == OATEP
+#define pp_map_sim_k16(R, P, Q, M) pp_map_sim_oatep_k16(R, P, Q, M)
#endif
/**
@@ -474,11 +631,11 @@
* @param[in] M - the number of pairings to evaluate.
*/
#if PP_MAP == TATEP
-#define pp_map_sim_k18(R, P, Q, M) pp_map_sim_tatep_k18(R, P, Q, M)
+#define pp_map_sim_k18(R, P, Q, M) pp_map_sim_tatep_k18(R, P, Q, M)
#elif PP_MAP == WEILP
-#define pp_map_sim_k18(R, P, Q, M) pp_map_sim_weilp_k18(R, P, Q, M)
+#define pp_map_sim_k18(R, P, Q, M) pp_map_sim_weilp_k18(R, P, Q, M)
#elif PP_MAP == OATEP
-#define pp_map_sim_k18(R, P, Q, M) pp_map_sim_oatep_k18(R, P, Q, M)
+#define pp_map_sim_k18(R, P, Q, M) pp_map_sim_oatep_k18(R, P, Q, M)
#endif
/*============================================================================*/
@@ -495,6 +652,31 @@ void pp_map_init(void);
*/
void pp_map_clean(void);
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 1 using affine coordinates.
+ *
+ * @param[out] l - the numerator of the result of the evaluation.
+ * @param[out] m - the denominator of the result of the evaluation.
+ * @param[in, out] r - the resulting point and first point to add.
+ * @param[in] p - the second point to add.
+ * @param[in] q - the affine point to evaluate the line function.
+ */
+void pp_add_k1_basic(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q);
+
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 1 using projective
+ * coordinates.
+ *
+ * @param[out] l - the numerator of the result of the evaluation.
+ * @param[out] m - the denominator of the result of the evaluation.
+ * @param[in, out] r - the resulting point and first point to add.
+ * @param[in] p - the second point to add.
+ * @param[in] q - the affine point to evaluate the line function.
+ */
+void pp_add_k1_projc(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q);
+
/**
* Adds two points and evaluates the corresponding line function at another
* point on an elliptic curve with embedding degree 2 using affine coordinates.
@@ -612,6 +794,53 @@ void pp_add_k12_projc_lazyr(fp12_t l, ep2_t r, const ep2_t q, const ep_t p);
*/
void pp_add_lit_k12(fp12_t l, ep_t r, const ep_t p, const ep2_t q);
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using affine coordinates.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point and first point to add.
+ * @param[in] q - the second point to add.
+ * @param[in] p - the affine point to evaluate the line function.
+ */
+void pp_add_k16_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p);
+
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using projective
+ * coordinates.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point and first point to add.
+ * @param[in] q - the second point to add.
+ * @param[in] p - the affine point to evaluate the line function.
+ */
+void pp_add_k16_projc_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p);
+
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using projective
+ * coordinates and lazy reduction.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point and first point to add.
+ * @param[in] q - the second point to add.
+ * @param[in] p - the affine point to evaluate the line function.
+ */
+void pp_add_k16_projc_lazyr(fp16_t l, ep4_t r, const ep4_t q, const ep_t p);
+
+/**
+ * Adds two points and evaluates the corresponding line function at another
+ * point on an elliptic curve twist with embedding degree 16 using projective
+ * coordinates.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point and first point to add.
+ * @param[in] p - the second point to add.
+ * @param[in] q - the affine point to evaluate the line function.
+ */
+void pp_add_lit_k16(fp16_t l, ep_t r, const ep_t p, const ep4_t q);
+
/**
* Adds two points and evaluates the corresponding line function at another
* point on an elliptic curve with embedding degree 18 using affine coordinates.
@@ -691,8 +920,7 @@ void pp_add_k24_projc(fp24_t l, ep4_t r, const ep4_t q, const ep_t p);
* @param[in] q - the second point to add.
* @param[in] p - the affine point to evaluate the line function.
*/
-void pp_add_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, fp8_t qx, fp8_t qy,
- const ep_t p);
+void pp_add_k48_basic(fp48_t l, ep8_t r, const ep8_t q, const ep_t p);
/**
* Adds two points and evaluates the corresponding line function at another
@@ -704,8 +932,7 @@ void pp_add_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, fp8_t qx, fp8_t qy,
* @param[in] q - the second point to add.
* @param[in] p - the affine point to evaluate the line function.
*/
-void pp_add_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const fp8_t qx,
- const fp8_t qy, const ep_t p);
+void pp_add_k48_projc(fp48_t l, ep8_t r, const ep8_t q, const ep_t p);
/**
* Adds two points and evaluates the corresponding line function at another
@@ -732,6 +959,32 @@ void pp_add_k54_basic(fp54_t l, fp9_t rx, fp9_t ry, const fp9_t qx,
void pp_add_k54_projc(fp54_t l, fp9_t rx, fp9_t ry, fp9_t rz, const fp9_t qx,
const fp9_t qy, const ep_t p);
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 1 using affine
+ * coordinates.
+ *
+ * @param[out] l - the numerator of the result of the evaluation.
+ * @param[out] m - the denominator of the result of the evaluation.
+ * @param[in, out] r - the resulting point.
+ * @param[in] p - the point to double.
+ * @param[in] q - the affine point to evaluate the line function.
+ */
+void pp_dbl_k1_basic(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q);
+
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 1 using projective
+ * coordinates.
+ *
+ * @param[out] l - the numerator of the result of the evaluation.
+ * @param[out] m - the denominator of the result of the evaluation.
+ * @param[in, out] r - the resulting point.
+ * @param[in] p - the point to double.
+ * @param[in] q - the affine point to evaluate the line function.
+ */
+void pp_dbl_k1_projc(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q);
+
/**
* Doubles a point and evaluates the corresponding line function at another
* point on an elliptic curve with embedding degree 2 using affine
@@ -746,7 +999,7 @@ void pp_dbl_k2_basic(fp2_t l, ep_t r, const ep_t p, const ep_t q);
/**
* Doubles a point and evaluates the corresponding line function at another
- * point on an elliptic curve with embedding degree 12 using projective
+ * point on an elliptic curve with embedding degree 2 using projective
* coordinates.
*
* @param[out] l - the result of the evaluation.
@@ -758,7 +1011,7 @@ void pp_dbl_k2_projc_basic(fp2_t l, ep_t r, const ep_t p, const ep_t q);
/**
* Doubles a point and evaluates the corresponding line function at another
- * point on an elliptic curve with embedding degree 12 using projective
+ * point on an elliptic curve with embedding degree 2 using projective
* coordinates and lazy reduction.
*
* @param[out] l - the result of the evaluation.
@@ -840,6 +1093,42 @@ void pp_dbl_k12_projc_basic(fp12_t l, ep2_t r, const ep2_t q, const ep_t p);
*/
void pp_dbl_k12_projc_lazyr(fp12_t l, ep2_t r, const ep2_t q, const ep_t p);
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using affine
+ * coordinates.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point.
+ * @param[in] q - the point to double.
+ * @param[in] p - the affine point to evaluate the line function.
+ */
+void pp_dbl_k16_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p);
+
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using projective
+ * coordinates.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point.
+ * @param[in] q - the point to double.
+ * @param[in] p - the affine point to evaluate the line function.
+ */
+void pp_dbl_k16_projc_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p);
+
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve with embedding degree 16 using projective
+ * coordinates and lazy reduction.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point.
+ * @param[in] q - the point to double.
+ * @param[in] p - the affine point to evaluate the line function.
+ */
+void pp_dbl_k16_projc_lazyr(fp16_t l, ep4_t r, const ep4_t q, const ep_t p);
+
/**
* Doubles a point and evaluates the corresponding line function at another
* point on an elliptic curve with embedding degree 18 using affine
@@ -910,7 +1199,7 @@ void pp_dbl_k24_projc(fp24_t l, ep4_t r, const ep4_t q, const ep_t p);
* @param[in] q - the point to double.
* @param[in] p - the affine point to evaluate the line function.
*/
-void pp_dbl_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, const ep_t p);
+void pp_dbl_k48_basic(fp48_t l, ep8_t r, const ep8_t q, const ep_t p);
/**
* Doubles a point and evaluates the corresponding line function at another
@@ -922,7 +1211,7 @@ void pp_dbl_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, const ep_t p);
* @param[in] q - the point to double.
* @param[in] p - the affine point to evaluate the line function.
*/
-void pp_dbl_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const ep_t p);
+void pp_dbl_k48_projc(fp48_t l, ep8_t r, const ep8_t q, const ep_t p);
/**
* Doubles a point and evaluates the corresponding line function at another
@@ -960,6 +1249,18 @@ void pp_dbl_k54_projc(fp54_t l, fp9_t rx, fp9_t ry, fp9_t rz, const ep_t p);
*/
void pp_dbl_lit_k12(fp12_t l, ep_t r, const ep_t p, const ep2_t q);
+/**
+ * Doubles a point and evaluates the corresponding line function at another
+ * point on an elliptic curve twist with embedding degree 16 using projective
+ * coordinates.
+ *
+ * @param[out] l - the result of the evaluation.
+ * @param[in, out] r - the resulting point.
+ * @param[in] p - the point to double.
+ * @param[in] q - the affine point to evaluate the line function.
+ */
+void pp_dbl_lit_k16(fp16_t l, ep_t r, const ep_t p, const ep4_t q);
+
/**
* Doubles a point and evaluates the corresponding line function at another
* point on an elliptic curve twist with embedding degree 18 using projective
@@ -972,6 +1273,15 @@ void pp_dbl_lit_k12(fp12_t l, ep_t r, const ep_t p, const ep2_t q);
*/
void pp_dbl_lit_k18(fp18_t l, ep_t r, const ep_t p, const ep3_t q);
+/**
+ * Computes the final exponentiation for a pairing defined over curves of
+ * embedding degree 1. Computes c = a^(p - 1)/r.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element to exponentiate.
+ */
+void pp_exp_k1(fp_t c, fp_t a);
+
/**
* Computes the final exponentiation for a pairing defined over curves of
* embedding degree 2. Computes c = a^(p^2 - 1)/r.
@@ -999,6 +1309,15 @@ void pp_exp_k8(fp8_t c, fp8_t a);
*/
void pp_exp_k12(fp12_t c, fp12_t a);
+/**
+ * Computes the final exponentiation for a pairing defined over curves of
+ * embedding degree 16. Computes c = a^(p^16 - 1)/r.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element to exponentiate.
+ */
+void pp_exp_k16(fp16_t c, fp16_t a);
+
/**
* Computes the final exponentiation for a pairing defined over curves of
* embedding degree 18. Computes c = a^(p^18 - 1)/r.
@@ -1035,6 +1354,15 @@ void pp_exp_k48(fp48_t c, fp48_t a);
*/
void pp_exp_k54(fp54_t c, fp54_t a);
+/**
+ * Normalizes the accumulator point used inside pairing computation defined
+ * over curves of embedding degree 1.
+ *
+ * @param[out] r - the resulting point.
+ * @param[in] p - the point to normalize.
+ */
+void pp_norm_k1(ep_t c, const ep_t a);
+
/**
* Normalizes the accumulator point used inside pairing computation defined
* over curves of embedding degree 2.
@@ -1062,6 +1390,15 @@ void pp_norm_k8(ep2_t c, const ep2_t a);
*/
void pp_norm_k12(ep2_t c, const ep2_t a);
+/**
+ * Normalizes the accumulator point used inside pairing computation defined
+ * over curves of embedding degree 16.
+ *
+ * @param[out] r - the resulting point.
+ * @param[in] p - the point to normalize.
+ */
+void pp_norm_k16(ep4_t c, const ep4_t a);
+
/**
* Normalizes the accumulator point used inside pairing computation defined
* over curves of embedding degree 18.
@@ -1080,9 +1417,39 @@ void pp_norm_k18(ep3_t c, const ep3_t a);
*/
void pp_norm_k24(ep4_t c, const ep4_t a);
+/**
+ * Normalizes the accumulator point used inside pairing computation defined
+ * over curves of embedding degree 48.
+ *
+ * @param[out] r - the resulting point.
+ * @param[in] p - the point to normalize.
+ */
+void pp_norm_k48(ep8_t c, const ep8_t a);
+
/**
* Computes the Tate pairing of two points in a parameterized elliptic curve
- * with embedding degree 12.
+ * with embedding degree 1.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first elliptic curve point.
+ * @param[in] p - the second elliptic curve point.
+ */
+void pp_map_tatep_k1(fp_t r, const ep_t p, const ep_t q);
+
+/**
+ * Computes the Tate multi-pairing in a parameterized elliptic curve with
+ * embedding degree 1.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first pairing arguments.
+ * @param[in] p - the second pairing arguments.
+ * @param[in] m - the number of pairings to evaluate.
+ */
+void pp_map_sim_tatep_k1(fp_t r, const ep_t *p, const ep_t *q, int m);
+
+/**
+ * Computes the Tate pairing of two points in a parameterized elliptic curve
+ * with embedding degree 2.
*
* @param[out] r - the result.
* @param[in] q - the first elliptic curve point.
@@ -1091,7 +1458,7 @@ void pp_norm_k24(ep4_t c, const ep4_t a);
void pp_map_tatep_k2(fp2_t r, const ep_t p, const ep_t q);
/**
- * Computes the Tate multi-pairing of in a parameterized elliptic curve with
+ * Computes the Tate multi-pairing in a parameterized elliptic curve with
* embedding degree 2.
*
* @param[out] r - the result.
@@ -1103,26 +1470,37 @@ void pp_map_sim_tatep_k2(fp2_t r, const ep_t *p, const ep_t *q, int m);
/**
* Computes the Weil pairing of two points in a parameterized elliptic curve
- * with embedding degree 2.
+ * with embedding degree 1.
*
* @param[out] r - the result.
* @param[in] q - the first elliptic curve point.
* @param[in] p - the second elliptic curve point.
*/
-void pp_map_weilp_k2(fp2_t r, const ep_t p, const ep_t q);
+void pp_map_weilp_k1(fp_t r, const ep_t p, const ep_t q);
/**
- * Computes the optimal ate pairing of two points in a parameterized elliptic
- * curve with embedding degree 8.
+ * Computes the Weil multi-pairing in a parameterized elliptic curve with
+ * embedding degree 1.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first pairing arguments.
+ * @param[in] p - the second pairing arguments.
+ * @param[in] m - the number of pairings to evaluate.
+ */
+void pp_map_sim_weilp_k1(fp_t r, const ep_t *p, const ep_t *q, int m);
+
+/**
+ * Computes the Weil pairing of two points in a parameterized elliptic curve
+ * with embedding degree 2.
*
* @param[out] r - the result.
* @param[in] q - the first elliptic curve point.
* @param[in] p - the second elliptic curve point.
*/
-void pp_map_oatep_k8(fp8_t r, const ep_t p, const ep2_t q);
+void pp_map_weilp_k2(fp2_t r, const ep_t p, const ep_t q);
/**
- * Computes the Weil multi-pairing of in a parameterized elliptic curve with
+ * Computes the Weil multi-pairing in a parameterized elliptic curve with
* embedding degree 2.
*
* @param[out] r - the result.
@@ -1132,6 +1510,16 @@ void pp_map_oatep_k8(fp8_t r, const ep_t p, const ep2_t q);
*/
void pp_map_sim_weilp_k2(fp2_t r, const ep_t *p, const ep_t *q, int m);
+/**
+ * Computes the optimal ate pairing of two points in a parameterized elliptic
+ * curve with embedding degree 8.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first elliptic curve point.
+ * @param[in] p - the second elliptic curve point.
+ */
+void pp_map_oatep_k8(fp8_t r, const ep_t p, const ep2_t q);
+
/**
* Computes the Tate pairing of two points in a parameterized elliptic curve
* with embedding degree 12.
@@ -1143,7 +1531,7 @@ void pp_map_sim_weilp_k2(fp2_t r, const ep_t *p, const ep_t *q, int m);
void pp_map_tatep_k12(fp12_t r, const ep_t p, const ep2_t q);
/**
- * Computes the Tate multi-pairing of in a parameterized elliptic curve with
+ * Computes the Tate multi-pairing in a parameterized elliptic curve with
* embedding degree 12.
*
* @param[out] r - the result.
@@ -1164,7 +1552,7 @@ void pp_map_sim_tatep_k12(fp12_t r, const ep_t *p, const ep2_t *q, int m);
void pp_map_weilp_k12(fp12_t r, const ep_t p, const ep2_t q);
/**
- * Computes the Weil multi-pairing of in a parameterized elliptic curve with
+ * Computes the Weil multi-pairing in a parameterized elliptic curve with
* embedding degree 12.
*
* @param[out] r - the result.
@@ -1185,7 +1573,7 @@ void pp_map_sim_weilp_k12(fp12_t r, const ep_t *p, const ep2_t *q, int m);
void pp_map_oatep_k12(fp12_t r, const ep_t p, const ep2_t q);
/**
- * Computes the optimal ate multi-pairing of in a parameterized elliptic
+ * Computes the optimal ate multi-pairing in a parameterized elliptic
* curve with embedding degree 12.
*
* @param[out] r - the result.
@@ -1195,6 +1583,69 @@ void pp_map_oatep_k12(fp12_t r, const ep_t p, const ep2_t q);
*/
void pp_map_sim_oatep_k12(fp12_t r, const ep_t *p, const ep2_t *q, int m);
+/**
+ * Computes the Tate pairing of two points in a parameterized elliptic curve
+ * with embedding degree 16.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first elliptic curve point.
+ * @param[in] p - the second elliptic curve point.
+ */
+void pp_map_tatep_k16(fp16_t r, const ep_t p, const ep4_t q);
+
+/**
+ * Computes the Tate multi-pairing in a parameterized elliptic curve with
+ * embedding degree 16.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first pairing arguments.
+ * @param[in] p - the second pairing arguments.
+ * @param[in] m - the number of pairings to evaluate.
+ */
+void pp_map_sim_tatep_k16(fp16_t r, const ep_t *p, const ep4_t *q, int m);
+
+/**
+ * Computes the Weil pairing of two points in a parameterized elliptic curve
+ * with embedding degree 16.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first elliptic curve point.
+ * @param[in] p - the second elliptic curve point.
+ */
+void pp_map_weilp_k16(fp16_t r, const ep_t p, const ep4_t q);
+
+/**
+ * Computes the Weil multi-pairing in a parameterized elliptic curve with
+ * embedding degree 16.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first pairing arguments.
+ * @param[in] p - the second pairing arguments.
+ * @param[in] m - the number of pairings to evaluate.
+ */
+void pp_map_sim_weilp_k16(fp16_t r, const ep_t *p, const ep4_t *q, int m);
+
+/**
+ * Computes the optimal ate pairing of two points in a parameterized elliptic
+ * curve with embedding degree 16.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first elliptic curve point.
+ * @param[in] p - the second elliptic curve point.
+ */
+void pp_map_oatep_k16(fp16_t r, const ep_t p, const ep4_t q);
+
+/**
+ * Computes the optimal ate multi-pairing in a parameterized elliptic
+ * curve with embedding degree 16.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first pairing arguments.
+ * @param[in] p - the second pairing arguments.
+ * @param[in] m - the number of pairings to evaluate.
+ */
+void pp_map_sim_oatep_k16(fp16_t r, const ep_t *p, const ep4_t *q, int m);
+
/**
* Computes the Tate pairing of two points in a parameterized elliptic curve
* with embedding degree 18.
@@ -1206,7 +1657,7 @@ void pp_map_sim_oatep_k12(fp12_t r, const ep_t *p, const ep2_t *q, int m);
void pp_map_tatep_k18(fp18_t r, const ep_t p, const ep3_t q);
/**
- * Computes the Tate multi-pairing of in a parameterized elliptic curve with
+ * Computes the Tate multi-pairing in a parameterized elliptic curve with
* embedding degree 18.
*
* @param[out] r - the result.
@@ -1227,7 +1678,7 @@ void pp_map_sim_tatep_k18(fp18_t r, const ep_t *p, const ep3_t *q, int m);
void pp_map_weilp_k18(fp18_t r, const ep_t p, const ep3_t q);
/**
- * Computes the Weil multi-pairing of in a parameterized elliptic curve with
+ * Computes the Weil multi-pairing in a parameterized elliptic curve with
* embedding degree 18.
*
* @param[out] r - the result.
@@ -1248,7 +1699,7 @@ void pp_map_sim_weilp_k18(fp18_t r, const ep_t *p, const ep3_t *q, int m);
void pp_map_oatep_k18(fp18_t r, const ep_t p, const ep3_t q);
/**
- * Computes the optimal ate multi-pairing of in a parameterized elliptic
+ * Computes the optimal ate multi-pairing in a parameterized elliptic
* curve with embedding degree 18.
*
* @param[out] r - the result.
@@ -1269,7 +1720,7 @@ void pp_map_sim_oatep_k18(fp18_t r, const ep_t *p, const ep3_t *q, int m);
void pp_map_k24(fp24_t r, const ep_t p, const ep4_t q);
/**
- * Computes the optimal ate multi-pairing of in a parameterized elliptic
+ * Computes the optimal ate multi-pairing in a parameterized elliptic
* curve with embedding degree 24.
*
* @param[out] r - the result.
@@ -1287,7 +1738,18 @@ void pp_map_sim_k24(fp24_t r, const ep_t *p, const ep4_t *q, int m);
* @param[in] q - the first elliptic curve point.
* @param[in] p - the second elliptic curve point.
*/
-void pp_map_k48(fp48_t r, const ep_t p, const fp8_t qx, const fp8_t qy);
+void pp_map_k48(fp48_t r, const ep_t p, const ep8_t q);
+
+/**
+ * Computes the optimal ate multi-pairing in a parameterized elliptic
+ * curve with embedding degree 48.
+ *
+ * @param[out] r - the result.
+ * @param[in] q - the first pairing arguments.
+ * @param[in] p - the second pairing arguments.
+ * @param[in] m - the number of pairings to evaluate.
+ */
+void pp_map_sim_k48(fp48_t r, const ep_t *p, const ep8_t *q, int m);
/**
* Computes the Optimal Ate pairing of two points in a parameterized elliptic
diff --git a/include/relic_types.h b/include/relic_types.h
index ca034d5cd..7c6b93a7f 100644
--- a/include/relic_types.h
+++ b/include/relic_types.h
@@ -178,7 +178,7 @@ typedef unsigned long uint_t;
#if ALIGN > 1
#define rlc_align __attribute__ ((aligned (ALIGN)))
#else
-#define rlc_align /* empty*/
+#define rlc_align /* empty */
#endif
/**
diff --git a/preset/avr-pbc-80.sh b/preset/avr-pbc-80.sh
index 4bf44ede6..fb5ef4235 100755
--- a/preset/avr-pbc-80.sh
+++ b/preset/avr-pbc-80.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-CC=avr-gcc CXX=c++ LDFLAGS="-mmcu=atmega128 -Wl,-gc-sections" CFLAGS="-O2 -ggdb -Wa,-mmcu=atmega128 -mmcu=atmega128 -ffunction-sections -fdata-sections" cmake -DARCH=AVR -DWSIZE=8 -DOPSYS= -DSEED=LIBC -DSHLIB=OFF -DSTBIN=ON -DTIMER= -DWITH="DV;MD;BN;FP;FPX;EP;EC;PP;PC" -DBENCH=20 -DTESTS=20 -DCHECK=off -DVERBS=off -DSTRIP=on -DQUIET=on -DARITH=avr-asm-158 -DFP_PRIME=158 -DBN_METHD="COMBA;COMBA;MONTY;BASIC;BINAR;LOWER;BASIC" -DFP_QNRES=off -DFP_METHD="INTEG;COMBA;COMBA;MONTY;MONTY;SLIDE" -DBN_PRECI=160 -DBN_MAGNI=DOUBLE -DEP_PRECO=off -DEP_METHD="PROJC;LWNAF;LWNAF;BASIC" -DEP_ENDOM=on -DEP_PLAIN=on -DEC_METHD="PRIME" -DFPX_METHD="INTEG;INTEG;BASIC" -DPP_METHD="BASIC;OATEP" -DRAND=HASHD -DSEED=LIBC -DMD_METHD=SH256 $1
+CC=avr-gcc CXX=c++ LDFLAGS="-mmcu=atmega128 -Wl,-gc-sections" CFLAGS="-O2 -ggdb -Wa,-mmcu=atmega128 -mmcu=atmega128 -ffunction-sections -fdata-sections" cmake -DARCH=AVR -DWSIZE=8 -DOPSYS= -DSEED=LIBC -DSHLIB=OFF -DSTBIN=ON -DTIMER= -DWITH="DV;MD;BN;FP;FPX;EP;EC;PP;PC" -DBENCH=20 -DTESTS=20 -DCHECK=off -DVERBS=off -DSTRIP=on -DQUIET=on -DARITH=avr-asm-158 -DFP_PRIME=158 -DBN_METHD="COMBA;COMBA;MONTY;BASIC;BINAR;LOWER;BASIC" -DFP_QNRES=off -DFP_METHD="INTEG;COMBA;COMBA;MONTY;MONTY;SLIDE" -DBN_PRECI=160 -DBN_MAGNI=DOUBLE -DEP_PRECO=off -DEP_METHD="PROJC;LWNAF;LWNAF;BASIC;SSWUM" -DEP_ENDOM=on -DEP_PLAIN=on -DEC_METHD="PRIME" -DFPX_METHD="INTEG;INTEG;BASIC" -DPP_METHD="BASIC;OATEP" -DRAND=HASHD -DSEED=LIBC -DMD_METHD=SH256 $1
diff --git a/preset/fiat-pbc-bls381.sh b/preset/fiat-pbc-bls381.sh
index 51143840f..e0575f649 100755
--- a/preset/fiat-pbc-bls381.sh
+++ b/preset/fiat-pbc-bls381.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DCHECK=off -DARITH=x64-fiat-381 -DFP_PRIME=381 -DFP_QNRES=on -DFP_METHD="BASIC;COMBA;COMBA;MONTY;LOWER;LOWER;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" $1
+cmake -DCHECK=off -DARITH=x64-fiat-381 -DFP_PRIME=381 -DFP_QNRES=on -DFP_METHD="BASIC;COMBA;COMBA;MONTY;JMPDS;JMPDS;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" $1
diff --git a/preset/gmp-pbc-bls381.sh b/preset/gmp-pbc-bls381.sh
index 3fc96146a..8de5aac57 100755
--- a/preset/gmp-pbc-bls381.sh
+++ b/preset/gmp-pbc-bls381.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DCHECK=off -DARITH=gmp -DFP_PRIME=381 -DFP_QNRES=on -DFP_METHD="BASIC;COMBA;COMBA;MONTY;LOWER;LOWER;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DCFLAGS="-O2 -funroll-loops -fomit-frame-pointer" $1
+cmake -DCHECK=off -DARITH=gmp -DFP_PRIME=381 -DFP_QNRES=on -DFP_METHD="BASIC;COMBA;COMBA;MONTY;JMPDS;JMPDS;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DCFLAGS="-O2 -funroll-loops -fomit-frame-pointer" $1
diff --git a/preset/gmp-pbc-bn254.sh b/preset/gmp-pbc-bn254.sh
index ce18da40a..cf29d8bfa 100755
--- a/preset/gmp-pbc-bn254.sh
+++ b/preset/gmp-pbc-bn254.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DCHECK=off -DARITH=gmp -DFP_PRIME=254 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" $1
+cmake -DCHECK=off -DARITH=gmp -DFP_PRIME=254 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/gmp-pbc-ss1536.sh b/preset/gmp-pbc-ss1536.sh
index e08dbb044..3879f4c30 100755
--- a/preset/gmp-pbc-ss1536.sh
+++ b/preset/gmp-pbc-ss1536.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DCHECK=off -DARITH=gmp -DBN_PRECI=1536 -DFP_PRIME=1536 -DFP_QNRES=on -DFP_METHD="BASIC;COMBA;COMBA;MONTY;LOWER;LOWER;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DCFLAGS="-O2 -funroll-loops -fomit-frame-pointer" $1
+cmake -DCHECK=off -DARITH=gmp -DBN_PRECI=1536 -DFP_PRIME=1536 -DFP_QNRES=on -DFP_METHD="BASIC;COMBA;COMBA;MONTY;JMPDS;JMPDS;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" -DCFLAGS="-O2 -funroll-loops -fomit-frame-pointer" $1
diff --git a/preset/x64-ecc-128.sh b/preset/x64-ecc-128.sh
index bc6009727..dd05a799b 100755
--- a/preset/x64-ecc-128.sh
+++ b/preset/x64-ecc-128.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DCHECK=off -DARITH=x64-hacl-25519 -DFP_PRIME=255 -DFP_QNRES=off -DEC_METHD="EDDIE" -DFP_METHD="INTEG;INTEG;INTEG;QUICK;LOWER;LOWER;SLIDE" -DED_METHD='EXTND;LWNAF;COMBS;INTER' -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" $1
+cmake -DCHECK=off -DARITH=x64-hacl-25519 -DFP_PRIME=255 -DFP_QNRES=off -DSTRIP=on -DEC_ENDOM=off -DEC_METHD="EDDIE" -DFP_METHD="INTEG;INTEG;INTEG;QUICK;JMPDS;JMPDS;SLIDE" -DED_METHD='EXTND;LWNAF;COMBS;INTER' -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DWITH="DV;MD;BC;BN;FP;ED;EC;CP" $1
diff --git a/preset/x64-pbc-afg16-765.sh b/preset/x64-pbc-afg16-765.sh
new file mode 100755
index 000000000..4cc9fbcdb
--- /dev/null
+++ b/preset/x64-pbc-afg16-765.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-12l -DBN_PRECI=3072 -DFP_PRIME=765 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
diff --git a/preset/x64-pbc-bls12-377.sh b/preset/x64-pbc-bls12-377.sh
index a5fbe7367..82f57ec53 100755
--- a/preset/x64-pbc-bls12-377.sh
+++ b/preset/x64-pbc-bls12-377.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-6l -DFP_PRIME=377 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-6l -DFP_PRIME=377 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bls12-381.sh b/preset/x64-pbc-bls12-381.sh
index e3ed68136..8e388f68b 100755
--- a/preset/x64-pbc-bls12-381.sh
+++ b/preset/x64-pbc-bls12-381.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-6l -DFP_PRIME=381 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-6l -DFP_PRIME=381 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_METHD="JACOB;LWNAF;COMBS;INTER;SWIFT" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bls12-446.sh b/preset/x64-pbc-bls12-446.sh
index 07406b5df..26bd71d20 100755
--- a/preset/x64-pbc-bls12-446.sh
+++ b/preset/x64-pbc-bls12-446.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-7l -DFP_PRIME=446 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-7l -DFP_PRIME=446 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bls12-455.sh b/preset/x64-pbc-bls12-455.sh
index 302570ad2..9cb313591 100755
--- a/preset/x64-pbc-bls12-455.sh
+++ b/preset/x64-pbc-bls12-455.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-8l -DFP_PRIME=455 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-8l -DFP_PRIME=455 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bls12-638.sh b/preset/x64-pbc-bls12-638.sh
index 2b4eaabab..f9e551709 100755
--- a/preset/x64-pbc-bls12-638.sh
+++ b/preset/x64-pbc-bls12-638.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-10l -DFP_PRIME=638 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-10l -DFP_PRIME=638 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bls24-315.sh b/preset/x64-pbc-bls24-315.sh
index d7a294c9a..d80fb07ba 100755
--- a/preset/x64-pbc-bls24-315.sh
+++ b/preset/x64-pbc-bls24-315.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-5l -DFP_PRIME=315 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-5l -DFP_PRIME=315 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
diff --git a/preset/x64-pbc-bls24-317.sh b/preset/x64-pbc-bls24-317.sh
index 987b3b7f8..80d80dc83 100755
--- a/preset/x64-pbc-bls24-317.sh
+++ b/preset/x64-pbc-bls24-317.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-5l -DFP_PRIME=317 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-5l -DFP_PRIME=317 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
diff --git a/preset/x64-pbc-bls24-509.sh b/preset/x64-pbc-bls24-509.sh
index 51eafeae6..3792bd2f7 100755
--- a/preset/x64-pbc-bls24-509.sh
+++ b/preset/x64-pbc-bls24-509.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-8l -DFP_PRIME=509 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-8l -DFP_PRIME=509 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_METHD="JACOB;LWNAF;COMBS;INTER;SWIFT" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
diff --git a/preset/x64-pbc-bls48-575.sh b/preset/x64-pbc-bls48-575.sh
index 83c171bcd..32388fe17 100755
--- a/preset/x64-pbc-bls48-575.sh
+++ b/preset/x64-pbc-bls48-575.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-9l -DFP_PRIME=575 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-9l -DBN_PRECI=3072 -DFP_PRIME=575 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_METHD="JACOB;LWNAF;COMBS;INTER;SWIFT" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bn254.sh b/preset/x64-pbc-bn254.sh
index b3a0924cd..59f61e4d4 100755
--- a/preset/x64-pbc-bn254.sh
+++ b/preset/x64-pbc-bn254.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-4l -DFP_PRIME=254 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-4l -DFP_PRIME=254 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bn382.sh b/preset/x64-pbc-bn382.sh
index bb3094695..b62906f6d 100755
--- a/preset/x64-pbc-bn382.sh
+++ b/preset/x64-pbc-bn382.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-6l -DFP_PRIME=382 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-6l -DFP_PRIME=382 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=on -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-bn446.sh b/preset/x64-pbc-bn446.sh
index fb353e6b1..6fff36685 100755
--- a/preset/x64-pbc-bn446.sh
+++ b/preset/x64-pbc-bn446.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-7l -DFP_PRIME=446 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-7l -DFP_PRIME=446 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -finline-small-functions -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" $1
diff --git a/preset/x64-pbc-kss16-330.sh b/preset/x64-pbc-kss16-330.sh
new file mode 100755
index 000000000..86457dbbe
--- /dev/null
+++ b/preset/x64-pbc-kss16-330.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-6l -DFP_PRIME=330 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
diff --git a/preset/x64-pbc-kss16-766.sh b/preset/x64-pbc-kss16-766.sh
new file mode 100755
index 000000000..1f1de18ae
--- /dev/null
+++ b/preset/x64-pbc-kss16-766.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-12l -DBN_PRECI=3072 -DFP_PRIME=766 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
diff --git a/preset/x64-pbc-kss18-638.sh b/preset/x64-pbc-kss18-638.sh
index ffffd7aea..c5806438a 100755
--- a/preset/x64-pbc-kss18-638.sh
+++ b/preset/x64-pbc-kss18-638.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-10l -DFP_PRIME=638 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;LOWER;LOWER;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
+cmake -DWSIZE=64 -DRAND=UDEV -DSHLIB=OFF -DSTBIN=ON -DTIMER=CYCLE -DCHECK=off -DVERBS=off -DARITH=x64-asm-10l -DFP_PRIME=638 -DFP_METHD="INTEG;INTEG;INTEG;MONTY;JMPDS;JMPDS;SLIDE" -DCFLAGS="-O3 -funroll-loops -fomit-frame-pointer -march=native -mtune=native" -DFP_PMERS=off -DFP_QNRES=off -DFPX_METHD="INTEG;INTEG;LAZYR" -DEP_PLAIN=off -DEP_SUPER=off -DPP_METHD="LAZYR;OATEP" -DWITH="ALL" $1
diff --git a/src/bn/relic_bn_prime.c b/src/bn/relic_bn_prime.c
index 044748601..d562780dc 100644
--- a/src/bn/relic_bn_prime.c
+++ b/src/bn/relic_bn_prime.c
@@ -286,7 +286,7 @@ int bn_is_prime_rabin(const bn_t a) {
bn_set_dig(t, primes[i]);
/* Ensure t <= n - 2 as per HAC */
- if( bn_cmp(t, n1) != RLC_LT ) {
+ if (bn_cmp(t, n1) != RLC_LT) {
result = 1;
break;
}
@@ -523,32 +523,34 @@ int bn_gen_prime_factor(bn_t a, bn_t b, size_t abits, size_t bbits) {
bn_t t, u;
int result = RLC_OK;
- if (! (bbits>abits) ) {
+ if (!(bbits > abits)) {
return RLC_ERR;
- }
+ }
- bn_null(t);
+ bn_null(t);
bn_null(u);
- RLC_TRY {
- bn_new(t);
+ RLC_TRY {
+ bn_new(t);
+ bn_new(u);
+
bn_gen_prime(a, abits);
- bn_set_dig(t,1);
- bn_lsh(t, t, bbits - bn_bits(a) - 1);
- do {
- bn_rand(u, RLC_POS, bbits - bn_bits(a) - 1);
- bn_add(u, u, t);
- bn_mul(b, a, u);
- bn_add_dig(b, b, 1);
- } while ((bn_bits(b) != bbits) || (! bn_is_prime(b)));
- }
- RLC_CATCH_ANY {
+ bn_set_dig(t, 1);
+ bn_lsh(t, t, bbits - bn_bits(a) - 1);
+ do {
+ bn_rand(u, RLC_POS, bbits - bn_bits(a) - 1);
+ bn_add(u, u, t);
+ bn_mul(b, a, u);
+ bn_add_dig(b, b, 1);
+ } while ((bn_bits(b) != bbits) || (!bn_is_prime(b)));
+ }
+ RLC_CATCH_ANY {
result = RLC_ERR;
- }
- RLC_FINALLY {
- bn_free(t);
+ }
+ RLC_FINALLY {
+ bn_free(t);
bn_free(u);
- }
+ }
- return result;
+ return result;
}
diff --git a/src/cp/relic_cp_cmlhs.c b/src/cp/relic_cp_cmlhs.c
index 83b8c0980..db734fe8e 100644
--- a/src/cp/relic_cp_cmlhs.c
+++ b/src/cp/relic_cp_cmlhs.c
@@ -79,8 +79,7 @@ int cp_cmlhs_gen(bn_t x[], gt_t hs[], size_t len, uint8_t prf[], size_t plen,
result = cp_bls_gen(sk, pk);
} else {
if (cp_ecdsa_gen(sk, g1) == RLC_OK) {
- fp_copy(pk->x[0], g1->x);
- fp_copy(pk->y[0], g1->y);
+ g2_set_g1(pk, g1);
} else {
result = RLC_ERR;
}
@@ -106,7 +105,7 @@ int cp_cmlhs_sig(g1_t sig, g2_t z, g1_t a, g1_t c, g1_t r, g2_t s,
g1_t t;
uint8_t mac[RLC_MD_LEN];
size_t len, dlen = strlen(data);
- uint8_t *buf = RLC_ALLOCA(uint8_t, 1 + 8 * RLC_PC_BYTES + dlen);
+ uint8_t *buf = RLC_ALLOCA(uint8_t, 1 + 16 * RLC_PC_BYTES + dlen);
int result = RLC_OK;
bn_null(k);
@@ -217,7 +216,7 @@ int cp_cmlhs_ver(const g1_t r, const g2_t s, const g1_t sig[], const g2_t z[],
gt_t e, u, v;
bn_t k, n;
size_t len, dlen = strlen(data);
- uint8_t *buf = RLC_ALLOCA(uint8_t, 1 + 8 * RLC_PC_BYTES + dlen);
+ uint8_t *buf = RLC_ALLOCA(uint8_t, 1 + g2_size_bin(s, 0) + dlen);
int result = 1;
g1_null(g1);
@@ -249,8 +248,7 @@ int cp_cmlhs_ver(const g1_t r, const g2_t s, const g1_t sig[], const g2_t z[],
} else {
fp_prime_back(k, sig[i]->x);
fp_prime_back(n, sig[i]->y);
- fp_copy(g1->x, pk[i]->x[0]);
- fp_copy(g1->y, pk[i]->y[0]);
+ g1_set_g2(g1, pk[i]);
fp_set_dig(g1->z, 1);
result &= cp_ecdsa_ver(k, n, buf, len + dlen, 0, g1);
}
@@ -338,7 +336,7 @@ int cp_cmlhs_onv(const g1_t r, const g2_t s, const g1_t sig[], const g2_t z[],
gt_t e, u, v;
bn_t k, n;
size_t len, dlen = strlen(data);
- uint8_t *buf = RLC_ALLOCA(uint8_t, 1 + 8 * RLC_FP_BYTES + dlen);
+ uint8_t *buf = RLC_ALLOCA(uint8_t, 1 + g2_size_bin(s, 0) + dlen);
int result = 1;
g1_null(g1);
@@ -370,9 +368,7 @@ int cp_cmlhs_onv(const g1_t r, const g2_t s, const g1_t sig[], const g2_t z[],
} else {
fp_prime_back(k, sig[i]->x);
fp_prime_back(n, sig[i]->y);
- fp_copy(g1->x, pk[i]->x[0]);
- fp_copy(g1->y, pk[i]->y[0]);
- fp_set_dig(g1->z, 1);
+ g1_set_g2(g1, pk[i]);
result &= cp_ecdsa_ver(k, n, buf, len + dlen, 0, g1);
}
}
diff --git a/src/cp/relic_cp_rsa.c b/src/cp/relic_cp_rsa.c
index eb5565a00..c7ea1d67f 100644
--- a/src/cp/relic_cp_rsa.c
+++ b/src/cp/relic_cp_rsa.c
@@ -246,7 +246,7 @@ static uint8_t *hash_id(int md, int *len) {
*/
static int pad_pkcs1(bn_t m, int *p_len, size_t m_len, size_t k_len, int op) {
uint8_t *id, pad = 0;
- size_t len;
+ size_t len = 0;
int result = RLC_ERR;
bn_t t;
diff --git a/src/eb/relic_eb_map.c b/src/eb/relic_eb_map.c
index 69fd5ba7d..bbc61810f 100644
--- a/src/eb/relic_eb_map.c
+++ b/src/eb/relic_eb_map.c
@@ -56,8 +56,6 @@ void eb_map(eb_t p, const uint8_t *msg, size_t len) {
fb_set_dig(p->z, 1);
while (1) {
- bn_add_dig(k, k, 1);
- bn_mod_2b(k, k, RLC_FB_BITS);
dv_copy(p->x, k->dp, RLC_FB_DIGS);
eb_rhs(t1, p);
@@ -68,7 +66,10 @@ void eb_map(eb_t p, const uint8_t *msg, size_t len) {
/* t0 = t1/x1^2. */
fb_mul(t0, t0, t1);
/* Solve t1^2 + t1 = t0. */
- if (fb_trc(t0) == 0) {
+ if (fb_trc(t0) != 0) {
+ bn_add_dig(k, k, 1);
+ bn_mod_2b(k, k, RLC_FB_BITS);
+ } else {
fb_slv(t1, t0);
/* x3 = x1, y3 = t1 * x1, z3 = 1. */
fb_mul(p->y, t1, p->x);
diff --git a/src/eb/relic_eb_mul.c b/src/eb/relic_eb_mul.c
index e1c7e028a..b23b81141 100644
--- a/src/eb/relic_eb_mul.c
+++ b/src/eb/relic_eb_mul.c
@@ -617,22 +617,33 @@ static void eb_mul_rnaf_imp(eb_t r, const eb_t p, const bn_t k) {
void eb_mul_basic(eb_t r, const eb_t p, const bn_t k) {
eb_t t;
+ int8_t u, *naf = RLC_ALLOCA(int8_t, bn_bits(k) + 1);
+ size_t l;
+
+ eb_null(t);
if (bn_is_zero(k) || eb_is_infty(p)) {
eb_set_infty(r);
return;
}
- eb_null(t);
-
RLC_TRY {
eb_new(t);
+ if (naf == NULL) {
+ RLC_THROW(ERR_NO_BUFFER);
+ }
- eb_copy(t, p);
- for (int i = bn_bits(k) - 2; i >= 0; i--) {
+ l = bn_bits(k) + 1;
+ bn_rec_naf(naf, &l, k, 2);
+ eb_set_infty(t);
+ for (int i = l - 1; i >= 0; i--) {
eb_dbl(t, t);
- if (bn_get_bit(k, i)) {
+
+ u = naf[i];
+ if (u > 0) {
eb_add(t, t, p);
+ } else if (u < 0) {
+ eb_sub(t, t, p);
}
}
@@ -646,6 +657,7 @@ void eb_mul_basic(eb_t r, const eb_t p, const bn_t k) {
}
RLC_FINALLY {
eb_free(t);
+ RLC_FREE(naf);
}
}
@@ -718,7 +730,7 @@ void eb_mul_lodah(eb_t r, const eb_t p, const bn_t k) {
break;
}
- /* Blind both points independently. */
+ /* Blind both points indebendently. */
fb_rand(z1);
fb_mul(x1, z1, p->x);
fb_rand(r1);
diff --git a/src/eb/relic_eb_mul_sim.c b/src/eb/relic_eb_mul_sim.c
index e84497caa..9717f6a02 100644
--- a/src/eb/relic_eb_mul_sim.c
+++ b/src/eb/relic_eb_mul_sim.c
@@ -109,12 +109,6 @@ static void eb_mul_sim_kbltz(eb_t r, const eb_t p, const bn_t k, const eb_t q,
l = RLC_MAX(l0, l1);
_k = tnaf0 + l - 1;
_m = tnaf1 + l - 1;
- for (i = l0; i < l; i++) {
- tnaf0[i] = 0;
- }
- for (i = l1; i < l; i++) {
- tnaf1[i] = 0;
- }
if (bn_sign(k) == RLC_NEG) {
for (i = 0; i < l0; i++) {
@@ -184,7 +178,7 @@ static void eb_mul_sim_kbltz(eb_t r, const eb_t p, const bn_t k, const eb_t q,
*/
static void eb_mul_sim_plain(eb_t r, const eb_t p, const bn_t k, const eb_t q,
const bn_t m, const eb_t *t) {
- int i, n0, n1, w, g;
+ int i, n0, n1, w, g = (t == NULL ? 0 : 1);
int8_t naf0[RLC_FB_BITS + 1], naf1[RLC_FB_BITS + 1], *_k, *_m;
eb_t t0[1 << (RLC_WIDTH - 2)];
eb_t t1[1 << (RLC_WIDTH - 2)];
@@ -196,7 +190,6 @@ static void eb_mul_sim_plain(eb_t r, const eb_t p, const bn_t k, const eb_t q,
}
RLC_TRY {
- g = (t == NULL ? 0 : 1);
if (!g) {
for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
eb_new(t0[i]);
@@ -368,18 +361,12 @@ void eb_mul_sim_trick(eb_t r, const eb_t p, const bn_t k, const eb_t q,
}
#if RLC_WIDTH > 2 && defined(EB_MIXED)
- eb_norm_sim(t + 1, (const eb_t *)(t + 1), (1 << RLC_WIDTH) - 1);
+ eb_norm_sim(t + 2, (const eb_t *)(t + 2), (1 << (w + w)) - 2);
#endif
l0 = l1 = RLC_CEIL(RLC_FB_BITS + 1, w);
bn_rec_win(w0, &l0, k, w);
bn_rec_win(w1, &l1, m, w);
- for (int i = l0; i < l1; i++) {
- w0[i] = 0;
- }
- for (int i = l1; i < l0; i++) {
- w1[i] = 0;
- }
eb_set_infty(r);
for (int i = RLC_MAX(l0, l1) - 1; i >= 0; i--) {
diff --git a/src/ed/relic_ed_mul.c b/src/ed/relic_ed_mul.c
index f2a66a5fa..c52972926 100644
--- a/src/ed/relic_ed_mul.c
+++ b/src/ed/relic_ed_mul.c
@@ -117,10 +117,6 @@ static void ed_mul_reg_imp(ed_t r, const ed_t p, const bn_t k) {
size_t l;
bn_null(_k);
- if (bn_is_zero(k)) {
- ed_set_infty(r);
- return;
- }
RLC_TRY {
bn_new(_k);
@@ -139,7 +135,7 @@ static void ed_mul_reg_imp(ed_t r, const ed_t p, const bn_t k) {
_k->dp[0] |= bn_is_even(_k);
/* Compute the w-NAF representation of k. */
- l = RLC_CEIL(RLC_FP_BITS + 1, RLC_WIDTH - 1);
+ l = RLC_CEIL(RLC_FP_BITS + 1, RLC_WIDTH - 1) + 1;
bn_rec_reg(reg, &l, _k, RLC_FP_BITS, RLC_WIDTH);
ed_set_infty(r);
@@ -197,22 +193,34 @@ static void ed_mul_reg_imp(ed_t r, const ed_t p, const bn_t k) {
void ed_mul_basic(ed_t r, const ed_t p, const bn_t k) {
ed_t t;
+ int8_t u, *naf = RLC_ALLOCA(int8_t, bn_bits(k) + 1);
+ size_t l;
ed_null(t);
if (bn_is_zero(k) || ed_is_infty(p)) {
+ RLC_FREE(naf);
ed_set_infty(r);
return;
}
RLC_TRY {
ed_new(t);
+ if (naf == NULL) {
+ RLC_THROW(ERR_NO_BUFFER);
+ }
- ed_copy(t, p);
- for (int i = bn_bits(k) - 2; i >= 0; i--) {
+ l = bn_bits(k) + 1;
+ bn_rec_naf(naf, &l, k, 2);
+ ed_set_infty(t);
+ for (int i = l - 1; i >= 0; i--) {
ed_dbl(t, t);
- if (bn_get_bit(k, i)) {
+
+ u = naf[i];
+ if (u > 0) {
ed_add(t, t, p);
+ } else if (u < 0) {
+ ed_sub(t, t, p);
}
}
@@ -226,6 +234,7 @@ void ed_mul_basic(ed_t r, const ed_t p, const bn_t k) {
}
RLC_FINALLY {
ed_free(t);
+ RLC_FREE(naf);
}
}
diff --git a/src/ed/relic_ed_mul_sim.c b/src/ed/relic_ed_mul_sim.c
index a7b28d8b3..1cb62a4b7 100644
--- a/src/ed/relic_ed_mul_sim.c
+++ b/src/ed/relic_ed_mul_sim.c
@@ -53,14 +53,13 @@
*/
static void ed_mul_sim_plain(ed_t r, const ed_t p, const bn_t k, const ed_t q,
const bn_t m, const ed_t *t) {
- int i, n0, n1, w, gen;
+ int i, n0, n1, w, gen = (t == NULL ? 0 : 1);
int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], *_k, *_m;
ed_t t0[1 << (RLC_WIDTH - 2)];
ed_t t1[1 << (RLC_WIDTH - 2)];
size_t l, l0, l1;
RLC_TRY {
- gen = (t == NULL ? 0 : 1);
if (!gen) {
for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
ed_null(t0[i]);
@@ -232,20 +231,13 @@ void ed_mul_sim_trick(ed_t r, const ed_t p, const bn_t k, const ed_t q,
}
#if defined(ED_MIXED)
- ed_norm_sim(t + 1, (const ed_t *)t + 1, (1 << (RLC_WIDTH)) - 1);
+ ed_norm_sim(t + 2, (const ed_t *)t + 2, (1 << ((w + w))) - 2);
#endif
l0 = l1 = RLC_CEIL(RLC_FP_BITS, w);
bn_rec_win(w0, &l0, k, w);
bn_rec_win(w1, &l1, m, w);
- for (int i = l0; i < l1; i++) {
- w0[i] = 0;
- }
- for (int i = l1; i < l0; i++) {
- w1[i] = 0;
- }
-
ed_set_infty(r);
for (int i = RLC_MAX(l0, l1) - 1; i >= 0; i--) {
for (int j = 0; j < w; j++) {
diff --git a/src/ep/relic_ep_curve.c b/src/ep/relic_ep_curve.c
index f4aa0f329..9f3cf7e7b 100644
--- a/src/ep/relic_ep_curve.c
+++ b/src/ep/relic_ep_curve.c
@@ -79,19 +79,20 @@ static void detect_opt(int *opt, fp_t a) {
* @param[in] u - the non-square used for hashing to this curve.
* @param[in] ctmap - true if this curve will use an isogeny for mapping.
*/
-static void ep_curve_set_map(const fp_t u) {
+static void ep_curve_set_map(void) {
bn_t t;
bn_null(t);
- const int abNeq0 = (ep_curve_opt_a() != RLC_ZERO) && (ep_curve_opt_b() != RLC_ZERO);
+ const int abNeq0 = (ep_curve_opt_a() * ep_curve_opt_b()) != RLC_ZERO;
ctx_t *ctx = core_get();
- dig_t *c1 = ctx->ep_map_c[0];
- dig_t *c2 = ctx->ep_map_c[1];
- dig_t *c3 = ctx->ep_map_c[2];
- dig_t *c4 = ctx->ep_map_c[3];
-
- fp_copy(ctx->ep_map_u, u);
+ dig_t *c0 = ctx->ep_map_c[0];
+ dig_t *c1 = ctx->ep_map_c[1];
+ dig_t *c2 = ctx->ep_map_c[2];
+ dig_t *c3 = ctx->ep_map_c[3];
+ dig_t *c4 = ctx->ep_map_c[4];
+ dig_t *c5 = ctx->ep_map_c[5];
+ dig_t *c6 = ctx->ep_map_c[6];
RLC_TRY {
bn_new(t);
@@ -101,56 +102,118 @@ static void ep_curve_set_map(const fp_t u) {
/* constants 3 and 4: a and b for either the curve or the isogeny */
#ifdef EP_CTMAP
if (ep_curve_is_ctmap()) {
- fp_copy(c3, ctx->ep_iso.a);
- fp_copy(c4, ctx->ep_iso.b);
+ fp_copy(c2, ctx->ep_iso.a);
+ fp_copy(c3, ctx->ep_iso.b);
} else {
#endif
- fp_copy(c3, ctx->ep_a);
- fp_copy(c4, ctx->ep_b);
+ fp_copy(c2, ctx->ep_a);
+ fp_copy(c3, ctx->ep_b);
+ /* Generate a non-square u to define the map. */
+ fp_set_dig(ctx->ep_map_u, 0);
+ do {
+ fp_add_dig(ctx->ep_map_u, ctx->ep_map_u, 1);
+ /* Check that g(b/ua) = u^3 + a * u + b is square*/
+ fp_mul(c1, ctx->ep_a, ctx->ep_map_u);
+ fp_inv(c1, c1);
+ fp_mul(c1, c1, ctx->ep_b);
+ fp_sqr(c0, c1);
+ fp_add(c0, c0, ctx->ep_a);
+ fp_mul(c0, c0, ctx->ep_map_u);
+ fp_add(c0, c0, ctx->ep_b);
+ } while (fp_is_sqr(ctx->ep_map_u) || !fp_is_sqr(c0));
#ifdef EP_CTMAP
}
#endif
/* constant 1: -b / a */
- fp_neg(c1, c3); /* c1 = -a */
- fp_inv(c1, c1); /* c1 = -1 / a */
- fp_mul(c1, c1, c4); /* c1 = -b / a */
+ fp_neg(c0, c2); /* c0 = -a */
+ fp_inv(c0, c0); /* c0 = -1 / a */
+ fp_mul(c0, c0, c3); /* c0 = -b / a */
/* constant 2 is unused in this case */
} else {
/* SvdW map constants */
- /* constant 1: g(u) = u^3 + a * u + b */
- fp_sqr(c1, ctx->ep_map_u);
- fp_add(c1, c1, ctx->ep_a);
- fp_mul(c1, c1, ctx->ep_map_u);
- fp_add(c1, c1, ctx->ep_b);
-
- /* constant 2: -u / 2 */
- fp_set_dig(c2, 1);
- fp_neg(c2, c2); /* -1 */
- fp_hlv(c2, c2); /* -1/2 */
- fp_mul(c2, c2, ctx->ep_map_u); /* c2 = -1/2 * u */
-
- /* constant 3: sqrt(-g(u) * (3 * u^2 + 4 * a)) */
- fp_sqr(c3, ctx->ep_map_u); /* c3 = u^2 */
- fp_mul_dig(c3, c3, 3); /* c3 = 3 * u^2 */
- fp_mul_dig(c4, ctx->ep_a, 4); /* c4 = 4 * a */
- fp_add(c4, c3, c4); /* c4 = 3 * u^2 + 4 * a */
- fp_neg(c4, c4); /* c4 = -(3 * u^2 + 4 * a) */
- fp_mul(c3, c4, c1); /* c3 = -g(u) * (3 * u^2 + 4 * a) */
- if (!fp_srt(c3, c3)) { /* c3 = sqrt(-g(u) * (3 * u^2 + 4 * a)) */
+ fp_set_dig(ctx->ep_map_u, 0);
+ do {
+ /* Generate u by trial and error. */
+ fp_add_dig(ctx->ep_map_u, ctx->ep_map_u, 1);
+
+ /* constant 1: g(u) = u^3 + a * u + b */
+ fp_sqr(c0, ctx->ep_map_u);
+ fp_add(c0, c0, ctx->ep_a);
+ fp_mul(c0, c0, ctx->ep_map_u);
+ fp_add(c0, c0, ctx->ep_b);
+
+ /* constant 2: -u / 2 */
+ fp_set_dig(c1, 1);
+ fp_neg(c1, c1); /* -1 */
+ fp_hlv(c1, c1); /* -1/2 */
+ fp_mul(c1, c1, ctx->ep_map_u); /* c1 = -1/2 * u */
+
+ /* constant 3: sqrt(-g(u) * (3 * u^2 + 4 * a)) */
+ fp_sqr(c2, ctx->ep_map_u); /* c2 = u^2 */
+ fp_mul_dig(c2, c2, 3); /* c2 = 3 * u^2 */
+ fp_mul_dig(c3, ctx->ep_a, 4); /* c3 = 4 * a */
+ fp_add(c3, c2, c3); /* c3 = 3 * u^2 + 4 * a */
+ fp_neg(c3, c3); /* c3 = -(3 * u^2 + 4 * a) */
+ fp_mul(c2, c3, c0); /* c2 = -g(u) * (3 * u^2 + 4 * a) */
+ } while (fp_is_zero(c2) || !fp_is_sqr(c2));
+ if (!fp_srt(c2, c2)) { /* c2 = sqrt(-g(u) * (3 * u^2 + 4 * a)) */
RLC_THROW(ERR_NO_VALID);
}
- /* make sure sgn0(c3) == 0 */
- fp_prime_back(t, c3);
+ /* make sure sgn0(c2) == 0 */
+ fp_prime_back(t, c2);
if (bn_get_bit(t, 0) != 0) {
- /* set sgn0(c3) == 0 */
- fp_neg(c3, c3);
+ /* set sgn0(c2) == 0 */
+ fp_neg(c2, c2);
}
/* constant 4: -4 * g(u) / (3 * u^2 + 4 * a) */
- fp_inv(c4, c4); /* c4 = -1 / (3 * u^2 + 4 * a) */
- fp_mul(c4, c4, c1); /* c4 *= g(u) */
- fp_mul_dig(c4, c4, 4); /* c4 *= 4 */
+ fp_inv(c3, c3); /* c3 = -1 / (3 * u^2 + 4 * a) */
+ fp_mul(c3, c3, c0); /* c3 *= g(u) */
+ fp_mul_dig(c3, c3, 4); /* c3 *= 4 */
+ }
+
+ /* if b = 0, precompute constants. */
+ if (ep_curve_opt_b() == RLC_ZERO) {
+ dig_t r = 0;
+
+ fp_set_dig(c4, -fp_prime_get_qnr());
+ fp_neg(c4, c4);
+
+ bn_read_raw(t, fp_prime_get(), RLC_FP_DIGS);
+ bn_sub_dig(t, t, 1);
+ bn_rsh(t, t, 2);
+ fp_exp(c5, c4, t);
+
+ bn_read_raw(t, fp_prime_get(), RLC_FP_DIGS);
+ if ((t->dp[0] & 0xF) == 5) {
+ /* n = (3p + 1)/16 */
+ bn_mul_dig(t, t, 3);
+ bn_add_dig(t, t, 1);
+ r = 1;
+ } else {
+ /* n = (p + 3)/16 */
+ bn_add_dig(t, t, 3);
+ r = 3;
+ }
+ bn_rsh(t, t, 4);
+ /* Compute d = 1/c^n. */
+ fp_exp(c4, c4, t);
+ fp_inv(c4, c4);
+ fp_exp_dig(c5, c5, r);
+ /* Compute 1/sqrt(-1) as well. */
+ fp_set_dig(c6, 1);
+ fp_neg(c6, c6);
+ fp_srt(c6, c6);
+ }
+
+ /* If a = 0, precompute and store a square root of -3. */
+ if (ep_curve_opt_a() == RLC_ZERO) {
+ fp_set_dig(c4, 3);
+ fp_neg(c4, c4);
+ if (!fp_srt(c4, c4)) {
+ RLC_THROW(ERR_NO_VALID);
+ }
}
}
RLC_CATCH_ANY {
@@ -173,7 +236,7 @@ static void ep_curve_set_map(const fp_t u) {
* @param[in] ctmap - true if this curve will use an isogeny for mapping.
*/
static void ep_curve_set(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
- const bn_t h, const fp_t u, int ctmap) {
+ const bn_t h, int ctmap) {
ctx_t *ctx = core_get();
fp_copy(ctx->ep_a, a);
@@ -186,7 +249,7 @@ static void ep_curve_set(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
detect_opt(&(ctx->ep_opt_b3), ctx->ep_b3);
ctx->ep_is_ctmap = ctmap;
- ep_curve_set_map(u);
+ ep_curve_set_map();
ep_norm(&(ctx->ep_g), g);
bn_copy(&(ctx->ep_r), r);
@@ -391,12 +454,21 @@ iso_t ep_curve_get_iso() {
#if defined(EP_PLAIN)
void ep_curve_set_plain(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
- const bn_t h, const fp_t u, int ctmap) {
+ const bn_t h, int ctmap) {
ctx_t *ctx = core_get();
ctx->ep_is_endom = 0;
ctx->ep_is_super = 0;
- ep_curve_set(a, b, g, r, h, u, ctmap);
+ /* We do not use beta due to lack of endomorphisms so compute and cache
+ * square root of -1 for evaluating the distortion map in pairing-friendly
+ * curves with embedding degree 1. */
+ if (ctx->ep_is_pairf) {
+ fp_set_dig(ctx->beta, 1);
+ fp_neg(ctx->beta, ctx->beta);
+ fp_srt(ctx->beta, ctx->beta);
+ }
+
+ ep_curve_set(a, b, g, r, h, ctmap);
}
#endif
@@ -404,12 +476,12 @@ void ep_curve_set_plain(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
#if defined(EP_SUPER)
void ep_curve_set_super(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
- const bn_t h, const fp_t u, int ctmap) {
+ const bn_t h, int ctmap) {
ctx_t *ctx = core_get();
ctx->ep_is_endom = 0;
ctx->ep_is_super = 1;
- ep_curve_set(a, b, g, r, h, u, ctmap);
+ ep_curve_set(a, b, g, r, h, ctmap);
}
#endif
@@ -417,13 +489,13 @@ void ep_curve_set_super(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
#if defined(EP_ENDOM)
void ep_curve_set_endom(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
- const bn_t h, const fp_t beta, const bn_t l, const fp_t u, int ctmap) {
+ const bn_t h, const fp_t beta, const bn_t l, int ctmap) {
int bits = bn_bits(r);
ctx_t *ctx = core_get();
ctx->ep_is_endom = 1;
ctx->ep_is_super = 0;
- ep_curve_set(a, b, g, r, h, u, ctmap);
+ ep_curve_set(a, b, g, r, h, ctmap);
/* Precompute endomorphism constants. */
#if EP_MUL == LWNAF || EP_FIX == COMBS || EP_FIX == LWNAF || EP_SIM == INTER || !defined(STRIP)
@@ -441,20 +513,27 @@ void ep_curve_set_endom(const fp_t a, const fp_t b, const ep_t g, const bn_t r,
/* Check if [m]P = \psi(P). */
fp_copy(ctx->beta, beta);
- bn_copy(m, l);
- ep_psi(p, g);
- ep_copy(q, g);
- for (int i = bn_bits(m) - 2; i >= 0; i--) {
- ep_dbl(q, q);
- if (bn_get_bit(m, i)) {
- ep_add(q, q, g);
- }
+ /* Fix lambda in case it is negative. */
+ if (bn_sign(l) == RLC_NEG) {
+ bn_add(m, l, r);
+ } else {
+ bn_copy(m, l);
}
- ep_norm(q, q);
+ /* Now check that beta and lambda match each other. */
+ ep_psi(p, g);
+ ep_mul_basic(q, g, m);
/* Fix beta in case it is the wrong value. */
if (ep_cmp(q, p) != RLC_EQ) {
fp_neg(ctx->beta, ctx->beta);
- fp_sub_dig(ctx->beta, ctx->beta, 1);
+ if (fp_is_zero(a)) {
+ /* In this case, look for other choice of beta. */
+ fp_sub_dig(ctx->beta, ctx->beta, 1);
+ }
+ ep_psi(p, g);
+ ep_mul_basic(q, g, m);
+ if (ep_cmp(q, p) != RLC_EQ) {
+ RLC_THROW(ERR_NO_VALID);
+ }
}
bn_gcd_ext_mid(&(ctx->ep_v1[1]), &(ctx->ep_v1[2]), &(ctx->ep_v2[1]),
&(ctx->ep_v2[2]), m, r);
diff --git a/src/ep/relic_ep_map.c b/src/ep/relic_ep_map.c
index c34d3a4cc..f95f9d047 100644
--- a/src/ep/relic_ep_map.c
+++ b/src/ep/relic_ep_map.c
@@ -72,23 +72,25 @@ TMPL_MAP_SVDW(ep, fp, dig_t, EP_MAP_COPY_COND);
#undef EP_MAP_COPY_COND
-/* caution: this function overwrites k, which used as an auxiliary variable */
-static inline int fp_sgn0(const fp_t t, bn_t k) {
- fp_prime_back(k, t);
- return bn_get_bit(k, 0);
-}
-
-/*============================================================================*/
-/* Public definitions */
-/*============================================================================*/
-
-void ep_map_from_field(ep_t p, const uint8_t *uniform_bytes, size_t len) {
+/**
+ * Maps an array of uniformly random bytes to a point in a prime elliptic
+ * curve.
+ * That array is expected to have a length suitable for two field elements plus
+ * extra bytes for uniformity.
+ *
+ * @param[out] p - the result.
+ * @param[in] uniform_bytes - the array of uniform bytes to map.
+ * @param[in] len - the array length in bytes.
+ * @param[in] map_fn - the mapping function.
+ */
+static void ep_map_from_field(ep_t p, const uint8_t *uniform_bytes, size_t len,
+ const void (*const map_fn)(ep_t, const fp_t)) {
bn_t k;
fp_t t;
ep_t q;
int neg;
/* enough space for two field elements plus extra bytes for uniformity */
- const int len_per_elm = (FP_PRIME + ep_param_level() + 7) / 8;
+ const size_t len_per_elm = (FP_PRIME + ep_param_level() + 7) / 8;
bn_null(k);
fp_null(t);
@@ -103,29 +105,23 @@ void ep_map_from_field(ep_t p, const uint8_t *uniform_bytes, size_t len) {
fp_new(t);
ep_new(q);
- /* figure out which hash function to use */
- const int abNeq0 = (ep_curve_opt_a() != RLC_ZERO) &&
- (ep_curve_opt_b() != RLC_ZERO);
- void (*const map_fn)(ep_t, fp_t) = (ep_curve_is_ctmap() ||
- abNeq0) ? ep_map_sswu : ep_map_svdw;
-
#define EP_MAP_CONVERT_BYTES(IDX) \
- do { \
- bn_read_bin(k, uniform_bytes + IDX * len_per_elm, len_per_elm); \
- fp_prime_conv(t, k); \
- } while (0)
+ do { \
+ bn_read_bin(k, uniform_bytes + IDX * len_per_elm, len_per_elm); \
+ fp_prime_conv(t, k); \
+ } while (0)
#define EP_MAP_APPLY_MAP(PT) \
- do { \
- /* check sign of t */ \
- neg = fp_sgn0(t, k); \
- /* convert */ \
- map_fn(PT, t); \
- /* compare sign of y and sign of t; fix if necessary */ \
- neg = neg != fp_sgn0(PT->y, k); \
- fp_neg(t, PT->y); \
- dv_copy_cond(PT->y, t, RLC_FP_DIGS, neg); \
- } while (0)
+ do { \
+ /* check sign of t */ \
+ neg = fp_is_even(t); \
+ /* convert */ \
+ map_fn(PT, t); \
+ /* compare sign of y and sign of t; fix if necessary */ \
+ neg = neg != fp_is_even(PT->y); \
+ fp_neg(t, PT->y); \
+ dv_copy_cond(PT->y, t, RLC_FP_DIGS, neg); \
+ } while (0)
/* first map invocation */
EP_MAP_CONVERT_BYTES(0);
@@ -146,34 +142,7 @@ void ep_map_from_field(ep_t p, const uint8_t *uniform_bytes, size_t len) {
/* sum the result */
ep_add(p, p, q);
ep_norm(p, p);
-
- /* clear cofactor */
- switch (ep_curve_is_pairf()) {
- case EP_BN:
- /* h = 1 */
- break;
- case EP_B12:
- case EP_B24:
- /* Multiply by (1-x) to get the correct group, as proven in
- * Piellard. https://eprint.iacr.org/2022/352.pdf */
- fp_prime_get_par(k);
- bn_neg(k, k);
- bn_add_dig(k, k, 1);
- if (bn_bits(k) < RLC_DIG) {
- ep_mul_dig(p, p, k->dp[0]);
- } else {
- ep_mul(p, p, k);
- }
- break;
- default:
- /* multiply by cofactor to get the correct group. */
- ep_curve_get_cof(k);
- if (bn_bits(k) < RLC_DIG) {
- ep_mul_dig(p, p, k->dp[0]);
- } else {
- ep_mul_basic(p, p, k);
- }
- }
+ ep_mul_cof(p, p);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -185,29 +154,427 @@ void ep_map_from_field(ep_t p, const uint8_t *uniform_bytes, size_t len) {
}
}
-void ep_map_dst(ep_t p, const uint8_t *msg, size_t len, const uint8_t *dst,
- size_t dst_len) {
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_MAP == BASIC || !defined(STRIP)
+
+void ep_map_basic(ep_t p, const uint8_t *msg, size_t len) {
+ bn_t x;
+ fp_t t0;
+ uint8_t digest[RLC_MD_LEN];
+
+ bn_null(x);
+ fp_null(t0);
+
+ RLC_TRY {
+ bn_new(x);
+ fp_new(t0);
+
+ md_map(digest, msg, len);
+ bn_read_bin(x, digest, RLC_MIN(RLC_FP_BYTES, RLC_MD_LEN));
+
+ fp_zero(p->x);
+ fp_prime_conv(p->x, x);
+ fp_set_dig(p->z, 1);
+
+ while (1) {
+ ep_rhs(t0, p);
+
+ if (fp_smb(t0) == 1) {
+ fp_srt(p->y, t0);
+ p->coord = BASIC;
+ break;
+ }
+
+ fp_add_dig(p->x, p->x, 1);
+ }
+
+ ep_mul_cof(p, p);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(x);
+ fp_free(t0);
+ }
+}
+
+#endif
+#if EP_MAP == SSWUM || !defined(STRIP)
+
+void ep_map_sswum(ep_t p, const uint8_t *msg, size_t len) {
/* enough space for two field elements plus extra bytes for uniformity */
- const int len_per_elm = (FP_PRIME + ep_param_level() + 7) / 8;
- uint8_t *pseudo_random_bytes = RLC_ALLOCA(uint8_t, 2 * len_per_elm);
+ const size_t elm = (FP_PRIME + ep_param_level() + 7) / 8;
+ uint8_t *r = RLC_ALLOCA(uint8_t, 2 * elm);
RLC_TRY {
/* for hash_to_field, need to hash to a pseudorandom string */
/* XXX(rsw) the below assumes that we want to use MD_MAP for hashing.
* Consider making the hash function a per-curve option!
*/
- md_xmd(pseudo_random_bytes, 2 * len_per_elm, msg, len, dst, dst_len);
- ep_map_from_field(p, pseudo_random_bytes, 2 * len_per_elm);
+ md_xmd(r, 2 * elm, msg, len, (const uint8_t *)"RELIC", 5);
+ /* figure out which hash function to use */
+ const int abNeq0 = (ep_curve_opt_a() != RLC_ZERO) &&
+ (ep_curve_opt_b() != RLC_ZERO);
+ const void (*const map_fn)(ep_t, const fp_t) = (void (*const))
+ (ep_curve_is_ctmap() || abNeq0 ? ep_map_sswu : ep_map_svdw);
+ ep_map_from_field(p, r, 2 * elm, map_fn);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
- RLC_FREE(pseudo_random_bytes);
+ RLC_FREE(r);
}
}
-void ep_map(ep_t p, const uint8_t *msg, size_t len) {
- ep_map_dst(p, msg, len, (const uint8_t *)"RELIC", 5);
+#endif
+
+#if EP_MAP == SWIFT || !defined(STRIP)
+
+void ep_map_swift(ep_t p, const uint8_t *msg, size_t len) {
+ /* enough space for two field elements plus extra bytes for uniformity */
+ const size_t len_per_elm = (FP_PRIME + ep_param_level() + 7) / 8;
+ uint8_t s, *pseudo_random_bytes = RLC_ALLOCA(uint8_t, 2 * len_per_elm + 1);
+ fp_t c, t, u, v, w, y, x1, y1, z1;
+ ctx_t *ctx = core_get();
+ bn_t k;
+
+ bn_null(k);
+ fp_null(c);
+ fp_null(t);
+ fp_null(u);
+ fp_null(v);
+ fp_null(w);
+ fp_null(y);
+ fp_null(x1);
+ fp_null(y1);
+ fp_null(z1);
+
+ RLC_TRY {
+ bn_new(k);
+ fp_new(c);
+ fp_new(t);
+ fp_new(u);
+ fp_new(v);
+ fp_new(w);
+ fp_new(y);
+ fp_new(x1);
+ fp_new(y1);
+ fp_new(z1);
+
+ md_xmd(pseudo_random_bytes, 2 * len_per_elm + 1, msg, len,
+ (const uint8_t *)"RELIC", 5);
+
+ bn_read_bin(k, pseudo_random_bytes, len_per_elm);
+ fp_prime_conv(u, k);
+ bn_read_bin(k, pseudo_random_bytes + len_per_elm, len_per_elm);
+ fp_prime_conv(t, k);
+ s = pseudo_random_bytes[2 * len_per_elm] & 1;
+
+ if ((ep_curve_opt_b() == RLC_ZERO) && (ctx->mod8 == 1)) {
+ /* This is the approach due to Koshelev introduced in
+ * https://eprint.iacr.org/2021/1034.pdf */
+
+ /* Compute t^2 = 3c*sqrt(a)*(2c^3*x^6 - 3*c^2*x^4 - 3*c*x^2 + 2).*/
+ /* Compute w = 3*c. */
+ fp_set_dig(c, -fp_prime_get_qnr());
+ fp_neg(c, c);
+ fp_dbl(w, c);
+ fp_add(w, w, c);
+
+ /* Compute x^2, x^4 and x^6 in sequence. */
+ fp_sqr(z1, u);
+ fp_sqr(y1, z1);
+ fp_mul(t, z1, y1);
+
+ fp_dbl(t, t);
+ fp_mul(t, t, c);
+ fp_mul(t, t, c);
+ fp_mul(t, t, c);
+
+ fp_mul(v, y1, c);
+ fp_mul(v, v, w);
+ fp_sub(t, t, v);
+
+ /* v = -3*c*x^2. */
+ fp_mul(v, w, z1);
+ fp_neg(v, v);
+ fp_add(t, t, v);
+ fp_add_dig(t, t, 2);
+
+ /* Assume a = 1 for simplicitly. */
+ fp_mul(t, t, w);
+ fp_mul(t, t, ctx->ep_map_c[6]);
+ dig_t c1 = fp_is_sqr(t);
+ /* If t is not square, compute u = 1/(uc), t = sqrt(t/c)/(c*u^3)*/
+ fp_inv(v, c);
+ fp_inv(x1, u);
+ fp_mul(y1, t, v);
+ /* If t is a square, extract its square root. */
+ dv_copy_cond(t, y1, RLC_FP_DIGS, !c1);
+ fp_srt(t, t);
+ fp_mul(y1, t, v);
+ fp_sqr(y, x1);
+ fp_mul(y, y, x1);
+ fp_mul(y1, y1, y);
+ fp_mul(x1, x1, v);
+ dv_copy_cond(u, x1, RLC_FP_DIGS, !c1);
+ dv_copy_cond(t, y1, RLC_FP_DIGS, !c1);
+
+ /* Compute x = sqrt(a)*(c*x^2 - 2)/(-3*c*x^2). */
+ fp_sqr(z1, u);
+ fp_mul(v, w, z1);
+ fp_neg(v, v);
+ fp_inv(v, v);
+ fp_mul(p->x, z1, c);
+ fp_sub_dig(p->x, p->x, 2);
+ fp_mul(p->x, p->x, v);
+ fp_mul(p->x, p->x, ctx->ep_map_c[6]);
+
+ /* Compute y = y*2*sqrt(a)/(3^2*c^2*x^3). */
+ fp_mul(z1, z1, u);
+ fp_sqr(w, w);
+ fp_mul(w, w, z1);
+ fp_inv(w, w);
+ fp_dbl(p->y, ctx->ep_map_c[6]);
+ fp_mul(p->y, p->y, t);
+ fp_mul(p->y, p->y, w);
+ fp_set_dig(p->z, 1);
+ p->coord = BASIC;
+ } else if ((ep_curve_opt_b() == RLC_ZERO) && (ctx->mod8 != 1)) {
+ /* This is the approach due to Koshelev introduced in
+ * https://eprint.iacr.org/2021/1604.pdf */
+ fp_set_dig(c, -fp_prime_get_qnr());
+ fp_neg(c, c);
+
+ /* u = t0, t = t1, v = t0^4, y = t1^4, w = c^2, z1 = 8*a^2*c. */
+ fp_sqr(v, u);
+ fp_sqr(v, v);
+ fp_sqr(y, t);
+ fp_sqr(y, y);
+ fp_sqr(w, c);
+ fp_sqr(z1, ep_curve_get_a());
+ fp_mul(z1, z1, c);
+ fp_dbl(z1, z1);
+ fp_dbl(z1, z1);
+ fp_dbl(z1, z1);
+ /* w = c^2*t0^4+t1^4, y1 = c^4*t0^8, x1 = 2*c^2*t0^4*t1^4, y = t1^8. */
+ fp_mul(w, w, v);
+ fp_sqr(y1, w);
+ fp_mul(x1, w, y);
+ fp_dbl(x1, x1);
+ fp_add(w, w, y);
+ fp_sqr(y, y);
+ /* w = den = 8*a^2*c(c^2*t0^4 + t1^4), z1 = 16*a^3*c^2. */
+ fp_mul(w, w, z1);
+ fp_inv(p->z, w);
+ fp_mul(z1, z1, c);
+ fp_mul(z1, z1, ep_curve_get_a());
+ fp_dbl(z1, z1);
+ /* v = num2 = c^4*t0^8 - 2*c^2t0^4*t1^4 + t1^8 - 16*a^3*c^2*/
+ fp_sub(v, y1, x1);
+ fp_add(v, v, y);
+ fp_sub(v, v, z1);
+ /* w = num0 = t0 * ac(-3*c^4t0^8 + 2c^2*t0^4*t1^4 + t1^8 + 16*a^3*c^2)*/
+ fp_add(w, y, z1);
+ fp_add(w, w, x1);
+ fp_sub(w, w, y1);
+ fp_sub(w, w, y1);
+ fp_sub(w, w, y1);
+ fp_mul(w, w, u);
+ fp_mul(w, w, c);
+ fp_mul(w, w, ep_curve_get_a());
+ /* z1 = num1 = t1 * ac^2(c^4t0^8 + 2c^2t0^4*t1^4 - 3^t1^8 + 16a^3c^2)*/
+ fp_sub(z1, z1, y);
+ fp_sub(z1, z1, y);
+ fp_sub(z1, z1, y);
+ fp_add(z1, z1, x1);
+ fp_add(z1, z1, y1);
+ fp_mul(z1, z1, t);
+ fp_mul(z1, z1, c);
+ fp_mul(z1, z1, c);
+ fp_mul(z1, z1, ep_curve_get_a());
+ /* v2 = num2/den = v/w. */
+ fp_mul(w, w, p->z);
+ fp_mul(z1, z1, p->z);
+ fp_mul(v, v, p->z);
+ fp_inv(v, v);
+
+ bn_read_raw(k, fp_prime_get(), RLC_FP_DIGS);
+ if ((k->dp[0] & 0xF) == 5) {
+ /* n = (3p + 1)/16 */
+ bn_mul_dig(k, k, 3);
+ bn_add_dig(k, k, 1);
+ } else if ((k->dp[0] & 0xF) == 13) {
+ /* n = (p + 3)/16 */
+ bn_add_dig(k, k, 3);
+ } else {
+ RLC_THROW(ERR_NO_VALID);
+ }
+ bn_rsh(k, k, 4);
+ /* Compute x1 = f = (1/v2)^3 + a*(1/v2) = (1/v2)((1/v2)^2 + a). */
+ fp_sqr(x1, v);
+ fp_add(x1, x1, ep_curve_get_a());
+ fp_mul(x1, x1, v);
+ /* Compute y = theta, zp = theta^4. */
+ fp_exp(y, x1, k);
+ fp_sqr(p->z, y);
+ fp_sqr(p->z, p->z);
+ /* Perform the base change from (t0,t1) to (u0, u1). */
+ fp_sqr(u, u);
+ fp_mul(u, u, c);
+ fp_sqr(t, t);
+ fp_mul(t, t, c);
+ /* Compute c = i^r * f. */
+ fp_mul(c, ctx->ep_map_c[5], x1);
+ fp_copy(p->x, v);
+ fp_sqr(p->y, y);
+ p->coord = BASIC;
+ /* We use zp as temporary, but there is no problem with \psi. */
+ int index = 0;
+ fp_copy(y1, u);
+ /* Make the following constant-time. */
+ for (int m = 0; m < 4; m++) {
+ fp_mul(y1, y1, ctx->ep_map_c[5]);
+ index += (fp_bits(y1) < fp_bits(u));
+ }
+ for (int m = 0; m < index; m++) {
+ ep_psi(p, p);
+ }
+ fp_neg(y1, x1);
+ /* Compute 1/d * 1/theta. */
+ fp_inv(y, y);
+ fp_mul(y, y, ctx->ep_map_c[4]);
+ dig_t c0 = fp_cmp(p->z, x1) == RLC_EQ;
+ dig_t c1 = fp_cmp(p->z, y1) == RLC_EQ;
+ dig_t c2 = fp_cmp(p->z, c) == RLC_EQ;
+ fp_neg(c, c);
+ dig_t c3 = fp_cmp(p->z, c) == RLC_EQ;
+ c2 = !c0 && !c1 && c2;
+ c3 = !c0 && !c1 && !c2 && c3;
+ fp_copy(p->z, ctx->ep_map_c[6]);
+ fp_mul(p->z, p->z, p->y);
+ dv_copy_cond(p->y, p->z, RLC_FP_DIGS, c1);
+ fp_copy(y1, ctx->ep_map_c[4]);
+ /* Convert from projective coordinates on the surface to affine. */
+ fp_mul(u, u, v);
+ fp_mul(t, t, v);
+ fp_sqr(v, v);
+ fp_mul(w, w, v);
+ fp_mul(z1, z1, v);
+ /* Compute (x,y) = (x0/(d*theta)^2, y0/(d*theta)^3). */
+ fp_sqr(y1, y);
+ fp_mul(u, u, y1);
+ fp_mul(w, w, y);
+ fp_mul(w, w, y1);
+ dv_copy_cond(p->x, u, RLC_FP_DIGS, c2);
+ dv_copy_cond(p->y, w, RLC_FP_DIGS, c2);
+ /* Compute (x,y) = (x1/(d^3*theta)^2, y1/(d^3*theta)^3). */
+ fp_mul(z1, z1, y);
+ fp_mul(t, t, y1);
+ fp_mul(z1, z1, y1);
+ fp_sqr(y, ctx->ep_map_c[4]);
+ fp_mul(z1, z1, y);
+ fp_sqr(y, y);
+ fp_mul(t, t, y);
+ fp_mul(z1, z1, y);
+ dv_copy_cond(p->x, t, RLC_FP_DIGS, c3);
+ dv_copy_cond(p->y, z1, RLC_FP_DIGS, c3);
+ /* Multiply by cofactor. */
+ fp_set_dig(p->z, 1);
+ ep_mul_cof(p, p);
+ } else {
+ /* This is the SwiftEC case per se. */
+ if (ep_curve_opt_a() != RLC_ZERO) {
+ RLC_THROW(ERR_NO_VALID);
+ } else {
+ fp_sqr(x1, u);
+ fp_mul(x1, x1, u);
+ fp_sqr(y1, t);
+ fp_add(x1, x1, ctx->ep_b);
+ fp_sub(x1, x1, y1);
+ fp_dbl(y1, y1);
+ fp_add(y1, y1, x1);
+ fp_mul(z1, u, ctx->ep_map_c[4]);
+ fp_mul(x1, x1, z1);
+ fp_mul(z1, z1, t);
+ fp_dbl(z1, z1);
+
+ fp_dbl(y, y1);
+ fp_sqr(y, y);
+ fp_mul(v, y1, u);
+ fp_sub(v, x1, v);
+ fp_mul(v, v, z1);
+ fp_mul(w, y1, z1);
+ fp_dbl(w, w);
+
+ if (fp_is_zero(w)) {
+ ep_set_infty(p);
+ } else {
+ fp_inv(w, w);
+ fp_mul(x1, v, w);
+ fp_add(y1, u, x1);
+ fp_neg(y1, y1);
+ fp_mul(z1, y, w);
+ fp_sqr(z1, z1);
+ fp_add(z1, z1, u);
+
+ fp_sqr(t, x1);
+ fp_mul(t, t, x1);
+ fp_add(t, t, ep_curve_get_b());
+
+ fp_sqr(u, y1);
+ fp_mul(u, u, y1);
+ fp_add(u, u, ep_curve_get_b());
+
+ fp_sqr(v, z1);
+ fp_mul(v, v, z1);
+ fp_add(v, v, ep_curve_get_b());
+
+ int c2 = fp_is_sqr(u);
+ int c3 = fp_is_sqr(v);
+
+ dv_swap_cond(x1, y1, RLC_FP_DIGS, c2);
+ dv_swap_cond(t, u, RLC_FP_DIGS, c2);
+ dv_swap_cond(x1, z1, RLC_FP_DIGS, c3);
+ dv_swap_cond(t, v, RLC_FP_DIGS, c3);
+
+ if (!fp_srt(t, t)) {
+ RLC_THROW(ERR_NO_VALID);
+ }
+ fp_neg(u, t);
+ dv_swap_cond(t, u, RLC_FP_DIGS, fp_is_even(t) ^ s);
+
+ fp_copy(p->x, x1);
+ fp_copy(p->y, t);
+ fp_set_dig(p->z, 1);
+ p->coord = BASIC;
+ ep_mul_cof(p, p);
+ }
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(k);
+ fp_free(c);
+ fp_free(t);
+ fp_free(u);
+ fp_free(v);
+ fp_free(w);
+ fp_free(y);
+ fp_free(x1);
+ fp_free(y1);
+ fp_free(z1);
+ RLC_FREE(pseudo_random_bytes);
+ }
}
+
+#endif
diff --git a/src/ep/relic_ep_mul.c b/src/ep/relic_ep_mul.c
index 5b51b9119..6a47f081a 100644
--- a/src/ep/relic_ep_mul.c
+++ b/src/ep/relic_ep_mul.c
@@ -124,9 +124,6 @@ static void ep_mul_glv_imp(ep_t r, const ep_t p, const bn_t k) {
}
/* Convert r to affine coordinates. */
ep_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -145,7 +142,6 @@ static void ep_mul_glv_imp(ep_t r, const ep_t p, const bn_t k) {
bn_free(v1[i]);
bn_free(v2[i]);
}
-
}
}
@@ -195,9 +191,6 @@ static void ep_mul_naf_imp(ep_t r, const ep_t p, const bn_t k) {
}
/* Convert r to affine coordinates. */
ep_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -215,8 +208,6 @@ static void ep_mul_naf_imp(ep_t r, const ep_t p, const bn_t k) {
#endif /* EP_PLAIN || EP_SUPER */
#endif /* EP_MUL == LWNAF */
-#if EP_MUL == LWREG || !defined(STRIP)
-
#if defined(EP_ENDOM)
static void ep_mul_reg_glv(ep_t r, const ep_t p, const bn_t k) {
@@ -260,8 +251,7 @@ static void ep_mul_reg_glv(ep_t r, const ep_t p, const bn_t k) {
ep_curve_get_v1(v1);
ep_curve_get_v2(v2);
- bn_abs(_k, k);
- bn_mod(_k, _k, n);
+ bn_mod(_k, k, n);
bn_rec_glv(k0, k1, _k, n, (const bn_t *)v1, (const bn_t *)v2);
s0 = bn_sign(k0);
@@ -341,8 +331,6 @@ static void ep_mul_reg_glv(ep_t r, const ep_t p, const bn_t k) {
/* Convert r to affine coordinates. */
ep_norm(r, r);
- ep_neg(u, r);
- dv_copy_cond(r->y, u->y, RLC_FP_DIGS, bn_sign(k) == RLC_NEG);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -378,11 +366,6 @@ static void ep_mul_reg_imp(ep_t r, const ep_t p, const bn_t k) {
ep_t t[1 << (RLC_WIDTH - 2)], u, v;
size_t l;
- if (bn_is_zero(k)) {
- ep_set_infty(r);
- return;
- }
-
bn_null(_k);
RLC_TRY {
@@ -460,7 +443,6 @@ static void ep_mul_reg_imp(ep_t r, const ep_t p, const bn_t k) {
}
#endif /* EP_PLAIN || EP_SUPER */
-#endif /* EP_MUL == LWNAF */
/*============================================================================*/
/* Public definitions */
@@ -468,22 +450,34 @@ static void ep_mul_reg_imp(ep_t r, const ep_t p, const bn_t k) {
void ep_mul_basic(ep_t r, const ep_t p, const bn_t k) {
ep_t t;
+ int8_t u, *naf = RLC_ALLOCA(int8_t, bn_bits(k) + 1);
+ size_t l;
ep_null(t);
if (bn_is_zero(k) || ep_is_infty(p)) {
ep_set_infty(r);
+ RLC_FREE(naf);
return;
}
RLC_TRY {
ep_new(t);
+ if (naf == NULL) {
+ RLC_THROW(ERR_NO_BUFFER);
+ }
- ep_copy(t, p);
- for (int i = bn_bits(k) - 2; i >= 0; i--) {
+ l = bn_bits(k) + 1;
+ bn_rec_naf(naf, &l, k, 2);
+ ep_set_infty(t);
+ for (int i = l - 1; i >= 0; i--) {
ep_dbl(t, t);
- if (bn_get_bit(k, i)) {
+
+ u = naf[i];
+ if (u > 0) {
ep_add(t, t, p);
+ } else if (u < 0) {
+ ep_sub(t, t, p);
}
}
@@ -497,6 +491,7 @@ void ep_mul_basic(ep_t r, const ep_t p, const bn_t k) {
}
RLC_FINALLY {
ep_free(t);
+ RLC_FREE(naf);
}
}
@@ -560,9 +555,6 @@ void ep_mul_slide(ep_t r, const ep_t p, const bn_t k) {
}
ep_norm(r, q);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -578,7 +570,7 @@ void ep_mul_slide(ep_t r, const ep_t p, const bn_t k) {
}
#endif
-#include "assert.h"
+
#if EP_MUL == MONTY || !defined(STRIP)
void ep_mul_monty(ep_t r, const ep_t p, const bn_t k) {
@@ -623,7 +615,7 @@ void ep_mul_monty(ep_t r, const ep_t p, const bn_t k) {
ep_blind(t[1], t[1]);
for (int i = bits - 1; i >= 0; i--) {
- int j = bn_get_bit(l, i);
+ int j = bn_get_bit(l, i);
dv_swap_cond(t[0]->x, t[1]->x, RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->y, t[1]->y, RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->z, t[1]->z, RLC_FP_DIGS, j ^ 1);
@@ -635,8 +627,6 @@ void ep_mul_monty(ep_t r, const ep_t p, const bn_t k) {
}
ep_norm(r, t[0]);
- ep_neg(t[0], r);
- dv_copy_cond(r->y, t[0]->y, RLC_FP_DIGS, bn_sign(_k) == RLC_NEG);
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
@@ -673,8 +663,8 @@ void ep_mul_lwnaf(ep_t r, const ep_t p, const bn_t k) {
#endif
-#if EP_MUL == LWREG || !defined(STRIP)
-
+/* Conditional compilation of the function below was turned off because it
+ * is used by the default for protected scalar multiplication in G1. */
void ep_mul_lwreg(ep_t r, const ep_t p, const bn_t k) {
if (bn_is_zero(k) || ep_is_infty(p)) {
ep_set_infty(r);
@@ -693,8 +683,6 @@ void ep_mul_lwreg(ep_t r, const ep_t p, const bn_t k) {
#endif
}
-#endif
-
void ep_mul_gen(ep_t r, const bn_t k) {
if (bn_is_zero(k)) {
ep_set_infty(r);
diff --git a/src/ep/relic_ep_mul_cof.c b/src/ep/relic_ep_mul_cof.c
new file mode 100644
index 000000000..1da814637
--- /dev/null
+++ b/src/ep/relic_ep_mul_cof.c
@@ -0,0 +1,153 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2022 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of point multiplication of a prime elliptic curve by the
+ * curve cofactor.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+#include "relic_md.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep_mul_cof(ep_t r, const ep_t p) {
+ ep_t v;
+ bn_t k;
+ bn_t l;
+
+ bn_null(k);
+ bn_null(l);
+ ep_null(v);
+
+ RLC_TRY {
+ bn_new(k);
+ bn_new(l);
+ ep_new(v);
+
+ switch (ep_curve_is_pairf()) {
+#if defined(EP_ENDOM) && !defined(STRIP)
+ case EP_BN:
+ /* h = 1 */
+ break;
+ case EP_B12:
+ case EP_B24:
+ case EP_B48:
+ /* Multiply by (1-x) to get the correct group, as proven in
+ * Piellard. https://eprint.iacr.org/2022/352.pdf */
+ fp_prime_get_par(k);
+ bn_neg(k, k);
+ bn_add_dig(k, k, 1);
+ if (bn_bits(k) < RLC_DIG) {
+ ep_mul_dig(r, p, k->dp[0]);
+ } else {
+ ep_mul_basic(r, p, k);
+ }
+ break;
+ case EP_N16:
+ /* if (u % 2) == 0, compute = (u * (u**3+1)//2)*P
+ * else Compute (u * (u**3+1))*P */
+ fp_prime_get_par(k);
+ bn_sqr(l, k);
+ bn_mul(l, l, k);
+ bn_add_dig(l, l, 1);
+ bn_mul(k, l, k);
+ if (bn_is_even(k)) {
+ bn_hlv(k, k);
+ }
+ if (bn_bits(k) < RLC_DIG) {
+ ep_mul_dig(r, p, k->dp[0]);
+ } else {
+ ep_mul_basic(r, p, k);
+ }
+ break;
+ case EP_K16:
+ /* Compute 1250*(P + [(u+1)/2]phi(P)) */
+ fp_prime_get_par(k);
+ bn_add_dig(k, k, 1);
+ bn_hlv(k, k);
+ ep_dbl(r, p);
+ ep_norm(r, r);
+ ep_psi(v, r);
+ ep_neg(v, v);
+ ep_mul_dig(v, v, 182);
+ ep_add(r, r, v);
+ ep_norm(r, r);
+ ep_psi(v, r);
+ ep_neg(v, v);
+ if (bn_bits(k) < RLC_DIG) {
+ ep_mul_dig(v, v, k->dp[0]);
+ } else {
+ ep_mul_basic(v, v, k);
+ }
+ ep_add(r, r, v);
+ ep_norm(r, r);
+ break;
+ case EP_K18:
+ /* Compute 343*(P + [u+3]psi(P)). */
+ fp_prime_get_par(k);
+ bn_add_dig(k, k, 3);
+ ep_psi(v, p);
+ if (bn_bits(k) < RLC_DIG) {
+ ep_mul_dig(v, v, k->dp[0]);
+ } else {
+ ep_mul_basic(v, v, k);
+ }
+ ep_add(v, v, p);
+ ep_norm(r, v);
+ ep_mul_dig(r, r, 49);
+ ep_mul_dig(r, r, 7);
+ break;
+ case EP_SG18:
+ /* Compute [3u^2-1]P. */
+ fp_prime_get_par(k);
+ ep_mul_basic(v, p, k);
+ bn_mul_dig(k, k, 3);
+ ep_mul_basic(v, v, k);
+ ep_sub(v, v, p);
+ ep_norm(r, v);
+ break;
+#endif
+ default:
+ /* multiply by cofactor to get the correct group. */
+ ep_curve_get_cof(k);
+ if (bn_bits(k) < RLC_DIG) {
+ ep_mul_dig(r, p, k->dp[0]);
+ } else {
+ ep_mul_basic(r, p, k);
+ }
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(k);
+ bn_free(l);
+ ep_free(v);
+ }
+}
diff --git a/src/ep/relic_ep_mul_fix.c b/src/ep/relic_ep_mul_fix.c
index 5505cafb2..cb7dcbe56 100644
--- a/src/ep/relic_ep_mul_fix.c
+++ b/src/ep/relic_ep_mul_fix.c
@@ -175,9 +175,6 @@ static void ep_mul_combs_endom(ep_t r, const ep_t *t, const bn_t k) {
}
}
ep_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -250,9 +247,6 @@ static void ep_mul_combs_plain(ep_t r, const ep_t *t, const bn_t k) {
}
}
ep_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -323,9 +317,6 @@ void ep_mul_fix_basic(ep_t r, const ep_t *t, const bn_t k) {
}
}
ep_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(r, r);
- }
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
@@ -500,9 +491,6 @@ void ep_mul_fix_combd(ep_t r, const ep_t *t, const bn_t k) {
ep_add(r, r, t[(1 << RLC_DEPTH) + w1]);
}
ep_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
diff --git a/src/ep/relic_ep_mul_sim.c b/src/ep/relic_ep_mul_sim.c
index 3e74ae224..9f6cacdb3 100644
--- a/src/ep/relic_ep_mul_sim.c
+++ b/src/ep/relic_ep_mul_sim.c
@@ -488,14 +488,13 @@ void ep_mul_sim_lot_endom(ep_t r, const ep_t p[], const bn_t k[], int n) {
*/
static void ep_mul_sim_plain(ep_t r, const ep_t p, const bn_t k, const ep_t q,
const bn_t m, const ep_t *t) {
- int i, w, gen;
+ int i, w, gen = (t == NULL ? 0 : 1);
int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], n0, n1, *u, *v;
ep_t t0[1 << (RLC_WIDTH - 2)];
ep_t t1[1 << (RLC_WIDTH - 2)];
size_t l, l0, l1;
RLC_TRY {
- gen = (t == NULL ? 0 : 1);
if (!gen) {
for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
ep_null(t0[i]);
@@ -719,18 +718,12 @@ void ep_mul_sim_trick(ep_t r, const ep_t p, const bn_t k, const ep_t q,
ep_set_infty(t0[0]);
ep_copy(t0[1], p);
- if (bn_sign(_k) == RLC_NEG) {
- ep_neg(t0[1], t0[1]);
- }
for (int i = 2; i < (1 << w); i++) {
ep_add(t0[i], t0[i - 1], t0[1]);
}
ep_set_infty(t1[0]);
ep_copy(t1[1], q);
- if (bn_sign(_m) == RLC_NEG) {
- ep_neg(t1[1], t1[1]);
- }
for (int i = 2; i < (1 << w); i++) {
ep_add(t1[i], t1[i - 1], t1[1]);
}
@@ -742,18 +735,12 @@ void ep_mul_sim_trick(ep_t r, const ep_t p, const bn_t k, const ep_t q,
}
#if RLC_WIDTH > 2 && defined(EP_MIXED)
- ep_norm_sim(t + 1, (const ep_t *)(t + 1), (1 << RLC_WIDTH) - 1);
+ ep_norm_sim(t + 2, (const ep_t *)(t + 2), (1 << (w + w)) - 2);
#endif
l0 = l1 = RLC_CEIL(RLC_FP_BITS + 1, w);
bn_rec_win(w0, &l0, _k, w);
bn_rec_win(w1, &l1, _m, w);
- for (int i = l0; i < l1; i++) {
- w0[i] = 0;
- }
- for (int i = l1; i < l0; i++) {
- w1[i] = 0;
- }
ep_set_infty(r);
for (int i = RLC_MAX(l0, l1) - 1; i >= 0; i--) {
diff --git a/src/ep/relic_ep_param.c b/src/ep/relic_ep_param.c
index 2f5e5150a..eec143808 100644
--- a/src/ep/relic_ep_param.c
+++ b/src/ep/relic_ep_param.c
@@ -64,7 +64,6 @@
#define SECG_P160_Y "23A628553168947D59DCC912042351377AC5FB32"
#define SECG_P160_R "100000000000000000001F4C8F927AED3CA752257"
#define SECG_P160_H "1"
-#define SECG_P160_MAPU "3"
/** @} */
#endif
@@ -79,7 +78,6 @@
#define SECG_K160_Y "938CF935318FDCED6BC28286531733C3F03C4FEE"
#define SECG_K160_R "100000000000000000001B8FA16DFAB9ACA16B6B3"
#define SECG_K160_H "1"
-#define SECG_K160_MAPU "-1"
/** @} */
#endif
@@ -94,7 +92,6 @@
#define NIST_P192_Y "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"
#define NIST_P192_R "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"
#define NIST_P192_H "1"
-#define NIST_P192_MAPU "-5"
/** @} */
#endif
@@ -109,7 +106,6 @@
#define SECG_K192_Y "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"
#define SECG_K192_R "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"
#define SECG_K192_H "1"
-#define SECG_K192_MAPU "1"
/** @} */
#endif
@@ -124,7 +120,6 @@
#define CURVE_22103_Y "36429404D97E1E217BAD2E5601F6551F95D8FE9481BD454D1F3E7B6"
#define CURVE_22103_R "3FFFFFFFFFFFFFFFFFFFFFFFFFFF5CD04695A145C3067CF4AAE2025"
#define CURVE_22103_H "8"
-#define CURVE_22103_MAPU "F"
/** @} */
#endif
@@ -139,7 +134,6 @@
#define NIST_P224_Y "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"
#define NIST_P224_R "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"
#define NIST_P224_H "1"
-#define NIST_P224_MAPU "1F"
/** @} */
#endif
@@ -154,9 +148,6 @@
#define SECG_K224_Y "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"
#define SECG_K224_R "10000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"
#define SECG_K224_H "1"
-#define SECG_K224_BETA "FE0E87005B4E83761908C5131D552A850B3F58B749C37CF5B84D6768"
-#define SECG_K224_LAMB "60DCD2104C4CBC0BE6EEEFC2BDD610739EC34E317F9B33046C9E4788"
-#define SECG_K224_MAPU "-1"
/** @} */
#endif
@@ -171,7 +162,6 @@
#define CURVE_4417_Y "3E9036ADC1A41FCE2F2CA08E2D1BE4F6D97E30CA7761DB1F3E2F2CE96"
#define CURVE_4417_R "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4A75594D4923FC93D42713CDAF"
#define CURVE_4417_H "4"
-#define CURVE_4417_MAPU "-E"
/** @} */
#endif
@@ -186,7 +176,6 @@
#define CURVE_1174_Y "66FE4E7B8B6FE152F743393029A61BFB839747C8FB00F7B27A6841C07532A0"
#define CURVE_1174_R "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77965C4DFD307348944D45FD166C971"
#define CURVE_1174_H "4"
-#define CURVE_1174_MAPU "-A"
/** @} */
#endif
@@ -201,7 +190,6 @@
#define CURVE_25519_Y "72FB43CD5568B3B691204CA8E6A2930633716B80FE7DADAF91E072344991E1F1"
#define CURVE_25519_R "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"
#define CURVE_25519_H "8"
-#define CURVE_25519_MAPU "8"
/** @} */
#endif
@@ -216,7 +204,6 @@
#define NIST_P256_Y "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
#define NIST_P256_R "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
#define NIST_P256_H "1"
-#define NIST_P256_MAPU "-A"
/** @} */
#endif
@@ -231,7 +218,6 @@
#define BSI_P256_Y "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997"
#define BSI_P256_R "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7"
#define BSI_P256_H "1"
-#define BSI_P256_MAPU "-2"
/** @} */
#endif
@@ -246,9 +232,6 @@
#define SECG_K256_Y "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"
#define SECG_K256_R "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
#define SECG_K256_H "1"
-#define SECG_K256_BETA "7AE96A2B657C07106E64479EAC3434E99CF0497512F58995C1396C28719501EE"
-#define SECG_K256_LAMB "5363AD4CC05C30E0A5261C028812645A122E22EA20816678DF02967C1B23BD72"
-#define SECG_K256_MAPU "1"
/** @} */
#endif
@@ -263,7 +246,6 @@
#define SM2_P256_Y "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
#define SM2_P256_R "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
#define SM2_P256_H "1"
-#define SM2_P256_MAPU "-A"
/** @} */
#endif
@@ -278,7 +260,6 @@
#define CURVE_67254_Y "D51BF79D968F4A076022E750F821058E2B5073697B639EDD355EBF8AD32352B1EFA9478DE7EB5662EF0D26EF6EEA795"
#define CURVE_67254_R "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5FB21F21E95EEE17C5E69281B102D2773E27E13FD3C9719"
#define CURVE_67254_H "4"
-#define CURVE_67254_MAPU "-9"
/** @} */
#endif
@@ -293,7 +274,6 @@
#define CURVE_383187_Y "55AB95F2C81569A8E2EADF7C823B133547094AF055BDB287DF4B89F07F1E187D6FCF17FAFA89375C092463FD3D750C55"
#define CURVE_383187_R "1000000000000000000000000000000000000000000000000E85A85287A1488ACD41AE84B2B7030446F72088B00A0E21"
#define CURVE_383187_H "8"
-#define CURVE_383187_MAPU "2"
/** @} */
#endif
@@ -308,7 +288,6 @@
#define NIST_P384_Y "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"
#define NIST_P384_R "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"
#define NIST_P384_H "1"
-#define NIST_P384_MAPU "-C"
/** @} */
#endif
@@ -323,7 +302,6 @@
#define CURVE_511187_Y "4515C654CEF9B490BDD32C5DC3930C3E287752AF10D0438213A2873B4A71BA95DD90EE5B3A0D0A1ACD6DBEECC0AB188B748EDF0D31BF92E434867B5948DE59C9"
#define CURVE_511187_R "100000000000000000000000000000000000000000000000000000000000000017B5FEFF30C7F5677AB2AEEBD13779A2AC125042A6AA10BFA54C15BAB76BAF1B"
#define CURVE_511187_H "8"
-#define CURVE_511187_MAPU "-18"
/** @} */
#endif
@@ -338,7 +316,6 @@
#define NIST_P521_Y "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"
#define NIST_P521_R "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"
#define NIST_P521_H "1"
-#define NIST_P521_MAPU "-4"
/** @} */
#endif
@@ -353,7 +330,6 @@
#define BN_P158_Y "4"
#define BN_P158_R "240000006ED000007FE96000419F59800C9FFD81"
#define BN_P158_H "1"
-#define BN_P158_MAPU "1"
/** @} */
#endif
@@ -368,7 +344,6 @@
#define BN_P254_Y "1"
#define BN_P254_R "2523648240000001BA344D8000000007FF9F800000000010A10000000000000D"
#define BN_P254_H "1"
-#define BN_P254_MAPU "-1"
/** @} */
#endif
@@ -383,9 +358,6 @@
#define TWEEDLEDUM_Y "D27E5D5B7C3AFAED0754EA62B947B23546EBF597530A7369EDC466E456761D8"
#define TWEEDLEDUM_R "40000000000000000000000000000000038AA127696286C9842CAFD400000001"
#define TWEEDLEDUM_H "1"
-#define TWEEDLEDUM_BETA "1508415AB5E97C949BEBC9146EF83D9A7881FB239BA41A268598ABB3A410C9C8"
-#define TWEEDLEDUM_LAMB "36C66D3A1E049A5887AD8B5FF9731FFE69CF8DE720E52EC14394C2BD148FA4FD"
-#define TWEEDLEDUM_MAPU "-1"
/** @} */
#endif
@@ -400,7 +372,6 @@
#define BN_P256_Y "4"
#define BN_P256_R "B64000000000FF2F2200000085FD547FD8001F44B6B7F4B7C2BC818F7B6BEF99"
#define BN_P256_H "1"
-#define BN_P256_MAPU "1"
/** @} */
#endif
@@ -415,7 +386,6 @@
#define SM9_P256_Y "21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616"
#define SM9_P256_R "B640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25"
#define SM9_P256_H "1"
-#define SM9_P256_MAPU "-1"
/** @} */
#endif
@@ -430,7 +400,6 @@
#define B24_P315_Y "2E6F83C55DEFF20227ECDF0DB2BB2EBB5D72C8A29010871D3CCE9059E83DFB96F2922D5DA4E4E5F"
#define B24_P315_R "196DEAC24A9DA12B25FC7EC9CF927A98C8C480ECE644E36419D0C5FD00C00001"
#define B24_P315_H "2FE8030000000000"
-#define B24_P315_MAPU "-2"
/** @} */
#endif
@@ -445,7 +414,20 @@
#define B24_P317_Y "32239CB1D737F2283BA0707D11B291DF9AC9255DF42134F7D5C9A6B3B4038E13B4544BDC6F7E333"
#define B24_P317_R "443F917EA68DAFC2D0B097F28D83CD491CD1E79196BF0E7AF000000000000001"
#define B24_P317_H "3D512E5584A9AAAB"
-#define B24_P317_MAPU "-3"
+/** @} */
+#endif
+
+#if defined(EP_ENDOM) && FP_PRIME == 330
+/**
+ * Parameters for a 766-bit pairing-friendly prime curve.
+ */
+/** @{ */
+#define K16_P330_A "1"
+#define K16_P330_B "0"
+#define K16_P330_X "033596D1D0B1FEB292325D72BB9872B1A8DF543FFFFF83B0802DC45CA4B714C533D085235CD2F470111"
+#define K16_P330_Y "1FCDBF207B0F767A67CFCFB017C7EEB580CF5C9D39B6D872AE2F091E12028107C097DCB606B30388E5D"
+#define K16_P330_R "A9AE90F426EE7F9DB56D9C82F1C0B2CA3CB15B2F8ABF5803C963444D043D2731"
+#define K16_P330_H "3772AC7257379575CB4"
/** @} */
#endif
@@ -460,7 +442,6 @@
#define B12_P377_Y "1914A69C5102EFF1F674F5D30AFEEC4BD7FB348CA3E52D96D182AD44FB82305C2FE3D3634A9591AFD82DE55559C8EA6"
#define B12_P377_R "12AB655E9A2CA55660B44D1E5C37B00159AA76FED00000010A11800000000001"
#define B12_P377_H "170B5D44300000000000000000000000"
-#define B12_P377_MAPU "-2"
/** @} */
#endif
@@ -483,8 +464,6 @@
#define B12_P381_ISO_YN "90D97C81BA24EE0259D1F094980DCFA11AD138E48A869522B52AF6C956543D3CD0C7AEE9B3BA3C2BE9845719707BB33;134996A104EE5811D51036D776FB46831223E96C254F383D0F906343EB67AD34D6C56711962FA8BFE097E75A2E41C696;CC786BAA966E66F4A384C86A3B49942552E2D658A31CE2C344BE4B91400DA7D26D521628B00523B8DFE240C72DE1F6;1F86376E8981C217898751AD8746757D42AA7B90EEB791C09E4A3EC03251CF9DE405ABA9EC61DECA6355C77B0E5F4CB;8CC03FDEFE0FF135CAF4FE2A21529C4195536FBE3CE50B879833FD221351ADC2EE7F8DC099040A841B6DAECF2E8FEDB;16603FCA40634B6A2211E11DB8F0A6A074A7D0D4AFADB7BD76505C3D3AD5544E203F6326C95A807299B23AB13633A5F0;4AB0B9BCFAC1BBCB2C977D027796B3CE75BB8CA2BE184CB5231413C4D634F3747A87AC2460F415EC961F8855FE9D6F2;987C8D5333AB86FDE9926BD2CA6C674170A05BFE3BDD81FFD038DA6C26C842642F64550FEDFE935A15E4CA31870FB29;9FC4018BD96684BE88C9E221E4DA1BB8F3ABD16679DC26C1E8B6E6A1F20CABE69D65201C78607A360370E577BDBA587;E1BBA7A1186BDB5223ABDE7ADA14A23C42A0CA7915AF6FE06985E7ED1E4D43B9B3F7055DD4EBA6F2BAFAAEBCA731C30;19713E47937CD1BE0DFD0B8F1D43FB93CD2FCBCB6CAF493FD1183E416389E61031BF3A5CCE3FBAFCE813711AD011C132;18B46A908F36F6DEB918C143FED2EDCC523559B8AAF0C2462E6BFE7F911F643249D9CDF41B44D606CE07C8A4D0074D8E;B182CAC101B9399D155096004F53F447AA7B12A3426B08EC02710E807B4633F06C851C1919211F20D4C04F00B971EF8;245A394AD1ECA9B72FC00AE7BE315DC757B3B080D4C158013E6632D3C40659CC6CF90AD1C232A6442D9D3F5DB980133;5C129645E44CF1102A159F748C4A3FC5E673D81D7E86568D9AB0F5D396A7CE46BA1049B6579AFB7866B1E715475224B;15E6BE4E990F03CE4EA50B3B42DF2EB5CB181D8F84965A3957ADD4FA95AF01B2B665027EFEC01C7704B456BE69C8B604"
#define B12_P381_ISO_YD "16112C4C3A9C98B252181140FAD0EAE9601A6DE578980BE6EEC3232B5BE72E7A07F3688EF60C206D01479253B03663C1;1962D75C2381201E1A0CBD6C43C348B885C84FF731C4D59CA4A10356F453E01F78A4260763529E3532F6102C2E49A03D;58DF3306640DA276FAAAE7D6E8EB15778C4855551AE7F310C35A5DD279CD2ECA6757CD636F96F891E2538B53DBF67F2;16B7D288798E5395F20D23BF89EDB4D1D115C5DBDDBCD30E123DA489E726AF41727364F2C28297ADA8D26D98445F5416;BE0E079545F43E4B00CC912F8228DDCC6D19C9F0F69BBB0542EDA0FC9DEC916A20B15DC0FD2EDEDDA39142311A5001D;8D9E5297186DB2D9FB266EAAC783182B70152C65550D881C5ECD87B6F0F5A6449F38DB9DFA9CCE202C6477FAAF9B7AC;166007C08A99DB2FC3BA8734ACE9824B5EECFDFA8D0CF8EF5DD365BC400A0051D5FA9C01A58B1FB93D1A1399126A775C;16A3EF08BE3EA7EA03BCDDFABBA6FF6EE5A4375EFA1F4FD7FEB34FD206357132B920F5B00801DEE460EE415A15812ED9;1866C8ED336C61231A1BE54FD1D74CC4F9FB0CE4C6AF5920ABC5750C4BF39B4852CFE2F7BB9248836B233D9D55535D4A;167A55CDA70A6E1CEA820597D94A84903216F763E13D87BB5308592E7EA7D4FBC7385EA3D529B35E346EF48BB8913F55;4D2F259EEA405BD48F010A01AD2911D9C6DD039BB61A6290E591B36E636A5C871A5C29F4F83060400F8B49CBA8F6AA8;ACCBB67481D033FF5852C1E48C50C477F94FF8AEFCE42D28C0F9A88CEA7913516F968986F7EBBEA9684B529E2561092;AD6B9514C767FE3C3613144B45F1496543346D98ADF02267D5CEEF9A00D9B8693000763E3B90AC11E99B138573345CC;2660400EB2E4F3B628BDD0D53CD76F2BF565B94E72927C1CB748DF27942480E420517BD8714CC80D1FADC1326ED06F7;E0FA1D816DDC03E6B24255E0D7819C171C40F65E273B853324EFCD6356CAA205CA2F570F13497804415473A1D634B8F;1"
#define B12_P381_MAPU "B"
-#else /* !defined(EP_CTMAP) */
-#define B12_P381_MAPU "-3"
#endif /* EP_CTMAP */
/** @} */
#endif
@@ -500,7 +479,6 @@
#define BN_P382_Y "1"
#define BN_P382_R "24009015183F94892D996CC179C6D1666F82CEFBE47879BB46E4CDA2E2E2281D08DC008E80108252004200000000000D"
#define BN_P382_H "1"
-#define BN_P382_MAPU "2"
/** @} */
#endif
@@ -515,7 +493,6 @@
#define B12_P383_Y "DD3BFDE4A26B777CEDA2A8F1C4C4E6192C586D8227CC05A34705CCC5A32288C0944408D54909F31BF5C664E81778B03"
#define B12_P383_R "1002001800C00B809C04401C81698B381DE05F095A120D3973B2099EBFEBC0001"
#define B12_P383_H "555AAAC000AABBFFB550556155169EAB"
-#define B12_P383_MAPU "5"
/** @} */
#endif
@@ -530,7 +507,6 @@
#define BN_P446_Y "10"
#define BN_P446_R "2400000000000000002400000002D00000000D800000021C00000017A0000000870000000AD400000054C000000156000000126000000061"
#define BN_P446_H "1"
-#define BN_P446_MAPU "1"
#endif
#if defined(EP_ENDOM) && FP_PRIME == 446
@@ -544,7 +520,6 @@
#define B12_P446_Y "DC40DDCBAB2823A7870B5C688AA04FEE40369D913E4F2F0947A152FE1C27A79B7F787E9C35B869C3846FAC4F12A70D0FE22D2E244268CC"
#define B12_P446_R "511B70539F27995B34995830FA4D04C98CCC4C050BC7BB9B0E8D8CA34610428001400040001"
#define B12_P446_H "C02082602B0055D560AB0AD5AAAAC0002AAAC"
-#define B12_P446_MAPU "2"
#endif
#if defined(EP_ENDOM) && FP_PRIME == 455
@@ -558,7 +533,6 @@
#define B12_P455_Y "19A8A9C4C3AC2FFB4C6B380D17B8282E029615052EAA6416C16C8F36F251D87C272657F0702CC58C4E072628D7BAD3C0E9B3A8AEBFC6B2357C"
#define B12_P455_R "10000080000380002E0000F10004F00025E000750001D1000A00000400001C00007FFFFC00001"
#define B12_P455_H "555556AAAAB15555B54AAB6A9557FFAABFFAAB"
-#define B12_P455_MAPU "-1"
#endif
#if defined(EP_ENDOM) && FP_PRIME == 508
@@ -566,15 +540,12 @@
* Parameters for a 508-bit pairing-friendly prime curve at the 192-bit security level.
*/
/** @{ */
-#define KSS_P508_A "0"
-#define KSS_P508_B "2"
-#define KSS_P508_X "3ADD59EAC7B6A0ABC781139CE46388AB3426C6619C27187CB1F2B48AC92E04608AFBD25DA121EDB06015CB5D2BCF369C03C163605BBA21FAF7D550960553784"
-#define KSS_P508_Y "8773227730CBE52483BF6AAAA9E4FE2870B463FA14D92C31D0F99C6B6EE13106A0E8C87AD7631F8ECCE0DD6189B4C2232C644E4B857F325923FC8A80A947FFA"
-#define KSS_P508_R "BF33E1C9934E7868ECE51D291E5644DA8A2F179CEE74854EE6819B240F20CE4E7D19F4CDABA6EAEA5B0E3000000001"
-#define KSS_P508_H "10565283D505534A492ADC6AAABB051B1D"
-#define KSS_P508_BETA "926C960A5EC3B3A6C6B9CEF2CB923D3240E4780BC1AE423EE39586AD923B1C949768022369DD2CE502E7FCA0670B3A996AC44B48B523DAA7390CCB1F6D9012F"
-#define KSS_P508_LAMB "1001740B431D14BFD17F4BD000300173FFFFFFFEFFFFFFFED"
-#define KSS_P508_MAPU "1"
+#define K18_P508_A "0"
+#define K18_P508_B "2"
+#define K18_P508_X "3ADD59EAC7B6A0ABC781139CE46388AB3426C6619C27187CB1F2B48AC92E04608AFBD25DA121EDB06015CB5D2BCF369C03C163605BBA21FAF7D550960553784"
+#define K18_P508_Y "8773227730CBE52483BF6AAAA9E4FE2870B463FA14D92C31D0F99C6B6EE13106A0E8C87AD7631F8ECCE0DD6189B4C2232C644E4B857F325923FC8A80A947FFA"
+#define K18_P508_R "BF33E1C9934E7868ECE51D291E5644DA8A2F179CEE74854EE6819B240F20CE4E7D19F4CDABA6EAEA5B0E3000000001"
+#define K18_P508_H "10565283D505534A492ADC6AAABB051B1D"
/** @} */
#endif
@@ -589,24 +560,6 @@
#define B24_P509_Y "101264A0ACB6129DE3CEB5FF829968E5030855FAD666E88506531D46050023ACB15843C4EA8F8AB478F618D263D4B6271D5972803F2046DDD7C7DBC2F6232FFD"
#define B24_P509_R "100000FFFF870FF91CE195DB5B6F3EBD1E08C94C9E193B724ED58B907FF7C311A80D7CABC647746AE3ECB627C943998457FE001"
#define B24_P509_H "155555AAAA805FFFAAC0154AAC"
-#define B24_P509_MAPU "2"
-/** @} */
-#endif
-
-#if defined(EP_ENDOM) && FP_PRIME == 511
-/**
- * Parameters for the 511-bit jacobi quartic curve.
- */
-/** @{ */
-#define OT8_P511_A "1"
-#define OT8_P511_B "0"
-#define OT8_P511_X "17D8A9281052D5C14B26B88FBDA0DE7001F384C09F7425270874BD187725FF7D68887EC3539658E3C60F6FFADCED61F47267CCDAF5B850DF4A441105AE49CE6"
-#define OT8_P511_Y "9CB933777C7E567A2040EC255073F2C271F632E6E81490D85377DD77659416965584F5F44DFB146E33393CE36D908F79A4ED5B4B411D78572E6CA972F66DEC8"
-#define OT8_P511_R "100000000002AC000000002AD56000000131304C0000032F6D0B1000000000001"
-#define OT8_P511_H "40000000000AB000000000AB5580000044C4C130000564BDB42C401C8E400000"
-#define OT8_P511_BETA "20000000000AB0000000018FC7800000816148500019C9EF620CC291655380BA94133E310D1CC71ED0A7EBD9B2AB859C0F60AC90F7A2E5A1140C3FCBF1DD5400"
-#define OT8_P511_LAMB "100000000002AC000000002AD55FFFFFF131304BFFFEAD2F6D0B0FF8DC7000001"
-#define OT8_P511_MAPU "1"
/** @} */
#endif
@@ -623,7 +576,6 @@
#define GMT8_P544_H "BC5A106E29D336CBF340F2BB98248FFC0719523D3233C6B3909C882E2BD2251BD3B22F14"
#define GMT8_P544_BETA "AEB8BAFC09BEB98DE5FB37D9FC56F9EAC4F908F09D88B1CD8622513C94499803C18F54E6B4FB9180292A2FD4C8AFD2AF43F54BCF308198872F3A6B591394AED0EBF7961A"
#define GMT8_P544_LAMB "FF801041EF80043901FFFEF800000010"
-#define GMT8_P544_MAPU "5"
#endif
/** @} */
@@ -640,7 +592,6 @@
#define SG54_P569_H "1C242734823F3D3"
#define SG54_P569_BETA "11B4A0273012B3534BEA4F2B96E641113A156E510AED07E600BE9DD709E2015B0F8E69E3F1A44690DA0652831007C27346D9F444F22DA68B20C46EDC4889EA0B49C773C72195876"
#define SG54_P569_LAMB "15FB59F1AFF4B536CBEBB5F1317A6D0332AAEF63DBEE47A528280DACBB244A601"
-#define SG54_P569_MAPU "-1"
/** @} */
#endif
@@ -655,9 +606,6 @@
#define B48_P575_Y "4E0AB4BE01EEA9C4A3EA81C84E2081B03934596D846AC24862A851F811CBE5078CD4AF03DECAD5571C4BB90F502155F462E23D3180562EED28C72882F3F538893BD643EDE63C4567"
#define B48_P575_R "FFBFC68EB6176EFB58025E547BF4EBACB1315C184DC37EAAF67BBCCE069D07F425050E765ABB8B40D5E6D7AE8A2A5698B771DDBD6E109D56D59C3DFF00000001"
#define B48_P575_H "5552A7FA0ADD830B"
-#define B48_P575_BETA "FFBBC37DA1869F31B9AAFAF31296EECB5167E1C9E9CE0B077E9903AE049FC122282856929B2DF0C32C0B39C487860D76077734153C1C276F79B75B1CB20A7935EB5F2611"
-#define B48_P575_LAMB "FFDFE14381A38FBBE3439A4861838B75D01E7A1E85BAE6AA2A63C200FFFFFFFF"
-#define B48_P575_MAPU "1"
/** @} */
#endif
@@ -672,7 +620,6 @@
#define BN_P638_Y "128AC488584B7C05EFD5436E559D741C978A5027926525B3DECB22D40E03FC7BD8D4235FD7E9DD2F3BFF3945D54C25E701624E27AFEF8F27F7DDEADEDAF3FE3AA0234D35290703FCE6254A7D75B6A304"
#define BN_P638_R "23FFFFFDC000000D7FFFFFB8000001D3FFFFF942D000165E3FFF94870000D52FFFFDD0E00008DE55600086550021E555FFFFF54FFFF4EAC000000049800154D9FFFFFFFFFFFFEDA00000000000000061"
#define BN_P638_H "1"
-#define BN_P638_MAPU "-1"
/** @} */
/**
@@ -685,7 +632,6 @@
#define B12_P638_Y "2D340B33877480A9785E86ED2EDCAFC170B82568CB21B708B79FC6DA3748461FCD80697E486695F3CAE76FCB1781E784F6812F57BE05DFC850426650DED8B40A464B00A35718228EC8E02B52B59D876E"
#define B12_P638_R "50F94035FF4000FFFFFFFFFFF9406BFDC0040000000000000035FB801DFFBFFFFFFFFFFFFFFF401BFF80000000000000000000FFC01"
#define B12_P638_H "BFF8001555555555555555554D957EAAAAAAAAAAAAAAAAAAAABEB"
-#define B12_P638_MAPU "3"
/** @} */
/**
@@ -698,10 +644,45 @@
#define K18_P638_Y "1AD0E6C8D2F8B84E81E17D20277BFF5E7784849B6B3F570F6CB7DDD7BB51E680A9B01A9E2CBF87B7D1CA40F3F9DB65DCDD485800C7D6BCE6F11F85F4FC91381A1F6FF721BE1FA7DC73B1452EC9E067C1"
#define K18_P638_R "217C6AD09A8C1501A39F40A5CAE9A8FA6C1D721892617A6D5AB381B7B89EF9B4A91AE277CAAA0EE0BC3E2910806BDC08EA69545693C740000000001"
#define K18_P638_H "1708507726EC82EBF64DB756506B2000010540EB1D"
-#define K18_P638_MAPU "1"
+/** @} */
+
+/**
+ * Parameters for a 638-bit pairing-friendly prime curve.
+ */
+/** @{ */
+#define SG18_P638_A "0"
+#define SG18_P638_B "F"
+#define SG18_P638_X "E0D4EFF000926F3F04EC069C865F33B6ABD8F70B19B71E93111193736C505A211C527AF75475C92513B4601BA248A97A6717B631A462BF7366F2767D3C9ECB1A1782524B131853E2684A33EB28C518B"
+#define SG18_P638_Y "1F11E9002370B0A9F5E3A3CCFF9468621FE85FB70CC024C3636B7427714C19140A00B09975E0F42921C8839A3D0E3DDCE74B09A556771D5A072F4B5F77C8F816B69C4F093B1FAA547EA906F1E405F229"
+#define SG18_P638_R "6D45960E65595E64AE55954202C604A99543E572A870006483A877DC004A61BE5000000D793FFFFFFFF7000000000001"
+#define SG18_P638_H "9120D848090486C36090000D8D835FFE7E91A8FFFFF9FD08FFFFFFFA00000001"
/** @} */
#endif
+/**
+ * Parameters for a 765-bit pairing-friendly prime curve.
+ */
+/** @{ */
+#define N16_P765_A "1"
+#define N16_P765_B "0"
+#define N16_P765_X "71A955588AD4E8236811AA1770428A86CA487504E3964600E51FAD83E8EDF03883360471538D685B7CA156BC9AD56E6FED4BE76C099A752E70E867A8FD79CDFBD0C00294E59C4F2F348302FB270336BE8D2EC25E6234D33CB33C8840BC059D4"
+#define N16_P765_Y "F6DEB4CAA67257010A3286CECBE4E4127D53701CF5897E3426F675BEFE36F60CD0E779433306B0A34C826584307F96100ECA6EB01F69637C2EB0B295E6C13E9721A5EA0FC05A04B47FC565AEBF41016525A69F554BC9D68D9EF2B5CD77D1D4"
+#define N16_P765_R "9965D956A0DBC8AF273C0100000000000000000000000000000000000000000000000000000000000000000000000001"
+#define N16_P765_H "26597655A836F22BC9CF003FFFFFFFFFFFFFA30FAB330D5A7F0000000000000000000000384F01000000000000000000"
+/** @} */
+
+/**
+ * Parameters for a 766-bit pairing-friendly prime curve.
+ */
+/** @{ */
+#define K16_P766_A "1"
+#define K16_P766_B "0"
+#define K16_P766_X "025F4A0BE80AC747A4C260A96F17BACD76B068415EC40DBAC38FCDD5FF14A5974A3B73AFE417CB4391CFC9A5E8F5DA2C7E6244E30CFE1097AE864DD3FC5B45450043F0EFE0C181D198E6C07129367CF4A7E78ACD4D1C438AD486AF79BB712017"
+#define K16_P766_Y "1F9736A1ED817C6B41A07FD71902DF11786996DEAA1C9707671D491C4A8C430BABECE74E1664C0DE5C73A08B3758D2E3EBEB42F69DF624DEDEEDDD0F94EF01658AAD2F3426DD91CA34545DBF5FCBA7CF0784F2C3DCFAB7A1EBDCE75566F0538A"
+#define K16_P766_R "1B6C1BFC8E56CCE359E1D8A9B94553D096A506CE2ECF4A33C5D526AC5F3B61CB0A6D76FCD8487EDEE0B0F9BA2DFA29D5AB0B164B8792C233ED1E6EB350BA9F4D37112A98DE816BEB1EA8DDB1"
+#define K16_P766_H "2327FFFFFFFFE8905E7E6E0003E7E080C57EE9EF4"
+/** @} */
+
#if defined(EP_SUPER) && FP_PRIME == 1536
/**
* Parameters for a 1536-bit supersingular elliptic curve.
@@ -713,7 +694,20 @@
#define SS_P1536_Y "76F05A21A057DB46D591CED876EDCA9241A4A9618E13E091EE383BE3D8ECDA72C42449CB20CEA8C21B4A58B08F5871C6E101473933ABCD0BBB61C36F51BE5309138BA1040325EFE2D47B2216923BAC07BA64E6668C67D4647DA5916BF2305280A1BFFA1407ED68F0D28C2C2FC200BA7D1B7C5D71492CD39A2FC6BB7EF2D162B69984460A81D324DA69B0949DA2C7D0F79E39333EAF074F360243BAA824C762A039EBB3DEFF1ABDE3157482134BE93D73B4D8CB308C3ED0E72BA644DEFE22AAB9"
#define SS_P1536_R "8000000000000000000000000000000000000000000000000000020000000001"
#define SS_P1536_H "106126E85211A9AA539DE0D8E432340BABCC0E7FD0C3CC6FAEE8F87CA5F7725B54BBBE7DE38C3EBEE164AD00490346D95FD32BFC679AA8029708CEA26C981A77064FB3C8A6CDD411E36688D584793A96CAD10CE6351A0AC319F434764054488B5741CEF8BE9E019424732EB40A6EE109E4ADBD540FA43899E5484F37822EC07596F62045187571F182E85ACE872AE0376040E3510D06083B388463D1DD30571B4"
-#define SS_P1536_MAPU "1"
+/** @} */
+#endif
+
+#if defined(EP_PLAIN) && FP_PRIME == 3072
+/**
+ * Parameters for a 1536-bit supersingular elliptic curve.
+ */
+/** @{ */
+#define K1_P3072_A "-4"
+#define K1_P3072_B "0"
+#define K1_P3072_X "8253FA83029E6059E1B34C169D6F471EE952E41C9E24B9AF67F53289914A337D7C34E8703B78C56A45B3E4DD8D55B5958092C76B871F9CE74CBA96B087FA8C9454B51F22C2A23BCEC5136DA5D4A008B5EC42A46B333793B4E94C458AC0DB61A7A3B28756760E9B40B55979B7DE7D313FBA9214653F37510AC65E923D9FC96AEC907B22582D86E4E95EA5B9ACA3ED56BB2A0367FC8BA6DB0388F9EEB44AA937F834F89C2281B35F5283BDA9C31F17D3B8F2C226AB7A075F01E95817C36F808B9262932ECDFD40DE1C49DCE71D9E4ECAF6CA054996058B8305AB8A0AB17F5AC1B83191B80EB7961AB5DC357C0212D317E1FA0F3FC15409B61D67ED257376C6758A772D84B43FC36212DD84908E9FA8F16608C1C980FCD42350C484DE107959DD26C6AD463674B1C59B8CFDFAA9FFC7BFF06DE608327A9FCD9D227981C30503C0766056F7AC560509889512020EB0AC38A65B62D8376813AB64623C16DBB119232C6B2ABD266E58DD2366F86E407C5C474DB1A127A360F75BE1B3540FD74F758139"
+#define K1_P3072_Y "38EEF990FF8CE03E21336501356D3BDAA765D96BE110FAF7A7FD0DA5D876AE0A8F25AF2FCA3F17A0D98FA886B9EC40CEAB625D60BD1EAB1533D271F35BBC7D232135D2173565F2E6C35F616079C98A5D116BC5829AC90A1D5FCBAE7E1995ABB00D5125449DBDC3DA5D577BC740A8896C488E8322D1B2A284349BE8A87D0A49D31FC39E22E5933126FF43D735CA53EF6ED20537B6F3D0DF4904F80A5D1307946A8CBEF4451620E97CDD4CB35F525D5969DED0049325A9B012BE0036A67023DDE37265D0E59484FEFE00FE5CF9A79F008E2F021D8E3E55A46BED45424AB8B6B09C7704DB227D591A871D856CF61563FACD2DC5D6BC498B55ED9F590E8D8ED1BD1F9BA20F41EA7D9707C60F50A759EF923953CA91334C0CEA6A12AF7DE44FFFD001BCD724491C86644664BEAB79245B546E23EC95D0927B2254671BC2311B9E9EDC44A4CC6B0404EC933327B602ED435CFDE8892C406908B6F98ED941514E4AA5123F84957B15D523A14040943C72379E12D83F7B79FEC3FFC8C99B32FE0E0E6901"
+#define K1_P3072_R "10000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
+#define K1_P3072_H "E4C6467513F6DA5D303FCF2C5285C33206AC48901ADBE523D00F9F3B9E4895075BEB07DD1AAEEBF957F2DCBBEC4FB900E2ADE744AA7206BC2A60709BA08CA540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
/** @} */
#endif
@@ -737,8 +731,6 @@
bn_read_str(r, str, strlen(str), 16); \
RLC_GET(str, CURVE##_H, sizeof(CURVE##_H)); \
bn_read_str(h, str, strlen(str), 16); \
- RLC_GET(str, CURVE##_MAPU, sizeof(CURVE##_MAPU)); \
- fp_read_str(u, str, strlen(str), 16); \
/**
* Assigns a set of parameters for an elliptic curve with endomorphisms.
@@ -762,7 +754,7 @@
*/
#define ASSIGNM(CURVE) \
ep_param_set_ctmap(CURVE##_ISO_A, CURVE##_ISO_B, CURVE##_ISO_XN, \
- CURVE##_ISO_XD, CURVE##_ISO_YN, CURVE##_ISO_YD) \
+ CURVE##_ISO_XD, CURVE##_ISO_YN, CURVE##_ISO_YD, CURVE##_MAPU) \
#endif /* EP_CTMAP */
@@ -815,11 +807,12 @@ static int ep_param_get_coeffs(fp_st *coeffs, const char *str) {
*/
/* declaring this function inline suppresses unused function warnings */
static inline void ep_param_set_ctmap(const char *a_str, const char *b_str,
- const char *xn_str, const char *xd_str,
- const char *yn_str, const char *yd_str) {
+ const char *xn_str, const char *xd_str, const char *yn_str,
+ const char *yd_str, const char *u_str) {
/* coefficients of isogenous curve */
fp_read_str(ep_curve_get_iso()->a, a_str, strlen(a_str), 16);
fp_read_str(ep_curve_get_iso()->b, b_str, strlen(b_str), 16);
+ fp_read_str(core_get()->ep_map_u, u_str, strlen(u_str), 16);
/* isogeny map coeffs */
iso_t coeffs = ep_curve_get_iso();
@@ -842,14 +835,13 @@ int ep_param_get(void) {
void ep_param_set(int param) {
int plain = 0, endom = 0, super = 0, pairf = 0, ctmap = 0;
char str[2 * RLC_FP_BYTES + 2];
- fp_t a, b, beta, u;
+ fp_t a, b, beta;
ep_t g;
bn_t r, t, h, lamb;
fp_null(a);
fp_null(b);
fp_null(beta);
- fp_null(u);
bn_null(lamb);
ep_null(g);
bn_null(r);
@@ -860,7 +852,6 @@ void ep_param_set(int param) {
fp_new(a);
fp_new(b);
fp_new(beta);
- fp_new(u);
bn_new(lamb);
ep_new(g);
bn_new(r);
@@ -868,6 +859,8 @@ void ep_param_set(int param) {
bn_new(h);
core_get()->ep_id = 0;
+ fp_zero(beta);
+ bn_zero(lamb);
switch (param) {
#if defined(EP_ENDOM) && FP_PRIME == 158
@@ -885,7 +878,7 @@ void ep_param_set(int param) {
#endif
#if defined(EP_ENDOM) && FP_PRIME == 160
case SECG_K160:
- ASSIGNK(SECG_K160, SECG_160D);
+ ASSIGN(SECG_K160, SECG_160D);
endom = 1;
break;
#endif
@@ -915,7 +908,7 @@ void ep_param_set(int param) {
#endif
#if defined(EP_ENDOM) && FP_PRIME == 224
case SECG_K224:
- ASSIGNK(SECG_K224, SECG_224);
+ ASSIGN(SECG_K224, SECG_224);
endom = 1;
break;
#endif
@@ -946,7 +939,7 @@ void ep_param_set(int param) {
#endif
#if defined(EP_ENDOM) && FP_PRIME == 255
case TWEEDLEDUM:
- ASSIGNK(TWEEDLEDUM, PRIME_H2ADC);
+ ASSIGN(TWEEDLEDUM, PRIME_H2ADC);
endom = 1;
break;
#endif
@@ -966,7 +959,7 @@ void ep_param_set(int param) {
#endif
#if defined(EP_ENDOM) && FP_PRIME == 256
case SECG_K256:
- ASSIGNK(SECG_K256, SECG_256);
+ ASSIGN(SECG_K256, SECG_256);
endom = 1;
break;
case SM9_P256:
@@ -994,6 +987,13 @@ void ep_param_set(int param) {
pairf = EP_B24;
break;
#endif
+#if defined(EP_ENDOM) & FP_PRIME == 330
+ case K16_P330:
+ ASSIGN(K16_P330, K16_330);
+ endom = 1;
+ pairf = EP_K16;
+ break;
+#endif
#if defined(EP_ENDOM) & FP_PRIME == 377
case B12_P377:
ASSIGN(B12_P377, B12_377);
@@ -1064,9 +1064,10 @@ void ep_param_set(int param) {
break;
#endif
#if defined(EP_ENDOM) && FP_PRIME == 508
- case KSS_P508:
- ASSIGNK(KSS_P508, KSS_508);
+ case K18_P508:
+ ASSIGN(K18_P508, K18_508);
endom = 1;
+ pairf = EP_K18;
break;
#endif
#if defined(EP_ENDOM) && FP_PRIME == 509
@@ -1076,12 +1077,6 @@ void ep_param_set(int param) {
pairf = EP_B24;
break;
#endif
-#if defined(EP_ENDOM) && FP_PRIME == 511
- case OT8_P511:
- ASSIGNK(OT8_P511, OT_511);
- endom = 1;
- break;
-#endif
#if defined(EP_PLAIN) && FP_PRIME == 511
case CURVE_511187:
ASSIGN(CURVE_511187, PRIME_511187);
@@ -1110,7 +1105,7 @@ void ep_param_set(int param) {
#endif
#if defined(EP_ENDOM) && FP_PRIME == 575
case B48_P575:
- ASSIGNK(B48_P575, B48_575);
+ ASSIGN(B48_P575, B48_575);
endom = 1;
pairf = EP_B48;
break;
@@ -1131,11 +1126,38 @@ void ep_param_set(int param) {
endom = 1;
pairf = EP_K18;
break;
+ case SG18_P638:
+ ASSIGN(SG18_P638, SG18_638);
+ endom = 1;
+ pairf = EP_SG18;
+ break;
+#endif
+#if defined(EP_ENDOM) && FP_PRIME == 765
+ case N16_P765:
+ ASSIGN(N16_P765, N16_765);
+ endom = 1;
+ pairf = EP_N16;
+ break;
+#endif
+#if defined(EP_ENDOM) && FP_PRIME == 766
+ case K16_P766:
+ ASSIGN(K16_P766, K16_766);
+ endom = 1;
+ pairf = EP_K16;
+ break;
#endif
#if defined(EP_SUPER) && FP_PRIME == 1536
case SS_P1536:
ASSIGN(SS_P1536, SS_1536);
super = 1;
+ pairf = EP_SS2;
+ break;
+#endif
+#if defined(EP_PLAIN) && FP_PRIME == 3072
+ case K1_P3072:
+ ASSIGN(K1_P3072, K1_3072);
+ plain = 1;
+ pairf = EP_K1;
break;
#endif
default:
@@ -1146,15 +1168,29 @@ void ep_param_set(int param) {
#if defined(EP_ENDOM)
if (endom) {
- switch(pairf) {
- /* beta = (-1+sqrt(-3))/2, lambda = 36*u^3 + 18*u^2 + 6*u + 1 */
- case EP_BN:
+ if (fp_is_zero(beta)) {
+ if (fp_is_zero(b)) {
+ /* beta = sqrt(-1). */
+ fp_set_dig(beta, 1);
+ fp_neg(beta, beta);
+ fp_srt(beta, beta);
+ } else {
+ /* beta = (-1+sqrt(-3))/2 */
fp_set_dig(beta, 3);
fp_neg(beta, beta);
fp_srt(beta, beta);
fp_sub_dig(beta, beta, 1);
fp_hlv(beta, beta);
- fp_prime_get_par(lamb);
+ }
+ }
+
+ if (bn_is_zero(lamb)) {
+ fp_prime_get_par(lamb);
+ }
+
+ switch(pairf) {
+ case EP_BN:
+ /* lambda = 36*u^3 + 18*u^2 + 6*u + 1 */
bn_sqr(lamb, lamb);
bn_sqr(lamb, lamb);
bn_mul_dig(lamb, lamb, 36);
@@ -1164,61 +1200,63 @@ void ep_param_set(int param) {
bn_sub_dig(lamb, lamb, 1);
}
break;
- /* beta = (-1 + sqrt(-3))/2, lambda = z^2 - 1 */
case EP_B12:
- fp_set_dig(beta, 3);
- fp_neg(beta, beta);
- fp_srt(beta, beta);
- fp_sub_dig(beta, beta, 1);
- fp_hlv(beta, beta);
- fp_prime_get_par(lamb);
+ /* lambda = z^2 - 1 */
bn_sqr(lamb, lamb);
bn_sub_dig(lamb, lamb, 1);
break;
- /* beta = (-1 + sqrt(-3))/2, lambda = z^3 + 18 */
+ case EP_N16:
+ bn_sqr(lamb, lamb);
+ bn_sqr(lamb, lamb);
+ bn_neg(lamb, lamb);
+ break;
+ case EP_K16:
+ /* lambda = -(z^4 + 24)/7 */
+ bn_sqr(t, lamb);
+ bn_sqr(lamb, t);
+ bn_add_dig(lamb, lamb, 24);
+ bn_div_dig(lamb, lamb, 7);
+ bn_neg(lamb, lamb);
+ break;
case EP_K18:
- fp_set_dig(beta, 3);
- fp_neg(beta, beta);
- fp_srt(beta, beta);
- fp_sub_dig(beta, beta, 1);
- fp_hlv(beta, beta);
- fp_prime_get_par(lamb);
+ /* lambda = z^3 + 18 */
bn_sqr(t, lamb);
bn_mul(lamb, t, lamb);
bn_add_dig(lamb, lamb, 18);
break;
+ case EP_SG18:
+ /* lambda = -9z^3 - 2 */
+ bn_sqr(t, lamb);
+ bn_mul(lamb, t, lamb);
+ bn_mul_dig(lamb, lamb, 9);
+ bn_add_dig(lamb, lamb, 2);
+ bn_neg(lamb, lamb);
+ break;
case EP_B24:
- /* beta = (-1 + sqrt(-3))/2, lambda = z^4 - 1. */
- fp_set_dig(beta, 3);
- fp_neg(beta, beta);
- fp_srt(beta, beta);
- fp_sub_dig(beta, beta, 1);
- fp_hlv(beta, beta);
- fp_prime_get_par(lamb);
+ /* lambda = z^4 - 1. */
bn_sqr(lamb, lamb);
bn_sqr(lamb, lamb);
bn_sub_dig(lamb, lamb, 1);
break;
+ case EP_B48:
+ /* lambda = z^8 - 1. */
+ bn_sqr(lamb, lamb);
+ bn_sqr(lamb, lamb);
+ bn_sqr(lamb, lamb);
+ bn_sub_dig(lamb, lamb, 1);
+ break;
default:
if (bn_cmp_dig(h, 1) == RLC_EQ) {
- /* SECG curves with endomorphisms. */
- fp_set_dig(beta, 2);
- h->used = RLC_FP_DIGS;
- dv_copy(h->dp, fp_prime_get(), RLC_FP_DIGS);
- /* Borrow h but restore at the end. */
- bn_sub_dig(h, h, 1);
- bn_div_dig(h, h, 3);
- fp_exp(beta, beta, h);
+ /* other curves with endomorphisms. */
bn_set_dig(lamb, 3);
- bn_sub_dig(h, r, 1);
- bn_div_dig(h, h, 3);
- bn_mxp(lamb, lamb, h, r);
+ bn_sub_dig(t, r, 1);
+ bn_div_dig(t, t, 3);
+ bn_mxp(lamb, lamb, t, r);
/* Try another primitive root. */
if (bn_cmp_dig(lamb, 1) == RLC_EQ) {
bn_set_dig(lamb, 2);
- bn_mxp(lamb, lamb, h, r);
+ bn_mxp(lamb, lamb, t, r);
}
- bn_set_dig(h, 1);
}
break;
}
@@ -1236,25 +1274,25 @@ void ep_param_set(int param) {
fp_set_dig(g->z, 1);
g->coord = BASIC;
+ core_get()->ep_id = param;
+ core_get()->ep_is_pairf = pairf;
+
#if defined(EP_PLAIN)
if (plain) {
- ep_curve_set_plain(a, b, g, r, h, u, ctmap);
- core_get()->ep_id = param;
+ ep_curve_set_plain(a, b, g, r, h, ctmap);
}
+
#endif
#if defined(EP_ENDOM)
if (endom) {
- ep_curve_set_endom(a, b, g, r, h, beta, lamb, u, ctmap);
- core_get()->ep_id = param;
- core_get()->ep_is_pairf = pairf;
+ ep_curve_set_endom(a, b, g, r, h, beta, lamb, ctmap);
}
#endif
#if defined(EP_SUPER)
if (super) {
- ep_curve_set_super(a, b, g, r, h, u, ctmap);
- core_get()->ep_id = param;
+ ep_curve_set_super(a, b, g, r, h, ctmap);
}
#endif
}
@@ -1265,7 +1303,6 @@ void ep_param_set(int param) {
fp_free(a);
fp_free(b);
fp_free(beta);
- fp_free(u);
bn_free(lamb);
ep_free(g);
bn_free(r);
@@ -1345,6 +1382,8 @@ int ep_param_set_any_endom(void) {
ep_param_set(B24_P315);
#elif FP_PRIME == 317
ep_param_set(B24_P317);
+#elif FP_PRIME == 330
+ ep_param_set(K16_P330);
#elif FP_PRIME == 377
ep_param_set(B12_P377);
#elif FP_PRIME == 381
@@ -1362,11 +1401,9 @@ int ep_param_set_any_endom(void) {
#elif FP_PRIME == 455
ep_param_set(B12_P455);
#elif FP_PRIME == 508
- ep_param_set(KSS_P508);
+ ep_param_set(K18_P508);
#elif FP_PRIME == 509
ep_param_set(B24_P509);
-#elif FP_PRIME == 511
- ep_param_set(OT8_P511);
#elif FP_PRIME == 544
ep_param_set(GMT8_P544);
#elif FP_PRIME == 638
@@ -1374,7 +1411,12 @@ int ep_param_set_any_endom(void) {
ep_param_set(B12_P638);
#else
ep_param_set(K18_P638);
+ //ep_param_set(SG18_P638);
#endif
+#elif FP_PRIME == 765
+ ep_param_set(N16_P765);
+#elif FP_PRIME == 766
+ ep_param_set(K16_P766);
#else
r = RLC_ERR;
#endif
@@ -1389,9 +1431,6 @@ int ep_param_set_any_super(void) {
#if defined(EP_SUPER)
#if FP_PRIME == 1536
ep_param_set(SS_P1536);
-#elif FP_PRIME == 3072
- ep_param_set(SS_P3072);
-#else
r = RLC_ERR;
#endif
#else
@@ -1401,98 +1440,110 @@ int ep_param_set_any_super(void) {
}
int ep_param_set_any_pairf(void) {
- int type = 0, degree = 0, r = RLC_OK;
+ int type = 0, extension = 0, r = RLC_OK;
#if defined(EP_ENDOM)
#if FP_PRIME == 158
ep_param_set(BN_P158);
type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 254
ep_param_set(BN_P254);
type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 256
ep_param_set(BN_P256);
type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 315
ep_param_set(B24_P315);
type = RLC_EP_DTYPE;
- degree = 4;
+ extension = 4;
#elif FP_PRIME == 317
ep_param_set(B24_P317);
type = RLC_EP_MTYPE;
- degree = 4;
+ extension = 4;
+#elif FP_PRIME == 330
+ ep_param_set(K16_P330);
+ type = RLC_EP_MTYPE;
+ extension = 4;
#elif FP_PRIME == 377
ep_param_set(B12_P377);
type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 381
ep_param_set(B12_P381);
type = RLC_EP_MTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 382
ep_param_set(BN_P382);
type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 383
ep_param_set(B12_P383);
type = RLC_EP_MTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 446
#ifdef FP_QNRES
ep_param_set(B12_P446);
type = RLC_EP_MTYPE;
- degree = 2;
+ extension = 2;
#else
ep_param_set(BN_P446);
type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 2;
#endif
#elif FP_PRIME == 455
ep_param_set(B12_P455);
type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 508
- ep_param_set(KSS_P508);
+ ep_param_set(K18_P508);
type = RLC_EP_DTYPE;
- degree = 3;
+ extension = 3;
#elif FP_PRIME == 509
ep_param_set(B24_P509);
type = RLC_EP_DTYPE;
- degree = 4;
-#elif FP_PRIME == 511
- ep_param_set(OT8_P511);
- type = RLC_EP_DTYPE;
- degree = 2;
+ extension = 4;
#elif FP_PRIME == 544
ep_param_set(GMT8_P544);
type = RLC_EP_MTYPE;
- degree = 2;
+ extension = 2;
#elif FP_PRIME == 569
ep_param_set(SG54_P569);
type = RLC_EP_MTYPE;
- degree = 9;
+ extension = 9;
#elif FP_PRIME == 575
ep_param_set(B48_P575);
type = RLC_EP_MTYPE;
- degree = 8;
+ extension = 8;
#elif FP_PRIME == 638
#ifdef FP_QNRES
ep_param_set(B12_P638);
type = RLC_EP_MTYPE;
- degree = 2;
+ extension = 2;
#else
+ //ep_param_set(BN_P638);
+ //type = RLC_EP_DTYPE;
+ //extension = 2;
ep_param_set(K18_P638);
+ //ep_param_set(SG18_P638);
type = RLC_EP_MTYPE;
- degree = 3;
+ extension = 3;
#endif
+#elif FP_PRIME == 765
+ ep_param_set(N16_P765);
+ type = RLC_EP_MTYPE;
+ extension = 4;
+#elif FP_PRIME == 766
+ ep_param_set(K16_P766);
+ type = RLC_EP_MTYPE;
+ extension = 4;
#elif FP_PRIME == 1536
ep_param_set(SS_P1536);
- degree = 0;
+ extension = 1;
#elif FP_PRIME == 3072
- ep_param_set(SS_P3072);
- degree = 0;
+ ep_param_set(K1_P3072);
+ extension = 1;
#else
r = RLC_ERR;
#endif
@@ -1501,10 +1552,8 @@ int ep_param_set_any_pairf(void) {
#endif
#ifdef WITH_PP
if (r == RLC_OK) {
- switch (degree) {
- case 0:
- ep2_curve_set_twist(0);
- /* Compute pairing generator. */
+ switch (extension) {
+ case 1:
pc_core_calc();
break;
case 2:
@@ -1516,6 +1565,9 @@ int ep_param_set_any_pairf(void) {
case 4:
ep4_curve_set_twist(type);
break;
+ case 8:
+ ep8_curve_set_twist(type);
+ break;
}
}
#else
@@ -1584,6 +1636,12 @@ void ep_param_print(void) {
case B24_P317:
util_banner("Curve B24-P317:", 0);
break;
+ case K16_P330:
+ util_banner("Curve K16-P330:", 0);
+ break;
+ case B12_P377:
+ util_banner("Curve B12-P377:", 0);
+ break;
case B12_P381:
util_banner("Curve B12-P381:", 0);
break;
@@ -1605,15 +1663,12 @@ void ep_param_print(void) {
case B12_P455:
util_banner("Curve B12-P455:", 0);
break;
- case KSS_P508:
- util_banner("Curve KSS-P508:", 0);
+ case K18_P508:
+ util_banner("Curve K18-P508:", 0);
break;
case B24_P509:
util_banner("Curve B24-P509:", 0);
break;
- case OT8_P511:
- util_banner("Curve OT8-P511:", 0);
- break;
case SG54_P569:
util_banner("Curve SG54-P569:", 0);
break;
@@ -1629,11 +1684,20 @@ void ep_param_print(void) {
case K18_P638:
util_banner("Curve K18-P638:", 0);
break;
+ case SG18_P638:
+ util_banner("Curve SG18-P638:", 0);
+ break;
+ case N16_P765:
+ util_banner("Curve N16-P765:", 0);
+ break;
+ case K16_P766:
+ util_banner("Curve K16-P766:", 0);
+ break;
case SS_P1536:
util_banner("Curve SS-P1536:", 0);
break;
- case SS_P3072:
- util_banner("Curve SS-3072:", 0);
+ case K1_P3072:
+ util_banner("Curve K1-P3072:", 0);
break;
case CURVE_1174:
util_banner("Curve Curve1174:", 0);
@@ -1674,7 +1738,9 @@ int ep_param_level(void) {
case TWEEDLEDUM:
return 128;
case B24_P315:
+ case B24_P317:
case B12_P377:
+ case K16_P330:
case B12_P381:
case BN_P382:
case B12_P383:
@@ -1686,6 +1752,7 @@ int ep_param_level(void) {
case B12_P455:
return 140;
case NIST_P384:
+ case K16_P766:
case K18_P638:
case B24_P509:
return 192;
@@ -1693,6 +1760,7 @@ int ep_param_level(void) {
return 256;
case BN_P638:
case B12_P638:
+ case K18_P508:
return 160;
}
return 0;
@@ -1700,19 +1768,20 @@ int ep_param_level(void) {
int ep_param_embed(void) {
switch (core_get()->ep_is_pairf) {
- case EP_SS1:
+ case EP_K1:
return 1;
case EP_SS2:
return 2;
- case EP_OT8:
case EP_GMT8:
return 8;
case EP_BN:
case EP_B12:
return 12;
+ case EP_N16:
case EP_K16:
return 16;
case EP_K18:
+ case EP_SG18:
return 18;
case EP_B24:
return 24;
diff --git a/src/ep/relic_ep_psi.c b/src/ep/relic_ep_psi.c
index 28352ece5..d080fcbbb 100644
--- a/src/ep/relic_ep_psi.c
+++ b/src/ep/relic_ep_psi.c
@@ -36,8 +36,6 @@
/* Public definitions */
/*============================================================================*/
-#if defined(EP_ENDOM) && !defined(STRIP)
-
void ep_psi(ep_t r, const ep_t p) {
if (ep_is_infty(p)) {
ep_set_infty(r);
@@ -55,4 +53,3 @@ void ep_psi(ep_t r, const ep_t p) {
}
}
-#endif
diff --git a/src/epx/relic_ep2_curve.c b/src/epx/relic_ep2_curve.c
index bd97a5efe..26a3b7216 100644
--- a/src/epx/relic_ep2_curve.c
+++ b/src/epx/relic_ep2_curve.c
@@ -241,23 +241,6 @@
/** @} */
#endif
-#if defined(EP_ENDOM) && FP_PRIME == 511
-/** @{ */
-#define OT8_P511_A0 "0"
-#define OT8_P511_A1 "1"
-#define OT8_P511_B0 "0"
-#define OT8_P511_B1 "0"
-#define OT8_P511_X0 "09541B7BB446EBE58277E0183B448E09D567ACFAAA07F2D3C01967088544C6FA844B803CFC8C8A91D0DFFAB5F55B95372C5AB5DD38E13EE92DAA6882535A1244"
-#define OT8_P511_X1 "332FBBD88DA3493CAF2F082C9C43E463523C8611AC52AB498F1D28D7844E42C67AF62A9BF0F4D9DDD38F79F51C9DBDB10735AC3CD69FF7867E27EBD65DD8D3EF"
-#define OT8_P511_Y0 "2E298CA6C71CE0C6CABA9208E6350B73B0E8BF3EE7CC1777C64BD3680AC857D1823993C8877CBD0203CD3A9835A053F5549BDF7DC206EE1B40BA43A2BD59B793"
-#define OT8_P511_Y1 "109CF99B6C312D74CEFF87959789AF53D231988B0E77FF424C8738C20EA91E7F634399A3899E101EBF5C6A0DBE2E40ACA8D0DBCE0F2C6A0300987BBABD9097DC"
-#define OT8_P511_R "100000000002AC000000002AD56000000131304C0000032F6D0B1000000000001"
-#define OT8_P511_H "1000000000080400000001D72B20000061916054001384B3D863F2EBD23CF44774A8836D060A488CB13701DF690F23AF2A5394A1F9EE0B564F725AD505A8F75463E3DBDF97FBE852B96A19E4477DB82D7C260034DEDA6C75853BB18EE3956002"
-#define OT8_P511_MAPU0 "0"
-#define OT8_P511_MAPU1 "1"
-/** @} */
-#endif
-
#if defined(EP_ENDOM) && FP_PRIME == 544
/** @{ */
#define GMT8_P544_A0 "0"
@@ -678,53 +661,6 @@ fp_t *ep2_curve_get_b(void) {
return core_get()->ep2_b;
}
-void ep2_curve_get_vs(bn_t *v) {
- bn_t x, t;
-
- bn_null(x);
- bn_null(t);
-
- RLC_TRY {
- bn_new(x);
- bn_new(t);
-
- fp_prime_get_par(x);
- bn_copy(v[1], x);
- bn_copy(v[2], x);
- bn_copy(v[3], x);
-
- /* t = 2x^2. */
- bn_sqr(t, x);
- bn_dbl(t, t);
-
- /* v0 = 2x^2 + 3x + 1. */
- bn_mul_dig(v[0], x, 3);
- bn_add_dig(v[0], v[0], 1);
- bn_add(v[0], v[0], t);
-
- /* v3 = -(2x^2 + x). */
- bn_add(v[3], v[3], t);
- bn_neg(v[3], v[3]);
-
- /* v1 = 12x^3 + 8x^2 + x, v2 = 6x^3 + 4x^2 + x. */
- bn_dbl(t, t);
- bn_add(v[2], v[2], t);
- bn_dbl(t, t);
- bn_add(v[1], v[1], t);
- bn_rsh(t, t, 2);
- bn_mul(t, t, x);
- bn_mul_dig(t, t, 3);
- bn_add(v[2], v[2], t);
- bn_dbl(t, t);
- bn_add(v[1], v[1], t);
- } RLC_CATCH_ANY {
- RLC_THROW(ERR_CAUGHT);
- } RLC_FINALLY {
- bn_free(x);
- bn_free(t);
- }
-}
-
void ep2_curve_get_ord(bn_t n) {
ctx_t *ctx = core_get();
if (ctx->ep2_is_twist) {
@@ -835,10 +771,6 @@ void ep2_curve_set_twist(int type) {
case B12_P455:
ASSIGN(B12_P455);
break;
-#elif FP_PRIME == 511
- case OT8_P511:
- ASSIGN(OT8_P511);
- break;
#elif FP_PRIME == 544
case GMT8_P544:
ASSIGN(GMT8_P544);
diff --git a/src/epx/relic_ep2_frb.c b/src/epx/relic_ep2_frb.c
index 833759d96..b43695e04 100644
--- a/src/epx/relic_ep2_frb.c
+++ b/src/epx/relic_ep2_frb.c
@@ -37,14 +37,34 @@
/*============================================================================*/
void ep2_frb(ep2_t r, const ep2_t p, int i) {
- ctx_t *ctx = core_get();
+ if (ep2_curve_opt_a() == RLC_ZERO) {
+ ctx_t *ctx = core_get();
- ep2_copy(r, p);
- for (; i > 0; i--) {
- fp2_frb(r->x, r->x, 1);
- fp2_frb(r->y, r->y, 1);
- fp2_frb(r->z, r->z, 1);
- fp2_mul(r->x, r->x, ctx->ep2_frb[0]);
- fp2_mul(r->y, r->y, ctx->ep2_frb[1]);
+ ep2_copy(r, p);
+ for (; i > 0; i--) {
+ fp2_frb(r->x, r->x, 1);
+ fp2_frb(r->y, r->y, 1);
+ fp2_frb(r->z, r->z, 1);
+ fp2_mul(r->x, r->x, ctx->ep2_frb[0]);
+ fp2_mul(r->y, r->y, ctx->ep2_frb[1]);
+ }
+ } else {
+ bn_t t;
+
+ bn_null(t);
+
+ RLC_TRY {
+ bn_new(t);
+
+ /* Can we do faster than this? */
+ fp_prime_get_par(t);
+ for (; i > 0; i--) {
+ ep2_mul_basic(r, p, t);
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_NO_MEMORY);
+ } RLC_FINALLY {
+ bn_free(t);
+ }
}
}
diff --git a/src/epx/relic_ep2_map.c b/src/epx/relic_ep2_map.c
index 8a130c0fc..31f2c8db9 100644
--- a/src/epx/relic_ep2_map.c
+++ b/src/epx/relic_ep2_map.c
@@ -48,11 +48,13 @@
* @param[in] len - the degree of the polynomial.
*/
TMPL_MAP_HORNER(fp2, fp2_t)
+
/**
* Generic isogeny map evaluation for use with SSWU map.
*/
TMPL_MAP_ISOGENY_MAP(ep2, fp2, iso2)
#endif /* EP_CTMAP */
+
/**
* Simplified SWU mapping.
*/
@@ -62,11 +64,14 @@ TMPL_MAP_ISOGENY_MAP(ep2, fp2, iso2)
dv_copy_cond(O[1], I[1], RLC_FP_DIGS, C); \
} while (0)
TMPL_MAP_SSWU(ep2, fp2, fp_t, EP2_MAP_COPY_COND)
+
/**
* Shallue--van de Woestijne map.
*/
TMPL_MAP_SVDW(ep2, fp2, fp_t, EP2_MAP_COPY_COND)
+
#undef EP2_MAP_COPY_COND
+
/* caution: this function overwrites k, which it uses as an auxiliary variable */
static inline int fp2_sgn0(const fp2_t t, bn_t k) {
const int t_0_zero = fp_is_zero(t[0]);
@@ -81,11 +86,17 @@ static inline int fp2_sgn0(const fp2_t t, bn_t k) {
return t_0_neg | (t_0_zero & t_1_neg);
}
-/*============================================================================*/
-/* Public definitions */
-/*============================================================================*/
-
-void ep2_map_from_field(ep2_t p, const uint8_t *uniform_bytes, size_t len) {
+/**
+ * Maps a byte array to a point in an elliptic curve over a quadratic extension
+ * using an explicit domain separation tag.
+ *
+ * @param[out] p - the result.
+ * @param[in] msg - the byte array to map.
+ * @param[in] len - the array length in bytes.
+ * @param[in] dst - the domain separatoin tag.
+ * @param[in] dst_len - the domain separation tag length in bytes.
+ */
+static void ep2_map_from_field(ep2_t p, const uint8_t *r, size_t len) {
bn_t k;
fp2_t t;
ep2_t q;
@@ -109,14 +120,14 @@ void ep2_map_from_field(ep2_t p, const uint8_t *uniform_bytes, size_t len) {
/* which hash function should we use? */
const int abNeq0 = (ep2_curve_opt_a() != RLC_ZERO) &&
(ep2_curve_opt_b() != RLC_ZERO);
- void (*const map_fn)(ep2_t, fp2_t) = (ep2_curve_is_ctmap() ||
- abNeq0) ? ep2_map_sswu : ep2_map_svdw;
+ const void (*const map_fn)(ep2_t, fp2_t) = (void (*const))
+ (ep2_curve_is_ctmap() || abNeq0 ? ep2_map_sswu : ep2_map_svdw);
#define EP2_MAP_CONVERT_BYTES(IDX) \
do { \
- bn_read_bin(k, uniform_bytes + 2 * IDX * lpe, lpe); \
+ bn_read_bin(k, r + 2 * IDX * lpe, lpe); \
fp_prime_conv(t[0], k); \
- bn_read_bin(k, uniform_bytes + (2 * IDX + 1) * lpe, lpe); \
+ bn_read_bin(k, r + (2 * IDX + 1) * lpe, lpe); \
fp_prime_conv(t[1], k); \
} while (0)
@@ -164,27 +175,221 @@ void ep2_map_from_field(ep2_t p, const uint8_t *uniform_bytes, size_t len) {
}
}
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_MAP == BASIC || !defined(STRIP)
+
+void ep2_map_basic(ep2_t p, const uint8_t *msg, size_t len) {
+ bn_t x;
+ fp2_t t0;
+ uint8_t digest[RLC_MD_LEN];
+
+ bn_null(x);
+ fp2_null(t0);
+
+ RLC_TRY {
+ bn_new(x);
+ fp2_new(t0);
+
+ md_map(digest, msg, len);
+ bn_read_bin(x, digest, RLC_MIN(RLC_FP_BYTES, RLC_MD_LEN));
+
+ fp2_zero(p->x);
+ fp_prime_conv(p->x[0], x);
+ fp2_set_dig(p->z, 1);
+
+ while (1) {
+ ep2_rhs(t0, p);
+
+ if (fp2_is_sqr(t0) == 1) {
+ fp2_srt(p->y, t0);
+ p->coord = BASIC;
+ break;
+ }
+
+ fp2_add_dig(p->x, p->x, 1);
+ }
+
+ ep2_mul_cof(p, p);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(x);
+ fp2_free(t0);
+ }
+}
+
+#endif
-void ep2_map_dst(ep2_t p, const uint8_t *msg, size_t len, const uint8_t *dst,
- size_t dst_len) {
+#if EP_MAP == SSWUM || !defined(STRIP)
+
+void ep2_map_sswum(ep2_t p, const uint8_t *msg, size_t len) {
/* enough space for two field elements plus extra bytes for uniformity */
const int lpe = (FP_PRIME + ep_param_level() + 7) / 8;
- uint8_t *pseudo_random_bytes = RLC_ALLOCA(uint8_t, 4 * lpe);
+ uint8_t *r = RLC_ALLOCA(uint8_t, 4 * lpe);
RLC_TRY {
+ if (r == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
/* XXX(rsw) See note in ep/relic_ep_map.c about using MD_MAP. */
/* hash to a pseudorandom string using md_xmd */
- md_xmd(pseudo_random_bytes, 4 * lpe, msg, len, dst, dst_len);
- ep2_map_from_field(p, pseudo_random_bytes, 2 * lpe);
+ md_xmd(r, 4 * lpe, msg, len, (const uint8_t *)"RELIC", 5);
+ ep2_map_from_field(p, r, 2 * lpe);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
- RLC_FREE(pseudo_random_bytes);
+ RLC_FREE(r);
}
}
-void ep2_map(ep2_t p, const uint8_t *msg, size_t len) {
- ep2_map_dst(p, msg, len, (const uint8_t *)"RELIC", 5);
+#endif
+
+#if EP_MAP == SWIFT || !defined(STRIP)
+
+void ep2_map_swift(ep2_t p, const uint8_t *msg, size_t len) {
+ /* enough space for two field elements plus extra bytes for uniformity */
+ const size_t elm = (FP_PRIME + ep_param_level() + 7) / 8;
+ uint8_t t0z, t0, t1, sign, *r = RLC_ALLOCA(uint8_t, 4 * elm + 1);
+ fp2_t t, u, v, w, y, x1, y1, z1;
+ ctx_t *ctx = core_get();
+ dig_t c2, c3;
+ bn_t k;
+
+ bn_null(k);
+ fp2_null(t);
+ fp2_null(u);
+ fp2_null(v);
+ fp2_null(w);
+ fp2_null(y);
+ fp2_null(x1);
+ fp2_null(y1);
+ fp2_null(z1);
+
+ RLC_TRY {
+ bn_new(k);
+ fp2_new(t);
+ fp2_new(u);
+ fp2_new(v);
+ fp2_new(w);
+ fp2_new(y);
+ fp2_new(x1);
+ fp2_new(y1);
+ fp2_new(z1);
+
+ md_xmd(r, 4 * elm + 1, msg, len, (const uint8_t *)"RELIC", 5);
+
+ for (int i = 0; i < 2; i++) {
+ bn_read_bin(k, r, elm);
+ fp_prime_conv(u[i], k);
+ r += elm;
+ bn_read_bin(k, r, elm);
+ fp_prime_conv(t[i], k);
+ r += elm;
+ }
+ sign = r[0] & 1;
+
+ /* Assume that a = 0. */
+ fp2_sqr(x1, u);
+ fp2_mul(x1, x1, u);
+ fp2_sqr(y1, t);
+ fp2_add(x1, x1, ctx->ep2_b);
+ fp2_sub(x1, x1, y1);
+ fp2_dbl(y1, y1);
+ fp2_add(y1, y1, x1);
+ fp2_copy(z1, u);
+ fp_mul(z1[0], z1[0], ctx->ep_map_c[4]);
+ fp_mul(z1[1], z1[1], ctx->ep_map_c[4]);
+ fp2_mul(x1, x1, z1);
+ fp2_mul(z1, z1, t);
+ fp2_dbl(z1, z1);
+
+ fp2_dbl(y, y1);
+ fp2_sqr(y, y);
+ fp2_mul(v, y1, u);
+ fp2_sub(v, x1, v);
+ fp2_mul(v, v, z1);
+ fp2_mul(w, y1, z1);
+ fp2_dbl(w, w);
+
+ if (fp2_is_zero(w)) {
+ ep2_set_infty(p);
+ } else {
+ fp2_inv(w, w);
+ fp2_mul(x1, v, w);
+ fp2_add(y1, u, x1);
+ fp2_neg(y1, y1);
+ fp2_mul(z1, y, w);
+ fp2_sqr(z1, z1);
+ fp2_add(z1, z1, u);
+
+ fp2_sqr(t, x1);
+ fp2_mul(t, t, x1);
+ fp2_add(t, t, ctx->ep2_b);
+
+ fp2_sqr(u, y1);
+ fp2_mul(u, u, y1);
+ fp2_add(u, u, ctx->ep2_b);
+
+ fp2_sqr(v, z1);
+ fp2_mul(v, v, z1);
+ fp2_add(v, v, ctx->ep2_b);
+
+ c2 = fp2_is_sqr(u);
+ c3 = fp2_is_sqr(v);
+
+ for (int i = 0; i < 2; i++) {
+ dv_swap_cond(x1[i], y1[i], RLC_FP_DIGS, c2);
+ dv_swap_cond(t[i], u[i], RLC_FP_DIGS, c2);
+ dv_swap_cond(x1[i], z1[i], RLC_FP_DIGS, c3);
+ dv_swap_cond(t[i], v[i], RLC_FP_DIGS, c3);
+ }
+
+ if (!fp2_srt(t, t)) {
+ RLC_THROW(ERR_NO_VALID);
+ }
+
+ t0z = fp_is_zero(t[0]);
+ fp_prime_back(k, t[0]);
+ t0 = bn_get_bit(k, 0);
+ fp_prime_back(k, t[1]);
+ t1 = bn_get_bit(k, 0);
+ /* t[0] == 0 ? sgn0(t[1]) : sgn0(t[0]) */
+ sign ^= (t0 | (t0z & t1));
+
+ fp2_neg(u, t);
+ dv_swap_cond(t[0], u[0], RLC_FP_DIGS, sign);
+ dv_swap_cond(t[1], u[1], RLC_FP_DIGS, sign);
+
+ fp2_copy(p->x, x1);
+ fp2_copy(p->y, t);
+ fp2_set_dig(p->z, 1);
+ p->coord = BASIC;
+
+ ep2_mul_cof(p, p);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(k);
+ fp2_free(t);
+ fp2_free(u);
+ fp2_free(v);
+ fp2_free(w);
+ fp2_free(y);
+ fp2_free(x1);
+ fp2_free(y1);
+ fp2_free(z1);
+ RLC_FREE(r);
+ }
}
+
+#endif
diff --git a/src/epx/relic_ep2_mul.c b/src/epx/relic_ep2_mul.c
index ba087bbfa..ed49a8062 100644
--- a/src/epx/relic_ep2_mul.c
+++ b/src/epx/relic_ep2_mul.c
@@ -112,9 +112,11 @@ static void ep2_mul_glv_imp(ep2_t r, const ep2_t p, const bn_t k) {
#endif /* EP_ENDOM */
+#if defined(EP_PLAIN) || defined(EP_SUPER)
+
static void ep2_mul_naf_imp(ep2_t r, const ep2_t p, const bn_t k) {
- size_t l, n;
- int8_t naf[RLC_FP_BITS + 1];
+ size_t l;
+ int8_t n, naf[RLC_FP_BITS + 1];
ep2_t t[1 << (RLC_WIDTH - 2)];
RLC_TRY {
@@ -159,6 +161,7 @@ static void ep2_mul_naf_imp(ep2_t r, const ep2_t p, const bn_t k) {
}
}
+#endif /* EP_PLAIN || EP_SUPER */
#endif /* EP_MUL == LWNAF */
/*============================================================================*/
@@ -167,22 +170,25 @@ static void ep2_mul_naf_imp(ep2_t r, const ep2_t p, const bn_t k) {
void ep2_mul_basic(ep2_t r, const ep2_t p, const bn_t k) {
ep2_t t;
- int8_t u, naf[2 * RLC_FP_BITS + 1];
+ int8_t u, *naf = RLC_ALLOCA(int8_t, bn_bits(k) + 1);
size_t l;
ep2_null(t);
if (bn_is_zero(k) || ep2_is_infty(p)) {
+ RLC_FREE(naf);
ep2_set_infty(r);
return;
}
RLC_TRY {
ep2_new(t);
+ if (naf == NULL) {
+ RLC_THROW(ERR_NO_BUFFER);
+ }
- l = 2 * RLC_FP_BITS + 1;
+ l = bn_bits(k) + 1;
bn_rec_naf(naf, &l, k, 2);
-
ep2_set_infty(t);
for (int i = l - 1; i >= 0; i--) {
ep2_dbl(t, t);
@@ -205,6 +211,7 @@ void ep2_mul_basic(ep2_t r, const ep2_t p, const bn_t k) {
}
RLC_FINALLY {
ep2_free(t);
+ RLC_FREE(naf);
}
}
@@ -282,7 +289,12 @@ void ep2_mul_slide(ep2_t r, const ep2_t p, const bn_t k) {
void ep2_mul_monty(ep2_t r, const ep2_t p, const bn_t k) {
ep2_t t[2];
+ bn_t n, l, _k;
+ size_t bits;
+ bn_null(n);
+ bn_null(l);
+ bn_null(_k);
ep2_null(t[0]);
ep2_null(t[1]);
@@ -292,14 +304,32 @@ void ep2_mul_monty(ep2_t r, const ep2_t p, const bn_t k) {
}
RLC_TRY {
+ bn_new(n);
+ bn_new(l);
+ bn_new(_k);
ep2_new(t[0]);
ep2_new(t[1]);
- ep2_set_infty(t[0]);
- ep2_copy(t[1], p);
+ ep2_curve_get_ord(n);
+ bits = bn_bits(n);
- for (int i = bn_bits(k) - 1; i >= 0; i--) {
- int j = bn_get_bit(k, i);
+ bn_mod(_k, k, n);
+ bn_abs(l, _k);
+ bn_add(l, l, n);
+ bn_add(n, l, n);
+ dv_swap_cond(l->dp, n->dp, RLC_MAX(l->used, n->used),
+ bn_get_bit(l, bits) == 0);
+ l->used = RLC_SEL(l->used, n->used, bn_get_bit(l, bits) == 0);
+
+ ep2_norm(t[0], p);
+ ep2_dbl(t[1], t[0]);
+
+ /* Blind both points independently. */
+ ep2_blind(t[0], t[0]);
+ ep2_blind(t[1], t[1]);
+
+ for (int i = bits - 1; i >= 0; i--) {
+ int j = bn_get_bit(l, i);
dv_swap_cond(t[0]->x[0], t[1]->x[0], RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->x[1], t[1]->x[1], RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->y[0], t[1]->y[0], RLC_FP_DIGS, j ^ 1);
@@ -317,13 +347,13 @@ void ep2_mul_monty(ep2_t r, const ep2_t p, const bn_t k) {
}
ep2_norm(r, t[0]);
- if (bn_sign(k) == RLC_NEG) {
- ep2_neg(r, r);
- }
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
+ bn_free(n);
+ bn_free(l);
+ bn_free(_k);
ep2_free(t[1]);
ep2_free(t[0]);
}
@@ -341,11 +371,7 @@ void ep2_mul_lwnaf(ep2_t r, const ep2_t p, const bn_t k) {
#if defined(EP_ENDOM)
if (ep_curve_is_endom()) {
- if (ep2_curve_opt_a() == RLC_ZERO) {
- ep2_mul_glv_imp(r, p, k);
- } else {
- ep2_mul_naf_imp(r, p, k);
- }
+ ep2_mul_glv_imp(r, p, k);
return;
}
#endif
diff --git a/src/epx/relic_ep2_mul_fix.c b/src/epx/relic_ep2_mul_fix.c
index 70efb83a1..075c9227a 100644
--- a/src/epx/relic_ep2_mul_fix.c
+++ b/src/epx/relic_ep2_mul_fix.c
@@ -136,9 +136,6 @@ void ep2_mul_fix_basic(ep2_t r, const ep2_t *t, const bn_t k) {
}
}
ep2_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep2_neg(r, r);
- }
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
@@ -244,9 +241,6 @@ void ep2_mul_fix_combs(ep2_t r, const ep2_t *t, const bn_t k) {
}
}
ep2_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep2_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -361,9 +355,6 @@ void ep2_mul_fix_combd(ep2_t r, const ep2_t *t, const bn_t k) {
ep2_add(r, r, t[(1 << RLC_DEPTH) + w1]);
}
ep2_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep2_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
diff --git a/src/epx/relic_ep2_mul_sim.c b/src/epx/relic_ep2_mul_sim.c
index 1e8d7ab6f..a4c69bfd2 100644
--- a/src/epx/relic_ep2_mul_sim.c
+++ b/src/epx/relic_ep2_mul_sim.c
@@ -56,8 +56,7 @@ static void ep2_mul_sim_endom(ep2_t r, const ep2_t p, const bn_t k,
const ep2_t q, const bn_t m) {
size_t l, _l[4];
bn_t _k[4], _m[4], n, u;
- int8_t naf0[4][RLC_FP_BITS + 1];
- int8_t naf1[4][RLC_FP_BITS + 1];
+ int8_t naf0[4][RLC_FP_BITS + 1], naf1[4][RLC_FP_BITS + 1];
ep2_t _p[4], _q[4];
bn_null(n);
@@ -162,14 +161,12 @@ static void ep2_mul_sim_endom(ep2_t r, const ep2_t p, const bn_t k,
*/
static void ep2_mul_sim_plain(ep2_t r, const ep2_t p, const bn_t k,
const ep2_t q, const bn_t m, const ep2_t *t) {
- int i, n0, n1, w, gen;
- int8_t naf0[2 * RLC_FP_BITS + 1], naf1[2 * RLC_FP_BITS + 1], *_k, *_m;
- ep2_t t0[1 << (RLC_WIDTH - 2)];
- ep2_t t1[1 << (RLC_WIDTH - 2)];
+ int i, w, gen = (t == NULL ? 0 : 1);
+ int8_t n0, n1, naf0[2 * RLC_FP_BITS + 1], naf1[2 * RLC_FP_BITS + 1];
+ ep2_t t0[1 << (RLC_WIDTH - 2)], t1[1 << (RLC_WIDTH - 2)];
size_t l, l0, l1;
RLC_TRY {
- gen = (t == NULL ? 0 : 1);
if (!gen) {
for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
ep2_null(t0[i]);
@@ -198,8 +195,6 @@ static void ep2_mul_sim_plain(ep2_t r, const ep2_t p, const bn_t k,
bn_rec_naf(naf1, &l1, m, RLC_WIDTH);
l = RLC_MAX(l0, l1);
- _k = naf0 + l - 1;
- _m = naf1 + l - 1;
if (bn_sign(k) == RLC_NEG) {
for (i = 0; i < l0; i++) {
naf0[i] = -naf0[i];
@@ -212,11 +207,11 @@ static void ep2_mul_sim_plain(ep2_t r, const ep2_t p, const bn_t k,
}
ep2_set_infty(r);
- for (i = l - 1; i >= 0; i--, _k--, _m--) {
+ for (i = l - 1; i >= 0; i--) {
ep2_dbl(r, r);
- n0 = *_k;
- n1 = *_m;
+ n0 = naf0[i];
+ n1 = naf1[i];
if (n0 > 0) {
ep2_add(r, r, t[n0 / 2]);
}
@@ -250,7 +245,6 @@ static void ep2_mul_sim_plain(ep2_t r, const ep2_t p, const bn_t k,
}
#endif /* EP_PLAIN || EP_SUPER */
-
#endif /* EP_SIM == INTER */
/*============================================================================*/
@@ -358,13 +352,6 @@ void ep2_mul_sim_trick(ep2_t r, const ep2_t p, const bn_t k, const ep2_t q,
bn_rec_win(w0, &l0, k, w);
bn_rec_win(w1, &l1, m, w);
- for (int i = l0; i < l1; i++) {
- w0[i] = 0;
- }
- for (int i = l1; i < l0; i++) {
- w1[i] = 0;
- }
-
ep2_set_infty(r);
for (int i = RLC_MAX(l0, l1) - 1; i >= 0; i--) {
for (int j = 0; j < w; j++) {
@@ -395,7 +382,6 @@ void ep2_mul_sim_trick(ep2_t r, const ep2_t p, const bn_t k, const ep2_t q,
void ep2_mul_sim_inter(ep2_t r, const ep2_t p, const bn_t k, const ep2_t q,
const bn_t m) {
- int flag = 0;
bn_t n, _k, _m;
if (bn_is_zero(k) || ep2_is_infty(p)) {
@@ -424,16 +410,14 @@ void ep2_mul_sim_inter(ep2_t r, const ep2_t p, const bn_t k, const ep2_t q,
#if defined(EP_ENDOM)
if (ep_curve_is_endom()) {
ep2_mul_sim_endom(r, p, _k, q, _m);
- flag = 1;
+ return;
}
#endif
#if defined(EP_PLAIN) || defined(EP_SUPER)
- if (!flag) {
- ep2_mul_sim_plain(r, p, _k, q, _m, NULL);
- }
+ ep2_mul_sim_plain(r, p, _k, q, _m, NULL);
#endif
- (void)flag;
+
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
diff --git a/src/epx/relic_ep2_norm.c b/src/epx/relic_ep2_norm.c
index 265c502a0..3276649d3 100644
--- a/src/epx/relic_ep2_norm.c
+++ b/src/epx/relic_ep2_norm.c
@@ -36,7 +36,7 @@
/* Private definitions */
/*============================================================================*/
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
/**
* Normalizes a point represented in projective coordinates.
@@ -95,7 +95,7 @@ void ep2_norm(ep2_t r, const ep2_t p) {
/* If the point is represented in affine coordinates, we just copy it. */
ep2_copy(r, p);
}
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
ep2_norm_imp(r, p, 0);
#endif
}
@@ -122,9 +122,11 @@ void ep2_norm_sim(ep2_t *r, const ep2_t *t, int n) {
fp2_copy(r[i]->z, a[i]);
}
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
for (i = 0; i < n; i++) {
ep2_norm_imp(r[i], r[i], 1);
}
+#endif
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
diff --git a/src/epx/relic_ep2_pck.c b/src/epx/relic_ep2_pck.c
index e51b4a07a..699ebde41 100644
--- a/src/epx/relic_ep2_pck.c
+++ b/src/epx/relic_ep2_pck.c
@@ -39,28 +39,28 @@
void ep2_pck(ep2_t r, const ep2_t p) {
bn_t halfQ, yValue;
- bn_null(halfQ);
- bn_null(yValue);
+ bn_null(halfQ);
+ bn_null(yValue);
RLC_TRY {
bn_new(halfQ);
bn_new(yValue);
- halfQ->used = RLC_FP_DIGS;
- dv_copy(halfQ->dp, fp_prime_get(), RLC_FP_DIGS);
- bn_hlv(halfQ, halfQ);
+ halfQ->used = RLC_FP_DIGS;
+ dv_copy(halfQ->dp, fp_prime_get(), RLC_FP_DIGS);
+ bn_hlv(halfQ, halfQ);
- fp_prime_back(yValue, p->y[1]);
+ fp_prime_back(yValue, p->y[1]);
- int b = bn_cmp(yValue, halfQ) == RLC_GT;
+ int b = bn_cmp(yValue, halfQ) == RLC_GT;
- fp2_copy(r->x, p->x);
- fp2_zero(r->y);
- fp_set_bit(r->y[0], 0, b);
- fp_zero(r->y[1]);
- fp_set_dig(r->z[0], 1);
- fp_zero(r->z[1]);
- r->coord = BASIC;
+ fp2_copy(r->x, p->x);
+ fp2_zero(r->y);
+ fp_set_bit(r->y[0], 0, b);
+ fp_zero(r->y[1]);
+ fp_set_dig(r->z[0], 1);
+ fp_zero(r->z[1]);
+ r->coord = BASIC;
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
diff --git a/src/epx/relic_ep3_curve.c b/src/epx/relic_ep3_curve.c
index 8c0c44c3c..8e4996cdb 100644
--- a/src/epx/relic_ep3_curve.c
+++ b/src/epx/relic_ep3_curve.c
@@ -36,7 +36,27 @@
/* Private definitions */
/*============================================================================*/
-/* See ep/relic_ep_param.c for discussion of MAP_U parameters. */
+#if defined(EP_ENDOM) && FP_PRIME == 508
+/**
+ * Parameters for a pairing-friendly prime curve over a quadratic extension.
+ */
+/** @{ */
+#define K18_P508_A0 "0"
+#define K18_P508_A1 "0"
+#define K18_P508_A2 "0"
+#define K18_P508_B0 "0"
+#define K18_P508_B1 "0"
+#define K18_P508_B2 "1"
+#define K18_P508_X0 "0481B38AB0B95B9F699145EE9E0F5BB85063ADEC07039B7464F659BEAB3CC3AE5157FCB2D4F5D88503AAF143C9A9D039A351AA833A08506F7F079885DF87D8D"
+#define K18_P508_X1 "AE31CBE29A26EF9A326FC66011A14B6DE0C28B0E117DD8EB86741147BDC64FEE7676A00F3E824BAAEF393CC9BED562D2E5B2F307278ACE7F75A9664F06331FC"
+#define K18_P508_X2 "A7B35C55E843DD3D9C8D1785C3023D5983AF01D86662DCFAED2BB86798BE458539192D4E3CCA863D6A9D1E7B9DEBF7DCAB8AD3D8708BE2D79057F3191ADDD16"
+#define K18_P508_Y0 "A9E391BA5067387349BAB815425F98056D9841347A1D4B18EBD2C3AA409389F972559F3605324A71BDB3D6AD2F019AA11078B9CF6DE4CF2BEEAF383AFD2936E"
+#define K18_P508_Y1 "B4783EC28E495F56D7E84F616367F95BC34F4A23031E5944066F611AA47EB1538EFACDC386CDA4BE64F845ACC2097B93891ECB5DAF450BF817A5CEA3ED70021"
+#define K18_P508_Y2 "016AAD68D7ABF2F5AA8910FDE09231927194F3EE1507264418367CBA2DAC99666E0FE4E7FD65D604198E858E0DF718AC2F1B35246DC4087ECE1580FCFA9FE14"
+#define K18_P508_R "BF33E1C9934E7868ECE51D291E5644DA8A2F179CEE74854EE6819B240F20CE4E7D19F4CDABA6EAEA5B0E3000000001"
+#define K18_P508_H "9806E5E0CE73547F36E994F52B22DD8416121B7A9BA69D6384DFD0B9B51D54E2090C657EF80A51D82E653A1E7902C7FB690AC973C4CA83469894F5F75495B65B1185A9AD5AF835E3F2B54A4E90CDA9F00FF09AFF09AC5BF7B13ACCE2E862BB30718D4D9806D5488EB4BDA0B0D5A5B770050C4FA6C9148DA1C77BEBE19701967DAA73F47B10D257F2A942F1860DCEB6B"
+/** @} */
+#endif
#if defined(EP_ENDOM) && FP_PRIME == 638
/** @{ */
@@ -55,6 +75,23 @@
#define K18_P638_R "217C6AD09A8C1501A39F40A5CAE9A8FA6C1D721892617A6D5AB381B7B89EF9B4A91AE277CAAA0EE0BC3E2910806BDC08EA69545693C740000000001"
#define K18_P638_H "D10F161A65711BAE126EE4D96E29E6BF525A11BD7BC76B44C5EFF1E59229DCDCAC7CDF4627E564E2046C46D868DA9C8A13B6DF56D99B94D915E385CDC71C047AA9B5E11835A3B37571D1822F23B77B2ECA4F71FC1DF25E659264279F89AB8F7490ED9354E08614239C571B3BD7DDAD3C6C8DD23E27CC0F87C40EE0945B05D3349FE931900ACE29582AF47FCD57C6C3ADCF1F67FFEE4767D4ECB7969FEC7AFFC48C84E9719C0A2C2D4D830FCDEA56F4F1F3CECB6B"
/** @} */
+
+/** @{ */
+#define SG18_P638_A0 "0"
+#define SG18_P638_A1 "0"
+#define SG18_P638_A2 "0"
+#define SG18_P638_B0 "2D"
+#define SG18_P638_B1 "F"
+#define SG18_P638_B2 "0"
+#define SG18_P638_X0 "1755624848CF51F3209A74B978D9E0547518D2F0E563A6EE4759652BF199892BFBF175C37E4E0726ABFFF10CCB23EAA292F85F286706CF3B2B9397212F6DD1F5EDDD294CFDD9F0459DFF37080FEC2612"
+#define SG18_P638_X1 "1A879D2ED904732EC6DA468711A78B088661F67CC580045FC8F2E964EFF69C7DF46D4BAB135385DF79E9BF10DF7F5672B483A6F325B1D17B0345C864030A097D822AE6CD0C97C88D6057212C105D05BE"
+#define SG18_P638_X2 "152B2968451C399C716962F3B418022D93E33A083A9E093D1CFFF0A7AC85F279E6FC17AEE2A55B89BCBA9280C69EFA3C19B4EAC0A5598AEED18978DE95DD6291C39A2108DC982418C705116AFAB8406E"
+#define SG18_P638_Y0 "1BA3F3688C6CAEB5CDE7E1EC316C4C239F04E21AF8C3A29FEA60D1AD10BE89534DC29EDA41F11ABCEF877FDC72331F6AB3B91F5A9A0EACECAB6185D0F70BF16A200C775AF6FFA8C7FA929D336ABD5933"
+#define SG18_P638_Y1 "2341147722E627ACA8F027D929976CE638412C3D310C556D2CCF16DCFED3BB7F5FA5C62278C1D67EEF6C93181BC15B16BC8FFC7AC419077BA7BE92DCDF2A81BD8F98EBB58E70F91EE9B725CB0D84F632"
+#define SG18_P638_Y2 "2F32085FC7D6305CB13F58995ACAB1A0B0BBC5C642E0804470F84E0F80E9E1FBA51F8DD11ADDC122EA9A632B276DD9331174A6CBF5E7FBD500A38930DBB26F2C59220C1299B79C4752C8ADF87E1AF255"
+#define SG18_P638_R "6D45960E65595E64AE55954202C604A99543E572A870006483A877DC004A61BE5000000D793FFFFFFFF7000000000001"
+#define SG18_P638_H "87F77ECC6011A73A6F9B3C239413E8278746F3627BECED8355475CE8177053C1DBBEAC0159D2293A4B0F440F9ABCA65386C7305E1888F5A70111BDCE2772A8DA52DE9869A61C0A345DD4AE51209AC13095F27A9636D5B798073A9056163BBB7B3B393CFB5D537C932BFF5EA26FB1455D22D7362313A54DB182588963081F5B011858B919A5BDE89A2F1345AB93F7BE8DD7D186476A6E1B8F3F9A7CA17FF609E65AB7E05B61E57D63A1F73B483C8FAF0C5C1000000A200000000000000000003"
+/** @} */
#endif
/**
@@ -202,53 +239,6 @@ void ep3_curve_get_b(fp3_t b) {
fp3_copy(b, core_get()->ep3_b);
}
-void ep3_curve_get_vs(bn_t *v) {
- bn_t x, t;
-
- bn_null(x);
- bn_null(t);
-
- RLC_TRY {
- bn_new(x);
- bn_new(t);
-
- fp_prime_get_par(x);
- bn_copy(v[1], x);
- bn_copy(v[2], x);
- bn_copy(v[3], x);
-
- /* t = 2x^2. */
- bn_sqr(t, x);
- bn_dbl(t, t);
-
- /* v0 = 2x^2 + 3x + 1. */
- bn_mul_dig(v[0], x, 3);
- bn_add_dig(v[0], v[0], 1);
- bn_add(v[0], v[0], t);
-
- /* v3 = -(2x^2 + x). */
- bn_add(v[3], v[3], t);
- bn_neg(v[3], v[3]);
-
- /* v1 = 12x^3 + 8x^2 + x, v2 = 6x^3 + 4x^2 + x. */
- bn_dbl(t, t);
- bn_add(v[2], v[2], t);
- bn_dbl(t, t);
- bn_add(v[1], v[1], t);
- bn_rsh(t, t, 2);
- bn_mul(t, t, x);
- bn_mul_dig(t, t, 3);
- bn_add(v[2], v[2], t);
- bn_dbl(t, t);
- bn_add(v[1], v[1], t);
- } RLC_CATCH_ANY {
- RLC_THROW(ERR_CAUGHT);
- } RLC_FINALLY {
- bn_free(x);
- bn_free(t);
- }
-}
-
void ep3_curve_get_ord(bn_t n) {
ctx_t *ctx = core_get();
if (ctx->ep3_is_twist) {
@@ -305,10 +295,17 @@ void ep3_curve_set_twist(int type) {
bn_new(h);
switch (ep_param_get()) {
-#if FP_PRIME == 638
+#if FP_PRIME == 508
+ case K18_P508:
+ ASSIGN(K18_P508);
+ break;
+#elif FP_PRIME == 638
case K18_P638:
ASSIGN(K18_P638);
break;
+ case SG18_P638:
+ ASSIGN(SG18_P638);
+ break;
#endif
default:
(void)str;
@@ -339,6 +336,8 @@ void ep3_curve_set_twist(int type) {
if (type == RLC_EP_MTYPE) {
fp3_inv(ctx->ep3_frb[0], ctx->ep3_frb[0]);
fp3_inv(ctx->ep3_frb[1], ctx->ep3_frb[1]);
+ } else {
+ fp3_mul_art(ctx->ep3_frb[0], ctx->ep3_frb[0]);
}
fp18_zero(c);
diff --git a/src/epx/relic_ep3_map.c b/src/epx/relic_ep3_map.c
index 2e545943f..dd398ede7 100644
--- a/src/epx/relic_ep3_map.c
+++ b/src/epx/relic_ep3_map.c
@@ -37,43 +37,149 @@
/* Public definitions */
/*============================================================================*/
-void ep3_map(ep3_t p, const uint8_t *msg, int len) {
- bn_t x;
- fp3_t t0;
- uint8_t digest[RLC_MD_LEN];
+void ep3_map(ep3_t p, const uint8_t *msg, size_t len) {
+ /* enough space for two field elements plus extra bytes for uniformity */
+ const size_t elm = (FP_PRIME + ep_param_level() + 7) / 8;
+ uint8_t t0z, t0, t1, t1z, t2, sign, *r = RLC_ALLOCA(uint8_t, 6 * elm + 1);
+ fp3_t t, u, v, w, y, x1, y1, z1;
+ ctx_t *ctx = core_get();
+ dig_t c2, c3;
+ bn_t k;
- bn_null(x);
- fp3_null(t0);
+ bn_null(k);
+ fp3_null(t);
+ fp3_null(u);
+ fp3_null(v);
+ fp3_null(w);
+ fp3_null(y);
+ fp3_null(x1);
+ fp3_null(y1);
+ fp3_null(z1);
RLC_TRY {
- bn_new(x);
- fp3_new(t0);
+ bn_new(k);
+ fp3_new(t);
+ fp3_new(u);
+ fp3_new(v);
+ fp3_new(w);
+ fp3_new(y);
+ fp3_new(x1);
+ fp3_new(y1);
+ fp3_new(z1);
- md_map(digest, msg, len);
- bn_read_bin(x, digest, RLC_MIN(RLC_FP_BYTES, RLC_MD_LEN));
+ md_xmd(r, 6 * elm + 1, msg, len, (const uint8_t *)"RELIC", 5);
- fp3_zero(p->x);
- fp_prime_conv(p->x[0], x);
- fp3_set_dig(p->z, 1);
+ for (int i = 0; i <= 2; i++) {
+ bn_read_bin(k, r, elm);
+ fp_prime_conv(u[i], k);
+ r += elm;
+ bn_read_bin(k, r, elm);
+ fp_prime_conv(t[i], k);
+ r += elm;
+ }
+ sign = r[0] & 1;
+
+ /* Assume that a = 0. */
+ fp3_sqr(x1, u);
+ fp3_mul(x1, x1, u);
+ fp3_sqr(y1, t);
+ fp3_add(x1, x1, ctx->ep3_b);
+ fp3_sub(x1, x1, y1);
+ fp3_dbl(y1, y1);
+ fp3_add(y1, y1, x1);
+ fp3_copy(z1, u);
+ fp_mul(z1[0], z1[0], ctx->ep_map_c[4]);
+ fp_mul(z1[1], z1[1], ctx->ep_map_c[4]);
+ fp_mul(z1[2], z1[2], ctx->ep_map_c[4]);
+ fp3_mul(x1, x1, z1);
+ fp3_mul(z1, z1, t);
+ fp3_dbl(z1, z1);
+
+ fp3_dbl(y, y1);
+ fp3_sqr(y, y);
+ fp3_mul(v, y1, u);
+ fp3_sub(v, x1, v);
+ fp3_mul(v, v, z1);
+ fp3_mul(w, y1, z1);
+ fp3_dbl(w, w);
+
+ if (fp3_is_zero(w)) {
+ ep3_set_infty(p);
+ } else {
+ fp3_inv(w, w);
+ fp3_mul(x1, v, w);
+ fp3_add(y1, u, x1);
+ fp3_neg(y1, y1);
+ fp3_mul(z1, y, w);
+ fp3_sqr(z1, z1);
+ fp3_add(z1, z1, u);
+
+ ep3_curve_get_b(w);
+
+ fp3_sqr(t, x1);
+ fp3_mul(t, t, x1);
+ fp3_add(t, t, w);
+
+ fp3_sqr(u, y1);
+ fp3_mul(u, u, y1);
+ fp3_add(u, u, w);
+
+ fp3_sqr(v, z1);
+ fp3_mul(v, v, z1);
+ fp3_add(v, v, w);
- while (1) {
- ep3_rhs(t0, p);
+ c2 = fp3_is_sqr(u);
+ c3 = fp3_is_sqr(v);
- if (fp3_srt(p->y, t0)) {
- p->coord = BASIC;
- break;
+ for (int i = 0; i <= 2; i++) {
+ dv_swap_cond(x1[i], y1[i], RLC_FP_DIGS, c2);
+ dv_swap_cond(t[i], u[i], RLC_FP_DIGS, c2);
+ dv_swap_cond(x1[i], z1[i], RLC_FP_DIGS, c3);
+ dv_swap_cond(t[i], v[i], RLC_FP_DIGS, c3);
}
- fp_add_dig(p->x[0], p->x[0], 1);
- }
+ if (!fp3_srt(t, t)) {
+ RLC_THROW(ERR_NO_VALID);
+ }
+
+ t0z = fp_is_zero(t[0]);
+ fp_prime_back(k, t[0]);
+ t0 = bn_get_bit(k, 0);
+ t1z = fp_is_zero(t[1]);
+ fp_prime_back(k, t[1]);
+ t1 = bn_get_bit(k, 0);
+ fp_prime_back(k, t[2]);
+ t2 = bn_get_bit(k, 0);
+
+ /* t[0] == 0 ? sgn0(t[1]) : sgn0(t[0]) */
+ sign ^= (t0 | (t0z & (t1 | (t1z & t2))));
- ep3_mul_cof(p, p);
+ fp3_neg(u, t);
+ dv_swap_cond(t[0], u[0], RLC_FP_DIGS, sign);
+ dv_swap_cond(t[1], u[1], RLC_FP_DIGS, sign);
+ dv_swap_cond(t[2], u[2], RLC_FP_DIGS, sign);
+
+ fp3_copy(p->x, x1);
+ fp3_copy(p->y, t);
+ fp3_set_dig(p->z, 1);
+ p->coord = BASIC;
+
+ ep3_mul_cof(p, p);
+ }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
- bn_free(x);
- fp3_free(t0);
+ bn_free(k);
+ fp3_free(t);
+ fp3_free(u);
+ fp3_free(v);
+ fp3_free(w);
+ fp3_free(y);
+ fp3_free(x1);
+ fp3_free(y1);
+ fp3_free(z1);
+ RLC_FREE(r);
}
}
diff --git a/src/epx/relic_ep3_mul.c b/src/epx/relic_ep3_mul.c
index c72714620..e034f5c21 100644
--- a/src/epx/relic_ep3_mul.c
+++ b/src/epx/relic_ep3_mul.c
@@ -53,12 +53,20 @@ static void ep3_psi(ep3_t r, const ep3_t p) {
RLC_TRY {
ep3_new(q);
- /* We have that u mod n = p^4 - 3*p mod n. */
- ep3_dbl(q, p);
- ep3_add(q, q, p);
- ep3_frb(r, p, 3);
- ep3_sub(r, r, q);
- ep3_frb(r, r, 1);
+ if (ep_curve_is_pairf() == EP_SG18) {
+ /* -3*u = (2*p^2 - p^5) mod r */
+ ep3_frb(q, p, 5);
+ ep3_frb(r, p, 2);
+ ep3_dbl(r, r);
+ ep3_sub(r, r, q);
+ } else {
+ /* For KSS18, we have that u = p^4 - 3*p mod r. */
+ ep3_dbl(q, p);
+ ep3_add(q, q, p);
+ ep3_frb(r, p, 3);
+ ep3_sub(r, r, q);
+ ep3_frb(r, r, 1);
+ }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -88,8 +96,14 @@ static void ep3_mul_glv_imp(ep3_t r, const ep3_t p, const bn_t k) {
ep3_new(q[i]);
}
- ep3_curve_get_ord(n);
fp_prime_get_par(u);
+ if (ep_curve_is_pairf() == EP_SG18) {
+ /* Compute base -3*u for the recoding below. */
+ bn_dbl(n, u);
+ bn_add(u, u, n);
+ bn_neg(u, u);
+ }
+ ep3_curve_get_ord(n);
bn_mod(_k[0], k, n);
bn_rec_frb(_k, 6, _k[0], u, n, ep_curve_is_pairf() == EP_BN);
@@ -103,6 +117,9 @@ static void ep3_mul_glv_imp(ep3_t r, const ep3_t p, const bn_t k) {
l = 0;
for (i = 0; i < 6; i++) {
+ if (bn_sign(_k[i]) == RLC_NEG) {
+ ep3_neg(q[i], q[i]);
+ }
_l[i] = RLC_FP_BITS + 1;
bn_rec_naf(naf[i], &_l[i], _k[i], 2);
l = RLC_MAX(l, _l[i]);
@@ -197,22 +214,25 @@ static void ep3_mul_naf_imp(ep3_t r, const ep3_t p, const bn_t k) {
void ep3_mul_basic(ep3_t r, const ep3_t p, const bn_t k) {
ep3_t t;
- int8_t u, naf[2 * RLC_FP_BITS + 1];
+ int8_t u, *naf = RLC_ALLOCA(int8_t, bn_bits(k) + 1);
size_t l;
ep3_null(t);
if (bn_is_zero(k) || ep3_is_infty(p)) {
+ RLC_FREE(naf);
ep3_set_infty(r);
return;
}
RLC_TRY {
ep3_new(t);
+ if (naf == NULL) {
+ RLC_THROW(ERR_NO_BUFFER);
+ }
- l = 2 * RLC_FP_BITS + 1;
+ l = bn_bits(k) + 1;
bn_rec_naf(naf, &l, k, 2);
-
ep3_set_infty(t);
for (int i = l - 1; i >= 0; i--) {
ep3_dbl(t, t);
@@ -235,6 +255,7 @@ void ep3_mul_basic(ep3_t r, const ep3_t p, const bn_t k) {
}
RLC_FINALLY {
ep3_free(t);
+ RLC_FREE(naf);
}
}
@@ -313,7 +334,12 @@ void ep3_mul_slide(ep3_t r, const ep3_t p, const bn_t k) {
void ep3_mul_monty(ep3_t r, const ep3_t p, const bn_t k) {
ep3_t t[2];
+ bn_t n, l, _k;
+ size_t bits;
+ bn_null(n);
+ bn_null(l);
+ bn_null(_k);
ep3_null(t[0]);
ep3_null(t[1]);
@@ -323,14 +349,32 @@ void ep3_mul_monty(ep3_t r, const ep3_t p, const bn_t k) {
}
RLC_TRY {
+ bn_new(n);
+ bn_new(l);
+ bn_new(_k);
ep3_new(t[0]);
ep3_new(t[1]);
- ep3_set_infty(t[0]);
- ep3_copy(t[1], p);
+ ep3_curve_get_ord(n);
+ bits = bn_bits(n);
+
+ bn_mod(_k, k, n);
+ bn_abs(l, _k);
+ bn_add(l, l, n);
+ bn_add(n, l, n);
+ dv_swap_cond(l->dp, n->dp, RLC_MAX(l->used, n->used),
+ bn_get_bit(l, bits) == 0);
+ l->used = RLC_SEL(l->used, n->used, bn_get_bit(l, bits) == 0);
+
+ ep3_norm(t[0], p);
+ ep3_dbl(t[1], t[0]);
+
+ /* Blind both points independently. */
+ ep3_blind(t[0], t[0]);
+ ep3_blind(t[1], t[1]);
- for (int i = bn_bits(k) - 1; i >= 0; i--) {
- int j = bn_get_bit(k, i);
+ for (int i = bits - 1; i >= 0; i--) {
+ int j = bn_get_bit(l, i);
dv_swap_cond(t[0]->x[0], t[1]->x[0], RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->x[1], t[1]->x[1], RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->x[2], t[1]->x[2], RLC_FP_DIGS, j ^ 1);
@@ -354,13 +398,13 @@ void ep3_mul_monty(ep3_t r, const ep3_t p, const bn_t k) {
}
ep3_norm(r, t[0]);
- if (bn_sign(k) == RLC_NEG) {
- ep3_neg(r, r);
- }
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
+ bn_free(n);
+ bn_free(l);
+ bn_free(_k);
ep3_free(t[1]);
ep3_free(t[0]);
}
diff --git a/src/epx/relic_ep3_mul_cof.c b/src/epx/relic_ep3_mul_cof.c
index 1fc9c4fc7..02a47498d 100644
--- a/src/epx/relic_ep3_mul_cof.c
+++ b/src/epx/relic_ep3_mul_cof.c
@@ -35,16 +35,19 @@
#include "relic_tmpl_map.h"
/*============================================================================*/
-/* Public definitions */
+/* Private definitions */
/*============================================================================*/
-void ep3_mul_cof(ep3_t r, const ep3_t p) {
- ep3_t tx1, tx2, tx3, t0, t1, t2, t3, t4, t5;
+/**
+ * Multiplies a point by the cofactor in a KSS18 curve.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ */
+static void ep3_mul_cof_k18(ep3_t r, const ep3_t p) {
+ ep3_t t0, t1, t2, t3, t4, t5;
bn_t x;
- ep3_null(tx1);
- ep3_null(tx2);
- ep3_null(tx3);
ep3_null(t0);
ep3_null(t1);
ep3_null(t2);
@@ -54,9 +57,6 @@ void ep3_mul_cof(ep3_t r, const ep3_t p) {
bn_null(x);
RLC_TRY {
- ep3_new(tx1);
- ep3_new(tx2);
- ep3_new(tx3);
ep3_new(t0);
ep3_new(t1);
ep3_new(t2);
@@ -65,54 +65,78 @@ void ep3_mul_cof(ep3_t r, const ep3_t p) {
ep3_new(t5);
bn_new(x);
+ /* Method from "Faster Hashing to G2" by Laura Fuentes-Castañeda,
+ * Edward Knapp and Francisco RodrÃguez-HenrÃquez.
+ . */
+
+ /* Compute multi-addition-subtraction chain \sum \lambda_i \psi^P, where
+ * \lambda_0 = 5u + 18
+ * \lambda_1 = (u^3+3u^2+1)
+ * \lambda_2 = -(3u^2+8*u)
+ * \lambda_3 = (3u+1)
+ * \lambda_4 = -(u^2+2)
+ * \lambda_5 = (u^2+5u)
+
+ * We will write the subscalars below as vectors for simplicity.
+ */
+
fp_prime_get_par(x);
- ep3_mul_basic(tx1, p, x);
- ep3_mul_basic(tx2, tx1, x);
- ep3_mul_basic(tx3, tx2, x);
+ /* t0 = [u]P, t4 = [u^2]P, later t2 = [u^3]P. */
+ ep3_mul_basic(t0, p, x);
+ ep3_mul_basic(t4, t0, x);
- ep3_frb(t1, tx1, 2);
+ /* t1 = [1, 0, -u, 0, 0, 0]. */
+ ep3_frb(t1, t0, 2);
+ /* t2 = [u, 0, 0, 0, 0, u]. */
ep3_frb(t2, t1, 3);
- ep3_add(t2, t2, tx1);
+ ep3_add(t2, t2, t0);
+ /* t3 = [0, 0, 0, -u, 0, 0]. */
ep3_frb(t3, t1, 1);
ep3_neg(t1, t1);
-
- ep3_frb(t4, tx2, 1);
- ep3_add(t3, t3, t4);
- ep3_frb(t4, t4, 1);
- ep3_sub(t3, t3, t4);
-
- ep3_frb(t4, p, 4);
- ep3_neg(t4, t4);
-
- ep3_frb(t5, p, 1);
- ep3_frb(tx1, t5, 2);
- ep3_add(t5, t5, tx1);
- ep3_frb(tx1, tx2, 4);
- ep3_sub(t5, t5, tx1);
- ep3_frb(tx2, tx1, 1);
- ep3_add(t5, t5, tx2);
- ep3_frb(tx3, tx3, 1);
- ep3_add(t5, t5, tx3);
-
ep3_add(t1, t1, p);
+ /* t0 = [u+3, 0, -u, 0, 0, u]. */
ep3_dbl(t0, p);
ep3_add(t0, t0, t2);
ep3_add(t0, t0, t1);
+
+ /* t2 = [0, 0, u^2, 0, 0, 0], t3 = [0, u^2, -u^2, -u, 0, 0]. */
+ ep3_frb(t2, t4, 1);
+ ep3_add(t3, t3, t2);
+ ep3_frb(t2, t2, 1);
+ ep3_sub(t3, t3, t2);
+
+ /* t5 = [0, u^3 + 1, 0, 1, -u^2, u^2] */
+ ep3_frb(t5, p, 1);
+ ep3_frb(t2, t5, 2);
+ ep3_add(t5, t5, t2);
+ ep3_frb(t2, t4, 4);
+ ep3_sub(t5, t5, t2);
+ ep3_frb(t2, t2, 1);
+ ep3_add(t5, t5, t2);
+ ep3_mul_basic(t2, t4, x);
+ ep3_frb(t2, t2, 1);
+ ep3_add(t5, t5, t2);
+
+ /* t4 = [0, 0, 0, 0, -1, 0], t3 = [1, u^2, -u^2-u, -u, 0, 0]. */
+ ep3_frb(t4, p, 4);
+ ep3_neg(t4, t4);
ep3_add(t3, t3, t1);
+ /* t4 = [u+3, 0, -u, 0, -1, u]. */
ep3_add(t4, t4, t0);
+ /* t3 = [u+4, u^2, -u^2-2u, -u, -1, u]. */
ep3_add(t3, t3, t0);
+ /* t4 = [2u+7, u^2, -u^2-3u, -u, -1, 2u]. */
ep3_add(t4, t4, t3);
+ /* t3 = [u+4, u^3+u^2+1, -u^2-2u, -u+1, -u^2, u^2+u]. */
ep3_add(t3, t3, t5);
+ /* t4 = [4u+14, 2u^2, -2u^2-6u, -2u, -2, 4u]. */
ep3_dbl(t4, t4);
+ /* r = [5u+18, u^3+3u^2+1, -3u^2-8u, -3u+1, -u^2-2, u^2+5u]. */
ep3_add(r, t4, t3);
-
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
- ep3_free(tx1);
- ep3_free(tx2);
- ep3_free(tx3);
ep3_free(t0);
ep3_free(t1);
ep3_free(t2);
@@ -122,3 +146,104 @@ void ep3_mul_cof(ep3_t r, const ep3_t p) {
bn_free(x);
}
}
+
+/**
+ * Multiplies a point by the cofactor in a Scott-Guillevic curve.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ */
+static void ep3_mul_cof_sg18(ep3_t r, const ep3_t p) {
+ ep3_t t0, t1, t2, t3, t4;
+ bn_t x;
+
+ ep3_null(t0);
+ ep3_null(t1);
+ ep3_null(t2);
+ ep3_null(t3);
+ ep3_null(t4);
+ bn_null(x);
+
+ RLC_TRY {
+ ep3_new(t0);
+ ep3_new(t1);
+ ep3_new(t2);
+ ep3_new(t3);
+ ep3_new(t4);
+ bn_new(x);
+
+ /* Vector computed by Guillevic's MAGMA script:
+ [9*u^4-3*u^2+u, 3*u^2-1, -6*u^3 + 2*u, -2*u, 0, 3*u^3-u+1] */
+ fp_prime_get_par(x);
+
+ /* t0 = [u]P, t1 = [3u^2]P, t2 = [3u^3]P, t3 = [9u^4]P. */
+ ep3_mul_basic(t0, p, x);
+ bn_mul_dig(x, x, 3);
+ ep3_mul_basic(t1, t0, x);
+ bn_div_dig(x, x, 3);
+ ep3_mul_basic(t2, t1, x);
+ bn_mul_dig(x, x, 3);
+ ep3_mul_basic(t3, t2, x);
+ ep3_sub(t3, t3, t1);
+ ep3_add(t3, t3, t0);
+
+ ep3_sub(t4, t1, p),
+ ep3_frb(t4, t4, 1);
+ ep3_add(t3, t3, t4);
+
+ ep3_sub(t2, t2, t0);
+ ep3_frb(t4, t2, 2);
+ ep3_dbl(t4, t4);
+ ep3_sub(t3, t3, t4);
+ ep3_add(t2, t2, p);
+ ep3_frb(t2, t2, 5);
+ ep3_add(t3, t3, t2);
+
+ ep3_dbl(t4, t0);
+ ep3_frb(t4, t4, 3);
+ ep3_sub(r, t3, t4);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep3_free(t0);
+ ep3_free(t1);
+ ep3_free(t2);
+ ep3_free(t3);
+ ep3_free(t4);
+ bn_free(x);
+ }
+}
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep3_mul_cof(ep3_t r, const ep3_t p) {
+ bn_t k;
+
+ bn_null(k);
+
+ RLC_TRY {
+ switch (ep_curve_is_pairf()) {
+ case EP_K18:
+ ep3_mul_cof_k18(r, p);
+ break;
+ case EP_SG18:
+ ep3_mul_cof_sg18(r, p);
+ break;
+ default:
+ /* Now, multiply by cofactor to get the correct group. */
+ ep3_curve_get_cof(k);
+ if (bn_bits(k) < RLC_DIG) {
+ ep3_mul_dig(r, p, k->dp[0]);
+ } else {
+ ep3_mul_basic(r, p, k);
+ }
+ break;
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(k);
+ }
+}
diff --git a/src/epx/relic_ep3_mul_fix.c b/src/epx/relic_ep3_mul_fix.c
index 241aeee9c..66276d5a2 100644
--- a/src/epx/relic_ep3_mul_fix.c
+++ b/src/epx/relic_ep3_mul_fix.c
@@ -136,9 +136,6 @@ void ep3_mul_fix_basic(ep3_t r, const ep3_t *t, const bn_t k) {
}
}
ep3_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep3_neg(r, r);
- }
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
@@ -244,9 +241,6 @@ void ep3_mul_fix_combs(ep3_t r, const ep3_t *t, const bn_t k) {
}
}
ep3_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep3_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -361,9 +355,6 @@ void ep3_mul_fix_combd(ep3_t r, const ep3_t *t, const bn_t k) {
ep3_add(r, r, t[(1 << RLC_DEPTH) + w1]);
}
ep3_norm(r, r);
- if (bn_sign(_k) == RLC_NEG) {
- ep3_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
diff --git a/src/epx/relic_ep3_mul_sim.c b/src/epx/relic_ep3_mul_sim.c
index 08bfab688..408232a57 100644
--- a/src/epx/relic_ep3_mul_sim.c
+++ b/src/epx/relic_ep3_mul_sim.c
@@ -52,14 +52,13 @@
*/
static void ep3_mul_sim_plain(ep3_t r, const ep3_t p, const bn_t k,
const ep3_t q, const bn_t m, ep3_t *t) {
- int i, n0, n1, w, gen;
+ int i, n0, n1, w, gen = (t == NULL ? 0 : 1);
size_t l, l0, l1;
int8_t naf0[2 * RLC_FP_BITS + 1], naf1[2 * RLC_FP_BITS + 1], *_k, *_m;
ep3_t t0[1 << (RLC_WIDTH - 2)];
ep3_t t1[1 << (RLC_WIDTH - 2)];
RLC_TRY {
- gen = (t == NULL ? 0 : 1);
if (!gen) {
for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
ep3_null(t0[i]);
@@ -390,14 +389,14 @@ void ep3_mul_sim_gen(ep3_t r, const bn_t k, const ep3_t q, const bn_t m) {
}
}
-void ep3_mul_sim_dig(ep3_t r, const ep3_t p[], const dig_t k[], int len) {
+void ep3_mul_sim_dig(ep3_t r, const ep3_t p[], const dig_t k[], size_t len) {
ep3_t t;
int max;
ep3_null(t);
max = util_bits_dig(k[0]);
- for (int i = 1; i < len; i++) {
+ for (size_t i = 1; i < len; i++) {
max = RLC_MAX(max, util_bits_dig(k[i]));
}
diff --git a/src/epx/relic_ep3_norm.c b/src/epx/relic_ep3_norm.c
index 84d475e47..0015c2711 100644
--- a/src/epx/relic_ep3_norm.c
+++ b/src/epx/relic_ep3_norm.c
@@ -36,7 +36,7 @@
/* Private definitions */
/*============================================================================*/
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
/**
* Normalizes a point represented in projective coordinates.
@@ -95,7 +95,7 @@ void ep3_norm(ep3_t r, const ep3_t p) {
/* If the point is represented in affine coordinates, we just copy it. */
ep3_copy(r, p);
}
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
ep3_norm_imp(r, p, 0);
#endif
}
@@ -121,10 +121,11 @@ void ep3_norm_sim(ep3_t *r, const ep3_t *t, int n) {
fp3_copy(r[i]->y, t[i]->y);
fp3_copy(r[i]->z, a[i]);
}
-
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
for (i = 0; i < n; i++) {
ep3_norm_imp(r[i], r[i], 1);
}
+#endif
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
diff --git a/src/epx/relic_ep3_util.c b/src/epx/relic_ep3_util.c
index c28b95ad5..723bfdfcf 100644
--- a/src/epx/relic_ep3_util.c
+++ b/src/epx/relic_ep3_util.c
@@ -248,7 +248,7 @@ int ep3_size_bin(const ep3_t a, int pack) {
return size;
}
-void ep3_read_bin(ep3_t a, const uint8_t *bin, int len) {
+void ep3_read_bin(ep3_t a, const uint8_t *bin, size_t len) {
if (len == 1) {
if (bin[0] == 0) {
ep3_set_infty(a);
@@ -282,7 +282,7 @@ void ep3_read_bin(ep3_t a, const uint8_t *bin, int len) {
}
}
-void ep3_write_bin(uint8_t *bin, int len, const ep3_t a, int pack) {
+void ep3_write_bin(uint8_t *bin, size_t len, const ep3_t a, int pack) {
ep3_t t;
ep3_null(t);
diff --git a/src/epx/relic_ep4_curve.c b/src/epx/relic_ep4_curve.c
index dafdf678d..5b228c439 100644
--- a/src/epx/relic_ep4_curve.c
+++ b/src/epx/relic_ep4_curve.c
@@ -84,6 +84,29 @@
/** @} */
#endif
+#if defined(EP_ENDOM) && FP_PRIME == 330
+/** @{ */
+#define K16_P330_A0 "0"
+#define K16_P330_A1 "0"
+#define K16_P330_A2 "1"
+#define K16_P330_A3 "0"
+#define K16_P330_B0 "0"
+#define K16_P330_B1 "0"
+#define K16_P330_B2 "0"
+#define K16_P330_B3 "0"
+#define K16_P330_X0 "0A8E1814295DCD3B32115B7ECA482E00E799D573C1C87226DF403C088C4E0D6867D0F782463D75EF703"
+#define K16_P330_X1 "1C35DF89EBA1F4F7F0914CCC2217236A2DEBD627A4140DB7DE5B6C34B64CBFEB0D6A81D37175FC2D2D0"
+#define K16_P330_X2 "121D8B058C749480DBD0C3B80A7A87A6062EAFBA48C38A4209D366182B5CF34144A63EA4D2D22A49810"
+#define K16_P330_X3 "13DD1C6C7EF26A3BE18758FDD4DA5B1FC973B9C7B2FE6F95742E63209743DA5DC9D78508FFF7D6577F5"
+#define K16_P330_Y0 "1D6E4D1204B71D526B26E4F9659A56950863CA7A11798AD0002A662C94925555508BDC74A72AFF20761"
+#define K16_P330_Y1 "174D707AAB7BE8D7FD66A81C116C35FAA3DE173AF8E78EBF4D21946D1DAE273D2F01D18BF58FB6774F9"
+#define K16_P330_Y2 "07B52F66D7F4F13D402C90F25289B984F4803D5AB4C5D27C38205B96A35D4BA7E21128C628CB8533252"
+#define K16_P330_Y3 "230B103DC9594C0EAC2F136CAF4CC297EE32FBB5D6F2EB1F39F73ED0715410E528827C27A28E47E32C3"
+#define K16_P330_R "A9AE90F426EE7F9DB56D9C82F1C0B2CA3CB15B2F8ABF5803C963444D043D2731"
+#define K16_P330_H "29FFFB0947F8B82A090873C9E956B3A36AB6E037E0A77753117BF9F84FF2EB53D7B3AA3AFB0124167228D28EA26DF7AB6B4A69C60F0F66576B9A07331B9FB744EEF9DEB9AC59EF48BA9872139AF319E427E6DEEF4D6F24C1525725A22B36AA73476912FE2295DE6353A113DB8C14637D012DD09C2637D6F6EA569A3ABC835DF9E3AB55DA62"
+/** @} */
+#endif
+
#if defined(EP_ENDOM) && FP_PRIME == 509
/** @{ */
#define B24_P509_A0 "0"
@@ -107,6 +130,53 @@
/** @} */
#endif
+#if defined(EP_ENDOM) && FP_PRIME == 765
+/** @{ */
+#define N16_P765_A0 "0"
+#define N16_P765_A1 "0"
+#define N16_P765_A2 "1"
+#define N16_P765_A3 "0"
+#define N16_P765_B0 "0"
+#define N16_P765_B1 "0"
+#define N16_P765_B2 "0"
+#define N16_P765_B3 "0"
+#define N16_P765_X0 "004C4A977FFCA75E15AEB9C8B8EAB0CAB30A488EF0424C9658FB8A05E4CA6A1E2997FAD9F0DE053D69751CBA6F49059CB2E0BAC08AA25A575BC1E1468E2E1BD78FB87C2ABCA3C20AB55B8B18F5266CD05FC4B26DFB091FB4A130312132D09614"
+#define N16_P765_X1 "0EE552F7143FA01D9919C462036AEC50C76BE752823C49910EF121F05B22494897A213DDF33166C6F8CA16995A83B9526EADE2D74366C349313DD126CC89249F282C1F3715BB690A1AD176F53F6EF6D75873E8A857FC0794F2AE1AE7C12D8F8B"
+#define N16_P765_X2 "14A32856133B3D59AC0DC99C3D34D830A7003BF41CED95B126BF0D2BAAB3C92A0E24CAFE5B6030F0FBD29E7CF08F808787A273B171B05C50CD052A3C031288BFBDE6CF4F53270477B12621F35193B5FAD47E6A77B33BD2B9FF9D3687AE6AE48D"
+#define N16_P765_X3 "0C478BC2CC455CDE662F112B2C4F9B24A0DA57515A44DD61591E3F3532AA8C640D84CAFADECADAE4D249D1038F3D030E173CFA87C51BF90BF49B1DFAB84B9ACC0ABD72349A3ADAB2BF056EF39AB6101F1D89C6C9D7761BFC9D5E0E050E299138"
+#define N16_P765_Y0 "00DEDAE825C143B4DFCB3A8B5F87BA7BADE72AF792AB7DFF198FE234AE16D8B5B45D9B033415FD4B59099DAFEF8A5782AC4D86BCD555AFCBA31111E07E34D1233A59505BEABB6FDEDE470A5182D0B6DDE2E48BE313D445EA0D11062D109382D6"
+#define N16_P765_Y1 "0D77B57018036B23B857B823374756FC62C05244E47D5237961304B9B7BFDE3BE874B58B5F7B4805726BB0042CEEFF3FBF76F7EBEA3D36CC1E46BBAF4819F76DB1BFBC05E8577D4E992407C245418170CE03D6DD3A153DCC217F995191749773"
+#define N16_P765_Y2 "0ADFD23B22ABAF4C64ECE323D37878D1D437EB77860ABF4EC0C2ADA1054D4BAB06422FF17E3A59FE4AE7B254F2228138A50E819616A6F6F44671CE2FB19962D4687510516A6786E06060560D714FF35C05C7F3B8600E5ADBE796DC7FD331C8C4"
+#define N16_P765_Y3 "0E9EA14175A8DAA9C83F5A6C7CCBE6E7CBE534B5AEB9A92B8689F73AF7356EEC955FBE18F6D687561E3D13D781DCB3B90C78392093343E30FE68A5E92A61434F366945C20896A3AD11856AF4B4558791CA9BDE9598734BBE1B33CE618E809982"
+#define N16_P765_R "9965D956A0DBC8AF273C0100000000000000000000000000000000000000000000000000000000000000000000000001"
+#define N16_P765_H "719C0F18991838D271B16518B194F6F145242127E49DC9A094D6CB692E28DC5F17FFA92321BB6498A829BA8C587373ED1198514FA52F945FEF0BD7DB7AEECF44BA1DC59375BEFBFC8467B4B2DCB8BC87E9FBD6615875E2CDA99813230882AE3B19CC78906339C451CE982DED4C8C2B44D01B86D2440D89A5F5AC3BF04E1393A4DC6712246A0E6F966D734F449D38655E7BF22CC56C0609840678EB8285D561CE1E65F73F1142F3C526CA2E28484D72F0B0492E78604F0AAB2DBBD13A082DFB9513D5C0D5C6CCFD13A6D3DA2EEC9A2AEFD40EC51A940F59D64F45BADB3EBEB96FCDAE11951717C5DF0125F274306A90C0FCF19D34FCB0D37683A2743F8C3ECAFE55863AA6B35BD14C7A894E6D7DC05D12E0D551AE0E46AB11D80610EA749AAEA445FE78651B64091AB67E32F33AA4CE905E2AF4A64A03B25A5C08233C52CBB94BF8000E13C04000003C08000000002"
+/** @} */
+#endif
+
+
+#if defined(EP_ENDOM) && FP_PRIME == 766
+/** @{ */
+#define K16_P766_A0 "0"
+#define K16_P766_A1 "0"
+#define K16_P766_A2 "1"
+#define K16_P766_A3 "0"
+#define K16_P766_B0 "0"
+#define K16_P766_B1 "0"
+#define K16_P766_B2 "0"
+#define K16_P766_B3 "0"
+#define K16_P766_X0 "2864F5E5FB6FED078FAD04D5587701E9973407697AB1BBF402111C686E6FD2AFD20658BB74DCE094C1316032413E662255F923A11D68AB9851527074A01855830F521B431F14026FCB0BD075402203D31C4DA096A9B85EC3B297144700D2D377"
+#define K16_P766_X1 "2823AC7365F9C56A3B5C27882F05C971087A0D54E44AA1C4D697C1BF371E7DA060FC680601C3F78AA6D8BD91BDCD213ACA6D65A3700742900FB4D3A3AA78C2EBD61763CD4727C057BF9EEA3A5EACC023B66B61A3473BE5BCF98125A91F1C084E"
+#define K16_P766_X2 "37FC8358DC23B2A6FE3763ED787841E4355D203DD94A113A6EFEF3ED4E4ED1D7D47E5B7B8F85CF52C0B2479ECC74AAB21C56537D80708D65C1BC1E5E6FF69CC93B2F292DA61270386520FB79B780DE7BEF87EF43006EADCDF3AF82ED9556A0A4"
+#define K16_P766_X3 "2E699CE6FA1448A9523F867F0C1FCB9C4CE22B007C058C474EF0BAEA2B3E3F486BC1A6A3BF0C396D23E60C60C7FBCDFF8AFF535E9786923B3E8798E23724355422DA4E3AB07D9FF519C94A79610CBF0449A4FC8AB1EEB75EC87879F22655F850"
+#define K16_P766_Y0 "03F2F35FCFCCEA92B77B4C6F7A331D1EF96E9616CB26539FF018D0DE51B2A536CE69C9E564B665A6C806CE46AF3DD7FA478AB78548526E0305545C332A5DD7A19694069C2D9585197ED80C81BF9F2CBDD7A0F0FE37156FACF93D2FCC4F2241D5"
+#define K16_P766_Y1 "02F05261C24AC6F7948C6F86E458E011E71E619BE8C8119E438EE184979A5F64D07A3845A7189FB1B9D0BC90E625C7194C43EA281559DD09A2E2FCE5A7D1CC50E8176F5458A620C70DCD32F1FEAB870D7B9AEC8F9620B9D88BA201C59511228D"
+#define K16_P766_Y2 "12936CF6E9B0279986ABD00C068B7376CA39D4EEAF2598D4276DC1060D75069A8E11E61C526BEDF38E523B9C176E34EF193B958B818CEF1FEE3FCB092D903EA747CB08F9B98338CE500030BE5539EDA6FBEE2B47A60EF989E180B50E125565BF"
+#define K16_P766_Y3 "16CBBA489FA40077403ECBE1817781E753BEBA8507D44A7FB6D40737E84C754ECA100C336243F9E763D8D71D31117EACDAB48C59E55065CEABAE97EC2CC66E0878F2377CF8E9312FF6615661D909314C28D5173B725BB81DF63465D862BBD53D"
+#define K16_P766_R "1B6C1BFC8E56CCE359E1D8A9B94553D096A506CE2ECF4A33C5D526AC5F3B61CB0A6D76FCD8487EDEE0B0F9BA2DFA29D5AB0B164B8792C233ED1E6EB350BA9F4D37112A98DE816BEB1EA8DDB1"
+#define K16_P766_H "755986B96E4AAB1797EAEDDCB714FA0EC4E13C9AF468746FEE467D8D27293EF56C4CFA83CC6DD8774B03009353D93F100EC1314BAB5764E3D32F3DA621C7B3DDACB086098C31F7999CA8F4EA67165C3595BFAD8DBE5B7951091040E97CC5A27149F16A9A960F2557EC038032C876E49E4C40E56C1BD543BD910CB3BAABFA2F9179D2B1711E168A6472FCC1A8D8AF3415559DBF3108029DB68CC8343D397F78577E9EF7DFE8E239D9F5D9EBC1011B8F9E6043DD53C1B98C12BFA48E8A17B3BB0F5DE92DEEA7C9088EA9A643C66D4016BF81616AE20C609045A3EBA6AF3F7BEDC6AE78ABBF788F36CA894B789C84C484B4D31B83DB5CC95783DA34FC601EF7D7F07F60128E0F0E007AE29AB2F98C7A483F0E4CA614E4E45650D3E210A2EB030A6C339DB66CC198FE0EAC1CA827A8A975D094B7862"
+/** @} */
+#endif
+
/**
* Assigns a set of ordinary elliptic curve parameters.
*
@@ -260,53 +330,6 @@ void ep4_curve_get_b(fp4_t b) {
fp4_copy(b, core_get()->ep4_b);
}
-void ep4_curve_get_vs(bn_t *v) {
- bn_t x, t;
-
- bn_null(x);
- bn_null(t);
-
- RLC_TRY {
- bn_new(x);
- bn_new(t);
-
- fp_prime_get_par(x);
- bn_copy(v[1], x);
- bn_copy(v[2], x);
- bn_copy(v[3], x);
-
- /* t = 2x^2. */
- bn_sqr(t, x);
- bn_dbl(t, t);
-
- /* v0 = 2x^2 + 3x + 1. */
- bn_mul_dig(v[0], x, 3);
- bn_add_dig(v[0], v[0], 1);
- bn_add(v[0], v[0], t);
-
- /* v3 = -(2x^2 + x). */
- bn_add(v[3], v[3], t);
- bn_neg(v[3], v[3]);
-
- /* v1 = 12x^3 + 8x^2 + x, v2 = 6x^3 + 4x^2 + x. */
- bn_dbl(t, t);
- bn_add(v[2], v[2], t);
- bn_dbl(t, t);
- bn_add(v[1], v[1], t);
- bn_rsh(t, t, 2);
- bn_mul(t, t, x);
- bn_mul_dig(t, t, 3);
- bn_add(v[2], v[2], t);
- bn_dbl(t, t);
- bn_add(v[1], v[1], t);
- } RLC_CATCH_ANY {
- RLC_THROW(ERR_CAUGHT);
- } RLC_FINALLY {
- bn_free(x);
- bn_free(t);
- }
-}
-
void ep4_curve_get_ord(bn_t n) {
ctx_t *ctx = core_get();
if (ctx->ep4_is_twist) {
@@ -368,10 +391,22 @@ void ep4_curve_set_twist(int type) {
case B24_P317:
ASSIGN(B24_P317);
break;
+#elif FP_PRIME == 330
+ case K16_P330:
+ ASSIGN(K16_P330);
+ break;
#elif FP_PRIME == 509
case B24_P509:
ASSIGN(B24_P509);
break;
+#elif FP_PRIME == 765
+ case N16_P765:
+ ASSIGN(N16_P765);
+ break;
+#elif FP_PRIME == 766
+ case K16_P766:
+ ASSIGN(K16_P766);
+ break;
#endif
default:
(void)str;
@@ -393,13 +428,27 @@ void ep4_curve_set_twist(int type) {
bn_copy(&(ctx->ep4_r), r);
bn_copy(&(ctx->ep4_h), h);
- if (type == RLC_EP_MTYPE) {
+ if (ep4_curve_opt_b() == RLC_ZERO) {
fp2_zero(a[0]);
- fp_copy(a[1][0], ctx->fp4_p1[0]);
- fp_copy(a[1][1], ctx->fp4_p1[1]);
+ fp_copy(a[1][0], ctx->fp2_p2[1][0]);
+ fp_copy(a[1][1], ctx->fp2_p2[1][1]);
fp4_inv(a, a);
fp_copy(ctx->fp4_p1[0], a[1][0]);
fp_copy(ctx->fp4_p1[1], a[1][1]);
+ if (fp2_is_zero(a[1])) {
+ ctx->frb4 = 0;
+ } else {
+ ctx->frb4 = 1;
+ }
+ } else {
+ if (type == RLC_EP_MTYPE) {
+ fp2_zero(a[0]);
+ fp_copy(a[1][0], ctx->fp4_p1[0]);
+ fp_copy(a[1][1], ctx->fp4_p1[1]);
+ fp4_inv(a, a);
+ fp_copy(ctx->fp4_p1[0], a[1][0]);
+ fp_copy(ctx->fp4_p1[1], a[1][1]);
+ }
}
#if defined(WITH_PC)
diff --git a/src/epx/relic_ep4_map.c b/src/epx/relic_ep4_map.c
index 6701e8fbd..55d37cd39 100644
--- a/src/epx/relic_ep4_map.c
+++ b/src/epx/relic_ep4_map.c
@@ -38,42 +38,262 @@
/*============================================================================*/
void ep4_map(ep4_t p, const uint8_t *msg, size_t len) {
- bn_t x;
- fp4_t t0;
- uint8_t digest[RLC_MD_LEN];
+ /* enough space for two field elements plus extra bytes for uniformity */
+ const size_t elm = (FP_PRIME + ep_param_level() + 7) / 8;
+ uint8_t t0z, t0, t1, s[2], sign, *h = RLC_ALLOCA(uint8_t, 8 * elm + 1);
+ fp4_t a, c, t, u, v, w, y, x1, y1, z1;
+ ctx_t *ctx = core_get();
+ bn_t k;
- bn_null(x);
- fp4_null(t0);
+ bn_null(k);
+ fp4_null(a);
+ fp4_null(c);
+ fp4_null(t);
+ fp4_null(u);
+ fp4_null(v);
+ fp4_null(w);
+ fp4_null(y);
+ fp4_null(x1);
+ fp4_null(y1);
+ fp4_null(z1);
RLC_TRY {
- bn_new(x);
- fp4_new(t0);
+ bn_new(k);
+ fp4_new(a);
+ fp4_new(c);
+ fp4_new(t);
+ fp4_new(u);
+ fp4_new(v);
+ fp4_new(w);
+ fp4_new(y);
+ fp4_new(x1);
+ fp4_new(y1);
+ fp4_new(z1);
- md_map(digest, msg, len);
- bn_read_bin(x, digest, RLC_MIN(RLC_FP_BYTES, RLC_MD_LEN));
+ if (ep4_curve_opt_b() == RLC_ZERO) {
+ /* This is the approach due to Koshelev introduced in
+ * https://eprint.iacr.org/2021/1034.pdf */
+
+ md_xmd(h, 4 * elm + 1, msg, len, (const uint8_t *)"RELIC", 5);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ bn_read_bin(k, h, elm);
+ fp_prime_conv(u[i][j], k);
+ h += elm;
+ }
+ }
- fp4_zero(p->x);
- fp_prime_conv(p->x[0][0], x);
- fp4_set_dig(p->z, 1);
+ /* Compute c = 3*a^2, t^2 = 6a(9u^5 − 14au^3 + 3cu).*/
+ ep4_curve_get_a(a);
+ fp4_neg(a, a);
+ fp4_sqr(c, a);
+ fp4_dbl(t, c);
+ fp4_add(c, c, t);
+ fp4_dbl(t, c);
+ fp4_add(t, t, c);
+ fp4_mul(t, t, u);
- while (1) {
- ep4_rhs(t0, p);
+ fp4_sqr(v, u);
+ fp4_mul(w, v, u);
+ fp4_mul(x1, w, a);
+ fp4_mul_dig(x1, x1, 14);
+ fp4_sub(t, t, x1);
- if (fp4_srt(p->y, t0)) {
- p->coord = BASIC;
- break;
+ fp4_mul(w, w, v);
+ fp4_dbl(x1, w);
+ fp4_add(w, w, x1);
+ fp4_dbl(x1, w);
+ fp4_add(w, w, x1);
+ fp4_add(t, t, w);
+ fp4_mul(t, t, a);
+ fp4_dbl(t, t);
+ fp4_dbl(x1, t);
+ fp4_add(t, t, x1);
+ dig_t c1 = fp4_is_sqr(t);
+ /* If t is not square, compute u = a/u, t = a*sqrt(a*t)/u^3*/
+ fp4_inv(x1, u);
+ fp4_mul(y1, t, a);
+ /* If t is a square, extract its square root. */
+ dv_copy_cond(t[0][0], y1[0][0], RLC_FP_DIGS, !c1);
+ dv_copy_cond(t[0][1], y1[0][1], RLC_FP_DIGS, !c1);
+ dv_copy_cond(t[1][0], y1[1][0], RLC_FP_DIGS, !c1);
+ dv_copy_cond(t[1][1], y1[1][1], RLC_FP_DIGS, !c1);
+ fp4_srt(t, t);
+ fp4_mul(y1, t, a);
+ fp4_sqr(y, x1);
+ fp4_mul(y, y, x1);
+ fp4_mul(y1, y1, y);
+ fp4_mul(x1, x1, a);
+ dv_copy_cond(u[0][0], x1[0][0], RLC_FP_DIGS, !c1);
+ dv_copy_cond(u[0][1], x1[0][1], RLC_FP_DIGS, !c1);
+ dv_copy_cond(u[1][0], x1[1][0], RLC_FP_DIGS, !c1);
+ dv_copy_cond(u[1][1], x1[1][1], RLC_FP_DIGS, !c1);
+ dv_copy_cond(t[0][0], y1[0][0], RLC_FP_DIGS, !c1);
+ dv_copy_cond(t[0][1], y1[0][1], RLC_FP_DIGS, !c1);
+ dv_copy_cond(t[1][0], y1[1][0], RLC_FP_DIGS, !c1);
+ dv_copy_cond(t[1][1], y1[1][1], RLC_FP_DIGS, !c1);
+
+ /* Compute x = 2^4*i*3*a^2*u / (3*(3*u^2 - a))^2. */
+ fp4_zero(y);
+ fp_copy(y[0][0], ctx->ep_map_c[6]);
+ fp4_mul(c, c, u);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ fp_mul(x1[i][j], c[i][j], y[0][0]);
+ }
}
+ fp4_dbl(x1, x1);
+ fp4_dbl(x1, x1);
+ fp4_dbl(x1, x1);
+ fp4_dbl(p->x, x1);
+ fp4_sqr(v, u);
+ fp4_dbl(z1, v);
+ fp4_add(z1, z1, v);
+ fp4_sub(z1, z1, a);
+ fp4_dbl(p->z, z1);
+ fp4_add(p->z, p->z, z1);
- fp_add_dig(p->x[0][0], p->x[0][0], 1);
+ /* Compute y = 3*2*(i-1)*a*(3^2*u^2 + a)*t / (3*(3*u^2 - a))^3. */
+ fp_sub_dig(y[0][0], y[0][0], 1);
+ fp4_mul(y1, y, a);
+ fp4_dbl(y1, y1);
+ fp4_dbl(p->y, y1);
+ fp4_add(p->y, p->y, y1);
+ fp4_mul(p->y, p->y, t);
+ fp4_dbl(y1, v);
+ fp4_add(y1, y1, v);
+ fp4_dbl(v, y1);
+ fp4_add(y1, y1, v);
+ fp4_add(y1, y1, a);
+ fp4_mul(p->y, p->y, y1);
+
+ /* Multiply by cofactor. */
+ p->coord = JACOB;
+ ep4_norm(p, p);
}
+ if (ep_curve_opt_a() == RLC_ZERO) {
+ md_xmd(h, 8 * elm + 1, msg, len, (const uint8_t *)"RELIC", 5);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ bn_read_bin(k, h, elm);
+ fp_prime_conv(u[i][j], k);
+ h += elm;
+ bn_read_bin(k, h, elm);
+ fp_prime_conv(t[i][j], k);
+ h += elm;
+ }
+ }
+ sign = h[0] & 1;
+
+ fp4_sqr(x1, u);
+ fp4_mul(x1, x1, u);
+ fp4_sqr(y1, t);
+ fp4_add(x1, x1, ctx->ep4_b);
+ fp4_sub(x1, x1, y1);
+ fp4_dbl(y1, y1);
+ fp4_add(y1, y1, x1);
+ fp4_copy(z1, u);
+ fp_mul(z1[0][0], z1[0][0], ctx->ep_map_c[4]);
+ fp_mul(z1[0][1], z1[0][1], ctx->ep_map_c[4]);
+ fp_mul(z1[1][0], z1[1][0], ctx->ep_map_c[4]);
+ fp_mul(z1[1][1], z1[1][1], ctx->ep_map_c[4]);
+ fp4_mul(x1, x1, z1);
+ fp4_mul(z1, z1, t);
+ fp4_dbl(z1, z1);
+
+ fp4_dbl(y, y1);
+ fp4_sqr(y, y);
+ fp4_mul(v, y1, u);
+ fp4_sub(v, x1, v);
+ fp4_mul(v, v, z1);
+ fp4_mul(w, y1, z1);
+ fp4_dbl(w, w);
+
+ if (fp4_is_zero(w)) {
+ ep4_set_infty(p);
+ } else {
+ fp4_inv(w, w);
+ fp4_mul(x1, v, w);
+ fp4_add(y1, u, x1);
+ fp4_neg(y1, y1);
+ fp4_mul(z1, y, w);
+ fp4_sqr(z1, z1);
+ fp4_add(z1, z1, u);
+
+ ep4_curve_get_b(w);
+
+ fp4_sqr(t, x1);
+ fp4_mul(t, t, x1);
+ fp4_add(t, t, w);
+
+ fp4_sqr(u, y1);
+ fp4_mul(u, u, y1);
+ fp4_add(u, u, w);
+
+ fp4_sqr(v, z1);
+ fp4_mul(v, v, z1);
+ fp4_add(v, v, w);
+
+ dig_t c2 = fp4_is_sqr(u);
+ dig_t c3 = fp4_is_sqr(v);
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ dv_swap_cond(x1[i][j], y1[i][j], RLC_FP_DIGS, c2);
+ dv_swap_cond(t[i][j], u[i][j], RLC_FP_DIGS, c2);
+ dv_swap_cond(x1[i][j], z1[i][j], RLC_FP_DIGS, c3);
+ dv_swap_cond(t[i][j], v[i][j], RLC_FP_DIGS, c3);
+ }
+ }
+
+ if (!fp4_srt(t, t)) {
+ RLC_THROW(ERR_NO_VALID);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ t0z = fp_is_zero(t[i][0]);
+ fp_prime_back(k, t[i][0]);
+ t0 = bn_get_bit(k, 0);
+ fp_prime_back(k, t[i][1]);
+ t1 = bn_get_bit(k, 0);
+ /* t[0] == 0 ? sgn0(t[1]) : sgn0(t[0]) */
+ s[i] = t0 | (t0z & t1);
+ }
+
+ t0z = fp2_is_zero(t[0]);
+ sign ^= (s[0] | (t0z & s[1]));
+
+ fp4_neg(u, t);
+ dv_swap_cond(t[0][0], u[0][0], RLC_FP_DIGS, sign);
+ dv_swap_cond(t[0][1], u[0][1], RLC_FP_DIGS, sign);
+ dv_swap_cond(t[1][0], u[1][0], RLC_FP_DIGS, sign);
+ dv_swap_cond(t[1][1], u[1][1], RLC_FP_DIGS, sign);
+
+ fp4_copy(p->x, x1);
+ fp4_copy(p->y, t);
+ fp4_set_dig(p->z, 1);
+ p->coord = BASIC;
+ }
+ }
+
ep4_mul_cof(p, p);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
- bn_free(x);
- fp4_free(t0);
+ bn_free(k);
+ fp4_free(a);
+ fp4_free(c);
+ fp4_free(t);
+ fp4_free(u);
+ fp4_free(v);
+ fp4_free(w);
+ fp4_free(y);
+ fp4_free(x1);
+ fp4_free(y1);
+ fp4_free(z1);
+ RLC_FREE(h);
}
}
diff --git a/src/epx/relic_ep4_mul.c b/src/epx/relic_ep4_mul.c
index 8510e5dcc..912742dcf 100644
--- a/src/epx/relic_ep4_mul.c
+++ b/src/epx/relic_ep4_mul.c
@@ -41,67 +41,49 @@
#if defined(EP_ENDOM)
static void ep4_mul_glv_imp(ep4_t r, const ep4_t p, const bn_t k) {
- int sign, i, j;
- bn_t n, _k[8], u, v;
+ size_t l, _l[8];
+ bn_t n, _k[8], u;
int8_t naf[8][RLC_FP_BITS + 1];
ep4_t q[8];
- size_t l, _l[8];
bn_null(n);
bn_null(u);
- bn_null(v);
RLC_TRY {
bn_new(n);
bn_new(u);
- bn_new(v);
- for (i = 0; i < 8; i++) {
+ for (int i = 0; i < 8; i++) {
bn_null(_k[i]);
ep4_null(q[i]);
bn_new(_k[i]);
ep4_new(q[i]);
}
- bn_abs(v, k);
ep4_curve_get_ord(n);
- if (bn_cmp_abs(v, n) == RLC_GT) {
- bn_mod(v, v, n);
- }
-
fp_prime_get_par(u);
- sign = bn_sign(u);
- bn_abs(u, u);
+ bn_mod(_k[0], k, n);
+ bn_rec_frb(_k, 8, _k[0], u, n, ep_curve_is_pairf() == EP_BN);
ep4_norm(q[0], p);
- for (i = 0; i < 8; i++) {
- bn_mod(_k[i], v, u);
- bn_div(v, v, u);
- if ((sign == RLC_NEG) && (i % 2 != 0)) {
- bn_neg(_k[i], _k[i]);
- }
- if (bn_sign(k) == RLC_NEG) {
- bn_neg(_k[i], _k[i]);
- }
- if (i > 0) {
- ep4_frb(q[i], q[i - 1], 1);
- }
+ for (size_t i = 1; i < 8; i++) {
+ ep4_frb(q[i], q[i - 1], 1);
}
- l = 0;
- for (i = 0; i < 8; i++) {
+ l = 0;
+ for (size_t i = 0; i < 8; i++) {
if (bn_sign(_k[i]) == RLC_NEG) {
ep4_neg(q[i], q[i]);
}
_l[i] = RLC_FP_BITS + 1;
bn_rec_naf(naf[i], &_l[i], _k[i], 2);
- l = RLC_MAX(l, _l[i]);
+ l = RLC_MAX(l, _l[i]);
}
ep4_set_infty(r);
- for (j = l - 1; j >= 0; j--) {
+ for (int j = l - 1; j >= 0; j--) {
ep4_dbl(r, r);
- for (i = 0; i < 8; i++) {
+ for (int i = 0; i < 8; i++) {
if (naf[i][j] > 0) {
ep4_add(r, r, q[i]);
}
@@ -119,9 +101,8 @@ static void ep4_mul_glv_imp(ep4_t r, const ep4_t p, const bn_t k) {
}
RLC_FINALLY {
bn_free(n);
- bn_free(u);
- bn_free(v);
- for (i = 0; i < 8; i++) {
+ bn_free(u);
+ for (int i = 0; i < 8; i++) {
bn_free(_k[i]);
ep4_free(q[i]);
}
@@ -186,35 +167,39 @@ static void ep4_mul_naf_imp(ep4_t r, const ep4_t p, const bn_t k) {
/*============================================================================*/
void ep4_mul_basic(ep4_t r, const ep4_t p, const bn_t k) {
- int i, l;
ep4_t t;
+ int8_t u, *naf = RLC_ALLOCA(int8_t, bn_bits(k) + 1);
+ size_t l;
ep4_null(t);
if (bn_is_zero(k) || ep4_is_infty(p)) {
+ RLC_FREE(naf);
ep4_set_infty(r);
return;
}
RLC_TRY {
ep4_new(t);
- l = bn_bits(k);
-
- if (bn_get_bit(k, l - 1)) {
- ep4_copy(t, p);
- } else {
- ep4_set_infty(t);
+ if (naf == NULL) {
+ RLC_THROW(ERR_NO_BUFFER);
}
- for (i = l - 2; i >= 0; i--) {
+ l = bn_bits(k) + 1;
+ bn_rec_naf(naf, &l, k, 2);
+ ep4_set_infty(t);
+ for (int i = l - 1; i >= 0; i--) {
ep4_dbl(t, t);
- if (bn_get_bit(k, i)) {
+
+ u = naf[i];
+ if (u > 0) {
ep4_add(t, t, p);
+ } else if (u < 0) {
+ ep4_sub(t, t, p);
}
}
- ep4_copy(r, t);
- ep4_norm(r, r);
+ ep4_norm(r, t);
if (bn_sign(k) == RLC_NEG) {
ep4_neg(r, r);
}
@@ -224,6 +209,7 @@ void ep4_mul_basic(ep4_t r, const ep4_t p, const bn_t k) {
}
RLC_FINALLY {
ep4_free(t);
+ RLC_FREE(naf);
}
}
@@ -301,7 +287,12 @@ void ep4_mul_slide(ep4_t r, const ep4_t p, const bn_t k) {
void ep4_mul_monty(ep4_t r, const ep4_t p, const bn_t k) {
ep4_t t[2];
+ bn_t n, l, _k;
+ size_t bits;
+ bn_null(n);
+ bn_null(l);
+ bn_null(_k);
ep4_null(t[0]);
ep4_null(t[1]);
@@ -311,14 +302,32 @@ void ep4_mul_monty(ep4_t r, const ep4_t p, const bn_t k) {
}
RLC_TRY {
+ bn_new(n);
+ bn_new(l);
+ bn_new(_k);
ep4_new(t[0]);
ep4_new(t[1]);
- ep4_set_infty(t[0]);
- ep4_copy(t[1], p);
+ ep4_curve_get_ord(n);
+ bits = bn_bits(n);
+
+ bn_mod(_k, k, n);
+ bn_abs(l, _k);
+ bn_add(l, l, n);
+ bn_add(n, l, n);
+ dv_swap_cond(l->dp, n->dp, RLC_MAX(l->used, n->used),
+ bn_get_bit(l, bits) == 0);
+ l->used = RLC_SEL(l->used, n->used, bn_get_bit(l, bits) == 0);
+
+ ep4_norm(t[0], p);
+ ep4_dbl(t[1], t[0]);
- for (int i = bn_bits(k) - 1; i >= 0; i--) {
- int j = bn_get_bit(k, i);
+ /* Blind both points independently. */
+ ep4_blind(t[0], t[0]);
+ ep4_blind(t[1], t[1]);
+
+ for (int i = bits - 1; i >= 0; i--) {
+ int j = bn_get_bit(l, i);
dv_swap_cond(t[0]->x[0][0], t[1]->x[0][0], RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->x[0][1], t[1]->x[0][1], RLC_FP_DIGS, j ^ 1);
dv_swap_cond(t[0]->x[1][0], t[1]->x[1][0], RLC_FP_DIGS, j ^ 1);
@@ -348,13 +357,13 @@ void ep4_mul_monty(ep4_t r, const ep4_t p, const bn_t k) {
}
ep4_norm(r, t[0]);
- if (bn_sign(k) == RLC_NEG) {
- ep4_neg(r, r);
- }
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
+ bn_free(n);
+ bn_free(l);
+ bn_free(_k);
ep4_free(t[1]);
ep4_free(t[0]);
}
@@ -372,7 +381,7 @@ void ep4_mul_lwnaf(ep4_t r, const ep4_t p, const bn_t k) {
#if defined(EP_ENDOM)
if (ep_curve_is_endom()) {
- if (ep_curve_opt_a() == RLC_ZERO) {
+ if (ep4_curve_opt_a() == RLC_ZERO) {
ep4_mul_glv_imp(r, p, k);
} else {
ep4_mul_naf_imp(r, p, k);
diff --git a/src/epx/relic_ep4_mul_cof.c b/src/epx/relic_ep4_mul_cof.c
index 2884290b3..ed3285e24 100644
--- a/src/epx/relic_ep4_mul_cof.c
+++ b/src/epx/relic_ep4_mul_cof.c
@@ -25,7 +25,7 @@
* @file
*
* Implementation of point multiplication of a prime elliptic curve over a
- * quadratic extension by the curve cofactor.
+ * quartic extension by the curve cofactor.
*
* @ingroup epx
*/
@@ -38,7 +38,177 @@
/* Public definitions */
/*============================================================================*/
-void ep4_mul_cof(ep4_t r, const ep4_t p) {
+/**
+ * Multiplies a point by the cofactor in a KSS16 curve.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ */
+static void ep4_mul_cof_k16(ep4_t r, const ep4_t p) {
+ bn_t x;
+ ep4_t t0, t1, t2, t3, t4, t5;
+
+ ep4_null(t0);
+ ep4_null(t1);
+ ep4_null(t2);
+ ep4_null(t3);
+ ep4_null(t4);
+ ep4_null(t5);
+ bn_null(x);
+
+ RLC_TRY {
+ bn_new(x);
+ ep4_new(t0);
+ ep4_new(t1);
+ ep4_new(t2);
+ ep4_new(t3);
+ ep4_new(t4);
+ ep4_new(t5);
+
+ fp_prime_get_par(x);
+
+ /* [x^3-3*x^2, 3*x^2+11*x, -11*x-7, 2*x^3+14, -2*x^3-4*x^2, 4*x^2-2*x, 2*x+24, x^4+x^3] */
+ ep4_mul_basic(t1, p, x);
+ ep4_mul_basic(t2, t1, x);
+ ep4_mul_basic(t3, t2, x);
+
+ ep4_dbl(t0, t2);
+ ep4_add(t2, t2, t0);
+ ep4_sub(t5, t3, t2);
+
+ ep4_dbl(t0, t0);
+ ep4_dbl(t4, t3);
+ ep4_add(t4, t4, t0);
+ ep4_frb(t4, t4, 4);
+ ep4_sub(t5, t5, t4);
+
+ ep4_sub(t4, t0, t1);
+ ep4_sub(t4, t4, t1);
+ ep4_frb(t4, t4, 5);
+ ep4_add(t5, t5, t4);
+
+ ep4_dbl(t0, t1);
+ ep4_mul_dig(t4, p, 24);
+ ep4_add(t4, t4, t0);
+ ep4_frb(t4, t4, 6);
+ ep4_add(t5, t5, t4);
+
+ ep4_mul_dig(t4, t1, 11);
+ ep4_mul_dig(t0, p, 7);
+ ep4_add(t0, t0, t4);
+ ep4_add(t4, t4, t2);
+ ep4_frb(t4, t4, 1);
+ ep4_add(t5, t5, t4);
+ ep4_frb(t4, t0, 2);
+ ep4_sub(t5, t5, t4);
+
+ ep4_dbl(t0, t3);
+ ep4_mul_dig(t4, p, 14);
+ ep4_add(t4, t4, t0);
+ ep4_frb(t4, t4, 3);
+ ep4_add(t5, t5, t4);
+
+ ep4_mul_basic(t4, t3, x);
+ ep4_add(t4, t4, t3);
+ ep4_frb(t4, t4, 7);
+ ep4_add(t5, t5, t4);
+
+ ep4_norm(r, t5);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep4_free(t0);
+ ep4_free(t1);
+ ep4_free(t2);
+ ep4_free(t3);
+ ep4_free(t4);
+ ep4_free(t5);
+ bn_free(x);
+
+ }
+}
+
+/**
+ * Multiplies a point by the cofactor in a KSS16 curve.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ */
+static void ep4_mul_cof_n16(ep4_t r, const ep4_t p) {
+ bn_t x;
+ ep4_t t0, t1, t2, t3, t4, t5;
+
+ ep4_null(t0);
+ ep4_null(t1);
+ ep4_null(t2);
+ ep4_null(t3);
+ ep4_null(t4);
+ ep4_null(t5);
+ bn_null(x);
+
+ RLC_TRY {
+ bn_new(x);
+ ep4_new(t0);
+ ep4_new(t1);
+ ep4_new(t2);
+ ep4_new(t3);
+ ep4_new(t4);
+ ep4_new(t5);
+
+ fp_prime_get_par(x);
+
+ /* [2*(1+u^3), -u^3*(1+u^3), -2*u, u*(1+u^3), -u^4*(u^3+1), -2*u^2, u^2*(1+u^3), 2] */
+ ep4_mul_basic(t1, p, x);
+ ep4_mul_basic(t2, t1, x);
+ ep4_mul_basic(t3, t2, x);
+
+ ep4_frb(t5, p, 7);
+ ep4_frb(t4, t1, 2);
+ ep4_sub(t5, t5, t4);
+ ep4_frb(t4, t2, 5);
+ ep4_sub(t5, t5, t4);
+ ep4_add(t3, t3, p);
+ ep4_add(t5, t5, t3);
+ ep4_dbl(t5, t5);
+
+ ep4_mul_basic(t0, t3, x);
+ ep4_frb(t4, t0, 3);
+ ep4_add(t5, t5, t4);
+
+ ep4_mul_basic(t0, t0, x);
+ ep4_frb(t4, t0, 6);
+ ep4_add(t5, t5, t4);
+
+ ep4_mul_basic(t0, t0, x);
+ ep4_frb(t4, t0, 1);
+ ep4_sub(t5, t5, t4);
+
+ ep4_mul_basic(t0, t0, x);
+ ep4_frb(t4, t0, 4);
+ ep4_sub(t5, t5, t4);
+
+ ep4_norm(r, t5);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep4_free(t0);
+ ep4_free(t1);
+ ep4_free(t2);
+ ep4_free(t3);
+ ep4_free(t4);
+ ep4_free(t5);
+ bn_free(x);
+
+ }
+}
+
+/**
+ * Multiplies a point by the cofactor in a BLS24 curve.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ */
+void ep4_mul_cof_b24(ep4_t r, const ep4_t p) {
bn_t z;
ep4_t t0, t1, t2, t3;
@@ -57,21 +227,21 @@ void ep4_mul_cof(ep4_t r, const ep4_t p) {
fp_prime_get_par(z);
+ bn_sub_dig(z, z, 1);
ep4_mul_basic(t0, p, z);
+ bn_add_dig(z, z, 1);
ep4_mul_basic(t1, t0, z);
ep4_mul_basic(t2, t1, z);
ep4_mul_basic(t3, t2, z);
- ep4_sub(t3, t3, t2);
- ep4_sub(t3, t3, p);
- ep4_sub(t2, t2, t1);
+ /* Compute t0 = [u - 1]*\psi^3(P). */
+ ep4_frb(t0, t0, 3);
+ /* Compute t2 = [u^2*(u-1)]\psi(P). */
ep4_frb(t2, t2, 1);
-
- ep4_sub(t1, t1, t0);
+ /* Compute t1 = [u*(u-1)]\psi^2(P). */
ep4_frb(t1, t1, 2);
-
- ep4_sub(t0, t0, p);
- ep4_frb(t0, t0, 3);
+ /* Compute t3 = [u^3(u-1) - 1]P. */
+ ep4_sub(t3, t3, p);
ep4_dbl(r, p);
ep4_frb(r, r, 4);
@@ -92,3 +262,40 @@ void ep4_mul_cof(ep4_t r, const ep4_t p) {
}
}
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep4_mul_cof(ep4_t r, const ep4_t p) {
+ bn_t k;
+
+ bn_null(k);
+
+ RLC_TRY {
+ switch (ep_curve_is_pairf()) {
+ case EP_K16:
+ ep4_mul_cof_k16(r, p);
+ break;
+ case EP_N16:
+ ep4_mul_cof_n16(r, p);
+ break;
+ case EP_B24:
+ ep4_mul_cof_b24(r, p);
+ break;
+ default:
+ /* Now, multiply by cofactor to get the correct group. */
+ ep4_curve_get_cof(k);
+ if (bn_bits(k) < RLC_DIG) {
+ ep4_mul_dig(r, p, k->dp[0]);
+ } else {
+ ep4_mul_basic(r, p, k);
+ }
+ break;
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(k);
+ }
+}
diff --git a/src/epx/relic_ep4_mul_fix.c b/src/epx/relic_ep4_mul_fix.c
index 96fe25a3a..33b8dac4c 100644
--- a/src/epx/relic_ep4_mul_fix.c
+++ b/src/epx/relic_ep4_mul_fix.c
@@ -140,21 +140,35 @@ void ep4_mul_pre_basic(ep4_t *t, const ep4_t p) {
}
void ep4_mul_fix_basic(ep4_t r, const ep4_t *t, const bn_t k) {
+ bn_t n, _k;
+
if (bn_is_zero(k)) {
ep4_set_infty(r);
return;
}
- ep4_set_infty(r);
+ bn_null(n);
+ bn_null(_k);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(_k);
- for (int i = 0; i < bn_bits(k); i++) {
- if (bn_get_bit(k, i)) {
- ep4_add(r, r, t[i]);
+ ep4_curve_get_ord(n);
+ bn_mod(_k, k, n);
+
+ ep4_set_infty(r);
+ for (int i = 0; i < bn_bits(_k); i++) {
+ if (bn_get_bit(_k, i)) {
+ ep4_add(r, r, t[i]);
+ }
}
- }
- ep4_norm(r, r);
- if (bn_sign(k) == RLC_NEG) {
- ep4_neg(r, r);
+ ep4_norm(r, r);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(n);
+ bn_free(_k);
}
}
@@ -206,7 +220,7 @@ void ep4_mul_pre_combs(ep4_t *t, const ep4_t p) {
void ep4_mul_fix_combs(ep4_t r, const ep4_t *t, const bn_t k) {
int i, j, l, w, n0, p0, p1;
- bn_t n;
+ bn_t n, _k;
if (bn_is_zero(k)) {
ep4_set_infty(r);
@@ -214,15 +228,18 @@ void ep4_mul_fix_combs(ep4_t r, const ep4_t *t, const bn_t k) {
}
bn_null(n);
+ bn_null(_k);
RLC_TRY {
bn_new(n);
+ bn_new(_k);
ep4_curve_get_ord(n);
l = bn_bits(n);
l = ((l % RLC_DEPTH) == 0 ? (l / RLC_DEPTH) : (l / RLC_DEPTH) + 1);
- n0 = bn_bits(k);
+ bn_mod(_k, k, n);
+ n0 = bn_bits(_k);
p0 = (RLC_DEPTH) * l - 1;
@@ -230,7 +247,7 @@ void ep4_mul_fix_combs(ep4_t r, const ep4_t *t, const bn_t k) {
p1 = p0--;
for (j = RLC_DEPTH - 1; j >= 0; j--, p1 -= l) {
w = w << 1;
- if (p1 < n0 && bn_get_bit(k, p1)) {
+ if (p1 < n0 && bn_get_bit(_k, p1)) {
w = w | 1;
}
}
@@ -243,7 +260,7 @@ void ep4_mul_fix_combs(ep4_t r, const ep4_t *t, const bn_t k) {
p1 = p0--;
for (j = RLC_DEPTH - 1; j >= 0; j--, p1 -= l) {
w = w << 1;
- if (p1 < n0 && bn_get_bit(k, p1)) {
+ if (p1 < n0 && bn_get_bit(_k, p1)) {
w = w | 1;
}
}
@@ -252,15 +269,13 @@ void ep4_mul_fix_combs(ep4_t r, const ep4_t *t, const bn_t k) {
}
}
ep4_norm(r, r);
- if (bn_sign(k) == RLC_NEG) {
- ep4_neg(r, r);
- }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
bn_free(n);
+ bn_free(_k);
}
}
diff --git a/src/epx/relic_ep4_mul_sim.c b/src/epx/relic_ep4_mul_sim.c
index 2d789bf38..719332f38 100644
--- a/src/epx/relic_ep4_mul_sim.c
+++ b/src/epx/relic_ep4_mul_sim.c
@@ -52,7 +52,7 @@
*/
static void ep4_mul_sim_plain(ep4_t r, const ep4_t p, const bn_t k,
const ep4_t q, const bn_t m, ep4_t *t) {
- int i, n0, n1, w, gen;
+ int i, n0, n1, w, gen = (t == NULL ? 0 : 1);
int8_t naf0[2 * RLC_FP_BITS + 1], naf1[2 * RLC_FP_BITS + 1], *_k, *_m;
ep4_t t0[1 << (RLC_WIDTH - 2)];
ep4_t t1[1 << (RLC_WIDTH - 2)];
@@ -240,13 +240,6 @@ void ep4_mul_sim_trick(ep4_t r, const ep4_t p, const bn_t k, const ep4_t q,
bn_rec_win(w0, &l0, k, w);
bn_rec_win(w1, &l1, m, w);
- for (int i = l0; i < l1; i++) {
- w0[i] = 0;
- }
- for (int i = l1; i < l0; i++) {
- w1[i] = 0;
- }
-
ep4_set_infty(r);
for (int i = RLC_MAX(l0, l1) - 1; i >= 0; i--) {
for (int j = 0; j < w; j++) {
@@ -484,14 +477,6 @@ void ep4_mul_sim_lot(ep4_t r, const ep4_t p[], const bn_t k[], size_t n) {
}
}
- for (i = 0; i < n; i++) {
- for (j = 0; j < 8; j++) {
- for (m = _l[8*i + j]; m < l; m++) {
- naf[(8*i + j)*len + m] = 0;
- }
- }
- }
-
ep4_set_infty(r);
for (i = l - 1; i >= 0; i--) {
ep4_dbl(r, r);
diff --git a/src/epx/relic_ep4_norm.c b/src/epx/relic_ep4_norm.c
index ed41baa7f..ca2646dd5 100644
--- a/src/epx/relic_ep4_norm.c
+++ b/src/epx/relic_ep4_norm.c
@@ -36,7 +36,7 @@
/* Private definitions */
/*============================================================================*/
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
/**
* Normalizes a point represented in projective coordinates.
@@ -95,7 +95,7 @@ void ep4_norm(ep4_t r, const ep4_t p) {
/* If the point is represented in affine coordinates, we just copy it. */
ep4_copy(r, p);
}
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
ep4_norm_imp(r, p, 0);
#endif
}
@@ -121,10 +121,11 @@ void ep4_norm_sim(ep4_t *r, const ep4_t *t, int n) {
fp4_copy(r[i]->y, t[i]->y);
fp4_copy(r[i]->z, a[i]);
}
-
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
for (i = 0; i < n; i++) {
ep4_norm_imp(r[i], r[i], 1);
}
+#endif
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
diff --git a/src/epx/relic_ep4_util.c b/src/epx/relic_ep4_util.c
index c358369c9..6b036da4d 100644
--- a/src/epx/relic_ep4_util.c
+++ b/src/epx/relic_ep4_util.c
@@ -238,7 +238,7 @@ int ep4_size_bin(const ep4_t a, int pack) {
ep4_norm(t, a);
size = 1 + 8 * RLC_FP_BYTES;
- //TODO: Implement compression.
+ //TODO: implement compression properly
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
diff --git a/src/epx/relic_ep8_add.c b/src/epx/relic_ep8_add.c
new file mode 100644
index 000000000..1141da873
--- /dev/null
+++ b/src/epx/relic_ep8_add.c
@@ -0,0 +1,434 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of addition on prime elliptic curves over quartic
+ * extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+/**
+ * Adds two points represented in affine coordinates on an ordinary prime
+ * elliptic curve.
+ *
+ * @param r - the result.
+ * @param s - the resulting slope.
+ * @param p - the first point to add.
+ * @param q - the second point to add.
+ */
+static void ep8_add_basic_imp(ep8_t r, fp8_t s, const ep8_t p, const ep8_t q) {
+ fp8_t t0, t1, t2;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t2);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t2);
+
+ /* t0 = x2 - x1. */
+ fp8_sub(t0, q->x, p->x);
+ /* t1 = y2 - y1. */
+ fp8_sub(t1, q->y, p->y);
+
+ /* If t0 is zero. */
+ if (fp8_is_zero(t0)) {
+ if (fp8_is_zero(t1)) {
+ /* If t1 is zero, q = p, should have doubled. */
+ ep8_dbl_slp_basic(r, s, p);
+ } else {
+ /* If t1 is not zero and t0 is zero, q = -p and r = infty. */
+ ep8_set_infty(r);
+ }
+ } else {
+ /* t2 = 1/(x2 - x1). */
+ fp8_inv(t2, t0);
+ /* t2 = lambda = (y2 - y1)/(x2 - x1). */
+ fp8_mul(t2, t1, t2);
+
+ /* x3 = lambda^2 - x2 - x1. */
+ fp8_sqr(t1, t2);
+ fp8_sub(t0, t1, p->x);
+ fp8_sub(t0, t0, q->x);
+
+ /* y3 = lambda * (x1 - x3) - y1. */
+ fp8_sub(t1, p->x, t0);
+ fp8_mul(t1, t2, t1);
+ fp8_sub(r->y, t1, p->y);
+
+ fp8_copy(r->x, t0);
+ fp8_copy(r->z, p->z);
+
+ if (s != NULL) {
+ fp8_copy(s, t2);
+ }
+
+ r->coord = BASIC;
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t2);
+ }
+}
+
+#endif /* EP_ADD == BASIC */
+
+#if EP_ADD == PROJC || !defined(STRIP)
+
+#if defined(EP_MIXED) || !defined(STRIP)
+
+/**
+ * Adds a point represented in affine coordinates to a point represented in
+ * projective coordinates.
+ *
+ * @param r - the result.
+ * @param s - the slope.
+ * @param p - the affine point.
+ * @param q - the projective point.
+ */
+static void ep8_add_projc_mix(ep8_t r, const ep8_t p, const ep8_t q) {
+ fp8_t t0, t1, t2, t3, t4, t5, t6;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t2);
+ fp8_null(t3);
+ fp8_null(t4);
+ fp8_null(t5);
+ fp8_null(t6);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t2);
+ fp8_new(t3);
+ fp8_new(t4);
+ fp8_new(t5);
+ fp8_new(t6);
+
+ if (p->coord != BASIC) {
+ /* t0 = z1^2. */
+ fp8_sqr(t0, p->z);
+
+ /* t3 = U2 = x2 * z1^2. */
+ fp8_mul(t3, q->x, t0);
+
+ /* t1 = S2 = y2 * z1^3. */
+ fp8_mul(t1, t0, p->z);
+ fp8_mul(t1, t1, q->y);
+
+ /* t3 = H = U2 - x1. */
+ fp8_sub(t3, t3, p->x);
+
+ /* t1 = R = 2 * (S2 - y1). */
+ fp8_sub(t1, t1, p->y);
+ } else {
+ /* H = x2 - x1. */
+ fp8_sub(t3, q->x, p->x);
+
+ /* t1 = R = 2 * (y2 - y1). */
+ fp8_sub(t1, q->y, p->y);
+ }
+
+ /* t2 = HH = H^2. */
+ fp8_sqr(t2, t3);
+
+ /* If E is zero. */
+ if (fp8_is_zero(t3)) {
+ if (fp8_is_zero(t1)) {
+ /* If I is zero, p = q, should have doubled. */
+ ep8_dbl_projc(r, p);
+ } else {
+ /* If I is not zero, q = -p, r = infinity. */
+ ep8_set_infty(r);
+ }
+ } else {
+ /* t5 = J = H * HH. */
+ fp8_mul(t5, t3, t2);
+
+ /* t4 = V = x1 * HH. */
+ fp8_mul(t4, p->x, t2);
+
+ /* x3 = R^2 - J - 2 * V. */
+ fp8_sqr(r->x, t1);
+ fp8_sub(r->x, r->x, t5);
+ fp8_dbl(t6, t4);
+ fp8_sub(r->x, r->x, t6);
+
+ /* y3 = R * (V - x3) - Y1 * J. */
+ fp8_sub(t4, t4, r->x);
+ fp8_mul(t4, t4, t1);
+ fp8_mul(t1, p->y, t5);
+ fp8_sub(r->y, t4, t1);
+
+ if (p->coord != BASIC) {
+ /* z3 = z1 * H. */
+ fp8_mul(r->z, p->z, t3);
+ } else {
+ /* z3 = H. */
+ fp8_copy(r->z, t3);
+ }
+ }
+ r->coord = PROJC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t2);
+ fp8_free(t3);
+ fp8_free(t4);
+ fp8_free(t5);
+ fp8_free(t6);
+ }
+}
+
+#endif
+
+/**
+ * Adds two points represented in projective coordinates on an ordinary prime
+ * elliptic curve.
+ *
+ * @param r - the result.
+ * @param p - the first point to add.
+ * @param q - the second point to add.
+ */
+static void ep8_add_projc_imp(ep8_t r, const ep8_t p, const ep8_t q) {
+#if defined(EP_MIXED) && defined(STRIP)
+ ep8_add_projc_mix(r, p, q);
+#else /* General addition. */
+ fp8_t t0, t1, t2, t3, t4, t5, t6;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t2);
+ fp8_null(t3);
+ fp8_null(t4);
+ fp8_null(t5);
+ fp8_null(t6);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t2);
+ fp8_new(t3);
+ fp8_new(t4);
+ fp8_new(t5);
+ fp8_new(t6);
+
+ if (q->coord == BASIC) {
+ ep8_add_projc_mix(r, p, q);
+ } else {
+ /* t0 = z1^2. */
+ fp8_sqr(t0, p->z);
+
+ /* t1 = z2^2. */
+ fp8_sqr(t1, q->z);
+
+ /* t2 = U1 = x1 * z2^2. */
+ fp8_mul(t2, p->x, t1);
+
+ /* t3 = U2 = x2 * z1^2. */
+ fp8_mul(t3, q->x, t0);
+
+ /* t6 = z1^2 + z2^2. */
+ fp8_add(t6, t0, t1);
+
+ /* t0 = S2 = y2 * z1^3. */
+ fp8_mul(t0, t0, p->z);
+ fp8_mul(t0, t0, q->y);
+
+ /* t1 = S1 = y1 * z2^3. */
+ fp8_mul(t1, t1, q->z);
+ fp8_mul(t1, t1, p->y);
+
+ /* t3 = H = U2 - U1. */
+ fp8_sub(t3, t3, t2);
+
+ /* t0 = R = 2 * (S2 - S1). */
+ fp8_sub(t0, t0, t1);
+
+ fp8_dbl(t0, t0);
+
+ /* If E is zero. */
+ if (fp8_is_zero(t3)) {
+ if (fp8_is_zero(t0)) {
+ /* If I is zero, p = q, should have doubled. */
+ ep8_dbl_projc(r, p);
+ } else {
+ /* If I is not zero, q = -p, r = infinity. */
+ ep8_set_infty(r);
+ }
+ } else {
+ /* t4 = I = (2*H)^2. */
+ fp8_dbl(t4, t3);
+ fp8_sqr(t4, t4);
+
+ /* t5 = J = H * I. */
+ fp8_mul(t5, t3, t4);
+
+ /* t4 = V = U1 * I. */
+ fp8_mul(t4, t2, t4);
+
+ /* x3 = R^2 - J - 2 * V. */
+ fp8_sqr(r->x, t0);
+ fp8_sub(r->x, r->x, t5);
+ fp8_dbl(t2, t4);
+ fp8_sub(r->x, r->x, t2);
+
+ /* y3 = R * (V - x3) - 2 * S1 * J. */
+ fp8_sub(t4, t4, r->x);
+ fp8_mul(t4, t4, t0);
+ fp8_mul(t1, t1, t5);
+ fp8_dbl(t1, t1);
+ fp8_sub(r->y, t4, t1);
+
+ /* z3 = ((z1 + z2)^2 - z1^2 - z2^2) * H. */
+ fp8_add(r->z, p->z, q->z);
+ fp8_sqr(r->z, r->z);
+ fp8_sub(r->z, r->z, t6);
+ fp8_mul(r->z, r->z, t3);
+ }
+ }
+ r->coord = PROJC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t2);
+ fp8_free(t3);
+ fp8_free(t4);
+ fp8_free(t5);
+ fp8_free(t6);
+ }
+#endif
+}
+
+#endif /* EP_ADD == PROJC */
+
+/*============================================================================*/
+ /* Public definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+void ep8_add_basic(ep8_t r, const ep8_t p, const ep8_t q) {
+ if (ep8_is_infty(p)) {
+ ep8_copy(r, q);
+ return;
+ }
+
+ if (ep8_is_infty(q)) {
+ ep8_copy(r, p);
+ return;
+ }
+
+ ep8_add_basic_imp(r, NULL, p, q);
+}
+
+void ep8_add_slp_basic(ep8_t r, fp8_t s, const ep8_t p, const ep8_t q) {
+ if (ep8_is_infty(p)) {
+ ep8_copy(r, q);
+ return;
+ }
+
+ if (ep8_is_infty(q)) {
+ ep8_copy(r, p);
+ return;
+ }
+
+ ep8_add_basic_imp(r, s, p, q);
+}
+
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+
+void ep8_add_projc(ep8_t r, const ep8_t p, const ep8_t q) {
+ if (ep8_is_infty(p)) {
+ ep8_copy(r, q);
+ return;
+ }
+
+ if (ep8_is_infty(q)) {
+ ep8_copy(r, p);
+ return;
+ }
+
+ if (p == q) {
+ /* TODO: This is a quick hack. Should we fix this? */
+ ep8_dbl(r, p);
+ return;
+ }
+
+ ep8_add_projc_imp(r, p, q);
+}
+
+#endif
+
+void ep8_sub(ep8_t r, const ep8_t p, const ep8_t q) {
+ ep8_t t;
+
+ ep8_null(t);
+
+ if (p == q) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ RLC_TRY {
+ ep8_new(t);
+
+ ep8_neg(t, q);
+ ep8_add(r, p, t);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(t);
+ }
+}
diff --git a/src/epx/relic_ep8_cmp.c b/src/epx/relic_ep8_cmp.c
new file mode 100644
index 000000000..cf00e38a6
--- /dev/null
+++ b/src/epx/relic_ep8_cmp.c
@@ -0,0 +1,82 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of utilities for prime elliptic curves over quadratic
+ * extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+int ep8_cmp(const ep8_t p, const ep8_t q) {
+ ep8_t r, s;
+ int result = RLC_NE;
+
+ if (ep8_is_infty(p) && ep8_is_infty(q)) {
+ return RLC_EQ;
+ }
+
+ ep8_null(r);
+ ep8_null(s);
+
+ RLC_TRY {
+ ep8_new(r);
+ ep8_new(s);
+
+ if ((p->coord != BASIC) && (q->coord != BASIC)) {
+ /* If the two points are not normalized, it is faster to compare
+ * x1 * z2^2 == x2 * z1^2 and y1 * z2^3 == y2 * z1^3. */
+ fp8_sqr(r->z, p->z);
+ fp8_sqr(s->z, q->z);
+ fp8_mul(r->x, p->x, s->z);
+ fp8_mul(s->x, q->x, r->z);
+ fp8_mul(r->z, r->z, p->z);
+ fp8_mul(s->z, s->z, q->z);
+ fp8_mul(r->y, p->y, s->z);
+ fp8_mul(s->y, q->y, r->z);
+ } else {
+ ep8_norm(r, p);
+ ep8_norm(s, q);
+ }
+
+ if ((fp8_cmp(r->x, s->x) == RLC_EQ) &&
+ (fp8_cmp(r->y, s->y) == RLC_EQ)) {
+ result = RLC_EQ;
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep8_free(r);
+ ep8_free(s);
+ }
+
+ return result;
+}
diff --git a/src/epx/relic_ep8_curve.c b/src/epx/relic_ep8_curve.c
new file mode 100644
index 000000000..a76921115
--- /dev/null
+++ b/src/epx/relic_ep8_curve.c
@@ -0,0 +1,364 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of configuration of prime elliptic curves over octic
+ * extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+/* See ep/relic_ep_param.c for discussion of MAP_U parameters. */
+
+#if defined(EP_ENDOM) && FP_PRIME == 575
+/** @{ */
+#define B48_P575_B0 "0"
+#define B48_P575_B1 "0"
+#define B48_P575_B2 "0"
+#define B48_P575_B3 "0"
+#define B48_P575_B4 "4"
+#define B48_P575_B5 "0"
+#define B48_P575_B6 "0"
+#define B48_P575_B7 "0"
+#define B48_P575_X0 "266A6ACAA4B8DDCFBF97F09DFBEB01999BFBFF872276FA7700114F761E8971C6C25A53CC77E96BCC9579F63D8A39D641B8070B07EF40E93C301A5B49CE87110CC30E044BEE5A2D43"
+#define B48_P575_X1 "5009EEB2A67C52B79D0727B408A193FFCE76B4F80C8DCF4D61ECEE5471601CD7A94341F697CE9D375DB5470EA055B73C256CCC0AC12F52EAD276C26E001DDCE02DE634BEFCB9CC7C"
+#define B48_P575_X2 "11A8DDB59724C01696BE52862B5AC2C7E1C0C42EFCAF456A80F6C6D9F95F89649D5575DE3BA8D28D1012E14308DE1D8F15CE1617611F961032B0B5DFA27EF3E3670B9B537ACC66B9"
+#define B48_P575_X3 "4E8BDED03587581A173AD008DFF600EB24054E4CDDCA8D7BFABA2898822DB5ED701BF59BD3F108AD7C714B6A6C7ECB11A1BC5DEEC1D49AE7FCA597C43943A66441B03164975D9BE0"
+#define B48_P575_X4 "29E2751CAC7D0FBA8E12CC818BDE6F2A7173D3C2ED74EC1991B936071DEB1AED1E07CDF71EA3501BEB4645C86BDC8A575898303FF6A058C7062F079F594E5B865626D0C031CF7E44"
+#define B48_P575_X5 "2F3A1BE54DFFB814DA4AE6311B9B1EEE6198CDB9F36CE92084272416462F4D0AC9ACAC025FDA6D3D0D1C239FE8CE4B7F22A1D0F65582DDA36EEB328843FDE5C0BDA02E871796CC8E"
+#define B48_P575_X6 "2FEE7B15EB22B05476A462374860140DCC9F00910E0555918D6357F6E32E623B88B893647AD07B615F364093D6F6D2A7B7614590A8833385B5A833563C0DD6C89AF89D06428E8AFE"
+#define B48_P575_X7 "005082322BB5E610DC0E61E3D01B8BFF23D195117F58B1FA68EC04A6769FEB754A58742C7F729E2A684386C40EFB871CB3D32A040966155649DC45C49E6FB5DEE58DB1586CBFD33E"
+#define B48_P575_Y0 "3B603A4C408A402FB885B607C4A661BF92354D22F46945F222C6F51CCDEBF4006640346AE6BFD60F7E22240D4BF83EFDA1B575267A89597D7BC54FA4899BFBAAC4138E30C8DA55C0"
+#define B48_P575_Y1 "35D3ECCC1F3C69A921E57CCDEA6C794A5ED01A53E19208854EA3B10D519CCCE64A30007CD7A57673567F2FFA070E5CE01C4E5C8BF1C61225DAC36A93C6524F4D0350C6358C67F85B"
+#define B48_P575_Y2 "4228DA69A29E14E2CF00EC8FDD877CA9049DA161778A6ACE8DC275D4CE94C90AD9176280703AD9C6714A4865EF6160ED2FA7A5FC601025CF096AB6CF21B8FAA41421C7913DECF3B5"
+#define B48_P575_Y3 "5273C1679E18D316C6988820E06335094FCCCD5E8FD870492EB96FCBC5B5494B2B9D0869C18309FF2D49CD80CF6E6FE1A660027A6E924831F8D5A070645A7B794BA7AE72507809AE"
+#define B48_P575_Y4 "0ABD2F582F0D4C3C89770C13F02FF17CDEA5B22CDD661B6F82905ADCDC44E59900C5D09F8CAC90760CCC57D1987DE4BA21F34455E5B7394B68A7883E3F8D918AF308F0C3E6F98F4B"
+#define B48_P575_Y5 "36FAE1DE9DD31FFE238526F618C14E5CB61EEA8E8E6D82235E43E45E306C5E60B4E5499BF4663516CE1202EF6CDE3B2E098E406B3186937483FC104A173707C6419F460A23ADF628"
+#define B48_P575_Y6 "09E1BB455FCB47E98C5263B5098E2D148EC2EDEE5634B8F94F10AF9221D09BD60D28920342C11B1987A24B7F56AC4F5E290E7EA483727ED16FFC88C0F5EAD00892FDA66BA68FACE4"
+#define B48_P575_Y7 "4F781C32F5CAFD446F299BE6BC600BF3482DF6ECAF4ABE3D410A7255B18A88DB77CC539CAC4A0D30A00690CCA8CC7661BCE042D0AC40FF8DC9171847A8E42696E4EF9DD8A5907A3D"
+#define B48_P575_R "FFBFC68EB6176EFB58025E547BF4EBACB1315C184DC37EAAF67BBCCE069D07F425050E765ABB8B40D5E6D7AE8A2A5698B771DDBD6E109D56D59C3DFF00000001"
+#define B48_P575_H "9E9223EB731FB087A7A45CA84E1C06F79C4326124DE74264AA1FCFB1FB41AFF2CBA999F970BD426881824E1A7562ED4F1E249817937F029045954EED2EB984ED650EF97D1189758800D5926B4CA05A197A0B8D1FD9697173D9B8389AAA1B76E1AF1AAC3B9999905ADD15F51DB643E2B16361CD2E54E7B18B29AB0A08ECF2818F8EAB997AC33C00D0901C913B44817E1E3F5B89E3CA71C8A59556AF31D4998B77BE410ADC0C19CAE9A82DEAC267087E382A39F4ADC7043BD46F38D00454D2A8D7EFA4109F3AE1157580E650F5614A3BB05A8DDFEB789CEEE1F91A31CFA50BB5E689A006B43B4D4364E3001144F12DA0A5F388DE9A09B24A00CE5D91E42C0BFDA4BBE3A59C60439B347B5A727EE436069DBF413F6190F212C5BE3F02F9381AB92830E65AA13C3D583D63C077777F32BFC912726FC49B5082059BFDC912C81C4259542DA560430230B4D0E905E3ADAA2AF0E0BEB18C5B6BC52A452BE1E70CCAC2A23F954EA5548B11FE3FD7C02940A6DA75340BB3459CCC74EA778E3B3B239FB5D1B815B929BAF390372BB0043C3A920B878F4AC32243ED6E2A7F79D85A5D66C9ED8D08A20E5EC0E9145561868EB5987EF043EF9A1176149B3618D96F9F179519B89027A2648576E807E1A4B1C8E9F5C0A147D2750E65DF130DF53D7AAD8D4EA7D0CEB1C03BAF8A0C7BE62F433C5747E851661399976495246EAF448690CD4B1"
+/** @} */
+#endif
+
+/**
+ * Assigns a set of ordinary elliptic curve parameters.
+ *
+ * @param[in] CURVE - the curve parameters to assign.
+ */
+#define ASSIGN(CURVE) \
+ RLC_GET(str, CURVE##_B0, sizeof(CURVE##_B0)); \
+ fp_read_str(b[0][0][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_B1, sizeof(CURVE##_B1)); \
+ fp_read_str(b[0][0][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_B2, sizeof(CURVE##_B2)); \
+ fp_read_str(b[0][1][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_B3, sizeof(CURVE##_B3)); \
+ fp_read_str(b[0][1][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_B4, sizeof(CURVE##_B4)); \
+ fp_read_str(b[1][0][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_B5, sizeof(CURVE##_B5)); \
+ fp_read_str(b[1][0][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_B6, sizeof(CURVE##_B6)); \
+ fp_read_str(b[1][1][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_B7, sizeof(CURVE##_B7)); \
+ fp_read_str(b[1][1][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X0, sizeof(CURVE##_X0)); \
+ fp_read_str(g->x[0][0][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X1, sizeof(CURVE##_X1)); \
+ fp_read_str(g->x[0][0][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X2, sizeof(CURVE##_X2)); \
+ fp_read_str(g->x[0][1][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X3, sizeof(CURVE##_X3)); \
+ fp_read_str(g->x[0][1][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X4, sizeof(CURVE##_X4)); \
+ fp_read_str(g->x[1][0][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X5, sizeof(CURVE##_X5)); \
+ fp_read_str(g->x[1][0][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X6, sizeof(CURVE##_X6)); \
+ fp_read_str(g->x[1][1][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_X7, sizeof(CURVE##_X7)); \
+ fp_read_str(g->x[1][1][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y0, sizeof(CURVE##_Y0)); \
+ fp_read_str(g->y[0][0][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y1, sizeof(CURVE##_Y1)); \
+ fp_read_str(g->y[0][0][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y2, sizeof(CURVE##_Y2)); \
+ fp_read_str(g->y[0][1][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y3, sizeof(CURVE##_Y3)); \
+ fp_read_str(g->y[0][1][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y4, sizeof(CURVE##_Y4)); \
+ fp_read_str(g->y[1][0][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y5, sizeof(CURVE##_Y5)); \
+ fp_read_str(g->y[1][0][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y6, sizeof(CURVE##_Y6)); \
+ fp_read_str(g->y[1][1][0], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_Y7, sizeof(CURVE##_Y7)); \
+ fp_read_str(g->y[1][1][1], str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_R, sizeof(CURVE##_R)); \
+ bn_read_str(r, str, strlen(str), 16); \
+ RLC_GET(str, CURVE##_H, sizeof(CURVE##_H)); \
+ bn_read_str(h, str, strlen(str), 16); \
+
+/**
+ * Detects an optimization based on the curve coefficients.
+ */
+static void detect_opt(int *opt, fp8_t a) {
+ fp8_t t;
+ fp8_null(t);
+
+ RLC_TRY {
+ fp8_new(t);
+ fp8_set_dig(t, 3);
+ fp8_neg(t, t);
+
+ if (fp8_cmp(a, t) == RLC_EQ) {
+ *opt = RLC_MIN3;
+ } else if (fp8_is_zero(a)) {
+ *opt = RLC_ZERO;
+ } else if (fp8_cmp_dig(a, 1) == RLC_EQ) {
+ *opt = RLC_ONE;
+ } else if (fp8_cmp_dig(a, 2) == RLC_EQ) {
+ *opt = RLC_TWO;
+ } else if ((fp_bits(a[0][0][0]) <= RLC_DIG) && fp_is_zero(a[0][0][1]) &&
+ fp2_is_zero(a[0][1]) && fp4_is_zero(a[1])) {
+ *opt = RLC_TINY;
+ } else {
+ *opt = RLC_HUGE;
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp8_free(t);
+ }
+}
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep8_curve_init(void) {
+ ctx_t *ctx = core_get();
+
+#ifdef EP_PRECO
+ for (int i = 0; i < RLC_EP_TABLE; i++) {
+ ctx->ep8_ptr[i] = &(ctx->ep8_pre[i]);
+ }
+#endif
+
+#if ALLOC == DYNAMIC
+ ep8_new(ctx->ep8_g);
+ fp8_new(ctx->ep8_a);
+ fp8_new(ctx->ep8_b);
+#endif
+
+#ifdef EP_PRECO
+#if ALLOC == DYNAMIC
+ for (int i = 0; i < RLC_EP_TABLE; i++) {
+ fp8_new(ctx->ep8_pre[i].x);
+ fp8_new(ctx->ep8_pre[i].y);
+ fp8_new(ctx->ep8_pre[i].z);
+ }
+#endif
+#endif
+ ep8_set_infty(ctx->ep8_g);
+ bn_make(&(ctx->ep8_r), RLC_FP_DIGS);
+ bn_make(&(ctx->ep8_h), RLC_FP_DIGS);
+}
+
+void ep8_curve_clean(void) {
+ ctx_t *ctx = core_get();
+ if (ctx != NULL) {
+#ifdef EP_PRECO
+ for (int i = 0; i < RLC_EP_TABLE; i++) {
+ fp8_free(ctx->ep8_pre[i].x);
+ fp8_free(ctx->ep8_pre[i].y);
+ fp8_free(ctx->ep8_pre[i].z);
+ }
+#endif
+ bn_clean(&(ctx->ep8_r));
+ bn_clean(&(ctx->ep8_h));
+ ep8_free(ctx->ep8_g);
+ fp8_free(ctx->ep8_a);
+ fp8_free(ctx->ep8_b);
+ }
+}
+
+int ep8_curve_opt_a(void) {
+ return core_get()->ep8_opt_a;
+}
+
+int ep8_curve_opt_b(void) {
+ return core_get()->ep8_opt_b;
+}
+
+int ep8_curve_is_twist(void) {
+ return core_get()->ep8_is_twist;
+}
+
+void ep8_curve_get_gen(ep8_t g) {
+ ep8_copy(g, core_get()->ep8_g);
+}
+
+void ep8_curve_get_a(fp8_t a) {
+ fp8_copy(a, core_get()->ep8_a);
+}
+
+void ep8_curve_get_b(fp8_t b) {
+ fp8_copy(b, core_get()->ep8_b);
+}
+
+void ep8_curve_get_ord(bn_t n) {
+ ctx_t *ctx = core_get();
+ if (ctx->ep8_is_twist) {
+ ep_curve_get_ord(n);
+ } else {
+ bn_copy(n, &(ctx->ep8_r));
+ }
+}
+
+void ep8_curve_get_cof(bn_t h) {
+ bn_copy(h, &(core_get()->ep8_h));
+}
+
+#if defined(EP_PRECO)
+
+ep8_t *ep8_curve_get_tab(void) {
+#if ALLOC == AUTO
+ return (ep8_t *)*(core_get()->ep8_ptr);
+#else
+ return core_get()->ep8_ptr;
+#endif
+}
+
+#endif
+
+void ep8_curve_set_twist(int type) {
+ char str[16 * RLC_FP_BYTES + 1];
+ ctx_t *ctx = core_get();
+ ep8_t g;
+ fp8_t a, b;
+ bn_t r, h;
+
+ ep8_null(g);
+ fp8_null(a);
+ fp8_null(b);
+ bn_null(r);
+ bn_null(h);
+
+ ctx->ep8_is_twist = 0;
+ if (type == RLC_EP_MTYPE || type == RLC_EP_DTYPE) {
+ ctx->ep8_is_twist = type;
+ } else {
+ return;
+ }
+
+ RLC_TRY {
+ ep8_new(g);
+ fp8_new(a);
+ fp8_new(b);
+ bn_new(r);
+ bn_new(h);
+
+ switch (ep_param_get()) {
+#if FP_PRIME == 575
+ case B48_P575:
+ fp8_zero(a);
+ ASSIGN(B48_P575);
+ break;
+#endif
+ default:
+ (void)str;
+ RLC_THROW(ERR_NO_VALID);
+ break;
+ }
+
+ fp8_zero(g->z);
+ fp8_set_dig(g->z, 1);
+ g->coord = BASIC;
+
+ ep8_copy(ctx->ep8_g, g);
+ fp8_copy(ctx->ep8_a, a);
+ fp8_copy(ctx->ep8_b, b);
+
+ detect_opt(&(ctx->ep8_opt_a), ctx->ep8_a);
+ detect_opt(&(ctx->ep8_opt_b), ctx->ep8_b);
+
+ bn_copy(&(ctx->ep8_r), r);
+ bn_copy(&(ctx->ep8_h), h);
+
+ if (type == RLC_EP_MTYPE) {
+ fp8_zero(a);
+ fp_copy(a[1][1][0], ctx->fp8_p1[0]);
+ fp_copy(a[1][1][1], ctx->fp8_p1[1]);
+ fp8_inv(a, a);
+ fp_copy(ctx->fp8_p1[0], a[1][0][0]);
+ fp_copy(ctx->fp8_p1[1], a[1][0][1]);
+ }
+
+#if defined(WITH_PC)
+ /* Compute pairing generator. */
+ pc_core_calc();
+#endif
+
+#if defined(EP_PRECO)
+ ep8_mul_pre((ep8_t *)ep8_curve_get_tab(), ctx->ep8_g);
+#endif
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(g);
+ fp8_free(a);
+ fp8_free(b);
+ bn_free(r);
+ bn_free(h);
+ }
+}
+
+void ep8_curve_set(const fp8_t a, const fp8_t b, const ep8_t g, const bn_t r, const bn_t h) {
+ ctx_t *ctx = core_get();
+ ctx->ep8_is_twist = 0;
+
+ fp8_copy(ctx->ep8_a, a);
+ fp8_copy(ctx->ep8_b, b);
+
+ ep8_norm(ctx->ep8_g, g);
+ bn_copy(&(ctx->ep8_r), r);
+ bn_copy(&(ctx->ep8_h), h);
+
+#if defined(EP_PRECO)
+ ep8_mul_pre((ep8_t *)ep8_curve_get_tab(), ctx->ep8_g);
+#endif
+}
diff --git a/src/epx/relic_ep8_dbl.c b/src/epx/relic_ep8_dbl.c
new file mode 100644
index 000000000..2fa1449e1
--- /dev/null
+++ b/src/epx/relic_ep8_dbl.c
@@ -0,0 +1,276 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of doubling on elliptic prime curves over quartic
+ * extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+/**
+ * Doubles a point represented in affine coordinates on an ordinary prime
+ * elliptic curve.
+ *
+ * @param[out] r - the result.
+ * @param[out] s - the resulting slope.
+ * @param[in] p - the point to double.
+ */
+static void ep8_dbl_basic_imp(ep8_t r, fp8_t s, const ep8_t p) {
+ fp8_t t0, t1, t2;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t2);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t2);
+
+ /* t0 = 1/(2 * y1). */
+ fp8_dbl(t0, p->y);
+ fp8_inv(t0, t0);
+
+ /* t1 = 3 * x1^2 + a. */
+ fp8_sqr(t1, p->x);
+ fp8_copy(t2, t1);
+ fp8_dbl(t1, t1);
+ fp8_add(t1, t1, t2);
+
+ ep8_curve_get_a(t2);
+ fp8_add(t1, t1, t2);
+
+ /* t1 = (3 * x1^2 + a)/(2 * y1). */
+ fp8_mul(t1, t1, t0);
+
+ if (s != NULL) {
+ fp8_copy(s, t1);
+ }
+
+ /* t2 = t1^2. */
+ fp8_sqr(t2, t1);
+
+ /* x3 = t1^2 - 2 * x1. */
+ fp8_dbl(t0, p->x);
+ fp8_sub(t0, t2, t0);
+
+ /* y3 = t1 * (x1 - x3) - y1. */
+ fp8_sub(t2, p->x, t0);
+ fp8_mul(t1, t1, t2);
+
+ fp8_sub(r->y, t1, p->y);
+
+ fp8_copy(r->x, t0);
+ fp8_copy(r->z, p->z);
+
+ r->coord = BASIC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t2);
+ }
+}
+
+#endif /* EP_ADD == BASIC */
+
+#if EP_ADD == PROJC || !defined(STRIP)
+
+/**
+ * Doubles a point represented in affine coordinates on an ordinary prime
+ * elliptic curve.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to double.
+ */
+static void ep8_dbl_projc_imp(ep8_t r, const ep8_t p) {
+ fp8_t t0, t1, t2, t3, t4, t5;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t2);
+ fp8_null(t3);
+ fp8_null(t4);
+ fp8_null(t5);
+
+ RLC_TRY {
+ if (ep_curve_opt_a() == RLC_ZERO) {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t2);
+ fp8_new(t3);
+ fp8_new(t4);
+ fp8_new(t5);
+
+ fp8_sqr(t0, p->x);
+ fp8_add(t2, t0, t0);
+ fp8_add(t0, t2, t0);
+
+ fp8_sqr(t3, p->y);
+ fp8_mul(t1, t3, p->x);
+ fp8_add(t1, t1, t1);
+ fp8_add(t1, t1, t1);
+ fp8_sqr(r->x, t0);
+ fp8_add(t2, t1, t1);
+ fp8_sub(r->x, r->x, t2);
+ fp8_mul(r->z, p->z, p->y);
+ fp8_add(r->z, r->z, r->z);
+ fp8_add(t3, t3, t3);
+
+ fp8_sqr(t3, t3);
+ fp8_add(t3, t3, t3);
+ fp8_sub(t1, t1, r->x);
+ fp8_mul(r->y, t0, t1);
+ fp8_sub(r->y, r->y, t3);
+ } else {
+ /* dbl-2007-bl formulas: 1M + 8S + 1*a + 10add + 1*8 + 2*2 + 1*3 */
+ /* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl */
+
+ /* t0 = x1^2, t1 = y1^2, t2 = y1^4. */
+ fp8_sqr(t0, p->x);
+ fp8_sqr(t1, p->y);
+ fp8_sqr(t2, t1);
+
+ if (p->coord != BASIC) {
+ /* t3 = z1^2. */
+ fp8_sqr(t3, p->z);
+
+ if (ep_curve_get_a() == RLC_ZERO) {
+ /* z3 = 2 * y1 * z1. */
+ fp8_mul(r->z, p->y, p->z);
+ fp8_dbl(r->z, r->z);
+ } else {
+ /* z3 = (y1 + z1)^2 - y1^2 - z1^2. */
+ fp8_add(r->z, p->y, p->z);
+ fp8_sqr(r->z, r->z);
+ fp8_sub(r->z, r->z, t1);
+ fp8_sub(r->z, r->z, t3);
+ }
+ } else {
+ /* z3 = 2 * y1. */
+ fp8_dbl(r->z, p->y);
+ }
+
+ /* t4 = S = 2*((x1 + y1^2)^2 - x1^2 - y1^4). */
+ fp8_add(t4, p->x, t1);
+ fp8_sqr(t4, t4);
+ fp8_sub(t4, t4, t0);
+ fp8_sub(t4, t4, t2);
+ fp8_dbl(t4, t4);
+
+ /* t5 = M = 3 * x1^2 + a * z1^4. */
+ fp8_dbl(t5, t0);
+ fp8_add(t5, t5, t0);
+ if (p->coord != BASIC) {
+ fp8_sqr(t3, t3);
+ ep8_curve_get_a(t1);
+ fp8_mul(t1, t3, t1);
+ fp8_add(t5, t5, t1);
+ } else {
+ ep8_curve_get_a(t1);
+ fp8_add(t5, t5, t1);
+ }
+
+ /* x3 = T = M^2 - 2 * S. */
+ fp8_sqr(r->x, t5);
+ fp8_dbl(t1, t4);
+ fp8_sub(r->x, r->x, t1);
+
+ /* y3 = M * (S - T) - 8 * y1^4. */
+ fp8_dbl(t2, t2);
+ fp8_dbl(t2, t2);
+ fp8_dbl(t2, t2);
+ fp8_sub(t4, t4, r->x);
+ fp8_mul(t5, t5, t4);
+ fp8_sub(r->y, t5, t2);
+ }
+
+ r->coord = PROJC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t2);
+ fp8_free(t3);
+ fp8_free(t4);
+ fp8_free(t5);
+ }
+}
+
+#endif /* EP_ADD == PROJC */
+
+/*============================================================================*/
+ /* Public definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+void ep8_dbl_basic(ep8_t r, const ep8_t p) {
+ if (ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ ep8_dbl_basic_imp(r, NULL, p);
+}
+
+void ep8_dbl_slp_basic(ep8_t r, fp8_t s, const ep8_t p) {
+ if (ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ ep8_dbl_basic_imp(r, s, p);
+}
+
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+
+void ep8_dbl_projc(ep8_t r, const ep8_t p) {
+ if (ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ ep8_dbl_projc_imp(r, p);
+}
+
+#endif
diff --git a/src/epx/relic_ep8_frb.c b/src/epx/relic_ep8_frb.c
new file mode 100644
index 000000000..1cd8c4f72
--- /dev/null
+++ b/src/epx/relic_ep8_frb.c
@@ -0,0 +1,48 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of frobenius action on prime elliptic curves over
+ * quartic extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep8_frb(ep8_t r, const ep8_t p, int i) {
+ ep8_copy(r, p);
+ for (; i > 0; i--) {
+ fp8_frb(r->x, r->x, 1);
+ fp8_frb(r->y, r->y, 1);
+ fp8_frb(r->z, r->z, 1);
+ fp8_mul_frb(r->x, r->x, 1, 2);
+ fp8_mul_frb(r->y, r->y, 1, 3);
+ }
+}
diff --git a/src/epx/relic_ep8_map.c b/src/epx/relic_ep8_map.c
new file mode 100644
index 000000000..898d45ea5
--- /dev/null
+++ b/src/epx/relic_ep8_map.c
@@ -0,0 +1,205 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of hashing to a prime elliptic curve over a quadratic
+ * extension.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+#include "relic_md.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep8_map(ep8_t p, const uint8_t *msg, size_t len) {
+ /* enough space for two field elements plus extra bytes for uniformity */
+ const size_t elm = (FP_PRIME + ep_param_level() + 7) / 8;
+ uint8_t t0z, t0, t1, s[2][2], sign, *r = RLC_ALLOCA(uint8_t, 16 * elm + 1);
+ fp8_t t, u, v, w, y, x1, y1, z1;
+ ctx_t *ctx = core_get();
+ dig_t c2, c3;
+ bn_t k;
+
+ bn_null(k);
+ fp8_null(t);
+ fp8_null(u);
+ fp8_null(v);
+ fp8_null(w);
+ fp8_null(y);
+ fp8_null(x1);
+ fp8_null(y1);
+ fp8_null(z1);
+
+ RLC_TRY {
+ bn_new(k);
+ fp8_new(t);
+ fp8_new(u);
+ fp8_new(v);
+ fp8_new(w);
+ fp8_new(y);
+ fp8_new(x1);
+ fp8_new(y1);
+ fp8_new(z1);
+
+ md_xmd(r, 16 * elm + 1, msg, len, (const uint8_t *)"RELIC", 5);
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int l = 0; l < 2; l++) {
+ bn_read_bin(k, r, elm);
+ fp_prime_conv(u[i][j][l], k);
+ r += elm;
+ bn_read_bin(k, r, elm);
+ fp_prime_conv(t[i][j][l], k);
+ r += elm;
+ }
+ }
+ }
+ sign = r[0] & 1;
+
+ /* Assume that a = 0. */
+ fp8_sqr(x1, u);
+ fp8_mul(x1, x1, u);
+ fp8_sqr(y1, t);
+ fp8_add(x1, x1, ctx->ep8_b);
+ fp8_sub(x1, x1, y1);
+ fp8_dbl(y1, y1);
+ fp8_add(y1, y1, x1);
+ fp8_copy(z1, u);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int l = 0; l < 2; l++) {
+ fp_mul(z1[i][j][l], z1[i][j][l], ctx->ep_map_c[4]);
+ }
+ }
+ }
+
+ fp8_mul(x1, x1, z1);
+ fp8_mul(z1, z1, t);
+ fp8_dbl(z1, z1);
+
+ fp8_dbl(y, y1);
+ fp8_sqr(y, y);
+ fp8_mul(v, y1, u);
+ fp8_sub(v, x1, v);
+ fp8_mul(v, v, z1);
+ fp8_mul(w, y1, z1);
+ fp8_dbl(w, w);
+
+ if (fp8_is_zero(w)) {
+ ep8_set_infty(p);
+ } else {
+ fp8_inv(w, w);
+ fp8_mul(x1, v, w);
+ fp8_add(y1, u, x1);
+ fp8_neg(y1, y1);
+ fp8_mul(z1, y, w);
+ fp8_sqr(z1, z1);
+ fp8_add(z1, z1, u);
+
+ ep8_curve_get_b(w);
+
+ fp8_sqr(t, x1);
+ fp8_mul(t, t, x1);
+ fp8_add(t, t, w);
+
+ fp8_sqr(u, y1);
+ fp8_mul(u, u, y1);
+ fp8_add(u, u, w);
+
+ fp8_sqr(v, z1);
+ fp8_mul(v, v, z1);
+ fp8_add(v, v, w);
+
+ c2 = fp8_is_sqr(u);
+ c3 = fp8_is_sqr(v);
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int l = 0; l < 2; l++) {
+ dv_swap_cond(x1[i][j][l], y1[i][j][l], RLC_FP_DIGS, c2);
+ dv_swap_cond(t[i][j][l], u[i][j][l], RLC_FP_DIGS, c2);
+ dv_swap_cond(x1[i][j][l], z1[i][j][l], RLC_FP_DIGS, c3);
+ dv_swap_cond(t[i][j][l], v[i][j][l], RLC_FP_DIGS, c3);
+ }
+ }
+ }
+
+ if (!fp8_srt(t, t)) {
+ RLC_THROW(ERR_NO_VALID);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ t0z = fp_is_zero(t[i][j][0]);
+ fp_prime_back(k, t[i][j][0]);
+ t0 = bn_get_bit(k, 0);
+ fp_prime_back(k, t[i][j][1]);
+ t1 = bn_get_bit(k, 0);
+ /* t[0] == 0 ? sgn0(t[1]) : sgn0(t[0]) */
+ s[i][j] = t0 | (t0z & t1);
+ }
+
+ t0z = fp4_is_zero(t[i]);
+ sign ^= (s[i][0] | (t0z & s[i][1]));
+ }
+
+ fp8_neg(u, t);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int l = 0; l < 2; l++) {
+ dv_swap_cond(t[i][j][l], u[i][j][l], RLC_FP_DIGS, sign);
+ }
+ }
+ }
+
+ fp8_copy(p->x, x1);
+ fp8_copy(p->y, t);
+ fp8_set_dig(p->z, 1);
+ p->coord = BASIC;
+
+ ep8_mul_cof(p, p);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(k);
+ fp8_free(t);
+ fp8_free(u);
+ fp8_free(v);
+ fp8_free(w);
+ fp8_free(y);
+ fp8_free(x1);
+ fp8_free(y1);
+ fp8_free(z1);
+ RLC_FREE(r);
+ }
+}
diff --git a/src/epx/relic_ep8_mul.c b/src/epx/relic_ep8_mul.c
new file mode 100644
index 000000000..14e02fe74
--- /dev/null
+++ b/src/epx/relic_ep8_mul.c
@@ -0,0 +1,454 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of point multiplication on prime elliptic curves over
+ * quadratic extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if EP_MUL == LWNAF || !defined(STRIP)
+
+#if defined(EP_ENDOM)
+
+static void ep8_mul_glv_imp(ep8_t r, const ep8_t p, const bn_t k) {
+ size_t l, _l[16];
+ bn_t n, _k[16], u;
+ int8_t naf[16][RLC_FP_BITS + 1];
+ ep8_t q[16];
+
+ bn_null(n);
+ bn_null(u);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(u);
+ for (int i = 0; i < 16; i++) {
+ bn_null(_k[i]);
+ ep8_null(q[i]);
+ bn_new(_k[i]);
+ ep8_new(q[i]);
+ }
+
+ ep8_curve_get_ord(n);
+ fp_prime_get_par(u);
+ bn_mod(_k[0], k, n);
+ bn_rec_frb(_k, 16, _k[0], u, n, ep_curve_is_pairf() == EP_BN);
+
+ ep8_norm(q[0], p);
+ for (size_t i = 1; i < 16; i++) {
+ ep8_frb(q[i], q[i - 1], 1);
+ }
+
+ l = 0;
+ for (size_t i = 0; i < 16; i++) {
+ if (bn_sign(_k[i]) == RLC_NEG) {
+ ep8_neg(q[i], q[i]);
+ }
+ _l[i] = RLC_FP_BITS + 1;
+ bn_rec_naf(naf[i], &_l[i], _k[i], 2);
+ l = RLC_MAX(l, _l[i]);
+ }
+
+ ep8_set_infty(r);
+ for (int j = l - 1; j >= 0; j--) {
+ ep8_dbl(r, r);
+
+ for (int i = 0; i < 16; i++) {
+ if (naf[i][j] > 0) {
+ ep8_add(r, r, q[i]);
+ }
+ if (naf[i][j] < 0) {
+ ep8_sub(r, r, q[i]);
+ }
+ }
+ }
+
+ /* Convert r to affine coordinates. */
+ ep8_norm(r, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ bn_free(u);
+ for (int i = 0; i < 16; i++) {
+ bn_free(_k[i]);
+ ep8_free(q[i]);
+ }
+
+ }
+}
+
+#endif /* EP_ENDOM */
+
+static void ep8_mul_naf_imp(ep8_t r, const ep8_t p, const bn_t k) {
+ int i, n;
+ int8_t naf[RLC_FP_BITS + 1];
+ ep8_t t[1 << (RLC_WIDTH - 2)];
+ size_t l;
+
+ RLC_TRY {
+ /* Prepare the precomputation table. */
+ for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ ep8_null(t[i]);
+ ep8_new(t[i]);
+ }
+ /* Compute the precomputation table. */
+ ep8_tab(t, p, RLC_WIDTH);
+
+ /* Compute the w-NAF representation of k. */
+ l = sizeof(naf);
+ bn_rec_naf(naf, &l, k, RLC_WIDTH);
+
+ ep8_set_infty(r);
+ for (i = l - 1; i >= 0; i--) {
+ ep8_dbl(r, r);
+
+ n = naf[i];
+ if (n > 0) {
+ ep8_add(r, r, t[n / 2]);
+ }
+ if (n < 0) {
+ ep8_sub(r, r, t[-n / 2]);
+ }
+ }
+ /* Convert r to affine coordinates. */
+ ep8_norm(r, r);
+ if (bn_sign(k) == RLC_NEG) {
+ ep8_neg(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ /* Free the precomputation table. */
+ for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ ep8_free(t[i]);
+ }
+ }
+}
+
+#endif /* EP_MUL == LWNAF */
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep8_mul_basic(ep8_t r, const ep8_t p, const bn_t k) {
+ ep8_t t;
+ int8_t u, *naf = RLC_ALLOCA(int8_t, bn_bits(k) + 1);
+ size_t l;
+
+ ep8_null(t);
+
+ if (bn_is_zero(k) || ep8_is_infty(p)) {
+ RLC_FREE(naf);
+ ep8_set_infty(r);
+ return;
+ }
+
+ RLC_TRY {
+ ep8_new(t);
+ if (naf == NULL) {
+ RLC_THROW(ERR_NO_BUFFER);
+ }
+
+ l = bn_bits(k) + 1;
+ bn_rec_naf(naf, &l, k, 2);
+ ep8_set_infty(t);
+ for (int i = l - 1; i >= 0; i--) {
+ ep8_dbl(t, t);
+
+ u = naf[i];
+ if (u > 0) {
+ ep8_add(t, t, p);
+ } else if (u < 0) {
+ ep8_sub(t, t, p);
+ }
+ }
+
+ ep8_norm(r, t);
+ if (bn_sign(k) == RLC_NEG) {
+ ep8_neg(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(t);
+ RLC_FREE(naf);
+ }
+}
+
+#if EP_MUL == SLIDE || !defined(STRIP)
+
+void ep8_mul_slide(ep8_t r, const ep8_t p, const bn_t k) {
+ ep8_t t[1 << (RLC_WIDTH - 1)], q;
+ uint8_t win[RLC_FP_BITS + 1];
+ size_t l;
+
+ ep8_null(q);
+
+ if (bn_is_zero(k) || ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ RLC_TRY {
+ for (size_t i = 0; i < (1 << (RLC_WIDTH - 1)); i ++) {
+ ep8_null(t[i]);
+ ep8_new(t[i]);
+ }
+
+ ep8_new(q);
+
+ ep8_copy(t[0], p);
+ ep8_dbl(q, p);
+
+#if defined(EP_MIXED)
+ ep8_norm(q, q);
+#endif
+
+ /* Create table. */
+ for (size_t i = 1; i < (1 << (RLC_WIDTH - 1)); i++) {
+ ep8_add(t[i], t[i - 1], q);
+ }
+
+#if defined(EP_MIXED)
+ ep8_norm_sim(t + 1, t + 1, (1 << (RLC_WIDTH - 1)) - 1);
+#endif
+
+ ep8_set_infty(q);
+ l = RLC_FP_BITS + 1;
+ bn_rec_slw(win, &l, k, RLC_WIDTH);
+ for (size_t i = 0; i < l; i++) {
+ if (win[i] == 0) {
+ ep8_dbl(q, q);
+ } else {
+ for (size_t j = 0; j < util_bits_dig(win[i]); j++) {
+ ep8_dbl(q, q);
+ }
+ ep8_add(q, q, t[win[i] >> 1]);
+ }
+ }
+
+ ep8_norm(r, q);
+ if (bn_sign(k) == RLC_NEG) {
+ ep8_neg(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ for (size_t i = 0; i < (1 << (RLC_WIDTH - 1)); i++) {
+ ep8_free(t[i]);
+ }
+ ep8_free(q);
+ }
+}
+
+#endif
+
+#if EP_MUL == MONTY || !defined(STRIP)
+
+void ep8_mul_monty(ep8_t r, const ep8_t p, const bn_t k) {
+ ep8_t t[2];
+ bn_t n, l, _k;
+ size_t bits;
+
+ bn_null(n);
+ bn_null(l);
+ bn_null(_k);
+ ep8_null(t[0]);
+ ep8_null(t[1]);
+
+ if (bn_is_zero(k) || ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(l);
+ bn_new(_k);
+ ep8_new(t[0]);
+ ep8_new(t[1]);
+
+ ep8_curve_get_ord(n);
+ bits = bn_bits(n);
+
+ bn_mod(_k, k, n);
+ bn_abs(l, _k);
+ bn_add(l, l, n);
+ bn_add(n, l, n);
+ dv_swap_cond(l->dp, n->dp, RLC_MAX(l->used, n->used),
+ bn_get_bit(l, bits) == 0);
+ l->used = RLC_SEL(l->used, n->used, bn_get_bit(l, bits) == 0);
+
+ ep8_norm(t[0], p);
+ ep8_dbl(t[1], t[0]);
+
+ /* Blind both points independently. */
+ ep8_blind(t[0], t[0]);
+ ep8_blind(t[1], t[1]);
+
+ for (int i = bits - 1; i >= 0; i--) {
+ int j = bn_get_bit(l, i);
+ for (int l = 0; l < 2; l++) {
+ for (int m = 0; m < 2; m++) {
+ for (int n = 0; n < 2; n++) {
+ dv_swap_cond(t[0]->x[l][m][n], t[1]->x[l][m][n], RLC_FP_DIGS, j ^ 1);
+ dv_swap_cond(t[0]->y[l][m][n], t[1]->y[l][m][n], RLC_FP_DIGS, j ^ 1);
+ dv_swap_cond(t[0]->z[l][m][n], t[1]->z[l][m][n], RLC_FP_DIGS, j ^ 1);
+ }
+ }
+ }
+ ep8_add(t[0], t[0], t[1]);
+ ep8_dbl(t[1], t[1]);
+ for (int l = 0; l < 2; l++) {
+ for (int m = 0; m < 2; m++) {
+ for (int n = 0; n < 2; n++) {
+ dv_swap_cond(t[0]->x[l][m][n], t[1]->x[l][m][n], RLC_FP_DIGS, j ^ 1);
+ dv_swap_cond(t[0]->y[l][m][n], t[1]->y[l][m][n], RLC_FP_DIGS, j ^ 1);
+ dv_swap_cond(t[0]->z[l][m][n], t[1]->z[l][m][n], RLC_FP_DIGS, j ^ 1);
+ }
+ }
+ }
+ }
+
+ ep8_norm(r, t[0]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ bn_free(l);
+ bn_free(_k);
+ ep8_free(t[1]);
+ ep8_free(t[0]);
+ }
+}
+
+#endif
+
+#if EP_MUL == LWNAF || !defined(STRIP)
+
+void ep8_mul_lwnaf(ep8_t r, const ep8_t p, const bn_t k) {
+ if (bn_is_zero(k) || ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+#if defined(EP_ENDOM)
+ if (ep_curve_is_endom()) {
+ if (ep_curve_opt_a() == RLC_ZERO) {
+ ep8_mul_glv_imp(r, p, k);
+ } else {
+ ep8_mul_naf_imp(r, p, k);
+ }
+ return;
+ }
+#endif
+
+#if defined(EP_PLAIN) || defined(EP_SUPER)
+ ep8_mul_naf_imp(r, p, k);
+#endif
+}
+
+#endif
+
+void ep8_mul_gen(ep8_t r, const bn_t k) {
+ if (bn_is_zero(k)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+#ifdef EP_PRECO
+ ep8_mul_fix(r, ep8_curve_get_tab(), k);
+#else
+ ep8_t g;
+
+ ep8_null(g);
+
+ RLC_TRY {
+ ep8_new(g);
+ ep8_curve_get_gen(g);
+ ep8_mul(r, g, k);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(g);
+ }
+#endif
+}
+
+void ep8_mul_dig(ep8_t r, const ep8_t p, const dig_t k) {
+ int i, l;
+ ep8_t t;
+
+ ep8_null(t);
+
+ if (k == 0 || ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ RLC_TRY {
+ ep8_new(t);
+
+ l = util_bits_dig(k);
+
+ ep8_copy(t, p);
+
+ for (i = l - 2; i >= 0; i--) {
+ ep8_dbl(t, t);
+ if (k & ((dig_t)1 << i)) {
+ ep8_add(t, t, p);
+ }
+ }
+
+ ep8_norm(r, t);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(t);
+ }
+}
diff --git a/src/epx/relic_ep8_mul_cof.c b/src/epx/relic_ep8_mul_cof.c
new file mode 100644
index 000000000..65f85a660
--- /dev/null
+++ b/src/epx/relic_ep8_mul_cof.c
@@ -0,0 +1,122 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of point multiplication of a prime elliptic curve over an
+ * octic extension by the curve cofactor.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+#include "relic_md.h"
+#include "relic_tmpl_map.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep8_mul_cof(ep8_t r, const ep8_t p) {
+ bn_t z;
+ ep8_t t0, t1, t2, t3, t4, t5, t6, t7;
+
+ ep8_null(t0);
+ ep8_null(t1);
+ ep8_null(t2);
+ ep8_null(t3);
+ ep8_null(t4);
+ ep8_null(t5);
+ ep8_null(t6);
+ ep8_null(t7);
+ bn_null(z);
+
+ RLC_TRY {
+ bn_new(z);
+ ep8_new(t0);
+ ep8_new(t1);
+ ep8_new(t2);
+ ep8_new(t3);
+
+ fp_prime_get_par(z);
+
+ ep8_mul_basic(t0, p, z);
+ ep8_mul_basic(t1, t0, z);
+ ep8_mul_basic(t2, t1, z);
+ ep8_mul_basic(t3, t2, z);
+ ep8_mul_basic(t4, t3, z);
+ ep8_mul_basic(t5, t4, z);
+ ep8_mul_basic(t6, t5, z);
+ ep8_mul_basic(t7, t6, z);
+
+ ep8_sub(t7, t7, t6);
+ ep8_sub(t7, t7, p);
+
+ ep8_sub(t6, t6, t5);
+ ep8_frb(t6, t6, 1);
+
+ ep8_sub(t5, t5, t4);
+ ep8_frb(t5, t5, 2);
+
+ ep8_sub(t4, t4, t3);
+ ep8_frb(t4, t4, 3);
+
+ ep8_sub(t3, t3, t2);
+ ep8_frb(t3, t3, 4);
+
+ ep8_sub(t2, t2, t1);
+ ep8_frb(t2, t2, 5);
+
+ ep8_sub(t1, t1, t0);
+ ep8_frb(t1, t1, 6);
+
+ ep8_sub(t0, t0, p);
+ ep8_frb(t0, t0, 7);
+
+ ep8_dbl(r, p);
+ ep8_frb(r, r, 8);
+ ep8_add(r, r, t0);
+ ep8_add(r, r, t1);
+ ep8_add(r, r, t2);
+ ep8_add(r, r, t3);
+ ep8_add(r, r, t4);
+ ep8_add(r, r, t5);
+ ep8_add(r, r, t6);
+ ep8_add(r, r, t7);
+
+ ep8_norm(r, r);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep8_free(t0);
+ ep8_free(t1);
+ ep8_free(t2);
+ ep8_free(t3);
+ ep8_free(t4);
+ ep8_free(t5);
+ ep8_free(t6);
+ ep8_free(t7);
+ bn_free(z);
+ }
+}
diff --git a/src/epx/relic_ep8_mul_fix.c b/src/epx/relic_ep8_mul_fix.c
new file mode 100644
index 000000000..94e80748e
--- /dev/null
+++ b/src/epx/relic_ep8_mul_fix.c
@@ -0,0 +1,407 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of fixed point multiplication on a prime elliptic curve over
+ * a quartic extension.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if EP_FIX == LWNAF || !defined(STRIP)
+
+/**
+ * Precomputes a table for a point multiplication on an ordinary curve.
+ *
+ * @param[out] t - the destination table.
+ * @param[in] p - the point to multiply.
+ */
+static void ep8_mul_pre_ordin(ep8_t *t, const ep8_t p) {
+ ep8_dbl(t[0], p);
+#if defined(EP_MIXED)
+ ep8_norm(t[0], t[0]);
+#endif
+
+#if RLC_DEPTH > 2
+ ep8_add(t[1], t[0], p);
+ for (int i = 2; i < (1 << (RLC_DEPTH - 2)); i++) {
+ ep8_add(t[i], t[i - 1], t[0]);
+ }
+
+#if defined(EP_MIXED)
+ for (int i = 1; i < (1 << (RLC_DEPTH - 2)); i++) {
+ ep8_norm(t[i], t[i]);
+ }
+#endif
+
+#endif
+ ep8_copy(t[0], p);
+}
+
+/**
+ * Multiplies a binary elliptic curve point by an integer using the w-NAF
+ * method.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the point to multiply.
+ * @param[in] k - the integer.
+ */
+static void ep8_mul_fix_ordin(ep8_t r, const ep8_t *table, const bn_t k) {
+ int8_t naf[2 * RLC_FP_BITS + 1], *t;
+ size_t len;
+ int n;
+
+ if (bn_is_zero(k)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ /* Compute the w-TNAF representation of k. */
+ len = 2 * RLC_FP_BITS + 1;
+ bn_rec_naf(naf, &len, k, RLC_DEPTH);
+
+ t = naf + len - 1;
+ ep8_set_infty(r);
+ for (int i = len - 1; i >= 0; i--, t--) {
+ ep8_dbl(r, r);
+
+ n = *t;
+ if (n > 0) {
+ ep8_add(r, r, table[n / 2]);
+ }
+ if (n < 0) {
+ ep8_sub(r, r, table[-n / 2]);
+ }
+ }
+ /* Convert r to affine coordinates. */
+ ep8_norm(r, r);
+ if (bn_sign(k) == RLC_NEG) {
+ ep8_neg(r, r);
+ }
+}
+
+#endif /* EP_FIX == LWNAF */
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_FIX == BASIC || !defined(STRIP)
+
+void ep8_mul_pre_basic(ep8_t *t, const ep8_t p) {
+ bn_t n;
+
+ bn_null(n);
+
+ RLC_TRY {
+ bn_new(n);
+
+ ep8_curve_get_ord(n);
+
+ ep8_copy(t[0], p);
+ for (int i = 1; i < bn_bits(n); i++) {
+ ep8_dbl(t[i], t[i - 1]);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ }
+}
+
+void ep8_mul_fix_basic(ep8_t r, const ep8_t *t, const bn_t k) {
+ bn_t n, _k;
+
+ if (bn_is_zero(k)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ bn_null(n);
+ bn_null(_k);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(_k);
+
+ ep8_curve_get_ord(n);
+ bn_mod(_k, k, n);
+
+ ep8_set_infty(r);
+ for (int i = 0; i < bn_bits(_k); i++) {
+ if (bn_get_bit(_k, i)) {
+ ep8_add(r, r, t[i]);
+ }
+ }
+ ep8_norm(r, r);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(n);
+ bn_free(_k);
+ }
+}
+
+#endif
+
+#if EP_FIX == COMBS || !defined(STRIP)
+
+void ep8_mul_pre_combs(ep8_t *t, const ep8_t p) {
+ int i, j, l;
+ bn_t n;
+
+ bn_null(n);
+
+ RLC_TRY {
+ bn_new(n);
+
+ ep8_curve_get_ord(n);
+ l = bn_bits(n);
+ l = ((l % RLC_DEPTH) == 0 ? (l / RLC_DEPTH) : (l / RLC_DEPTH) + 1);
+
+ ep8_set_infty(t[0]);
+
+ ep8_copy(t[1], p);
+ for (j = 1; j < RLC_DEPTH; j++) {
+ ep8_dbl(t[1 << j], t[1 << (j - 1)]);
+ for (i = 1; i < l; i++) {
+ ep8_dbl(t[1 << j], t[1 << j]);
+ }
+#if defined(EP_MIXED)
+ ep8_norm(t[1 << j], t[1 << j]);
+#endif
+ for (i = 1; i < (1 << j); i++) {
+ ep8_add(t[(1 << j) + i], t[i], t[1 << j]);
+ }
+ }
+#if defined(EP_MIXED)
+ for (i = 1; i < RLC_EP_TABLE_COMBS; i++) {
+ ep8_norm(t[i], t[i]);
+ }
+#endif
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ }
+}
+
+void ep8_mul_fix_combs(ep8_t r, const ep8_t *t, const bn_t k) {
+ int i, j, l, w, n0, p0, p1;
+ bn_t n, _k;
+
+ if (bn_is_zero(k)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ bn_null(n);
+ bn_null(_k);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(_k);
+
+ ep8_curve_get_ord(n);
+ l = bn_bits(n);
+ l = ((l % RLC_DEPTH) == 0 ? (l / RLC_DEPTH) : (l / RLC_DEPTH) + 1);
+
+ bn_mod(_k, k, n);
+ n0 = bn_bits(_k);
+
+ p0 = (RLC_DEPTH) * l - 1;
+
+ w = 0;
+ p1 = p0--;
+ for (j = RLC_DEPTH - 1; j >= 0; j--, p1 -= l) {
+ w = w << 1;
+ if (p1 < n0 && bn_get_bit(_k, p1)) {
+ w = w | 1;
+ }
+ }
+ ep8_copy(r, t[w]);
+
+ for (i = l - 2; i >= 0; i--) {
+ ep8_dbl(r, r);
+
+ w = 0;
+ p1 = p0--;
+ for (j = RLC_DEPTH - 1; j >= 0; j--, p1 -= l) {
+ w = w << 1;
+ if (p1 < n0 && bn_get_bit(_k, p1)) {
+ w = w | 1;
+ }
+ }
+ if (w > 0) {
+ ep8_add(r, r, t[w]);
+ }
+ }
+ ep8_norm(r, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ bn_free(_k);
+ }
+}
+
+#endif
+
+#if EP_FIX == COMBD || !defined(STRIP)
+
+void ep8_mul_pre_combd(ep8_t *t, const ep8_t p) {
+ int i, j, d, e;
+ bn_t n;
+
+ bn_null(n);
+
+ RLC_TRY {
+ bn_new(n);
+
+ ep8_curve_get_ord(n);
+ d = bn_bits(n);
+ d = ((d % RLC_DEPTH) == 0 ? (d / RLC_DEPTH) : (d / RLC_DEPTH) + 1);
+ e = (d % 2 == 0 ? (d / 2) : (d / 2) + 1);
+
+ ep8_set_infty(t[0]);
+ ep8_copy(t[1], p);
+ for (j = 1; j < RLC_DEPTH; j++) {
+ ep8_dbl(t[1 << j], t[1 << (j - 1)]);
+ for (i = 1; i < d; i++) {
+ ep8_dbl(t[1 << j], t[1 << j]);
+ }
+#if defined(EP_MIXED)
+ ep8_norm(t[1 << j], t[1 << j]);
+#endif
+ for (i = 1; i < (1 << j); i++) {
+ ep8_add(t[(1 << j) + i], t[i], t[1 << j]);
+ }
+ }
+ ep8_set_infty(t[1 << RLC_DEPTH]);
+ for (j = 1; j < (1 << RLC_DEPTH); j++) {
+ ep8_dbl(t[(1 << RLC_DEPTH) + j], t[j]);
+ for (i = 1; i < e; i++) {
+ ep8_dbl(t[(1 << RLC_DEPTH) + j], t[(1 << RLC_DEPTH) + j]);
+ }
+ }
+#if defined(EP_MIXED)
+ for (i = 1; i < RLC_EP_TABLE_COMBD; i++) {
+ ep8_norm(t[i], t[i]);
+ }
+#endif
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ }
+}
+
+void ep8_mul_fix_combd(ep8_t r, const ep8_t *t, const bn_t k) {
+ int i, j, d, e, w0, w1, n0, p0, p1;
+ bn_t n;
+
+ if (bn_is_zero(k)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ bn_null(n);
+
+ RLC_TRY {
+ bn_new(n);
+
+ ep8_curve_get_ord(n);
+ d = bn_bits(n);
+ d = ((d % RLC_DEPTH) == 0 ? (d / RLC_DEPTH) : (d / RLC_DEPTH) + 1);
+ e = (d % 2 == 0 ? (d / 2) : (d / 2) + 1);
+
+ ep8_set_infty(r);
+ n0 = bn_bits(k);
+
+ p1 = (e - 1) + (RLC_DEPTH - 1) * d;
+ for (i = e - 1; i >= 0; i--) {
+ ep8_dbl(r, r);
+
+ w0 = 0;
+ p0 = p1;
+ for (j = RLC_DEPTH - 1; j >= 0; j--, p0 -= d) {
+ w0 = w0 << 1;
+ if (p0 < n0 && bn_get_bit(k, p0)) {
+ w0 = w0 | 1;
+ }
+ }
+
+ w1 = 0;
+ p0 = p1-- + e;
+ for (j = RLC_DEPTH - 1; j >= 0; j--, p0 -= d) {
+ w1 = w1 << 1;
+ if (i + e < d && p0 < n0 && bn_get_bit(k, p0)) {
+ w1 = w1 | 1;
+ }
+ }
+
+ ep8_add(r, r, t[w0]);
+ ep8_add(r, r, t[(1 << RLC_DEPTH) + w1]);
+ }
+ ep8_norm(r, r);
+ if (bn_sign(k) == RLC_NEG) {
+ ep8_neg(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ }
+}
+
+#endif
+
+#if EP_FIX == LWNAF || !defined(STRIP)
+
+void ep8_mul_pre_lwnaf(ep8_t *t, const ep8_t p) {
+ ep8_mul_pre_ordin(t, p);
+}
+
+void ep8_mul_fix_lwnaf(ep8_t r, const ep8_t *t, const bn_t k) {
+ ep8_mul_fix_ordin(r, t, k);
+}
+
+#endif
diff --git a/src/epx/relic_ep8_mul_sim.c b/src/epx/relic_ep8_mul_sim.c
new file mode 100644
index 000000000..db08c8cbc
--- /dev/null
+++ b/src/epx/relic_ep8_mul_sim.c
@@ -0,0 +1,619 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of simultaneous point multiplication on a prime elliptic
+ * curve over a quartic extension.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if EP_SIM == INTER || !defined(STRIP)
+
+/**
+ * Multiplies and adds two prime elliptic curve points simultaneously,
+ * optionally choosing the first point as the generator depending on an optional
+ * table of precomputed points.
+ *
+ * @param[out] r - the result.
+ * @param[in] p - the first point to multiply.
+ * @param[in] k - the first integer.
+ * @param[in] q - the second point to multiply.
+ * @param[in] m - the second integer.
+ * @param[in] t - the pointer to the precomputed table.
+ */
+static void ep8_mul_sim_plain(ep8_t r, const ep8_t p, const bn_t k,
+ const ep8_t q, const bn_t m, ep8_t *t) {
+ int i, n0, n1, w, gen = (t == NULL ? 0 : 1);
+ int8_t naf0[2 * RLC_FP_BITS + 1], naf1[2 * RLC_FP_BITS + 1], *_k, *_m;
+ ep8_t t0[1 << (RLC_WIDTH - 2)];
+ ep8_t t1[1 << (RLC_WIDTH - 2)];
+ size_t l, l0, l1;
+
+ RLC_TRY {
+ if (!gen) {
+ for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ ep8_null(t0[i]);
+ ep8_new(t0[i]);
+ }
+ ep8_tab(t0, p, RLC_WIDTH);
+ t = (ep8_t *)t0;
+ }
+
+ /* Prepare the precomputation table. */
+ for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ ep8_null(t1[i]);
+ ep8_new(t1[i]);
+ }
+ /* Compute the precomputation table. */
+ ep8_tab(t1, q, RLC_WIDTH);
+
+ /* Compute the w-TNAF representation of k. */
+ if (gen) {
+ w = RLC_DEPTH;
+ } else {
+ w = RLC_WIDTH;
+ }
+ l0 = l1 = 2 * RLC_FP_BITS + 1;
+ bn_rec_naf(naf0, &l0, k, w);
+ bn_rec_naf(naf1, &l1, m, RLC_WIDTH);
+
+ l = RLC_MAX(l0, l1);
+ _k = naf0 + l - 1;
+ _m = naf1 + l - 1;
+ if (bn_sign(k) == RLC_NEG) {
+ for (i = 0; i < l0; i++) {
+ naf0[i] = -naf0[i];
+ }
+ }
+ if (bn_sign(m) == RLC_NEG) {
+ for (i = 0; i < l1; i++) {
+ naf1[i] = -naf1[i];
+ }
+ }
+
+ ep8_set_infty(r);
+ for (i = l - 1; i >= 0; i--, _k--, _m--) {
+ ep8_dbl(r, r);
+
+ n0 = *_k;
+ n1 = *_m;
+ if (n0 > 0) {
+ ep8_add(r, r, t[n0 / 2]);
+ }
+ if (n0 < 0) {
+ ep8_sub(r, r, t[-n0 / 2]);
+ }
+ if (n1 > 0) {
+ ep8_add(r, r, t1[n1 / 2]);
+ }
+ if (n1 < 0) {
+ ep8_sub(r, r, t1[-n1 / 2]);
+ }
+ }
+ /* Convert r to affine coordinates. */
+ ep8_norm(r, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ /* Free the precomputation tables. */
+ if (!gen) {
+ for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ ep8_free(t0[i]);
+ }
+ }
+ for (i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ ep8_free(t1[i]);
+ }
+ }
+}
+
+#endif /* EP_SIM == INTER */
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_SIM == BASIC || !defined(STRIP)
+
+void ep8_mul_sim_basic(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q,
+ const bn_t l) {
+ ep8_t t;
+
+ ep8_null(t);
+
+ RLC_TRY {
+ ep8_new(t);
+ ep8_mul(t, q, l);
+ ep8_mul(r, p, k);
+ ep8_add(t, t, r);
+ ep8_norm(r, t);
+
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(t);
+ }
+}
+
+#endif
+
+#if EP_SIM == TRICK || !defined(STRIP)
+
+void ep8_mul_sim_trick(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q,
+ const bn_t m) {
+ ep8_t t0[1 << (RLC_WIDTH / 2)];
+ ep8_t t1[1 << (RLC_WIDTH / 2)];
+ ep8_t t[1 << RLC_WIDTH];
+ bn_t n;
+ size_t l0, l1, w = RLC_WIDTH / 2;
+ uint8_t w0[2 * RLC_FP_BITS], w1[2 * RLC_FP_BITS];
+
+ bn_null(n);
+
+ if (bn_is_zero(k) || ep8_is_infty(p)) {
+ ep8_mul(r, q, m);
+ return;
+ }
+ if (bn_is_zero(m) || ep8_is_infty(q)) {
+ ep8_mul(r, p, k);
+ return;
+ }
+
+ RLC_TRY {
+ bn_new(n);
+
+ ep8_curve_get_ord(n);
+
+ for (int i = 0; i < (1 << w); i++) {
+ ep8_null(t0[i]);
+ ep8_null(t1[i]);
+ ep8_new(t0[i]);
+ ep8_new(t1[i]);
+ }
+ for (int i = 0; i < (1 << RLC_WIDTH); i++) {
+ ep8_null(t[i]);
+ ep8_new(t[i]);
+ }
+
+ ep8_set_infty(t0[0]);
+ ep8_copy(t0[1], p);
+ if (bn_sign(k) == RLC_NEG) {
+ ep8_neg(t0[1], t0[1]);
+ }
+ for (int i = 2; i < (1 << w); i++) {
+ ep8_add(t0[i], t0[i - 1], t0[1]);
+ }
+
+ ep8_set_infty(t1[0]);
+ ep8_copy(t1[1], q);
+ if (bn_sign(m) == RLC_NEG) {
+ ep8_neg(t1[1], t1[1]);
+ }
+ for (int i = 1; i < (1 << w); i++) {
+ ep8_add(t1[i], t1[i - 1], t1[1]);
+ }
+
+ for (int i = 0; i < (1 << w); i++) {
+ for (int j = 0; j < (1 << w); j++) {
+ ep8_add(t[(i << w) + j], t0[i], t1[j]);
+ }
+ }
+
+#if defined(EP_MIXED)
+ ep8_norm_sim(t + 1, t + 1, (1 << (RLC_WIDTH)) - 1);
+#endif
+
+ l0 = l1 = RLC_CEIL(2 * RLC_FP_BITS, w);
+ bn_rec_win(w0, &l0, k, w);
+ bn_rec_win(w1, &l1, m, w);
+
+ ep8_set_infty(r);
+ for (int i = RLC_MAX(l0, l1) - 1; i >= 0; i--) {
+ for (int j = 0; j < w; j++) {
+ ep8_dbl(r, r);
+ }
+ ep8_add(r, r, t[(w0[i] << w) + w1[i]]);
+ }
+ ep8_norm(r, r);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ for (int i = 0; i < (1 << w); i++) {
+ ep8_free(t0[i]);
+ ep8_free(t1[i]);
+ }
+ for (int i = 0; i < (1 << RLC_WIDTH); i++) {
+ ep8_free(t[i]);
+ }
+ }
+}
+#endif
+
+#if EP_SIM == INTER || !defined(STRIP)
+
+void ep8_mul_sim_inter(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q,
+ const bn_t m) {
+ if (bn_is_zero(k) || ep8_is_infty(p)) {
+ ep8_mul(r, q, m);
+ return;
+ }
+ if (bn_is_zero(m) || ep8_is_infty(q)) {
+ ep8_mul(r, p, k);
+ return;
+ }
+
+ ep8_mul_sim_plain(r, p, k, q, m, NULL);
+}
+
+#endif
+
+#if EP_SIM == JOINT || !defined(STRIP)
+
+void ep8_mul_sim_joint(ep8_t r, const ep8_t p, const bn_t k, const ep8_t q,
+ const bn_t m) {
+ ep8_t t[5];
+ int i, u_i, offset;
+ int8_t jsf[4 * (RLC_FP_BITS + 1)];
+ size_t l;
+
+ if (bn_is_zero(k) || ep8_is_infty(p)) {
+ ep8_mul(r, q, m);
+ return;
+ }
+ if (bn_is_zero(m) || ep8_is_infty(q)) {
+ ep8_mul(r, p, k);
+ return;
+ }
+
+ RLC_TRY {
+ for (i = 0; i < 5; i++) {
+ ep8_null(t[i]);
+ ep8_new(t[i]);
+ }
+
+ ep8_set_infty(t[0]);
+ ep8_copy(t[1], q);
+ if (bn_sign(m) == RLC_NEG) {
+ ep8_neg(t[1], t[1]);
+ }
+ ep8_copy(t[2], p);
+ if (bn_sign(k) == RLC_NEG) {
+ ep8_neg(t[2], t[2]);
+ }
+ ep8_add(t[3], t[2], t[1]);
+ ep8_sub(t[4], t[2], t[1]);
+#if defined(EP_MIXED)
+ ep8_norm_sim(t + 3, t + 3, 2);
+#endif
+
+ l = 4 * (RLC_FP_BITS + 1);
+ bn_rec_jsf(jsf, &l, k, m);
+
+ ep8_set_infty(r);
+
+ offset = RLC_MAX(bn_bits(k), bn_bits(m)) + 1;
+ for (i = l - 1; i >= 0; i--) {
+ ep8_dbl(r, r);
+ if (jsf[i] != 0 && jsf[i] == -jsf[i + offset]) {
+ u_i = jsf[i] * 2 + jsf[i + offset];
+ if (u_i < 0) {
+ ep8_sub(r, r, t[4]);
+ } else {
+ ep8_add(r, r, t[4]);
+ }
+ } else {
+ u_i = jsf[i] * 2 + jsf[i + offset];
+ if (u_i < 0) {
+ ep8_sub(r, r, t[-u_i]);
+ } else {
+ ep8_add(r, r, t[u_i]);
+ }
+ }
+ }
+ ep8_norm(r, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ for (i = 0; i < 5; i++) {
+ ep8_free(t[i]);
+ }
+ }
+}
+
+#endif
+
+void ep8_mul_sim_gen(ep8_t r, const bn_t k, const ep8_t q, const bn_t m) {
+ ep8_t gen;
+
+ ep8_null(gen);
+
+ if (bn_is_zero(k)) {
+ ep8_mul(r, q, m);
+ return;
+ }
+ if (bn_is_zero(m) || ep8_is_infty(q)) {
+ ep8_mul_gen(r, k);
+ return;
+ }
+
+ RLC_TRY {
+ ep8_new(gen);
+
+ ep8_curve_get_gen(gen);
+#if EP_FIX == LWNAF && defined(EP_PRECO)
+ ep8_mul_sim_plain(r, gen, k, q, m, ep8_curve_get_tab());
+#else
+ ep8_mul_sim(r, gen, k, q, m);
+#endif
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(gen);
+ }
+}
+
+void ep8_mul_sim_dig(ep8_t r, const ep8_t p[], const dig_t k[], size_t len) {
+ ep8_t t;
+ int max;
+
+ ep8_null(t);
+
+ max = util_bits_dig(k[0]);
+ for (int i = 1; i < len; i++) {
+ max = RLC_MAX(max, util_bits_dig(k[i]));
+ }
+
+ RLC_TRY {
+ ep8_new(t);
+
+ ep8_set_infty(t);
+ for (int i = max - 1; i >= 0; i--) {
+ ep8_dbl(t, t);
+ for (int j = 0; j < len; j++) {
+ if (k[j] & ((dig_t)1 << i)) {
+ ep8_add(t, t, p[j]);
+ }
+ }
+ }
+
+ ep8_norm(r, t);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep8_free(t);
+ }
+}
+
+void ep8_mul_sim_lot(ep8_t r, const ep8_t p[], const bn_t k[], size_t n) {
+ const size_t len = RLC_FP_BITS + 1;
+ int i, j, m;
+ bn_t _k[8], q, x;
+ int8_t *naf = RLC_ALLOCA(int8_t, 8 * n * len);
+ size_t l, *_l = RLC_ALLOCA(size_t, 8 * n);
+
+ bn_null(q);
+ bn_null(x);
+
+ if (n <= 10) {
+ ep8_t *_p = RLC_ALLOCA(ep8_t, 8 * n);
+
+ RLC_TRY {
+ bn_new(q);
+ bn_new(x);
+ for (j = 0; j < 8; j++) {
+ bn_null(_k[j]);
+ bn_new(_k[j]);
+ for (i = 0; i < n; i++) {
+ ep8_null(_p[8*i + j]);
+ ep8_new(_p[8*i + j]);
+ }
+ }
+
+ for (int i = 0; i < n; i++) {
+ ep8_norm(_p[8*i], p[i]);
+ ep8_frb(_p[8*i + 1], _p[8*i], 1);
+ ep8_frb(_p[8*i + 2], _p[8*i + 1], 1);
+ ep8_frb(_p[8*i + 3], _p[8*i + 2], 1);
+ ep8_frb(_p[8*i + 4], _p[8*i + 3], 1);
+ ep8_frb(_p[8*i + 5], _p[8*i + 4], 1);
+ ep8_frb(_p[8*i + 6], _p[8*i + 5], 1);
+ ep8_frb(_p[8*i + 7], _p[8*i + 6], 1);
+ }
+
+ ep_curve_get_ord(q);
+ fp_prime_get_par(x);
+
+ l = 0;
+ for (i = 0; i < n; i++) {
+ bn_rec_frb(_k, 8, k[i], q, x, ep_curve_is_pairf() == EP_BN);
+ for (j = 0; j < 8; j++) {
+ _l[8*i + j] = len;
+ bn_rec_naf(&naf[(8*i + j)*len], &_l[8*i + j], _k[j], 2);
+ if (bn_sign(_k[j]) == RLC_NEG) {
+ ep8_neg(_p[8*i + j], _p[8*i + j]);
+ }
+ l = RLC_MAX(l, _l[8*i + j]);
+ }
+ }
+
+ ep8_set_infty(r);
+ for (i = l - 1; i >= 0; i--) {
+ ep8_dbl(r, r);
+ for (j = 0; j < n; j++) {
+ for (m = 0; m < 8; m++) {
+ if (naf[(8*j + m)*len + i] > 0) {
+ ep8_add(r, r, _p[8*j + m]);
+ }
+ if (naf[(8*j + m)*len + i] < 0) {
+ ep8_sub(r, r, _p[8*j + m]);
+ }
+ }
+ }
+ }
+
+ /* Convert r to affine coordinates. */
+ ep8_norm(r, r);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(q);
+ bn_free(x);
+ for (j = 0; j < 8; j++) {
+ bn_free(_k[j]);
+ for (i = 0; i < n; i++) {
+ ep8_free(_p[8*i + j]);
+ }
+ }
+ RLC_FREE(_l);
+ RLC_FREE(_p);
+ RLC_FREE(naf);
+ }
+ } else {
+ const int w = RLC_MAX(2, util_bits_dig(n) - 2), c = (1 << (w - 2));
+ ep8_t s, t, u, v, *_p = RLC_ALLOCA(ep8_t, 8 * c);
+ int8_t ptr;
+
+ ep8_null(s);
+ ep8_null(t);
+ ep8_null(u);
+ ep8_null(v);
+
+ RLC_TRY {
+ bn_new(q);
+ bn_new(x);
+ ep8_new(s);
+ ep8_new(t);
+ ep8_new(u);
+ ep8_new(v);
+ for (i = 0; i < 8; i++) {
+ bn_null(_k[i]);
+ bn_new(_k[i]);
+ for (j = 0; j < c; j++) {
+ ep8_null(_p[i*c + j]);
+ ep8_new(_p[i*c + j]);
+ ep8_set_infty(_p[i*c + j]);
+ }
+ }
+
+ ep_curve_get_ord(q);
+ fp_prime_get_par(x);
+
+ l = 0;
+ for (i = 0; i < n; i++) {
+ bn_rec_frb(_k, 8, k[i], q, x, ep_curve_is_pairf() == EP_BN);
+ for (j = 0; j < 8; j++) {
+ _l[8*i + j] = len;
+ bn_rec_naf(&naf[(8*i + j)*len], &_l[8*i + j], _k[j], w);
+ l = RLC_MAX(l, _l[8*i + j]);
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < 8; j++) {
+ for (m = _l[8*i + j]; m < l; m++) {
+ naf[(8*i + j)*len + m] = 0;
+ }
+ }
+ }
+
+ ep8_set_infty(s);
+ for (i = l - 1; i >= 0; i--) {
+ for (j = 0; j < n; j++) {
+ for (m = 0; m < 8; m++) {
+ ptr = naf[(8*j + m)*len + i];
+ if (ptr != 0) {
+ ep8_copy(t, p[j]);
+ if (ptr < 0) {
+ ptr = -ptr;
+ ep8_neg(t, t);
+ }
+ if (bn_sign(_k[m]) == RLC_NEG) {
+ ep8_neg(t, t);
+ }
+ ep8_add(_p[m*c + (ptr/2)], _p[m*c + (ptr/2)], t);
+ }
+ }
+ }
+
+ ep8_set_infty(t);
+ for (m = 3; m >= 0; m--) {
+ ep8_frb(t, t, 1);
+ ep8_set_infty(u);
+ ep8_set_infty(v);
+ for (j = c - 1; j >= 0; j--) {
+ ep8_add(u, u, _p[m*c + j]);
+ if (j == 0) {
+ ep8_dbl(v, v);
+ }
+ ep8_add(v, v, u);
+ ep8_set_infty(_p[m*c + j]);
+ }
+ ep8_add(t, t, v);
+ }
+ ep8_dbl(s, s);
+ ep8_add(s, s, t);
+ }
+
+ /* Convert r to affine coordinates. */
+ ep8_norm(r, s);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(q);
+ bn_free(x);
+ ep8_free(s);
+ ep8_free(t);
+ ep8_free(u);
+ ep8_free(v);
+ for (i = 0; i < 8; i++) {
+ bn_free(_k[i]);
+ for (j = 0; j < c; j++) {
+ ep8_free(_p[i*c + j]);
+ }
+ }
+ RLC_FREE(_l);
+ RLC_FREE(_p);
+ RLC_FREE(naf);
+ }
+ }
+}
diff --git a/src/epx/relic_ep8_neg.c b/src/epx/relic_ep8_neg.c
new file mode 100644
index 000000000..3f0f3061e
--- /dev/null
+++ b/src/epx/relic_ep8_neg.c
@@ -0,0 +1,53 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of point negation on elliptic prime curves over quartic
+ * extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep8_neg(ep8_t r, const ep8_t p) {
+ if (ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ if (r != p) {
+ fp8_copy(r->x, p->x);
+ fp8_copy(r->z, p->z);
+ }
+
+ fp8_neg(r->y, p->y);
+
+ r->coord = p->coord;
+}
diff --git a/src/epx/relic_ep8_norm.c b/src/epx/relic_ep8_norm.c
new file mode 100644
index 000000000..1fe215a1a
--- /dev/null
+++ b/src/epx/relic_ep8_norm.c
@@ -0,0 +1,138 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of point normalization on prime elliptic curves over octic
+ * extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if EP_ADD == PROJC || !defined(STRIP)
+
+/**
+ * Normalizes a point represented in projective coordinates.
+ *
+ * @param r - the result.
+ * @param p - the point to normalize.
+ */
+static void ep8_norm_imp(ep8_t r, const ep8_t p, int inverted) {
+ if (p->coord != BASIC) {
+ fp8_t t0, t1;
+
+ fp8_null(t0);
+ fp8_null(t1);
+
+ RLC_TRY {
+
+ fp8_new(t0);
+ fp8_new(t1);
+
+ if (inverted) {
+ fp8_copy(t1, p->z);
+ } else {
+ fp8_inv(t1, p->z);
+ }
+ fp8_sqr(t0, t1);
+ fp8_mul(r->x, p->x, t0);
+ fp8_mul(t0, t0, t1);
+ fp8_mul(r->y, p->y, t0);
+ fp8_set_dig(r->z, 1);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ }
+ }
+
+ r->coord = BASIC;
+}
+
+#endif /* EP_ADD == PROJC */
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void ep8_norm(ep8_t r, const ep8_t p) {
+ if (ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ if (p->coord == BASIC) {
+ /* If the point is represented in affine coordinates, we just copy it. */
+ ep8_copy(r, p);
+ }
+#if EP_ADD == PROJC || !defined(STRIP)
+ ep8_norm_imp(r, p, 0);
+#endif
+}
+
+void ep8_norm_sim(ep8_t *r, const ep8_t *t, int n) {
+ int i;
+ fp8_t *a = RLC_ALLOCA(fp8_t, n);
+
+ RLC_TRY {
+ if (a == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (i = 0; i < n; i++) {
+ fp8_null(a[i]);
+ fp8_new(a[i]);
+ fp8_copy(a[i], t[i]->z);
+ }
+
+ fp8_inv_sim(a, a, n);
+
+ for (i = 0; i < n; i++) {
+ fp8_copy(r[i]->x, t[i]->x);
+ fp8_copy(r[i]->y, t[i]->y);
+ fp8_copy(r[i]->z, a[i]);
+ }
+
+ for (i = 0; i < n; i++) {
+ ep8_norm_imp(r[i], r[i], 1);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ for (i = 0; i < n; i++) {
+ fp8_free(a[i]);
+ }
+ RLC_FREE(a);
+ }
+}
diff --git a/src/epx/relic_ep8_util.c b/src/epx/relic_ep8_util.c
new file mode 100644
index 000000000..2f4952563
--- /dev/null
+++ b/src/epx/relic_ep8_util.c
@@ -0,0 +1,328 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of comparison for points on prime elliptic curves over
+ * quartic extensions.
+ *
+ * @ingroup epx
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+int ep8_is_infty(const ep8_t p) {
+ return (fp8_is_zero(p->z) == 1);
+}
+
+void ep8_set_infty(ep8_t p) {
+ fp8_zero(p->x);
+ fp8_zero(p->y);
+ fp8_zero(p->z);
+ p->coord = BASIC;
+}
+
+void ep8_copy(ep8_t r, const ep8_t p) {
+ fp8_copy(r->x, p->x);
+ fp8_copy(r->y, p->y);
+ fp8_copy(r->z, p->z);
+ r->coord = p->coord;
+}
+
+void ep8_rand(ep8_t p) {
+ bn_t n, k;
+
+ bn_null(k);
+ bn_null(n);
+
+ RLC_TRY {
+ bn_new(k);
+ bn_new(n);
+
+ ep8_curve_get_ord(n);
+ bn_rand_mod(k, n);
+
+ ep8_mul_gen(p, k);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(k);
+ bn_free(n);
+ }
+}
+
+void ep8_blind(ep8_t r, const ep8_t p) {
+ fp8_t rand;
+
+ fp8_null(rand);
+
+ RLC_TRY {
+ fp8_new(rand);
+ fp8_rand(rand);
+#if EP_ADD == BASIC
+ (void)rand;
+ ep8_copy(r, p);
+#else
+ fp8_mul(r->z, p->z, rand);
+ fp8_mul(r->y, p->y, rand);
+ fp8_sqr(rand, rand);
+ fp8_mul(r->x, r->x, rand);
+ fp8_mul(r->y, r->y, rand);
+ r->coord = EP_ADD;
+#endif
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(rand);
+ }
+}
+
+void ep8_rhs(fp8_t rhs, const ep8_t p) {
+ fp8_t t0, t1;
+
+ fp8_null(t0);
+ fp8_null(t1);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+
+ fp8_sqr(t0, p->x); /* x1^2 */
+
+ switch (ep8_curve_opt_a()) {
+ case RLC_ZERO:
+ break;
+#if FP_RDC != MONTY
+ case RLC_MIN3:
+ fp_sub_dig(t0[0][0][0], t0[0][0][0], 3);
+ break;
+ case RLC_ONE:
+ fp_add_dig(t0[0][0][0], t0[0][0][0], 1);
+ break;
+ case RLC_TWO:
+ fp_add_dig(t0[0][0][0], t0[0][0][0], 2);
+ break;
+ case RLC_TINY:
+ ep8_curve_get_a(t1);
+ fp_mul_dig(t0[0][0][0], t0[0][0][0], t1[0][0][0]);
+ fp_mul_dig(t0[0][0][1], t0[0][0][1], t1[0][0][0]);
+ fp_mul_dig(t0[0][1][0], t0[0][1][0], t1[0][0][0]);
+ fp_mul_dig(t0[0][1][1], t0[0][1][1], t1[0][0][0]);
+ fp_mul_dig(t0[1][0][0], t0[1][0][0], t1[0][0][0]);
+ fp_mul_dig(t0[1][0][1], t0[1][0][1], t1[0][0][0]);
+ fp_mul_dig(t0[1][1][0], t0[1][1][0], t1[0][0][0]);
+ fp_mul_dig(t0[1][1][1], t0[1][1][1], t1[0][0][0]);
+ break;
+#endif
+ default:
+ ep8_curve_get_a(t1);
+ fp8_add(t0, t0, t1);
+ break;
+ }
+
+ fp8_mul(t0, t0, p->x); /* x1^3 + a * x */
+
+ switch (ep8_curve_opt_b()) {
+ case RLC_ZERO:
+ break;
+#if FP_RDC != MONTY
+ case RLC_MIN3:
+ fp_sub_dig(t0[0][0], t0[0][0], 3);
+ break;
+ case RLC_ONE:
+ fp_add_dig(t0[0][0], t0[0][0], 1);
+ break;
+ case RLC_TWO:
+ fp_add_dig(t0[0][0], t0[0][0], 2);
+ break;
+ case RLC_TINY:
+ ep8_curve_get_b(t1);
+ fp_mul_dig(t0[0][0], t0[0][0], t1[0][0][0]);
+ fp_mul_dig(t0[0][1], t0[0][1], t1[0][0][0]);
+ fp_mul_dig(t0[1][0], t0[0][0], t1[0][0][0]);
+ fp_mul_dig(t0[1][1], t0[1][1], t1[0][0][0]);
+ break;
+#endif
+ default:
+ ep8_curve_get_b(t1);
+ fp8_add(t0, t0, t1);
+ break;
+ }
+
+ fp8_copy(rhs, t0);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ }
+}
+
+
+int ep8_on_curve(const ep8_t p) {
+ ep8_t t;
+ int r = 0;
+
+ ep8_null(t);
+
+ RLC_TRY {
+ ep8_new(t);
+
+ ep8_norm(t, p);
+
+ ep8_rhs(t->x, t);
+ fp8_sqr(t->y, t->y);
+
+ r = (fp8_cmp(t->x, t->y) == RLC_EQ) || ep8_is_infty(p);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep8_free(t);
+ }
+ return r;
+}
+
+void ep8_tab(ep8_t *t, const ep8_t p, int w) {
+ if (w > 2) {
+ ep8_dbl(t[0], p);
+#if defined(EP_MIXED)
+ ep8_norm(t[0], t[0]);
+#endif
+ ep8_add(t[1], t[0], p);
+ for (int i = 2; i < (1 << (w - 2)); i++) {
+ ep8_add(t[i], t[i - 1], t[0]);
+ }
+#if defined(EP_MIXED)
+ ep8_norm_sim(t + 1, t + 1, (1 << (w - 2)) - 1);
+#endif
+ }
+ ep8_copy(t[0], p);
+}
+
+void ep8_print(const ep8_t p) {
+ fp8_print(p->x);
+ fp8_print(p->y);
+ fp8_print(p->z);
+}
+
+int ep8_size_bin(const ep8_t a, int pack) {
+ ep8_t t;
+ int size = 0;
+
+ ep8_null(t);
+
+ if (ep8_is_infty(a)) {
+ return 1;
+ }
+
+ RLC_TRY {
+ ep8_new(t);
+
+ ep8_norm(t, a);
+
+ size = 1 + 16 * RLC_FP_BYTES;
+ //TODO: implement compression properly
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep8_free(t);
+ }
+
+ return size;
+}
+
+void ep8_read_bin(ep8_t a, const uint8_t *bin, size_t len) {
+ if (len == 1) {
+ if (bin[0] == 0) {
+ ep8_set_infty(a);
+ return;
+ } else {
+ RLC_THROW(ERR_NO_BUFFER);
+ return;
+ }
+ }
+
+ if (len != (16 * RLC_FP_BYTES + 1)) {
+ RLC_THROW(ERR_NO_BUFFER);
+ return;
+ }
+
+ a->coord = BASIC;
+ fp8_set_dig(a->z, 1);
+ fp8_read_bin(a->x, bin + 1, 8 * RLC_FP_BYTES);
+
+ if (len == 16 * RLC_FP_BYTES + 1) {
+ if (bin[0] == 4) {
+ fp8_read_bin(a->y, bin + 8 * RLC_FP_BYTES + 1, 8 * RLC_FP_BYTES);
+ } else {
+ RLC_THROW(ERR_NO_VALID);
+ return;
+ }
+ }
+
+ if (!ep8_on_curve(a)) {
+ RLC_THROW(ERR_NO_VALID);
+ }
+}
+
+void ep8_write_bin(uint8_t *bin, size_t len, const ep8_t a, int pack) {
+ ep8_t t;
+
+ ep8_null(t);
+
+ memset(bin, 0, len);
+
+ if (ep8_is_infty(a)) {
+ if (len < 1) {
+ RLC_THROW(ERR_NO_BUFFER);
+ return;
+ } else {
+ return;
+ }
+ }
+
+ RLC_TRY {
+ ep8_new(t);
+
+ ep8_norm(t, a);
+
+ if (len < 16 * RLC_FP_BYTES + 1) {
+ RLC_THROW(ERR_NO_BUFFER);
+ } else {
+ bin[0] = 4;
+ fp8_write_bin(bin + 1, 8 * RLC_FP_BYTES, t->x);
+ fp8_write_bin(bin + 8 * RLC_FP_BYTES + 1, 8 * RLC_FP_BYTES, t->y);
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ ep8_free(t);
+ }
+}
diff --git a/src/fp/relic_fp_crt.c b/src/fp/relic_fp_crt.c
new file mode 100644
index 000000000..140f64683
--- /dev/null
+++ b/src/fp/relic_fp_crt.c
@@ -0,0 +1,216 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2010 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the cube root function.
+ *
+ * @ingroup bn
+ */
+
+#include "relic_core.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+int fp_is_cub(const fp_t a) {
+ bn_t t;
+ int r = 0;
+
+ bn_null(t);
+
+ if (fp_is_zero(a) || (fp_prime_get_mod18() % 3 == 2)) {
+ return 1;
+ }
+
+ RLC_TRY {
+ bn_new(t);
+
+ /* t = (b - 1)/3. */
+ t->sign = RLC_POS;
+ t->used = RLC_FP_DIGS;
+ dv_copy(t->dp, fp_prime_get(), RLC_FP_DIGS);
+ bn_sub_dig(t, t, 1);
+ bn_div_dig(t, t, 3);
+
+ fp_exp(t->dp, a, t);
+ r = (fp_cmp_dig(t->dp, 1) == RLC_EQ);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(t);
+ }
+ return r;
+}
+
+int fp_crt(fp_t c, const fp_t a) {
+ bn_t e;
+ fp_t t0, t1, t2, t3, t4, t5;
+ int f = 0, r = 0;
+
+ bn_null(e);
+ fp_null(t0);
+ fp_null(t1);
+ fp_null(t2);
+ fp_null(t3);
+ fp_null(t4);
+ fp_null(t5);
+
+ if (fp_is_zero(a)) {
+ fp_zero(c);
+ return 1;
+ }
+
+ RLC_TRY {
+ bn_new(e);
+ fp_new(t0);
+ fp_new(t1);
+ fp_new(t2);
+ fp_new(t3);
+ fp_new(t4);
+ fp_new(t5);
+
+ /* Make e = p. */
+ e->used = RLC_FP_DIGS;
+ dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
+
+ /* Special cases and algorithm taken from "New Cube Root Algorithm Based
+ * on Third Order Linear Recurrence Relation in Finite Field"
+ * https://eprint.iacr.org/2013/024.pdf
+ */
+ if (fp_prime_get_mod18() % 3 == 2) {
+ /* Easy case, compute a^((2q - 1)/3). */
+ bn_dbl(e, e);
+ bn_sub_dig(e, e, 1);
+ bn_div_dig(e, e, 3);
+
+ fp_exp(t0, a, e);
+ fp_sqr(t1, t0);
+ fp_mul(t1, t1, t0);
+ r = (fp_cmp(t1, a) == RLC_EQ);
+ fp_copy(c, t0);
+ } else if (fp_prime_get_mod18() % 9 == 4) {
+ /* Easy case, compute a^((2q + 1)/9). */
+ bn_dbl(e, e);
+ bn_add_dig(e, e, 1);
+ bn_div_dig(e, e, 9);
+
+ fp_exp(t0, a, e);
+ fp_sqr(t1, t0);
+ fp_mul(t1, t1, t0);
+ r = (fp_cmp(t1, a) == RLC_EQ);
+ fp_copy(c, t0);
+ } else if (fp_prime_get_mod18() % 9 == 7) {
+ /* Easy case, compute a^((q + 2)/9). */
+ bn_add_dig(e, e, 2);
+ bn_div_dig(e, e, 9);
+
+ fp_exp(t0, a, e);
+ fp_sqr(t1, t0);
+ fp_mul(t1, t1, t0);
+ r = (fp_cmp(t1, a) == RLC_EQ);
+ fp_copy(c, t0);
+ } else {
+ dig_t rem;
+
+ /* First check that a is a square. */
+ r = fp_is_cub(a);
+
+ /* Compute progenitor as x^(p-1-3^f)/3^(f+1) where 3^f|(p-1). */
+
+ /* Write p - 1 as (e * 3^f), with e = 3l \pm 1. */
+ bn_sub_dig(e, e, 1);
+ bn_mod_dig(&rem, e, 3);
+ while (rem == 0) {
+ bn_div_dig(e, e, 3);
+ bn_mod_dig(&rem, e, 3);
+ f++;
+ }
+
+ /* Make it e = (p - 1 - 3^f)/3^(f + 1), compute t0 = a^e. */
+ bn_mod_dig(&rem, e, 3);
+ bn_div_dig(e, e, 3);
+ fp_exp(t0, a, e);
+
+ /* Recover 3^f-root of unity, and continue algorithm. */
+ fp_copy(t3, fp_prime_get_crt());
+
+ fp_copy(c, t3);
+ for (int i = 0; i < f - 1; i++) {
+ fp_sqr(t4, c);
+ fp_mul(c, c, t4);
+ }
+ fp_sqr(t1, t0);
+ fp_mul(t1, t1, t0);
+ fp_mul(t1, t1, a);
+ if (rem == 2) {
+ fp_mul(t0, t0, a);
+ fp_mul(t1, t1, a);
+ }
+ fp_set_dig(t5, 1);
+ for (int j = f; j > 1; j--) {
+ fp_copy(t2, t1);
+ for (int i = 1; i < j - 1; i++) {
+ fp_sqr(t4, t2);
+ fp_mul(t2, t2, t4);
+ }
+ if (fp_cmp(t2, c) == RLC_EQ) {
+ fp_sqr(t4, t3);
+ fp_mul(t5, t5, t4);
+ fp_mul(t4, t4, t3);
+ fp_sqr(t4, t4);
+ fp_mul(t1, t1, t4);
+ } else if (fp_cmp_dig(t2, 1) != RLC_EQ) {
+ fp_mul(t5, t5, t3);
+ fp_sqr(t4, t3);
+ fp_mul(t4, t4, t3);
+ fp_mul(t1, t1, t4);
+ }
+ fp_sqr(t4, t3);
+ fp_mul(t3, t3, t4);
+ }
+
+ fp_mul(c, t0, t5);
+ if (rem == 1) {
+ fp_inv(c, c);
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(e);
+ fp_free(t0);
+ fp_free(t1);
+ fp_free(t2);
+ fp_free(t3);
+ fp_free(t4);
+ fp_free(t5);
+ }
+ return r;
+}
diff --git a/src/fp/relic_fp_exp.c b/src/fp/relic_fp_exp.c
index 947807f59..de847ba78 100644
--- a/src/fp/relic_fp_exp.c
+++ b/src/fp/relic_fp_exp.c
@@ -189,3 +189,34 @@ void fp_exp_monty(fp_t c, const fp_t a, const bn_t b) {
}
#endif
+
+void fp_exp_dig(fp_t c, const fp_t a, dig_t b) {
+ fp_t t;
+
+ if (b == 0) {
+ fp_set_dig(c, 1);
+ return;
+ }
+
+ fp_null(t);
+
+ RLC_TRY {
+ fp_new(t);
+
+ fp_copy(t, a);
+ for (int i = util_bits_dig(b) - 2; i >= 0; i--) {
+ fp_sqr(t, t);
+ if (b & ((dig_t)1 << i)) {
+ fp_mul(t, t, a);
+ }
+ }
+
+ fp_copy(c, t);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp_free(t);
+ }
+}
diff --git a/src/fp/relic_fp_inv.c b/src/fp/relic_fp_inv.c
index 6ec85f98a..3d94594f2 100644
--- a/src/fp/relic_fp_inv.c
+++ b/src/fp/relic_fp_inv.c
@@ -33,6 +33,71 @@
#include "relic_fp_low.h"
#include "relic_bn_low.h"
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if FP_INV == JMPDS || !defined(STRIP)
+
+/**
+ * Conditionally negate a digit vector using two's complement representation.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the digit vector to conditionally negate.
+ * @param[in] sa - the sign of the digit vector.
+ * @param[in] n - the number of digits to conditionally negate.
+ */
+static void bn_negs_low(dig_t c[], const dig_t a[], dig_t sa, size_t n) {
+ dig_t carry = sa & 1;
+
+ sa = -sa;
+ for (int i = 0; i < n; i++) {
+ c[i] = (a[i] ^ sa) + carry;
+ carry = (c[i] < carry);
+ }
+}
+
+static void bn_mul2_low(dig_t *c, const dig_t *a, dis_t digit, int size) {
+ int sd = digit >> (RLC_DIG - 1);
+ digit = (digit ^ sd) - sd;
+ c[size] = bn_mul1_low(c, a, digit, size);
+}
+
+static dis_t jumpdivstep(dis_t m[4], dis_t delta, dig_t f, dig_t g, int s) {
+ dig_t u = 1, v = 0, q = 0, r = 1, c0, c1;
+
+ /* This is actually faster than my previous version, several tricks from
+ * https://github.com/bitcoin-core/secp256k1/blob/master/src/modinv64_impl.h
+ */
+ for (s--; s >= 0; s--) {
+ /* First handle the else part: if delta < 0, compute -(f,u,v). */
+ c0 = delta >> (RLC_DIG - 1);
+ c1 = -(g & 1);
+ c0 &= c1;
+ /* Conditionally add -(f,u,v) to (g,q,r) */
+ g += ((f ^ c0) - c0) & c1;
+ q += ((u ^ c0) - c0) & c1;
+ r += ((v ^ c0) - c0) & c1;
+ /* Now handle the 'if' part, so c0 will be (delta < 0) && (g & 1)) */
+ /* delta = RLC_SEL(delta, -delta, c0 & 1) - 2 (for half-divstep), thus
+ * delta = - delta - 2 or delta - 1 */
+ delta = (delta ^ c0) - 1;
+ f = f + (g & c0);
+ u = u + (q & c0);
+ v = v + (r & c0);
+ g >>= 1;
+ u += u;
+ v += v;
+ }
+ m[0] = u;
+ m[1] = v;
+ m[2] = q;
+ m[3] = r;
+ return delta;
+}
+
+#endif
+
/*============================================================================*/
/* Public definitions */
/*============================================================================*/
@@ -404,9 +469,9 @@ void fp_inv_exgcd(fp_t c, const fp_t a) {
void fp_inv_divst(fp_t c, const fp_t a) {
/* Compute number of iterations based on modulus size. */
#if FP_PRIME < 46
- int d = (49 * FP_PRIME + 80) / 17;
+ const int d = (49 * FP_PRIME + 80) / 17;
#else
- int d = (49 * FP_PRIME + 57) / 17;
+ const int d = (49 * FP_PRIME + 57) / 17;
#endif
int g0, d0;
dig_t fs, gs, delta = 1;
@@ -511,52 +576,14 @@ void fp_inv_divst(fp_t c, const fp_t a) {
#if FP_INV == JMPDS || !defined(STRIP)
-static dis_t jumpdivstep(dis_t m[4], dis_t delta, dig_t f, dig_t g, int s) {
- dig_t u = 1, v = 0, q = 0, r = 1, c0, c1;
-
- /* This is actually faster than my previous version, several tricks from
- * https://github.com/bitcoin-core/secp256k1/blob/master/src/modinv64_impl.h
- */
- for (s--; s >= 0; s--) {
- /* First handle the else part: if delta < 0, compute -(f,u,v). */
- c0 = delta >> (RLC_DIG - 1);
- c1 = -(g & 1);
- c0 &= c1;
- /* Conditionally add -(f,u,v) to (g,q,r) */
- g += ((f ^ c0) - c0) & c1;
- q += ((u ^ c0) - c0) & c1;
- r += ((v ^ c0) - c0) & c1;
- /* Now handle the 'if' part, so c0 will be (delta < 0) && (g & 1)) */
- /* delta = RLC_SEL(delta, -delta, c0 & 1) - 2 (for half-divstep), thus
- * delta = - delta - 2 or delta - 1 */
- delta = (delta ^ c0) - 1;
- f = f + (g & c0);
- u = u + (q & c0);
- v = v + (r & c0);
- g >>= 1;
- u += u;
- v += v;
- }
- m[0] = u;
- m[1] = v;
- m[2] = q;
- m[3] = r;
- return delta;
-}
-
-static inline void bn_mul2_low(dig_t *c, const dig_t *a, dis_t digit, int size) {
- int sd = digit >> (RLC_DIG - 1);
- digit = (digit ^ sd) - sd;
- c[size] = bn_mul1_low(c, a, digit, size);
-}
-
void fp_inv_jmpds(fp_t c, const fp_t a) {
- dis_t m[4];
+ dis_t m[4], d = -1;
/* Compute number of iterations based on modulus size. */
- int i, d = -1, s = RLC_DIG - 2;
/* Iterations taken directly from https://github.com/sipa/safegcd-bounds */
- int iterations = (45907 * FP_PRIME + 26313) / 19929;
+ const int iterations = (45907 * FP_PRIME + 26313) / 19929;
+ int loops, i, s = RLC_DIG - 2;
dv_t f, g, t, p, t0, t1, u0, u1, v0, v1, p01, p11;
+ dig_t sf, sg;
fp_t pre;
if (fp_is_zero(a)) {
@@ -593,7 +620,7 @@ void fp_inv_jmpds(fp_t c, const fp_t a) {
dv_new(p11);
fp_new(pre);
-#if (FP_PRIME % WSIZE) != 0
+#ifdef RLC_FP_ROOM
int j = 0;
fp_copy(pre, core_get()->inv.dp);
#else
@@ -601,7 +628,6 @@ void fp_inv_jmpds(fp_t c, const fp_t a) {
fp_mul(pre, pre, core_get()->conv.dp);
fp_mul(pre, pre, core_get()->inv.dp);
#endif
-
f[RLC_FP_DIGS] = g[RLC_FP_DIGS] = 0;
dv_zero(t, 2 * RLC_FP_DIGS);
dv_zero(p, 2 * RLC_FP_DIGS);
@@ -644,25 +670,28 @@ void fp_inv_jmpds(fp_t c, const fp_t a) {
dv_copy(p01, v1, 2 * RLC_FP_DIGS);
dv_copy(p11, u1, 2 * RLC_FP_DIGS);
- int loops = iterations / s;
+ loops = iterations / s;
loops = (iterations % s == 0 ? loops - 1 : loops);
for (i = 1; i < loops; i++) {
d = jumpdivstep(m, d, f[0] & RLC_MASK(s), g[0] & RLC_MASK(s), s);
- t0[RLC_FP_DIGS] = bn_muls_low(t0, f, RLC_SIGN(f[RLC_FP_DIGS]), m[0], RLC_FP_DIGS);
- t1[RLC_FP_DIGS] = bn_muls_low(t1, g, RLC_SIGN(g[RLC_FP_DIGS]), m[1], RLC_FP_DIGS);
- bn_addn_low(t0, t0, t1, RLC_FP_DIGS + 1);
-
- f[RLC_FP_DIGS] = bn_muls_low(f, f, RLC_SIGN(f[RLC_FP_DIGS]), m[2], RLC_FP_DIGS);
- t1[RLC_FP_DIGS] = bn_muls_low(t1, g, RLC_SIGN(g[RLC_FP_DIGS]), m[3], RLC_FP_DIGS);
- bn_addn_low(t1, t1, f, RLC_FP_DIGS + 1);
+ sf = RLC_SIGN(f[RLC_FP_DIGS]);
+ sg = RLC_SIGN(g[RLC_FP_DIGS]);
+ bn_negs_low(u0, f, sf, RLC_FP_DIGS);
+ bn_negs_low(u1, g, sg, RLC_FP_DIGS);
- /* Update f and g. */
+ t0[RLC_FP_DIGS] = bn_muls_low(t0, u0, sf, m[0], RLC_FP_DIGS);
+ t1[RLC_FP_DIGS] = bn_muls_low(t1, u1, sg, m[1], RLC_FP_DIGS);
+ bn_addn_low(t0, t0, t1, RLC_FP_DIGS + 1);
bn_rshs_low(f, t0, RLC_FP_DIGS + 1, s);
+
+ t0[RLC_FP_DIGS] = bn_muls_low(t0, u0, sf, m[2], RLC_FP_DIGS);
+ t1[RLC_FP_DIGS] = bn_muls_low(t1, u1, sg, m[3], RLC_FP_DIGS);
+ bn_addn_low(t1, t1, t0, RLC_FP_DIGS + 1);
bn_rshs_low(g, t1, RLC_FP_DIGS + 1, s);
-#if (FP_PRIME % WSIZE) != 0
+#ifdef RLC_FP_ROOM
p[j] = 0;
dv_copy(p + j + 1, fp_prime_get(), RLC_FP_DIGS);
@@ -727,23 +756,25 @@ void fp_inv_jmpds(fp_t c, const fp_t a) {
s = iterations - loops * s;
d = jumpdivstep(m, d, f[0] & RLC_MASK(s), g[0] & RLC_MASK(s), s);
- t0[RLC_FP_DIGS] = bn_muls_low(t0, f, RLC_SIGN(f[RLC_FP_DIGS]), m[0], RLC_FP_DIGS);
- t1[RLC_FP_DIGS] = bn_muls_low(t1, g, RLC_SIGN(g[RLC_FP_DIGS]), m[1], RLC_FP_DIGS);
- bn_addn_low(t0, t0, t1, RLC_FP_DIGS + 1);
-
- f[RLC_FP_DIGS] = bn_muls_low(f, f, RLC_SIGN(f[RLC_FP_DIGS]), m[2], RLC_FP_DIGS);
- t1[RLC_FP_DIGS] = bn_muls_low(t1, g, RLC_SIGN(g[RLC_FP_DIGS]), m[3], RLC_FP_DIGS);
- bn_addn_low(t1, t1, f, RLC_FP_DIGS + 1);
+ sf = RLC_SIGN(f[RLC_FP_DIGS]);
+ sg = RLC_SIGN(g[RLC_FP_DIGS]);
+ bn_negs_low(u0, f, sf, RLC_FP_DIGS);
+ bn_negs_low(u1, g, sg, RLC_FP_DIGS);
- /* Update f and g. */
+ t0[RLC_FP_DIGS] = bn_muls_low(t0, u0, sf, m[0], RLC_FP_DIGS);
+ t1[RLC_FP_DIGS] = bn_muls_low(t1, u1, sg, m[1], RLC_FP_DIGS);
+ bn_addn_low(t0, t0, t1, RLC_FP_DIGS + 1);
bn_rshs_low(f, t0, RLC_FP_DIGS + 1, s);
+
+ t0[RLC_FP_DIGS] = bn_muls_low(t0, u0, sf, m[2], RLC_FP_DIGS);
+ t1[RLC_FP_DIGS] = bn_muls_low(t1, u1, sg, m[3], RLC_FP_DIGS);
+ bn_addn_low(t1, t1, t0, RLC_FP_DIGS + 1);
bn_rshs_low(g, t1, RLC_FP_DIGS + 1, s);
-#if (FP_PRIME % WSIZE) != 0
+#ifdef RLC_FP_ROOM
p[j] = 0;
dv_copy(p + j + 1, fp_prime_get(), RLC_FP_DIGS);
- /* Update column vector below. */
/* Update column vector below. */
bn_mul2_low(v0, p01, m[0], RLC_FP_DIGS + j);
fp_subd_low(t, p, v0);
diff --git a/src/fp/relic_fp_param.c b/src/fp/relic_fp_param.c
index 2c8b7e557..da5424883 100644
--- a/src/fp/relic_fp_param.c
+++ b/src/fp/relic_fp_param.c
@@ -37,7 +37,6 @@
/*============================================================================*/
#if FP_PRIME == 255
-
/**
* Primes with high 2-adicity for curves Tweedledum and Tweedledee.
*/
@@ -47,7 +46,13 @@
/**
* Random prime modulus for the Brainpool P256r1.
*/
-#define STR_P256 "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"
+#define STR_P256 "AA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"
+
+#elif FP_PRIME == 511
+/**
+ * CTIDH prime with 511 bits.
+ */
+#define STR_P511 "65B48E8F740F89BFFC8AB0D15E3E4C4AB42D083AEDC88C425AFBFCC69322C9CDA7AAC6C567F35507516730CC1F0B4F25C2721BF457ACA8351B81B90533C6C87B"
#elif FP_PRIME == 544
/**
@@ -55,18 +60,35 @@
*/
#define STR_P544 "BB9DFD549299F1C803DDD5D7C05E7CC0373D9B1AC15B47AA5AA84626F33E58FE66943943049031AE4CA1D2719B3A84FA363BCD2539A5CD02C6F4B6B645A58C1085E14411"
+#elif FP_PRIME == 1024
+/**
+ * CTIDH prime with 1024 bits.
+ */
+#define STR_P1024 "ECE55ED427012A9D89DEC879007EBD7216C22BC86F21A080683CF25DB31AD5BF06DE2471CF9386E4D6C594A8AD82D2DF811D9C419EC83297611AD4F90441C800978DBEED90A2B58B97C56D1DE81EDE56B317C5431541F40642ACA4D5A313709C2CAB6A0E287F1BD514BA72CB8D89FD3A1D81EEBBC3D344DDBE34C5460E36453"
+
#elif FP_PRIME == 1536
/**
* Cofactor description of 1536-bit prime modulus.
*/
#define STR_P1536 "83093742908D4D529CEF06C72191A05D5E6073FE861E637D7747C3E52FBB92DAA5DDF3EF1C61F5F70B256802481A36CAFE995FE33CD54014B846751364C0D3B8327D9E45366EA08F1B3446AC23C9D4B656886731A8D05618CFA1A3B202A2445ABA0E77C5F4F00CA1239975A05377084F256DEAA07D21C4CF2A4279BC117603ACB7B10228C3AB8F8C1742D674395701BB02071A88683041D9C4231E8EE982B8DA"
-#elif FP_PRIME == 3072
+#elif FP_PRIME == 2048
+/**
+ * CTIDH prime with 2048 bits.
+ */
+#define STR_P2048 "438EFCAB10254C6497FEFC90E8196ED94D8854E8B3E19C53DDFFDCF1AEE53F12DBD1FC2133770253584EB12932F72ABB33A8779A1EC8B8C2B8523D6A302ABF284DD6024BF2F8FEAB6557EBE96D91AEDDC68049793337525393E73ABD17E3AA46095AC8A9F3CE2B0C30D2EDFE50198C647D84F102B5FDE2EAE33586D1208A10179844E5C09BAF59EC0DA1783672767ABB88C691B2D452A8AC7C4CB419996F45E75377D53E856CC9A39796620B3AD8A5D458E89497EF35BBB92842BBE4DBACC65E44084E1A73C76CB244454E851CF305ABA7BEC86FABAF787F6478407D7A9A56EEE111B0D22AB8ECAA95A98036C813C788DC703F0CD8C4D9187790D615EA034943"
+#elif FP_PRIME == 3072
/**
* Cofactor description of 3072-bit prime modulus.
*/
-#define STR_P3072 "D2DECB54BA1C33C49BD7B174FBC6E56AD9B05D1B2B4100708AA3B6AA620B5CD167F66D33818B608FC25C9F56A0C685129B9DDAA342ADB37B2CEA7E09DEB49F3BC85B467801ED7507149CF025A021D8109926CAC3C774AD8E3C0B4D175CF1C94A6641A8E5BBBE63FB40EC52B206315D20C074B538785E63174FB8A72C912F51B6A3D132A185FD95B067B817AB9F4C01ABA6CC7BF1546D94FD79AC2D0183814FD8"
+#define STR_P3072 "E4C6467513F6DA5D303FCF2C5285C33206AC48901ADBE523D00F9F3B9E4895075BEB07DD1AAEEBF957F2DCBBEC4FB900E2ADE744AA7206BC2A60709BA08CA540"
+
+#elif FP_PRIME == 4096
+/**
+ * SQALE prime with 4096 bits.
+ */
+#define STR_P4096 "5E7717415B4CA2B9C447D91852630BDD26650A3BB26C86B690F049B4591045979B3908337C3FCE9453BDAD5DB6E3F21009C117DD6D5390FBF3924E59A2AFFCB043640CDA1CD63586511586409A8B182FB61117429E0FAD42661F279E970400FFC4BCEFE6A5B783100DAC14812B370ACFF9D051A0FB768F71FB7997BE77856D9284530ADB4A502D6EC3249D4EEA4683A8985A6B47BE6E7821DEF1AD022E6ECAB6CBA7B9B3710891E6757B7B0EA38391F577E88B3F5AADC520FB7E8F8314D444512BA4A0C4C2765F310A825D48E93D16A3B848542F632F95EF18B06DAC453EE68530A8AD864CE7CFEA2ABEADC289712A45C37A2496D6A0643ADBF7269D993760ED6855D97BA9DB63D9D28976E599D8F92E19D841ED1C3B26FCD527B24495B02AC1B19C8D8A6BFE007C68E6C44B4D5D26C6262D87B73F4A55FD9E324EE60EC15289442AE0D0EB23485C9760DB220C5F584BBD9A5671A61D5E08938F4FDC64215E5B3F9D2D3E15ED1B60E2C9D7F2E2DBDA4B10C1665D7FB1B9C76B02F4FD9D35FD9EB061D95CAFC1292BCCE8116D756C8905973DC84CFF577C5B68D30CA59CE3425CFB2F371E06C9D3AACF8DC03746E8A12DD786E8EDD70F9D4F1D32B79F32E14CD64D59D8DEC8B88D8AEE6235F05176385C0EA561D56AF87D0146535D892DB5C5F6D4A09051509BF0ECB893B4DADA515DABD369B93E277B867FD1FCF47604E79BCB"
#endif
@@ -99,7 +121,13 @@ void fp_param_set(int param) {
core_get()->fp_id = param;
switch (param) {
-#if FP_PRIME == 158
+#if FP_PRIME == 127
+ case MP_127:
+ f[0] = -1;
+ f[1] = 127;
+ fp_prime_set_pmers(f, 2);
+ break;
+#elif FP_PRIME == 158
case BN_158:
/* x = 0x4000000031. */
bn_set_2b(t0, 38);
@@ -295,6 +323,18 @@ void fp_param_set(int param) {
bn_set_bit(t0, 15, 1);
fp_prime_set_pairf(t0, EP_B24);
break;
+#elif FP_PRIME == 330
+ case K16_330:
+ /* x = 2^34-2^30+2^26+2^23+2^14-2^5+1. */
+ bn_set_2b(t0, 34);
+ bn_set_2b(t1, 30);
+ bn_sub(t0, t0, t1);
+ bn_set_bit(t0, 26, 1);
+ bn_set_bit(t0, 23, 1);
+ bn_set_bit(t0, 14, 1);
+ bn_sub_dig(t0, t0, 31);
+ fp_prime_set_pairf(t0, EP_K16);
+ break;
#elif FP_PRIME == 377
case B12_377:
/* x = 2^63 + 2^58 + 2^56 + 2^51 + 2^47 + 2^46 + 1. */
@@ -400,7 +440,7 @@ void fp_param_set(int param) {
fp_prime_set_pairf(t0, EP_B12);
break;
#elif FP_PRIME == 508
- case KSS_508:
+ case K508:
/* x = -(2^64 + 2^51 - 2^46 - 2^12). */
bn_set_2b(t0, 64);
bn_set_2b(t1, 51);
@@ -410,34 +450,7 @@ void fp_param_set(int param) {
bn_set_2b(t1, 12);
bn_sub(t0, t0, t1);
bn_neg(t0, t0);
- /* h = (49*u^2 + 245 * u + 343)/3 */
- bn_mul_dig(p, t0, 245);
- bn_add_dig(p, p, 200);
- bn_add_dig(p, p, 143);
- bn_sqr(t1, t0);
- bn_mul_dig(t2, t1, 49);
- bn_add(p, p, t2);
- bn_div_dig(p, p, 3);
- /* n = (u^6 + 37 * u^3 + 343)/343. */
- bn_mul(t1, t1, t0);
- bn_mul_dig(t2, t1, 37);
- bn_sqr(t1, t1);
- bn_add(t2, t2, t1);
- bn_add_dig(t2, t2, 200);
- bn_add_dig(t2, t2, 143);
- bn_div_dig(t2, t2, 49);
- bn_div_dig(t2, t2, 7);
- bn_mul(p, p, t2);
- /* t = (u^4 + 16 * u + 7)/7. */
- bn_mul_dig(t1, t0, 16);
- bn_add_dig(t1, t1, 7);
- bn_sqr(t2, t0);
- bn_sqr(t2, t2);
- bn_add(t2, t2, t1);
- bn_div_dig(t2, t2, 7);
- bn_add(p, p, t2);
- bn_sub_dig(p, p, 1);
- fp_prime_set_dense(p);
+ fp_prime_set_pairf(t0, EP_K18);
break;
#elif FP_PRIME == 509
case B24_509:
@@ -452,11 +465,9 @@ void fp_param_set(int param) {
fp_prime_set_pairf(t0, EP_B24);
break;
#elif FP_PRIME == 511
- case OT_511:
- bn_set_2b(t0, 52);
- bn_add_dig(t0, t0, 0xAB);
- bn_lsh(t0, t0, 12);
- fp_prime_set_pairf(t0, EP_OT8);
+ case CTIDH_511:
+ bn_read_str(p, STR_P511, strlen(STR_P511), 16);
+ fp_prime_set_dense(p);
break;
case PRIME_511187:
bn_set_2b(p, 511);
@@ -557,6 +568,36 @@ void fp_param_set(int param) {
bn_neg(t0, t0);
fp_prime_set_pairf(t0, EP_SG18);
break;
+#elif FP_PRIME == 765
+ case N16_765:
+ /* u = -(2^48 - 2^44 + 2^37) */
+ bn_set_2b(t0, 48);
+ bn_set_2b(t1, 44);
+ bn_sub(t0, t0, t1);
+ bn_set_2b(t1, 37);
+ bn_add(t0, t0, t1);
+ bn_neg(t0, t0);
+ fp_prime_set_pairf(t0, EP_N16);
+ break;
+#elif FP_PRIME == 766
+ case K16_766:
+ /* u = 2^78-2^76-2^28+2^14+2^7+1 */
+ bn_set_2b(t0, 78);
+ bn_set_2b(t1, 76);
+ bn_sub(t0, t0, t1);
+ bn_set_2b(t1, 28);
+ bn_sub(t0, t0, t1);
+ bn_set_2b(t1, 14);
+ bn_add(t0, t0, t1);
+ bn_add_dig(t0, t0, 128);
+ bn_add_dig(t0, t0, 1);
+ fp_prime_set_pairf(t0, EP_K16);
+ break;
+#elif FP_PRIME == 1024
+ case CTIDH_1024:
+ bn_read_str(p, STR_P1024, strlen(STR_P1024), 16);
+ fp_prime_set_dense(p);
+ break;
#elif FP_PRIME == 1536
case SS_1536:
/* x = 2^255 + 2^41 + 1. */
@@ -570,18 +611,30 @@ void fp_param_set(int param) {
fp_prime_set_dense(p);
fp_prime_set_pairf(t0, EP_SS2);
break;
+#elif FP_PRIME == 2048
+ case CTIDH_2048:
+ bn_read_str(p, STR_P2048, strlen(STR_P2048), 16);
+ fp_prime_set_dense(p);
+ break;
#elif FP_PRIME == 3072
- case SS_3072:
+ case K1_3072:
/* x = 2^256 + 2^96 - 1. */
bn_set_2b(t0, 256);
- bn_set_bit(t0, 96, 1);
+ bn_set_2b(p, 96);
+ bn_add(t0, t0, p);
bn_sub_dig(t0, t0, 1);
bn_read_str(p, STR_P3072, strlen(STR_P3072), 16);
+ bn_lsh(p, p, 768);
bn_mul(p, p, t0);
bn_sqr(p, p);
bn_add_dig(p, p, 1);
fp_prime_set_dense(p);
- fp_prime_set_pairf(t0, EP_SS1);
+ fp_prime_set_pairf(t0, EP_K1);
+ break;
+#elif FP_PRIME == 4096
+ case SQALE_4096:
+ bn_read_str(p, STR_P4096, strlen(STR_P4096), 16);
+ fp_prime_set_dense(p);
break;
#else
default:
@@ -630,7 +683,7 @@ int fp_param_set_any_dense(void) {
#ifdef FP_QNRES
do {
bn_gen_prime(p, RLC_FP_BITS);
- } while ((p->dp[0] & 0x7) != 3);
+ } while ((p->dp[0] % 8) != 3);
#else
bn_gen_prime(p, RLC_FP_BITS);
#endif
@@ -650,7 +703,9 @@ int fp_param_set_any_dense(void) {
}
int fp_param_set_any_pmers(void) {
-#if FP_PRIME == 160
+#if FP_PRIME == 127
+ fp_param_set(MP_127);
+#elif FP_PRIME == 160
fp_param_set(SECG_160);
#elif FP_PRIME == 192
fp_param_set(NIST_192);
@@ -692,6 +747,8 @@ int fp_param_set_any_tower(void) {
fp_param_set(B24_315);
#elif FP_PRIME == 317
fp_param_set(B24_317);
+#elif FP_PRIME == 330
+ fp_param_set(K16_330);
#elif FP_PRIME == 377
fp_param_set(B12_377);
#elif FP_PRIME == 381
@@ -709,11 +766,11 @@ int fp_param_set_any_tower(void) {
#elif FP_PRIME == 455
fp_param_set(B12_455);
#elif FP_PRIME == 508
- fp_param_set(KSS_508);
+ fp_param_set(K18_508);
#elif FP_PRIME == 509
fp_param_set(B24_509);
#elif FP_PRIME == 511
- fp_param_set(OT_511);
+ fp_param_set(CTIDH_511);
#elif FP_PRIME == 544
fp_param_set(GMT8_544);
#elif FP_PRIME == 569
@@ -728,13 +785,22 @@ int fp_param_set_any_tower(void) {
fp_param_set(K18_638);
//fp_param_set(SG18_638);
#endif
+#elif FP_PRIME == 765
+ fp_param_set(N16_765);
+#elif FP_PRIME == 766
+ fp_param_set(K16_766);
#elif FP_PRIME == 1536
fp_param_set(SS_1536);
+#elif FP_PRIME == 3072
+ fp_param_set(K1_3072);
+#elif FP_PRIME == 4096
+ fp_param_set(SQALE_4096);
#else
do {
/* Since we have to generate a prime number, pick a nice towering. */
fp_param_set_any_dense();
- } while (fp_prime_get_mod8() == 1 || fp_prime_get_mod8() == 5);
+ } while (fp_prime_get_mod8() == 1 || fp_prime_get_mod8() == 5
+ || fp_prime_get_mod18() % 3 == 2);
#endif
return RLC_OK;
@@ -743,9 +809,5 @@ int fp_param_set_any_tower(void) {
void fp_param_print(void) {
util_banner("Prime modulus:", 0);
util_print(" ");
-#if ALLOC == AUTO
- fp_print(fp_prime_get());
-#else
- fp_print((const fp_t)fp_prime_get());
-#endif
+ bn_print(&(core_get()->prime));
}
diff --git a/src/fp/relic_fp_prime.c b/src/fp/relic_fp_prime.c
index 44335f3bd..c18319e98 100644
--- a/src/fp/relic_fp_prime.c
+++ b/src/fp/relic_fp_prime.c
@@ -48,6 +48,7 @@ static void fp_prime_set(const bn_t p) {
bn_t t;
fp_t r;
ctx_t *ctx = core_get();
+ dig_t rem;
if (p->used != RLC_FP_DIGS) {
RLC_THROW(ERR_NO_VALID);
@@ -101,7 +102,7 @@ static void fp_prime_set(const bn_t p) {
#if FP_RDC == MONTY
-#if (FP_PRIME % WSIZE) != 0
+#ifdef RLC_FP_ROOM
fp_mul(ctx->inv.dp, ctx->inv.dp, ctx->conv.dp);
fp_mul(ctx->inv.dp, ctx->inv.dp, ctx->conv.dp);
@@ -129,40 +130,60 @@ static void fp_prime_set(const bn_t p) {
break;
case 7:
ctx->qnr = -1;
+ /* Try this one, pick another later if not a CNR. */
ctx->cnr = -2;
- /* TODO: implement cube root to handle this better. */
-#if FP_PRIME == 638
- ctx->cnr = -3;
-#endif
break;
case 1:
case 5:
ctx->qnr = -2;
ctx->cnr = 2;
- /* TODO: implement cube root to handle this better. */
#if FP_PRIME == 638
- ctx->qnr = -6;
- ctx->cnr = 3;
+ if (fp_param_get() == K18_638) {
+ ctx->qnr = -6;
+ } else {
+ ctx->qnr = -7;
+ }
#endif
+ break;
+ }
- /* Check if it is a quadratic non-residue or find another. */
- fp_set_dig(r, -ctx->qnr);
+ /* Check if qnr is a quadratic non-residue or find another. */
+ fp_set_dig(r, -ctx->qnr);
+ fp_neg(r, r);
+ while (fp_is_sqr(r)) {
+ ctx->qnr--;
+ fp_set_dig(r, -ctx->qnr);
+ fp_neg(r, r);
+ };
+
+ /* Check if cnr is a cubic non-residue or find another. */
+ if (ctx->mod18 % 3 == 1) {
+ if (ctx->cnr > 0) {
+ fp_set_dig(r, ctx->cnr);
+ while (fp_is_cub(r)) {
+ ctx->cnr++;
+ fp_set_dig(r, ctx->cnr);
+ };
+ } else {
+ fp_set_dig(r, -ctx->cnr);
fp_neg(r, r);
- while (fp_srt(r, r) == 1) {
- ctx->qnr--;
- fp_set_dig(r, -ctx->qnr);
+ while (fp_is_cub(r)) {
+ ctx->cnr--;
+ fp_set_dig(r, -ctx->cnr);
fp_neg(r, r);
- /* We cannot guarantee a cubic extension anymore. */
- ctx->cnr = 0;
};
- break;
+ }
+ } else {
+ ctx->cnr = 0;
}
+
#ifdef FP_QNRES
if (ctx->mod8 != 3) {
RLC_THROW(ERR_NO_VALID);
}
#endif
+ /* Compute root of unity by computing QNR to (p - 1)/2^f. */
ctx->ad2 = 0;
bn_sub_dig(t, p, 1);
while (bn_is_even(t)) {
@@ -170,6 +191,30 @@ static void fp_prime_set(const bn_t p) {
bn_hlv(t, t);
}
+ ctx->srt.used = RLC_FP_DIGS;
+ if (ctx->qnr < 0) {
+ fp_set_dig(ctx->srt.dp, -ctx->qnr);
+ } else {
+ fp_set_dig(ctx->srt.dp, ctx->qnr);
+ }
+ fp_exp(ctx->srt.dp, ctx->srt.dp, t);
+
+ /* Write p - 1 as (e * 3^f), with e = 3l \pm 1. */
+ bn_sub_dig(t, p, 1);
+ bn_mod_dig(&rem, t, 3);
+ while (rem == 0) {
+ bn_div_dig(t, t, 3);
+ bn_mod_dig(&rem, t, 3);
+ }
+
+ /* Compute root of unity by computing CNR to (p - 1)/3^f. */
+ if (ctx->cnr < 0) {
+ fp_set_dig(ctx->crt.dp, -fp_prime_get_cnr());
+ } else {
+ fp_set_dig(ctx->crt.dp, fp_prime_get_cnr());
+ }
+ fp_exp(ctx->crt.dp, ctx->crt.dp, t);
+
fp_prime_calc();
}
RLC_CATCH_ANY {
@@ -201,6 +246,8 @@ void fp_prime_init(void) {
#if FP_INV == JUMPDS || !defined(STRIP)
bn_make(&(ctx->inv), RLC_FP_DIGS);
#endif /* FP_INV */
+ bn_make(&(ctx->srt), RLC_FP_DIGS);
+ bn_make(&(ctx->crt), RLC_FP_DIGS);
}
void fp_prime_clean(void) {
@@ -218,6 +265,8 @@ void fp_prime_clean(void) {
#if FP_INV == JUMPDS || !defined(STRIP)
bn_clean(&(ctx->inv));
#endif /* FP_INV */
+ bn_clean(&(ctx->srt));
+ bn_clean(&(ctx->crt));
bn_clean(&(ctx->prime));
bn_clean(&(ctx->par));
}
@@ -276,6 +325,14 @@ const dig_t *fp_prime_get_conv(void) {
#endif
}
+const dig_t *fp_prime_get_srt(void) {
+ return core_get()->srt.dp;
+}
+
+const dig_t *fp_prime_get_crt(void) {
+ return core_get()->crt.dp;
+}
+
dig_t fp_prime_get_mod8(void) {
return core_get()->mod8;
}
@@ -354,29 +411,69 @@ void fp_prime_set_pairf(const bn_t x, int pairf) {
bn_add(p, p, t0);
fp_prime_set_dense(p);
break;
- case EP_OT8:
- /* p = (x^8 + x^6 + 5*x^4 + x^2 + 4*x + 4) / 4. */
- bn_set_dig(p, 4);
- bn_mul_dig(t1, t0, 4);
- bn_add(p, p, t1);
- bn_sqr(t0, t0);
- bn_add(p, p, t0);
- bn_sqr(t1, t0);
- bn_add(p, p, t1);
- bn_add(p, p, t1);
- bn_add(p, p, t1);
- bn_add(p, p, t1);
- bn_add(p, p, t1);
- bn_mul(t1, t1, t0);
- bn_add(p, p, t1);
- bn_mul(t1, t1, t0);
- bn_add(p, p, t1);
+ case EP_N16:
+ /* p = (x^16 + 2*x^13 + x^10 + 5*x^8 + 6*x^5 + x^2 + 4)/4 */
+ bn_sqr(p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 2);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 1);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 5);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 6);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 1);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 4);
bn_div_dig(p, p, 4);
fp_prime_set_dense(p);
break;
+ case EP_K16:
+ /* p = (u^10 + 2*u^9 + 5*u^8 + 48*u^6 + 152*u^5 + 240*u^4 +
+ 625*u^2 + 2398*u + 3125) div 980 */
+ bn_add_dig(p, t0, 2);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 5);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 48);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 152);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 240);
+ bn_mul(p, p, t0);
+ bn_mul(p, p, t0);
+ bn_add_dig(p, p, 256);
+ bn_add_dig(p, p, 256);
+ bn_add_dig(p, p, 113);
+ bn_mul(p, p, t0);
+ bn_set_dig(t1, 9);
+ bn_lsh(t1, t1, 8);
+ bn_add_dig(t1, t1, 94);
+ bn_add(p, p, t1);
+ bn_mul(p, p, t0);
+ bn_set_dig(t0, 12);
+ bn_lsh(t0, t0, 8);
+ bn_add_dig(t0, t0, 53);
+ bn_add(p, p, t0);
+ bn_set_dig(t1, 3);
+ bn_lsh(t1, t1, 8);
+ bn_add_dig(t1, t1, 212);
+ bn_div(p, p, t1);
+ fp_prime_set_dense(p);
+ break;
case EP_K18:
- /* (x^8 + 5x^7 + 7x^6 + 37x^5 + 188x^4 + 259x^3 + 343x^2 +
- 1763x + 2401)/21 */
+ /* p = (x^8 + 5x^7 + 7x^6 + 37x^5 + 188x^4 + 259x^3 + 343x^2 +
+ 1763x + 2401)/21 */
bn_add_dig(p, t0, 5);
bn_mul(p, p, t0);
bn_add_dig(p, p, 7);
@@ -404,8 +501,8 @@ void fp_prime_set_pairf(const bn_t x, int pairf) {
fp_prime_set_dense(p);
break;
case EP_SG18:
- /* 243x^10 - 162x^8 + 81*x^7 + 27x^6 - 54x^5 + 9x^4 + 9x^3 -
- 3x^2 + 1 */
+ /* p = 243x^10 - 162x^8 + 81*x^7 + 27x^6 - 54x^5 + 9x^4 + 9x^3 -
+ 3x^2 + 1 */
bn_sqr(p, t0);
bn_mul_dig(p, p, 243);
bn_sub_dig(p, p, 162);
@@ -456,7 +553,8 @@ void fp_prime_set_pairf(const bn_t x, int pairf) {
fp_prime_set_dense(p);
break;
case EP_SG54:
- /* p = (1+3*x+3*x^2+(3^5)*x^9+(3^5)*x^10+(3^6)*x^10+(3^6)*x^11+(3^9)*x^18+(3^10)*x^19+(3^10)*x^20) */
+ /* p = (1+3*x+3*x^2+(3^5)*x^9+(3^5)*x^10+(3^6)*x^10+(3^6)*x^11+
+ (3^9)*x^18+(3^10)*x^19+(3^10)*x^20) */
bn_set_dig(p, 1);
bn_mul_dig(t1, t0, 3);
bn_add(p, p, t1);
@@ -577,6 +675,7 @@ void fp_prime_calc(void) {
if (fp_prime_get_qnr() != 0) {
fp2_field_init();
fp4_field_init();
+ fp8_field_init();
}
if (fp_prime_get_cnr() != 0) {
fp3_field_init();
diff --git a/src/fp/relic_fp_smb.c b/src/fp/relic_fp_smb.c
index ee42147a5..54a4c42ad 100644
--- a/src/fp/relic_fp_smb.c
+++ b/src/fp/relic_fp_smb.c
@@ -33,6 +33,98 @@
#include "relic_bn_low.h"
#include "relic_fp_low.h"
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+#if FP_SMB == JMPDS || !defined(STRIP)
+
+/**
+ * Conditionally negate a digit vector using two's complement representation.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the digit vector to conditionally negate.
+ * @param[in] sa - the sign of the digit vector.
+ * @param[in] n - the number of digits to conditionally negate.
+ */
+static void bn_negs_low(dig_t c[], const dig_t a[], dig_t sa, size_t n) {
+ dig_t carry = sa & 1;
+
+ sa = -sa;
+ for (int i = 0; i < n; i++) {
+ c[i] = (a[i] ^ sa) + carry;
+ carry = (c[i] < carry);
+ }
+}
+
+static dis_t jumpdivstep(dis_t m[4], dig_t *k, dis_t delta, dis_t y, dis_t x,
+ int s) {
+ dig_t d0, t0, t1, t2, c0, c1, yi, ai = 1, bi = 0, ci = 0, di = 1, u = 0;
+
+ /* Unrolling twice makes it faster. */
+ for (s -= 2; s >= 0; s -= 2) {
+ yi = y;
+
+ d0 = (delta >= 0);
+ c1 = -(x & 1);
+ c0 = (-d0) & c1;
+
+ t0 = (y ^ -d0) + d0;
+ t1 = (ci ^ -d0) + d0;
+ t2 = (di ^ -d0) + d0;
+ x += t0 & c1;
+ ai += t1 & c1;
+ bi += t2 & c1;
+
+ /* delta = RLC_SEL(delta + 1, -delta, c0) */
+ y += x & c0;
+ ci += ai & c0;
+ di += bi & c0;
+
+ x >>= 1;
+ ci <<= 1;
+ di <<= 1;
+ delta = (delta ^ c0) + 1;
+
+ u += ((yi & y) ^ (y >> 1)) & 2;
+ u += (u & 1) ^ RLC_SIGN(ci);
+
+ yi = y;
+
+ d0 = (delta >= 0);
+ c1 = -(x & 1);
+ c0 = (-d0) & c1;
+
+ t0 = (y ^ -d0) + d0;
+ t1 = (ci ^ -d0) + d0;
+ t2 = (di ^ -d0) + d0;
+ x += t0 & c1;
+ ai += t1 & c1;
+ bi += t2 & c1;
+
+ /* delta = RLC_SEL(delta + 1, -delta, c0) */
+ y += x & c0;
+ ci += ai & c0;
+ di += bi & c0;
+
+ x >>= 1;
+ ci <<= 1;
+ di <<= 1;
+ delta = (delta ^ c0) + 1;
+
+ u += ((yi & y) ^ (y >> 1)) & 2;
+ u += (u & 1) ^ RLC_SIGN(ci);
+ }
+ m[0] = ai;
+ m[1] = bi;
+ m[2] = ci;
+ m[3] = di;
+ *k = u;
+ return delta;
+}
+
+#endif
+
/*============================================================================*/
/* Public definitions */
/*============================================================================*/
@@ -76,13 +168,14 @@ int fp_smb_basic(const fp_t a) {
int fp_smb_divst(const fp_t a) {
/* Compute number of iterations based on modulus size. */
#if FP_PRIME < 46
- int r, d = (49 * FP_PRIME + 80)/17;
+ const int d = (49 * FP_PRIME + 80) / 17;
#else
- int r, d = (49 * FP_PRIME + 57)/17;
+ const int d = (49 * FP_PRIME + 57) / 17;
#endif
dig_t delta = 1, g0, d0, fs, gs, k, mask, s;
bn_t _t;
dv_t f, g, t;
+ int r = 0;
bn_null(_t);
dv_null(f);
@@ -114,8 +207,6 @@ int fp_smb_divst(const fp_t a) {
d0 = g[0] & ((int)delta > 0);
/* Conditionally negate delta if d0 is set. */
delta = (delta ^ -d0) + d0;
- k ^= (((g[0] >> (dig_t)1) & ((f[0] >> (dig_t)1) ^ 1)) ^ (~fs & gs)) & d0;
-
/* Conditionally swap and negate based on d0. */
mask = -d0;
s = (fs ^ gs) & mask;
@@ -128,6 +219,7 @@ int fp_smb_divst(const fp_t a) {
}
fp_add1_low(g, g, d0);
+ k ^= (((g[0] & f[0]) >> (dig_t)1) ^ (fs & gs)) & d0;
k ^= (f[0] >> 1) ^ (f[0] >> 2);
k &= 1;
@@ -145,16 +237,18 @@ int fp_smb_divst(const fp_t a) {
g[RLC_FP_DIGS - 1] |= (dig_t)gs << (RLC_DIG - 1);
}
+ k = (2*k) % 4;
+ fp_zero(t);
+ t[0] = 1;
for (int j = 0; j < RLC_FP_DIGS; j++) {
- t[j] = 0;
f[j] ^= -fs;
}
- t[0] = 1;
fp_add1_low(f, f, fs);
- r = !(dv_cmp_const(f, t, RLC_FP_DIGS) == RLC_NE);
- r = RLC_SEL(r, -1, (r == 1 && k == 1));
- r = RLC_SEL(r, 1, (r == 1 && k == 0));
+ r = RLC_SEL(r, 1 - k, dv_cmp_const(f, t, RLC_FP_DIGS) == RLC_EQ);
+ bn_negs_low(t, t, 1, RLC_FP_DIGS);
+ r = RLC_SEL(r, 1 - k, dv_cmp_const(f, t, RLC_FP_DIGS) == RLC_EQ);
+ r = RLC_SEL(r, 1 - k, fp_is_zero(f));
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT)
} RLC_FINALLY {
@@ -170,146 +264,101 @@ int fp_smb_divst(const fp_t a) {
#if FP_SMB == JMPDS || !defined(STRIP)
-static dis_t jumpdivstep(dis_t m[4], dig_t *k, dis_t delta, dis_t x, dis_t y, int s) {
- dig_t c0, c1, yi, ai = 1, bi = 0, ci = 0, di = 1, u = 0;
- for (; s > 0; s--) {
- yi = y;
-
- c0 = ~(delta >> (RLC_DIG - 1));
- c1 = -(x & 1);
- c0 &= c1;
-
- x += ((y ^ c0) - c0) & c1;
- ai += ((ci ^ c0) - c0) & c1;
- bi += ((di ^ c0) - c0) & c1;
-
- /* delta = RLC_SEL(delta + 1, -delta, c0) */
- delta = (delta ^ c0) + 1;
- y = y + (x & c0);
- ci = ci + (ai & c0);
- di = di + (bi & c0);
- x >>= 1;
- ci += ci;
- di += di;
-
- u += ((yi & y) ^ (y >> (dig_t)1)) & 2;
- u += (u & (dig_t)1) ^ (ci >> (dig_t)(RLC_DIG - 1));
- u %= 4;
- }
- m[0] = ai;
- m[1] = bi;
- m[2] = ci;
- m[3] = di;
- *k = u;
- return delta;
-}
-
int fp_smb_jmpds(const fp_t a) {
dis_t m[4], d = 0;
- int r, i, s = RLC_DIG - 2;
/* Iterations taken directly from https://github.com/sipa/safegcd-bounds */
- int loops, iterations = (45907 * FP_PRIME + 26313) / 19929;
- dv_t f, g, t, p, t0, t1, u0, u1, v0, v1, p01, p11;
- dig_t j, k, mask = RLC_MASK(s + 2);
+ const int iterations = (45907 * FP_PRIME + 26313) / 19929;
+ int loops, precision, i, r = 0, s = RLC_DIG - 2;
+ dv_t f, g, t0, t1, u0, u1;
+ dig_t sf, sg, j, k;
dv_null(f);
dv_null(g);
- dv_null(t);
- dv_null(p);
dv_null(t0);
dv_null(t1);
dv_null(u0);
dv_null(u1);
- dv_null(v0);
- dv_null(v1);
- dv_null(p01);
- dv_null(p11);
RLC_TRY {
- dv_new(t0);
dv_new(f);
- dv_new(t);
- dv_new(p);
dv_new(g);
+ dv_new(t0);
dv_new(t1);
dv_new(u0);
dv_new(u1);
- dv_new(v0);
- dv_new(v1);
- dv_new(p01);
- dv_new(p11);
-
- f[RLC_FP_DIGS] = g[RLC_FP_DIGS] = 0;
- dv_zero(f, 2 * RLC_FP_DIGS);
- dv_zero(g, 2 * RLC_FP_DIGS);
- dv_zero(t, 2 * RLC_FP_DIGS);
- dv_zero(p, 2 * RLC_FP_DIGS);
- dv_zero(u0, 2 * RLC_FP_DIGS);
- dv_zero(u1, 2 * RLC_FP_DIGS);
- dv_zero(v0, 2 * RLC_FP_DIGS);
- dv_zero(v1, 2 * RLC_FP_DIGS);
-
- dv_copy(g, fp_prime_get(), RLC_FP_DIGS);
+
+ dv_copy(f, fp_prime_get(), RLC_FP_DIGS);
+ f[RLC_FP_DIGS] = 0;
+ dv_zero(g, RLC_FP_DIGS + 1);
+ dv_zero(t0 + RLC_FP_DIGS, RLC_FP_DIGS);
+
#if FP_RDC == MONTY
/* Convert a from Montgomery form. */
- fp_copy(t, a);
- fp_rdcn_low(f, t);
+ fp_copy(t0, a);
+ fp_rdcn_low(g, t0);
#else
- fp_copy(f, a);
+ fp_copy(g, a);
#endif
-
+ precision = RLC_FP_DIGS;
loops = iterations / s;
loops = (iterations % s == 0 ? loops - 1 : loops);
- j = k = 0;
- for (i = 0; i <= loops; i++) {
- d = jumpdivstep(m, &k, d, f[0] & mask, g[0] & mask, s);
-
- t0[RLC_FP_DIGS] = bn_muls_low(t0, f, f[RLC_FP_DIGS] >> (RLC_DIG - 1), m[0], RLC_FP_DIGS);
- t1[RLC_FP_DIGS] = bn_muls_low(t1, g, g[RLC_FP_DIGS] >> (RLC_DIG - 1), m[1], RLC_FP_DIGS);
- bn_addn_low(t0, t0, t1, RLC_FP_DIGS + 1);
+ for (i = j = k = 0; i < loops; i++) {
+ d = jumpdivstep(m, &k, d, f[0], g[0], s);
- f[RLC_FP_DIGS] = bn_muls_low(f, f, f[RLC_FP_DIGS] >> (RLC_DIG - 1), m[2], RLC_FP_DIGS);
- t1[RLC_FP_DIGS] = bn_muls_low(t1, g, g[RLC_FP_DIGS] >> (RLC_DIG - 1), m[3], RLC_FP_DIGS);
- bn_addn_low(t1, t1, f, RLC_FP_DIGS + 1);
+ sf = RLC_SIGN(f[precision]);
+ sg = RLC_SIGN(g[precision]);
+ bn_negs_low(u0, f, sf, precision);
+ bn_negs_low(u1, g, sg, precision);
+
+ t0[precision] = bn_muls_low(t0, u0, sf, m[3], precision);
+ t1[precision] = bn_muls_low(t1, u1, sg, m[2], precision);
+ bn_addn_low(t0, t0, t1, precision + 1);
+ bn_rshs_low(f, t0, precision + 1, s);
- /* Update f and g. */
- bn_rshs_low(f, t0, RLC_FP_DIGS + 1, s);
- bn_rshs_low(g, t1, RLC_FP_DIGS + 1, s);
+ t0[precision] = bn_muls_low(t0, u0, sf, m[1], precision);
+ t1[precision] = bn_muls_low(t1, u1, sg, m[0], precision);
+ bn_addn_low(t1, t1, t0, precision + 1);
+ bn_rshs_low(g, t1, precision + 1, s);
j = (j + k) % 4;
- j = (j + ((j & 1) ^ (g[RLC_FP_DIGS] >> (RLC_DIG - 1)))) % 4;
+ j = (j + ((j & 1) ^ (RLC_SIGN(f[precision])))) % 4;
}
- r = 0;
+ s = iterations - loops * s;
+ d = jumpdivstep(m, &k, d, f[0], g[0], s);
+
+ sf = RLC_SIGN(f[precision]);
+ sg = RLC_SIGN(g[precision]);
+ bn_negs_low(u0, f, sf, precision);
+ bn_negs_low(u1, g, sg, precision);
+
+ t0[precision] = bn_muls_low(t0, u0, sf, m[3], precision);
+ t1[precision] = bn_muls_low(t1, u1, sg, m[2], precision);
+ bn_addn_low(t0, t0, t1, precision + 1);
+ bn_rshs_low(f, t0, precision + 1, s);
+
+ j = (j + k) % 4;
+ j = (j + ((j & 1) ^ (RLC_SIGN(f[precision])))) % 4;
j = (j + (j & 1)) % 4;
fp_zero(t0);
+ r = RLC_SEL(r, 1 - j, dv_cmp_const(f, t0, RLC_FP_DIGS) == RLC_EQ);
t0[0] = 1;
- r = RLC_SEL(r, 1 - j, dv_cmp_const(g, t0, RLC_FP_DIGS) == RLC_EQ);
- for (i = 0; i < RLC_FP_DIGS; i++) {
- g[i] = ~g[i];
- }
- bn_add1_low(g, g, 1, RLC_FP_DIGS);
- r = RLC_SEL(r, 1 - j, dv_cmp_const(g, t0, RLC_FP_DIGS) == RLC_EQ);
- r = RLC_SEL(r, 1 - j, fp_is_zero(g));
+ r = RLC_SEL(r, 1 - j, dv_cmp_const(f, t0, RLC_FP_DIGS) == RLC_EQ);
+ bn_negs_low(t0, t0, 1, RLC_FP_DIGS);
+ r = RLC_SEL(r, 1 - j, dv_cmp_const(f, t0, RLC_FP_DIGS) == RLC_EQ);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
- dv_free(t0);
dv_free(f);
- dv_free(t);
- dv_free(p);
dv_free(g);
+ dv_free(t0);
dv_free(t1);
dv_free(u0);
dv_free(u1);
- dv_free(v0);
- dv_free(v1);
- dv_free(p01);
- dv_free(p11);
}
return r;
diff --git a/src/fp/relic_fp_srt.c b/src/fp/relic_fp_srt.c
index 31bd0a765..c5656be1c 100644
--- a/src/fp/relic_fp_srt.c
+++ b/src/fp/relic_fp_srt.c
@@ -35,15 +35,24 @@
/* Public definitions */
/*============================================================================*/
+int fp_is_sqr(const fp_t a) {
+ if (fp_is_zero(a)) {
+ return 1;
+ }
+
+ return (fp_smb(a) == 1);
+}
+
int fp_srt(fp_t c, const fp_t a) {
bn_t e;
- fp_t t0;
- fp_t t1;
- int r = 0;
+ fp_t t0, t1, t2, t3;
+ int f = 0, r = 0;
bn_null(e);
fp_null(t0);
fp_null(t1);
+ fp_null(t2);
+ fp_null(t3);
if (fp_is_zero(a)) {
fp_zero(c);
@@ -54,75 +63,64 @@ int fp_srt(fp_t c, const fp_t a) {
bn_new(e);
fp_new(t0);
fp_new(t1);
+ fp_new(t2);
+ fp_new(t3);
/* Make e = p. */
e->used = RLC_FP_DIGS;
dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
- if (fp_prime_get_mod8() == 3 || fp_prime_get_mod8() == 7) {
- /* Easy case, compute a^((p + 1)/4). */
- bn_add_dig(e, e, 1);
- bn_rsh(e, e, 2);
-
- fp_exp(t0, a, e);
- fp_sqr(t1, t0);
- r = (fp_cmp(t1, a) == RLC_EQ);
- fp_copy(c, t0);
- } else {
- int f = 0, m = 0;
-
- /* First, check if there is a root. Compute t1 = a^((p - 1)/2). */
- bn_rsh(e, e, 1);
- fp_exp(t0, a, e);
-
- if (fp_cmp_dig(t0, 1) != RLC_EQ) {
- /* Nope, there is no square root. */
- r = 0;
- } else {
- r = 1;
- /* Find a quadratic non-residue modulo p, that is a number t2
- * such that (t2 | p) = t2^((p - 1)/2)!= 1. */
- do {
- fp_rand(t1);
- fp_exp(t0, t1, e);
- } while (fp_cmp_dig(t0, 1) == RLC_EQ);
+ switch(fp_prime_get_mod8() % 4) {
+ case 3:
+ /* Easy case, compute a^((p + 1)/4). */
+ bn_add_dig(e, e, 1);
+ bn_rsh(e, e, 2);
- /* Write p - 1 as (e * 2^f), odd e. */
- bn_lsh(e, e, 1);
- while (bn_is_even(e)) {
- bn_rsh(e, e, 1);
- f++;
- }
+ fp_exp(t0, a, e);
+ fp_sqr(t1, t0);
+ r = (fp_cmp(t1, a) == RLC_EQ);
+ fp_copy(c, t0);
+ break;
+ default:
+ /* Implement constant-time version of Tonelli-Shanks algorithm
+ * as per https://eprint.iacr.org/2020/1497.pdf */
- /* Compute t2 = t2^e. */
- fp_exp(t1, t1, e);
+ /* First check that a is a square. */
+ r = fp_is_sqr(a);
- /* Compute t1 = a^e, c = a^((e + 1)/2) = a^(e/2 + 1), odd e. */
+ /* Compute progenitor as x^(p-1-2^f)/2^(f+1) where 2^f|(p-1). */
+
+ /* Write p - 1 as (e * 2^f), odd e. */
+ f = fp_prime_get_2ad();
+ bn_rsh(e, e, f);
+
+ /* Make it e = (p - 1 - 2^f)/2^(f + 1), compute t0 = a^e. */
bn_rsh(e, e, 1);
fp_exp(t0, a, e);
- fp_mul(e->dp, t0, a);
- fp_sqr(t0, t0);
- fp_mul(t0, t0, a);
- fp_copy(c, e->dp);
-
- while (1) {
- if (fp_cmp_dig(t0, 1) == RLC_EQ) {
- break;
- }
- fp_copy(e->dp, t0);
- for (m = 0; (m < f) && (fp_cmp_dig(t0, 1) != RLC_EQ); m++) {
- fp_sqr(t0, t0);
- }
- fp_copy(t0, e->dp);
- for (int i = 0; i < f - m - 1; i++) {
- fp_sqr(t1, t1);
+
+ /* Recover 2^f-root of unity, and continue algorithm. */
+ fp_copy(t3, fp_prime_get_srt());
+
+ fp_sqr(t1, t0);
+ fp_mul(t1, t1, a);
+ fp_mul(c, t0, a);
+ for (int j = f; j > 1; j--) {
+ fp_copy(t2, t1);
+ for (int i = 1; i < j - 1; i++) {
+ fp_sqr(t2, t2);
}
- fp_mul(c, c, t1);
- fp_sqr(t1, t1);
- fp_mul(t0, t0, t1);
- f = m;
+ fp_mul(t0, c, t3);
+ dv_copy_cond(c, t0, RLC_FP_DIGS,
+ fp_cmp_dig(t2, 1) != RLC_EQ);
+ fp_sqr(t3, t3);
+ fp_mul(t0, t1, t3);
+ dv_copy_cond(t1, t0, RLC_FP_DIGS,
+ fp_cmp_dig(t2, 1) != RLC_EQ);
}
- }
+
+ fp_neg(t0, c);
+ dv_copy_cond(c, t0, RLC_FP_DIGS, fp_is_even(c) == 0);
+ break;
}
}
RLC_CATCH_ANY {
@@ -132,6 +130,8 @@ int fp_srt(fp_t c, const fp_t a) {
bn_free(e);
fp_free(t0);
fp_free(t1);
+ fp_free(t2);
+ fp_free(t3);
}
return r;
}
diff --git a/src/fp/relic_fp_util.c b/src/fp/relic_fp_util.c
index 4626b528e..86304f2fe 100644
--- a/src/fp/relic_fp_util.c
+++ b/src/fp/relic_fp_util.c
@@ -60,10 +60,24 @@ int fp_is_zero(const fp_t a) {
}
int fp_is_even(const fp_t a) {
- if ((a[0] & 0x01) == 0) {
- return 1;
+ int r;
+ bn_t t;
+
+ bn_null(t);
+
+ RLC_TRY {
+ bn_new(t);
+
+ fp_prime_back(t, a);
+ r = bn_is_even(t);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
}
- return 0;
+ RLC_FINALLY {
+ bn_free(t);
+ }
+
+ return r;
}
int fp_get_bit(const fp_t a, uint_t bit) {
diff --git a/src/fpx/relic_fp16_mul.c b/src/fpx/relic_fp16_mul.c
new file mode 100644
index 000000000..d2ce1447a
--- /dev/null
+++ b/src/fpx/relic_fp16_mul.c
@@ -0,0 +1,321 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 4.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 4.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of multiplication in an sextadecic extension of a prime field.
+ *
+ * @ingroup fpx
+ */
+
+#include "relic_core.h"
+#include "relic_fp_low.h"
+#include "relic_fpx_low.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if FPX_RDC == BASIC || !defined(STRIP)
+
+void fp16_mul_basic(fp16_t c, const fp16_t a, const fp16_t b) {
+ fp8_t t0, t1, t4;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t4);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t4);
+
+ /* Karatsuba algorithm. */
+
+ /* t0 = a_0 * b_0. */
+ fp8_mul(t0, a[0], b[0]);
+ /* t1 = a_1 * b_1. */
+ fp8_mul(t1, a[1], b[1]);
+ /* t4 = b_0 + b_1. */
+ fp8_add(t4, b[0], b[1]);
+
+ /* c_1 = a_0 + a_1. */
+ fp8_add(c[1], a[0], a[1]);
+
+ /* c_1 = (a_0 + a_1) * (b_0 + b_1) */
+ fp8_mul(c[1], c[1], t4);
+ fp8_sub(c[1], c[1], t0);
+ fp8_sub(c[1], c[1], t1);
+
+ /* c_0 = a_0b_0 + v * a_1b_1. */
+ fp8_mul_art(t4, t1);
+ fp8_add(c[0], t0, t4);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t4);
+ }
+}
+
+void fp16_mul_dxs_basic(fp16_t c, const fp16_t a, const fp16_t b) {
+ fp8_t t0, t1, t4;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t4);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t4);
+
+ /* Karatsuba algorithm. */
+
+ /* t0 = a_0 * b_0. */
+ fp8_mul(t0, a[0], b[0]);
+
+ /* t1 = a_1 * b_1. */
+ fp4_mul(t1[0], a[1][1], b[1][1]);
+ fp4_add(t1[1], a[1][0], a[1][1]);
+ fp4_mul(t1[1], t1[1], b[1][1]);
+ fp4_sub(t1[1], t1[1], t1[0]);
+ fp4_mul_art(t1[0], t1[0]);
+
+ /* t4 = b_0 + b_1. */
+ fp8_add(t4, b[0], b[1]);
+
+ /* c_1 = a_0 + a_1. */
+ fp8_add(c[1], a[0], a[1]);
+
+ /* c_1 = (a_0 + a_1) * (b_0 + b_1) */
+ fp8_mul(c[1], c[1], t4);
+ fp8_sub(c[1], c[1], t0);
+ fp8_sub(c[1], c[1], t1);
+
+ /* c_0 = a_0b_0 + v * a_1b_1. */
+ fp8_mul_art(t4, t1);
+ fp8_add(c[0], t0, t4);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t4);
+ }
+}
+
+#endif
+
+#if PP_EXT == LAZYR || !defined(STRIP)
+
+void fp16_mul_unr(dv16_t c, const fp16_t a, const fp16_t b) {
+ fp8_t t0, t1;
+ dv8_t u0, u1, u2, u3;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ dv8_null(u0);
+ dv8_null(u1);
+ dv8_null(u2);
+ dv8_null(u3);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ dv8_new(u0);
+ dv8_new(u1);
+ dv8_new(u2);
+ dv8_new(u3);
+
+ /* Karatsuba algorithm. */
+
+ /* u0 = a_0 * b_0. */
+ fp8_mul_unr(u0, a[0], b[0]);
+ /* u1 = a_1 * b_1. */
+ fp8_mul_unr(u1, a[1], b[1]);
+ /* t1 = a_0 + a_1. */
+ fp8_add(t0, a[0], a[1]);
+ /* t0 = b_0 + b_1. */
+ fp8_add(t1, b[0], b[1]);
+ /* u2 = (a_0 + a_1) * (b_0 + b_1) */
+ fp8_mul_unr(u2, t0, t1);
+ /* c_1 = u2 - a_0b_0 - a_1b_1. */
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ fp2_subc_low(c[1][i][j], u2[i][j], u0[i][j]);
+ fp2_subc_low(c[1][i][j], c[1][i][j], u1[i][j]);
+ }
+ }
+ /* c_0 = a_0b_0 + v * a_1b_1. */
+ fp2_nord_low(u2[0][0], u1[1][1]);
+ dv_copy(u2[0][1][0], u1[1][0][0], 2 * RLC_FP_DIGS);
+ dv_copy(u2[0][1][1], u1[1][0][1], 2 * RLC_FP_DIGS);
+ dv_copy(u2[1][0][0], u1[0][0][0], 2 * RLC_FP_DIGS);
+ dv_copy(u2[1][0][1], u1[0][0][1], 2 * RLC_FP_DIGS);
+ dv_copy(u2[1][1][0], u1[0][1][0], 2 * RLC_FP_DIGS);
+ dv_copy(u2[1][1][1], u1[0][1][1], 2 * RLC_FP_DIGS);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ fp2_addc_low(c[0][i][j], u0[i][j], u2[i][j]);
+ }
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ dv8_free(u0);
+ dv8_free(u1);
+ dv8_free(u2);
+ dv8_free(u3);
+ }
+}
+
+void fp16_mul_lazyr(fp16_t c, const fp16_t a, const fp16_t b) {
+ dv16_t t;
+
+ dv16_null(t);
+
+ RLC_TRY {
+ dv16_new(t);
+ fp16_mul_unr(t, a, b);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ fp2_rdcn_low(c[i][j][k], t[i][j][k]);
+ }
+ }
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ dv16_free(t);
+ }
+}
+
+void fp16_mul_dxs_lazyr(fp16_t c, const fp16_t a, const fp16_t b) {
+ fp8_t t0, t1;
+ dv8_t u0, u1, u2, u3;
+ dv16_t t;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ dv8_null(u0);
+ dv8_null(u1);
+ dv8_null(u2);
+ dv8_null(u3);
+ dv16_null(t);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ dv8_new(u0);
+ dv8_new(u1);
+ dv8_new(u2);
+ dv8_new(u3);
+ dv16_new(t);
+
+ /* Karatsuba algorithm. */
+
+ /* u0 = a_0 * b_0. */
+ fp8_mul_unr(u0, a[0], b[0]);
+
+ /* u1 = a_1 * b_1. */
+ fp4_mul_unr(u1[0], a[1][1], b[1][1]);
+ fp4_add(t1[0], a[1][0], a[1][1]);
+ fp4_mul_unr(u1[1], t1[0], b[1][1]);
+ fp2_subc_low(u2[1][0], u1[1][0], u1[0][0]);
+ fp2_subc_low(u2[1][1], u1[1][1], u1[0][1]);
+ fp2_nord_low(u2[0][0], u1[0][1]);
+ dv_copy(u2[0][1][0], u1[0][0][0], 2 * RLC_FP_DIGS);
+ dv_copy(u2[0][1][1], u1[0][0][1], 2 * RLC_FP_DIGS);
+
+ /* t1 = a_0 + a_1. */
+ fp8_add(t0, a[0], a[1]);
+ /* t0 = b_0 + b_1. */
+ fp8_add(t1, b[0], b[1]);
+ /* u2 = (a_0 + a_1) * (b_0 + b_1) */
+ fp8_mul_unr(u1, t0, t1);
+ /* c_1 = u2 - a_0b_0 - a_1b_1. */
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ fp2_subc_low(t[1][i][j], u1[i][j], u0[i][j]);
+ fp2_subc_low(t[1][i][j], t[1][i][j], u2[i][j]);
+ }
+ }
+ /* c_0 = a_0b_0 + v * a_1b_1. */
+ fp2_nord_low(u1[0][0], u2[1][1]);
+ dv_copy(u1[0][1][0], u2[1][0][0], 2 * RLC_FP_DIGS);
+ dv_copy(u1[0][1][1], u2[1][0][1], 2 * RLC_FP_DIGS);
+ dv_copy(u1[1][0][0], u2[0][0][0], 2 * RLC_FP_DIGS);
+ dv_copy(u1[1][0][1], u2[0][0][1], 2 * RLC_FP_DIGS);
+ dv_copy(u1[1][1][0], u2[0][1][0], 2 * RLC_FP_DIGS);
+ dv_copy(u1[1][1][1], u2[0][1][1], 2 * RLC_FP_DIGS);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ fp2_addc_low(t[0][i][j], u0[i][j], u1[i][j]);
+ }
+ }
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ fp2_rdcn_low(c[i][j][k], t[i][j][k]);
+ }
+ }
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ dv8_free(u0);
+ dv8_free(u1);
+ dv8_free(u2);
+ dv8_free(u3);
+ dv16_free(t);
+ }
+}
+
+#endif
+
+void fp16_mul_art(fp16_t c, const fp16_t a) {
+ fp8_t t0;
+
+ fp8_null(t0);
+
+ RLC_TRY {
+ fp8_new(t0);
+
+ /* (a_0 + a_1 * v) * v = a_0 * v + a_1 * v^4 */
+ fp8_copy(t0, a[0]);
+ fp8_mul_art(c[0], a[1]);
+ fp8_copy(c[1], t0);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ }
+}
\ No newline at end of file
diff --git a/src/fpx/relic_fp16_sqr.c b/src/fpx/relic_fp16_sqr.c
new file mode 100644
index 000000000..8e6f180b3
--- /dev/null
+++ b/src/fpx/relic_fp16_sqr.c
@@ -0,0 +1,181 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of squaring in an sextadecic extension of a prime field.
+ *
+ * @ingroup fpx
+ */
+
+#include "relic_core.h"
+#include "relic_fp_low.h"
+#include "relic_fpx_low.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if FPX_RDC == BASIC || !defined(STRIP)
+
+void fp16_sqr_basic(fp16_t c, const fp16_t a) {
+ fp8_t t0, t1;
+
+ fp8_null(t0);
+ fp8_null(t1);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+
+ fp8_add(t0, a[0], a[1]);
+ fp8_mul_art(t1, a[1]);
+ fp8_add(t1, a[0], t1);
+ fp8_mul(t0, t0, t1);
+ fp8_mul(c[1], a[0], a[1]);
+ fp8_sub(c[0], t0, c[1]);
+ fp8_mul_art(t1, c[1]);
+ fp8_sub(c[0], c[0], t1);
+ fp8_dbl(c[1], c[1]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ }
+}
+
+#endif
+
+#if PP_EXT == LAZYR || !defined(STRIP)
+
+void fp16_sqr_unr(dv16_t c, const fp16_t a) {
+ fp8_t t;
+ dv8_t u0, u1, u2;
+
+ fp8_null(t);
+ dv8_null(u0);
+ dv8_null(u1);
+ dv8_null(u2);
+
+ RLC_TRY {
+ fp8_new(t);
+ dv8_new(u0);
+ dv8_new(u1);
+ dv8_new(u2);
+
+ /* t0 = a^2. */
+ fp8_sqr_unr(u0, a[0]);
+ /* t1 = b^2. */
+ fp8_sqr_unr(u1, a[1]);
+
+ fp8_add(t, a[0], a[1]);
+
+ /* c = a^2 + b^2 * E. */
+ dv_copy(u2[1][0][0], u1[0][0][0], 2 * RLC_FP_DIGS);
+ dv_copy(u2[1][0][1], u1[0][0][1], 2 * RLC_FP_DIGS);
+ dv_copy(u2[1][1][0], u1[0][1][0], 2 * RLC_FP_DIGS);
+ dv_copy(u2[1][1][1], u1[0][1][1], 2 * RLC_FP_DIGS);
+ fp2_nord_low(u2[0][0], u1[1][1]);
+ dv_copy(u2[0][1][0], u1[1][0][0], 2 * RLC_FP_DIGS);
+ dv_copy(u2[0][1][1], u1[1][0][1], 2 * RLC_FP_DIGS);
+ fp2_addc_low(c[0][0][0], u2[0][0], u0[0][0]);
+ fp2_addc_low(c[0][0][1], u2[0][1], u0[0][1]);
+ fp2_addc_low(c[0][1][0], u2[1][0], u0[1][0]);
+ fp2_addc_low(c[0][1][1], u2[1][1], u0[1][1]);
+
+ /* d = (a + b)^2 - a^2 - b^2 = 2 * a * b. */
+ fp2_addc_low(u1[0][0], u1[0][0], u0[0][0]);
+ fp2_addc_low(u1[0][1], u1[0][1], u0[0][1]);
+ fp2_addc_low(u1[1][0], u1[1][0], u0[1][0]);
+ fp2_addc_low(u1[1][1], u1[1][1], u0[1][1]);
+
+ fp8_sqr_unr(u0, t);
+ fp2_subc_low(c[1][0][0], u0[0][0], u1[0][0]);
+ fp2_subc_low(c[1][0][1], u0[0][1], u1[0][1]);
+ fp2_subc_low(c[1][1][0], u0[1][0], u1[1][0]);
+ fp2_subc_low(c[1][1][1], u0[1][1], u1[1][1]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t);
+ dv8_free(u0);
+ dv8_free(u1);
+ dv8_free(u2);
+ }
+}
+
+void fp16_sqr_lazyr(fp16_t c, const fp16_t a) {
+ dv16_t t;
+
+ dv16_null(t);
+
+ RLC_TRY {
+ dv16_new(t);
+ fp16_sqr_unr(t, a);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ fp2_rdcn_low(c[i][j][k], t[i][j][k]);
+ }
+ }
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ dv16_free(t);
+ }
+}
+
+#endif
+
+void fp16_sqr_cyc(fp16_t c, const fp16_t a) {
+ fp8_t t0, t1, t2;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t2);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t2);
+
+ fp8_sqr(t0, a[1]);
+ fp8_add(t1, a[0], a[1]);
+ fp8_sqr(t2, t1);
+ fp8_sub(t2, t2, t0);
+ fp8_mul_art(c[0], t0);
+ fp8_sub(c[1], t2, c[0]);
+ fp8_dbl(c[0], c[0]);
+ fp_add_dig(c[0][0][0], c[0][0][0], 1);
+ fp_sub_dig(c[1][0][0], c[1][0][0], 1);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t2);
+ }
+}
diff --git a/src/fpx/relic_fp24_sqr.c b/src/fpx/relic_fp24_sqr.c
index 77c850f7e..cef7bacf5 100644
--- a/src/fpx/relic_fp24_sqr.c
+++ b/src/fpx/relic_fp24_sqr.c
@@ -362,7 +362,6 @@ void fp24_sqr_unr(dv24_t c, const fp24_t a) {
fp2_addc_low(c[1][0][j], u4[0][j], u3[0][j]);
fp2_addc_low(c[1][1][j], u2[0][j], u3[1][j]);
}
-
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
@@ -398,13 +397,191 @@ void fp24_sqr_lazyr(fp24_t c, const fp24_t a) {
}
void fp24_sqr_cyc_lazyr(fp24_t c, const fp24_t a) {
- /* TODO: implement lazy reduction. */
- fp24_sqr_cyc_basic(c, a);
+ fp4_t t0, t1, t2;
+ dv4_t u0, u1, u2, u3;
+
+ fp4_null(t0);
+ fp4_null(t1);
+ fp4_null(t2);
+ dv4_null(u0);
+ dv4_null(u1);
+ dv4_null(u2);
+ dv4_null(u3);
+
+ RLC_TRY {
+ fp4_new(t0);
+ fp4_new(t1);
+ fp4_new(t2);
+ dv4_new(u0);
+ dv4_new(u1);
+ dv4_new(u2);
+ dv4_new(u3);
+
+ fp4_sqr_unr(u2, a[0][0]);
+ fp4_sqr_unr(u3, a[0][1]);
+ fp4_add(t1, a[0][0], a[0][1]);
+
+ fp2_nord_low(u1[0], u3[1]);
+ fp2_addc_low(u0[0], u2[0], u1[0]);
+ fp2_addc_low(u0[1], u2[1], u3[0]);
+ fp2_rdcn_low(t0[0], u0[0]);
+ fp2_rdcn_low(t0[1], u0[1]);
+
+ fp4_sqr_unr(u1, t1);
+ fp2_subc_low(u1[0], u1[0], u2[0]);
+ fp2_subc_low(u1[1], u1[1], u2[1]);
+ fp2_subc_low(u1[0], u1[0], u3[0]);
+ fp2_subc_low(u1[1], u1[1], u3[1]);
+ fp2_rdcn_low(t1[0], u1[0]);
+ fp2_rdcn_low(t1[1], u1[1]);
+
+ fp4_sub(c[0][0], t0, a[0][0]);
+ fp4_add(c[0][0], c[0][0], c[0][0]);
+ fp4_add(c[0][0], t0, c[0][0]);
+
+ fp4_add(c[0][1], t1, a[0][1]);
+ fp4_add(c[0][1], c[0][1], c[0][1]);
+ fp4_add(c[0][1], t1, c[0][1]);
+
+ fp4_sqr_unr(u0, a[2][0]);
+ fp4_sqr_unr(u1, a[2][1]);
+ fp4_add(t1, a[2][0], a[2][1]);
+ fp4_sqr_unr(u2, t1);
+
+ for (int i = 0; i < 2; i++) {
+ fp2_addc_low(u3[i], u0[i], u1[i]);
+ fp2_subc_low(u3[i], u2[i], u3[i]);
+ fp2_rdcn_low(t1[i], u3[i]);
+ }
+
+ fp4_add(t0, a[1][0], a[1][1]);
+ fp4_sqr(t2, t0);
+ fp4_sqr_unr(u2, a[1][0]);
+
+ fp4_mul_art(t0, t1);
+ fp4_add(t1, t0, a[1][0]);
+ fp4_dbl(t1, t1);
+ fp4_add(c[1][0], t1, t0);
+
+ fp2_nord_low(u3[0], u1[1]);
+ fp2_addc_low(u3[0], u0[0], u3[0]);
+ fp2_addc_low(u3[1], u0[1], u1[0]);
+ fp4_sqr_unr(u1, a[1][1]);
+ fp2_rdcn_low(t1[0], u3[0]);
+ fp2_rdcn_low(t1[1], u3[1]);
+ fp4_sub(t0, t1, a[1][1]);
+ fp4_dbl(t0, t0);
+ fp4_add(c[1][1], t0, t1);
+
+ fp2_nord_low(u3[0], u1[1]);
+ fp2_addc_low(u3[0], u2[0], u3[0]);
+ fp2_addc_low(u3[1], u2[1], u1[0]);
+ fp2_rdcn_low(t1[0], u3[0]);
+ fp2_rdcn_low(t1[1], u3[1]);
+ fp4_sub(t0, t1, a[2][0]);
+ fp4_dbl(t0, t0);
+ fp4_add(c[2][0], t0, t1);
+
+ fp2_addc_low(u3[0], u2[0], u1[0]);
+ fp2_addc_low(u3[1], u2[1], u1[1]);
+ fp2_rdcn_low(t0[0], u3[0]);
+ fp2_rdcn_low(t0[1], u3[1]);
+ fp4_sub(t1, t2, t0);
+ fp4_add(t0, t1, a[2][1]);
+ fp4_dbl(t0, t0);
+ fp4_add(c[2][1], t1, t0);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp4_free(t0);
+ fp4_free(t1);
+ fp4_free(t2);
+ dv4_free(u0);
+ dv4_free(u1);
+ dv4_free(u2);
+ dv4_free(u3);
+ }
}
void fp24_sqr_pck_lazyr(fp24_t c, const fp24_t a) {
- /* TODO: implement lazy reduction. */
- fp24_sqr_pck_basic(c, a);
+ fp4_t t0, t1, t2;
+ dv4_t u0, u1, u2, u3;
+
+ fp4_null(t0);
+ fp4_null(t1);
+ fp4_null(t2);
+ dv4_null(u0);
+ dv4_null(u1);
+ dv4_null(u2);
+ dv4_null(u3);
+
+ RLC_TRY {
+ fp4_new(t0);
+ fp4_new(t1);
+ fp4_new(t2);
+ dv4_new(u0);
+ dv4_new(u1);
+ dv4_new(u2);
+ dv4_new(u3);
+
+ fp4_sqr_unr(u0, a[2][0]);
+ fp4_sqr_unr(u1, a[2][1]);
+ fp4_add(t1, a[2][0], a[2][1]);
+ fp4_sqr_unr(u2, t1);
+
+ for (int i = 0; i < 2; i++) {
+ fp2_addc_low(u3[i], u0[i], u1[i]);
+ fp2_subc_low(u3[i], u2[i], u3[i]);
+ fp2_rdcn_low(t1[i], u3[i]);
+ }
+
+ fp4_add(t0, a[1][0], a[1][1]);
+ fp4_sqr(t2, t0);
+ fp4_sqr_unr(u2, a[1][0]);
+
+ fp4_mul_art(t0, t1);
+ fp4_add(t1, t0, a[1][0]);
+ fp4_dbl(t1, t1);
+ fp4_add(c[1][0], t1, t0);
+
+ fp2_nord_low(u3[0], u1[1]);
+ fp2_addc_low(u3[0], u0[0], u3[0]);
+ fp2_addc_low(u3[1], u0[1], u1[0]);
+ fp4_sqr_unr(u1, a[1][1]);
+ fp2_rdcn_low(t1[0], u3[0]);
+ fp2_rdcn_low(t1[1], u3[1]);
+ fp4_sub(t0, t1, a[1][1]);
+ fp4_dbl(t0, t0);
+ fp4_add(c[1][1], t0, t1);
+
+ fp2_nord_low(u3[0], u1[1]);
+ fp2_addc_low(u3[0], u2[0], u3[0]);
+ fp2_addc_low(u3[1], u2[1], u1[0]);
+ fp2_rdcn_low(t1[0], u3[0]);
+ fp2_rdcn_low(t1[1], u3[1]);
+ fp4_sub(t0, t1, a[2][0]);
+ fp4_dbl(t0, t0);
+ fp4_add(c[2][0], t0, t1);
+
+ fp2_addc_low(u3[0], u2[0], u1[0]);
+ fp2_addc_low(u3[1], u2[1], u1[1]);
+ fp2_rdcn_low(t0[0], u3[0]);
+ fp2_rdcn_low(t0[1], u3[1]);
+ fp4_sub(t1, t2, t0);
+ fp4_add(t0, t1, a[2][1]);
+ fp4_dbl(t0, t0);
+ fp4_add(c[2][1], t1, t0);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp4_free(t0);
+ fp4_free(t1);
+ fp4_free(t2);
+ dv4_free(u0);
+ dv4_free(u1);
+ dv4_free(u2);
+ dv4_free(u3);
+ }
}
#endif
diff --git a/src/fpx/relic_fp3_mul.c b/src/fpx/relic_fp3_mul.c
index d02102bc9..88daea8a4 100644
--- a/src/fpx/relic_fp3_mul.c
+++ b/src/fpx/relic_fp3_mul.c
@@ -178,40 +178,43 @@ void fp3_mul_art(fp3_t c, const fp3_t a) {
}
void fp3_mul_nor(fp3_t c, const fp3_t a) {
- fp3_t t;
- bn_t b;
+ fp3_t t, u;
fp3_null(t);
- bn_null(b);
+ fp3_null(u);
RLC_TRY {
fp3_new(t);
- bn_new(b);
+ fp3_new(u);
- int cnr = fp3_field_get_cnr();
+ fp3_mul_art(t, a);
+ int cnr = fp3_field_get_cnr();
switch (fp_prime_get_mod18()) {
+ case 1:
case 7:
- /* If p = 7 mod 18, we choose (2^k + j) as a QNR/CNR. */
- fp3_mul_art(t, a);
- fp3_copy(c, a);
- while (cnr > 1) {
- fp3_dbl(c, c);
- cnr = cnr >> 1;
+ if (cnr != 0) {
+ fp3_copy(u, a);
+ while (cnr > 1) {
+ fp3_dbl(u, u);
+ if (cnr & 1) {
+ fp3_add(u, u, a);
+ }
+ cnr = cnr >> 1;
+ }
+ fp3_add(t, t, u);
}
- fp3_add(c, c, t);
- break;
- default:
- fp3_mul_art(c, a);
break;
}
+
+ fp3_copy(c, t);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
}
RLC_FINALLY {
fp3_free(t);
- bn_free(b);
+ fp3_free(u);
}
}
@@ -272,15 +275,15 @@ void fp3_mul_frb(fp3_t c, const fp3_t a, int i, int j) {
fp_copy(t[0], ctx->fp3_p1[j - 1][0]);
fp_copy(t[1], ctx->fp3_p1[j - 1][1]);
fp_copy(t[2], ctx->fp3_p1[j - 1][2]);
+ fp3_mul(c, c, t);
break;
case 2:
fp_copy(t[0], ctx->fp3_p2[j - 1][0]);
fp_copy(t[1], ctx->fp3_p2[j - 1][1]);
fp_copy(t[2], ctx->fp3_p2[j - 1][2]);
+ fp3_mul(c, c, t);
break;
}
-
- fp3_mul(c, c, t);
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
diff --git a/src/fpx/relic_fp48_mul.c b/src/fpx/relic_fp48_mul.c
index 3e2545195..f8019badc 100644
--- a/src/fpx/relic_fp48_mul.c
+++ b/src/fpx/relic_fp48_mul.c
@@ -86,7 +86,44 @@ void fp48_mul_basic(fp48_t c, const fp48_t a, const fp48_t b) {
void fp48_mul_lazyr(fp48_t c, const fp48_t a, const fp48_t b) {
/* TODO: implement lazy reduction. */
- fp48_mul_basic(c, a, b);
+ fp24_t t0, t1, t2;
+
+ fp24_null(t0);
+ fp24_null(t1);
+ fp24_null(t2);
+
+ RLC_TRY {
+ fp24_new(t0);
+ fp24_new(t1);
+ fp24_new(t2);
+
+ /* Karatsuba algorithm. */
+
+ /* t0 = a_0 * b_0. */
+ fp24_mul(t0, a[0], b[0]);
+ /* t1 = a_1 * b_1. */
+ fp24_mul(t1, a[1], b[1]);
+ /* t2 = b_0 + b_1. */
+ fp24_add(t2, b[0], b[1]);
+
+ /* c_1 = a_0 + a_1. */
+ fp24_add(c[1], a[0], a[1]);
+
+ /* c_1 = (a_0 + a_1) * (b_0 + b_1) */
+ fp24_mul(c[1], c[1], t2);
+ fp24_sub(c[1], c[1], t0);
+ fp24_sub(c[1], c[1], t1);
+
+ /* c_0 = a_0b_0 + v * a_1b_1. */
+ fp24_mul_art(t1, t1);
+ fp24_add(c[0], t0, t1);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp24_free(t0);
+ fp24_free(t1);
+ fp24_free(t2);
+ }
}
#endif
diff --git a/src/fpx/relic_fp48_sqr.c b/src/fpx/relic_fp48_sqr.c
index aec4d9f6d..c7cda8d02 100644
--- a/src/fpx/relic_fp48_sqr.c
+++ b/src/fpx/relic_fp48_sqr.c
@@ -231,7 +231,30 @@ void fp48_sqr_pck_basic(fp48_t c, const fp48_t a) {
void fp48_sqr_lazyr(fp48_t c, const fp48_t a) {
/* TODO: implement lazy reduction. */
- fp48_sqr_basic(c, a);
+ fp24_t t0, t1;
+
+ fp24_null(t0);
+ fp24_null(t1);
+
+ RLC_TRY {
+ fp24_new(t0);
+ fp24_new(t1);
+
+ fp24_add(t0, a[0], a[1]);
+ fp24_mul_art(t1, a[1]);
+ fp24_add(t1, a[0], t1);
+ fp24_mul(t0, t0, t1);
+ fp24_mul(c[1], a[0], a[1]);
+ fp24_sub(c[0], t0, c[1]);
+ fp24_mul_art(t1, c[1]);
+ fp24_sub(c[0], c[0], t1);
+ fp24_dbl(c[1], c[1]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp24_free(t0);
+ fp24_free(t1);
+ }
}
void fp48_sqr_cyc_lazyr(fp48_t c, const fp48_t a) {
diff --git a/src/fpx/relic_fp4_mul.c b/src/fpx/relic_fp4_mul.c
index 30ee90a93..16904cc59 100644
--- a/src/fpx/relic_fp4_mul.c
+++ b/src/fpx/relic_fp4_mul.c
@@ -170,12 +170,16 @@ void fp4_mul_frb(fp4_t c, const fp4_t a, int i, int j) {
fp_copy(t[1], core_get()->fp4_p1[1]);
if (i == 1) {
+ fp4_copy(c, a);
for (int k = 0; k < j; k++) {
- fp2_mul(c[0], a[0], t);
- fp2_mul(c[1], a[1], t);
+ fp2_mul(c[0], c[0], t);
+ fp2_mul(c[1], c[1], t);
/* If constant in base field, then second component is zero. */
if (core_get()->frb4 == 1) {
fp4_mul_art(c, c);
+ if (fp_prime_get_mod18() % 3 == 2) {
+ fp4_mul_art(c, c);
+ }
}
}
} else {
diff --git a/src/fpx/relic_fp54_mul.c b/src/fpx/relic_fp54_mul.c
index cd0e0d5a7..d2e96b23e 100644
--- a/src/fpx/relic_fp54_mul.c
+++ b/src/fpx/relic_fp54_mul.c
@@ -108,7 +108,66 @@ void fp54_mul_basic(fp54_t c, const fp54_t a, const fp54_t b) {
void fp54_mul_lazyr(fp54_t c, const fp54_t a, const fp54_t b) {
/* TODO: implement lazy reduction. */
- fp54_mul_basic(c, a, b);
+ fp18_t t0, t1, t2, t3, t4, t5;
+
+ fp18_null(t0);
+ fp18_null(t1);
+ fp18_null(t2);
+ fp18_null(t3);
+ fp18_null(t4);
+ fp18_null(t5);
+
+ RLC_TRY {
+ fp18_new(t0);
+ fp18_new(t1);
+ fp18_new(t2);
+ fp18_new(t3);
+ fp18_new(t4);
+ fp18_new(t5);
+
+ /* Karatsuba algorithm. */
+
+ /* t0 = a_0 * b_0. */
+ fp18_mul(t0, a[0], b[0]);
+ /* t1 = a_1 * b_1. */
+ fp18_mul(t1, a[1], b[1]);
+ /* t2 = a_2 * b_2. */
+ fp18_mul(t2, a[2], b[2]);
+
+ fp18_add(t3, a[1], a[2]);
+ fp18_add(t4, b[1], b[2]);
+ fp18_mul(t3, t3, t4);
+ fp18_sub(t3, t3, t1);
+ fp18_sub(t3, t3, t2);
+ fp18_mul_art(t3, t3);
+ fp18_add(t3, t3, t0);
+
+ fp18_add(t4, a[0], a[1]);
+ fp18_add(t5, b[0], b[1]);
+ fp18_mul(t4, t4, t5);
+ fp18_sub(t4, t4, t0);
+ fp18_sub(t4, t4, t1);
+ fp18_mul_art(t5, t2);
+ fp18_add(c[1], t4, t5);
+
+ fp18_add(t4, a[0], a[2]);
+ fp18_add(t5, b[0], b[2]);
+ fp18_mul(c[2], t4, t5);
+ fp18_sub(c[2], c[2], t0);
+ fp18_add(c[2], c[2], t1);
+ fp18_sub(c[2], c[2], t2);
+
+ fp18_copy(c[0], t3);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp18_free(t0);
+ fp18_free(t1);
+ fp18_free(t2);
+ fp18_free(t3);
+ fp18_free(t4);
+ fp18_free(t5);
+ }
}
#endif
diff --git a/src/fpx/relic_fp54_sqr.c b/src/fpx/relic_fp54_sqr.c
index a08e5b611..2bfc9deb8 100644
--- a/src/fpx/relic_fp54_sqr.c
+++ b/src/fpx/relic_fp54_sqr.c
@@ -276,12 +276,165 @@ void fp54_sqr_pck_basic(fp54_t c, const fp54_t a) {
void fp54_sqr_lazyr(fp54_t c, const fp54_t a) {
/* TODO: implement lazy reduction. */
- fp54_sqr_basic(c, a);
+ fp18_t t0, t1, t2, t3, t4;
+
+ fp18_null(t0);
+ fp18_null(t1);
+ fp18_null(t2);
+ fp18_null(t3);
+ fp18_null(t4);
+
+ RLC_TRY {
+ fp18_new(t0);
+ fp18_new(t1);
+ fp18_new(t2);
+ fp18_new(t3);
+ fp18_new(t4);
+
+ /* t0 = a_0^2 */
+ fp18_sqr(t0, a[0]);
+
+ /* t1 = 2 * a_1 * a_2 */
+ fp18_mul(t1, a[1], a[2]);
+ fp18_dbl(t1, t1);
+
+ /* t2 = a_2^2. */
+ fp18_sqr(t2, a[2]);
+
+ /* c_2 = a_0 + a_2. */
+ fp18_add(c[2], a[0], a[2]);
+
+ /* t3 = (a_0 + a_2 + a_1)^2. */
+ fp18_add(t3, c[2], a[1]);
+ fp18_sqr(t3, t3);
+
+ /* c_2 = (a_0 + a_2 - a_1)^2. */
+ fp18_sub(c[2], c[2], a[1]);
+ fp18_sqr(c[2], c[2]);
+
+ /* c_2 = (c_2 + t3)/2. */
+ fp18_add(c[2], c[2], t3);
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ fp_hlv(c[2][0][i][j], c[2][0][i][j]);
+ fp_hlv(c[2][1][i][j], c[2][1][i][j]);
+ }
+ }
+
+ /* t3 = t3 - c_2 - t1. */
+ fp18_sub(t3, t3, c[2]);
+ fp18_sub(t3, t3, t1);
+
+ /* c_2 = c_2 - t0 - t2. */
+ fp18_sub(c[2], c[2], t0);
+ fp18_sub(c[2], c[2], t2);
+
+ /* c_0 = t0 + t1 * E. */
+ fp18_mul_art(t4, t1);
+ fp18_add(c[0], t0, t4);
+
+ /* c_1 = t3 + t2 * E. */
+ fp18_mul_art(t4, t2);
+ fp18_add(c[1], t3, t4);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp18_free(t0);
+ fp18_free(t1);
+ fp18_free(t2);
+ fp18_free(t3);
+ fp18_free(t4);
+ }
}
void fp54_sqr_cyc_lazyr(fp54_t c, const fp54_t a) {
/* TODO: implement lazy reduction. */
- fp54_sqr_cyc_basic(c, a);
+ fp9_t t0, t1, t2, t3, t4, t5, t6;
+
+ fp9_null(t0);
+ fp9_null(t1);
+ fp9_null(t2);
+ fp9_null(t3);
+ fp9_null(t4);
+ fp9_null(t5);
+ fp9_null(t6);
+
+ RLC_TRY {
+ fp9_new(t0);
+ fp9_new(t1);
+ fp9_new(t2);
+ fp9_new(t3);
+ fp9_new(t4);
+ fp9_new(t5);
+ fp9_new(t6);
+
+ fp9_sqr(t2, a[0][0]);
+ fp9_sqr(t3, a[0][1]);
+ fp9_add(t1, a[0][0], a[0][1]);
+
+ fp9_mul_art(t0, t3);
+ fp9_add(t0, t0, t2);
+
+ fp9_sqr(t1, t1);
+ fp9_sub(t1, t1, t2);
+ fp9_sub(t1, t1, t3);
+
+ fp9_sub(c[0][0], t0, a[0][0]);
+ fp9_add(c[0][0], c[0][0], c[0][0]);
+ fp9_add(c[0][0], t0, c[0][0]);
+
+ fp9_add(c[0][1], t1, a[0][1]);
+ fp9_add(c[0][1], c[0][1], c[0][1]);
+ fp9_add(c[0][1], t1, c[0][1]);
+
+ fp9_sqr(t0, a[2][0]);
+ fp9_sqr(t1, a[2][1]);
+ fp9_add(t5, a[2][0], a[2][1]);
+ fp9_sqr(t2, t5);
+
+ fp9_add(t3, t0, t1);
+ fp9_sub(t5, t2, t3);
+
+ fp9_add(t6, a[1][0], a[1][1]);
+ fp9_sqr(t3, t6);
+ fp9_sqr(t2, a[1][0]);
+
+ fp9_mul_art(t6, t5);
+ fp9_add(t5, t6, a[1][0]);
+ fp9_dbl(t5, t5);
+ fp9_add(c[1][0], t5, t6);
+
+ fp9_mul_art(t4, t1);
+ fp9_add(t5, t0, t4);
+ fp9_sub(t6, t5, a[1][1]);
+
+ fp9_sqr(t1, a[1][1]);
+
+ fp9_dbl(t6, t6);
+ fp9_add(c[1][1], t6, t5);
+
+ fp9_mul_art(t4, t1);
+ fp9_add(t5, t2, t4);
+ fp9_sub(t6, t5, a[2][0]);
+ fp9_dbl(t6, t6);
+ fp9_add(c[2][0], t6, t5);
+
+ fp9_add(t0, t2, t1);
+ fp9_sub(t5, t3, t0);
+ fp9_add(t6, t5, a[2][1]);
+ fp9_dbl(t6, t6);
+ fp9_add(c[2][1], t5, t6);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp9_free(t0);
+ fp9_free(t1);
+ fp9_free(t2);
+ fp9_free(t3);
+ fp9_free(t4);
+ fp9_free(t5);
+ fp9_free(t6);
+ }
}
void fp54_sqr_pck_lazyr(fp54_t c, const fp54_t a) {
diff --git a/src/fpx/relic_fp8_mul.c b/src/fpx/relic_fp8_mul.c
index fc587f18c..c2d0587da 100644
--- a/src/fpx/relic_fp8_mul.c
+++ b/src/fpx/relic_fp8_mul.c
@@ -1,6 +1,6 @@
/*
* RELIC is an Efficient LIbrary for Cryptography
- * Copyright (c) 4007-4019 RELIC Authors
+ * Copyright (c) 2019 RELIC Authors
*
* This file is part of RELIC. RELIC is legal property of its developers,
* whose names are not listed here. Please refer to the COPYRIGHT file
@@ -176,14 +176,13 @@ void fp8_mul_dxs(fp8_t c, const fp8_t a, const fp8_t b) {
void fp8_mul_unr(dv8_t c, const fp8_t a, const fp8_t b) {
fp4_t t0, t1;
- dv4_t u0, u1, u2, u3;
+ dv4_t u0, u1, u2;
fp4_null(t0);
fp4_null(t1);
dv4_null(u0);
dv4_null(u1);
dv4_null(u2);
- dv4_null(u3);
RLC_TRY {
fp4_new(t0);
@@ -191,7 +190,6 @@ void fp8_mul_unr(dv8_t c, const fp8_t a, const fp8_t b) {
dv4_new(u0);
dv4_new(u1);
dv4_new(u2);
- dv4_new(u3);
/* Karatsuba algorithm. */
@@ -207,8 +205,8 @@ void fp8_mul_unr(dv8_t c, const fp8_t a, const fp8_t b) {
fp4_mul_unr(u2, t0, t1);
/* c_1 = u2 - a_0b_0 - a_1b_1. */
for (int i = 0; i < 2; i++) {
- fp2_addc_low(u3[i], u0[i], u1[i]);
- fp2_subc_low(c[1][i], u2[i], u3[i]);
+ fp2_subc_low(c[1][i], u2[i], u0[i]);
+ fp2_subc_low(c[1][i], c[1][i], u1[i]);
}
/* c_0 = a_0b_0 + v * a_1b_1. */
fp2_nord_low(u2[0], u1[1]);
@@ -225,7 +223,6 @@ void fp8_mul_unr(dv8_t c, const fp8_t a, const fp8_t b) {
dv4_free(u0);
dv4_free(u1);
dv4_free(u2);
- dv4_free(u3);
}
}
@@ -268,3 +265,36 @@ void fp8_mul_art(fp8_t c, const fp8_t a) {
fp4_free(t0);
}
}
+
+void fp8_mul_frb(fp8_t c, const fp8_t a, int i, int j) {
+ fp2_t t;
+
+ fp2_null(t);
+
+ RLC_TRY {
+ fp4_new(t);
+
+ fp_copy(t[0], core_get()->fp8_p1[0]);
+ fp_copy(t[1], core_get()->fp8_p1[1]);
+
+ if (i == 1) {
+ fp8_copy(c, a);
+ for (int k = 0; k < j; k++) {
+ fp2_mul(c[0][0], c[0][0], t);
+ fp2_mul(c[0][1], c[0][1], t);
+ fp2_mul(c[1][0], c[1][0], t);
+ fp2_mul(c[1][1], c[1][1], t);
+ /* If constant in base field, then second component is zero. */
+ if (core_get()->frb8 == 1) {
+ fp8_mul_art(c, c);
+ }
+ }
+ } else {
+ RLC_THROW(ERR_NO_VALID);
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp4_free(t);
+ }
+}
diff --git a/src/fpx/relic_fp9_mul.c b/src/fpx/relic_fp9_mul.c
index 3d33e7aaa..f03a7ee5a 100644
--- a/src/fpx/relic_fp9_mul.c
+++ b/src/fpx/relic_fp9_mul.c
@@ -267,7 +267,7 @@ void fp9_mul_art(fp9_t c, const fp9_t a) {
RLC_TRY {
fp3_new(t0);
- /* (a_0 + a_1 * v + a_2 * v^2) * v = a_2 + a_0 * v + a_1 * v^2 */
+ /* (a_0 + a_1 * v + a_2 * v^2) * v = a_2 * v^3 + a_0 * v + a_1 * v^2 */
fp3_copy(t0, a[0]);
fp3_mul_nor(c[0], a[2]);
fp3_copy(c[2], a[1]);
diff --git a/src/fpx/relic_fpx_add.c b/src/fpx/relic_fpx_add.c
index 96221488d..ff10c0aa4 100644
--- a/src/fpx/relic_fpx_add.c
+++ b/src/fpx/relic_fpx_add.c
@@ -263,6 +263,26 @@ void fp12_dbl(fp12_t c, const fp12_t a) {
fp6_dbl(c[1], a[1]);
}
+void fp16_add(fp16_t c, const fp16_t a, const fp16_t b) {
+ fp8_add(c[0], a[0], b[0]);
+ fp8_add(c[1], a[1], b[1]);
+}
+
+void fp16_sub(fp16_t c, const fp16_t a, const fp16_t b) {
+ fp8_sub(c[0], a[0], b[0]);
+ fp8_sub(c[1], a[1], b[1]);
+}
+
+void fp16_dbl(fp16_t c, const fp16_t a) {
+ fp8_dbl(c[0], a[0]);
+ fp8_dbl(c[1], a[1]);
+}
+
+void fp16_neg(fp16_t c, const fp16_t a) {
+ fp8_neg(c[0], a[0]);
+ fp8_neg(c[1], a[1]);
+}
+
void fp18_add(fp18_t c, const fp18_t a, const fp18_t b) {
fp9_add(c[0], a[0], b[0]);
fp9_add(c[1], a[1], b[1]);
diff --git a/src/fpx/relic_fpx_cmp.c b/src/fpx/relic_fpx_cmp.c
index 9655fccd5..e6fbfd48f 100644
--- a/src/fpx/relic_fpx_cmp.c
+++ b/src/fpx/relic_fpx_cmp.c
@@ -106,6 +106,16 @@ int fp12_cmp_dig(const fp12_t a, const dig_t b) {
RLC_EQ : RLC_NE;
}
+int fp16_cmp(const fp16_t a, const fp16_t b) {
+ return (fp8_cmp(a[0], b[0]) == RLC_EQ) && (fp8_cmp(a[1], b[1]) == RLC_EQ) ?
+ RLC_EQ : RLC_NE;
+}
+
+int fp16_cmp_dig(const fp16_t a, const dig_t b) {
+ return (fp8_cmp_dig(a[0], b) == RLC_EQ) && fp8_is_zero(a[1]) ?
+ RLC_EQ : RLC_NE;
+}
+
int fp18_cmp(const fp18_t a, const fp18_t b) {
return (fp9_cmp(a[0], b[0]) == RLC_EQ) && (fp9_cmp(a[1], b[1]) == RLC_EQ) ?
RLC_EQ : RLC_NE;
diff --git a/src/fpx/relic_fpx_cyc.c b/src/fpx/relic_fpx_cyc.c
index 5011aa2a7..a8ca94b4e 100644
--- a/src/fpx/relic_fpx_cyc.c
+++ b/src/fpx/relic_fpx_cyc.c
@@ -67,7 +67,7 @@ int fp2_test_cyc(const fp2_t a) {
RLC_TRY {
fp2_new(t);
- fp2_frb(t, a, 1);
+ fp2_inv_cyc(t, a);
fp2_mul(t, t, a);
result = ((fp2_cmp_dig(t, 1) == RLC_EQ) ? 1 : 0);
}
@@ -90,6 +90,14 @@ void fp2_exp_cyc(fp2_t c, const fp2_t a, const bn_t b) {
return fp2_set_dig(c, 1);
}
+ if (bn_bits(b) <= RLC_DIG) {
+ fp2_exp_dig(c, a, b->dp[0]);
+ if (bn_sign(b) == RLC_NEG) {
+ fp2_inv_cyc(c, c);
+ }
+ return;
+ }
+
fp2_null(r);
fp2_null(s);
@@ -146,6 +154,108 @@ void fp2_exp_cyc(fp2_t c, const fp2_t a, const bn_t b) {
}
}
+void fp2_exp_cyc_sim(fp2_t e, const fp2_t a, const bn_t b, const fp2_t c,
+ const bn_t d) {
+ int n0, n1;
+ int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], *_k, *_m;
+ fp2_t r, t0[1 << (RLC_WIDTH - 2)];
+ fp2_t s, t1[1 << (RLC_WIDTH - 2)];
+ size_t l, l0, l1;
+
+ if (bn_is_zero(b)) {
+ return fp2_exp_cyc(e, c, d);
+ }
+
+ if (bn_is_zero(d)) {
+ return fp2_exp_cyc(e, a, b);
+ }
+
+ fp2_null(r);
+ fp2_null(s);
+
+ RLC_TRY {
+ fp2_new(r);
+ fp2_new(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i ++) {
+ fp2_null(t0[i]);
+ fp2_null(t1[i]);
+ fp2_new(t0[i]);
+ fp2_new(t1[i]);
+ }
+
+#if RLC_WIDTH > 2
+ fp2_sqr(t0[0], a);
+ fp2_mul(t0[1], t0[0], a);
+ for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp2_mul(t0[i], t0[i - 1], t0[0]);
+ }
+
+ fp2_sqr(t1[0], c);
+ fp2_mul(t1[1], t1[0], c);
+ for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp2_mul(t1[i], t1[i - 1], t1[0]);
+ }
+#endif
+ fp2_copy(t0[0], a);
+ fp2_copy(t1[0], c);
+
+ l0 = l1 = RLC_FP_BITS + 1;
+ bn_rec_naf(naf0, &l0, b, RLC_WIDTH);
+ bn_rec_naf(naf1, &l1, d, RLC_WIDTH);
+
+ l = RLC_MAX(l0, l1);
+ if (bn_sign(b) == RLC_NEG) {
+ for (size_t i = 0; i < l0; i++) {
+ naf0[i] = -naf0[i];
+ }
+ }
+ if (bn_sign(d) == RLC_NEG) {
+ for (size_t i = 0; i < l1; i++) {
+ naf1[i] = -naf1[i];
+ }
+ }
+
+ _k = naf0 + l - 1;
+ _m = naf1 + l - 1;
+
+ fp2_set_dig(r, 1);
+ for (int i = l - 1; i >= 0; i--, _k--, _m--) {
+ fp2_sqr(r, r);
+
+ n0 = *_k;
+ n1 = *_m;
+
+ if (n0 > 0) {
+ fp2_mul(r, r, t0[n0 / 2]);
+ }
+ if (n0 < 0) {
+ fp2_inv_cyc(s, t0[-n0 / 2]);
+ fp2_mul(r, r, s);
+ }
+ if (n1 > 0) {
+ fp2_mul(r, r, t1[n1 / 2]);
+ }
+ if (n1 < 0) {
+ fp2_inv_cyc(s, t1[-n1 / 2]);
+ fp2_mul(r, r, s);
+ }
+ }
+
+ fp2_copy(e, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp2_free(r);
+ fp2_free(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp2_free(t0[i]);
+ fp2_free(t1[i]);
+ }
+ }
+}
+
void fp8_conv_cyc(fp8_t c, const fp8_t a) {
fp8_t t;
@@ -193,13 +303,17 @@ int fp8_test_cyc(const fp8_t a) {
void fp8_exp_cyc(fp8_t c, const fp8_t a, const bn_t b) {
fp8_t r, s, t[1 << (RLC_WIDTH - 2)];
- int8_t naf[RLC_FP_BITS + 1], *k;
+ int8_t naf[RLC_FP_BITS + 1], *k, w = RLC_WIDTH;
size_t l;
if (bn_is_zero(b)) {
return fp8_set_dig(c, 1);
}
+ if (bn_bits(b) <= RLC_DIG) {
+ w = 2;
+ }
+
fp8_null(r);
fp8_null(s);
@@ -214,7 +328,7 @@ void fp8_exp_cyc(fp8_t c, const fp8_t a, const bn_t b) {
#if RLC_WIDTH > 2
fp8_sqr_cyc(t[0], a);
fp8_mul(t[1], t[0], a);
- for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
+ for (int i = 2; i < (1 << (w - 2)); i++) {
fp8_mul(t[i], t[i - 1], t[0]);
}
#endif
@@ -222,7 +336,7 @@ void fp8_exp_cyc(fp8_t c, const fp8_t a, const bn_t b) {
l = RLC_FP_BITS + 1;
fp8_set_dig(r, 1);
- bn_rec_naf(naf, &l, b, RLC_WIDTH);
+ bn_rec_naf(naf, &l, b, w);
k = naf + l - 1;
@@ -328,26 +442,34 @@ void fp12_back_cyc(fp12_t c, const fp12_t a) {
fp2_new(t1);
fp2_new(t2);
- if (fp2_is_zero(a[1][0])) {
- /* If g2 = 0, t0 = 2 * g4 * g5, t1 = g3. */
- fp2_mul(t0, a[0][1], a[1][2]);
- fp2_dbl(t0, t0);
- fp2_copy(t1, a[0][2]);
- } else {
- /* t0 = g4^2. */
- fp2_sqr(t0, a[0][1]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp2_sub(t1, t0, a[0][2]);
- fp2_dbl(t1, t1);
- fp2_add(t1, t1, t0);
- /* t0 = E * g5^2 + t1. */
- fp2_sqr(t2, a[1][2]);
- fp2_mul_nor(t0, t2);
- fp2_add(t0, t0, t1);
- /* t1 = 4 * g2. */
- fp2_dbl(t1, a[1][0]);
- fp2_dbl(t1, t1);
- }
+ int f = fp2_is_zero(a[1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp2_copy(t2, a[0][1]);
+ dv_copy_cond(t2[0], a[1][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1], a[1][2][1], RLC_FP_DIGS, f);
+ /* t0 = g4^2. */
+ fp2_mul(t0, a[0][1], t2);
+ fp2_dbl(t2, t0);
+ dv_copy_cond(t0[0], t2[0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1], t2[1], RLC_FP_DIGS, f);
+ /* t1 = 3 * g4^2 - 2 * g3. */
+ fp2_sub(t1, t0, a[0][2]);
+ fp2_dbl(t1, t1);
+ fp2_add(t1, t1, t0);
+ /* t0 = E * g5^2 + t1. */
+ fp2_sqr(t2, a[1][2]);
+ fp2_mul_nor(t0, t2);
+ fp2_add(t0, t0, t1);
+ /* t1 = (4 * g2). */
+ fp2_dbl(t1, a[1][0]);
+ fp2_dbl(t1, t1);
+ dv_copy_cond(t1[0], a[0][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1], a[0][2][1], RLC_FP_DIGS, f);
+ /* If unity, decompress to unity as well. */
+ f = fp12_cmp_dig(a, 1) == RLC_EQ;
+ fp2_set_dig(t2, 1);
+ dv_copy_cond(t1[0], t2[0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1], t2[1], RLC_FP_DIGS, f);
/* t1 = 1/g3 or 1/(4*g2), depending on the above. */
fp2_inv(t1, t1);
@@ -406,31 +528,34 @@ void fp12_back_cyc_sim(fp12_t c[], const fp12_t a[], int n) {
}
for (int i = 0; i < n; i++) {
- /* TODO: make this constant time. */
- if (fp2_is_zero(a[i][1][0])) {
- /* t0 = 2 * g4 * g5, t1 = g3. */
- fp2_mul(t0[i], a[i][0][1], a[i][1][2]);
- fp2_dbl(t0[i], t0[i]);
- fp2_copy(t1[i], a[i][0][2]);
- } else {
- /* t0 = g4^2. */
- fp2_sqr(t0[i], a[i][0][1]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp2_sub(t1[i], t0[i], a[i][0][2]);
- fp2_dbl(t1[i], t1[i]);
- fp2_add(t1[i], t1[i], t0[i]);
- /* t0 = E * g5^2 + t1. */
- fp2_sqr(t2[i], a[i][1][2]);
- fp2_mul_nor(t0[i], t2[i]);
- fp2_add(t0[i], t0[i], t1[i]);
- /* t1 = (4 * g2). */
- fp2_dbl(t1[i], a[i][1][0]);
- fp2_dbl(t1[i], t1[i]);
- }
+ int f = fp2_is_zero(a[i][1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp2_copy(t2[i], a[i][0][1]);
+ dv_copy_cond(t2[i][0], a[i][1][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1], a[i][1][2][1], RLC_FP_DIGS, f);
+ /* t0 = g4^2. */
+ fp2_mul(t0[i], a[i][0][1], t2[i]);
+ fp2_dbl(t2[i], t0[i]);
+ dv_copy_cond(t0[i][0], t2[i][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1], t2[i][1], RLC_FP_DIGS, f);
+ /* t1 = 3 * g4^2 - 2 * g3. */
+ fp2_sub(t1[i], t0[i], a[i][0][2]);
+ fp2_dbl(t1[i], t1[i]);
+ fp2_add(t1[i], t1[i], t0[i]);
+ /* t0 = E * g5^2 + t1. */
+ fp2_sqr(t2[i], a[i][1][2]);
+ fp2_mul_nor(t0[i], t2[i]);
+ fp2_add(t0[i], t0[i], t1[i]);
+ /* t1 = (4 * g2). */
+ fp2_dbl(t1[i], a[i][1][0]);
+ fp2_dbl(t1[i], t1[i]);
+ dv_copy_cond(t1[i][0], a[i][0][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1], a[i][0][2][1], RLC_FP_DIGS, f);
/* If unity, decompress to unity as well. */
- if (fp12_cmp_dig(a[i], 1) == RLC_EQ) {
- fp2_set_dig(t1[i], 1);
- }
+ f = (fp12_cmp_dig(a[i], 1) == RLC_EQ);
+ fp2_set_dig(t2[i], 1);
+ dv_copy_cond(t1[i][0], t2[i][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1], t2[i][1], RLC_FP_DIGS, f);
}
/* t1 = 1 / t1. */
@@ -619,109 +744,8 @@ void fp12_exp_cyc(fp12_t c, const fp12_t a, const bn_t b) {
}
}
-void fp2_exp_cyc_sim(fp2_t e, const fp2_t a, const bn_t b, const fp2_t c, const bn_t d) {
- int n0, n1;
- int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], *_k, *_m;
- fp2_t r, t0[1 << (RLC_WIDTH - 2)];
- fp2_t s, t1[1 << (RLC_WIDTH - 2)];
- size_t l, l0, l1;
-
- if (bn_is_zero(b)) {
- return fp2_exp_cyc(e, c, d);
- }
-
- if (bn_is_zero(d)) {
- return fp2_exp_cyc(e, a, b);
- }
-
- fp2_null(r);
- fp2_null(s);
-
- RLC_TRY {
- fp2_new(r);
- fp2_new(s);
- for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i ++) {
- fp2_null(t0[i]);
- fp2_null(t1[i]);
- fp2_new(t0[i]);
- fp2_new(t1[i]);
- }
-
-#if RLC_WIDTH > 2
- fp2_sqr(t0[0], a);
- fp2_mul(t0[1], t0[0], a);
- for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
- fp2_mul(t0[i], t0[i - 1], t0[0]);
- }
-
- fp2_sqr(t1[0], c);
- fp2_mul(t1[1], t1[0], c);
- for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
- fp2_mul(t1[i], t1[i - 1], t1[0]);
- }
-#endif
- fp2_copy(t0[0], a);
- fp2_copy(t1[0], c);
-
- l0 = l1 = RLC_FP_BITS + 1;
- bn_rec_naf(naf0, &l0, b, RLC_WIDTH);
- bn_rec_naf(naf1, &l1, d, RLC_WIDTH);
-
- l = RLC_MAX(l0, l1);
- if (bn_sign(b) == RLC_NEG) {
- for (size_t i = 0; i < l0; i++) {
- naf0[i] = -naf0[i];
- }
- }
- if (bn_sign(d) == RLC_NEG) {
- for (size_t i = 0; i < l1; i++) {
- naf1[i] = -naf1[i];
- }
- }
-
- _k = naf0 + l - 1;
- _m = naf1 + l - 1;
-
- fp2_set_dig(r, 1);
- for (int i = l - 1; i >= 0; i--, _k--, _m--) {
- fp2_sqr(r, r);
-
- n0 = *_k;
- n1 = *_m;
-
- if (n0 > 0) {
- fp2_mul(r, r, t0[n0 / 2]);
- }
- if (n0 < 0) {
- fp2_inv_cyc(s, t0[-n0 / 2]);
- fp2_mul(r, r, s);
- }
- if (n1 > 0) {
- fp2_mul(r, r, t1[n1 / 2]);
- }
- if (n1 < 0) {
- fp2_inv_cyc(s, t1[-n1 / 2]);
- fp2_mul(r, r, s);
- }
- }
-
- fp2_copy(e, r);
- }
- RLC_CATCH_ANY {
- RLC_THROW(ERR_CAUGHT);
- }
- RLC_FINALLY {
- fp2_free(r);
- fp2_free(s);
- for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
- fp2_free(t0[i]);
- fp2_free(t1[i]);
- }
- }
-}
-
-
-void fp12_exp_cyc_sim(fp12_t e, const fp12_t a, const bn_t b, const fp12_t c, const bn_t d) {
+void fp12_exp_cyc_sim(fp12_t e, const fp12_t a, const bn_t b, const fp12_t c,
+ const bn_t d) {
int i, j, l;
bn_t _b[4], _d[4], n, x;
fp12_t t[4], u[4];
@@ -903,6 +927,223 @@ void fp12_exp_cyc_sps(fp12_t c, const fp12_t a, const int *b, size_t len,
}
}
+void fp16_conv_cyc(fp16_t c, const fp16_t a) {
+ fp16_t t;
+
+ fp16_null(t);
+
+ RLC_TRY {
+ fp16_new(t);
+
+ /* t = a^{-1}. */
+ fp16_inv(t, a);
+ /* c = a^(p^8). */
+ fp16_inv_cyc(c, a);
+ /* c = a^(p^8 - 1). */
+ fp16_mul(c, c, t);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(t);
+ }
+}
+
+int fp16_test_cyc(const fp16_t a) {
+ fp16_t t;
+ int result = 0;
+
+ fp16_null(t);
+
+ RLC_TRY {
+ fp16_new(t);
+ fp16_inv_cyc(t, a);
+ fp16_mul(t, t, a);
+ result = ((fp16_cmp_dig(t, 1) == RLC_EQ) ? 1 : 0);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(t);
+ }
+
+ return result;
+}
+
+void fp16_exp_cyc(fp16_t c, const fp16_t a, const bn_t b) {
+ fp16_t r, s, t[1 << (RLC_WIDTH - 2)];
+ int8_t naf[RLC_FP_BITS + 1], *k, w = RLC_WIDTH;
+ size_t l;
+
+ if (bn_is_zero(b)) {
+ return fp16_set_dig(c, 1);
+ }
+
+ if (bn_bits(b) <= RLC_DIG) {
+ w = 2;
+ }
+
+ fp16_null(r);
+ fp16_null(s);
+
+ RLC_TRY {
+ fp16_new(r);
+ fp16_new(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i ++) {
+ fp16_null(t[i]);
+ fp16_new(t[i]);
+ }
+
+#if RLC_WIDTH > 2
+ fp16_sqr_cyc(t[0], a);
+ fp16_mul(t[1], t[0], a);
+ for (int i = 2; i < (1 << (w - 2)); i++) {
+ fp16_mul(t[i], t[i - 1], t[0]);
+ }
+#endif
+ fp16_copy(t[0], a);
+
+ l = RLC_FP_BITS + 1;
+ fp16_set_dig(r, 1);
+ bn_rec_naf(naf, &l, b, w);
+
+ k = naf + l - 1;
+
+ for (int i = l - 1; i >= 0; i--, k--) {
+ fp16_sqr_cyc(r, r);
+
+ if (*k > 0) {
+ fp16_mul(r, r, t[*k / 2]);
+ }
+ if (*k < 0) {
+ fp16_inv_cyc(s, t[-*k / 2]);
+ fp16_mul(r, r, s);
+ }
+ }
+
+ if (bn_sign(b) == RLC_NEG) {
+ fp16_inv_cyc(c, r);
+ } else {
+ fp16_copy(c, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(r);
+ fp16_free(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp16_free(t[i]);
+ }
+ }
+}
+
+void fp16_exp_cyc_sim(fp16_t e, const fp16_t a, const bn_t b, const fp16_t c,
+ const bn_t d) {
+ int n0, n1;
+ int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], *_k, *_m;
+ fp16_t r, t0[1 << (RLC_WIDTH - 2)];
+ fp16_t s, t1[1 << (RLC_WIDTH - 2)];
+ size_t l, l0, l1;
+
+ if (bn_is_zero(b)) {
+ return fp16_exp_cyc(e, c, d);
+ }
+
+ if (bn_is_zero(d)) {
+ return fp16_exp_cyc(e, a, b);
+ }
+
+ fp16_null(r);
+ fp16_null(s);
+
+ RLC_TRY {
+ fp16_new(r);
+ fp16_new(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i ++) {
+ fp16_null(t0[i]);
+ fp16_null(t1[i]);
+ fp16_new(t0[i]);
+ fp16_new(t1[i]);
+ }
+
+#if RLC_WIDTH > 2
+ fp16_sqr_cyc(t0[0], a);
+ fp16_mul(t0[1], t0[0], a);
+ for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp16_mul(t0[i], t0[i - 1], t0[0]);
+ }
+
+ fp16_sqr_cyc(t1[0], c);
+ fp16_mul(t1[1], t1[0], c);
+ for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp16_mul(t1[i], t1[i - 1], t1[0]);
+ }
+#endif
+ fp16_copy(t0[0], a);
+ fp16_copy(t1[0], c);
+
+ l0 = l1 = RLC_FP_BITS + 1;
+ bn_rec_naf(naf0, &l0, b, RLC_WIDTH);
+ bn_rec_naf(naf1, &l1, d, RLC_WIDTH);
+
+ l = RLC_MAX(l0, l1);
+ if (bn_sign(b) == RLC_NEG) {
+ for (size_t i = 0; i < l0; i++) {
+ naf0[i] = -naf0[i];
+ }
+ }
+ if (bn_sign(d) == RLC_NEG) {
+ for (size_t i = 0; i < l1; i++) {
+ naf1[i] = -naf1[i];
+ }
+ }
+
+ _k = naf0 + l - 1;
+ _m = naf1 + l - 1;
+
+ fp16_set_dig(r, 1);
+ for (int i = l - 1; i >= 0; i--, _k--, _m--) {
+ fp16_sqr(r, r);
+
+ n0 = *_k;
+ n1 = *_m;
+
+ if (n0 > 0) {
+ fp16_mul(r, r, t0[n0 / 2]);
+ }
+ if (n0 < 0) {
+ fp16_inv_cyc(s, t0[-n0 / 2]);
+ fp16_mul(r, r, s);
+ }
+ if (n1 > 0) {
+ fp16_mul(r, r, t1[n1 / 2]);
+ }
+ if (n1 < 0) {
+ fp16_inv_cyc(s, t1[-n1 / 2]);
+ fp16_mul(r, r, s);
+ }
+ }
+
+ fp16_copy(e, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(r);
+ fp16_free(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp16_free(t0[i]);
+ fp16_free(t1[i]);
+ }
+ }
+}
+
+
void fp18_conv_cyc(fp18_t c, const fp18_t a) {
fp18_t t;
@@ -975,26 +1216,38 @@ void fp18_back_cyc(fp18_t c, const fp18_t a) {
fp3_new(t1);
fp3_new(t2);
- if (fp3_is_zero(a[1][0])) {
- /* If g2 = 0, t0 = 2 * g4 * g5, t1 = g3. */
- fp3_mul(t0, a[0][1], a[1][2]);
- fp3_dbl(t0, t0);
- fp3_copy(t1, a[0][2]);
- } else {
- /* t0 = g4^2. */
- fp3_sqr(t0, a[0][1]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp3_sub(t1, t0, a[0][2]);
- fp3_dbl(t1, t1);
- fp3_add(t1, t1, t0);
- /* t0 = E * g5^2 + t1. */
- fp3_sqr(t2, a[1][2]);
- fp3_mul_nor(t0, t2);
- fp3_add(t0, t0, t1);
- /* t1 = 4 * g2. */
- fp3_dbl(t1, a[1][0]);
- fp3_dbl(t1, t1);
- }
+ int f = fp3_is_zero(a[1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp3_copy(t2, a[0][1]);
+ dv_copy_cond(t2[0], a[1][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1], a[1][2][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[2], a[1][2][2], RLC_FP_DIGS, f);
+ /* t0 = g4^2. */
+ fp3_mul(t0, a[0][1], t2);
+ fp3_dbl(t2, t0);
+ dv_copy_cond(t0[0], t2[0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1], t2[1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[2], t2[2], RLC_FP_DIGS, f);
+ /* t1 = 3 * g4^2 - 2 * g3. */
+ fp3_sub(t1, t0, a[0][2]);
+ fp3_dbl(t1, t1);
+ fp3_add(t1, t1, t0);
+ /* t0 = E * g5^2 + t1. */
+ fp3_sqr(t2, a[1][2]);
+ fp3_mul_nor(t0, t2);
+ fp3_add(t0, t0, t1);
+ /* t1 = (4 * g2). */
+ fp3_dbl(t1, a[1][0]);
+ fp3_dbl(t1, t1);
+ dv_copy_cond(t1[0], a[0][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1], a[0][2][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[2], a[0][2][2], RLC_FP_DIGS, f);
+ /* If unity, decompress to unity as well. */
+ f = fp18_cmp_dig(a, 1) == RLC_EQ;
+ fp3_set_dig(t2, 1);
+ dv_copy_cond(t1[0], t2[0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1], t2[1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[2], t2[2], RLC_FP_DIGS, f);
/* t1 = 1/g3 or 1/(4 * g2), depending on the above. */
fp3_inv(t1, t1);
@@ -1053,31 +1306,38 @@ void fp18_back_cyc_sim(fp18_t c[], const fp18_t a[], int n) {
}
for (int i = 0; i < n; i++) {
- /* TODO: make this constant time. */
- if (fp3_is_zero(a[i][1][0])) {
- /* t0 = 2 * g4 * g5, t1 = g3. */
- fp3_mul(t0[i], a[i][0][1], a[i][1][2]);
- fp3_dbl(t0[i], t0[i]);
- fp3_copy(t1[i], a[i][0][2]);
- } else {
- /* t0 = g4^2. */
- fp3_sqr(t0[i], a[i][0][1]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp3_sub(t1[i], t0[i], a[i][0][2]);
- fp3_dbl(t1[i], t1[i]);
- fp3_add(t1[i], t1[i], t0[i]);
- /* t0 = E * g5^2 + t1. */
- fp3_sqr(t2[i], a[i][1][2]);
- fp3_mul_nor(t0[i], t2[i]);
- fp3_add(t0[i], t0[i], t1[i]);
- /* t1 = (4 * g2). */
- fp3_dbl(t1[i], a[i][1][0]);
- fp3_dbl(t1[i], t1[i]);
- }
+ int f = fp3_is_zero(a[i][1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp3_copy(t2[i], a[i][0][1]);
+ dv_copy_cond(t2[i][0], a[i][1][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1], a[i][1][2][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][2], a[i][1][2][2], RLC_FP_DIGS, f);
+ /* t0 = g4^2. */
+ fp3_mul(t0[i], a[i][0][1], t2[i]);
+ fp3_dbl(t2[i], t0[i]);
+ dv_copy_cond(t0[i][0], t2[i][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1], t2[i][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][2], t2[i][2], RLC_FP_DIGS, f);
+ /* t1 = 3 * g4^2 - 2 * g3. */
+ fp3_sub(t1[i], t0[i], a[i][0][2]);
+ fp3_dbl(t1[i], t1[i]);
+ fp3_add(t1[i], t1[i], t0[i]);
+ /* t0 = E * g5^2 + t1. */
+ fp3_sqr(t2[i], a[i][1][2]);
+ fp3_mul_nor(t0[i], t2[i]);
+ fp3_add(t0[i], t0[i], t1[i]);
+ /* t1 = (4 * g2). */
+ fp3_dbl(t1[i], a[i][1][0]);
+ fp3_dbl(t1[i], t1[i]);
+ dv_copy_cond(t1[i][0], a[i][0][2][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1], a[i][0][2][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][2], a[i][0][2][2], RLC_FP_DIGS, f);
/* If unity, decompress to unity as well. */
- if (fp18_cmp_dig(a[i], 1) == RLC_EQ) {
- fp3_set_dig(t1[i], 1);
- }
+ f = (fp18_cmp_dig(a[i], 1) == RLC_EQ);
+ fp3_set_dig(t2[i], 1);
+ dv_copy_cond(t1[i][0], t2[i][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1], t2[i][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][2], t2[i][2], RLC_FP_DIGS, f);
}
/* t1 = 1 / t1. */
@@ -1126,13 +1386,22 @@ static void fp18_gls(fp18_t c, const fp18_t a) {
RLC_TRY {
fp18_new(b);
- /* We have that x = p^4 - 3*p = (p^3 - 3)p mod n. */
- fp18_sqr_cyc(b, a);
- fp18_mul(b, b, a);
- fp18_frb(c, a, 3);
- fp18_inv_cyc(b, b);
- fp18_mul(c, c, b);
- fp18_frb(c, c, 1);
+ if (ep_curve_is_pairf() == EP_SG18) {
+ /* -3*u = (2*p^2 - p^5) mod r */
+ fp18_frb(b, a, 5);
+ fp18_inv_cyc(b, b);
+ fp18_frb(c, a, 2);
+ fp18_sqr_cyc(c, c);
+ fp18_mul(c, c, b);
+ } else {
+ /* For KSS18, we have that x = p^4 - 3*p = (p^3 - 3)p mod n. */
+ fp18_sqr_cyc(b, a);
+ fp18_mul(b, b, a);
+ fp18_frb(c, a, 3);
+ fp18_inv_cyc(b, b);
+ fp18_mul(c, c, b);
+ fp18_frb(c, c, 1);
+ }
}
RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -1146,8 +1415,7 @@ void fp18_exp_cyc(fp18_t c, const fp18_t a, const bn_t b) {
int i, j, k, w = bn_ham(b);
if (bn_is_zero(b)) {
- fp18_set_dig(c, 1);
- return;
+ return fp18_set_dig(c, 1);
}
if ((bn_bits(b) > RLC_DIG) && ((w << 3) > bn_bits(b))) {
@@ -1169,8 +1437,14 @@ void fp18_exp_cyc(fp18_t c, const fp18_t a, const bn_t b) {
fp18_new(t[i]);
}
- ep_curve_get_ord(n);
fp_prime_get_par(x);
+ if (ep_curve_is_pairf() == EP_SG18) {
+ /* Compute base -3*u for the recoding below. */
+ bn_dbl(n, x);
+ bn_add(x, x, n);
+ bn_neg(x, x);
+ }
+ ep_curve_get_ord(n);
bn_mod(_b[0], b, n);
bn_rec_frb(_b, 6, _b[0], x, n, ep_curve_is_pairf() == EP_BN);
@@ -1178,26 +1452,32 @@ void fp18_exp_cyc(fp18_t c, const fp18_t a, const bn_t b) {
l = 0;
fp18_copy(t[0], a);
- for (i = 0; i < 6; i++) {
- if (i > 0) {
- fp18_gls(t[i], t[i - 1]);
- }
+ for (int i = 0; i < 6; i++) {
_l[i] = RLC_FP_BITS + 1;
bn_rec_naf(naf[i], &_l[i], _b[i], 2);
l = RLC_MAX(l, _l[i]);
+ if (i > 0) {
+ fp18_gls(t[i], t[i - 1]);
+ }
+ }
+
+ for (int i = 0; i < 6; i++) {
+ if (bn_sign(_b[i]) == RLC_NEG) {
+ fp18_inv_cyc(t[i], t[i]);
+ }
}
fp18_set_dig(c, 1);
- for (j = l - 1; j >= 0; j--) {
+ for (int i = l - 1; i >= 0; i--) {
fp18_sqr_cyc(c, c);
- for (i = 0; i < 6; i++) {
- if (naf[i][j] > 0) {
- fp18_mul(c, c, t[i]);
+ for (int j = 0; j < 6; j++) {
+ if (naf[j][i] > 0) {
+ fp18_mul(c, c, t[j]);
}
- if (naf[i][j] < 0) {
- fp18_inv_cyc(t[i], t[i]);
- fp18_mul(c, c, t[i]);
- fp18_inv_cyc(t[i], t[i]);
+ if (naf[j][i] < 0) {
+ fp18_inv_cyc(t[j], t[j]);
+ fp18_mul(c, c, t[j]);
+ fp18_inv_cyc(t[j], t[j]);
}
}
}
@@ -1289,7 +1569,8 @@ void fp18_exp_cyc(fp18_t c, const fp18_t a, const bn_t b) {
}
}
-void fp18_exp_cyc_sim(fp18_t e, const fp18_t a, const bn_t b, const fp18_t c, const bn_t d) {
+void fp18_exp_cyc_sim(fp18_t e, const fp18_t a, const bn_t b, const fp18_t c,
+ const bn_t d) {
int i, n0, n1;
size_t l, l0, l1;
int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], *_k, *_m;
@@ -1390,7 +1671,8 @@ void fp18_exp_cyc_sim(fp18_t e, const fp18_t a, const bn_t b, const fp18_t c, co
}
}
-void fp18_exp_cyc_sps(fp18_t c, const fp18_t a, const int *b, int len, int sign) {
+void fp18_exp_cyc_sps(fp18_t c, const fp18_t a, const int *b, int len,
+ int sign) {
int i, j, k, w = len;
fp18_t t, *u = RLC_ALLOCA(fp18_t, w);
@@ -1541,26 +1823,42 @@ void fp24_back_cyc(fp24_t c, const fp24_t a) {
fp4_new(t1);
fp4_new(t2);
- if (fp4_is_zero(a[1][0])) {
- /* If g2 = 0, t0 = 2 * g4 * g5, t1 = g3. */
- fp4_mul(t0, a[2][0], a[2][1]);
- fp4_dbl(t0, t0);
- fp4_copy(t1, a[1][1]);
- } else {
- /* t0 = g4^2. */
- fp4_sqr(t0, a[2][0]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp4_sub(t1, t0, a[1][1]);
- fp4_dbl(t1, t1);
- fp4_add(t1, t1, t0);
- /* t0 = E * g5^2 + t1. */
- fp4_sqr(t2, a[2][1]);
- fp4_mul_art(t0, t2);
- fp4_add(t0, t0, t1);
- /* t1 = 1/(4 * g2). */
- fp4_dbl(t1, a[1][0]);
- fp4_dbl(t1, t1);
- }
+ int f = fp4_is_zero(a[1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp4_copy(t2, a[2][0]);
+ dv_copy_cond(t2[0][0], a[2][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[0][1], a[2][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1][0], a[2][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1][1], a[2][1][1][1], RLC_FP_DIGS, f);
+ /* t0 = g4^2. */
+ fp4_mul(t0, a[2][0], t2);
+ fp4_dbl(t2, t0);
+ dv_copy_cond(t0[0][0], t2[0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[0][1], t2[0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1][0], t2[1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1][1], t2[1][1], RLC_FP_DIGS, f);
+ /* t1 = 3 * g4^2 - 2 * g3. */
+ fp4_sub(t1, t0, a[1][1]);
+ fp4_dbl(t1, t1);
+ fp4_add(t1, t1, t0);
+ /* t0 = E * g5^2 + t1. */
+ fp4_sqr(t2, a[2][1]);
+ fp4_mul_art(t0, t2);
+ fp4_add(t0, t0, t1);
+ /* t1 = (4 * g2). */
+ fp4_dbl(t1, a[1][0]);
+ fp4_dbl(t1, t1);
+ dv_copy_cond(t1[0][0], a[1][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][1], a[1][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][0], a[1][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][1], a[1][1][1][1], RLC_FP_DIGS, f);
+ /* If unity, decompress to unity as well. */
+ f = fp24_cmp_dig(a, 1) == RLC_EQ;
+ fp4_set_dig(t2, 1);
+ dv_copy_cond(t1[0][0], t2[0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][1], t2[0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][0], t2[1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][1], t2[1][1], RLC_FP_DIGS, f);
fp4_inv(t1, t1);
/* c_1 = g1. */
@@ -1618,30 +1916,42 @@ void fp24_back_cyc_sim(fp24_t c[], const fp24_t a[], int n) {
}
for (int i = 0; i < n; i++) {
- if (fp4_is_zero(a[i][1][0])) {
- /* t0 = 2 * g4 * g5, t1 = g3. */
- fp4_mul(t0[i], a[i][2][0], a[i][2][1]);
- fp4_dbl(t0[i], t0[i]);
- fp4_copy(t1[i], a[i][1][1]);
- } else {
- /* t0 = g4^2. */
- fp4_sqr(t0[i], a[i][2][0]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp4_sub(t1[i], t0[i], a[i][1][1]);
- fp4_dbl(t1[i], t1[i]);
- fp4_add(t1[i], t1[i], t0[i]);
- /* t0 = E * g5^2 + t1. */
- fp4_sqr(t2[i], a[i][2][1]);
- fp4_mul_art(t0[i], t2[i]);
- fp4_add(t0[i], t0[i], t1[i]);
- /* t1 = (4 * g2). */
- fp4_dbl(t1[i], a[i][1][0]);
- fp4_dbl(t1[i], t1[i]);
- }
+ int f = fp4_is_zero(a[i][1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp4_copy(t2[i], a[i][2][0]);
+ dv_copy_cond(t2[i][0][0], a[i][2][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][0][1], a[i][2][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1][0], a[i][2][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1][1], a[i][2][1][1][1], RLC_FP_DIGS, f);
+ /* t0 = g4^2. */
+ fp4_mul(t0[i], a[i][2][0], t2[i]);
+ fp4_dbl(t2[i], t0[i]);
+ dv_copy_cond(t0[i][0][0], t2[i][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][0][1], t2[i][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1][0], t2[i][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1][1], t2[i][1][1], RLC_FP_DIGS, f);
+ /* t1 = 3 * g4^2 - 2 * g3. */
+ fp4_sub(t1[i], t0[i], a[i][1][1]);
+ fp4_dbl(t1[i], t1[i]);
+ fp4_add(t1[i], t1[i], t0[i]);
+ /* t0 = E * g5^2 + t1. */
+ fp4_sqr(t2[i], a[i][2][1]);
+ fp4_mul_art(t0[i], t2[i]);
+ fp4_add(t0[i], t0[i], t1[i]);
+ /* t1 = (4 * g2). */
+ fp4_dbl(t1[i], a[i][1][0]);
+ fp4_dbl(t1[i], t1[i]);
+ dv_copy_cond(t1[i][0][0], a[i][1][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][1], a[i][1][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][0], a[i][1][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][1], a[i][1][1][1][1], RLC_FP_DIGS, f);
/* If unity, decompress to unity as well. */
- if (fp24_cmp_dig(a[i], 1) == RLC_EQ) {
- fp4_set_dig(t1[i], 1);
- }
+ f = fp24_cmp_dig(a[i], 1) == RLC_EQ;
+ fp4_set_dig(t2[i], 1);
+ dv_copy_cond(t1[i][0][0], t2[i][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][1], t2[i][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][0], t2[i][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][1], t2[i][1][1], RLC_FP_DIGS, f);
}
/* t1 = 1 / t1. */
@@ -1834,7 +2144,8 @@ void fp24_exp_cyc(fp24_t c, const fp24_t a, const bn_t b) {
}
}
-void fp24_exp_cyc_sim(fp24_t e, const fp24_t a, const bn_t b, const fp24_t c, const bn_t d) {
+void fp24_exp_cyc_sim(fp24_t e, const fp24_t a, const bn_t b, const fp24_t c,
+ const bn_t d) {
int n0, n1;
int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], *_k, *_m;
fp24_t r, t0[1 << (RLC_WIDTH - 2)];
@@ -2087,26 +2398,58 @@ void fp48_back_cyc(fp48_t c, const fp48_t a) {
fp8_new(t1);
fp8_new(t2);
- if (fp8_is_zero(a[1][0])) {
- /* If g2 = 0, t0 = 2 * g4 * g5, t1 = g3. */
- fp8_mul(t0, a[0][1], a[1][2]);
- fp8_dbl(t0, t0);
- fp8_copy(t1, a[0][2]);
- } else {
- /* t0 = g4^2. */
- fp8_sqr(t0, a[0][1]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp8_sub(t1, t0, a[0][2]);
- fp8_dbl(t1, t1);
- fp8_add(t1, t1, t0);
- /* t0 = E * g5^2 + t1. */
- fp8_sqr(t2, a[1][2]);
- fp8_mul_art(t0, t2);
- fp8_add(t0, t0, t1);
- /* t1 = 1/(4 * g2). */
- fp8_dbl(t1, a[1][0]);
- fp8_dbl(t1, t1);
- }
+ int f = fp8_is_zero(a[1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp8_copy(t2, a[0][1]);
+ dv_copy_cond(t2[0][0][0], a[1][2][0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[0][0][1], a[1][2][0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[0][1][0], a[1][2][0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[0][1][1], a[1][2][0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1][0][0], a[1][2][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1][0][1], a[1][2][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1][1][0], a[1][2][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[1][1][1], a[1][2][1][1][1], RLC_FP_DIGS, f);
+ /* t0 = g4^2. */
+ fp8_mul(t0, a[0][1], t2);
+ fp8_dbl(t2, t0);
+ dv_copy_cond(t0[0][0][0], t2[0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[0][0][1], t2[0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[0][1][0], t2[0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[0][1][1], t2[0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1][0][0], t2[1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1][0][1], t2[1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1][1][0], t2[1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[1][1][1], t2[1][1][1], RLC_FP_DIGS, f);
+ /* t1 = 3 * g4^2 - 2 * g3. */
+ fp8_sub(t1, t0, a[0][2]);
+ fp8_dbl(t1, t1);
+ fp8_add(t1, t1, t0);
+ /* t0 = E * g5^2 + t1. */
+ fp8_sqr(t2, a[1][2]);
+ fp8_mul_art(t0, t2);
+ fp8_add(t0, t0, t1);
+ /* t1 = (4 * g2). */
+ fp8_dbl(t1, a[1][0]);
+ fp8_dbl(t1, t1);
+ dv_copy_cond(t1[0][0][0], a[0][2][0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][0][1], a[0][2][0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][1][0], a[0][2][0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][1][1], a[0][2][0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][0][0], a[0][2][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][0][1], a[0][2][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][1][0], a[0][2][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][1][1], a[0][2][1][1][1], RLC_FP_DIGS, f);
+ /* If unity, decompress to unity as well. */
+ f = fp48_cmp_dig(a, 1) == RLC_EQ;
+ fp8_set_dig(t2, 1);
+ dv_copy_cond(t1[0][0][0], t2[0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][0][1], t2[0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][1][0], t2[0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[0][1][1], t2[0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][0][0], t2[1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][0][1], t2[1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][1][0], t2[1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[1][1][1], t2[1][1][1], RLC_FP_DIGS, f);
/* t1 = 1/g3 or 1/(4 * g2), depending on the above. */
fp8_inv(t1, t1);
@@ -2165,30 +2508,58 @@ void fp48_back_cyc_sim(fp48_t c[], const fp48_t a[], int n) {
}
for (int i = 0; i < n; i++) {
- if (fp8_is_zero(a[i][1][0])) {
- /* If g2 = 0, t0 = 2 * g4 * g5, t1 = g3. */
- fp8_mul(t0[i], a[i][0][1], a[i][1][2]);
- fp8_dbl(t0[i], t0[i]);
- fp8_copy(t1[i], a[i][0][2]);
- } else {
- /* t0 = g4^2. */
- fp8_sqr(t0[i], a[i][0][1]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp8_sub(t1[i], t0[i], a[i][0][2]);
- fp8_dbl(t1[i], t1[i]);
- fp8_add(t1[i], t1[i], t0[i]);
- /* t0 = E * g5^2 + t1. */
- fp8_sqr(t2[i], a[i][1][2]);
- fp8_mul_art(t0[i], t2[i]);
- fp8_add(t0[i], t0[i], t1[i]);
- /* t1 = (4 * g2). */
- fp8_dbl(t1[i], a[i][1][0]);
- fp8_dbl(t1[i], t1[i]);
- }
+ int f = fp8_is_zero(a[i][1][0]);
+ /* If f, t0[i] = 2 * g4 * g5, t1[i] = g3. */
+ fp8_copy(t2[i], a[i][0][1]);
+ dv_copy_cond(t2[i][0][0][0], a[i][1][2][0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][0][0][1], a[i][1][2][0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][0][1][0], a[i][1][2][0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][0][1][1], a[i][1][2][0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1][0][0], a[i][1][2][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1][0][1], a[i][1][2][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1][1][0], a[i][1][2][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][1][1][1], a[i][1][2][1][1][1], RLC_FP_DIGS, f);
+ /* t0[i] = g4^2. */
+ fp8_mul(t0[i], a[i][0][1], t2[i]);
+ fp8_dbl(t2[i], t0[i]);
+ dv_copy_cond(t0[i][0][0][0], t2[i][0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][0][0][1], t2[i][0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][0][1][0], t2[i][0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][0][1][1], t2[i][0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1][0][0], t2[i][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1][0][1], t2[i][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1][1][0], t2[i][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][1][1][1], t2[i][1][1][1], RLC_FP_DIGS, f);
+ /* t1[i] = 3 * g4^2 - 2 * g3. */
+ fp8_sub(t1[i], t0[i], a[i][0][2]);
+ fp8_dbl(t1[i], t1[i]);
+ fp8_add(t1[i], t1[i], t0[i]);
+ /* t0[i] = E * g5^2 + t1[i]. */
+ fp8_sqr(t2[i], a[i][1][2]);
+ fp8_mul_art(t0[i], t2[i]);
+ fp8_add(t0[i], t0[i], t1[i]);
+ /* t1[i] = (4 * g2). */
+ fp8_dbl(t1[i], a[i][1][0]);
+ fp8_dbl(t1[i], t1[i]);
+ dv_copy_cond(t1[i][0][0][0], a[i][0][2][0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][0][1], a[i][0][2][0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][1][0], a[i][0][2][0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][1][1], a[i][0][2][0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][0][0], a[i][0][2][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][0][1], a[i][0][2][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][1][0], a[i][0][2][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][1][1], a[i][0][2][1][1][1], RLC_FP_DIGS, f);
/* If unity, decompress to unity as well. */
- if (fp48_cmp_dig(a[i], 1) == RLC_EQ) {
- fp8_set_dig(t1[i], 1);
- }
+ f = fp48_cmp_dig(a[i], 1) == RLC_EQ;
+ fp8_set_dig(t2[i], 1);
+ dv_copy_cond(t1[i][0][0][0], t2[i][0][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][0][1], t2[i][0][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][1][0], t2[i][0][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][0][1][1], t2[i][0][1][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][0][0], t2[i][1][0][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][0][1], t2[i][1][0][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][1][0], t2[i][1][1][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][1][1][1], t2[i][1][1][1], RLC_FP_DIGS, f);
}
/* t1 = 1 / t1. */
@@ -2324,6 +2695,108 @@ void fp48_exp_cyc(fp48_t c, const fp48_t a, const bn_t b) {
}
}
+void fp48_exp_cyc_sim(fp48_t e, const fp48_t a, const bn_t b, const fp48_t c,
+ const bn_t d) {
+ int n0, n1;
+ int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1], *_k, *_m;
+ fp48_t r, t0[1 << (RLC_WIDTH - 2)];
+ fp48_t s, t1[1 << (RLC_WIDTH - 2)];
+ size_t l, l0, l1;
+
+ if (bn_is_zero(b)) {
+ return fp48_exp_cyc(e, c, d);
+ }
+
+ if (bn_is_zero(d)) {
+ return fp48_exp_cyc(e, a, b);
+ }
+
+ fp48_null(r);
+ fp48_null(s);
+
+ RLC_TRY {
+ fp48_new(r);
+ fp48_new(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i ++) {
+ fp48_null(t0[i]);
+ fp48_null(t1[i]);
+ fp48_new(t0[i]);
+ fp48_new(t1[i]);
+ }
+
+#if RLC_WIDTH > 2
+ fp48_sqr(t0[0], a);
+ fp48_mul(t0[1], t0[0], a);
+ for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp48_mul(t0[i], t0[i - 1], t0[0]);
+ }
+
+ fp48_sqr(t1[0], c);
+ fp48_mul(t1[1], t1[0], c);
+ for (int i = 2; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp48_mul(t1[i], t1[i - 1], t1[0]);
+ }
+#endif
+ fp48_copy(t0[0], a);
+ fp48_copy(t1[0], c);
+
+ l0 = l1 = RLC_FP_BITS + 1;
+ bn_rec_naf(naf0, &l0, b, RLC_WIDTH);
+ bn_rec_naf(naf1, &l1, d, RLC_WIDTH);
+
+ l = RLC_MAX(l0, l1);
+ if (bn_sign(b) == RLC_NEG) {
+ for (size_t i = 0; i < l0; i++) {
+ naf0[i] = -naf0[i];
+ }
+ }
+ if (bn_sign(d) == RLC_NEG) {
+ for (size_t i = 0; i < l1; i++) {
+ naf1[i] = -naf1[i];
+ }
+ }
+
+ _k = naf0 + l - 1;
+ _m = naf1 + l - 1;
+
+ fp48_set_dig(r, 1);
+ for (int i = l - 1; i >= 0; i--, _k--, _m--) {
+ fp48_sqr(r, r);
+
+ n0 = *_k;
+ n1 = *_m;
+
+ if (n0 > 0) {
+ fp48_mul(r, r, t0[n0 / 2]);
+ }
+ if (n0 < 0) {
+ fp48_inv_cyc(s, t0[-n0 / 2]);
+ fp48_mul(r, r, s);
+ }
+ if (n1 > 0) {
+ fp48_mul(r, r, t1[n1 / 2]);
+ }
+ if (n1 < 0) {
+ fp48_inv_cyc(s, t1[-n1 / 2]);
+ fp48_mul(r, r, s);
+ }
+ }
+
+ fp48_copy(e, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp48_free(r);
+ fp48_free(s);
+ for (int i = 0; i < (1 << (RLC_WIDTH - 2)); i++) {
+ fp48_free(t0[i]);
+ fp48_free(t1[i]);
+ }
+ }
+}
+
void fp48_exp_cyc_sps(fp48_t c, const fp48_t a, const int *b, size_t len,
int sign) {
size_t i, j, k, w = len;
@@ -2475,8 +2948,22 @@ void fp54_back_cyc(fp54_t c, const fp54_t a) {
fp9_new(t1);
fp9_new(t2);
+ int f = fp9_is_zero(a[1][0]);
+ /* If f, t0 = 2 * g4 * g5, t1 = g3. */
+ fp9_copy(t2, a[2][0]);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t2[j][0], a[2][1][j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[j][1], a[2][1][j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[j][2], a[2][1][j][2], RLC_FP_DIGS, f);
+ }
/* t0 = g4^2. */
- fp9_sqr(t0, a[2][0]);
+ fp9_mul(t0, a[2][0], t2);
+ fp9_dbl(t2, t0);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t0[j][0], t2[j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[j][1], t2[j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[j][2], t2[j][2], RLC_FP_DIGS, f);
+ }
/* t1 = 3 * g4^2 - 2 * g3. */
fp9_sub(t1, t0, a[1][1]);
fp9_dbl(t1, t1);
@@ -2485,6 +2972,23 @@ void fp54_back_cyc(fp54_t c, const fp54_t a) {
fp9_sqr(t2, a[2][1]);
fp9_mul_art(t0, t2);
fp9_add(t0, t0, t1);
+ /* t1 = (4 * g2). */
+ fp9_dbl(t1, a[1][0]);
+ fp9_dbl(t1, t1);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t1[j][0], a[1][1][j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[j][1], a[1][1][j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[j][2], a[1][1][j][2], RLC_FP_DIGS, f);
+ }
+ /* If unity, decompress to unity as well. */
+ f = fp54_cmp_dig(a, 1) == RLC_EQ;
+ fp9_set_dig(t2, 1);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t1[j][0], t2[j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[j][1], t2[j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[j][2], t2[j][2], RLC_FP_DIGS, f);
+ }
+
/* t1 = 1/(4 * g2). */
fp9_dbl(t1, a[1][0]);
fp9_dbl(t1, t1);
@@ -2544,29 +3048,45 @@ void fp54_back_cyc_sim(fp54_t c[], const fp54_t a[], int n) {
}
for (int i = 0; i < n; i++) {
- if (fp9_is_zero(a[i][1][0])) {
- /* t0 = 2 * g4 * g5, t1 = g3. */
- fp9_mul(t0[i], a[i][2][0], a[i][2][1]);
- fp9_dbl(t0[i], t0[i]);
- fp9_copy(t1[i], a[i][1][1]);
- } else {
- /* t0 = g4^2. */
- fp9_sqr(t0[i], a[i][2][0]);
- /* t1 = 3 * g4^2 - 2 * g3. */
- fp9_sub(t1[i], t0[i], a[i][1][1]);
- fp9_dbl(t1[i], t1[i]);
- fp9_add(t1[i], t1[i], t0[i]);
- /* t0 = E * g5^2 + t1. */
- fp9_sqr(t2[i], a[i][2][1]);
- fp9_mul_art(t0[i], t2[i]);
- fp9_add(t0[i], t0[i], t1[i]);
- /* t1 = (4 * g2). */
- fp9_dbl(t1[i], a[i][1][0]);
- fp9_dbl(t1[i], t1[i]);
+ int f = fp9_is_zero(a[i][1][0]);
+ /* If f, t0[i] = 2 * g4 * g5, t1[i] = g3. */
+ fp9_copy(t2[i], a[i][2][0]);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t2[i][j][0], a[i][2][1][j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][j][1], a[i][2][1][j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t2[i][j][2], a[i][2][1][j][2], RLC_FP_DIGS, f);
+ }
+ /* t0[i] = g4^2. */
+ fp9_mul(t0[i], a[i][2][0], t2[i]);
+ fp9_dbl(t2[i], t0[i]);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t0[i][j][0], t2[i][j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][j][1], t2[i][j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t0[i][j][2], t2[i][j][2], RLC_FP_DIGS, f);
+ }
+ /* t1[i] = 3 * g4^2 - 2 * g3. */
+ fp9_sub(t1[i], t0[i], a[i][1][1]);
+ fp9_dbl(t1[i], t1[i]);
+ fp9_add(t1[i], t1[i], t0[i]);
+ /* t0[i] = E * g5^2 + t1[i]. */
+ fp9_sqr(t2[i], a[i][2][1]);
+ fp9_mul_art(t0[i], t2[i]);
+ fp9_add(t0[i], t0[i], t1[i]);
+ /* t1[i] = (4 * g2). */
+ fp9_dbl(t1[i], a[i][1][0]);
+ fp9_dbl(t1[i], t1[i]);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t1[i][j][0], a[i][1][1][j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][j][1], a[i][1][1][j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][j][2], a[i][1][1][j][2], RLC_FP_DIGS, f);
}
/* If unity, decompress to unity as well. */
- if (fp54_cmp_dig(a[i], 1) == RLC_EQ) {
- fp9_set_dig(t1[i], 1);
+ f = fp54_cmp_dig(a[i], 1) == RLC_EQ;
+ fp9_set_dig(t2[i], 1);
+ for (int j = 0; j < 3; j++) {
+ dv_copy_cond(t1[i][j][0], t2[i][j][0], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][j][1], t2[i][j][1], RLC_FP_DIGS, f);
+ dv_copy_cond(t1[i][j][2], t2[i][j][2], RLC_FP_DIGS, f);
}
}
diff --git a/src/fpx/relic_fpx_exp.c b/src/fpx/relic_fpx_exp.c
index fd9d506bd..665087e84 100644
--- a/src/fpx/relic_fpx_exp.c
+++ b/src/fpx/relic_fpx_exp.c
@@ -249,6 +249,66 @@ void fp8_exp(fp8_t c, const fp8_t a, const bn_t b) {
}
}
+void fp8_exp_dig(fp8_t c, const fp8_t a, dig_t b) {
+ bn_t _b;
+ fp8_t t, v;
+ int8_t u, naf[RLC_DIG + 1];
+ size_t l;
+
+ if (b == 0) {
+ fp8_set_dig(c, 1);
+ return;
+ }
+
+ bn_null(_b);
+ fp8_null(t);
+ fp8_null(v);
+
+ RLC_TRY {
+ bn_new(_b);
+ fp8_new(t);
+ fp8_new(v);
+
+ fp8_copy(t, a);
+
+ if (fp8_test_cyc(a)) {
+ fp8_inv_cyc(v, a);
+ bn_set_dig(_b, b);
+
+ l = RLC_DIG + 1;
+ bn_rec_naf(naf, &l, _b, 2);
+
+ for (int i = bn_bits(_b) - 2; i >= 0; i--) {
+ fp8_sqr_cyc(t, t);
+
+ u = naf[i];
+ if (u > 0) {
+ fp8_mul(t, t, a);
+ } else if (u < 0) {
+ fp8_mul(t, t, v);
+ }
+ }
+ } else {
+ for (int i = util_bits_dig(b) - 2; i >= 0; i--) {
+ fp8_sqr(t, t);
+ if (b & ((dig_t)1 << i)) {
+ fp8_mul(t, t, a);
+ }
+ }
+ }
+
+ fp8_copy(c, t);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(_b);
+ fp8_free(t);
+ fp8_free(v);
+ }
+}
+
void fp9_exp(fp9_t c, const fp9_t a, const bn_t b) {
fp9_t t;
@@ -385,6 +445,106 @@ void fp12_exp_dig(fp12_t c, const fp12_t a, dig_t b) {
}
}
+void fp16_exp(fp16_t c, const fp16_t a, const bn_t b) {
+ fp16_t t;
+
+ if (bn_is_zero(b)) {
+ fp16_set_dig(c, 1);
+ return;
+ }
+
+ fp16_null(t);
+
+ RLC_TRY {
+ fp16_new(t);
+
+ if (fp16_test_cyc(a)) {
+ fp16_exp_cyc(c, a, b);
+ } else {
+ fp16_copy(t, a);
+
+ for (int i = bn_bits(b) - 2; i >= 0; i--) {
+ fp16_sqr(t, t);
+ if (bn_get_bit(b, i)) {
+ fp16_mul(t, t, a);
+ }
+ }
+
+ if (bn_sign(b) == RLC_NEG) {
+ fp16_inv(c, t);
+ } else {
+ fp16_copy(c, t);
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(t);
+ }
+}
+
+void fp16_exp_dig(fp16_t c, const fp16_t a, dig_t b) {
+ bn_t _b;
+ fp16_t t, v;
+ int8_t u, naf[RLC_DIG + 1];
+ size_t l;
+
+ if (b == 0) {
+ fp16_set_dig(c, 1);
+ return;
+ }
+
+ bn_null(_b);
+ fp16_null(t);
+ fp16_null(v);
+
+ RLC_TRY {
+ bn_new(_b);
+ fp16_new(t);
+ fp16_new(v);
+
+ fp16_copy(t, a);
+
+ if (fp16_test_cyc(a)) {
+ fp16_inv_cyc(v, a);
+ bn_set_dig(_b, b);
+
+ l = RLC_DIG + 1;
+ bn_rec_naf(naf, &l, _b, 2);
+
+ for (int i = bn_bits(_b) - 2; i >= 0; i--) {
+ fp16_sqr_cyc(t, t);
+
+ u = naf[i];
+ if (u > 0) {
+ fp16_mul(t, t, a);
+ } else if (u < 0) {
+ fp16_mul(t, t, v);
+ }
+ }
+ } else {
+ for (int i = util_bits_dig(b) - 2; i >= 0; i--) {
+ fp16_sqr(t, t);
+ if (b & ((dig_t)1 << i)) {
+ fp16_mul(t, t, a);
+ }
+ }
+ }
+
+ fp16_copy(c, t);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(_b);
+ fp16_free(t);
+ fp16_free(v);
+ }
+}
+
void fp18_exp(fp18_t c, const fp18_t a, const bn_t b) {
fp18_t t;
diff --git a/src/fpx/relic_fpx_field.c b/src/fpx/relic_fpx_field.c
index 0f86dfa27..cb05e31ce 100644
--- a/src/fpx/relic_fpx_field.c
+++ b/src/fpx/relic_fpx_field.c
@@ -49,9 +49,14 @@ int fp2_field_get_qnr() {
int fp3_field_get_cnr() {
#if FP_PRIME == 638
- return 8;
+ if (fp_param_get() == K18_638) {
+ return 8;
+ } else {
+ return 3;
+ }
#endif
- return 0;
+
+ return core_get()->cnr3;
}
void fp2_field_init(void) {
@@ -77,10 +82,11 @@ void fp2_field_init(void) {
fp_zero(t0[0]);
fp_set_dig(t0[1], 1);
/* If it does not work, attempt (u + 2), otherwise double. */
- if (fp2_srt(t1, t0) == 1) {
+ /* We cannot used QR test here because Frobenius constants below. */
+ if (fp2_srt(t1, t0)) {
ctx->qnr2 = 2;
fp_set_dig(t0[0], ctx->qnr2);
- while (fp2_srt(t1, t0) == 1 && util_bits_dig(ctx->qnr2) < RLC_DIG - 1) {
+ while (fp2_srt(t1, t0) && util_bits_dig(ctx->qnr2) < RLC_DIG - 1) {
/* Pick a power of 2 for efficiency. */
ctx->qnr2 *= 2;
fp_set_dig(t0[0], ctx->qnr2);
@@ -123,25 +129,35 @@ void fp2_field_init(void) {
fp_copy(ctx->fp2_p2[0][0], t0[0]);
fp_copy(ctx->fp2_p2[0][1], t0[1]);
- /* Compute QNR^(p - (p mod 12))/12. */
+ /* Compute QNR^(p - (p mod 8))/8. */
fp2_set_dig(t1, 1);
fp2_mul_nor(t0, t1);
e->used = RLC_FP_DIGS;
dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
- bn_div_dig(e, e, 12);
+ bn_div_dig(e, e, 8);
fp2_exp(t0, t0, e);
fp_copy(ctx->fp2_p2[1][0], t0[0]);
fp_copy(ctx->fp2_p2[1][1], t0[1]);
- /* Compute QNR^(p - (p mod 24))/24. */
+ /* Compute QNR^(p - (p mod 12))/12. */
fp2_set_dig(t1, 1);
fp2_mul_nor(t0, t1);
e->used = RLC_FP_DIGS;
dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
- bn_div_dig(e, e, 24);
+ bn_div_dig(e, e, 12);
fp2_exp(t0, t0, e);
fp_copy(ctx->fp2_p2[2][0], t0[0]);
fp_copy(ctx->fp2_p2[2][1], t0[1]);
+
+ /* Compute QNR^(p - (p mod 24))/24. */
+ fp2_set_dig(t1, 1);
+ fp2_mul_nor(t0, t1);
+ e->used = RLC_FP_DIGS;
+ dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
+ bn_div_dig(e, e, 24);
+ fp2_exp(t0, t0, e);
+ fp_copy(ctx->fp2_p2[3][0], t0[0]);
+ fp_copy(ctx->fp2_p2[3][1], t0[1]);
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
@@ -165,6 +181,24 @@ void fp3_field_init(void) {
fp3_new(t0);
fp3_new(t1);
+ /* Start by trying a trivial quadratic non-residue. */
+ ctx->cnr3 = 0;
+ fp_zero(t0[0]);
+ fp_set_dig(t0[1], 1);
+ fp_zero(t0[2]);
+ /* If it does not work, attempt (u + 1), otherwise double. */
+ /* This code will fail if p \neq 1 mod 8 because square root in Fp^3
+ * relic on Frobenius. Must implement explicit test for those cases. */
+ if (fp3_srt(t1, t0)) {
+ ctx->cnr3 = 1;
+ fp_set_dig(t0[0], ctx->cnr3);
+ while (fp3_srt(t1, t0) && util_bits_dig(ctx->qnr2) < RLC_DIG - 1) {
+ /* Pick a power of 2 for efficiency. */
+ ctx->cnr3 *= 2;
+ fp_set_dig(t0[0], ctx->cnr3);
+ }
+ }
+
/* Compute t0 = u^((p - (p mod 3))/3). */
if (fp_prime_get_cnr() < 0) {
fp_set_dig(ctx->fp3_p0[0], -fp_prime_get_cnr());
@@ -183,7 +217,6 @@ void fp3_field_init(void) {
bn_read_raw(e, fp_prime_get(), RLC_FP_DIGS);
bn_div_dig(e, e, 6);
fp3_exp(t0, t0, e);
-
if (fp3_field_get_cnr() == 0) {
/* Look for a non-trivial subfield element.. */
ctx->frb3[0] = 0;
@@ -234,7 +267,9 @@ void fp3_field_init(void) {
while (ctx->frb3[1] < 3 && fp_is_zero(t0[ctx->frb3[1]++]));
fp_copy(ctx->fp3_p2[0][0], t0[--ctx->frb3[1]]);
} else {
- fp3_copy(ctx->fp3_p2[0], t0);
+ fp_copy(ctx->fp3_p2[0][0], t0[0]);
+ fp_copy(ctx->fp3_p2[0][1], t0[1]);
+ fp_copy(ctx->fp3_p2[0][2], t0[2]);
}
/* Compute t0 = u^((p - (p mod 18))/18). */
@@ -249,7 +284,9 @@ void fp3_field_init(void) {
while (ctx->frb3[2] < 3 && fp_is_zero(t0[ctx->frb3[2]++]));
fp_copy(ctx->fp3_p2[1][0], t0[--ctx->frb3[2]]);
} else {
- fp3_copy(ctx->fp3_p2[1], t0);
+ fp_copy(ctx->fp3_p2[1][0], t0[0]);
+ fp_copy(ctx->fp3_p2[1][1], t0[1]);
+ fp_copy(ctx->fp3_p2[1][2], t0[2]);
}
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
@@ -295,3 +332,39 @@ void fp4_field_init() {
fp4_free(t0);
}
}
+
+void fp8_field_init() {
+ bn_t e;
+ fp8_t t0;
+ ctx_t *ctx = core_get();
+
+ bn_null(e);
+ fp8_null(t0);
+
+ RLC_TRY {
+ bn_new(e);
+ fp8_new(t0);
+
+ fp8_set_dig(t0, 1);
+ fp8_mul_art(t0, t0);
+ e->used = RLC_FP_DIGS;
+ dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
+ bn_sub_dig(e, e, 1);
+ bn_div_dig(e, e, 6);
+ fp8_exp(t0, t0, e);
+ if (fp4_is_zero(t0[1])) {
+ ctx->frb8 = 0;
+ fp_copy(ctx->fp8_p1[0], t0[0][0][0]);
+ fp_copy(ctx->fp8_p1[1], t0[0][0][1]);
+ } else {
+ ctx->frb8 = 1;
+ fp_copy(ctx->fp8_p1[0], t0[1][1][0]);
+ fp_copy(ctx->fp8_p1[1], t0[1][1][1]);
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(e);
+ fp8_free(t0);
+ }
+}
diff --git a/src/fpx/relic_fpx_frb.c b/src/fpx/relic_fpx_frb.c
index 970671bfe..1578b791b 100644
--- a/src/fpx/relic_fpx_frb.c
+++ b/src/fpx/relic_fpx_frb.c
@@ -67,7 +67,12 @@ void fp4_frb(fp4_t c, const fp4_t a, int i) {
for (; i % 4 > 0; i--) {
fp2_frb(c[0], c[0], 1);
fp2_frb(c[1], c[1], 1);
- fp2_mul_frb(c[1], c[1], 1, 3);
+ if (fp_prime_get_mod18() % 3 == 1) {
+ fp2_mul_frb(c[1], c[1], 1, 3);
+ } else {
+ fp2_mul_frb(c[1], c[1], 2, 1);
+ fp2_mul_frb(c[1], c[1], 2, 1);
+ }
}
}
@@ -91,7 +96,7 @@ void fp8_frb(fp8_t c, const fp8_t a, int i) {
fp4_frb(c[1], c[1], 1);
fp2_mul_frb(c[1][0], c[1][0], 2, 1);
fp2_mul_frb(c[1][1], c[1][1], 2, 1);
- if (fp_prime_get_mod8() != 1 && fp_prime_get_mod8() != 5) {
+ if (fp_prime_get_mod8() % 4 != 1) {
fp4_mul_art(c[1], c[1]);
}
}
@@ -123,8 +128,28 @@ void fp12_frb(fp12_t c, const fp12_t a, int i) {
}
}
+void fp16_frb(fp16_t c, const fp16_t a, int i) {
+ /* Cost of four multiplication in Fp^2 per Frobenius. */
+ fp16_copy(c, a);
+ for (; i % 8 > 0; i--) {
+ fp8_frb(c[0], c[0], 1);
+ fp8_frb(c[1], c[1], 1);
+ fp2_mul_frb(c[1][0][0], c[1][0][0], 2, 2);
+ fp2_mul_frb(c[1][0][1], c[1][0][1], 2, 2);
+ fp2_mul_frb(c[1][1][0], c[1][1][0], 2, 2);
+ fp2_mul_frb(c[1][1][1], c[1][1][1], 2, 2);
+ if (fp_prime_get_mod8() % 4 != 1) {
+ fp8_mul_art(c[1], c[1]);
+ }
+ if (fp_prime_get_mod8() == 5) {
+ fp4_mul_art(c[1][0], c[1][0]);
+ fp4_mul_art(c[1][1], c[1][1]);
+ }
+ }
+}
+
void fp18_frb(fp18_t c, const fp18_t a, int i) {
- /* Cost of five multiplication in Fp^2 per Frobenius. */
+ /* Cost of five multiplication in Fp^3 per Frobenius. */
fp18_copy(c, a);
for (; i % 18 > 0; i--) {
fp9_frb(c[0], c[0], 1);
@@ -146,7 +171,7 @@ void fp24_frb(fp24_t c, const fp24_t a, int i) {
fp8_frb(c[2], c[2], 1);
for (int j = 0; j < 2; j++) {
for (int l = 0; l < 2; l++) {
- fp2_mul_frb(c[1][j][l], c[1][j][l], 2, 2);
+ fp2_mul_frb(c[1][j][l], c[1][j][l], 2, 3);
fp2_mul_frb(c[2][j][l], c[2][j][l], 1, 1);
}
if ((fp_prime_get_mod8() % 4) == 3) {
@@ -165,7 +190,7 @@ void fp48_frb(fp48_t c, const fp48_t a, int i) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 2; k++) {
for (int l = 0; l < 2; l++) {
- fp2_mul_frb(c[1][j][k][l], c[1][j][k][l], 2, 3);
+ fp2_mul_frb(c[1][j][k][l], c[1][j][k][l], 2, 4);
}
if (fp_prime_get_mod8() == 3) {
fp4_mul_art(c[1][j][k], c[1][j][k]);
@@ -187,7 +212,7 @@ void fp54_frb(fp54_t c, const fp54_t a, int i) {
fp18_frb(c[2], c[2], 1);
for (int j = 0; j < 2; j++) {
for (int l = 0; l < 3; l++) {
- fp3_mul_frb(c[1][j][l], c[1][j][l], 2, 2);
+ fp3_mul_frb(c[1][j][l], c[1][j][l], 2, 3);
fp3_mul_frb(c[2][j][l], c[2][j][l], 2, 1);
}
/* This is not genreal enough, so hard code parameters needing the
diff --git a/src/fpx/relic_fpx_inv.c b/src/fpx/relic_fpx_inv.c
index 1ffe85d37..d99c4ace3 100644
--- a/src/fpx/relic_fpx_inv.c
+++ b/src/fpx/relic_fpx_inv.c
@@ -609,6 +609,82 @@ void fp12_inv_cyc(fp12_t c, const fp12_t a) {
fp6_neg(c[1], a[1]);
}
+void fp16_inv_cyc(fp16_t c, const fp16_t a) {
+ fp8_copy(c[0], a[0]);
+ fp8_neg(c[1], a[1]);
+}
+
+void fp16_inv(fp16_t c, const fp16_t a) {
+ fp8_t t0;
+ fp8_t t1;
+
+ fp8_null(t0);
+ fp8_null(t1);
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+
+ fp8_sqr(t0, a[0]);
+ fp8_sqr(t1, a[1]);
+ fp8_mul_art(t1, t1);
+ fp8_sub(t0, t0, t1);
+ fp8_inv(t0, t0);
+
+ fp8_mul(c[0], a[0], t0);
+ fp8_neg(c[1], a[1]);
+ fp8_mul(c[1], c[1], t0);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ }
+}
+
+void fp16_inv_sim(fp16_t *c, const fp16_t *a, int n) {
+ int i;
+ fp16_t u, *t = RLC_ALLOCA(fp16_t, n);
+
+ for (i = 0; i < n; i++) {
+ fp16_null(t[i]);
+ }
+ fp16_null(u);
+
+ RLC_TRY {
+ for (i = 0; i < n; i++) {
+ fp16_new(t[i]);
+ }
+ fp16_new(u);
+
+ fp16_copy(c[0], a[0]);
+ fp16_copy(t[0], a[0]);
+
+ for (i = 1; i < n; i++) {
+ fp16_copy(t[i], a[i]);
+ fp16_mul(c[i], c[i - 1], t[i]);
+ }
+
+ fp16_inv(u, c[n - 1]);
+
+ for (i = n - 1; i > 0; i--) {
+ fp16_mul(c[i], c[i - 1], u);
+ fp16_mul(u, u, t[i]);
+ }
+ fp16_copy(c[0], u);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ for (i = 0; i < n; i++) {
+ fp16_free(t[i]);
+ }
+ fp16_free(u);
+ RLC_FREE(t);
+ }
+}
+
void fp18_inv(fp18_t c, const fp18_t a) {
fp9_t t0;
fp9_t t1;
diff --git a/src/fpx/relic_fpx_pck.c b/src/fpx/relic_fpx_pck.c
index 490e8607a..aeeec25f6 100644
--- a/src/fpx/relic_fpx_pck.c
+++ b/src/fpx/relic_fpx_pck.c
@@ -155,46 +155,46 @@ int fp12_upk_max(fp12_t c, const fp12_t a) {
}
}
-void fp24_pck(fp24_t c, const fp24_t a) {
- fp24_copy(c, a);
- if (fp24_test_cyc(c)) {
- fp4_zero(c[0][0]);
- fp4_zero(c[0][1]);
+void fp18_pck(fp18_t c, const fp18_t a) {
+ fp18_copy(c, a);
+ if (fp18_test_cyc(c)) {
+ fp2_zero(c[0][0]);
+ fp2_zero(c[1][1]);
}
}
-int fp24_upk(fp24_t c, const fp24_t a) {
- if (fp4_is_zero(a[0][0]) && fp4_is_zero(a[0][1])) {
- fp24_back_cyc(c, a);
- if (fp24_test_cyc(c)) {
+int fp18_upk(fp18_t c, const fp18_t a) {
+ if (fp2_is_zero(a[0][0]) && fp2_is_zero(a[1][1])) {
+ fp18_back_cyc(c, a);
+ if (fp18_test_cyc(c)) {
return 1;
} else {
return 0;
}
} else {
- fp24_copy(c, a);
+ fp18_copy(c, a);
return 1;
}
}
-void fp18_pck(fp18_t c, const fp18_t a) {
- fp18_copy(c, a);
- if (fp18_test_cyc(c)) {
- fp2_zero(c[0][0]);
- fp2_zero(c[1][1]);
+void fp24_pck(fp24_t c, const fp24_t a) {
+ fp24_copy(c, a);
+ if (fp24_test_cyc(c)) {
+ fp4_zero(c[0][0]);
+ fp4_zero(c[0][1]);
}
}
-int fp18_upk(fp18_t c, const fp18_t a) {
- if (fp2_is_zero(a[0][0]) && fp2_is_zero(a[1][1])) {
- fp18_back_cyc(c, a);
- if (fp18_test_cyc(c)) {
+int fp24_upk(fp24_t c, const fp24_t a) {
+ if (fp4_is_zero(a[0][0]) && fp4_is_zero(a[0][1])) {
+ fp24_back_cyc(c, a);
+ if (fp24_test_cyc(c)) {
return 1;
} else {
return 0;
}
} else {
- fp18_copy(c, a);
+ fp24_copy(c, a);
return 1;
}
}
diff --git a/src/fpx/relic_fpx_srt.c b/src/fpx/relic_fpx_srt.c
index 5a08cd827..574e36825 100644
--- a/src/fpx/relic_fpx_srt.c
+++ b/src/fpx/relic_fpx_srt.c
@@ -36,6 +36,31 @@
/* Public definitions */
/*============================================================================*/
+int fp2_is_sqr(const fp2_t a) {
+ fp2_t t;
+ int r = 0;
+
+ fp2_null(t);
+
+ /* QR testing in extension fields from "Square root computation over
+ * even extension fields", by Gora Adj and Francisco RodrÃguez-HenrÃquez.
+ * https://eprint.iacr.org/2012/685 */
+
+ RLC_TRY {
+ fp2_new(t);
+
+ fp2_frb(t, a, 1);
+ fp2_mul(t, t, a);
+ r = fp_is_sqr(t[0]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp2_free(t);
+ }
+
+ return r;
+}
+
int fp2_srt(fp2_t c, const fp2_t a) {
int r = 0;
fp_t t0;
@@ -60,7 +85,8 @@ int fp2_srt(fp2_t c, const fp2_t a) {
/* special case: either a[0] is square and sqrt is purely 'real'
* or a[0] is non-square and sqrt is purely 'imaginary' */
r = 1;
- if (fp_srt(t0, a[0])) {
+ if (fp_is_sqr(a[0])) {
+ fp_srt(t0, a[0]);
fp_copy(c[0], t0);
fp_zero(c[1]);
} else {
@@ -92,20 +118,18 @@ int fp2_srt(fp2_t c, const fp2_t a) {
}
fp_add(t0, t0, t1);
- if (fp_srt(t1, t0)) {
+ if (fp_is_sqr(t0)) {
+ fp_srt(t1, t0);
/* t0 = (a_0 + sqrt(t0)) / 2 */
fp_add(t0, a[0], t1);
fp_hlv(t0, t0);
+ /* t1 = (a_0 - sqrt(t0)) / 2 */
+ fp_sub(t1, a[0], t1);
+ fp_hlv(t1, t1);
+ dv_copy_cond(t0, t1, RLC_FP_DIGS, !fp_is_sqr(t0));
- if (!fp_srt(t2, t0)) {
- /* t0 = (a_0 - sqrt(t0)) / 2 */
- fp_sub(t0, a[0], t1);
- fp_hlv(t0, t0);
- if (!fp_srt(t2, t0)) {
- /* should never happen! */
- RLC_THROW(ERR_NO_VALID);
- }
- }
+ /* Should always be a quadratic residue. */
+ fp_srt(t2, t0);
/* c_0 = sqrt(t0) */
fp_copy(c[0], t2);
/* c_1 = a_1 / (2 * sqrt(t0)) */
@@ -127,15 +151,44 @@ int fp2_srt(fp2_t c, const fp2_t a) {
return r;
}
+int fp3_is_sqr(const fp3_t a) {
+ fp3_t t, u;
+ int r;
+
+ fp3_null(t);
+ fp3_null(u);
+
+ RLC_TRY {
+ fp3_new(t);
+ fp3_new(u);
+
+ fp3_frb(u, a, 1);
+ fp3_mul(t, u, a);
+ fp3_frb(u, u, 1);
+ fp3_mul(t, t, u);
+ r = fp_is_sqr(t[0]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp2_free(t);
+ fp2_free(u);
+ }
+
+ return r;
+}
+
int fp3_srt(fp3_t c, const fp3_t a) {
- int r = 0;
+ int f = 0, r = 0;
+ fp_t root;
fp3_t t0, t1, t2, t3;
- bn_t e;
+ bn_t d, e;
+ fp_null(root);
fp3_null(t0);
fp3_null(t1);
fp3_null(t2);
fp3_null(t3);
+ bn_null(d);
bn_null(e);
if (fp3_is_zero(a)) {
@@ -144,13 +197,72 @@ int fp3_srt(fp3_t c, const fp3_t a) {
}
RLC_TRY {
+ fp_new(root);
fp3_new(t0);
fp3_new(t1);
fp3_new(t2);
fp3_new(t3);
+ bn_new(d);
bn_new(e);
+ e->used = RLC_FP_DIGS;
+ dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
+
switch (fp_prime_get_mod8()) {
+ case 1:
+ /* Implement constant-time version of Tonelli-Shanks algorithm
+ * as per https://eprint.iacr.org/2020/1497.pdf */
+
+ /* Compute progenitor as x^(p^3-1-2^f)/2^(f+1) for 2^f|(p-1).
+ * Let q = (p-1)/2^f. We will write the exponent in p and q.
+ * Write (p^3-1-2^f)/2^(f+1) as (q*(p^2+p))/2 + (q - 1)/2 */
+ bn_sqr(d, e);
+ bn_add(d, d, e);
+ bn_rsh(d, d, 1);
+ /* Compute (q - 1)/2 = (p-1)/2^(f+1).*/
+ f = fp_prime_get_2ad();
+ bn_sub_dig(e, e, 1);
+ bn_rsh(e, e, f + 1);
+ fp3_exp(t1, a, e);
+ /* Now compute the power (q*(p^2+p))/2. */
+ fp3_sqr(t0, t1);
+ fp3_mul(t0, t0, a);
+ fp3_exp(t0, t0, d);
+ fp3_mul(t0, t0, t1);
+
+ /* Generate root of unity, and continue algorithm. */
+ dv_copy(root, fp_prime_get_srt(), RLC_FP_DIGS);
+
+ fp3_sqr(t1, t0);
+ fp3_mul(t1, t1, a);
+ fp3_mul(t3, t0, a);
+ fp3_copy(t2, t1);
+ for (int j = f; j > 1; j--) {
+ for (int i = 1; i < j - 1; i++) {
+ fp3_sqr(t2, t2);
+ }
+ fp_mul(t0[0], t3[0], root);
+ fp_mul(t0[1], t3[1], root);
+ fp_mul(t0[2], t3[2], root);
+ dv_copy_cond(t3[0], t0[0], RLC_FP_DIGS,
+ fp3_cmp_dig(t2, 1) != RLC_EQ);
+ dv_copy_cond(t3[1], t0[1], RLC_FP_DIGS,
+ fp3_cmp_dig(t2, 1) != RLC_EQ);
+ dv_copy_cond(t3[2], t0[2], RLC_FP_DIGS,
+ fp3_cmp_dig(t2, 1) != RLC_EQ);
+ fp_sqr(root, root);
+ fp_mul(t0[0], t1[0], root);
+ fp_mul(t0[1], t1[1], root);
+ fp_mul(t0[2], t1[2], root);
+ dv_copy_cond(t1[0], t0[0], RLC_FP_DIGS,
+ fp3_cmp_dig(t2, 1) != RLC_EQ);
+ dv_copy_cond(t1[1], t0[1], RLC_FP_DIGS,
+ fp3_cmp_dig(t2, 1) != RLC_EQ);
+ dv_copy_cond(t1[2], t0[2], RLC_FP_DIGS,
+ fp3_cmp_dig(t2, 1) != RLC_EQ);
+ fp3_copy(t2, t1);
+ }
+ break;
case 5:
fp3_dbl(t3, a);
fp3_frb(t0, t3, 1);
@@ -163,8 +275,6 @@ int fp3_srt(fp3_t c, const fp3_t a) {
fp3_mul(t3, t3, t1);
fp3_mul(t0, t0, t3);
- e->used = RLC_FP_DIGS;
- dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
bn_div_dig(e, e, 8);
fp3_exp(t0, t0, e);
@@ -175,7 +285,7 @@ int fp3_srt(fp3_t c, const fp3_t a) {
fp3_mul(t0, t0, a);
fp_sub_dig(t1[0], t1[0], 1);
- fp3_mul(c, t0, t1);
+ fp3_mul(t3, t0, t1);
break;
case 3:
case 7:
@@ -186,38 +296,69 @@ int fp3_srt(fp3_t c, const fp3_t a) {
fp3_mul(t3, t2, a);
fp3_mul(t0, t0, t3);
- e->used = RLC_FP_DIGS;
- dv_copy(e->dp, fp_prime_get(), RLC_FP_DIGS);
bn_div_dig(e, e, 4);
fp3_exp(t0, t0, e);
fp3_mul(t0, t0, a);
- fp3_mul(c, t0, t1);
+ fp3_mul(t3, t0, t1);
break;
default:
fp3_zero(c);
break;
}
-
- fp3_sqr(t0, c);
- if (fp3_cmp(t0, a) == RLC_EQ) {
- r = 1;
- }
+ /* Assume it is a square and test at the end. */
+ /* We cannot use QR test because it depends on Frobenius constants. */
+ fp3_sqr(t0, t3);
+ r = (fp3_cmp(t0, a) == RLC_EQ ? 1 : 0);
+ fp3_zero(c);
+ dv_copy_cond(c[0], t3[0], RLC_FP_DIGS, r);
+ dv_copy_cond(c[1], t3[1], RLC_FP_DIGS, r);
+ dv_copy_cond(c[2], t3[2], RLC_FP_DIGS, r);
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
+ fp_free(root);
fp3_free(t0);
fp3_free(t1);
fp3_free(t2);
fp3_free(t3);
+ bn_free(d);
bn_free(e);
}
return r;
}
+int fp4_is_sqr(const fp4_t a) {
+ fp4_t t, u;
+ int r;
+
+ fp4_null(t);
+ fp4_null(u);
+
+ RLC_TRY {
+ fp4_new(t);
+ fp4_new(u);
+
+ fp4_frb(u, a, 1);
+ fp4_mul(t, u, a);
+ for (int i = 2; i < 4; i++) {
+ fp4_frb(u, u, 1);
+ fp4_mul(t, t, u);
+ }
+ r = fp_is_sqr(t[0][0]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp4_free(t);
+ fp4_free(u);
+ }
+
+ return r;
+}
+
int fp4_srt(fp4_t c, const fp4_t a) {
- int r = 0;
+ int c0, r = 0;
fp2_t t0, t1, t2;
fp2_null(t0);
@@ -238,8 +379,8 @@ int fp4_srt(fp4_t c, const fp4_t a) {
/* special case: either a[0] is square and sqrt is purely 'real'
* or a[0] is non-square and sqrt is purely 'imaginary' */
r = 1;
- if (fp2_srt(t0, a[0])) {
- fp2_copy(c[0], t0);
+ if (fp2_is_sqr(a[0])) {
+ fp2_srt(c[0], a[0]);
fp2_zero(c[1]);
} else {
/* Compute a[0]/s^2. */
@@ -259,22 +400,22 @@ int fp4_srt(fp4_t c, const fp4_t a) {
fp2_sqr(t1, a[1]);
fp2_mul_nor(t2, t1);
fp2_sub(t0, t0, t2);
- if (fp2_srt(t1, t0)) {
+
+ if (fp2_is_sqr(t0)) {
+ fp2_srt(t1, t0);
/* t0 = (a_0 + sqrt(t0)) / 2 */
fp2_add(t0, a[0], t1);
fp_hlv(t0[0], t0[0]);
fp_hlv(t0[1], t0[1]);
-
- if (!fp2_srt(t2, t0)) {
- /* t0 = (a_0 - sqrt(t0)) / 2 */
- fp2_sub(t0, a[0], t1);
- fp_hlv(t0[0], t0[0]);
- fp_hlv(t0[1], t0[1]);
- if (!fp2_srt(t2, t0)) {
- /* should never happen! */
- RLC_THROW(ERR_NO_VALID);
- }
- }
+ c0 = fp2_is_sqr(t0);
+ /* t0 = (a_0 - sqrt(t0)) / 2 */
+ fp2_sub(t1, a[0], t1);
+ fp_hlv(t1[0], t1[0]);
+ fp_hlv(t1[1], t1[1]);
+ dv_copy_cond(t0[0], t1[0], RLC_FP_DIGS, !c0);
+ dv_copy_cond(t0[1], t1[1], RLC_FP_DIGS, !c0);
+ /* Should always be a quadratic residue. */
+ fp2_srt(t2, t0);
/* c_0 = sqrt(t0) */
fp2_copy(c[0], t2);
@@ -294,3 +435,234 @@ int fp4_srt(fp4_t c, const fp4_t a) {
}
return r;
}
+
+int fp8_is_sqr(const fp8_t a) {
+ fp8_t t, u;
+ int r;
+
+ fp8_null(t);
+ fp8_null(u);
+
+ RLC_TRY {
+ fp8_new(t);
+ fp8_new(u);
+
+ fp8_frb(u, a, 1);
+ fp8_mul(t, u, a);
+ for (int i = 2; i < 8; i++) {
+ fp8_frb(u, u, 1);
+ fp8_mul(t, t, u);
+ }
+ r = fp_is_sqr(t[0][0][0]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t);
+ fp8_free(u);
+ }
+
+ return r;
+}
+
+int fp8_srt(fp8_t c, const fp8_t a) {
+ int c0, r = 0;
+ fp4_t t0, t1, t2;
+
+ fp4_null(t0);
+ fp4_null(t1);
+ fp4_null(t2);
+
+ if (fp8_is_zero(a)) {
+ fp8_zero(c);
+ return 1;
+ }
+
+ RLC_TRY {
+ fp4_new(t0);
+ fp4_new(t1);
+ fp4_new(t2);
+
+ if (fp4_is_zero(a[1])) {
+ /* special case: either a[0] is square and sqrt is purely 'real'
+ * or a[0] is non-square and sqrt is purely 'imaginary' */
+ r = 1;
+ if (fp4_is_sqr(a[0])) {
+ fp4_srt(c[0], a[0]);
+ fp4_zero(c[1]);
+ } else {
+ /* Compute a[0]/s^2. */
+ fp4_set_dig(t0, 1);
+ fp4_mul_art(t0, t0);
+ fp4_inv(t0, t0);
+ fp4_mul(t0, a[0], t0);
+ fp4_zero(c[0]);
+ if (!fp4_srt(c[1], t0)) {
+ /* should never happen! */
+ RLC_THROW(ERR_NO_VALID);
+ }
+ }
+ } else {
+ /* t0 = a[0]^2 - s^2 * a[1]^2 */
+ fp4_sqr(t0, a[0]);
+ fp4_sqr(t1, a[1]);
+ fp4_mul_art(t2, t1);
+ fp4_sub(t0, t0, t2);
+
+ if (fp4_is_sqr(t0)) {
+ fp4_srt(t1, t0);
+ /* t0 = (a_0 + sqrt(t0)) / 2 */
+ fp4_add(t0, a[0], t1);
+ fp_hlv(t0[0][0], t0[0][0]);
+ fp_hlv(t0[0][1], t0[0][1]);
+ fp_hlv(t0[1][0], t0[1][0]);
+ fp_hlv(t0[1][1], t0[1][1]);
+ c0 = fp4_is_sqr(t0);
+ /* t0 = (a_0 - sqrt(t0)) / 2 */
+ fp4_sub(t1, a[0], t1);
+ fp_hlv(t1[0][0], t1[0][0]);
+ fp_hlv(t1[0][1], t1[0][1]);
+ fp_hlv(t1[1][0], t1[1][0]);
+ fp_hlv(t1[1][1], t1[1][1]);
+ dv_copy_cond(t0[0][0], t1[0][0], RLC_FP_DIGS, !c0);
+ dv_copy_cond(t0[0][1], t1[0][1], RLC_FP_DIGS, !c0);
+ dv_copy_cond(t0[1][0], t1[1][0], RLC_FP_DIGS, !c0);
+ dv_copy_cond(t0[1][1], t1[1][1], RLC_FP_DIGS, !c0);
+ /* Should always be a quadratic residue. */
+ fp4_srt(t2, t0);
+ /* c_0 = sqrt(t0) */
+ fp4_copy(c[0], t2);
+
+ /* c_1 = a_1 / (2 * sqrt(t0)) */
+ fp4_dbl(t2, t2);
+ fp4_inv(t2, t2);
+ fp4_mul(c[1], a[1], t2);
+ r = 1;
+ }
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp4_free(t0);
+ fp4_free(t1);
+ fp4_free(t2);
+ }
+ return r;
+}
+
+int fp16_is_sqr(const fp16_t a) {
+ fp16_t t, u;
+ int r;
+
+ fp16_null(t);
+ fp16_null(u);
+
+ RLC_TRY {
+ fp16_new(t);
+ fp16_new(u);
+
+ fp16_frb(u, a, 1);
+ fp16_mul(t, u, a);
+ for (int i = 2; i < 16; i++) {
+ fp16_frb(u, u, 1);
+ fp16_mul(t, t, u);
+ }
+ r = fp_is_sqr(t[0][0][0][0]);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp16_free(t);
+ fp16_free(u);
+ }
+
+ return r;
+}
+
+int fp16_srt(fp16_t c, const fp16_t a) {
+ int c0, r = 0;
+ fp8_t t0, t1, t2;
+
+ fp8_null(t0);
+ fp8_null(t1);
+ fp8_null(t2);
+
+ if (fp16_is_zero(a)) {
+ fp16_zero(c);
+ return 1;
+ }
+
+ RLC_TRY {
+ fp8_new(t0);
+ fp8_new(t1);
+ fp8_new(t2);
+
+ if (fp8_is_zero(a[1])) {
+ /* special case: either a[0] is square and sqrt is purely 'real'
+ * or a[0] is non-square and sqrt is purely 'imaginary' */
+ r = 1;
+ if (fp8_is_sqr(a[0])) {
+ fp8_srt(c[0], a[0]);
+ fp8_zero(c[1]);
+ } else {
+ /* Compute a[0]/s^2. */
+ fp8_set_dig(t0, 1);
+ fp8_mul_art(t0, t0);
+ fp8_inv(t0, t0);
+ fp8_mul(t0, a[0], t0);
+ fp8_zero(c[0]);
+ if (!fp8_srt(c[1], t0)) {
+ /* should never happen! */
+ RLC_THROW(ERR_NO_VALID);
+ }
+ }
+ } else {
+ /* t0 = a[0]^2 - s^2 * a[1]^2 */
+ fp8_sqr(t0, a[0]);
+ fp8_sqr(t1, a[1]);
+ fp8_mul_art(t2, t1);
+ fp8_sub(t0, t0, t2);
+
+ if (fp8_is_sqr(t0)) {
+ fp8_srt(t1, t0);
+ /* t0 = (a_0 + sqrt(t0)) / 2 */
+ fp8_add(t0, a[0], t1);
+ fp_hlv(t0[0][0][0], t0[0][0][0]);
+ fp_hlv(t0[0][0][1], t0[0][0][1]);
+ fp_hlv(t0[0][1][0], t0[0][1][0]);
+ fp_hlv(t0[0][1][1], t0[0][1][1]);
+ fp_hlv(t0[1][0][0], t0[1][0][0]);
+ fp_hlv(t0[1][0][1], t0[1][0][1]);
+ fp_hlv(t0[1][1][0], t0[1][1][0]);
+ fp_hlv(t0[1][1][1], t0[1][1][1]);
+ c0 = fp8_is_sqr(t0);
+ /* t0 = (a_0 - sqrt(t0)) / 2 */
+ fp8_sub(t1, a[0], t1);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int k = 0; k < 2; k++) {
+ fp_hlv(t1[i][j][k], t1[i][j][k]);
+ dv_copy_cond(t0[i][j][k], t1[i][j][k], RLC_FP_DIGS,
+ !c0);
+ }
+ }
+ }
+ /* Should always be a quadratic residue. */
+ fp8_srt(t2, t0);
+ /* c_0 = sqrt(t0) */
+ fp8_copy(c[0], t2);
+
+ /* c_1 = a_1 / (2 * sqrt(t0)) */
+ fp8_dbl(t2, t2);
+ fp8_inv(t2, t2);
+ fp8_mul(c[1], a[1], t2);
+ r = 1;
+ }
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp8_free(t0);
+ fp8_free(t1);
+ fp8_free(t2);
+ }
+ return r;
+}
diff --git a/src/fpx/relic_fpx_util.c b/src/fpx/relic_fpx_util.c
index cc171850f..bbc946c41 100644
--- a/src/fpx/relic_fpx_util.c
+++ b/src/fpx/relic_fpx_util.c
@@ -504,6 +504,65 @@ void fp12_set_dig(fp12_t a, const dig_t b) {
fp6_zero(a[1]);
}
+void fp16_copy(fp16_t c, const fp16_t a) {
+ fp8_copy(c[0], a[0]);
+ fp8_copy(c[1], a[1]);
+}
+
+void fp16_zero(fp16_t a) {
+ fp8_zero(a[0]);
+ fp8_zero(a[1]);
+}
+
+int fp16_is_zero(const fp16_t a) {
+ return fp8_is_zero(a[0]) && fp8_is_zero(a[1]);
+}
+
+void fp16_rand(fp16_t a) {
+ fp8_rand(a[0]);
+ fp8_rand(a[1]);
+}
+
+void fp16_print(const fp16_t a) {
+ fp8_print(a[0]);
+ fp8_print(a[1]);
+}
+
+int fp16_size_bin(fp16_t a, int pack) {
+ if (pack) {
+ if (fp16_test_cyc(a)) {
+ return 8 * RLC_FP_BYTES;
+ } else {
+ return 16 * RLC_FP_BYTES;
+ }
+ } else {
+ return 16 * RLC_FP_BYTES;
+ }
+}
+
+void fp16_read_bin(fp16_t a, const uint8_t *bin, size_t len) {
+ if (len != 16 * RLC_FP_BYTES) {
+ RLC_THROW(ERR_NO_BUFFER);
+ return;
+ }
+ fp8_read_bin(a[0], bin, 8 * RLC_FP_BYTES);
+ fp8_read_bin(a[1], bin + 8 * RLC_FP_BYTES, 8 * RLC_FP_BYTES);
+}
+
+void fp16_write_bin(uint8_t *bin, size_t len, const fp16_t a, int pack) {
+ if (len != 16 * RLC_FP_BYTES) {
+ RLC_THROW(ERR_NO_BUFFER);
+ return;
+ }
+ fp8_write_bin(bin, 8 * RLC_FP_BYTES, a[0]);
+ fp8_write_bin(bin + 8 * RLC_FP_BYTES, 8 * RLC_FP_BYTES, a[1]);
+}
+
+void fp16_set_dig(fp16_t a, const dig_t b) {
+ fp8_set_dig(a[0], b);
+ fp8_zero(a[1]);
+}
+
void fp18_copy(fp18_t c, const fp18_t a) {
fp9_copy(c[0], a[0]);
fp9_copy(c[1], a[1]);
diff --git a/src/low/easy/relic_bn_mul_low.c b/src/low/easy/relic_bn_mul_low.c
index 0e4c67e4d..4233d2eb5 100644
--- a/src/low/easy/relic_bn_mul_low.c
+++ b/src/low/easy/relic_bn_mul_low.c
@@ -64,24 +64,21 @@ dig_t bn_mul1_low(dig_t *c, const dig_t *a, dig_t digit, int size) {
return carry;
}
-dig_t bn_muls_low(dig_t *c, const dig_t *a, dig_t sa, dis_t digit, int size) {
- dig_t r, _a, _c, c0, c1, c2, sign, sd = digit >> (RLC_DIG - 1);
+dig_t bn_muls_low(dig_t *c, const dig_t *a, dig_t sa, dis_t digit,
+ int size) {
+ dig_t r, _c, c0, c1, sign, sd = digit >> (RLC_DIG - 1);
sa = -sa;
sign = sa ^ sd;
digit = (digit ^ sd) - sd;
- _a = (a[0] ^ sa) - sa;
- c2 = (_a < (a[0] ^ sa));
- RLC_MUL_DIG(r, _c, _a, (dig_t)digit);
+ RLC_MUL_DIG(r, _c, a[0], (dig_t)digit);
_c ^= sign;
c[0] = _c - sign;
c1 = (c[0] < _c);
c0 = r;
for (int i = 1; i < size; i++) {
- _a = (a[i] ^ sa) + c2;
- c2 = (_a < c2);
- RLC_MUL_DIG(r, _c, _a, (dig_t)digit);
+ RLC_MUL_DIG(r, _c, a[i], (dig_t)digit);
_c += c0;
c0 = r + (_c < c0);
_c ^= sign;
diff --git a/src/low/easy/relic_fpx_add_low.c b/src/low/easy/relic_fpx_add_low.c
index 378c5b279..b24055cf1 100755
--- a/src/low/easy/relic_fpx_add_low.c
+++ b/src/low/easy/relic_fpx_add_low.c
@@ -286,12 +286,14 @@ void fp3_dblm_low(fp3_t c, fp3_t a) {
}
void fp3_nord_low(dv3_t c, dv3_t a) {
- dv3_t t;
+ dv3_t t, u;
dv3_null(t);
+ dv3_null(u);
RLC_TRY {
dv3_new(t);
+ dv3_new(u);
dv_copy(t[0], a[2], 2 * RLC_FP_DIGS);
for (int i = 1; i < fp_prime_get_cnr(); i++) {
@@ -305,26 +307,30 @@ void fp3_nord_low(dv3_t c, dv3_t a) {
int cnr = fp3_field_get_cnr();
switch (fp_prime_get_mod18()) {
+ case 1:
case 7:
- /* If p = 7 mod 8, (2^k + i) is a QNR/CNR. */
- dv_copy(c[0], a[0], 2 * RLC_FP_DIGS);
- dv_copy(c[1], a[1], 2 * RLC_FP_DIGS);
- dv_copy(c[2], a[2], 2 * RLC_FP_DIGS);
- while (cnr > 1) {
- fp3_addc_low(c, c, c);
- cnr = cnr >> 1;
+ if (cnr != 0) {
+ dv_copy(u[0], a[0], 2 * RLC_FP_DIGS);
+ dv_copy(u[1], a[1], 2 * RLC_FP_DIGS);
+ dv_copy(u[2], a[2], 2 * RLC_FP_DIGS);
+ while (cnr > 1) {
+ fp3_addc_low(u, u, u);
+ if (cnr & 1) {
+ fp3_addc_low(u, u, a);
+ }
+ cnr = cnr >> 1;
+ }
+ fp3_addc_low(t, t, u);
}
- fp3_addc_low(c, c, t);
break;
- default:
- dv_copy(c[0], t[0], 2 * RLC_FP_DIGS);
- dv_copy(c[1], t[1], 2 * RLC_FP_DIGS);
- dv_copy(c[2], t[2], 2 * RLC_FP_DIGS);
- break;
- }
+ }
+ dv_copy(c[0], t[0], 2 * RLC_FP_DIGS);
+ dv_copy(c[1], t[1], 2 * RLC_FP_DIGS);
+ dv_copy(c[2], t[2], 2 * RLC_FP_DIGS);
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
dv3_free(t);
+ dv3_free(u);
}
}
diff --git a/src/low/gmp-sec/relic_bn_mul_low.c b/src/low/gmp-sec/relic_bn_mul_low.c
index 5fa5d265e..082815ede 100644
--- a/src/low/gmp-sec/relic_bn_mul_low.c
+++ b/src/low/gmp-sec/relic_bn_mul_low.c
@@ -61,11 +61,7 @@ dig_t bn_muls_low(dig_t *c, const dig_t *a, dig_t sa, dis_t digit, int size) {
sign = sa ^ sd;
digit = (digit ^ sd) - sd;
- for (size_t i = 0; i < size; i++) {
- _a[i] = a[i] ^ sa;
- }
- bn_add1_low(_a, _a, -sa, size);
- carry = bn_mul1_low(c, _a, (dig_t)digit, size);
+ carry = bn_mul1_low(c, a, (dig_t)digit, size);
for (size_t i = 0; i < size; i++) {
c[i] = c[i] ^ sign;
}
diff --git a/src/low/gmp/relic_bn_mul_low.c b/src/low/gmp/relic_bn_mul_low.c
index a6806a55f..6b88f9c12 100644
--- a/src/low/gmp/relic_bn_mul_low.c
+++ b/src/low/gmp/relic_bn_mul_low.c
@@ -49,17 +49,13 @@ dig_t bn_mul1_low(dig_t *c, const dig_t *a, dig_t digit, int size) {
}
dig_t bn_muls_low(dig_t *c, const dig_t *a, dig_t sa, dis_t digit, int size) {
- dig_t _a[size], carry, sign, sd = digit >> (RLC_DIG - 1);
+ dig_t carry, sign, sd = digit >> (RLC_DIG - 1);
sa = -sa;
sign = sa ^ sd;
digit = (digit ^ sd) - sd;
- for (size_t i = 0; i < size; i++) {
- _a[i] = a[i] ^ sa;
- }
- mpn_add_1(_a, _a, size, -sa);
- carry = mpn_mul_1(c, _a, size, digit);
+ carry = mpn_mul_1(c, a, size, digit);
for (size_t i = 0; i < size; i++) {
c[i] = c[i] ^ sign;
}
diff --git a/src/low/gmp/relic_fp_add_low.c b/src/low/gmp/relic_fp_add_low.c
index b5c6dc505..535cb8116 100644
--- a/src/low/gmp/relic_fp_add_low.c
+++ b/src/low/gmp/relic_fp_add_low.c
@@ -111,7 +111,7 @@ dig_t fp_dbln_low(dig_t *c, const dig_t *a) {
void fp_dblm_low(dig_t *c, const dig_t *a) {
dig_t carry = mpn_add_n(c, a, a, RLC_FP_DIGS);
if (carry || (dv_cmp(c, fp_prime_get(), RLC_FP_DIGS) != RLC_LT)) {
- carry = fp_subn_low(c, c, fp_prime_get());
+ carry = mpn_sub_n(c, c, fp_prime_get(), RLC_FP_DIGS);
}
}
diff --git a/src/low/x64-asm-8l/relic_fp_smb_low.c b/src/low/gmp/relic_fp_smb_low.c
similarity index 97%
rename from src/low/x64-asm-8l/relic_fp_smb_low.c
rename to src/low/gmp/relic_fp_smb_low.c
index d25200282..7c4b9b654 100644
--- a/src/low/x64-asm-8l/relic_fp_smb_low.c
+++ b/src/low/gmp/relic_fp_smb_low.c
@@ -1,6 +1,6 @@
/*
* RELIC is an Efficient LIbrary for Cryptography
- * Copyright (c) 2021 RELIC Authors
+ * Copyright (c) 2023 RELIC Authors
*
* This file is part of RELIC. RELIC is legal property of its developers,
* whose names are not listed here. Please refer to the COPYRIGHT file
@@ -61,6 +61,7 @@ int fp_smbm_low(const dig_t *a) {
res = mpz_jacobi(n, p);
+ (void)t;
mpz_clear(n);
mpz_clear(p);
return res;
diff --git a/src/low/x64-asm-10l/relic_fp_add_low.s b/src/low/x64-asm-10l/relic_fp_add_low.s
index 3905176d3..70ab7b72c 100644
--- a/src/low/x64-asm-10l/relic_fp_add_low.s
+++ b/src/low/x64-asm-10l/relic_fp_add_low.s
@@ -455,6 +455,21 @@ cdecl(fp_subc_low):
ret
cdecl(fp_negm_low):
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+
+ xorq %r9, %r9
+ xorq %r10, %r10
+ xorq %r11, %r11
+ xorq %r12, %r12
+ xorq %r13, %r13
+ xorq %rbx, %rbx
+ xorq %rbp, %rbp
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
movq 0(%rsi) , %r8
or 8(%rsi) , %r8
or 16(%rsi), %r8
@@ -464,37 +479,43 @@ cdecl(fp_negm_low):
or 48(%rsi), %r8
or 56(%rsi), %r8
or 64(%rsi), %r8
+ or 72(%rsi), %r8
test %r8, %r8
cmovnz p0(%rip), %r8
+ cmovnz p1(%rip), %r9
+ cmovnz p2(%rip), %r10
+ cmovnz p3(%rip), %r11
+ cmovnz p4(%rip), %rbx
+ cmovnz p5(%rip), %rbp
+ cmovnz p6(%rip), %r12
+ cmovnz p7(%rip), %r13
+ cmovnz p8(%rip), %rax
+ cmovnz p9(%rip), %rcx
subq 0(%rsi) , %r8
movq %r8 , 0(%rdi)
- cmovnz p1(%rip), %r8
- sbbq 8(%rsi) , %r8
- movq %r8 , 8(%rdi)
- cmovnz p2(%rip), %r8
- sbbq 16(%rsi), %r8
- movq %r8 , 16(%rdi)
- cmovnz p3(%rip), %r8
- sbbq 24(%rsi), %r8
- movq %r8 , 24(%rdi)
- cmovnz p4(%rip), %r8
- sbbq 32(%rsi), %r8
- movq %r8 , 32(%rdi)
- cmovnz p5(%rip), %r8
- sbbq 40(%rsi), %r8
- movq %r8 , 40(%rdi)
- cmovnz p6(%rip), %r8
- sbbq 48(%rsi), %r8
- movq %r8 , 48(%rdi)
- cmovnz p7(%rip), %r8
- sbbq 56(%rsi), %r8
- movq %r8 , 56(%rdi)
- cmovnz p8(%rip), %r8
- sbbq 64(%rsi), %r8
- movq %r8 , 64(%rdi)
- cmovnz p9(%rip), %r8
- sbbq 72(%rsi), %r8
- movq %r8 , 72(%rdi)
+ sbbq 8(%rsi) , %r9
+ movq %r9 , 8(%rdi)
+ sbbq 16(%rsi), %r10
+ movq %r10 , 16(%rdi)
+ sbbq 24(%rsi), %r11
+ movq %r11 , 24(%rdi)
+ sbbq 32(%rsi), %rbx
+ movq %rbx , 32(%rdi)
+ sbbq 40(%rsi), %rbp
+ movq %rbp , 40(%rdi)
+ sbbq 48(%rsi), %r12
+ movq %r12 , 48(%rdi)
+ sbbq 56(%rsi), %r13
+ movq %r13 , 56(%rdi)
+ sbbq 64(%rsi), %rax
+ movq %rax , 64(%rdi)
+ sbbq 72(%rsi), %rcx
+ movq %rcx , 72(%rdi)
+
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
ret
cdecl(fp_dbln_low):
@@ -670,7 +691,7 @@ cdecl(fp_hlvm_low):
adcq %rdx , %r15
movq 64(%rsi), %rdx
adcq %rdx , %rbp
- mov 72(%rsi), %rdx
+ movq 72(%rsi), %rdx
adcq %rdx ,%rbx
rcrq $1, %rbx
@@ -714,6 +735,10 @@ cdecl(fp_hlvd_low):
xorq %rdx, %rdx
+ movq $1 ,%rbp
+ movq 0(%rsi),%rcx
+ andq %rcx ,%rbp
+
movq $P0, %r8
movq $P1, %r9
movq $P2, %r10
@@ -725,10 +750,6 @@ cdecl(fp_hlvd_low):
movq $P8, %rax
movq $P9, %rbx
- movq $1 ,%rbp
- movq 0(%rsi),%rcx
- andq %rcx ,%rbp
-
cmovz %rdx, %r8
cmovz %rdx, %r9
cmovz %rdx, %r10
diff --git a/src/low/x64-asm-12l/CMakeLists.txt b/src/low/x64-asm-12l/CMakeLists.txt
new file mode 100644
index 000000000..ecca66b65
--- /dev/null
+++ b/src/low/x64-asm-12l/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(INHERIT "gmp")
+include(../cmake/gmp.cmake)
+if(GMP_FOUND)
+ include_directories(${GMP_INCLUDE_DIR})
+ set(ARITH_LIBS ${GMP_LIBRARIES})
+endif(GMP_FOUND)
diff --git a/src/low/x64-asm-12l/macro.s b/src/low/x64-asm-12l/macro.s
new file mode 100644
index 000000000..a33c14129
--- /dev/null
+++ b/src/low/x64-asm-12l/macro.s
@@ -0,0 +1,332 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+#include "relic_fp_low.h"
+
+/**
+ * @file
+ *
+ * Implementation of low-level prime field multiplication.
+ *
+ * @ingroup fp
+ */
+
+#if FP_PRIME == 766
+/* KSS16-P766 */
+#define P0 0xB955C8905EF99F8D
+#define P1 0x7D1C278139EFCE97
+#define P2 0xB72041F5E8174021
+#define P3 0xBC0E3DEC45049335
+#define P4 0xB2CBF189D4D4B3CB
+#define P5 0x941663A5AAF69407
+#define P6 0x74C81A64B9FAAE0C
+#define P7 0xB691EBF6CC4A8A9B
+#define P8 0x24FB15165CCAB927
+#define P9 0x91D2481C864D19F7
+#define P10 0xD1F39E5F37AEACB3
+#define P11 0x3C410B7E6EC19106
+#define U0 0xC18CA908C52344BB
+#elif FP_PRIME == 765
+#define P0 0x0000000000000001
+#define P1 0x00000000384F0100
+#define P2 0x7D00000000000000
+#define P3 0xFFFEE92F0199280F
+#define P4 0xF10B013FFFFFFFFF
+#define P5 0x4AC04FAC4912BADA
+#define P6 0x6AC50E5A1A6AEAE4
+#define P7 0xEE9C1E7F21BD9E92
+#define P8 0x249F514A2A836FBF
+#define P9 0x8866F5670199231B
+#define P10 0xB2847B1232833CC3
+#define P11 0x16FAB993B0C96754
+#define U0 0xFFFFFFFFFFFFFFFF
+#endif
+
+#if defined(__APPLE__)
+#define cdecl(S) _PREFIX(,S)
+#else
+#define cdecl(S) S
+#endif
+
+.text
+
+.macro ADD1 i, j
+ movq 8*\i(%rsi), %r10
+ adcq $0, %r10
+ movq %r10, 8*\i(%rdi)
+ .if \i - \j
+ ADD1 "(\i + 1)", \j
+ .endif
+.endm
+
+.macro ADDN i, j
+ movq 8*\i(%rdx), %r11
+ adcq 8*\i(%rsi), %r11
+ movq %r11, 8*\i(%rdi)
+ .if \i - \j
+ ADDN "(\i + 1)", \j
+ .endif
+.endm
+
+.macro SUB1 i, j
+ movq 8*\i(%rsi),%r10
+ sbbq $0, %r10
+ movq %r10,8*\i(%rdi)
+ .if \i - \j
+ SUB1 "(\i + 1)", \j
+ .endif
+.endm
+
+.macro SUBN i, j
+ movq 8*\i(%rsi), %r8
+ sbbq 8*\i(%rdx), %r8
+ movq %r8, 8*\i(%rdi)
+ .if \i - \j
+ SUBN "(\i + 1)", \j
+ .endif
+.endm
+
+.macro DBLN i, j
+ movq 8*\i(%rsi), %r8
+ adcq %r8, %r8
+ movq %r8, 8*\i(%rdi)
+ .if \i - \j
+ DBLN "(\i + 1)", \j
+ .endif
+.endm
+
+.macro MULN i, j, k, C, R0, R1, R2, A, B
+ .if \j > \k
+ movq 8*\i(\A), %rax
+ mulq 8*\j(\B)
+ addq %rax , \R0
+ adcq %rdx , \R1
+ adcq $0 , \R2
+ MULN "(\i + 1)", "(\j - 1)", \k, \C, \R0, \R1, \R2, \A, \B
+ .else
+ movq 8*\i(\A), %rax
+ mulq 8*\j(\B)
+ addq %rax , \R0
+ movq \R0 , 8*(\i+\j)(\C)
+ adcq %rdx , \R1
+ adcq $0 , \R2
+ .endif
+.endm
+
+.macro FP_MULN_LOW C, R0, R1, R2, A, B
+ movq 0(\A),%rax
+ mulq 0(\B)
+ movq %rax ,0(\C)
+ movq %rdx ,\R0
+
+ xorq \R1,\R1
+ xorq \R2,\R2
+ MULN 0, 1, 0, \C, \R0, \R1, \R2, \A, \B
+ xorq \R0,\R0
+ MULN 0, 2, 0, \C, \R1, \R2, \R0, \A, \B
+ xorq \R1,\R1
+ MULN 0, 3, 0, \C, \R2, \R0, \R1, \A, \B
+ xorq \R2,\R2
+ MULN 0, 4, 0, \C, \R0, \R1, \R2, \A, \B
+ xorq \R0,\R0
+ MULN 0, 5, 0, \C, \R1, \R2, \R0, \A, \B
+ xorq \R1,\R1
+ MULN 0, 6, 0, \C, \R2, \R0, \R1, \A, \B
+ xorq \R2,\R2
+ MULN 0, 7, 0, \C, \R0, \R1, \R2, \A, \B
+ xorq \R0,\R0
+ MULN 0, 8, 0, \C, \R1, \R2, \R0, \A, \B
+ xorq \R1,\R1
+ MULN 0, 9, 0, \C, \R2, \R0, \R1, \A, \B
+ xorq \R2,\R2
+ MULN 0,10, 0, \C, \R0, \R1, \R2, \A, \B
+ xorq \R0,\R0
+ MULN 0,11, 0, \C, \R1, \R2, \R0, \A, \B
+ xorq \R1,\R1
+ MULN 1,11, 1, \C, \R2, \R0, \R1, \A, \B
+ xorq \R2,\R2
+ MULN 2,11, 2, \C, \R0, \R1, \R2, \A, \B
+ xorq \R0,\R0
+ MULN 3,11, 3, \C, \R1, \R2, \R0, \A, \B
+ xorq \R1,\R1
+ MULN 4,11, 4, \C, \R2, \R0, \R1, \A, \B
+ xorq \R2,\R2
+ MULN 5,11, 5, \C, \R0, \R1, \R2, \A, \B
+ xorq \R0,\R0
+ MULN 6,11, 6, \C, \R1, \R2, \R0, \A, \B
+ xorq \R1,\R1
+ MULN 7,11, 7, \C, \R2, \R0, \R1, \A, \B
+ xorq \R2,\R2
+ MULN 8,11, 8, \C, \R0, \R1, \R2, \A, \B
+ xorq \R0,\R0
+ MULN 9,11, 9, \C, \R1, \R2, \R0, \A, \B
+ xorq \R1,\R1
+ MULN 10,11,10, \C, \R2, \R0, \R1, \A, \B
+
+ movq 88(\A),%rax
+ mulq 88(\B)
+ addq %rax ,\R0
+ movq \R0 ,176(\C)
+ adcq %rdx ,\R1
+ movq \R1 ,184(\C)
+.endm
+
+.macro _RDCN0 i, j, k, R0, R1, R2 A, P
+ movq 8*\i(\A), %rax
+ mulq 8*\j(\P)
+ addq %rax, \R0
+ adcq %rdx, \R1
+ adcq $0, \R2
+ .if \j > 1
+ _RDCN0 "(\i + 1)", "(\j - 1)", \k, \R0, \R1, \R2, \A, \P
+ .else
+ addq 8*\k(\A), \R0
+ adcq $0, \R1
+ adcq $0, \R2
+ movq \R0, %rax
+ mulq %rcx
+ movq %rax, 8*\k(\A)
+ mulq 0(\P)
+ addq %rax , \R0
+ adcq %rdx , \R1
+ adcq $0 , \R2
+ xorq \R0, \R0
+ .endif
+.endm
+
+.macro RDCN0 i, j, R0, R1, R2, A, P
+ _RDCN0 \i, \j, \j, \R0, \R1, \R2, \A, \P
+.endm
+
+.macro _RDCN1 i, j, k, l, R0, R1, R2 A, P
+ movq 8*\i(\A), %rax
+ mulq 8*\j(\P)
+ addq %rax, \R0
+ adcq %rdx, \R1
+ adcq $0, \R2
+ .if \j > \l
+ _RDCN1 "(\i + 1)", "(\j - 1)", \k, \l, \R0, \R1, \R2, \A, \P
+ .else
+ addq 8*\k(\A), \R0
+ adcq $0, \R1
+ adcq $0, \R2
+ movq \R0, 8*\k(\A)
+ xorq \R0, \R0
+ .endif
+.endm
+
+.macro RDCN1 i, j, R0, R1, R2, A, P
+ _RDCN1 \i, \j, "(\i + \j)", \i, \R0, \R1, \R2, \A, \P
+.endm
+
+// r8, r9, r10, r11, r12, r13, r14, r15, rbp, rbx, rsp, //rsi, rdi, //rax, rcx, rdx
+.macro FP_RDCN_LOW C, R0, R1, R2, A, P
+ xorq \R1, \R1
+ movq $U0, %rcx
+
+ movq 0(\A), \R0
+ movq \R0 , %rax
+ mulq %rcx
+ movq %rax , 0(\A)
+ mulq 0(\P)
+ addq %rax , \R0
+ adcq %rdx , \R1
+ xorq \R2 , \R2
+ xorq \R0 , \R0
+
+ RDCN0 0, 1, \R1, \R2, \R0, \A, \P
+ RDCN0 0, 2, \R2, \R0, \R1, \A, \P
+ RDCN0 0, 3, \R0, \R1, \R2, \A, \P
+ RDCN0 0, 4, \R1, \R2, \R0, \A, \P
+ RDCN0 0, 5, \R2, \R0, \R1, \A, \P
+ RDCN0 0, 6, \R0, \R1, \R2, \A, \P
+ RDCN0 0, 7, \R1, \R2, \R0, \A, \P
+ RDCN0 0, 8, \R2, \R0, \R1, \A, \P
+ RDCN0 0, 9, \R0, \R1, \R2, \A, \P
+ RDCN0 0,10, \R1, \R2, \R0, \A, \P
+ RDCN0 0,11, \R2, \R0, \R1, \A, \P
+ RDCN1 1,11, \R0, \R1, \R2, \A, \P
+ RDCN1 2,11, \R1, \R2, \R0, \A, \P
+ RDCN1 3,11, \R2, \R0, \R1, \A, \P
+ RDCN1 4,11, \R0, \R1, \R2, \A, \P
+ RDCN1 5,11, \R1, \R2, \R0, \A, \P
+ RDCN1 6,11, \R2, \R0, \R1, \A, \P
+ RDCN1 7,11, \R0, \R1, \R2, \A, \P
+ RDCN1 8,11, \R1, \R2, \R0, \A, \P
+ RDCN1 9,11, \R2, \R0, \R1, \A, \P
+ RDCN1 10,11,\R0, \R1, \R2, \A, \P
+ RDCN1 11,11,\R1, \R2, \R0, \A, \P
+ addq 184(\A), \R2
+ movq \R2, 184(\A)
+
+ movq 96(\A), %r11
+ movq 104(\A), %r12
+ movq 112(\A), %r13
+ movq 120(\A), %r14
+ movq 128(\A), %r15
+ movq 136(\A), %rcx
+ movq 144(\A), %rbp
+ movq 152(\A), %rdx
+ movq 160(\A), %r8
+ movq 168(\A), %r9
+ movq 176(\A), %r10
+ movq 184(\A), %rax
+
+ subq p0(%rip), %r11
+ sbbq p1(%rip), %r12
+ sbbq p2(%rip), %r13
+ sbbq p3(%rip), %r14
+ sbbq p4(%rip), %r15
+ sbbq p5(%rip), %rcx
+ sbbq p6(%rip), %rbp
+ sbbq p7(%rip), %rdx
+ sbbq p8(%rip), %r8
+ sbbq p9(%rip), %r9
+ sbbq p10(%rip), %r10
+ sbbq p11(%rip), %rax
+
+ cmovc 96(\A), %r11
+ cmovc 104(\A), %r12
+ cmovc 112(\A), %r13
+ cmovc 120(\A), %r14
+ cmovc 128(\A), %r15
+ cmovc 136(\A), %rcx
+ cmovc 144(\A), %rbp
+ cmovc 152(\A), %rdx
+ cmovc 160(\A), %r8
+ cmovc 168(\A), %r9
+ cmovc 176(\A), %r10
+ cmovc 184(\A), %rax
+ movq %r11,0(\C)
+ movq %r12,8(\C)
+ movq %r13,16(\C)
+ movq %r14,24(\C)
+ movq %r15,32(\C)
+ movq %rcx,40(\C)
+ movq %rbp,48(\C)
+ movq %rdx,56(\C)
+ movq %r8,64(\C)
+ movq %r9,72(\C)
+ movq %r10,80(\C)
+ movq %rax,88(\C)
+.endm
diff --git a/src/low/x64-asm-12l/relic_fp_add_low.s b/src/low/x64-asm-12l/relic_fp_add_low.s
new file mode 100644
index 000000000..d5e418c5e
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fp_add_low.s
@@ -0,0 +1,977 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+#include "relic_fp_low.h"
+
+/**
+ * @file
+ *
+ * Implementation of the low-level prime field addition and subtraction
+ * functions.
+ *
+ * @ingroup fp
+ */
+
+#include "macro.s"
+
+.data
+
+p0: .quad P0
+p1: .quad P1
+p2: .quad P2
+p3: .quad P3
+p4: .quad P4
+p5: .quad P5
+p6: .quad P6
+p7: .quad P7
+p8: .quad P8
+p9: .quad P9
+p10:.quad P10
+p11:.quad P11
+
+.global p0
+.global p1
+.global p2
+.global p3
+.global p4
+.global p5
+.global p6
+.global p7
+.global p8
+.global p9
+.global p10
+.global p11
+
+.hidden p0
+.hidden p1
+.hidden p2
+.hidden p3
+.hidden p4
+.hidden p5
+.hidden p6
+.hidden p7
+.hidden p8
+.hidden p9
+.global p10
+.global p11
+
+.text
+
+.global cdecl(fp_add1_low)
+.global cdecl(fp_addn_low)
+.global cdecl(fp_addm_low)
+.global cdecl(fp_addd_low)
+.global cdecl(fp_addc_low)
+.global cdecl(fp_sub1_low)
+.global cdecl(fp_subn_low)
+.global cdecl(fp_subm_low)
+.global cdecl(fp_subd_low)
+.global cdecl(fp_subc_low)
+.global cdecl(fp_negm_low)
+.global cdecl(fp_dbln_low)
+.global cdecl(fp_dblm_low)
+.global cdecl(fp_hlvm_low)
+.global cdecl(fp_hlvd_low)
+
+cdecl(fp_add1_low):
+ movq 0(%rsi), %r10
+ addq %rdx , %r10
+ movq %r10 , 0(%rdi)
+
+ ADD1 1, (RLC_FP_DIGS - 1)
+
+ ret
+
+cdecl(fp_addn_low):
+ movq 0(%rdx), %r10
+ addq 0(%rsi), %r10
+ movq %r10 , 0(%rdi)
+
+ ADDN 1, (RLC_FP_DIGS - 1)
+
+ xorq %rax, %rax
+
+ ret
+
+cdecl(fp_addm_low):
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rdi
+
+ movq 0(%rdx), %r8
+ addq 0(%rsi), %r8
+ movq 8(%rdx), %r9
+ adcq 8(%rsi), %r9
+ movq 16(%rdx), %r10
+ adcq 16(%rsi), %r10
+ movq 24(%rdx), %r11
+ adcq 24(%rsi), %r11
+ movq 32(%rdx), %r12
+ adcq 32(%rsi), %r12
+ movq 40(%rdx), %r13
+ adcq 40(%rsi), %r13
+ movq 48(%rdx), %r14
+ adcq 48(%rsi), %r14
+ movq 56(%rdx), %r15
+ adcq 56(%rsi), %r15
+ movq %r15 , 0(%rdi)
+ movq %r15 , 8(%rdi)
+ movq 64(%rdx), %rax
+ adcq 64(%rsi), %rax
+ movq %rax , 16(%rdi)
+ movq %rax , 24(%rdi)
+ movq 72(%rdx), %rcx
+ adcq 72(%rsi), %rcx
+ movq %rcx , 32(%rdi)
+ movq %rcx , 40(%rdi)
+ movq 80(%rdx), %rax
+ adcq 80(%rsi), %rax
+ movq %rax , 48(%rdi)
+ movq %rax , 56(%rdi)
+ movq 88(%rdx), %rcx
+ adcq 88(%rsi), %rcx
+ movq %rcx , 64(%rdi)
+ movq %rcx , 72(%rdi)
+
+ movq %rdi, %r15
+
+ movq %r8 , %rax
+ movq %r9 , %rcx
+ movq %r10, %rdx
+ movq %r11, %rsi
+ movq %r12, %rbx
+ movq %r13, %rbp
+ movq %r14, %rdi
+
+ subq p0(%rip), %rax
+ sbbq p1(%rip), %rcx
+ sbbq p2(%rip), %rdx
+ sbbq p3(%rip), %rsi
+ sbbq p4(%rip), %rbx
+ sbbq p5(%rip), %rbp
+ sbbq p6(%rip), %rdi
+
+ push %rdi
+
+ movq %r15, %rdi
+ movq 8(%rdi), %r15
+ sbbq p7(%rip), %r15
+ movq %r15, 8(%rdi)
+ movq 24(%rdi), %r15
+ sbbq p8(%rip), %r15
+ movq %r15, 24(%rdi)
+ movq 40(%rdi), %r15
+ sbbq p9(%rip), %r15
+ movq %r15, 40(%rdi)
+ movq 56(%rdi) , %r15
+ sbbq p10(%rip), %r15
+ movq %r15, 56(%rdi)
+ movq 72(%rdi) , %r15
+ sbbq p11(%rip), %r15
+ movq %r15, 72(%rdi)
+
+ pop %rdi
+ cmovnc %rax, %r8
+ cmovnc %rcx, %r9
+ cmovnc %rdx, %r10
+ cmovnc %rsi, %r11
+ cmovnc %rbx, %r12
+ cmovnc %rbp, %r13
+ cmovnc %rdi, %r14
+ pop %rdi
+ movq 0(%rdi) , %r15
+ movq 16(%rdi), %rax
+ movq 32(%rdi), %rcx
+ movq 48(%rdi), %rbx
+ movq 64(%rdi), %rbp
+ cmovnc 8(%rdi) , %r15
+ cmovnc 24(%rdi), %rax
+ cmovnc 40(%rdi), %rcx
+ cmovnc 56(%rdi), %rbx
+ cmovnc 72(%rdi), %rbp
+
+ movq %r8 , 0(%rdi)
+ movq %r9 , 8(%rdi)
+ movq %r10, 16(%rdi)
+ movq %r11, 24(%rdi)
+ movq %r12, 32(%rdi)
+ movq %r13, 40(%rdi)
+ movq %r14, 48(%rdi)
+ movq %r15, 56(%rdi)
+ movq %rax, 64(%rdi)
+ movq %rcx, 72(%rdi)
+ movq %rbx, 80(%rdi)
+ movq %rbp, 88(%rdi)
+ xorq %rax, %rax
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ ret
+
+cdecl(fp_addd_low):
+ movq 0(%rdx), %r11
+ addq 0(%rsi), %r11
+ movq %r11 , 0(%rdi)
+
+ ADDN 1, (2 * RLC_FP_DIGS - 1)
+
+ xorq %rax, %rax
+
+ ret
+
+cdecl(fp_addc_low):
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rdi
+
+ movq 0(%rsi), %r8
+ addq 0(%rdx), %r8
+ movq %r8 , 0(%rdi)
+
+ ADDN 1, (RLC_FP_DIGS - 1)
+
+ movq 96(%rsi), %r8
+ adcq 96(%rdx), %r8
+ movq 104(%rsi), %r9
+ adcq 104(%rdx), %r9
+ movq 112(%rsi), %r10
+ adcq 112(%rdx), %r10
+ movq 120(%rsi), %r11
+ adcq 120(%rdx), %r11
+ movq 128(%rsi), %r12
+ adcq 128(%rdx), %r12
+ movq 136(%rsi), %r13
+ adcq 136(%rdx), %r13
+ movq 144(%rsi), %r14
+ adcq 144(%rdx), %r14
+ movq 152(%rsi), %r15
+ adcq 152(%rdx), %r15
+ movq %r15 , 96(%rdi)
+ movq %r15 ,104(%rdi)
+ movq 160(%rdx), %rax
+ adcq 160(%rsi), %rax
+ movq %rax , 112(%rdi)
+ movq %rax , 120(%rdi)
+ movq 168(%rdx), %rcx
+ adcq 168(%rsi), %rcx
+ movq %rcx , 128(%rdi)
+ movq %rcx , 136(%rdi)
+ movq 176(%rdx), %rax
+ adcq 176(%rsi), %rax
+ movq %rax , 144(%rdi)
+ movq %rax , 152(%rdi)
+ movq 184(%rdx), %rcx
+ adcq 184(%rsi), %rcx
+ movq %rcx , 160(%rdi)
+ movq %rcx , 168(%rdi)
+
+ movq %rdi, %r15
+
+ movq %r8 , %rax
+ movq %r9 , %rcx
+ movq %r10, %rdx
+ movq %r11, %rsi
+ movq %r12, %rbx
+ movq %r13, %rbp
+ movq %r14, %rdi
+
+ subq p0(%rip), %rax
+ sbbq p1(%rip), %rcx
+ sbbq p2(%rip), %rdx
+ sbbq p3(%rip), %rsi
+ sbbq p4(%rip), %rbx
+ sbbq p5(%rip), %rbp
+ sbbq p6(%rip), %rdi
+
+ push %rdi
+
+ movq %r15, %rdi
+ movq 104(%rdi), %r15
+ sbbq p7(%rip), %r15
+ movq %r15, 104(%rdi)
+ movq 120(%rdi), %r15
+ sbbq p8(%rip), %r15
+ movq %r15, 120(%rdi)
+ movq 136(%rdi), %r15
+ sbbq p9(%rip), %r15
+ movq %r15, 136(%rdi)
+ movq 152(%rdi), %r15
+ sbbq p10(%rip), %r15
+ movq %r15, 152(%rdi)
+ movq 168(%rdi), %r15
+ sbbq p11(%rip), %r15
+ movq %r15, 168(%rdi)
+
+ pop %rdi
+
+ cmovnc %rax, %r8
+ cmovnc %rcx, %r9
+ cmovnc %rdx, %r10
+ cmovnc %rsi, %r11
+ cmovnc %rbx, %r12
+ cmovnc %rbp, %r13
+ cmovnc %rdi, %r14
+
+ pop %rdi
+ movq 96(%rdi), %r15
+ movq 112(%rdi), %rax
+ movq 128(%rdi), %rcx
+ movq 144(%rdi), %rbx
+ movq 160(%rdi), %rbp
+ cmovnc 104(%rdi), %r15
+ cmovnc 120(%rdi), %rax
+ cmovnc 136(%rdi), %rcx
+ cmovnc 152(%rdi), %rbx
+ cmovnc 168(%rdi), %rbp
+
+ movq %r8 , 96(%rdi)
+ movq %r9 , 104(%rdi)
+ movq %r10, 112(%rdi)
+ movq %r11, 120(%rdi)
+ movq %r12, 128(%rdi)
+ movq %r13, 136(%rdi)
+ movq %r14, 144(%rdi)
+ movq %r15, 152(%rdi)
+ movq %rax, 160(%rdi)
+ movq %rcx, 168(%rdi)
+ movq %rbx, 176(%rdi)
+ movq %rbp, 184(%rdi)
+ xorq %rax, %rax
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ ret
+
+cdecl(fp_sub1_low):
+ movq 0(%rsi), %r10
+ subq %rdx , %r10
+ movq %r10 , 0(%rdi)
+
+ SUB1 1, (RLC_FP_DIGS - 1)
+
+ ret
+
+cdecl(fp_subn_low):
+ xorq %rax , %rax
+ movq 0(%rsi), %r11
+ subq 0(%rdx), %r11
+ movq %r11 , 0(%rdi)
+
+ SUBN 1, (RLC_FP_DIGS - 1)
+
+ adcq $0, %rax
+
+ ret
+
+cdecl(fp_subm_low):
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
+ movq 0(%rsi), %r8
+ subq 0(%rdx), %r8
+ movq %r8 , 0(%rdi)
+
+ SUBN 1, (RLC_FP_DIGS - 1)
+
+ movq $0, %r8
+ movq $0, %r9
+ movq $0, %r10
+ movq $0, %r11
+ movq $0, %rdx
+ movq $0, %rsi
+ movq $0, %r12
+ movq $0, %r13
+ movq $0, %r14
+ movq $0, %r15
+
+ cmovc p0(%rip), %rax
+ cmovc p1(%rip), %rcx
+ cmovc p2(%rip), %r8
+ cmovc p3(%rip), %r9
+ cmovc p4(%rip), %r10
+ cmovc p5(%rip), %r11
+ cmovc p6(%rip), %rdx
+ cmovc p7(%rip), %rsi
+ cmovc p8(%rip), %r12
+ cmovc p9(%rip), %r13
+ cmovc p10(%rip), %r14
+ cmovc p11(%rip), %r15
+
+ addq %rax, 0(%rdi)
+ adcq %rcx, 8(%rdi)
+ adcq %r8, 16(%rdi)
+ adcq %r9, 24(%rdi)
+ adcq %r10, 32(%rdi)
+ adcq %r11, 40(%rdi)
+ adcq %rdx, 48(%rdi)
+ adcq %rsi, 56(%rdi)
+ adcq %r12, 64(%rdi)
+ adcq %r13, 72(%rdi)
+ adcq %r14, 80(%rdi)
+ adcq %r15, 88(%rdi)
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ ret
+
+cdecl(fp_subd_low):
+ movq 0(%rsi), %r8
+ subq 0(%rdx), %r8
+ movq %r8, 0(%rdi)
+
+ SUBN 1, (2 * RLC_FP_DIGS - 1)
+
+ ret
+
+cdecl(fp_subc_low):
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ xorq %rax,%rax
+ xorq %rcx,%rcx
+
+ movq 0(%rsi), %r8
+ subq 0(%rdx), %r8
+ movq %r8, 0(%rdi)
+
+ SUBN 1, (2 * RLC_FP_DIGS - 1)
+
+ movq $0, %r8
+ movq $0, %r9
+ movq $0, %r10
+ movq $0, %r11
+ movq $0, %rsi
+ movq $0, %rdx
+ movq $0, %r12
+ movq $0, %r13
+ movq $0, %r14
+ movq $0, %r15
+
+ cmovc p0(%rip), %rax
+ cmovc p1(%rip), %rcx
+ cmovc p2(%rip), %r8
+ cmovc p3(%rip), %r9
+ cmovc p4(%rip), %r10
+ cmovc p5(%rip), %r11
+ cmovc p6(%rip), %rsi
+ cmovc p7(%rip), %rdx
+ cmovc p8(%rip), %r12
+ cmovc p9(%rip), %r13
+ cmovc p10(%rip), %r14
+ cmovc p11(%rip), %r15
+
+ addq %rax, 96(%rdi)
+ adcq %rcx, 104(%rdi)
+ adcq %r8, 112(%rdi)
+ adcq %r9, 120(%rdi)
+ adcq %r10, 128(%rdi)
+ adcq %r11, 136(%rdi)
+ adcq %rsi, 144(%rdi)
+ adcq %rdx, 152(%rdi)
+ adcq %r12, 160(%rdi)
+ adcq %r13, 168(%rdi)
+ adcq %r14, 176(%rdi)
+ adcq %r15, 184(%rdi)
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ ret
+
+cdecl(fp_negm_low):
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ xorq %r9, %r9
+ xorq %r10, %r10
+ xorq %r11, %r11
+ xorq %r12, %r12
+ xorq %r13, %r13
+ xorq %r14, %r14
+ xorq %r15, %r15
+ xorq %rbx, %rbx
+ xorq %rbp, %rbp
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
+ movq 0(%rsi) , %r8
+ or 8(%rsi) , %r8
+ or 16(%rsi), %r8
+ or 24(%rsi), %r8
+ or 32(%rsi), %r8
+ or 40(%rsi), %r8
+ or 48(%rsi), %r8
+ or 56(%rsi), %r8
+ or 64(%rsi), %r8
+ or 72(%rsi), %r8
+ or 80(%rsi), %r8
+ or 88(%rsi), %r8
+ test %r8, %r8
+ cmovnz p0(%rip), %r8
+ cmovnz p1(%rip), %r9
+ cmovnz p2(%rip), %r10
+ cmovnz p3(%rip), %r11
+ cmovnz p4(%rip), %rbx
+ cmovnz p5(%rip), %rbp
+ cmovnz p6(%rip), %r12
+ cmovnz p7(%rip), %r13
+ cmovnz p8(%rip), %r14
+ cmovnz p9(%rip), %r15
+ cmovnz p10(%rip),%rax
+ cmovnz p11(%rip),%rcx
+ subq 0(%rsi) , %r8
+ movq %r8 , 0(%rdi)
+ sbbq 8(%rsi) , %r9
+ movq %r9 , 8(%rdi)
+ sbbq 16(%rsi), %r10
+ movq %r10 , 16(%rdi)
+ sbbq 24(%rsi), %r11
+ movq %r11 , 24(%rdi)
+ sbbq 32(%rsi), %rbx
+ movq %rbx , 32(%rdi)
+ sbbq 40(%rsi), %rbp
+ movq %rbp , 40(%rdi)
+ sbbq 48(%rsi), %r12
+ movq %r12 , 48(%rdi)
+ sbbq 56(%rsi), %r13
+ movq %r13 , 56(%rdi)
+ sbbq 64(%rsi), %r14
+ movq %r14 , 64(%rdi)
+ sbbq 72(%rsi), %r15
+ movq %r15 , 72(%rdi)
+ sbbq 80(%rsi), %rax
+ movq %rax , 80(%rdi)
+ sbbq 88(%rsi), %rcx
+ movq %rcx , 88(%rdi)
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ ret
+
+cdecl(fp_dbln_low):
+ movq 0(%rsi), %r8
+ addq %r8 , %r8
+ movq %r8 , 0(%rdi)
+
+ DBLN 1, (RLC_FP_DIGS - 1)
+
+ xorq %rax,%rax
+ ret
+
+cdecl(fp_dblm_low):
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rdi
+
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+ xorq %rdx, %rdx
+
+ movq 0(%rsi) , %r8
+ addq %r8 , %r8
+ movq 8(%rsi) , %r9
+ adcq %r9 , %r9
+ movq 16(%rsi), %r10
+ adcq %r10 , %r10
+ movq 24(%rsi), %r11
+ adcq %r11 , %r11
+ movq 32(%rsi), %r12
+ adcq %r12 , %r12
+ movq 40(%rsi), %r13
+ adcq %r13 , %r13
+ movq 48(%rsi), %r14
+ adcq %r14 , %r14
+ movq 56(%rsi), %r15
+ adcq %r15 , %r15
+ movq %r15 , 0(%rdi)
+ movq %r15 , 8(%rdi)
+ movq 64(%rsi), %rax
+ adcq %rax , %rax
+ movq %rax , 16(%rdi)
+ movq %rax , 24(%rdi)
+ movq 72(%rsi), %rcx
+ adcq %rcx , %rcx
+ movq %rcx , 32(%rdi)
+ movq %rcx , 40(%rdi)
+ movq 80(%rsi), %rax
+ adcq %rax , %rax
+ movq %rax , 48(%rdi)
+ movq %rax , 56(%rdi)
+ movq 88(%rsi), %rcx
+ adcq %rcx , %rcx
+ movq %rcx , 64(%rdi)
+ movq %rcx , 72(%rdi)
+
+ movq %rdi, %r15
+
+ movq %r8 , %rax
+ movq %r9 , %rcx
+ movq %r10, %rdx
+ movq %r11, %rsi
+ movq %r12, %rbx
+ movq %r13, %rbp
+ movq %r14, %rdi
+
+ subq p0(%rip), %rax
+ sbbq p1(%rip), %rcx
+ sbbq p2(%rip), %rdx
+ sbbq p3(%rip), %rsi
+ sbbq p4(%rip), %rbx
+ sbbq p5(%rip), %rbp
+ sbbq p6(%rip), %rdi
+
+ push %rdi
+ movq %r15, %rdi
+
+ movq 8(%rdi), %r15
+ sbbq p7(%rip), %r15
+ movq %r15, 8(%rdi)
+ movq 24(%rdi), %r15
+ sbbq p8(%rip), %r15
+ movq %r15, 24(%rdi)
+ movq 40(%rdi), %r15
+ sbbq p9(%rip), %r15
+ movq %r15, 40(%rdi)
+ movq 56(%rdi), %r15
+ sbbq p10(%rip), %r15
+ movq %r15, 56(%rdi)
+ movq 72(%rdi), %r15
+ sbbq p11(%rip), %r15
+ movq %r15, 72(%rdi)
+
+ pop %rdi
+
+ cmovnc %rax, %r8
+ cmovnc %rcx, %r9
+ cmovnc %rdx, %r10
+ cmovnc %rsi, %r11
+ cmovnc %rbx, %r12
+ cmovnc %rbp, %r13
+ cmovnc %rdi, %r14
+
+ pop %rdi
+
+ movq 0(%rdi), %r15
+ movq 16(%rdi), %rax
+ movq 32(%rdi), %rcx
+ movq 48(%rdi), %rbx
+ movq 64(%rdi), %rbp
+ cmovnc 8(%rdi), %r15
+ cmovnc 24(%rdi), %rax
+ cmovnc 40(%rdi), %rcx
+ cmovnc 56(%rdi), %rbx
+ cmovnc 72(%rdi), %rbp
+
+ movq %r8 , 0(%rdi)
+ movq %r9 , 8(%rdi)
+ movq %r10, 16(%rdi)
+ movq %r11, 24(%rdi)
+ movq %r12, 32(%rdi)
+ movq %r13, 40(%rdi)
+ movq %r14, 48(%rdi)
+ movq %r15, 56(%rdi)
+ movq %rax, 64(%rdi)
+ movq %rcx, 72(%rdi)
+ movq %rbx, 80(%rdi)
+ movq %rbp, 88(%rdi)
+ xorq %rax, %rax
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ ret
+
+cdecl(fp_hlvm_low):
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rbp
+ push %rbx
+
+ xorq %rdx, %rdx
+
+ movq $1 ,%rax
+ andq 0(%rsi),%rax
+
+ movq $P0, %r8
+ movq $P1, %r9
+ movq $P2, %r10
+ movq $P3, %r11
+ movq $P4, %r12
+ movq $P5, %r13
+ movq $P6, %r14
+ movq $P7, %r15
+ movq $P8, %rbp
+ movq $P9, %rbx
+ movq $P10, %rcx
+ movq $P11, %rax
+
+ cmovz %rdx, %r8
+ cmovz %rdx, %r9
+ cmovz %rdx, %r10
+ cmovz %rdx, %r11
+ cmovz %rdx, %r12
+ cmovz %rdx, %r13
+ cmovz %rdx, %r14
+ cmovz %rdx, %r15
+ cmovz %rdx, %rbp
+ cmovz %rdx, %rbx
+ cmovz %rdx, %rcx
+ cmovz %rdx, %rax
+
+ addq 0(%rsi) , %r8
+ movq 8(%rsi) , %rdx
+ adcq %rdx , %r9
+ movq 16(%rsi), %rdx
+ adcq %rdx , %r10
+ movq 24(%rsi), %rdx
+ adcq %rdx , %r11
+ movq 32(%rsi), %rdx
+ adcq %rdx , %r12
+ movq 40(%rsi), %rdx
+ adcq %rdx , %r13
+ movq 48(%rsi), %rdx
+ adcq %rdx , %r14
+ movq 56(%rsi), %rdx
+ adcq %rdx , %r15
+ movq 64(%rsi), %rdx
+ adcq %rdx , %rbp
+ movq 72(%rsi), %rdx
+ adcq %rdx , %rbx
+ movq 80(%rsi), %rdx
+ adcq %rdx , %rcx
+ movq 88(%rsi), %rdx
+ adcq %rdx , %rax
+
+ rcrq $1, %rax
+ rcrq $1, %rcx
+ rcrq $1, %rbx
+ rcrq $1, %rbp
+ rcrq $1, %r15
+ rcrq $1, %r14
+ rcrq $1, %r13
+ rcrq $1, %r12
+ rcrq $1, %r11
+ rcrq $1, %r10
+ rcrq $1, %r9
+ rcrq $1, %r8
+
+ movq %r8 , 0(%rdi)
+ movq %r9 , 8(%rdi)
+ movq %r10, 16(%rdi)
+ movq %r11, 24(%rdi)
+ movq %r12, 32(%rdi)
+ movq %r13, 40(%rdi)
+ movq %r14, 48(%rdi)
+ movq %r15, 56(%rdi)
+ movq %rbp, 64(%rdi)
+ movq %rbx, 72(%rdi)
+ movq %rcx, 80(%rdi)
+ movq %rax, 88(%rdi)
+ xorq %rax, %rax
+
+ pop %rbx
+ pop %rbp
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ ret
+
+cdecl(fp_hlvd_low):
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ xorq %rbp, %rbp
+ movq $1 ,%rdx
+ andq 0(%rsi),%rdx
+
+ movq $P0, %r8
+ movq $P1, %r9
+ movq $P2, %r10
+ movq $P3, %r11
+ movq $P4, %r12
+ movq $P5, %r13
+ movq $P6, %r14
+ movq $P7, %r15
+ movq $P8, %rax
+ movq $P9, %rbx
+ movq $P10, %rcx
+ movq $P11, %rdx
+
+ cmovz %rbp, %r8
+ cmovz %rbp, %r9
+ cmovz %rbp, %r10
+ cmovz %rbp, %r11
+ cmovz %rbp, %r12
+ cmovz %rbp, %r13
+ cmovz %rbp, %r14
+ cmovz %rbp, %r15
+ cmovz %rbp, %rax
+ cmovz %rbp, %rbx
+ cmovz %rbp, %rcx
+ cmovz %rbp, %rdx
+
+ addq 0(%rsi) , %r8
+ adcq 8(%rsi) , %r9
+ adcq 16(%rsi) , %r10
+ adcq 24(%rsi) , %r11
+ adcq 32(%rsi) , %r12
+ adcq 40(%rsi) , %r13
+ adcq 48(%rsi) , %r14
+ adcq 56(%rsi) , %r15
+ adcq 64(%rsi) , %rax
+ adcq 72(%rsi) , %rbx
+ adcq 80(%rsi) , %rcx
+ adcq 88(%rsi) , %rdx
+ movq 96(%rsi) , %rbp
+ adcq $0 , %rbp
+
+ push %rbp
+
+ movq 104(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 104(%rdi)
+ movq 112(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 112(%rdi)
+ movq 120(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 120(%rdi)
+ movq 128(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 128(%rdi)
+ movq 136(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 136(%rdi)
+ movq 144(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 144(%rdi)
+ movq 152(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 152(%rdi)
+ movq 160(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 160(%rdi)
+ movq 168(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 168(%rdi)
+ movq 176(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 176(%rdi)
+ movq 184(%rsi), %rbp
+ adcq $0 , %rbp
+ movq %rbp , 184(%rdi)
+
+ pop %rbp
+
+ rcrq $1, 184(%rdi)
+ rcrq $1, 176(%rdi)
+ rcrq $1, 168(%rdi)
+ rcrq $1, 160(%rdi)
+ rcrq $1, 152(%rdi)
+ rcrq $1, 144(%rdi)
+ rcrq $1, 136(%rdi)
+ rcrq $1, 128(%rdi)
+ rcrq $1, 120(%rdi)
+ rcrq $1, 112(%rdi)
+ rcrq $1, 104(%rdi)
+ rcrq $1, %rbp
+ rcrq $1, %rdx
+ rcrq $1, %rcx
+ rcrq $1, %rbx
+ rcrq $1, %rax
+ rcrq $1, %r15
+ rcrq $1, %r14
+ rcrq $1, %r13
+ rcrq $1, %r12
+ rcrq $1, %r11
+ rcrq $1, %r10
+ rcrq $1, %r9
+ rcrq $1, %r8
+
+ movq %rbp, 96(%rdi)
+ movq %rdx, 88(%rdi)
+ movq %rcx, 80(%rdi)
+ movq %rbx, 72(%rdi)
+ movq %rax, 64(%rdi)
+ movq %r15, 56(%rdi)
+ movq %r14, 48(%rdi)
+ movq %r13, 40(%rdi)
+ movq %r12, 32(%rdi)
+ movq %r11, 24(%rdi)
+ movq %r10, 16(%rdi)
+ movq %r9 , 8(%rdi)
+ movq %r8 , 0(%rdi)
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ ret
diff --git a/src/low/x64-asm-12l/relic_fp_mul_low.c b/src/low/x64-asm-12l/relic_fp_mul_low.c
new file mode 100644
index 000000000..4d5e493d5
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fp_mul_low.c
@@ -0,0 +1,47 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the low-level prime field multiplication functions.
+ *
+ * @ingroup bn
+ */
+
+#include "gmp.h"
+
+#include "relic_fp.h"
+#include "relic_fp_low.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+dig_t fp_mula_low(dig_t *c, const dig_t *a, dig_t digit) {
+ return mpn_addmul_1(c, a, RLC_FP_DIGS, digit);
+}
+
+dig_t fp_mul1_low(dig_t *c, const dig_t *a, dig_t digit) {
+ return mpn_mul_1(c, a, RLC_FP_DIGS, digit);
+}
diff --git a/src/low/x64-asm-12l/relic_fp_mul_low.s b/src/low/x64-asm-12l/relic_fp_mul_low.s
new file mode 100644
index 000000000..ced58a821
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fp_mul_low.s
@@ -0,0 +1,68 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the low-level prime field multiplication functions.
+ *
+ * @ingroup bn
+ */
+
+#include "macro.s"
+
+.text
+
+.global cdecl(fp_muln_low)
+.global cdecl(fp_mulm_low)
+
+cdecl(fp_muln_low):
+ movq %rdx,%rcx
+ FP_MULN_LOW %rdi, %r8, %r9, %r10, %rsi, %rcx
+ ret
+
+cdecl(fp_mulm_low):
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rbx
+ push %rbp
+ subq $240, %rsp
+
+ movq %rdx,%rcx
+ leaq p0(%rip), %rbx
+
+ FP_MULN_LOW %rsp, %r8, %r9, %r10, %rsi, %rcx
+
+ FP_RDCN_LOW %rdi, %r8, %r9, %r10, %rsp, %rbx
+
+ addq $240, %rsp
+
+ pop %rbp
+ pop %rbx
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ ret
diff --git a/src/low/x64-asm-12l/relic_fp_rdc_low.c b/src/low/x64-asm-12l/relic_fp_rdc_low.c
new file mode 100644
index 000000000..620678a13
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fp_rdc_low.c
@@ -0,0 +1,111 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the low-level prime field modular reduction functions.
+ *
+ * @ingroup fp
+ */
+
+#include "relic_core.h"
+#include "relic_fp.h"
+#include "relic_fp_low.h"
+#include "relic_bn_low.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void fp_rdcs_low(dig_t *c, const dig_t *a, const dig_t *m) {
+ rlc_align dig_t q[2 * RLC_FP_DIGS], _q[2 * RLC_FP_DIGS], t[2 * RLC_FP_DIGS], r[RLC_FP_DIGS];
+ const int *sform;
+ int len, first, i, j, k, b0, d0, b1, d1;
+
+ sform = fp_prime_get_sps(&len);
+
+ RLC_RIP(b0, d0, sform[len - 1]);
+ first = (d0) + (b0 == 0 ? 0 : 1);
+
+ /* q = floor(a/b^k) */
+ dv_zero(q, 2 * RLC_FP_DIGS);
+ dv_rshd(q, a, 2 * RLC_FP_DIGS, d0);
+ if (b0 > 0) {
+ bn_rshb_low(q, q, 2 * RLC_FP_DIGS, b0);
+ }
+
+ /* r = a - qb^k. */
+ dv_copy(r, a, first);
+ if (b0 > 0) {
+ r[first - 1] &= RLC_MASK(b0);
+ }
+
+ k = 0;
+ while (!fp_is_zero(q)) {
+ dv_zero(_q, 2 * RLC_FP_DIGS);
+ for (i = len - 2; i > 0; i--) {
+ j = (sform[i] < 0 ? -sform[i] : sform[i]);
+ RLC_RIP(b1, d1, j);
+ dv_zero(t, 2 * RLC_FP_DIGS);
+ dv_lshd(t, q, RLC_FP_DIGS, d1);
+ if (b1 > 0) {
+ bn_lshb_low(t, t, 2 * RLC_FP_DIGS, b1);
+ }
+ /* Check if these two have the same sign. */
+ if ((sform[len - 2] ^ sform[i]) >= 0) {
+ bn_addn_low(_q, _q, t, 2 * RLC_FP_DIGS);
+ } else {
+ bn_subn_low(_q, _q, t, 2 * RLC_FP_DIGS);
+ }
+ }
+ /* Check if these two have the same sign. */
+ if ((sform[len - 2] ^ sform[0]) >= 0) {
+ bn_addn_low(_q, _q, q, 2 * RLC_FP_DIGS);
+ } else {
+ bn_subn_low(_q, _q, q, 2 * RLC_FP_DIGS);
+ }
+ dv_rshd(q, _q, 2 * RLC_FP_DIGS, d0);
+ if (b0 > 0) {
+ bn_rshb_low(q, q, 2 * RLC_FP_DIGS, b0);
+ }
+ if (b0 > 0) {
+ _q[first - 1] &= RLC_MASK(b0);
+ }
+ if (sform[len - 2] < 0) {
+ fp_add(r, r, _q);
+ } else {
+ if (k++ % 2 == 0) {
+ if (fp_subn_low(r, r, _q)) {
+ fp_addn_low(r, r, m);
+ }
+ } else {
+ fp_addn_low(r, r, _q);
+ }
+ }
+ }
+ while (dv_cmp(r, m, RLC_FP_DIGS) != RLC_LT) {
+ fp_subn_low(r, r, m);
+ }
+ fp_copy(c, r);
+}
diff --git a/src/low/x64-asm-12l/relic_fp_rdc_low.s b/src/low/x64-asm-12l/relic_fp_rdc_low.s
new file mode 100644
index 000000000..4e8e69b71
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fp_rdc_low.s
@@ -0,0 +1,62 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of low-level prime field modular reduction.
+ *
+ * @ingroup fp
+ */
+
+#include "relic_fp_low.h"
+
+#include "macro.s"
+
+.text
+
+.global cdecl(fp_rdcn_low)
+
+/*
+ * Function: fp_rdcn_low
+ * Inputs: rdi = c, rsi = a
+ * Output: rax
+ */
+cdecl(fp_rdcn_low):
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rbx
+ push %rbp
+ leaq p0(%rip), %rbx
+
+ FP_RDCN_LOW %rdi, %r8, %r9, %r10, %rsi, %rbx
+
+ pop %rbp
+ pop %rbx
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ ret
diff --git a/src/low/x64-asm-12l/relic_fp_sqr_low.c b/src/low/x64-asm-12l/relic_fp_sqr_low.c
new file mode 100644
index 000000000..f0c879cd5
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fp_sqr_low.c
@@ -0,0 +1,48 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of low-level prime field squaring functions.
+ *
+ * @version $Id: relic_fp_sqr_low.c 677 2011-03-05 22:19:43Z dfaranha $
+ * @ingroup fp
+ */
+
+#include
+
+#include "relic_fp.h"
+#include "relic_fp_low.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void fp_sqrn_low(dig_t *c, const dig_t *a) {
+ fp_muln_low(c, a, a);
+}
+
+void fp_sqrm_low(dig_t *c, const dig_t *a) {
+ fp_mulm_low(c, a, a);
+}
diff --git a/src/low/x64-asm-12l/relic_fpx_rdc_low.c b/src/low/x64-asm-12l/relic_fpx_rdc_low.c
new file mode 100755
index 000000000..536c40ca8
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fpx_rdc_low.c
@@ -0,0 +1,50 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the low-level extension field modular reduction functions.
+ *
+ * @ingroup fpx
+ */
+
+#include "relic_core.h"
+#include "relic_fp_low.h"
+#include "relic_fpx_low.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void fp3_rdcn_low(fp3_t c, dv3_t a) {
+#if FP_RDC == MONTY
+ fp_rdcn_low(c[0], a[0]);
+ fp_rdcn_low(c[1], a[1]);
+ fp_rdcn_low(c[2], a[2]);
+#else
+ fp_rdc(c[0], a[0]);
+ fp_rdc(c[1], a[1]);
+ fp_rdc(c[2], a[2]);
+#endif
+}
diff --git a/src/low/x64-asm-12l/relic_fpx_rdc_low.s b/src/low/x64-asm-12l/relic_fpx_rdc_low.s
new file mode 100644
index 000000000..8a3c436ff
--- /dev/null
+++ b/src/low/x64-asm-12l/relic_fpx_rdc_low.s
@@ -0,0 +1,65 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2017 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of low-level prime field modular reduction.
+ *
+ * @ingroup fp
+ */
+
+#include "relic_dv_low.h"
+
+#include "macro.s"
+
+.text
+
+.global cdecl(fp2_rdcn_low)
+
+/*
+ * Function: fp_rdcn_low
+ * Inputs: rdi = c, rsi = a
+ * Output: rax
+ */
+cdecl(fp2_rdcn_low):
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rbx
+ push %rbp
+ leaq p0(%rip), %rbx
+
+ FP_RDCN_LOW %rdi, %r8, %r9, %r10, %rsi, %rbx
+ addq $(8*RLC_FP_DIGS), %rdi
+ addq $(8*RLC_DV_DIGS), %rsi
+ FP_RDCN_LOW %rdi, %r8, %r9, %r10, %rsi, %rbx
+
+ pop %rbp
+ pop %rbx
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ ret
diff --git a/src/low/x64-asm-6l/macro.s b/src/low/x64-asm-6l/macro.s
index bdf23114d..615677d31 100644
--- a/src/low/x64-asm-6l/macro.s
+++ b/src/low/x64-asm-6l/macro.s
@@ -32,7 +32,15 @@
* @ingroup fp
*/
-#if FP_PRIME == 377
+#if FP_PRIME == 330
+#define P0 0x523E67A53D5C40AD
+#define P1 0x27BBEC8F954D9613
+#define P2 0xF12A1C4947A0784F
+#define P3 0x5BF00BAF1EE31FEC
+#define P4 0x0832E1406555615B
+#define P5 0x24C
+#define U0 0x9876AE34F480DCDB
+#elif FP_PRIME == 377
#define P0 0x8508C00000000001
#define P1 0x170B5D4430000000
#define P2 0x1EF3622FBA094800
diff --git a/src/low/x64-asm-6l/relic_bn_mul_low.c b/src/low/x64-asm-6l/relic_bn_mul_low.c
new file mode 100644
index 000000000..2229b6d2e
--- /dev/null
+++ b/src/low/x64-asm-6l/relic_bn_mul_low.c
@@ -0,0 +1,60 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2009 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the multiple precision integer arithmetic multiplication
+ * functions.
+ *
+ * @ingroup bn
+ */
+
+#include
+
+#include "relic_bn.h"
+#include "relic_bn_low.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+dig_t bn_mula_low(dig_t *c, const dig_t *a, dig_t digit, int size) {
+ return mpn_addmul_1(c, a, size, digit);
+}
+
+dig_t bn_mul1_low(dig_t *c, const dig_t *a, dig_t digit, int size) {
+ return mpn_mul_1(c, a, size, digit);
+}
+
+void bn_muln_low(dig_t *c, const dig_t *a, const dig_t *b, int size) {
+ mpn_mul_n(c, a, b, size);
+}
+
+void bn_muld_low(dig_t *c, const dig_t *a, int sizea, const dig_t *b, int sizeb,
+ int low, int high) {
+ (void)low;
+ (void)high;
+ mpn_mul(c, a, sizea, b, sizeb);
+}
diff --git a/src/low/x64-asm-6l/relic_bn_mul_low.s b/src/low/x64-asm-6l/relic_bn_mul_low.s
new file mode 100644
index 000000000..fbd535a07
--- /dev/null
+++ b/src/low/x64-asm-6l/relic_bn_mul_low.s
@@ -0,0 +1,97 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2009 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the multiple precision integer arithmetic multiplication
+ * functions in ASM.
+ *
+ * @ingroup bn
+ */
+
+.text
+.global bn_muls_low
+
+/**
+ * c = rdi, a = rsi, sa = rdx, digit = rcx, size = RLC_FP_DIGS
+ */
+bn_muls_low:
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ movq %rcx, %rax
+ shrq $63, %rax
+ xorq %rdx, %rax # sign = sa ^ sd;
+ movq %rcx, %rdx
+ negq %rcx
+ cmovns %rcx, %rdx # rdx = (digit < 0 ? -digit : digit);
+ xorq %rcx, %rcx # clear flags, create zero
+
+ mulxq 0(%rsi), %r8, %r9
+
+ mulxq 8(%rsi), %r11, %r10
+ adcx %r11, %r9
+
+ mulxq 16(%rsi), %r12, %r11
+ adcx %r12, %r10
+
+ mulxq 24(%rsi), %r13, %r12
+ adcx %r13, %r11
+
+ mulxq 32(%rsi), %r14, %r13
+ adcx %r14, %r12
+
+ mulxq 40(%rsi), %rsi, %r14
+ adcx %rsi, %r13
+ adcx %rcx, %r14
+
+ negq %rax
+ xorq %rax, %r8
+ xorq %rax, %r9
+ xorq %rax, %r10
+ xorq %rax, %r11
+ xorq %rax, %r12
+ xorq %rax, %r13
+ xorq %rax, %r14
+
+ negq %rax
+ addq %rax, %r8
+ adcx %rcx, %r9
+ adcx %rcx, %r10
+ adcx %rcx, %r11
+ adcx %rcx, %r12
+ adcx %rcx, %r13
+ adcx %rcx, %r14
+ movq %r8, 0(%rdi)
+ movq %r9, 8(%rdi)
+ movq %r10,16(%rdi)
+ movq %r11,24(%rdi)
+ movq %r12,32(%rdi)
+ movq %r13,40(%rdi)
+ movq %r14, %rax
+
+ popq %r14
+ popq %r13
+ popq %r12
+ ret
diff --git a/src/low/x64-asm-6l/relic_bn_shift_low.c b/src/low/x64-asm-6l/relic_bn_shift_low.c
new file mode 100644
index 000000000..0445b5ab8
--- /dev/null
+++ b/src/low/x64-asm-6l/relic_bn_shift_low.c
@@ -0,0 +1,58 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2009 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the low-level multiple precision bit shifting functions.
+ *
+ * @ingroup bn
+ */
+
+#include
+#include
+#include
+#include
+
+#include "relic_bn.h"
+#include "relic_bn_low.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+dig_t bn_lsh1_low(dig_t *c, const dig_t *a, int size) {
+ return mpn_lshift(c, a, size, 1);
+}
+
+dig_t bn_lshb_low(dig_t *c, const dig_t *a, int size, int bits) {
+ return mpn_lshift(c, a, size, bits);
+}
+
+dig_t bn_rsh1_low(dig_t *c, const dig_t *a, int size) {
+ return mpn_rshift(c, a, size, 1);
+}
+
+dig_t bn_rshb_low(dig_t *c, const dig_t *a, int size, int bits) {
+ return mpn_rshift(c, a, size, bits);
+}
diff --git a/src/low/x64-asm-6l/relic_bn_shift_low.s b/src/low/x64-asm-6l/relic_bn_shift_low.s
new file mode 100644
index 000000000..563e2603e
--- /dev/null
+++ b/src/low/x64-asm-6l/relic_bn_shift_low.s
@@ -0,0 +1,57 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2009 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the ASM multiple precision bit shifting functions.
+ *
+ * @ingroup bn
+ */
+
+.text
+.global bn_rshs_low
+
+bn_rshs_low:
+ movq 0(%rsi), %r8
+ movq 8(%rsi), %r9
+ movq 16(%rsi), %r10
+ movq 24(%rsi), %r11
+ movq 32(%rsi), %rax
+ movq 40(%rsi), %rcx
+ movq 48(%rsi), %rsi
+ shrd $62, %r9, %r8
+ shrd $62, %r10, %r9
+ shrd $62, %r11, %r10
+ shrd $62, %rax, %r11
+ shrd $62, %rcx, %rax
+ shrd $62, %rsi, %rcx
+ sar $62, %rsi
+ movq %r8,0(%rdi)
+ movq %r9,8(%rdi)
+ movq %r10,16(%rdi)
+ movq %r11,24(%rdi)
+ movq %rax,32(%rdi)
+ movq %rcx,40(%rdi)
+ movq %rsi,48(%rdi)
+ ret
diff --git a/src/low/x64-asm-6l/relic_fp_add_low.s b/src/low/x64-asm-6l/relic_fp_add_low.s
index d49e8438f..4e51dcdc1 100644
--- a/src/low/x64-asm-6l/relic_fp_add_low.s
+++ b/src/low/x64-asm-6l/relic_fp_add_low.s
@@ -363,6 +363,12 @@ fp_subc_low:
ret
fp_negm_low:
+ xorq %r9, %r9
+ xorq %r10, %r10
+ xorq %r11, %r11
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
movq 0(%rsi) , %r8
or 8(%rsi) , %r8
or 16(%rsi), %r8
@@ -371,24 +377,24 @@ fp_negm_low:
or 40(%rsi), %r8
test %r8, %r8
cmovnz p0(%rip), %r8
+ cmovnz p1(%rip), %r9
+ cmovnz p2(%rip), %r10
+ cmovnz p3(%rip), %r11
+ cmovnz p4(%rip), %rax
+ cmovnz p5(%rip), %rcx
subq 0(%rsi) , %r8
movq %r8 , 0(%rdi)
- cmovnz p1(%rip), %r8
- sbbq 8(%rsi) , %r8
- movq %r8 , 8(%rdi)
- cmovnz p2(%rip), %r8
- sbbq 16(%rsi), %r8
- movq %r8 , 16(%rdi)
- cmovnz p3(%rip), %r8
- sbbq 24(%rsi), %r8
- movq %r8 , 24(%rdi)
- cmovnz p4(%rip), %r8
- sbbq 32(%rsi), %r8
- movq %r8 , 32(%rdi)
- cmovnz p5(%rip), %r8
- sbbq 40(%rsi), %r8
- movq %r8 , 40(%rdi)
- ret
+ sbbq 8(%rsi) , %r9
+ movq %r9 , 8(%rdi)
+ sbbq 16(%rsi), %r10
+ movq %r10 , 16(%rdi)
+ sbbq 24(%rsi), %r11
+ movq %r11 , 24(%rdi)
+ sbbq 32(%rsi), %rax
+ movq %rax , 32(%rdi)
+ sbbq 40(%rsi), %rcx
+ movq %rcx , 40(%rdi)
+ ret
fp_dbln_low:
movq 0(%rsi), %r8
diff --git a/src/low/x64-asm-6l/relic_fp_mul_low.s b/src/low/x64-asm-6l/relic_fp_mul_low.s
index 20e20f650..3fd3f3dba 100644
--- a/src/low/x64-asm-6l/relic_fp_mul_low.s
+++ b/src/low/x64-asm-6l/relic_fp_mul_low.s
@@ -42,6 +42,7 @@ fp_muln_low:
FP_MULN_LOW %rdi, %r8, %r9, %r10, %rsi, %rcx
ret
+#if FP_PRIME != 381
fp_mulm_low:
push %r12
push %r13
@@ -67,3 +68,9 @@ fp_mulm_low:
pop %r13
pop %r12
ret
+
+#else
+
+#include "relic_fp_mul_low_cryptopt.s"
+
+#endif
\ No newline at end of file
diff --git a/src/low/x64-asm-6l/relic_fp_mul_low_cryptopt.s b/src/low/x64-asm-6l/relic_fp_mul_low_cryptopt.s
new file mode 100644
index 000000000..5d9e7ed8e
--- /dev/null
+++ b/src/low/x64-asm-6l/relic_fp_mul_low_cryptopt.s
@@ -0,0 +1,473 @@
+.text
+.intel_syntax noprefix
+
+fp_mulm_low:
+sub rsp, 352
+mov rax, rdx
+mov rdx, [ rsi + 0x8 ]
+mulx r11, r10, [ rax + 0x8 ]
+mov rdx, [ rsi + 0x10 ]
+mulx r8, rcx, [ rax + 0x10 ]
+mov rdx, [ rax + 0x0 ]
+mov [ rsp - 0x80 ], rbx
+mulx rbx, r9, [ rsi + 0x10 ]
+mov rdx, [ rax + 0x10 ]
+mov [ rsp - 0x78 ], rbp
+mov [ rsp - 0x70 ], r12
+mulx r12, rbp, [ rsi + 0x28 ]
+mov rdx, [ rax + 0x0 ]
+mov [ rsp - 0x68 ], r13
+mov [ rsp - 0x60 ], r14
+mulx r14, r13, [ rsi + 0x8 ]
+mov rdx, [ rax + 0x0 ]
+mov [ rsp - 0x58 ], r15
+mov [ rsp - 0x50 ], rdi
+mulx rdi, r15, [ rsi + 0x18 ]
+test al, al
+adox r10, r14
+mov rdx, [ rax + 0x10 ]
+mov [ rsp - 0x48 ], r15
+mulx r15, r14, [ rsi + 0x8 ]
+mov rdx, [ rsi + 0x8 ]
+mov [ rsp - 0x40 ], r9
+mov [ rsp - 0x38 ], r10
+mulx r10, r9, [ rax + 0x18 ]
+adox r14, r11
+adox r9, r15
+mov rdx, [ rsi + 0x10 ]
+mulx r15, r11, [ rax + 0x8 ]
+adcx r11, rbx
+mov rdx, [ rsi + 0x8 ]
+mov [ rsp - 0x30 ], r11
+mulx r11, rbx, [ rax + 0x20 ]
+adcx rcx, r15
+mov rdx, [ rsi + 0x10 ]
+mov [ rsp - 0x28 ], rcx
+mulx rcx, r15, [ rax + 0x18 ]
+mov rdx, [ rsi + 0x8 ]
+mov [ rsp - 0x20 ], r9
+mov [ rsp - 0x18 ], r14
+mulx r14, r9, [ rax + 0x28 ]
+adox rbx, r10
+adox r9, r11
+mov rdx, [ rax + 0x20 ]
+mulx r11, r10, [ rsi + 0x10 ]
+adcx r15, r8
+adcx r10, rcx
+mov rdx, [ rax + 0x28 ]
+mulx rcx, r8, [ rsi + 0x10 ]
+adcx r8, r11
+mov rdx, [ rsi + 0x18 ]
+mov [ rsp - 0x10 ], r8
+mulx r8, r11, [ rax + 0x8 ]
+mov rdx, [ rax + 0x18 ]
+mov [ rsp - 0x8 ], r10
+mov [ rsp + 0x0 ], r15
+mulx r15, r10, [ rsi + 0x18 ]
+mov rdx, 0x0
+adcx rcx, rdx
+mov rdx, [ rax + 0x10 ]
+mov [ rsp + 0x8 ], rcx
+mov [ rsp + 0x10 ], r9
+mulx r9, rcx, [ rsi + 0x18 ]
+clc
+adcx r11, rdi
+adcx rcx, r8
+mov rdx, 0x0
+adox r14, rdx
+adcx r10, r9
+mov rdx, [ rax + 0x20 ]
+mulx r8, rdi, [ rsi + 0x18 ]
+adcx rdi, r15
+mov rdx, [ rax + 0x8 ]
+mulx r9, r15, [ rsi + 0x28 ]
+mov rdx, [ rax + 0x28 ]
+mov [ rsp + 0x18 ], rdi
+mov [ rsp + 0x20 ], r10
+mulx r10, rdi, [ rsi + 0x18 ]
+adcx rdi, r8
+mov rdx, [ rsi + 0x0 ]
+mov [ rsp + 0x28 ], rdi
+mulx rdi, r8, [ rax + 0x0 ]
+adc r10, 0x0
+mov rdx, [ rax + 0x0 ]
+mov [ rsp + 0x30 ], r10
+mov [ rsp + 0x38 ], rcx
+mulx rcx, r10, [ rsi + 0x28 ]
+mov rdx, 0x89f3fffcfffcfffd
+mov [ rsp + 0x40 ], r10
+mov [ rsp + 0x48 ], r11
+mulx r11, r10, r8
+xor r11, r11
+adox r15, rcx
+adox rbp, r9
+mov rdx, [ rax + 0x18 ]
+mulx rcx, r9, [ rsi + 0x28 ]
+mov rdx, [ rax + 0x8 ]
+mov [ rsp + 0x50 ], rbp
+mulx rbp, r11, [ rsi + 0x0 ]
+adox r9, r12
+mov rdx, [ rsi + 0x0 ]
+mov [ rsp + 0x58 ], r9
+mulx r9, r12, [ rax + 0x10 ]
+mov rdx, [ rax + 0x20 ]
+mov [ rsp + 0x60 ], r15
+mov [ rsp + 0x68 ], r14
+mulx r14, r15, [ rsi + 0x28 ]
+mov rdx, [ rsi + 0x28 ]
+mov [ rsp + 0x70 ], rbx
+mov [ rsp + 0x78 ], r13
+mulx r13, rbx, [ rax + 0x28 ]
+adox r15, rcx
+adox rbx, r14
+mov rdx, [ rsi + 0x0 ]
+mulx r14, rcx, [ rax + 0x20 ]
+adcx r11, rdi
+mov rdx, [ rsi + 0x0 ]
+mov [ rsp + 0x80 ], rbx
+mulx rbx, rdi, [ rax + 0x18 ]
+adcx r12, rbp
+adcx rdi, r9
+mov rdx, [ rax + 0x28 ]
+mulx r9, rbp, [ rsi + 0x0 ]
+adcx rcx, rbx
+adcx rbp, r14
+mov rdx, 0x0
+adox r13, rdx
+adc r9, 0x0
+mov r14, 0xb9feffffffffaaab
+mov rdx, r10
+mulx rbx, r10, r14
+mov r14, 0x1eabfffeb153ffff
+mov [ rsp + 0x88 ], r13
+mov [ rsp + 0x90 ], r15
+mulx r15, r13, r14
+test al, al
+adox r10, r8
+adcx r13, rbx
+adox r13, r11
+mov r10, 0x6730d2a0f6b0f624
+mulx r11, r8, r10
+adcx r8, r15
+adox r8, r12
+mov r12, 0x4b1ba7b6434bacd7
+mulx r15, rbx, r12
+mov r12, 0x64774b84f38512bf
+mulx r14, r10, r12
+adcx r10, r11
+adcx rbx, r14
+adox r10, rdi
+adox rbx, rcx
+mov rdi, 0x1a0111ea397fe69a
+mulx r11, rcx, rdi
+adcx rcx, r15
+mov rdx, 0x0
+adcx r11, rdx
+adox rcx, rbp
+clc
+adcx r13, [ rsp + 0x78 ]
+adox r11, r9
+adcx r8, [ rsp - 0x38 ]
+mov rdx, [ rsi + 0x20 ]
+mulx r9, rbp, [ rax + 0x18 ]
+adcx r10, [ rsp - 0x18 ]
+adcx rbx, [ rsp - 0x20 ]
+adcx rcx, [ rsp + 0x70 ]
+adcx r11, [ rsp + 0x10 ]
+mov rdx, [ rsi + 0x20 ]
+mulx r14, r15, [ rax + 0x0 ]
+mov rdx, [ rax + 0x10 ]
+mulx r12, rdi, [ rsi + 0x20 ]
+mov rdx, [ rax + 0x8 ]
+mov [ rsp + 0x98 ], r15
+mov [ rsp + 0xa0 ], r11
+mulx r11, r15, [ rsi + 0x20 ]
+setc dl
+clc
+adcx r15, r14
+adcx rdi, r11
+adcx rbp, r12
+movzx rdx, dl
+movzx r14, dl
+adox r14, [ rsp + 0x68 ]
+mov rdx, 0x89f3fffcfffcfffd
+mulx r11, r12, r13
+mov rdx, [ rsi + 0x20 ]
+mov [ rsp + 0xa8 ], rbp
+mulx rbp, r11, [ rax + 0x20 ]
+mov rdx, [ rax + 0x28 ]
+mov [ rsp + 0xb0 ], rdi
+mov [ rsp + 0xb8 ], r15
+mulx r15, rdi, [ rsi + 0x20 ]
+adcx r11, r9
+mov rdx, 0xb9feffffffffaaab
+mov [ rsp + 0xc0 ], r11
+mulx r11, r9, r12
+adcx rdi, rbp
+setc bpl
+clc
+adcx r9, r13
+mov r9, 0x1eabfffeb153ffff
+mov rdx, r12
+mulx r13, r12, r9
+movzx r9, bpl
+lea r9, [ r9 + r15 ]
+seto r15b
+mov rbp, -0x2
+inc rbp
+adox r12, r11
+mov r11, 0x6730d2a0f6b0f624
+mov [ rsp + 0xc8 ], r9
+mulx r9, rbp, r11
+adox rbp, r13
+adcx r12, r8
+adcx rbp, r10
+mov r8, 0x64774b84f38512bf
+mulx r13, r10, r8
+mov r8, 0x4b1ba7b6434bacd7
+mov [ rsp + 0xd0 ], rdi
+mulx rdi, r11, r8
+adox r10, r9
+adox r11, r13
+adcx r10, rbx
+mov rbx, 0x1a0111ea397fe69a
+mulx r13, r9, rbx
+adox r9, rdi
+adcx r11, rcx
+mov rcx, 0x0
+adox r13, rcx
+adcx r9, [ rsp + 0xa0 ]
+adcx r13, r14
+movzx r14, r15b
+adc r14, 0x0
+xor r15, r15
+adox r12, [ rsp - 0x40 ]
+adox rbp, [ rsp - 0x30 ]
+adox r10, [ rsp - 0x28 ]
+adox r11, [ rsp + 0x0 ]
+mov rcx, 0x89f3fffcfffcfffd
+mov rdx, rcx
+mulx rdi, rcx, r12
+adox r9, [ rsp - 0x8 ]
+mov rdi, 0x1eabfffeb153ffff
+mov rdx, rdi
+mulx r15, rdi, rcx
+adox r13, [ rsp - 0x10 ]
+mov rbx, 0xb9feffffffffaaab
+mov rdx, rcx
+mulx r8, rcx, rbx
+adcx rdi, r8
+adox r14, [ rsp + 0x8 ]
+seto r8b
+mov rbx, -0x2
+inc rbx
+adox rcx, r12
+adox rdi, rbp
+mov rcx, 0x6730d2a0f6b0f624
+mulx rbp, r12, rcx
+adcx r12, r15
+adox r12, r10
+mov r10, 0x64774b84f38512bf
+mulx rbx, r15, r10
+adcx r15, rbp
+mov rbp, 0x4b1ba7b6434bacd7
+mulx rcx, r10, rbp
+adox r15, r11
+adcx r10, rbx
+mov r11, 0x1a0111ea397fe69a
+mulx rbp, rbx, r11
+adcx rbx, rcx
+mov rdx, 0x0
+adcx rbp, rdx
+clc
+adcx rdi, [ rsp - 0x48 ]
+adcx r12, [ rsp + 0x48 ]
+mov rcx, 0x89f3fffcfffcfffd
+mov rdx, rdi
+mulx r11, rdi, rcx
+adox r10, r9
+adox rbx, r13
+mov r11, 0xb9feffffffffaaab
+xchg rdx, rdi
+mulx r13, r9, r11
+adox rbp, r14
+adcx r15, [ rsp + 0x38 ]
+adcx r10, [ rsp + 0x20 ]
+adcx rbx, [ rsp + 0x18 ]
+adcx rbp, [ rsp + 0x28 ]
+seto r14b
+mov r11, -0x2
+inc r11
+adox r9, rdi
+movzx r9, r14b
+movzx r8, r8b
+lea r9, [ r9 + r8 ]
+mov r8, 0x1eabfffeb153ffff
+mulx r14, rdi, r8
+adcx r9, [ rsp + 0x30 ]
+setc r11b
+clc
+adcx rdi, r13
+adox rdi, r12
+mov r12, 0x6730d2a0f6b0f624
+mulx r8, r13, r12
+adcx r13, r14
+adox r13, r15
+mov r15, 0x64774b84f38512bf
+mulx r12, r14, r15
+adcx r14, r8
+adox r14, r10
+mov r10, 0x4b1ba7b6434bacd7
+mulx r15, r8, r10
+adcx r8, r12
+adox r8, rbx
+mov rbx, 0x1a0111ea397fe69a
+mulx r10, r12, rbx
+adcx r12, r15
+adox r12, rbp
+setc dl
+clc
+adcx rdi, [ rsp + 0x98 ]
+adcx r13, [ rsp + 0xb8 ]
+movzx rbp, dl
+lea rbp, [ rbp + r10 ]
+adox rbp, r9
+adcx r14, [ rsp + 0xb0 ]
+mov rdx, rcx
+mulx r9, rcx, rdi
+mov r9, 0xb9feffffffffaaab
+mov rdx, r9
+mulx r15, r9, rcx
+movzx r10, r11b
+mov rbx, 0x0
+adox r10, rbx
+mov r11, 0x6730d2a0f6b0f624
+mov rdx, rcx
+mulx rbx, rcx, r11
+adcx r8, [ rsp + 0xa8 ]
+adcx r12, [ rsp + 0xc0 ]
+adcx rbp, [ rsp + 0xd0 ]
+mov r11, -0x2
+inc r11
+adox r9, rdi
+mov r9, 0x1eabfffeb153ffff
+mulx r11, rdi, r9
+adcx r10, [ rsp + 0xc8 ]
+setc r9b
+clc
+adcx rdi, r15
+adcx rcx, r11
+adox rdi, r13
+adox rcx, r14
+mov r13, 0x64774b84f38512bf
+mulx r15, r14, r13
+adcx r14, rbx
+mov rbx, 0x4b1ba7b6434bacd7
+mulx r13, r11, rbx
+adox r14, r8
+adcx r11, r15
+mov r8, 0x1a0111ea397fe69a
+mulx rbx, r15, r8
+adcx r15, r13
+mov rdx, 0x0
+adcx rbx, rdx
+adox r11, r12
+adox r15, rbp
+adox rbx, r10
+movzx r12, r9b
+adox r12, rdx
+xor rbp, rbp
+adox rdi, [ rsp + 0x40 ]
+adox rcx, [ rsp + 0x60 ]
+mov rdx, 0x89f3fffcfffcfffd
+mulx r10, r9, rdi
+mov r10, 0x1eabfffeb153ffff
+mov rdx, r9
+mulx r13, r9, r10
+adox r14, [ rsp + 0x50 ]
+adox r11, [ rsp + 0x58 ]
+adox r15, [ rsp + 0x90 ]
+mov rbp, 0xb9feffffffffaaab
+mulx r10, r8, rbp
+adox rbx, [ rsp + 0x80 ]
+adox r12, [ rsp + 0x88 ]
+adcx r9, r10
+seto r10b
+mov rbp, -0x2
+inc rbp
+adox r8, rdi
+adox r9, rcx
+mov r8, 0x6730d2a0f6b0f624
+mulx rcx, rdi, r8
+adcx rdi, r13
+mov r13, 0x64774b84f38512bf
+mulx r8, rbp, r13
+adcx rbp, rcx
+adox rdi, r14
+mov r14, 0x4b1ba7b6434bacd7
+mulx r13, rcx, r14
+adcx rcx, r8
+adox rbp, r11
+mov r11, 0x1a0111ea397fe69a
+mulx r14, r8, r11
+adcx r8, r13
+adox rcx, r15
+mov rdx, 0x0
+adcx r14, rdx
+adox r8, rbx
+adox r14, r12
+movzx r15, r10b
+adox r15, rdx
+mov rbx, r9
+mov r10, 0xb9feffffffffaaab
+sub rbx, r10
+mov r12, rdi
+mov r13, 0x1eabfffeb153ffff
+sbb r12, r13
+mov rdx, rbp
+mov r11, 0x6730d2a0f6b0f624
+sbb rdx, r11
+mov r11, rcx
+mov r13, 0x64774b84f38512bf
+sbb r11, r13
+mov r13, r8
+mov r10, 0x4b1ba7b6434bacd7
+sbb r13, r10
+mov r10, r14
+mov [ rsp + 0xd8 ], rdx
+mov rdx, 0x1a0111ea397fe69a
+sbb r10, rdx
+sbb r15, 0x00000000
+cmovc rbx, r9
+cmovc r11, rcx
+cmovc r13, r8
+mov r15, [ rsp - 0x50 ]
+mov [ r15 + 0x20 ], r13
+mov [ r15 + 0x0 ], rbx
+cmovc r12, rdi
+cmovc r10, r14
+mov [ r15 + 0x8 ], r12
+mov [ r15 + 0x28 ], r10
+mov [ r15 + 0x18 ], r11
+mov r9, [ rsp + 0xd8 ]
+cmovc r9, rbp
+mov [ r15 + 0x10 ], r9
+mov rbx, [ rsp - 0x80 ]
+mov rbp, [ rsp - 0x78 ]
+mov r12, [ rsp - 0x70 ]
+mov r13, [ rsp - 0x68 ]
+mov r14, [ rsp - 0x60 ]
+mov r15, [ rsp - 0x58 ]
+add rsp, 352
+ret
+// cpu Intel(R) Core(TM) i9-10900K CPU @ 3.70GHz
+// ratio 1.8980
+// seed 2910039682142008
+// CC / CFLAGS clang / -march=native -mtune=native -O3
+// time needed: 5268392 ms on 180000 evaluations.
+// Time spent for assembling and measuring (initial batch_size=31, initial num_batches=31): 132796 ms
+// number of used evaluations: 180000
+// Ratio (time for assembling + measure)/(total runtime for 180000 evals): 0.025206172965109658
+// number reverted permutation / tried permutation: 69492 / 89703 =77.469%
+// number reverted decision / tried decision: 62053 / 90296 =68.722%
+// validated in 51.361s
\ No newline at end of file
diff --git a/src/low/x64-asm-6l/relic_fp_smb_low.c b/src/low/x64-asm-6l/relic_fp_smb_low.c
index d25200282..118a053df 100644
--- a/src/low/x64-asm-6l/relic_fp_smb_low.c
+++ b/src/low/x64-asm-6l/relic_fp_smb_low.c
@@ -41,27 +41,5 @@
/*============================================================================*/
int fp_smbm_low(const dig_t *a) {
- mpz_t n, p;
- rlc_align dig_t t[2 * RLC_FP_DIGS], u[RLC_FP_DIGS];
- int res;
-
- mpz_init(n);
- mpz_init(p);
-
-#if FP_RDC == MONTY
- dv_zero(t + RLC_FP_DIGS, RLC_FP_DIGS);
- dv_copy(t, a, RLC_FP_DIGS);
- fp_rdcn_low(u, t);
-#else
- fp_copy(u, a);
-#endif
-
- mpz_import(n, RLC_FP_DIGS, -1, sizeof(dig_t), 0, 0, u);
- mpz_import(p, RLC_FP_DIGS, -1, sizeof(dig_t), 0, 0, fp_prime_get());
-
- res = mpz_jacobi(n, p);
-
- mpz_clear(n);
- mpz_clear(p);
- return res;
+ return (fp_is_zero(a) ? 0 : (ct_is_square_mod_384(a, fp_prime_get()) ? 1 : -1));
}
diff --git a/src/low/x64-asm-6l/relic_fp_smb_low.s b/src/low/x64-asm-6l/relic_fp_smb_low.s
new file mode 100644
index 000000000..4d6195845
--- /dev/null
+++ b/src/low/x64-asm-6l/relic_fp_smb_low.s
@@ -0,0 +1,479 @@
+.text
+
+.globl ct_is_square_mod_384
+.type ct_is_square_mod_384,@function
+.align 32
+ct_is_square_mod_384:
+.cfi_startproc
+ .byte 0xf3,0x0f,0x1e,0xfa
+
+
+ pushq %rbp
+.cfi_adjust_cfa_offset 8
+.cfi_offset %rbp,-16
+ pushq %rbx
+.cfi_adjust_cfa_offset 8
+.cfi_offset %rbx,-24
+ pushq %r12
+.cfi_adjust_cfa_offset 8
+.cfi_offset %r12,-32
+ pushq %r13
+.cfi_adjust_cfa_offset 8
+.cfi_offset %r13,-40
+ pushq %r14
+.cfi_adjust_cfa_offset 8
+.cfi_offset %r14,-48
+ pushq %r15
+.cfi_adjust_cfa_offset 8
+.cfi_offset %r15,-56
+ subq $536,%rsp
+.cfi_adjust_cfa_offset 536
+
+
+ leaq 24+255(%rsp),%rax
+ andq $-256,%rax
+
+ movq 0(%rdi),%r8
+ movq 8(%rdi),%r9
+ movq 16(%rdi),%r10
+ movq 24(%rdi),%r11
+ movq 32(%rdi),%r12
+ movq 40(%rdi),%r13
+
+ movq 0(%rsi),%r14
+ movq 8(%rsi),%r15
+ movq 16(%rsi),%rbx
+ movq 24(%rsi),%rcx
+ movq 32(%rsi),%rdx
+ movq 40(%rsi),%rdi
+ movq %rax,%rsi
+
+ movq %r8,0(%rax)
+ movq %r9,8(%rax)
+ movq %r10,16(%rax)
+ movq %r11,24(%rax)
+ movq %r12,32(%rax)
+ movq %r13,40(%rax)
+
+ movq %r14,48(%rax)
+ movq %r15,56(%rax)
+ movq %rbx,64(%rax)
+ movq %rcx,72(%rax)
+ movq %rdx,80(%rax)
+ movq %rdi,88(%rax)
+
+ xorq %rbp,%rbp
+ movl $24,%ecx
+ jmp .Loop_is_square
+
+.align 32
+.Loop_is_square:
+ movl %ecx,16(%rsp)
+
+ call __ab_approximation_30
+ movq %rax,0(%rsp)
+ movq %rbx,8(%rsp)
+
+ movq $128+48,%rdi
+ xorq %rsi,%rdi
+ call __smulq_384_n_shift_by_30
+
+ movq 0(%rsp),%rdx
+ movq 8(%rsp),%rcx
+ leaq -48(%rdi),%rdi
+ call __smulq_384_n_shift_by_30
+
+ movl 16(%rsp),%ecx
+ xorq $128,%rsi
+
+ andq 48(%rdi),%r14
+ shrq $1,%r14
+ addq %r14,%rbp
+
+ subl $1,%ecx
+ jnz .Loop_is_square
+
+
+
+
+ movq 48(%rsi),%r9
+ call __inner_loop_48
+
+ movq $1,%rax
+ andq %rbp,%rax
+ xorq $1,%rax
+
+ leaq 536(%rsp),%r8
+ movq 0(%r8),%r15
+.cfi_restore %r15
+ movq 8(%r8),%r14
+.cfi_restore %r14
+ movq 16(%r8),%r13
+.cfi_restore %r13
+ movq 24(%r8),%r12
+.cfi_restore %r12
+ movq 32(%r8),%rbx
+.cfi_restore %rbx
+ movq 40(%r8),%rbp
+.cfi_restore %rbp
+ leaq 48(%r8),%rsp
+.cfi_adjust_cfa_offset -536-8*6
+
+ .byte 0xf3,0xc3
+.cfi_endproc
+.size ct_is_square_mod_384,.-ct_is_square_mod_384
+
+.type __smulq_384_n_shift_by_30,@function
+.align 32
+__smulq_384_n_shift_by_30:
+.cfi_startproc
+ .byte 0xf3,0x0f,0x1e,0xfa
+
+ movq 0(%rsi),%r8
+ movq 8(%rsi),%r9
+ movq 16(%rsi),%r10
+ movq 24(%rsi),%r11
+ movq 32(%rsi),%r12
+ movq 40(%rsi),%r13
+
+ movq %rdx,%rbx
+ sarq $63,%rdx
+ xorq %rax,%rax
+ subq %rdx,%rax
+
+ xorq %rdx,%rbx
+ addq %rax,%rbx
+
+ xorq %rdx,%r8
+ xorq %rdx,%r9
+ xorq %rdx,%r10
+ xorq %rdx,%r11
+ xorq %rdx,%r12
+ xorq %rdx,%r13
+ addq %r8,%rax
+ adcq $0,%r9
+ adcq $0,%r10
+ adcq $0,%r11
+ adcq $0,%r12
+ adcq $0,%r13
+
+ movq %rdx,%r14
+ andq %rbx,%r14
+ mulq %rbx
+ movq %rax,%r8
+ movq %r9,%rax
+ movq %rdx,%r9
+ mulq %rbx
+ addq %rax,%r9
+ movq %r10,%rax
+ adcq $0,%rdx
+ movq %rdx,%r10
+ mulq %rbx
+ addq %rax,%r10
+ movq %r11,%rax
+ adcq $0,%rdx
+ movq %rdx,%r11
+ mulq %rbx
+ addq %rax,%r11
+ movq %r12,%rax
+ adcq $0,%rdx
+ movq %rdx,%r12
+ mulq %rbx
+ addq %rax,%r12
+ movq %r13,%rax
+ adcq $0,%rdx
+ movq %rdx,%r13
+ negq %r14
+ mulq %rbx
+ addq %rax,%r13
+ adcq %rdx,%r14
+ leaq 48(%rsi),%rsi
+ movq %rcx,%rdx
+
+ movq %r8,0(%rdi)
+ movq %r9,8(%rdi)
+ movq %r10,16(%rdi)
+ movq %r11,24(%rdi)
+ movq %r12,32(%rdi)
+ movq %r13,40(%rdi)
+ movq 0(%rsi),%r8
+ movq 8(%rsi),%r9
+ movq 16(%rsi),%r10
+ movq 24(%rsi),%r11
+ movq 32(%rsi),%r12
+ movq 40(%rsi),%r13
+
+ movq %rdx,%rbx
+ sarq $63,%rdx
+ xorq %rax,%rax
+ subq %rdx,%rax
+
+ xorq %rdx,%rbx
+ addq %rax,%rbx
+
+ xorq %rdx,%r8
+ xorq %rdx,%r9
+ xorq %rdx,%r10
+ xorq %rdx,%r11
+ xorq %rdx,%r12
+ xorq %rdx,%r13
+ addq %r8,%rax
+ adcq $0,%r9
+ adcq $0,%r10
+ adcq $0,%r11
+ adcq $0,%r12
+ adcq $0,%r13
+
+ movq %rdx,%r15
+ andq %rbx,%r15
+ mulq %rbx
+ movq %rax,%r8
+ movq %r9,%rax
+ movq %rdx,%r9
+ mulq %rbx
+ addq %rax,%r9
+ movq %r10,%rax
+ adcq $0,%rdx
+ movq %rdx,%r10
+ mulq %rbx
+ addq %rax,%r10
+ movq %r11,%rax
+ adcq $0,%rdx
+ movq %rdx,%r11
+ mulq %rbx
+ addq %rax,%r11
+ movq %r12,%rax
+ adcq $0,%rdx
+ movq %rdx,%r12
+ mulq %rbx
+ addq %rax,%r12
+ movq %r13,%rax
+ adcq $0,%rdx
+ movq %rdx,%r13
+ negq %r15
+ mulq %rbx
+ addq %rax,%r13
+ adcq %rdx,%r15
+ leaq -48(%rsi),%rsi
+
+ addq 0(%rdi),%r8
+ adcq 8(%rdi),%r9
+ adcq 16(%rdi),%r10
+ adcq 24(%rdi),%r11
+ adcq 32(%rdi),%r12
+ adcq 40(%rdi),%r13
+ adcq %r15,%r14
+
+ shrdq $30,%r9,%r8
+ shrdq $30,%r10,%r9
+ shrdq $30,%r11,%r10
+ shrdq $30,%r12,%r11
+ shrdq $30,%r13,%r12
+ shrdq $30,%r14,%r13
+
+ sarq $63,%r14
+ xorq %rbx,%rbx
+ subq %r14,%rbx
+
+ xorq %r14,%r8
+ xorq %r14,%r9
+ xorq %r14,%r10
+ xorq %r14,%r11
+ xorq %r14,%r12
+ xorq %r14,%r13
+ addq %rbx,%r8
+ adcq $0,%r9
+ adcq $0,%r10
+ adcq $0,%r11
+ adcq $0,%r12
+ adcq $0,%r13
+
+ movq %r8,0(%rdi)
+ movq %r9,8(%rdi)
+ movq %r10,16(%rdi)
+ movq %r11,24(%rdi)
+ movq %r12,32(%rdi)
+ movq %r13,40(%rdi)
+
+ .byte 0xf3,0xc3
+.cfi_endproc
+.size __smulq_384_n_shift_by_30,.-__smulq_384_n_shift_by_30
+.type __ab_approximation_30,@function
+.align 32
+__ab_approximation_30:
+.cfi_startproc
+ .byte 0xf3,0x0f,0x1e,0xfa
+
+ movq 88(%rsi),%rbx
+ movq 80(%rsi),%r15
+ movq 72(%rsi),%r14
+
+ movq %r13,%rax
+ orq %rbx,%rax
+ cmovzq %r12,%r13
+ cmovzq %r15,%rbx
+ cmovzq %r11,%r12
+ movq 64(%rsi),%r11
+ cmovzq %r14,%r15
+
+ movq %r13,%rax
+ orq %rbx,%rax
+ cmovzq %r12,%r13
+ cmovzq %r15,%rbx
+ cmovzq %r10,%r12
+ movq 56(%rsi),%r10
+ cmovzq %r11,%r15
+
+ movq %r13,%rax
+ orq %rbx,%rax
+ cmovzq %r12,%r13
+ cmovzq %r15,%rbx
+ cmovzq %r9,%r12
+ movq 48(%rsi),%r9
+ cmovzq %r10,%r15
+
+ movq %r13,%rax
+ orq %rbx,%rax
+ cmovzq %r12,%r13
+ cmovzq %r15,%rbx
+ cmovzq %r8,%r12
+ cmovzq %r9,%r15
+
+ movq %r13,%rax
+ orq %rbx,%rax
+ bsrq %rax,%rcx
+ leaq 1(%rcx),%rcx
+ cmovzq %r8,%r13
+ cmovzq %r9,%rbx
+ cmovzq %rax,%rcx
+ negq %rcx
+
+
+ shldq %cl,%r12,%r13
+ shldq %cl,%r15,%rbx
+
+ movq $0xFFFFFFFF00000000,%rax
+ movl %r8d,%r8d
+ movl %r9d,%r9d
+ andq %rax,%r13
+ andq %rax,%rbx
+ orq %r13,%r8
+ orq %rbx,%r9
+
+ jmp __inner_loop_30
+
+ .byte 0xf3,0xc3
+.cfi_endproc
+.size __ab_approximation_30,.-__ab_approximation_30
+.type __inner_loop_30,@function
+.align 32
+__inner_loop_30:
+.cfi_startproc
+ .byte 0xf3,0x0f,0x1e,0xfa
+
+ movq $0x7FFFFFFF80000000,%rbx
+ movq $0x800000007FFFFFFF,%rcx
+ leaq -1(%rbx),%r15
+ movl $30,%edi
+
+.Loop_30:
+ movq %r8,%rax
+ andq %r9,%rax
+ shrq $1,%rax
+
+ cmpq %r9,%r8
+ movq %r8,%r10
+ movq %r9,%r11
+ leaq (%rax,%rbp,1),%rax
+ movq %rbx,%r12
+ movq %rcx,%r13
+ movq %rbp,%r14
+ cmovbq %r9,%r8
+ cmovbq %r10,%r9
+ cmovbq %rcx,%rbx
+ cmovbq %r12,%rcx
+ cmovbq %rax,%rbp
+
+ subq %r9,%r8
+ subq %rcx,%rbx
+ addq %r15,%rbx
+
+ testq $1,%r10
+ cmovzq %r10,%r8
+ cmovzq %r11,%r9
+ cmovzq %r12,%rbx
+ cmovzq %r13,%rcx
+ cmovzq %r14,%rbp
+
+ leaq 2(%r9),%rax
+ shrq $1,%r8
+ shrq $2,%rax
+ addq %rcx,%rcx
+ leaq (%rax,%rbp,1),%rbp
+ subq %r15,%rcx
+
+ subl $1,%edi
+ jnz .Loop_30
+
+ shrq $32,%r15
+ movl %ebx,%eax
+ shrq $32,%rbx
+ movl %ecx,%edx
+ shrq $32,%rcx
+ subq %r15,%rax
+ subq %r15,%rbx
+ subq %r15,%rdx
+ subq %r15,%rcx
+
+ .byte 0xf3,0xc3
+.cfi_endproc
+.size __inner_loop_30,.-__inner_loop_30
+
+.type __inner_loop_48,@function
+.align 32
+__inner_loop_48:
+.cfi_startproc
+ .byte 0xf3,0x0f,0x1e,0xfa
+
+ movl $48,%edi
+
+.Loop_48:
+ movq %r8,%rax
+ andq %r9,%rax
+ shrq $1,%rax
+
+ cmpq %r9,%r8
+ movq %r8,%r10
+ movq %r9,%r11
+ leaq (%rax,%rbp,1),%rax
+ movq %rbp,%r12
+ cmovbq %r9,%r8
+ cmovbq %r10,%r9
+ cmovbq %rax,%rbp
+
+ subq %r9,%r8
+
+ testq $1,%r10
+ cmovzq %r10,%r8
+ cmovzq %r11,%r9
+ cmovzq %r12,%rbp
+
+ leaq 2(%r9),%rax
+ shrq $1,%r8
+ shrq $2,%rax
+ addq %rax,%rbp
+
+ subl $1,%edi
+ jnz .Loop_48
+
+ .byte 0xf3,0xc3
+.cfi_endproc
+.size __inner_loop_48,.-__inner_loop_48
+
+.section .note.GNU-stack,"",@progbits
+.section .note.gnu.property,"a",@note
+ .long 4,2f-1f,5
+ .byte 0x47,0x4E,0x55,0
+1: .long 0xc0000002,4,3
+.align 8
+2:
diff --git a/src/low/x64-asm-7l/relic_fp_add_low.s b/src/low/x64-asm-7l/relic_fp_add_low.s
index c53afb457..4f03c6d96 100644
--- a/src/low/x64-asm-7l/relic_fp_add_low.s
+++ b/src/low/x64-asm-7l/relic_fp_add_low.s
@@ -342,6 +342,15 @@ fp_subc_low:
ret
fp_negm_low:
+ push %rbx
+
+ xorq %r9, %r9
+ xorq %r10, %r10
+ xorq %r11, %r11
+ xorq %rbx, %rbx
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
movq 0(%rsi) , %r8
or 8(%rsi) , %r8
or 16(%rsi), %r8
@@ -357,6 +366,12 @@ fp_negm_low:
cmovnz p4(%rip), %rbx
cmovnz p5(%rip), %rax
cmovnz p6(%rip), %rcx
+ cmovnz p1(%rip), %r9
+ cmovnz p2(%rip), %r10
+ cmovnz p3(%rip), %r11
+ cmovnz p4(%rip), %rbx
+ cmovnz p5(%rip),%rax
+ cmovnz p6(%rip),%rcx
subq 0(%rsi) , %r8
movq %r8 , 0(%rdi)
sbbq 8(%rsi) , %r9
diff --git a/src/low/x64-asm-8.5l/relic_fp_add_low.s b/src/low/x64-asm-8.5l/relic_fp_add_low.s
index b531d1ac7..c7a18e7c3 100644
--- a/src/low/x64-asm-8.5l/relic_fp_add_low.s
+++ b/src/low/x64-asm-8.5l/relic_fp_add_low.s
@@ -458,6 +458,19 @@ cdecl(fp_subc_low):
ret
cdecl(fp_negm_low):
+ push %rbx
+ push %rbp
+ push %r12
+
+ xorq %r9, %r9
+ xorq %r10, %r10
+ xorq %r11, %r11
+ xorq %r12, %r12
+ xorq %rbx, %rbx
+ xorq %rbp, %rbp
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
movq 0(%rsi) , %r8
or 8(%rsi) , %r8
or 16(%rsi), %r8
@@ -469,33 +482,36 @@ cdecl(fp_negm_low):
or 64(%rsi), %r8
test %r8, %r8
cmovnz p0(%rip), %r8
+ cmovnz p1(%rip), %r9
+ cmovnz p2(%rip), %r10
+ cmovnz p3(%rip), %r11
+ cmovnz p4(%rip), %rbx
+ cmovnz p5(%rip), %rbp
+ cmovnz p6(%rip), %r12
+ cmovnz p7(%rip), %rax
+ cmovnz p8(%rip), %rcx
subq 0(%rsi) , %r8
movq %r8 , 0(%rdi)
- cmovnz p1(%rip), %r8
- sbbq 8(%rsi) , %r8
- movq %r8 , 8(%rdi)
- cmovnz p2(%rip), %r8
- sbbq 16(%rsi), %r8
- movq %r8 , 16(%rdi)
- cmovnz p3(%rip), %r8
- sbbq 24(%rsi), %r8
- movq %r8 , 24(%rdi)
- cmovnz p4(%rip), %r8
- sbbq 32(%rsi), %r8
- movq %r8 , 32(%rdi)
- cmovnz p5(%rip), %r8
- sbbq 40(%rsi), %r8
- movq %r8 , 40(%rdi)
- cmovnz p6(%rip), %r8
- sbbq 48(%rsi), %r8
- movq %r8 , 48(%rdi)
- cmovnz p7(%rip), %r8
- sbbq 56(%rsi), %r8
- movq %r8 , 56(%rdi)
- cmovnz p8(%rip), %r8
- sbbq 64(%rsi), %r8
- movq %r8 , 64(%rdi)
- ret
+ sbbq 8(%rsi) , %r9
+ movq %r9 , 8(%rdi)
+ sbbq 16(%rsi), %r10
+ movq %r10 ,16(%rdi)
+ sbbq 24(%rsi), %r11
+ movq %r11 ,24(%rdi)
+ sbbq 32(%rsi), %rbx
+ movq %rbx ,32(%rdi)
+ sbbq 40(%rsi), %rbp
+ movq %rbp ,40(%rdi)
+ sbbq 48(%rsi), %r12
+ movq %r12 ,48(%rdi)
+ sbbq 56(%rsi), %rax
+ movq %rax ,56(%rdi)
+ sbbq 64(%rsi), %rcx
+ movq %rcx ,64(%rdi)
+
+ pop %r12
+ pop %rbp
+ pop %rbx
cdecl(fp_dbln_low):
movq 0(%rsi), %r8
diff --git a/src/low/x64-asm-8l/relic_bn_mul_low.c b/src/low/x64-asm-8l/relic_bn_mul_low.c
new file mode 100644
index 000000000..2229b6d2e
--- /dev/null
+++ b/src/low/x64-asm-8l/relic_bn_mul_low.c
@@ -0,0 +1,60 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2009 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the multiple precision integer arithmetic multiplication
+ * functions.
+ *
+ * @ingroup bn
+ */
+
+#include
+
+#include "relic_bn.h"
+#include "relic_bn_low.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+dig_t bn_mula_low(dig_t *c, const dig_t *a, dig_t digit, int size) {
+ return mpn_addmul_1(c, a, size, digit);
+}
+
+dig_t bn_mul1_low(dig_t *c, const dig_t *a, dig_t digit, int size) {
+ return mpn_mul_1(c, a, size, digit);
+}
+
+void bn_muln_low(dig_t *c, const dig_t *a, const dig_t *b, int size) {
+ mpn_mul_n(c, a, b, size);
+}
+
+void bn_muld_low(dig_t *c, const dig_t *a, int sizea, const dig_t *b, int sizeb,
+ int low, int high) {
+ (void)low;
+ (void)high;
+ mpn_mul(c, a, sizea, b, sizeb);
+}
diff --git a/src/low/x64-asm-8l/relic_bn_mul_low.s b/src/low/x64-asm-8l/relic_bn_mul_low.s
new file mode 100644
index 000000000..4a9161c7a
--- /dev/null
+++ b/src/low/x64-asm-8l/relic_bn_mul_low.s
@@ -0,0 +1,113 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2009 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the multiple precision integer arithmetic multiplication
+ * functions in ASM.
+ *
+ * @ingroup bn
+ */
+
+.text
+.global bn_muls_low
+
+/**
+ * c = rdi, a = rsi, sa = rdx, digit = rcx, size = RLC_FP_DIGS
+ */
+bn_muls_low:
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ pushq %rbp
+ movq %rcx, %rax
+ shrq $63, %rax
+ xorq %rdx, %rax # sign = sa ^ sd;
+ movq %rcx, %rdx
+ negq %rcx
+ cmovns %rcx, %rdx # rdx = (digit < 0 ? -digit : digit);
+ xorq %rcx, %rcx # clear flags, create zero
+
+ mulxq 0(%rsi), %r8, %r9
+
+ mulxq 8(%rsi), %r11, %r10
+ adcx %r11, %r9
+
+ mulxq 16(%rsi), %r12, %r11
+ adcx %r12, %r10
+
+ mulxq 24(%rsi), %r13, %r12
+ adcx %r13, %r11
+
+ mulxq 32(%rsi), %r14, %r13
+ adcx %r14, %r12
+
+ mulxq 40(%rsi), %r15, %r14
+ adcx %r15, %r13
+
+ mulxq 48(%rsi), %rbp, %r15
+ adcx %rbp, %r14
+
+ mulxq 56(%rsi), %rsi, %rbp
+ adcx %rsi, %r15
+ adcx %rcx, %rbp
+
+ negq %rax
+ xorq %rax, %r8
+ xorq %rax, %r9
+ xorq %rax, %r10
+ xorq %rax, %r11
+ xorq %rax, %r12
+ xorq %rax, %r13
+ xorq %rax, %r14
+ xorq %rax, %r15
+ xorq %rax, %rbp
+
+ negq %rax
+ addq %rax, %r8
+ adcx %rcx, %r9
+ adcx %rcx, %r10
+ adcx %rcx, %r11
+ adcx %rcx, %r12
+ adcx %rcx, %r13
+ adcx %rcx, %r14
+ adcx %rcx, %r15
+ adcx %rcx, %rbp
+ movq %r8, 0(%rdi)
+ movq %r9, 8(%rdi)
+ movq %r10,16(%rdi)
+ movq %r11,24(%rdi)
+ movq %r12,32(%rdi)
+ movq %r13,40(%rdi)
+ movq %r14,48(%rdi)
+ movq %r15,56(%rdi)
+ movq %rbp, %rax
+
+ popq %rbp
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ ret
diff --git a/src/low/x64-asm-8l/relic_fp_add_low.s b/src/low/x64-asm-8l/relic_fp_add_low.s
index ded7cb8e3..b34dc0429 100644
--- a/src/low/x64-asm-8l/relic_fp_add_low.s
+++ b/src/low/x64-asm-8l/relic_fp_add_low.s
@@ -378,6 +378,17 @@ fp_subc_low:
ret
fp_negm_low:
+ push %rbx
+ push %rbp
+
+ xorq %r9, %r9
+ xorq %r10, %r10
+ xorq %r11, %r11
+ xorq %rbx, %rbx
+ xorq %rbp, %rbp
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
movq 0(%rsi) , %r8
or 8(%rsi) , %r8
or 16(%rsi), %r8
@@ -388,30 +399,33 @@ fp_negm_low:
or 56(%rsi), %r8
test %r8, %r8
cmovnz p0(%rip), %r8
+ cmovnz p1(%rip), %r9
+ cmovnz p2(%rip), %r10
+ cmovnz p3(%rip), %r11
+ cmovnz p4(%rip), %rbx
+ cmovnz p5(%rip), %rbp
+ cmovnz p6(%rip), %rax
+ cmovnz p7(%rip), %rcx
subq 0(%rsi) , %r8
movq %r8 , 0(%rdi)
- cmovnz p1(%rip), %r8
- sbbq 8(%rsi) , %r8
- movq %r8 , 8(%rdi)
- cmovnz p2(%rip), %r8
- sbbq 16(%rsi), %r8
- movq %r8 , 16(%rdi)
- cmovnz p3(%rip), %r8
- sbbq 24(%rsi), %r8
- movq %r8 , 24(%rdi)
- cmovnz p4(%rip), %r8
- sbbq 32(%rsi), %r8
- movq %r8 , 32(%rdi)
- cmovnz p5(%rip), %r8
- sbbq 40(%rsi), %r8
- movq %r8 , 40(%rdi)
- cmovnz p6(%rip), %r8
- sbbq 48(%rsi), %r8
- movq %r8 , 48(%rdi)
- cmovnz p7(%rip), %r8
- sbbq 56(%rsi), %r8
- movq %r8 , 56(%rdi)
- ret
+ sbbq 8(%rsi) , %r9
+ movq %r9 , 8(%rdi)
+ sbbq 16(%rsi), %r10
+ movq %r10 , 16(%rdi)
+ sbbq 24(%rsi), %r11
+ movq %r11 , 24(%rdi)
+ sbbq 32(%rsi), %rbx
+ movq %rbx , 32(%rdi)
+ sbbq 40(%rsi), %rbp
+ movq %rbp , 40(%rdi)
+ sbbq 48(%rsi), %rax
+ movq %rax , 48(%rdi)
+ sbbq 56(%rsi), %rcx
+ movq %rcx , 56(%rdi)
+
+ pop %rbp
+ pop %rbx
+ ret
fp_dbln_low:
movq 0(%rsi), %r8
diff --git a/src/low/x64-asm-8l/relic_fp_inv_low.s b/src/low/x64-asm-8l/relic_fp_inv_low.s
deleted file mode 100644
index 2be825dfd..000000000
--- a/src/low/x64-asm-8l/relic_fp_inv_low.s
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * RELIC is an Efficient LIbrary for Cryptography
- * Copyright (c) 2019 RELIC Authors
- *
- * This file is part of RELIC. RELIC is legal property of its developers,
- * whose names are not listed here. Please refer to the COPYRIGHT file
- * for contact information.
- *
- * RELIC is free software; you can redistribute it and/or modify it under the
- * terms of the version 2.1 (or later) of the GNU Lesser General Public License
- * as published by the Free Software Foundation; or version 2.0 of the Apache
- * License as published by the Apache Software Foundation. See the LICENSE files
- * for more details.
- *
- * RELIC 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 LICENSE files for more details.
- *
- * You should have received a copy of the GNU Lesser General Public or the
- * Apache License along with RELIC. If not, see
- * or .
- */
-
-/**
- * @file
- *
- * Implementation of the low-level in&version functions.
- *
- * @ingroup fp
- */
-
-#include "macro.s"
-
-
-/*============================================================================*/
-/* Public definitions */
-/*============================================================================*/
-
-/* No carry */
-.macro _DBL R, i
- movq \i+0(\R), %rdx
- addq %rdx, \i+0(\R)
- movq \i+8(\R), %rdx
- adcq %rdx, \i+8(\R)
- movq \i+16(\R), %rdx
- adcq %rdx, \i+16(\R)
- movq \i+24(\R), %rdx
- adcq %rdx, \i+24(\R)
- movq \i+32(\R), %rdx
- adcq %rdx, \i+32(\R)
- movq \i+40(\R), %rdx
- adcq %rdx, \i+40(\R)
- movq \i+48(\R), %rdx
- adcq %rdx, \i+48(\R)
- movq \i+56(\R), %rdx
- adcq %rdx, \i+56(\R)
-.endm
-
-.global fp_invn_asm
-
-/**
- * rdi = x1, rsi = a
- */
-fp_invn_asm:
- push %r12
- push %r13
- push %r14
- push %r15
- push %rbp
- push %rbx
- subq $256, %rsp
-
- /* v = p. */
- movq $P0, %r8
- movq $P1, %r9
- movq $P2, %r10
- movq $P3, %r11
- movq $P4, %r12
- movq $P5, %r13
- movq $P6, %r14
- movq $P7, %r15
-
- /* rsp[0..7] = u = a. */
- movq 0(%rsi),%rax
- movq %rax,0(%rsp)
- movq 8(%rsi),%rax
- movq %rax,8(%rsp)
- movq 16(%rsi),%rax
- movq %rax,16(%rsp)
- movq 24(%rsi),%rax
- movq %rax,24(%rsp)
- movq 32(%rsi),%rax
- movq %rax,32(%rsp)
- movq 40(%rsi),%rax
- movq %rax,40(%rsp)
- movq 48(%rsi),%rax
- movq %rax,48(%rsp)
- movq 56(%rsi),%rax
- movq %rax,56(%rsp)
- xorq %rax, %rax
-
- /* rsp[7..15] = x1 = 1. */
- movq $1,64(%rsp)
- movq $0,72(%rsp)
- movq $0,80(%rsp)
- movq $0,88(%rsp)
- movq $0,96(%rsp)
- movq $0,104(%rsp)
- movq $0,112(%rsp)
- movq $0,120(%rsp)
-
- /* rsp[16..23] = x2 = 0. */
- movq $0,128(%rsp)
- movq $0,136(%rsp)
- movq $0,144(%rsp)
- movq $0,152(%rsp)
- movq $0,160(%rsp)
- movq $0,168(%rsp)
- movq $0,176(%rsp)
- movq $0,184(%rsp)
-
-loop:
- movq %r8,%rdx
- orq %r9,%rdx
- orq %r10,%rdx
- orq %r11,%rdx
- orq %r12,%rdx
- orq %r13,%rdx
- orq %r14,%rdx
- orq %r15,%rdx
- jz end
-
- inc %rax
- test $1, %r8
- jnz v_odd
-
- /* fp_rsh1_low(v). */
- shrd $1, %r9, %r8
- shrd $1, %r10, %r9
- shrd $1, %r11, %r10
- shrd $1, %r12, %r11
- shrd $1, %r13, %r12
- shrd $1, %r14, %r13
- shrd $1, %r15, %r14
- shr $1, %r15
-
- /* fp_dbln_low(x1). */
- _DBL %rsp, 64
- jmp loop
-v_odd:
- movq 0(%rsp),%rdx
- test $1, %rdx
- jnz u_odd
-
- /* fp_rsh1_low(u). */
- movq 8(%rsp), %rdx
- shrd $1, %rdx, 0(%rsp)
- movq 16(%rsp), %rdx
- shrd $1, %rdx, 8(%rsp)
- movq 24(%rsp), %rdx
- shrd $1, %rdx, 16(%rsp)
- movq 32(%rsp), %rdx
- shrd $1, %rdx, 24(%rsp)
- movq 40(%rsp), %rdx
- shrd $1, %rdx, 32(%rsp)
- movq 48(%rsp), %rdx
- shrd $1, %rdx, 40(%rsp)
- movq 56(%rsp), %rdx
- shrd $1, %rdx, 48(%rsp)
- shr $1, %rdx
- movq %rdx, 56(%rsp)
-
- /* fp_dbln_low(x2). */
- _DBL %rsp, 128
- jmp loop
-u_odd:
- subq 0(%rsp), %r8
- sbbq 8(%rsp), %r9
- sbbq 16(%rsp), %r10
- sbbq 24(%rsp), %r11
- sbbq 32(%rsp), %r12
- sbbq 40(%rsp), %r13
- sbbq 48(%rsp), %r14
- sbbq 56(%rsp), %r15
- jc cmp_lt
-
- /* fp_rsh1_low(v). */
- shrd $1, %r9, %r8
- shrd $1, %r10, %r9
- shrd $1, %r11, %r10
- shrd $1, %r12, %r11
- shrd $1, %r13, %r12
- shrd $1, %r14, %r13
- shrd $1, %r15, %r14
- shr $1, %r15
-
- movq 64(%rsp), %rdx
- addq %rdx, 128(%rsp)
- movq 72(%rsp), %rdx
- adcq %rdx, 136(%rsp)
- movq 80(%rsp), %rdx
- adcq %rdx, 144(%rsp)
- movq 88(%rsp), %rdx
- adcq %rdx, 152(%rsp)
- movq 96(%rsp), %rdx
- adcq %rdx, 160(%rsp)
- movq 104(%rsp), %rdx
- adcq %rdx, 168(%rsp)
- movq 112(%rsp), %rdx
- adcq %rdx, 176(%rsp)
- movq 120(%rsp), %rdx
- adcq %rdx, 184(%rsp)
-
- _DBL %rsp, 64
- jmp loop
-cmp_lt:
- addq 0(%rsp), %r8
- adcq 8(%rsp), %r9
- adcq 16(%rsp), %r10
- adcq 24(%rsp), %r11
- adcq 32(%rsp), %r12
- adcq 40(%rsp), %r13
- adcq 48(%rsp), %r14
- adcq 56(%rsp), %r15
-
- subq %r8, 0(%rsp)
- sbbq %r9, 8(%rsp)
- sbbq %r10, 16(%rsp)
- sbbq %r11, 24(%rsp)
- sbbq %r12, 32(%rsp)
- sbbq %r13, 40(%rsp)
- sbbq %r14, 48(%rsp)
- sbbq %r15, 56(%rsp)
-
- movq 8(%rsp), %rdx
- shrd $1, %rdx, 0(%rsp)
- movq 16(%rsp), %rdx
- shrd $1, %rdx, 8(%rsp)
- movq 24(%rsp), %rdx
- shrd $1, %rdx, 16(%rsp)
- movq 32(%rsp), %rdx
- shrd $1, %rdx, 24(%rsp)
- movq 40(%rsp), %rdx
- shrd $1, %rdx, 32(%rsp)
- movq 48(%rsp), %rdx
- shrd $1, %rdx, 40(%rsp)
- movq 56(%rsp), %rdx
- shrd $1, %rdx, 48(%rsp)
- shr $1, %rdx
- movq %rdx, 56(%rsp)
-
- movq 128(%rsp), %rdx
- addq %rdx, 64(%rsp)
- movq 136(%rsp), %rdx
- adcq %rdx, 72(%rsp)
- movq 144(%rsp), %rdx
- adcq %rdx, 80(%rsp)
- movq 152(%rsp), %rdx
- adcq %rdx, 88(%rsp)
- movq 160(%rsp), %rdx
- adcq %rdx, 96(%rsp)
- movq 168(%rsp), %rdx
- adcq %rdx, 104(%rsp)
- movq 176(%rsp), %rdx
- adcq %rdx, 112(%rsp)
- movq 184(%rsp), %rdx
- adcq %rdx, 120(%rsp)
-
- _DBL %rsp, 128
- jmp loop
-end:
- movq 64(%rsp), %r9
- movq %r9, 0(%rdi)
- movq 72(%rsp), %r9
- movq %r9, 8(%rdi)
- movq 80(%rsp), %r9
- movq %r9, 16(%rdi)
- movq 88(%rsp), %r9
- movq %r9, 24(%rdi)
- movq 96(%rsp), %r9
- movq %r9, 32(%rdi)
- movq 104(%rsp), %r9
- movq %r9, 40(%rdi)
- movq 112(%rsp), %r9
- movq %r9, 48(%rdi)
- movq 120(%rsp), %r9
- movq %r9, 56(%rdi)
-exit:
- addq $256, %rsp
- pop %rbx
- pop %rbp
- pop %r15
- pop %r14
- pop %r13
- pop %r12
- ret
diff --git a/src/low/x64-asm-9l/relic_fp_add_low.s b/src/low/x64-asm-9l/relic_fp_add_low.s
index 8dc4734b8..609e39cc0 100644
--- a/src/low/x64-asm-9l/relic_fp_add_low.s
+++ b/src/low/x64-asm-9l/relic_fp_add_low.s
@@ -424,6 +424,19 @@ cdecl(fp_subc_low):
ret
cdecl(fp_negm_low):
+ push %rbx
+ push %rbp
+ push %r12
+
+ xorq %r9, %r9
+ xorq %r10, %r10
+ xorq %r11, %r11
+ xorq %r12, %r12
+ xorq %rbx, %rbx
+ xorq %rbp, %rbp
+ xorq %rax, %rax
+ xorq %rcx, %rcx
+
movq 0(%rsi) , %r8
or 8(%rsi) , %r8
or 16(%rsi), %r8
@@ -434,34 +447,39 @@ cdecl(fp_negm_low):
or 56(%rsi), %r8
or 64(%rsi), %r8
test %r8, %r8
- cmovnz p0(%rip), %r8
- subq 0(%rsi) , %r8
- movq %r8 , 0(%rdi)
- cmovnz p1(%rip), %r8
- sbbq 8(%rsi) , %r8
- movq %r8 , 8(%rdi)
- cmovnz p2(%rip), %r8
- sbbq 16(%rsi), %r8
- movq %r8 , 16(%rdi)
- cmovnz p3(%rip), %r8
- sbbq 24(%rsi), %r8
- movq %r8 , 24(%rdi)
- cmovnz p4(%rip), %r8
- sbbq 32(%rsi), %r8
- movq %r8 , 32(%rdi)
- cmovnz p5(%rip), %r8
- sbbq 40(%rsi), %r8
- movq %r8 , 40(%rdi)
- cmovnz p6(%rip), %r8
- sbbq 48(%rsi), %r8
- movq %r8 , 48(%rdi)
- cmovnz p7(%rip), %r8
- sbbq 56(%rsi), %r8
- movq %r8 , 56(%rdi)
- cmovnz p8(%rip), %r8
- sbbq 64(%rsi), %r8
- movq %r8 , 64(%rdi)
- ret
+ cmovnz p0(%rip), %r8
+ cmovnz p1(%rip), %r9
+ cmovnz p2(%rip), %r10
+ cmovnz p3(%rip), %r11
+ cmovnz p4(%rip), %rbx
+ cmovnz p5(%rip), %rbp
+ cmovnz p6(%rip), %r12
+ cmovnz p7(%rip), %rax
+ cmovnz p8(%rip), %rcx
+ subq 0(%rsi) , %r8
+ movq %r8 , 0(%rdi)
+ sbbq 8(%rsi) , %r9
+ movq %r9 , 8(%rdi)
+ sbbq 16(%rsi), %r10
+ movq %r10 , 16(%rdi)
+ sbbq 24(%rsi), %r11
+ movq %r11 , 24(%rdi)
+ sbbq 32(%rsi), %rbx
+ movq %rbx , 32(%rdi)
+ sbbq 40(%rsi), %rbp
+ movq %rbp , 40(%rdi)
+ sbbq 48(%rsi), %r12
+ movq %r12 , 48(%rdi)
+ sbbq 56(%rsi), %rax
+ movq %rax , 56(%rdi)
+ sbbq 64(%rsi), %rcx
+ movq %rcx , 64(%rdi)
+
+ pop %r12
+ pop %rbp
+ pop %rbx
+ ret
+
cdecl(fp_dbln_low):
movq 0(%rsi), %r8
diff --git a/src/pc/relic_pc_exp.c b/src/pc/relic_pc_exp.c
index a7c6d8ce7..85b8ebde4 100644
--- a/src/pc/relic_pc_exp.c
+++ b/src/pc/relic_pc_exp.c
@@ -160,7 +160,11 @@ void gt_exp(gt_t c, const gt_t a, const bn_t b) {
pc_get_ord(n);
bn_mod(_b, b, n);
+#if FP_PRIME <= 1536
RLC_CAT(RLC_GT_LOWER, exp_cyc)(c, a, _b);
+#else
+ RLC_CAT(RLC_GT_LOWER, exp)(c, a, _b);
+#endif
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
@@ -202,27 +206,36 @@ void gt_exp_dig(gt_t c, const gt_t a, dig_t b) {
void gt_exp_sim(gt_t e, const gt_t a, const bn_t b, const gt_t c, const bn_t d) {
bn_t n, _b, _d;
+ gt_t t;
bn_null(n);
bn_null(_b);
bn_null(_d);
+ gt_null(t);
RLC_TRY {
bn_new(n);
bn_new(_b);
bn_new(_d);
+ gt_new(t);
gt_get_ord(n);
bn_mod(_b, b, n);
bn_mod(_d, d, n);
-
+#if FP_PRIME <= 1536
RLC_CAT(RLC_GT_LOWER, exp_cyc_sim)(e, a, _b, c, _d);
+#else
+ gt_exp(t, a, _b);
+ gt_exp(e, c, _d);
+ gt_mul(e, e, t);
+#endif
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
bn_free(n);
bn_free(_b);
bn_free(_d);
+ gt_free(t);
}
}
diff --git a/src/pc/relic_pc_util.c b/src/pc/relic_pc_util.c
index e756fdfc3..fddd35d44 100644
--- a/src/pc/relic_pc_util.c
+++ b/src/pc/relic_pc_util.c
@@ -50,15 +50,23 @@
void gt_rand(gt_t a) {
gt_rand_imp(a);
#if FP_PRIME < 1536
-#if FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
+#if FP_PRIME == 575
+ pp_exp_k48(a, a);
+#elif FP_PRIME == 315 || FP_PRIME == 317 || FP_PRIME == 509
pp_exp_k24(a, a);
-#elif FP_PRIME == 638 && !defined(FP_QNRES)
+#elif FP_PRIME == 330 || FP_PRIME == 765 || FP_PRIME == 766
+ pp_exp_k16(a, a);
+#elif FP_PRIME == 508 || FP_PRIME == 638 && !defined(FP_QNRES)
pp_exp_k18(a, a);
#else
pp_exp_k12(a, a);
#endif
#else
+#if FP_PRIME == 1536
pp_exp_k2(a, a);
+#else
+ pp_exp_k1(a, a);
+#endif
#endif
}
@@ -68,7 +76,7 @@ void gt_get_gen(gt_t g) {
int g1_is_valid(const g1_t a) {
bn_t n, t;
- g1_t u, v;
+ g1_t u, v, w;
size_t l0, l1, r = 0;
int8_t naf0[RLC_FP_BITS + 1], naf1[RLC_FP_BITS + 1];
@@ -80,12 +88,14 @@ int g1_is_valid(const g1_t a) {
bn_null(t);
g1_null(u);
g1_null(v);
+ g1_null(w);
RLC_TRY {
bn_new(n);
bn_new(t);
g1_new(u);
g1_new(v);
+ g1_new(w);
ep_curve_get_cof(n);
if (bn_cmp_dig(n, 1) == RLC_EQ) {
@@ -99,10 +109,17 @@ int g1_is_valid(const g1_t a) {
* Piellard. https://eprint.iacr.org/2022/352.pdf */
case EP_B12:
case EP_B24:
+ case EP_B48:
/* Check [\psi(P) == [z^2 - 1]P. */
fp_prime_get_par(n);
bn_sqr(n, n);
if (ep_curve_is_pairf() == EP_B24) {
+ /* Check [\psi(P) == [z^4 - 1]P. */
+ bn_sqr(n, n);
+ }
+ if (ep_curve_is_pairf() == EP_B48) {
+ /* Check [\psi(P) == [z^8 - 1]P. */
+ bn_sqr(n, n);
bn_sqr(n, n);
}
bn_sub_dig(n, n, 1);
@@ -110,6 +127,52 @@ int g1_is_valid(const g1_t a) {
ep_psi(v, a);
r = g1_on_curve(a) && (g1_cmp(v, u) == RLC_EQ);
break;
+ /* if (u % 2) == 0, check (u**4)*\psi(P) == P
+ * else check (u**4-1)//2 * (\psi(P) - P) == P */
+ case EP_N16:
+ fp_prime_get_par(n);
+ bn_sqr(n, n);
+ bn_sqr(n, n);
+ ep_psi(u, a);
+ if (!bn_is_even(n)) {
+ bn_sub_dig(n, n, 1);
+ bn_hlv(n, n);
+ g1_sub(u, u, a);
+ g1_norm(u, u);
+ }
+ g1_mul_any(u, u, n);
+ r = g1_on_curve(a) && (g1_cmp(u, a) == RLC_EQ);
+ break;
+ /* Formulas from "Fast Subgroup Membership Testings on Pairing-
+ * friendly Curves" by Yu Dai, Kaizhan Lin, Chang-An Zhao,
+ * Zijian Zhou. https://eprint.iacr.org/2022/348.pdf */
+ case EP_K16:
+ /* If u = 25 or 45 mod 70 then a1 = ((u//5)**4 + 5)//14
+ * is an integer by definition. */
+ fp_prime_get_par(n);
+ bn_div_dig(n, n, 5);
+ bn_sqr(n, n);
+ bn_sqr(n, n);
+ bn_add_dig(n, n, 5);
+ bn_div_dig(n, n, 14);
+ bn_mul_dig(n, n, 17);
+ bn_neg(n, n);
+ bn_add_dig(n, n, 6);
+ /* Compute P1 = a1*P. */
+ g1_mul_any(w, a, n);
+ /* Compute \psi([17]P1) - [31]P1 */
+ g1_dbl(u, w);
+ g1_dbl(u, u);
+ g1_dbl(u, u);
+ g1_dbl(v, u);
+ g1_add(u, v, w);
+ g1_dbl(v, v);
+ g1_sub(v, v, w);
+ ep_psi(u, u);
+ g1_add(u, u, v);
+ g1_neg(u, u);
+ r = g1_on_curve(a) && (g1_cmp(u, a) == RLC_EQ);
+ break;
case EP_K18:
/* Check that [a_0]P + [a_1]\psi(P)) == O, for
* a_0 = 19a_1 + 1, a_1 = (x/7)^3 */
@@ -146,6 +209,22 @@ int g1_is_valid(const g1_t a) {
}
r = g1_on_curve(a) && g1_is_infty(u);
break;
+ case EP_SG18:
+ /* Check that [9u^3+2]\psi(P) == -P. */
+ fp_prime_get_par(n);
+ /* Apply \psi twice to get the other beta. */
+ ep_psi(u, a);
+ ep_psi(u, u);
+ g1_mul_any(v, u, n);
+ g1_mul_any(v, v, n);
+ g1_mul_any(v, v, n);
+ g1_mul_dig(v, v, 9);
+ g1_dbl(u, u);
+ g1_add(v, v, u);
+ g1_norm(v, v);
+ g1_neg(v, v);
+ r = g1_on_curve(a) && (g1_cmp(a, v) == RLC_EQ);
+ break;
#endif
default:
pc_get_ord(n);
@@ -164,34 +243,40 @@ int g1_is_valid(const g1_t a) {
bn_free(t);
g1_free(u);
g1_free(v);
+ g1_free(w);
}
return r;
}
int g2_is_valid(const g2_t a) {
+ g2_t s, t, u, v, w;
+ bn_t n;
+ dig_t rem;
+ int r = 0;
+
#if FP_PRIME >= 1536
- if (pc_map_is_type1()) {
- return g1_is_valid(a);
- }
+ return g1_is_valid(a);
#else
if (g2_is_infty(a)) {
return 0;
}
- bn_t n;
- g2_t u, v;
- int r = 0;
-
bn_null(n);
+ g2_null(s);
+ g2_null(t);
g2_null(u);
g2_null(v);
+ g2_null(w);
RLC_TRY {
bn_new(n);
+ g2_new(s);
+ g2_new(t);
g2_new(u);
g2_new(v);
+ g2_new(w);
switch (ep_curve_is_pairf()) {
#if defined(EP_ENDOM) && !defined(STRIP)
@@ -200,6 +285,7 @@ int g2_is_valid(const g2_t a) {
* Piellard. https://eprint.iacr.org/2022/352.pdf */
case EP_B12:
case EP_B24:
+ case EP_B48:
if (core_get()->ep_id == B12_383) {
/* Since p mod n = r, we can check instead that
* psi^4(P) + P == \psi^2(P). */
@@ -230,18 +316,97 @@ int g2_is_valid(const g2_t a) {
g2_dbl(v, v);
r = g2_on_curve(a) && (g2_cmp(u, v) == RLC_EQ);
break;
- case EP_K18:
- /* Check that [2z/7]P + \psi(P) + [z/7]\psi^3(P) == O. */
+ /* If u is even, check that [u*p^3]P = P
+ * else check [p^5]P = [u]P. */
+ case EP_N16:
fp_prime_get_par(n);
- bn_div_dig(n, n, 7);
g2_mul_any(u, a, n);
- g2_frb(v, u, 2);
- g2_dbl(u, u);
- g2_add(v, v, a);
- g2_frb(v, v, 1);
- g2_neg(v, v);
+ if (bn_is_even(n)) {
+ g2_frb(v, u, 3);
+ g2_copy(u, a);
+ } else {
+ g2_frb(v, a, 5);
+ }
r = g2_on_curve(a) && (g2_cmp(u, v) == RLC_EQ);
break;
+ /* Formulas from "Fast Subgroup Membership Testings for G1,
+ * G2 and GT on Pairing-friendly Curves" by Dai et al.
+ * https://eprint.iacr.org/2022/348.pdf
+ * Paper has u = 45 mod 70, we ran their code for u = 25 mod 70. */
+ case EP_K16:
+ fp_prime_get_par(n);
+ bn_mod_dig(&rem, n, 70);
+ if (rem == 45) {
+ bn_neg(n, n);
+ }
+ /* Compute s = (\pm u - 25)/70. */
+ bn_sub_dig(n, n, 25);
+ bn_div_dig(n, n, 70);
+ /* [11s+4, 9s+3, 3s+1, -(3s+1), -13*u-5, -7*u-3, u, -11s-4] */
+ /* or [11s+4, -9s-3, 3s+1, 3s+1, -13*u-5, 7*u+3, u, 11s+4]. */
+ g2_mul_any(u, a, n); /* u = a^s*/
+ g2_frb(w, u, 6);
+ g2_dbl(s, u);
+ g2_add(v, s, a);
+ g2_add(t, v, u); /* t = a^(3s + 1) */
+ g2_copy(u, v); /* u = a^(2s + 1)*/
+ g2_frb(v, t, 2);
+ g2_add(w, w, v);
+ g2_frb(v, t, 3);
+ if (rem == 45) {
+ g2_add(w, w, v);
+ } else {
+ g2_sub(w, w, v);
+ }
+ g2_dbl(v, t);
+ g2_add(t, t, v); /* t = a^(9s + 3). */
+ g2_frb(v, t, 1);
+ if (rem == 45) {
+ g2_neg(v, v);
+ }
+ g2_add(w, w, v);
+ g2_sub(s, t, s); /* s = a^(7s + 3). */
+ g2_frb(v, s, 5);
+ if (rem == 45) {
+ g2_add(w, w, v);
+ } else {
+ g2_sub(w, w, v);
+ }
+ g2_add(t, t, u); /* t = a^(11s + 4). */
+ g2_add(w, w, t);
+ g2_frb(v, t, 7);
+ if (rem == 45) {
+ g2_add(w, w, v);
+ } else {
+ g2_sub(w, w, v);
+ }
+ g2_add(t, t, u); /* t = a^(13s + 5). */
+ g2_frb(t, t, 4);
+ r = g2_on_curve(a) && (g2_cmp(w, t) == RLC_EQ);
+ break;
+ case EP_K18:
+ /* Check that P + u*psi2P + 2*psi3P == \mathcal{O}. */
+ fp_prime_get_par(n);
+ g2_frb(u, a, 2);
+ g2_frb(v, u, 1);
+ g2_dbl(v, v);
+ g2_mul_any(u, u, n);
+ g2_add(v, v, u);
+ g2_neg(u, v);
+ r = g2_on_curve(a) && (g2_cmp(u, a) == RLC_EQ);
+ break;
+ case EP_SG18:
+ /* Check that 3u*P + 2\psi^2(P) == \psi^5P] and [3]P \eq O. */
+ fp_prime_get_par(n);
+ bn_mul_dig(n, n, 3);
+ g2_mul_any(u, a, n);
+ r = g2_is_infty(a) == 0;
+ g2_frb(v, a, 2);
+ g2_add(u, u, v);
+ g2_add(u, u, v);
+ g2_frb(v, a, 5);
+ r &= g2_on_curve(a) && (g2_cmp(u, v) == RLC_EQ);
+ break;
#endif
default:
pc_get_ord(n);
@@ -256,8 +421,11 @@ int g2_is_valid(const g2_t a) {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
bn_free(n);
+ g2_free(s);
+ g2_free(t);
g2_free(u);
g2_free(v);
+ g2_free(w);
}
return r;
@@ -266,22 +434,29 @@ int g2_is_valid(const g2_t a) {
int gt_is_valid(const gt_t a) {
bn_t n;
- gt_t u, v;
+ gt_t s, t, u, v, w;
int l, r = 0;
const int *b;
+ dig_t rem;
if (gt_is_unity(a)) {
return 0;
}
bn_null(n);
+ gt_null(s);
+ gt_null(t);
gt_null(u);
gt_null(v);
+ gt_null(w);
RLC_TRY {
bn_new(n);
+ gt_new(s);
+ gt_new(t);
gt_new(u);
gt_new(v);
+ gt_new(w);
fp_prime_get_par(n);
b = fp_prime_get_par_sps(&l);
@@ -308,6 +483,13 @@ int gt_is_valid(const gt_t a) {
r = (gt_cmp(u, v) == RLC_EQ);
r &= fp24_test_cyc((void *)a);
break;
+ case EP_B48:
+ /* Check that a^u = a^p. */
+ gt_frb(u, a, 1);
+ fp48_exp_cyc_sps((void *)v, (void *)a, b, l, bn_sign(n));
+ r = (gt_cmp(u, v) == RLC_EQ);
+ r &= fp48_test_cyc((void *)a);
+ break;
/* Formulas from "Fast Subgroup Membership Testings for G1,
* G2 and GT on Pairing-friendly Curves" by Dai et al.
* https://eprint.iacr.org/2022/348.pdf */
@@ -324,21 +506,93 @@ int gt_is_valid(const gt_t a) {
r = (gt_cmp(u, v) == RLC_EQ);
r &= fp12_test_cyc((void *)a);
break;
+ /* If u is even, check that [u*p^3]P = P
+ * else check [p^5]P = [u]P. */
+ case EP_N16:
+ fp_prime_get_par(n);
+ gt_exp(u, a, n);
+ if (bn_is_even(n)) {
+ gt_frb(v, u, 3);
+ gt_copy(u, a);
+ } else {
+ gt_frb(v, a, 5);
+ }
+ r = (gt_cmp(u, v) == RLC_EQ);
+ r &= fp16_test_cyc((void *)a);
+ break;
+ case EP_K16:
+ fp_prime_get_par(n);
+ bn_mod_dig(&rem, n, 70);
+ if (rem == 45) {
+ bn_neg(n, n);
+ }
+ /* Compute s = (u - 25)/70. */
+ bn_sub_dig(n, n, 25);
+ bn_div_dig(n, n, 70);
+ /* Vectors for u = 25 or 45 mod 70 below, respectively: */
+ /* [11s+4, 9s+3, 3s+1, -(3s+1), -13*u-5, -7*u-3, u, -11s-4] */
+ /* or [11s+4, -9s-3, 3s+1, 3s+1, -13*u-5, 7*u+3, u, 11s+4]. */
+ gt_exp(u, a, n); /* u = a^s*/
+ gt_frb(w, u, 6);
+ gt_sqr(s, u);
+ gt_mul(v, s, a);
+ gt_mul(t, v, u); /* t = a^(3s + 1) */
+ gt_copy(u, v); /* u = a^(2s + 1)*/
+ gt_frb(v, t, 2);
+ gt_mul(w, w, v);
+ gt_frb(v, t, 3);
+ if (rem != 45) {
+ gt_inv(v, v);
+ }
+ gt_mul(w, w, v);
+ gt_sqr(v, t);
+ gt_mul(t, t, v); /* t = a^(9s + 3). */
+ gt_frb(v, t, 1);
+ if (rem == 45) {
+ gt_inv(v, v);
+ }
+ gt_mul(w, w, v);
+ gt_inv(s, s);
+ gt_mul(s, t, s); /* s = a^(7s + 3). */
+ gt_frb(v, s, 5);
+ if (rem != 45) {
+ gt_inv(v, v);
+ }
+ gt_mul(w, w, v);
+ gt_mul(t, t, u); /* t = a^(11s + 4). */
+ gt_mul(w, w, t);
+ gt_frb(v, t, 7);
+ if (rem != 45) {
+ gt_inv(v, v);
+ }
+ gt_mul(w, w, v);
+ gt_mul(t, t, u); /* t = a^(13s + 5). */
+ gt_frb(t, t, 4);
+ r = (gt_cmp(w, t) == RLC_EQ);
+ r &= fp16_test_cyc((void *)a);
+ break;
case EP_K18:
- /* Check that [2z]P + [z]\psi^3(P) == -7\psi(P). */
- fp18_exp_cyc_sps((void *)u, (void *)a, b, l, bn_sign(n));
- gt_frb(v, u, 3);
- gt_sqr(u, u);
- gt_mul(u, u, v);
- gt_sqr(v, a);
- gt_mul(v, v, a);
+ /* Check that P + u*psi2P + 2*psi3P == \mathcal{O}. */
+ gt_frb(u, a, 2);
+ gt_frb(v, u, 1);
gt_sqr(v, v);
- gt_mul(v, v, a);
- gt_frb(v, v, 1);
- gt_inv(v, v);
- r = (gt_cmp(u, v) == RLC_EQ);
+ fp18_exp_cyc_sps((void *)u, (void *)u, b, l, bn_sign(n));
+ gt_mul(v, v, u);
+ gt_inv(u, v);
+ r = (gt_cmp(u, a) == RLC_EQ);
r &= fp18_test_cyc((void *)a);
break;
+ case EP_SG18:
+ /* Check that 3u*P + 2\psi^2(P) == \psi^5P] and [3]P \eq O. */
+ fp_prime_get_par(n);
+ bn_mul_dig(n, n, 3);
+ gt_exp(u, a, n);
+ r = gt_is_unity(a) == 0;
+ gt_frb(v, a, 2);
+ gt_mul(u, u, v);
+ gt_mul(u, u, v);
+ gt_frb(v, a, 5);
+ r &= fp18_test_cyc((void *)a);
default:
/* Common case. */
pc_get_ord(n);
@@ -352,8 +606,11 @@ int gt_is_valid(const gt_t a) {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
bn_free(n);
+ gt_free(s);
+ gt_free(t);
gt_free(u);
gt_free(v);
+ gt_free(w);
}
return r;
diff --git a/src/pp/relic_pp_add_k1.c b/src/pp/relic_pp_add_k1.c
new file mode 100644
index 000000000..9d46c155e
--- /dev/null
+++ b/src/pp/relic_pp_add_k1.c
@@ -0,0 +1,174 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of Miller addition for curves of embedding degree 1.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_fp_low.h"
+#include "relic_fpx_low.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+void pp_add_k1_basic(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q) {
+ fp_t s;
+
+ fp_null(s);
+
+ RLC_TRY {
+ fp_new(s);
+
+ if (fp_cmp(r->x, p->x) == RLC_EQ) {
+ fp_set_dig(m, 1);
+ fp_sub(l, q->x, p->x);
+ } else {
+ fp_sub(l, q->x, p->x);
+ ep_add_slp_basic(r, s, r, p);
+ fp_mul(l, l, s);
+ fp_sub(l, q->y, l);
+ fp_sub(l, l, p->y);
+ if (fp_is_zero(l)) {
+ fp_set_dig(l, 1);
+ }
+ fp_sub(m, q->x, r->x);
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp_free(s);
+ }
+}
+
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+
+void pp_add_k1_projc(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q) {
+ fp_t t0, t1, t2, t3, t4, t5;
+
+ fp_null(t0);
+ fp_null(t1);
+ fp_null(t2);
+ fp_null(t3);
+ fp_null(t4);
+ fp_null(t5);
+
+ RLC_TRY {
+ fp_new(t0);
+ fp_new(t1);
+ fp_new(t2);
+ fp_new(t3);
+ fp_new(t4);
+ fp_new(t5);
+
+ fp_sqr(l, r->z);
+ fp_mul(l, l, p->x);
+ if (fp_cmp(l, r->x) == RLC_EQ) {
+ fp_set_dig(m, 1);
+ fp_sub(l, q->x, p->x);
+ } else {
+ /* t0 = z1^2. */
+ fp_sqr(t0, r->z);
+
+ /* t3 = U = x2 * z1^2. */
+ fp_mul(t3, p->x, t0);
+
+ /* t1 = S = y2 * z1^3. */
+ fp_mul(t1, t0, r->z);
+ fp_mul(t1, t1, p->y);
+
+ /* t2 = H = U - x1. */
+ fp_sub(t2, t3, r->x);
+
+ /* t4 = L = S - y1. */
+ fp_sub(t4, t1, r->y);
+
+ /* t5 = H_2 = 2H, t3 = I = 4H^2. */
+ fp_dbl(t5, t2);
+ fp_sqr(t3, t5);
+
+ /* Z3 = (Z1 + H)^2 - Z1^2 - H^2 = 2 * z1 * H. */
+ fp_mul(r->z, r->z, t5);
+
+ /* t4 = M = 2L, t5 = M3 = (L + Z3)^2 - L^2 - Z3^2 = 2 * L * Z3. */
+ fp_dbl(t4, t4);
+ fp_mul(t5, t4, r->z);
+
+ /* l = Z3^2 * (yQ - y2) - M3*(xQ - x2). */
+ fp_sqr(m, r->z);
+ fp_sub(l, q->y, p->y);
+ fp_mul(l, l, m);
+ fp_sub(t0, q->x, p->x);
+ fp_mul(t0, t0, t5);
+ fp_sub(l, l, t0);
+ if (fp_is_zero(l)) {
+ fp_set_dig(l, 1);
+ }
+
+ /* t0 = V = x1 * I, t3 = J = HI, x3 = 4L^2 - J - 2V*/
+ fp_mul(t0, r->x, t3);
+ fp_mul(t3, t3, t2);
+ fp_sqr(r->x, t4);
+ fp_sub(r->x, r->x, t3);
+ fp_sub(r->x, r->x, t0);
+ fp_sub(r->x, r->x, t0);
+
+ /* y3 = M * (V - X3) - 2y1 * J. */
+ fp_mul(r->y, r->y, t3);
+ fp_dbl(r->y, r->y);
+ fp_sub(t0, t0, r->x);
+ fp_mul(t0, t4, t0);
+ fp_sub(r->y, t0, r->y);
+
+ /* v = Z3^2 * xQ - X3. */
+ fp_mul(m, m, q->x);
+ fp_sub(m, m, r->x);
+
+ r->coord = JACOB;
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp_free(t0);
+ fp_free(t1);
+ fp_free(t2);
+ fp_free(t3);
+ fp_free(t4);
+ fp_free(t5);
+ }
+}
+
+#endif
diff --git a/src/pp/relic_pp_add_k16.c b/src/pp/relic_pp_add_k16.c
new file mode 100644
index 000000000..8c72c67f6
--- /dev/null
+++ b/src/pp/relic_pp_add_k16.c
@@ -0,0 +1,346 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of Miller addition for curves of embedding degree 16.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_fp_low.h"
+#include "relic_fpx_low.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+void pp_add_k16_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p) {
+ int one = 1, zero = 0;
+ fp4_t s;
+ ep4_t t;
+
+ fp4_null(s);
+ ep4_null(t);
+
+ RLC_TRY {
+ fp4_new(s);
+ ep4_new(t);
+
+ ep4_copy(t, r);
+ ep4_add_slp_basic(r, s, r, q);
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ fp_mul(l[one][zero][0][0], s[0][0], p->x);
+ fp_mul(l[one][zero][0][1], s[0][1], p->x);
+ fp_mul(l[one][zero][1][0], s[1][0], p->x);
+ fp_mul(l[one][zero][1][1], s[1][1], p->x);
+ fp4_mul(l[one][one], s, t->x);
+ fp4_sub(l[one][one], t->y, l[one][one]);
+ fp_copy(l[zero][zero][0][0], p->y);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp4_free(s);
+ ep4_free(t);
+ }
+}
+
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+
+#if PP_EXT == BASIC || !defined(STRIP)
+
+void pp_add_k16_projc_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p) {
+ fp4_t t0, t1, t2, t3, t4, t5;
+ int one = 1, zero = 0;
+
+ fp4_null(t0);
+ fp4_null(t1);
+ fp4_null(t2);
+ fp4_null(t3);
+ fp4_null(t4);
+
+ RLC_TRY {
+ fp4_new(t0);
+ fp4_new(t1);
+ fp4_new(t2);
+ fp4_new(t3);
+ fp4_new(t4);
+ fp4_new(t5);
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ /* t0 = A = Z1^2, t1 = B = X2*Z1. */
+ fp4_sqr(t0, r->z);
+ fp4_mul(t1, r->z, q->x);
+
+ /* t0 = C = y2*A, t2 = D = (x1 - B) */
+ fp4_mul(t0, t0, q->y);
+ fp4_sub(t2, r->x, t1);
+
+ /* t3 = E = 2*(y1 - C), t4 = F = 2*D*z1, t2 = G = 4*D*F. */
+ fp4_sub(t3, r->y, t0);
+ fp4_dbl(t3, t3);
+ fp4_dbl(t2, t2);
+ fp4_mul(t4, t2, r->z);
+ fp4_mul(t2, t2, t4);
+ fp4_dbl(t2, t2);
+
+ /* l = E*X2 - F*Y2 - E*xQ + F*yQ. */
+ fp4_mul(l[one][one], t3, q->x);
+ fp4_mul(t0, t4, q->y);
+ fp4_sub(l[one][one], l[one][one], t0);
+ fp_mul(l[one][zero][0][0], t3[0][0], p->x);
+ fp_mul(l[one][zero][0][1], t3[0][1], p->x);
+ fp_mul(l[one][zero][1][0], t3[1][0], p->x);
+ fp_mul(l[one][zero][1][1], t3[1][1], p->x);
+ fp_mul(l[zero][zero][0][0], t4[0][0], p->y);
+ fp_mul(l[zero][zero][0][1], t4[0][1], p->y);
+ fp_mul(l[zero][zero][1][0], t4[1][0], p->y);
+ fp_mul(l[zero][zero][1][1], t4[1][1], p->y);
+
+ /* z3 = F^2, t4 = (F + E)^2, t3 = E^2. */
+ fp4_sqr(r->z, t4);
+ fp4_add(t4, t4, t3);
+ fp4_sqr(t4, t4);
+ fp4_sqr(t3, t3);
+
+ /* t5 = x3 = 2*E^2 - (x1 + B)*G. */
+ fp4_add(t1, t1, r->x);
+ fp4_mul(t1, t1, t2);
+ fp4_dbl(t5, t3);
+ fp4_sub(t5, t5, t1);
+
+ /* y3 = ((F + E)^2 - E^2 - F^2)*(x1*G - x3) - y1*G^2. */
+ fp4_sub(t4, t4, r->z);
+ fp4_sub(t4, t4, t3);
+ fp4_mul(t1, r->x, t2);
+ fp4_sub(t1, t1, t5);
+ fp4_mul(t4, t4, t1);
+ fp4_sqr(t2, t2);
+ fp4_mul(r->y, r->y, t2);
+ fp4_sub(r->y, t4, r->y);
+
+ /* Z3 = 2*F^2. */
+ fp4_dbl(r->z, r->z);
+ fp4_copy(r->x, t5);
+
+ r->coord = PROJC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp4_free(t0);
+ fp4_free(t1);
+ fp4_free(t2);
+ fp4_free(t3);
+ fp4_free(t4);
+ fp4_free(t5);
+ }
+}
+
+#endif
+
+#if PP_EXT == LAZYR || !defined(STRIP)
+
+void pp_add_k16_projc_lazyr(fp16_t l, ep4_t r, const ep4_t q, const ep_t p) {
+ fp4_t t0, t1, t2, t3, t4, t5;
+ int one = 1, zero = 0;
+
+ fp4_null(t0);
+ fp4_null(t1);
+ fp4_null(t2);
+ fp4_null(t3);
+ fp4_null(t4);
+
+ RLC_TRY {
+ fp4_new(t0);
+ fp4_new(t1);
+ fp4_new(t2);
+ fp4_new(t3);
+ fp4_new(t4);
+ fp4_new(t5);
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ /* t0 = A = Z1^2, t1 = B = X2*Z1. */
+ fp4_sqr(t0, r->z);
+ fp4_mul(t1, r->z, q->x);
+
+ /* t0 = C = y2*A, t2 = D = (x1 - B) */
+ fp4_mul(t0, t0, q->y);
+ fp4_sub(t2, r->x, t1);
+
+ /* t3 = E = 2*(y1 - C), t4 = F = 2*D*z1, t2 = G = 4*D*F. */
+ fp4_sub(t3, r->y, t0);
+ fp4_dbl(t3, t3);
+ fp4_dbl(t2, t2);
+ fp4_mul(t4, t2, r->z);
+ fp4_mul(t2, t2, t4);
+ fp4_dbl(t2, t2);
+
+ /* l = E*X2 - F*Y2 - E*xQ + F*yQ. */
+ fp4_mul(l[one][one], t3, q->x);
+ fp4_mul(t0, t4, q->y);
+ fp4_sub(l[one][one], l[one][one], t0);
+ fp_mul(l[one][zero][0][0], t3[0][0], p->x);
+ fp_mul(l[one][zero][0][1], t3[0][1], p->x);
+ fp_mul(l[one][zero][1][0], t3[1][0], p->x);
+ fp_mul(l[one][zero][1][1], t3[1][1], p->x);
+ fp_mul(l[zero][zero][0][0], t4[0][0], p->y);
+ fp_mul(l[zero][zero][0][1], t4[0][1], p->y);
+ fp_mul(l[zero][zero][1][0], t4[1][0], p->y);
+ fp_mul(l[zero][zero][1][1], t4[1][1], p->y);
+
+ /* z3 = F^2, t4 = (F + E)^2, t3 = E^2. */
+ fp4_sqr(r->z, t4);
+ fp4_add(t4, t4, t3);
+ fp4_sqr(t4, t4);
+ fp4_sqr(t3, t3);
+
+ /* t5 = x3 = 2*E^2 - (x1 + B)*G. */
+ fp4_add(t1, t1, r->x);
+ fp4_mul(t1, t1, t2);
+ fp4_dbl(t5, t3);
+ fp4_sub(t5, t5, t1);
+
+ /* y3 = ((F + E)^2 - E^2 - F^2)*(x1*G - x3) - y1*G^2. */
+ fp4_sub(t4, t4, r->z);
+ fp4_sub(t4, t4, t3);
+ fp4_mul(t1, r->x, t2);
+ fp4_sub(t1, t1, t5);
+ fp4_mul(t4, t4, t1);
+ fp4_sqr(t2, t2);
+ fp4_mul(r->y, r->y, t2);
+ fp4_sub(r->y, t4, r->y);
+
+ /* Z3 = 2*F^2. */
+ fp4_dbl(r->z, r->z);
+ fp4_copy(r->x, t5);
+
+ r->coord = PROJC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp4_free(t0);
+ fp4_free(t1);
+ fp4_free(t2);
+ fp4_free(t3);
+ fp4_free(t4);
+ fp4_free(t5);
+ }
+}
+
+#endif
+
+#endif
+
+void pp_add_lit_k16(fp16_t l, ep_t r, const ep_t p, const ep4_t q) {
+ fp_t t0, t1, t2, t3;
+ int one = 1, zero = 0;
+
+ fp_null(t0);
+ fp_null(t1);
+ fp_null(t2);
+ fp_null(t3);
+
+ RLC_TRY {
+ fp_new(t0);
+ fp_new(t1);
+ fp_new(t2);
+ fp_new(t3);
+
+ fp_mul(t0, r->z, p->x);
+ fp_sub(t0, r->x, t0);
+ fp_mul(t1, r->z, p->y);
+ fp_sub(t1, r->y, t1);
+ fp_mul(t2, p->x, t1);
+ r->coord = PROJC;
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ fp_mul(l[zero][zero][0][0], t0, p->y);
+ fp_sub(l[zero][zero][0][0], t2, l[zero][zero][0][0]);
+
+ fp_mul(l[zero][one][0][0], q->x[0][0], t1);
+ fp_mul(l[zero][one][0][1], q->x[0][1], t1);
+ fp_mul(l[zero][one][1][0], q->x[1][0], t1);
+ fp_mul(l[zero][one][1][1], q->x[1][1], t1);
+ fp4_neg(l[zero][one], l[zero][one]);
+
+ fp_mul(l[one][one][0][0], q->y[0][0], t0);
+ fp_mul(l[one][one][0][1], q->y[0][1], t0);
+ fp_mul(l[one][one][1][0], q->y[1][0], t0);
+ fp_mul(l[one][one][1][1], q->y[1][1], t0);
+
+ fp_sqr(t2, t0);
+ fp_mul(r->x, t2, r->x);
+ fp_mul(t2, t0, t2);
+ fp_sqr(t3, t1);
+ fp_mul(t3, t3, r->z);
+ fp_add(t3, t2, t3);
+ fp_sub(t3, t3, r->x);
+ fp_sub(t3, t3, r->x);
+ fp_sub(r->x, r->x, t3);
+ fp_mul(t1, t1, r->x);
+ fp_mul(r->y, t2, r->y);
+ fp_sub(r->y, t1, r->y);
+ fp_mul(r->x, t0, t3);
+ fp_mul(r->z, r->z, t2);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp_free(t0);
+ fp_free(t1);
+ fp_free(t2);
+ fp_free(t3);
+ }
+}
diff --git a/src/pp/relic_pp_add_k18.c b/src/pp/relic_pp_add_k18.c
index 29b6030c6..f3616793a 100644
--- a/src/pp/relic_pp_add_k18.c
+++ b/src/pp/relic_pp_add_k18.c
@@ -24,7 +24,7 @@
/**
* @file
*
- * Implementation of Miller addition for curves of embedding degree 12.
+ * Implementation of Miller addition for curves of embedding degree 18.
*
* @ingroup pp
*/
diff --git a/src/pp/relic_pp_add_k48.c b/src/pp/relic_pp_add_k48.c
index 3be9b9dfb..a21b2f9ca 100644
--- a/src/pp/relic_pp_add_k48.c
+++ b/src/pp/relic_pp_add_k48.c
@@ -33,93 +33,25 @@
#include "relic_pp.h"
#include "relic_util.h"
-/*============================================================================*/
-/* Private definitions */
-/*============================================================================*/
-
-static void ep8_add_basic(fp8_t s, fp8_t rx, fp8_t ry, const fp8_t qx,
- const fp8_t qy) {
- fp8_t t0, t1, t2;
-
- fp8_null(t0);
- fp8_null(t1);
- fp8_null(t2);
-
- RLC_TRY {
- fp8_new(t0);
- fp8_new(t1);
- fp8_new(t2);
-
- /* t0 = x2 - x1. */
- fp8_sub(t0, qx, rx);
- /* t1 = y2 - y1. */
- fp8_sub(t1, qy, ry);
-
- /* If t0 is zero. */
- if (fp8_is_zero(t0)) {
- if (fp8_is_zero(t1)) {
- /* If t1 is zero, q = p, should have doubled. */
- //ep8_dbl_basic(s, rx, ry);
- RLC_THROW(ERR_NO_VALID);
- } else {
- /* If t1 is not zero and t0 is zero, q = -p and r = infty. */
- fp8_zero(rx);
- fp8_zero(ry);
- }
- } else {
- /* t2 = 1/(x2 - x1). */
- fp8_inv(t2, t0);
- /* t2 = lambda = (y2 - y1)/(x2 - x1). */
- fp8_mul(t2, t1, t2);
-
- /* x3 = lambda^2 - x2 - x1. */
- fp8_sqr(t1, t2);
- fp8_sub(t0, t1, rx);
- fp8_sub(t0, t0, qx);
-
- /* y3 = lambda * (x1 - x3) - y1. */
- fp8_sub(t1, rx, t0);
- fp8_mul(t1, t2, t1);
- fp8_sub(ry, t1, ry);
-
- fp8_copy(rx, t0);
-
- if (s != NULL) {
- fp8_copy(s, t2);
- }
- }
- }
- RLC_CATCH_ANY {
- RLC_THROW(ERR_CAUGHT);
- }
- RLC_FINALLY {
- fp8_free(t0);
- fp8_free(t1);
- fp8_free(t2);
- }
-}
-
/*============================================================================*/
/* Public definitions */
/*============================================================================*/
#if EP_ADD == BASIC || !defined(STRIP)
-void pp_add_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, fp8_t qx, fp8_t qy, const ep_t p) {
- fp8_t s, tx, ty;
+void pp_add_k48_basic(fp48_t l, ep8_t r, const ep8_t q, const ep_t p) {
+ fp8_t s;
+ ep8_t t;
fp8_null(s);
- fp8_null(tx);
- fp8_null(ty);
+ ep8_null(t);
RLC_TRY {
fp8_new(s);
- fp8_new(tx);
- fp8_new(ty);
+ ep8_new(t);
- fp8_copy(tx, rx);
- fp8_copy(ty, ry);
- ep8_add_basic(s, rx, ry, qx, qy);
+ ep8_copy(t, r);
+ ep8_add_slp_basic(r, s, r, q);
fp48_zero(l);
fp_mul(l[0][1][0][0][0], p->x, s[0][0][0]);
@@ -131,8 +63,8 @@ void pp_add_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, fp8_t qx, fp8_t qy, const ep
fp_mul(l[0][1][1][1][0], p->x, s[1][1][0]);
fp_mul(l[0][1][1][1][1], p->x, s[1][1][1]);
- fp8_mul(l[0][0], s, tx);
- fp8_sub(l[0][0], ty, l[0][0]);
+ fp8_mul(l[0][0], s, t->x);
+ fp8_sub(l[0][0], t->y, l[0][0]);
fp_neg(l[1][1][0][0][0], p->y);
}
@@ -141,8 +73,7 @@ void pp_add_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, fp8_t qx, fp8_t qy, const ep
}
RLC_FINALLY {
fp8_free(s);
- fp8_free(tx);
- fp8_free(ty);
+ ep8_free(t);
}
}
@@ -150,8 +81,7 @@ void pp_add_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, fp8_t qx, fp8_t qy, const ep
#if EP_ADD == PROJC || !defined(STRIP)
-void pp_add_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const fp8_t qx,
- const fp8_t qy, const ep_t p) {
+void pp_add_k48_projc(fp48_t l, ep8_t r, const ep8_t q, const ep_t p) {
fp8_t t0, t1, t2, t3, t4;
fp8_null(t0);
@@ -168,22 +98,22 @@ void pp_add_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const fp8_t qx,
fp8_new(t4);
/* B = t0 = x1 - x2 * z1. */
- fp8_mul(t0, rz, qx);
- fp8_sub(t0, rx, t0);
+ fp8_mul(t0, r->z, q->x);
+ fp8_sub(t0, r->x, t0);
/* A = t1 = y1 - y2 * z1. */
- fp8_mul(t1, rz, qy);
- fp8_sub(t1, ry, t1);
+ fp8_mul(t1, r->z, q->y);
+ fp8_sub(t1, r->y, t1);
/* D = B^2. */
fp8_sqr(t2, t0);
/* G = x1 * D. */
- fp8_mul(rx, rx, t2);
+ fp8_mul(r->x, r->x, t2);
/* E = B^3. */
fp8_mul(t2, t2, t0);
/* C = A^2. */
fp8_sqr(t3, t1);
/* F = E + z1 * C. */
- fp8_mul(t3, t3, rz);
+ fp8_mul(t3, t3, r->z);
fp8_add(t3, t2, t3);
/* l10 = - (A * xp). */
@@ -198,23 +128,23 @@ void pp_add_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const fp8_t qx,
fp_mul(l[0][1][1][1][1], t1[1][1][1], t4[0][0][0]);
/* t4 = B * x2. */
- fp8_mul(t4, qx, t1);
+ fp8_mul(t4, q->x, t1);
/* H = E + F - 2 * G. */
- fp8_sub(t3, t3, rx);
- fp8_sub(t3, t3, rx);
+ fp8_sub(t3, t3, r->x);
+ fp8_sub(t3, t3, r->x);
/* y3 = A * (G - H) - y1 * E. */
- fp8_sub(rx, rx, t3);
- fp8_mul(t1, t1, rx);
- fp8_mul(ry, t2, ry);
- fp8_sub(ry, t1, ry);
+ fp8_sub(r->x, r->x, t3);
+ fp8_mul(t1, t1, r->x);
+ fp8_mul(r->y, t2, r->y);
+ fp8_sub(r->y, t1, r->y);
/* x3 = B * H. */
- fp8_mul(rx, t0, t3);
+ fp8_mul(r->x, t0, t3);
/* z3 = z1 * E. */
- fp8_mul(rz, rz, t2);
+ fp8_mul(r->z, r->z, t2);
/* l11 = J = B * x2 - A * y2. */
- fp8_mul(t2, qy, t0);
+ fp8_mul(t2, q->y, t0);
fp8_sub(l[0][0], t4, t2);
/* l00 = B * yp. */
diff --git a/src/pp/relic_pp_add_k8.c b/src/pp/relic_pp_add_k8.c
index 91fea6f36..cb040b0c6 100644
--- a/src/pp/relic_pp_add_k8.c
+++ b/src/pp/relic_pp_add_k8.c
@@ -24,7 +24,7 @@
/**
* @file
*
- * Implementation of Miller addition for curves of embedding degree 2.
+ * Implementation of Miller addition for curves of embedding degree 8.
*
* @ingroup pp
*/
diff --git a/src/pp/relic_pp_dbl_k1.c b/src/pp/relic_pp_dbl_k1.c
new file mode 100644
index 000000000..0c7667e0e
--- /dev/null
+++ b/src/pp/relic_pp_dbl_k1.c
@@ -0,0 +1,168 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of Miller doubling for curves of embedding degree 1.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_fp_low.h"
+#include "relic_fpx_low.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+/* Formulas from "Generation and Tate Pairing Computation
+ * of Ordinary Elliptic Curves with Embedding Degree One", by Hu et al. */
+
+void pp_dbl_k1_basic(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q) {
+ fp_t s;
+
+ fp_null(s);
+
+ RLC_TRY {
+ fp_new(s);
+
+ ep_dbl_slp_basic(r, s, p);
+ fp_sub(m, q->x, r->x);
+ fp_mul(l, m, s);
+ fp_sub(l, r->y, l);
+ fp_add(l, l, q->y);
+ if (fp_is_zero(l)) {
+ fp_set_dig(l, 1);
+ }
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp_free(s);
+ }
+}
+
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+
+void pp_dbl_k1_projc(fp_t l, fp_t m, ep_t r, const ep_t p, const ep_t q) {
+ fp_t t0, t1, t2, t3, t4, t5;
+
+ fp_null(t0);
+ fp_null(t1);
+ fp_null(t2);
+ fp_null(t3);
+ fp_null(t4);
+ fp_null(t5);
+
+ RLC_TRY {
+ fp_new(t0);
+ fp_new(t1);
+ fp_new(t2);
+ fp_new(t3);
+ fp_new(t4);
+ fp_new(t5);
+
+ /* dbl-2007-bl formulas 1M + 8S + 1*a + 10add + 2*2 + 1*3 + 1*8 */
+
+ /* t0 = z1^2. */
+ fp_sqr(t0, p->z);
+
+ /* t1 = y1^2. */
+ fp_sqr(t1, p->y);
+
+ /* t2 = x1^2. */
+ fp_sqr(t2, p->x);
+
+ /* t3 = y1^4.*/
+ fp_sqr(t3, t1);
+
+ /* t4 = S = 2*((X1+YY)^2-XX-YYYY). */
+ fp_add(t4, p->x, t1);
+ fp_sqr(t4, t4);
+ fp_sub(t4, t4, t2);
+ fp_sub(t4, t4, t3);
+ fp_dbl(t4, t4);
+
+ /* z3 = (Y1+Z1)^2-YY-ZZ, */
+ fp_add(r->z, p->y, p->z);
+ fp_sqr(r->z, r->z);
+ fp_sub(r->z, r->z, t1);
+ fp_sub(r->z, r->z, t0);
+
+ /* t5 = M = 3*XX+a*ZZ^2. */
+ fp_dbl(t5, t2);
+ fp_add(t5, t5, t2);
+ fp_sqr(t2, t0);
+ fp_mul(t1, t2, ep_curve_get_a());
+ fp_add(t5, t5, t1);
+
+ /* x3 = T = M^2 - 2S. */
+ fp_sqr(r->x, t5);
+ fp_sub(r->x, r->x, t4);
+ fp_sub(r->x, r->x, t4);
+
+ /* y3 = M*(S-T)-8*YYYY. */
+ fp_sub(t1, t4, r->x);
+ fp_mul(t1, t5, t1);
+ fp_dbl(t3, t3);
+ fp_dbl(t3, t3);
+ fp_dbl(t3, t3);
+ fp_sub(r->y, t1, t3);
+
+ /* l = z3*z3^2*yQ + y3 − t5*(z3^2*xQ - x3), v = z3*(z3^2*xQ - x3)). */
+ fp_sqr(t2, r->z);
+ fp_mul(l, r->z, t2);
+ fp_mul(l, l, q->y);
+ fp_add(l, l, r->y);
+ fp_mul(t2, t2, q->x);
+ fp_sub(t2, t2, r->x);
+ fp_mul(m, r->z, t2);
+ fp_mul(t2, t2, t5);
+ fp_sub(l, l, t2);
+ if (fp_is_zero(l)) {
+ fp_set_dig(l, 1);
+ }
+
+ r->coord = JACOB;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp_free(t0);
+ fp_free(t1);
+ fp_free(t2);
+ fp_free(t3);
+ fp_free(t4);
+ fp_free(t5);
+ }
+}
+
+#endif
diff --git a/src/pp/relic_pp_dbl_k16.c b/src/pp/relic_pp_dbl_k16.c
new file mode 100644
index 000000000..61992eebb
--- /dev/null
+++ b/src/pp/relic_pp_dbl_k16.c
@@ -0,0 +1,415 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of Miller doubling for curves of embedding degree 16.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_fp_low.h"
+#include "relic_fpx_low.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if EP_ADD == BASIC || !defined(STRIP)
+
+void pp_dbl_k16_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p) {
+ fp4_t s;
+ ep4_t t;
+ int one = 1, zero = 0;
+
+ fp4_null(s);
+ ep4_null(t);
+
+ RLC_TRY {
+ fp4_new(s);
+ ep4_new(t);
+ ep4_copy(t, q);
+ ep4_dbl_slp_basic(r, s, q);
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ fp_mul(l[one][zero][0][0], s[0][0], p->x);
+ fp_mul(l[one][zero][0][1], s[0][1], p->x);
+ fp_mul(l[one][zero][1][0], s[1][0], p->x);
+ fp_mul(l[one][zero][1][1], s[1][1], p->x);
+ fp4_mul(l[one][one], s, t->x);
+ fp4_sub(l[one][one], t->y, l[one][one]);
+ fp_copy(l[zero][zero][0][0], p->y);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp4_free(s);
+ ep4_free(t);
+ }
+}
+
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+
+#if PP_EXT == BASIC || !defined(STRIP)
+
+void pp_dbl_k16_projc_basic(fp16_t l, ep4_t r, const ep4_t q, const ep_t p) {
+ fp4_t t0, t1, t2, t3, t4, t5, t6;
+ int one = 1, zero = 0;
+
+ fp4_null(t0);
+ fp4_null(t1);
+ fp4_null(t2);
+ fp4_null(t3);
+ fp4_null(t4);
+ fp4_null(t5);
+ fp4_null(t6);
+
+ RLC_TRY {
+ fp4_new(t0);
+ fp4_new(t1);
+ fp4_new(t2);
+ fp4_new(t3);
+ fp4_new(t4);
+ fp4_new(t5);
+ fp4_new(t6);
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ /* t0 = A = X1^2, t1 = B = Y1^2, t2 = C = Z1^2, t3 = D = a*C. */
+ fp4_sqr(t0, q->x);
+ fp4_sqr(t1, q->y);
+ fp4_sqr(t2, q->z);
+ switch (ep_curve_opt_a()) {
+ case RLC_ZERO:
+ fp4_zero(t3);
+ break;
+ case RLC_ONE:
+ fp4_copy(t3, t2);
+ break;
+#if FP_RDC != MONTY
+ case RLC_TINY:
+ fp_mul_dig(t3[0][0], t2[0][0], ep_curve_get_a()[0]);
+ fp_mul_dig(t3[0][1], t2[0][1], ep_curve_get_a()[0]);
+ fp_mul_dig(t3[1][0], t2[1][0], ep_curve_get_a()[0]);
+ fp_mul_dig(t3[1][1], t2[1][1], ep_curve_get_a()[0]);
+ break;
+#endif
+ default:
+ fp_mul(t3[0][0], t2[0][0], ep_curve_get_a());
+ fp_mul(t3[0][1], t2[0][1], ep_curve_get_a());
+ fp_mul(t3[1][0], t2[1][0], ep_curve_get_a());
+ fp_mul(t3[1][1], t2[1][1], ep_curve_get_a());
+ break;
+ }
+ fp4_mul_art(t3, t3);
+
+ /* x3 = (A - D)^2, l11 = (A - D + x1)^2 - x3 - A. */
+ fp4_sub(t5, t0, t3);
+ fp4_add(l[one][one], t5, q->x);
+ fp4_sqr(r->x, t5);
+ fp4_sqr(l[one][one], l[one][one]);
+ fp4_sub(l[one][one], l[one][one], r->x);
+ fp4_sub(l[one][one], l[one][one], t0);
+
+ /* l10 := -xp*z1*2*(3A + D). */
+ fp4_add(t6, t0, t3);
+ fp4_dbl(t0, t0);
+ fp4_add(t0, t0, t6);
+ fp4_dbl(t0, t0);
+ fp4_mul(l[one][zero], t0, q->z);
+ fp_mul(l[one][zero][0][0], l[one][zero][0][0], p->x);
+ fp_mul(l[one][zero][0][1], l[one][zero][0][1], p->x);
+ fp_mul(l[one][zero][1][0], l[one][zero][1][0], p->x);
+ fp_mul(l[one][zero][1][1], l[one][zero][1][1], p->x);
+
+ /* l01 = 2*((y1 + z1)^2 - B - C)*yP. */
+ fp4_add(l[zero][zero], q->y, q->z);
+ fp4_sqr(l[zero][zero], l[zero][zero]);
+ fp4_sub(l[zero][zero], l[zero][zero], t1);
+ fp4_sub(l[zero][zero], l[zero][zero], t2);
+ fp4_dbl(l[zero][zero], l[zero][zero]);
+ fp_mul(l[zero][zero][0][0], l[zero][zero][0][0], p->y);
+ fp_mul(l[zero][zero][0][1], l[zero][zero][0][1], p->y);
+ fp_mul(l[zero][zero][1][0], l[zero][zero][1][0], p->y);
+ fp_mul(l[zero][zero][1][1], l[zero][zero][1][1], p->y);
+
+ /* t4 = E = 2*(A + D)^2 - x3. */
+ fp4_sqr(t4, t6);
+ fp4_dbl(t4, t4);
+ fp4_sub(t4, t4, r->x);
+ /* y3 = E * ((A - D + y1)^2 - B - x3). */
+ fp4_add(r->y, t5, q->y);
+ fp4_sqr(r->y, r->y);
+ fp4_sub(r->y, r->y, t1);
+ fp4_sub(r->y, r->y, r->x);
+ fp4_mul(r->y, r->y, t4);
+ /* z3 = 4*B. */
+ fp4_dbl(r->z, t1);
+ fp4_dbl(r->z, r->z);
+
+ r->coord = PROJC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp4_free(t0);
+ fp4_free(t1);
+ fp4_free(t2);
+ fp4_free(t3);
+ fp4_free(t4);
+ fp4_free(t5);
+ fp4_free(t6);
+ }
+}
+
+#endif
+
+#if PP_EXT == LAZYR || !defined(STRIP)
+
+void pp_dbl_k16_projc_lazyr(fp16_t l, ep4_t r, const ep4_t q, const ep_t p) {
+ fp4_t t0, t1, t2, t3, t4, t5, t6;
+ dv4_t u0, u1;
+ int one = 1, zero = 0;
+
+ fp4_null(t0);
+ fp4_null(t1);
+ fp4_null(t2);
+ fp4_null(t3);
+ fp4_null(t4);
+ fp4_null(t5);
+ fp4_null(t6);
+ dv4_null(u0);
+ dv4_null(u1);
+
+ RLC_TRY {
+ fp4_new(t0);
+ fp4_new(t1);
+ fp4_new(t2);
+ fp4_new(t3);
+ fp4_new(t4);
+ fp4_new(t5);
+ fp4_new(t6);
+ dv4_new(u0);
+ dv4_new(u1);
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ /* t0 = A = X1^2, t1 = B = Y1^2, t2 = C = Z1^2, t3 = D = a*C. */
+ fp4_sqr(t0, q->x);
+ fp4_sqr(t1, q->y);
+ fp4_sqr(t2, q->z);
+ switch (ep_curve_opt_a()) {
+ case RLC_ZERO:
+ fp4_zero(t3);
+ break;
+ case RLC_ONE:
+ fp4_copy(t3, t2);
+ break;
+#if FP_RDC != MONTY
+ case RLC_TINY:
+ fp_mul_dig(t3[0][0], t2[0][0], ep_curve_get_a()[0]);
+ fp_mul_dig(t3[0][1], t2[0][1], ep_curve_get_a()[0]);
+ fp_mul_dig(t3[1][0], t2[1][0], ep_curve_get_a()[0]);
+ fp_mul_dig(t3[1][1], t2[1][1], ep_curve_get_a()[0]);
+ break;
+#endif
+ default:
+ fp_mul(t3[0][0], t2[0][0], ep_curve_get_a());
+ fp_mul(t3[0][1], t2[0][1], ep_curve_get_a());
+ fp_mul(t3[1][0], t2[1][0], ep_curve_get_a());
+ fp_mul(t3[1][1], t2[1][1], ep_curve_get_a());
+ break;
+ }
+ fp4_mul_art(t3, t3);
+
+ /* x3 = (A - D)^2, l11 = (A - D + x1)^2 - x3 - A. */
+ fp4_sub(t5, t0, t3);
+ fp4_add(l[one][one], t5, q->x);
+ fp4_sqr(r->x, t5);
+ fp4_sqr(l[one][one], l[one][one]);
+ fp4_sub(l[one][one], l[one][one], r->x);
+ fp4_sub(l[one][one], l[one][one], t0);
+
+ /* l10 := -xp*z1*2*(3A + D). */
+ fp4_add(t6, t0, t3);
+ fp4_dbl(t0, t0);
+ fp4_add(t0, t0, t6);
+ fp4_dbl(t0, t0);
+ fp4_mul(l[one][zero], t0, q->z);
+ fp_mul(l[one][zero][0][0], l[one][zero][0][0], p->x);
+ fp_mul(l[one][zero][0][1], l[one][zero][0][1], p->x);
+ fp_mul(l[one][zero][1][0], l[one][zero][1][0], p->x);
+ fp_mul(l[one][zero][1][1], l[one][zero][1][1], p->x);
+
+ /* l01 = 2*((y1 + z1)^2 - B - C)*yP. */
+ fp4_add(l[zero][zero], q->y, q->z);
+ fp4_sqr(l[zero][zero], l[zero][zero]);
+ fp4_sub(l[zero][zero], l[zero][zero], t1);
+ fp4_sub(l[zero][zero], l[zero][zero], t2);
+ fp4_dbl(l[zero][zero], l[zero][zero]);
+ fp_mul(l[zero][zero][0][0], l[zero][zero][0][0], p->y);
+ fp_mul(l[zero][zero][0][1], l[zero][zero][0][1], p->y);
+ fp_mul(l[zero][zero][1][0], l[zero][zero][1][0], p->y);
+ fp_mul(l[zero][zero][1][1], l[zero][zero][1][1], p->y);
+
+ /* t4 = E = 2*(A + D)^2 - x3. */
+ fp4_sqr(t4, t6);
+ fp4_dbl(t4, t4);
+ fp4_sub(t4, t4, r->x);
+ /* y3 = E * ((A - D + y1)^2 - B - x3). */
+ fp4_add(r->y, t5, q->y);
+ fp4_sqr(r->y, r->y);
+ fp4_sub(r->y, r->y, t1);
+ fp4_sub(r->y, r->y, r->x);
+ fp4_mul(r->y, r->y, t4);
+ /* z3 = 4*B. */
+ fp4_dbl(r->z, t1);
+ fp4_dbl(r->z, r->z);
+ r->coord = PROJC;
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp4_free(t0);
+ fp4_free(t1);
+ fp4_free(t2);
+ fp4_free(t3);
+ fp4_free(t4);
+ fp4_free(t5);
+ fp4_free(t6);
+ dv4_free(u0);
+ dv4_free(u1);
+ }
+}
+
+#endif
+
+#endif
+
+void pp_dbl_lit_k16(fp16_t l, ep_t r, const ep_t p, const ep4_t q) {
+ fp_t t0, t1, t2, t3, t4, t5, t6;
+ int one = 1, zero = 0;
+
+ fp_null(t0);
+ fp_null(t1);
+ fp_null(t2);
+ fp_null(t3);
+ fp_null(t4);
+ fp_null(t5);
+ fp_null(t6);
+
+ RLC_TRY {
+ fp_new(t0);
+ fp_new(t1);
+ fp_new(t2);
+ fp_new(t3);
+ fp_new(t4);
+ fp_new(t5);
+ fp_new(t6);
+
+ fp_sqr(t0, p->x);
+ fp_sqr(t1, p->y);
+ fp_sqr(t2, p->z);
+
+ fp_mul(t4, ep_curve_get_b(), t2);
+
+ fp_dbl(t3, t4);
+ fp_add(t3, t3, t4);
+
+ fp_add(t4, p->x, p->y);
+ fp_sqr(t4, t4);
+ fp_sub(t4, t4, t0);
+ fp_sub(t4, t4, t1);
+ fp_add(t5, p->y, p->z);
+ fp_sqr(t5, t5);
+ fp_sub(t5, t5, t1);
+ fp_sub(t5, t5, t2);
+ fp_dbl(t6, t3);
+ fp_add(t6, t6, t3);
+ fp_sub(r->x, t1, t6);
+ fp_mul(r->x, r->x, t4);
+ fp_add(r->y, t1, t6);
+ fp_sqr(r->y, r->y);
+ fp_sqr(t4, t3);
+ fp_dbl(t6, t4);
+ fp_add(t6, t6, t4);
+ fp_dbl(t6, t6);
+ fp_dbl(t6, t6);
+ fp_sub(r->y, r->y, t6);
+ fp_mul(r->z, t1, t5);
+ fp_dbl(r->z, r->z);
+ fp_dbl(r->z, r->z);
+ r->coord = PROJC;
+
+ if (ep4_curve_is_twist() == RLC_EP_MTYPE) {
+ one ^= 1;
+ zero ^= 1;
+ }
+
+ fp4_dbl(l[zero][one], q->x);
+ fp4_add(l[zero][one], l[zero][one], q->x);
+ fp_mul(l[zero][one][0][0], l[zero][one][0][0], t0);
+ fp_mul(l[zero][one][0][1], l[zero][one][0][1], t0);
+ fp_mul(l[zero][one][1][0], l[zero][one][1][0], t0);
+ fp_mul(l[zero][one][1][1], l[zero][one][1][1], t0);
+
+ fp_sub(l[zero][zero][0][0], t3, t1);
+
+ fp_mul(l[one][one][0][0], q->y[0][0], t5);
+ fp_mul(l[one][one][0][1], q->y[0][1], t5);
+ fp_mul(l[one][one][1][0], q->y[1][0], t5);
+ fp_mul(l[one][one][1][1], q->y[1][1], t5);
+
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp_free(t0);
+ fp_free(t1);
+ fp_free(t2);
+ fp_free(t3);
+ fp_free(t4);
+ fp_free(t5);
+ fp_free(t6);
+ }
+}
diff --git a/src/pp/relic_pp_dbl_k18.c b/src/pp/relic_pp_dbl_k18.c
index 9b34ed299..2837eed99 100644
--- a/src/pp/relic_pp_dbl_k18.c
+++ b/src/pp/relic_pp_dbl_k18.c
@@ -24,7 +24,7 @@
/**
* @file
*
- * Implementation of Miller doubling for curves of embedding degree 12.
+ * Implementation of Miller doubling for curves of embedding degree 18.
*
* @ingroup pp
*/
diff --git a/src/pp/relic_pp_dbl_k24.c b/src/pp/relic_pp_dbl_k24.c
index 6057a976e..5dc1e1111 100644
--- a/src/pp/relic_pp_dbl_k24.c
+++ b/src/pp/relic_pp_dbl_k24.c
@@ -37,7 +37,7 @@
/* Public definitions */
/*============================================================================*/
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == BASIC || !defined(STRIP)
void pp_dbl_k24_basic(fp24_t l, ep4_t r, const ep4_t q, const ep_t p) {
fp4_t s;
diff --git a/src/pp/relic_pp_dbl_k48.c b/src/pp/relic_pp_dbl_k48.c
index 743518c2b..888efc3ed 100644
--- a/src/pp/relic_pp_dbl_k48.c
+++ b/src/pp/relic_pp_dbl_k48.c
@@ -33,86 +33,25 @@
#include "relic_pp.h"
#include "relic_util.h"
-/*============================================================================*/
-/* Private definitions */
-/*============================================================================*/
-
-static void ep8_dbl_basic(fp8_t s, fp8_t rx, fp8_t ry) {
- fp8_t t0, t1, t2;
-
- fp8_null(t0);
- fp8_null(t1);
- fp8_null(t2);
-
- RLC_TRY {
- fp8_new(t0);
- fp8_new(t1);
- fp8_new(t2);
-
- /* t0 = 1/(2 * y1). */
- fp8_dbl(t0, ry);
- fp8_inv(t0, t0);
-
- /* t1 = 3 * x1^2 + a. */
- fp8_sqr(t1, rx);
- fp8_copy(t2, t1);
- fp8_dbl(t1, t1);
- fp8_add(t1, t1, t2);
-
- /* a = 0. */
- /* t1 = (3 * x1^2 + a)/(2 * y1). */
- fp8_mul(t1, t1, t0);
-
- if (s != NULL) {
- fp8_copy(s, t1);
- }
-
- /* t2 = t1^2. */
- fp8_sqr(t2, t1);
-
- /* x3 = t1^2 - 2 * x1. */
- fp8_dbl(t0, rx);
- fp8_sub(t0, t2, t0);
-
- /* y3 = t1 * (x1 - x3) - y1. */
- fp8_sub(t2, rx, t0);
- fp8_mul(t1, t1, t2);
-
- fp8_sub(ry, t1, ry);
-
- fp8_copy(rx, t0);
- }
- RLC_CATCH_ANY {
- RLC_THROW(ERR_CAUGHT);
- }
- RLC_FINALLY {
- fp8_free(t0);
- fp8_free(t1);
- fp8_free(t2);
- }
-}
-
/*============================================================================*/
/* Public definitions */
/*============================================================================*/
#if EP_ADD == BASIC || !defined(STRIP)
-void pp_dbl_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, const ep_t p) {
- fp8_t s, tx, ty;
+void pp_dbl_k48_basic(fp48_t l, ep8_t r, const ep8_t q, const ep_t p) {
+ fp8_t s;
+ ep8_t t;
fp8_null(s);
- fp8_null(tx);
- fp8_null(ty);
+ ep8_null(t);
RLC_TRY {
fp8_new(s);
- fp8_new(tx);
- fp8_new(ty);
+ ep8_new(t);
- fp8_copy(tx, rx);
- fp8_copy(ty, ry);
- ep8_dbl_basic(s, rx, ry);
+ ep8_copy(t, q);
+ ep8_dbl_slp_basic(r, s, q);
fp48_zero(l);
fp_mul(l[0][1][0][0][0], p->x, s[0][0][0]);
@@ -124,8 +63,8 @@ void pp_dbl_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, const ep_t p) {
fp_mul(l[0][1][1][1][0], p->x, s[1][1][0]);
fp_mul(l[0][1][1][1][1], p->x, s[1][1][1]);
- fp8_mul(l[0][0], s, tx);
- fp8_sub(l[0][0], ty, l[0][0]);
+ fp8_mul(l[0][0], s, t->x);
+ fp8_sub(l[0][0], t->y, l[0][0]);
fp_copy(l[1][1][0][0][0], p->y);
} RLC_CATCH_ANY {
@@ -133,8 +72,7 @@ void pp_dbl_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, const ep_t p) {
}
RLC_FINALLY {
fp8_free(s);
- fp8_free(tx);
- fp8_free(ty);
+ ep8_free(t);
}
}
@@ -142,7 +80,7 @@ void pp_dbl_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, const ep_t p) {
#if EP_ADD == PROJC || !defined(STRIP)
-void pp_dbl_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const ep_t p) {
+void pp_dbl_k48_projc(fp48_t l, ep8_t r, const ep8_t q, const ep_t p) {
fp8_t t0, t1, t2, t3, t4, t5, t6;
fp8_null(t0);
@@ -163,26 +101,25 @@ void pp_dbl_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const ep_t p) {
fp8_new(t6);
/* A = x1^2. */
- fp8_sqr(t0, rx);
+ fp8_sqr(t0, q->x);
/* B = y1^2. */
- fp8_sqr(t1, ry);
+ fp8_sqr(t1, q->y);
/* C = z1^2. */
- fp8_sqr(t2, rz);
+ fp8_sqr(t2, q->z);
/* D = 3bC, general b. */
fp8_dbl(t3, t2);
fp8_add(t3, t3, t2);
- fp8_zero(t4);
- fp_copy(t4[1][0][0], ep_curve_get_b());
-
+ ep8_curve_get_b(t4);
fp8_mul(t3, t3, t4);
+
/* E = (x1 + y1)^2 - A - B. */
- fp8_add(t4, rx, ry);
+ fp8_add(t4, q->x, q->y);
fp8_sqr(t4, t4);
fp8_sub(t4, t4, t0);
fp8_sub(t4, t4, t1);
/* F = (y1 + z1)^2 - B - C. */
- fp8_add(t5, ry, rz);
+ fp8_add(t5, q->y, q->z);
fp8_sqr(t5, t5);
fp8_sub(t5, t5, t1);
fp8_sub(t5, t5, t2);
@@ -192,23 +129,23 @@ void pp_dbl_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, const ep_t p) {
fp8_add(t6, t6, t3);
/* x3 = E * (B - G). */
- fp8_sub(rx, t1, t6);
- fp8_mul(rx, rx, t4);
+ fp8_sub(r->x, t1, t6);
+ fp8_mul(r->x, r->x, t4);
/* y3 = (B + G)^2 -12D^2. */
fp8_add(t6, t6, t1);
fp8_sqr(t6, t6);
fp8_sqr(t2, t3);
- fp8_dbl(ry, t2);
- fp8_dbl(t2, ry);
- fp8_dbl(ry, t2);
- fp8_add(ry, ry, t2);
- fp8_sub(ry, t6, ry);
+ fp8_dbl(r->y, t2);
+ fp8_dbl(t2, r->y);
+ fp8_dbl(r->y, t2);
+ fp8_add(r->y, r->y, t2);
+ fp8_sub(r->y, t6, r->y);
/* z3 = 4B * F. */
- fp8_dbl(rz, t1);
- fp8_dbl(rz, rz);
- fp8_mul(rz, rz, t5);
+ fp8_dbl(r->z, t1);
+ fp8_dbl(r->z, r->z);
+ fp8_mul(r->z, r->z, t5);
/* l11 = D - B. */
fp8_sub(l[0][0], t3, t1);
diff --git a/src/pp/relic_pp_dbl_k8.c b/src/pp/relic_pp_dbl_k8.c
index a15901b9b..1153f3d04 100644
--- a/src/pp/relic_pp_dbl_k8.c
+++ b/src/pp/relic_pp_dbl_k8.c
@@ -24,7 +24,7 @@
/**
* @file
*
- * Implementation of Miller doubling for curves of embedding degree 2.
+ * Implementation of Miller doubling for curves of embedding degree 8.
*
* @ingroup pp
*/
diff --git a/src/pp/relic_pp_exp_k1.c b/src/pp/relic_pp_exp_k1.c
new file mode 100644
index 000000000..b014a82db
--- /dev/null
+++ b/src/pp/relic_pp_exp_k1.c
@@ -0,0 +1,62 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2019 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the final exponentiation for curves of embedding degree 1.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void pp_exp_k1(fp_t c, fp_t a) {
+ bn_t e, n;
+
+ bn_null(n);
+ bn_null(e);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(e);
+
+ ep_curve_get_ord(n);
+
+ bn_read_raw(e, fp_prime_get(), RLC_FP_DIGS);
+ bn_sub_dig(e, e, 1);
+ bn_div(e, e, n);
+ fp_exp(c, a, e);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ bn_free(n);
+ bn_free(e);
+ }
+}
diff --git a/src/pp/relic_pp_exp_k16.c b/src/pp/relic_pp_exp_k16.c
new file mode 100644
index 000000000..48c71360c
--- /dev/null
+++ b/src/pp/relic_pp_exp_k16.c
@@ -0,0 +1,351 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of the final exponentiation for curves of embedding degree 16.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+/**
+ * Computes the final exponentiation of a pairing defined over a KSS curve.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element to exponentiate.
+ */
+static void pp_exp_kss(fp16_t c, fp16_t a) {
+ fp16_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13;
+ bn_t x;
+
+ bn_null(x);
+ fp16_null(t0);
+ fp16_null(t1);
+ fp16_null(t2);
+ fp16_null(t3);
+ fp16_null(t4);
+ fp16_null(t5);
+ fp16_null(t6);
+ fp16_null(t7);
+ fp16_null(t8);
+ fp16_null(t9);
+ fp16_null(t10);
+ fp16_null(t11);
+ fp16_null(t12);
+ fp16_null(t13);
+
+ RLC_TRY {
+ bn_new(x);
+ fp16_new(t0);
+ fp16_new(t1);
+ fp16_new(t2);
+ fp16_new(t3);
+ fp16_new(t4);
+ fp16_new(t5);
+ fp16_new(t6);
+ fp16_new(t7);
+ fp16_new(t8);
+ fp16_new(t9);
+ fp16_new(t10);
+ fp16_new(t11);
+ fp16_new(t12);
+ fp16_new(t13);
+
+ fp_prime_get_par(x);
+
+ /* First, compute m = f^(p^8 - 1). */
+ fp16_conv_cyc(c, a);
+
+ /* Now compute m^((p^8 + 1) / r). */
+ fp16_sqr_cyc(t0, c);
+ fp16_sqr_cyc(t1, t0);
+
+ bn_add_dig(x, x, 1);
+ fp16_exp_cyc(t2, c, x);
+ fp16_exp_cyc(t3, t2, x);
+ fp16_mul(t4, t3, t1);
+ bn_sub_dig(x, x, 1);
+
+ fp16_exp_cyc(t5, t4, x);
+ fp16_sqr_cyc(t6, t4);
+ fp16_sqr_cyc(t6, t6);
+ fp16_mul(t6, t6, t4);
+ fp16_sqr_cyc(t7, t1);
+ fp16_sqr_cyc(t7, t7);
+ fp16_sqr_cyc(t7, t7);
+ fp16_sqr_cyc(t8, t7);
+ fp16_inv_cyc(t9, t1);
+ fp16_mul(t9, t7, t9);
+ fp16_sqr_cyc(t10, t9);
+ fp16_exp_cyc(t11, t5, x);
+ fp16_exp_cyc(t12, t11, x);
+ fp16_mul(t13, t12, t10);
+
+ fp16_exp_cyc(t9, t13, x);
+ fp16_inv_cyc(t2, t9);
+ fp16_sqr_cyc(t2, t2);
+ fp16_sqr_cyc(t10, t6);
+ fp16_sqr_cyc(t10, t10);
+ fp16_mul(t10, t10, t6);
+ fp16_sqr_cyc(t0, t10);
+ fp16_sqr_cyc(t0, t0);
+ fp16_mul(t10, t10, t0);
+ fp16_inv_cyc(t0, t10);
+ fp16_mul(t0, t2, t0);
+
+ fp16_sqr_cyc(t3, t0);
+ fp16_sqr_cyc(t2, t2);
+ fp16_sqr_cyc(t2, t2);
+ fp16_mul(t2, t2, t9);
+ fp16_mul(t2, t2, t3);
+ fp16_exp_cyc(t3, t9, x);
+ fp16_exp_cyc(t6, t3, x);
+ fp16_exp_cyc(t7, t6, x);
+ fp16_sqr_cyc(t10, t3);
+
+ fp16_sqr_cyc(t9, t5);
+ fp16_sqr_cyc(t9, t9);
+ fp16_mul(t9, t9, t5);
+ fp16_sqr_cyc(t4, t9);
+ fp16_sqr_cyc(t4, t4);
+ fp16_mul(t9, t4, t9);
+ fp16_sqr_cyc(t4, t9);
+ fp16_mul(t4, t4, t9);
+ fp16_mul(t9, t4, t9);
+ fp16_sqr_cyc(t10, t10);
+ fp16_mul(c, t10, t4);
+ fp16_inv_cyc(c, c);
+ fp16_inv_cyc(t3, t3);
+ fp16_mul(t3, t3, t10);
+ fp16_mul(t3, t3, t9);
+ fp16_sqr_cyc(t9, t11);
+ fp16_sqr_cyc(t9, t9);
+ fp16_mul(t11, t11, t9);
+ fp16_sqr_cyc(t9, t11);
+ fp16_mul(t4, t9, t6);
+
+ fp16_sqr_cyc(t6, t6);
+ fp16_sqr_cyc(t10, t9);
+ fp16_sqr_cyc(t10, t10);
+ fp16_mul(t9, t9, t10);
+ fp16_mul(t9, t9, t11);
+ fp16_mul(t9, t9, t6);
+ fp16_sqr_cyc(t5, t12);
+ fp16_mul(t5, t5, t12);
+ fp16_sqr_cyc(t5, t5);
+ fp16_sqr_cyc(t5, t5);
+ fp16_sqr_cyc(t12, t5);
+ fp16_mul(t5, t7, t12);
+ fp16_inv_cyc(t5, t5);
+ fp16_sqr_cyc(t10, t8);
+ fp16_mul(t8, t8, t10);
+ fp16_mul(t6, t8, t1);
+ fp16_mul(t7, t5, t6);
+ fp16_sqr_cyc(t8, t13);
+ fp16_mul(t8, t8, t13);
+ fp16_sqr_cyc(t8, t8);
+ fp16_mul(t8, t8, t13);
+ fp16_frb(c, c, 1);
+ fp16_frb(t7, t7, 3);
+ fp16_frb(t3, t3, 5);
+ fp16_frb(t8, t8, 7);
+ fp16_mul(t1, c, t7);
+ fp16_mul(t1, t1, t3);
+ fp16_mul(t1, t1, t8);
+ fp16_frb(t0, t0, 2);
+ fp16_frb(t4, t4, 4);
+ fp16_frb(t2, t2, 6);
+ fp16_mul(t2, t2, t0);
+
+ fp16_mul(c, t2, t9);
+ fp16_mul(c, c, t1);
+ fp16_mul(c, c, t4);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(x);
+ fp16_free(t0);
+ fp16_free(t1);
+ fp16_free(t2);
+ fp16_free(t3);
+ fp16_free(t4);
+ fp16_free(t5);
+ fp16_free(t6);
+ fp16_free(t7);
+ fp16_free(t8);
+ fp16_free(t9);
+ fp16_free(t10);
+ fp16_free(t11);
+ fp16_free(t12);
+ fp16_free(t13);
+ }
+}
+
+/**
+ * Computes the final exponentiation of a pairing defined over a KSS curve.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element to exponentiate.
+ */
+static void pp_exp_new(fp16_t c, fp16_t a) {
+ fp16_t t0, t1, t2, t3, t4;
+ bn_t x, x_;
+
+ bn_null(x);
+ bn_null(x_);
+ fp16_null(t0);
+ fp16_null(t1);
+ fp16_null(t2);
+ fp16_null(t3);
+ fp16_null(t4);
+
+ RLC_TRY {
+ bn_new(x);
+ bn_new(x_);
+ fp16_new(t0);
+ fp16_new(t1);
+ fp16_new(t2);
+ fp16_new(t3);
+ fp16_new(t4);
+
+ fp_prime_get_par(x);
+
+ /* First, compute m = f^(p^8 - 1). */
+ fp16_conv_cyc(c, a);
+
+ /* Now compute m^((p^8 + 1) / r). */
+ bn_abs(x_, x);
+
+ /* Compute eq t0 = m^(u*p * (1+u*p^3)). */
+ fp16_exp_cyc(t0, c, x_);
+ fp16_frb(t0, t0, 3);
+ fp16_inv_cyc(t1, c);
+ if (bn_sign(x) == RLC_POS) {
+ fp16_mul(t0, t0, c);
+ } else {
+ fp16_mul(t0, t0, t1);
+ }
+ fp16_exp_cyc(t0, t0, x_);
+ fp16_frb(t0, t0, 1);
+
+ /* Compute t2 = m^(p^5 + u*(-1 + u^2 * u*p*(1+u*p^3))). */
+ fp16_exp_cyc(t2, t0, x_);
+ fp16_exp_cyc(t2, t2, x_);
+ fp16_mul(t2, t2, t1);
+ fp16_exp_cyc(t2, t2, x_);
+ if (bn_sign(x) == RLC_NEG) {
+ fp16_inv_cyc(t2, t2);
+ }
+ fp16_frb(t3, c, 5);
+ fp16_mul(t2, t2, t3);
+
+ /* Compute t2 = m2^(((u^2 div 4)*(u^3+1)^2 +1) */
+ if (bn_is_even(x_)) {
+ bn_hlv(x_, x_);
+ fp16_exp_cyc(t3, t2, x_);
+ fp16_exp_cyc(t3, t3, x_);
+ bn_dbl(x_, x_);
+ if (bn_sign(x) == RLC_NEG) {
+ fp16_inv_cyc(t4, t3);
+ } else {
+ fp16_copy(t4, t3);
+ }
+ fp16_exp_cyc(t3, t3, x_);
+ fp16_exp_cyc(t3, t3, x_);
+ fp16_exp_cyc(t3, t3, x_);
+ fp16_mul(t3, t3, t4);
+ if (bn_sign(x) == RLC_NEG) {
+ fp16_inv_cyc(t4, t3);
+ } else {
+ fp16_copy(t4, t3);
+ }
+ fp16_exp_cyc(t3, t3, x_);
+ fp16_exp_cyc(t3, t3, x_);
+ fp16_exp_cyc(t3, t3, x_);
+ fp16_mul(t3, t3, t4);
+ } else {
+ fp16_exp_cyc(t3, t2, x_);
+ fp16_exp_cyc(t3, t3, x_);
+ bn_sqr(x, x_);
+ bn_mul(x, x, x_);
+ bn_add_dig(x, x, 1);
+ bn_hlv(x, x);
+ bn_abs(x, x);
+ fp16_exp_cyc(t3, t3, x);
+ fp16_exp_cyc(t3, t3, x);
+ }
+ fp16_mul(t2, t2, t3);
+
+ /* Compute t2 = (t0 * m2)^((p^2-u^2). */
+ fp16_mul(t2, t2, t0);
+ fp16_frb(t4, t2, 2);
+ fp16_exp_cyc(t2, t2, x_);
+ fp16_exp_cyc(t2, t2, x_);
+ fp16_inv_cyc(t2, t2);
+ fp16_mul(t2, t4, t2);
+
+ fp16_mul(c, c, t2);
+ if (!bn_is_even(x_)) {
+ fp16_sqr_cyc(c, c);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(x);
+ bn_free(x_);
+ fp16_free(t0);
+ fp16_free(t1);
+ fp16_free(t2);
+ fp16_free(t3);
+ fp16_free(t4);
+ }
+}
+
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void pp_exp_k16(fp16_t c, fp16_t a) {
+ switch (ep_curve_is_pairf()) {
+ case EP_K16:
+ pp_exp_kss(c, a);
+ break;
+ case EP_N16:
+ pp_exp_new(c, a);
+ break;
+ }
+}
diff --git a/src/pp/relic_pp_exp_k18.c b/src/pp/relic_pp_exp_k18.c
index b096220c0..027398119 100644
--- a/src/pp/relic_pp_exp_k18.c
+++ b/src/pp/relic_pp_exp_k18.c
@@ -34,10 +34,16 @@
#include "relic_util.h"
/*============================================================================*/
-/* Public definitions */
+/* Private definitions */
/*============================================================================*/
-void pp_exp_k18(fp18_t c, fp18_t a) {
+/**
+ * Computes the final exponentiation of a pairing defined over a KSS curve.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element to exponentiate.
+ */
+static void pp_exp_kss(fp18_t c, fp18_t a) {
fp18_t t0, t1, t2, t3, t4, t5;
const int *b;
bn_t x;
@@ -155,3 +161,114 @@ void pp_exp_k18(fp18_t c, fp18_t a) {
fp18_free(t5);
}
}
+
+/**
+ * Computes the final exponentiation of a pairing defined over a SG curve.
+ *
+ * @param[out] c - the result.
+ * @param[in] a - the extension field element to exponentiate.
+ */
+void pp_exp_sg(fp18_t c, fp18_t a) {
+ fp18_t t0, t1, t2, t3;
+ const int *b;
+ bn_t x;
+ int l;
+
+ bn_null(x);
+ fp18_null(t0);
+ fp18_null(t1);
+ fp18_null(t2);
+ fp18_null(t3);
+
+ RLC_TRY {
+ bn_new(x);
+ fp18_new(t0);
+ fp18_new(t1);
+ fp18_new(t2);
+ fp18_new(t3);
+
+ fp_prime_get_par(x);
+ b = fp_prime_get_par_sps(&l);
+ /* First, compute m^(p^9 - 1)(p^3 + 1). */
+ fp18_conv_cyc(c, a);
+
+ /* t0 = f^(-3p^2), t1 = f^(1 - 3up + p^3). */
+ fp18_sqr(t1, c);
+ fp18_mul(t1, t1, c);
+ if (bn_sign(x) == RLC_POS) {
+ fp18_inv_cyc(t1, t1);
+ fp18_frb(t0, t1, 2);
+ } else {
+ fp18_frb(t0, t1, 2);
+ fp18_inv_cyc(t0, t0);
+ }
+ fp18_exp_cyc_sps(t1, t1, b, l, RLC_POS);
+ fp18_frb(t3, c, 2);
+ fp18_mul(t1, t1, t3);
+ fp18_frb(t1, t1, 1);
+ fp18_mul(t1, t1, c);
+
+ fp18_exp_cyc_sps(t2, t1, b, l, RLC_POS);
+ fp18_exp_cyc_sps(t2, t2, b, l, RLC_POS);
+ fp18_sqr_cyc(t3, t2);
+ fp18_mul(t2, t2, t3);
+ fp18_frb(t3, t1, 1);
+ fp18_mul(t2, t2, t3);
+ fp18_exp_cyc_sps(t2, t2, b, l, RLC_POS);
+ if (bn_sign(x) == RLC_NEG) {
+ fp18_inv_cyc(t3, t1);
+ } else {
+ fp18_copy(t3, t1);
+ }
+ fp18_mul(t2, t2, t3);
+ fp18_exp_cyc_sps(t2, t2, b, l, RLC_POS);
+ fp18_sqr_cyc(t3, t2);
+ fp18_mul(t2, t2, t3);
+ fp18_frb(t3, t1, 2);
+ fp18_mul(t2, t2, t3);
+ fp18_mul(t2, t2, t0);
+
+ /* Compute t2 = t2^(3*u^2-1). */
+ fp18_exp_cyc_sps(t3, t2, b, l, RLC_POS);
+ fp18_exp_cyc_sps(t3, t3, b, l, RLC_POS);
+ fp18_sqr_cyc(t0, t3);
+ fp18_mul(t3, t3, t0);
+ fp18_inv_cyc(t2, t2),
+ fp18_mul(t2, t2, t3);
+
+ /* Compute t2 = t2^(3*u^2-1). */
+ fp18_exp_cyc_sps(t3, t2, b, l, RLC_POS);
+ fp18_exp_cyc_sps(t3, t3, b, l, RLC_POS);
+ fp18_sqr_cyc(t0, t3);
+ fp18_mul(t3, t3, t0);
+ fp18_inv_cyc(t2, t2),
+ fp18_mul(t2, t2, t3);
+
+ fp18_mul(c, t1, t2);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(x);
+ fp18_free(t0);
+ fp18_free(t1);
+ fp18_free(t2);
+ fp18_free(t3);
+ }
+}
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+void pp_exp_k18(fp18_t c, fp18_t a) {
+ switch (ep_curve_is_pairf()) {
+ case EP_K18:
+ pp_exp_kss(c, a);
+ break;
+ case EP_SG18:
+ pp_exp_sg(c, a);
+ break;
+ }
+}
diff --git a/src/pp/relic_pp_exp_k8.c b/src/pp/relic_pp_exp_k8.c
index 089cdcbc7..7053f6167 100644
--- a/src/pp/relic_pp_exp_k8.c
+++ b/src/pp/relic_pp_exp_k8.c
@@ -24,7 +24,7 @@
/**
* @file
*
- * Implementation of the final exponentiation for curves of embedding degree 2.
+ * Implementation of the final exponentiation for curves of embedding degree 8.
*
* @ingroup pp
*/
diff --git a/src/pp/relic_pp_map.c b/src/pp/relic_pp_map.c
index 7c67182a9..4408feb1d 100644
--- a/src/pp/relic_pp_map.c
+++ b/src/pp/relic_pp_map.c
@@ -41,10 +41,12 @@ void pp_map_init(void) {
ep2_curve_init();
ep3_curve_init();
ep4_curve_init();
+ ep8_curve_init();
}
void pp_map_clean(void) {
ep2_curve_clean();
ep3_curve_clean();
ep4_curve_clean();
+ ep8_curve_clean();
}
diff --git a/src/pp/relic_pp_map_k1.c b/src/pp/relic_pp_map_k1.c
new file mode 100644
index 000000000..39d1786c9
--- /dev/null
+++ b/src/pp/relic_pp_map_k1.c
@@ -0,0 +1,320 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of pairing computation for curves with embedding degree 1.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+/**
+ * Compute the Miller loop for pairings of type G_2 x G_1 over the bits of a
+ * given parameter.
+ *
+ * @param[out] r - the result.
+ * @param[out] t - the resulting point.
+ * @param[in] p - the first pairing argument in affine coordinates.
+ * @param[in] q - the second pairing argument in affine coordinates.
+ * @param[in] n - the number of pairings to evaluate.
+ * @param[in] a - the loop parameter.
+ */
+static void pp_mil_k1(fp_t r, ep_t *t, ep_t *p, ep_t *q, int n, bn_t a) {
+ fp_t l, m, s;
+ int i, j;
+
+ fp_null(l);
+ fp_null(m);
+ fp_null(s);
+
+ RLC_TRY {
+ fp_new(l);
+ fp_new(m);
+ fp_new(s);
+ for (j = 0; j < n; j++) {
+ ep_copy(t[j], p[j]);
+ }
+
+ fp_set_dig(s, 1);
+ for (i = bn_bits(a) - 2; i >= 0; i--) {
+ fp_sqr(r, r);
+ fp_sqr(s, s);
+ for (j = 0; j < n; j++) {
+ pp_dbl_k1(l, m, t[j], t[j], q[j]);
+ fp_mul(r, r, l);
+ fp_mul(s, s, m);
+ if (bn_get_bit(a, i)) {
+ pp_add_k1(l, m, t[j], p[j], q[j]);
+ fp_mul(r, r, l);
+ fp_mul(s, s, m);
+ }
+ }
+ }
+
+ if (!fp_is_zero(s)) {
+ fp_inv(s, s);
+ fp_mul(r, r, s);
+ } else {
+ fp_set_dig(r, 1);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp_free(l);
+ fp_free(m);
+ fp_free(s);
+ }
+}
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if PP_MAP == TATEP || PP_MAP == OATEP || !defined(STRIP)
+
+void pp_map_tatep_k1(fp_t r, const ep_t p, const ep_t q) {
+ ep_t _p[1], _q[1], t[1];
+ bn_t n;
+
+ ep_null(_p[0]);
+ ep_null(_q[0]);
+ ep_null(t[0]);
+ bn_null(n);
+
+ RLC_TRY {
+ ep_new(t[0]);
+ bn_new(n);
+
+ ep_norm(_p[0], p);
+ ep_norm(_q[0], q);
+ ep_curve_get_ord(n);
+ fp_set_dig(r, 1);
+
+ if (!ep_is_infty(p) && !ep_is_infty(q)) {
+ pp_mil_k1(r, t, _p, _q, 1, n);
+ pp_exp_k1(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep_free(_p[0]);
+ ep_free(_q[0]);
+ ep_free(t[0]);
+ bn_free(n);
+ }
+}
+
+void pp_map_sim_tatep_k1(fp_t r, const ep_t *p, const ep_t *q, int m) {
+ ep_t *_p = RLC_ALLOCA(ep_t, m),
+ *_q = RLC_ALLOCA(ep_t, m), *t = RLC_ALLOCA(ep_t, m);
+ bn_t n;
+ int i, j;
+
+ bn_null(n);
+
+ RLC_TRY {
+ bn_new(n);
+ if (_p == NULL || _q == NULL || t == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (i = 0; i < m; i++) {
+ ep_null(_p[i]);
+ ep_null(_q[i]);
+ ep_null(t[i]);
+ ep_new(_p[i]);
+ ep_new(_q[i]);
+ ep_new(t[i]);
+ }
+
+ j = 0;
+ for (i = 0; i < m; i++) {
+ if (!ep_is_infty(p[i]) && !ep_is_infty(q[i])) {
+ ep_norm(_p[j], p[i]);
+ ep_norm(_q[j++], q[i]);
+ }
+ }
+
+ ep_curve_get_ord(n);
+ fp_set_dig(r, 1);
+ if (j > 0) {
+ pp_mil_k1(r, t, _p, _q, j, n);
+ pp_exp_k1(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ for (i = 0; i < m; i++) {
+ ep_free(_p[i]);
+ ep_free(_q[i]);
+ ep_free(t[i]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(_q);
+ RLC_FREE(t);
+ }
+}
+
+#endif
+
+#if PP_MAP == WEILP || !defined(STRIP)
+
+void pp_map_weilp_k1(fp_t r, const ep_t p, const ep_t q) {
+ ep_t _p[1], _q[1], t0[1], t1[1];
+ fp_t r0, r1;
+ bn_t n;
+
+ ep_null(_p[0]);
+ ep_null(_q[0]);
+ ep_null(t0[0]);
+ ep_null(t1[0]);
+ fp_null(r0);
+ fp_null(r1);
+ bn_null(n);
+
+ RLC_TRY {
+ ep_new(_p[0]);
+ ep_new(_q[0]);
+ ep_new(t0[0]);
+ ep_new(t1[0]);
+ fp_new(r0);
+ fp_new(r1);
+ bn_new(n);
+
+ ep_norm(_p[0], p);
+ ep_norm(_q[0], q);
+ ep_curve_get_ord(n);
+ fp_set_dig(r0, 1);
+ fp_set_dig(r1, 1);
+
+ if (!ep_is_infty(_p[0]) && !ep_is_infty(_q[0])) {
+ pp_mil_k1(r0, t0, _p, _q, 1, n);
+ pp_mil_k1(r1, t1, _q, _p, 1, n);
+ if (fp_cmp(r0, r1) != RLC_EQ) {
+ fp_neg(r0, r0);
+ }
+ fp_inv(r1, r1);
+ }
+ /* Compute r = (-1)^n * r0/r1. */
+ fp_mul(r, r0, r1);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep_free(_p[0]);
+ ep_free(_q[0]);
+ ep_free(t0[0]);
+ ep_free(t1[0]);
+ fp_free(r0);
+ fp_free(r1);
+ bn_free(n);
+ }
+}
+
+void pp_map_sim_weilp_k1(fp_t r, const ep_t *p, const ep_t *q, int m) {
+ ep_t *_p = RLC_ALLOCA(ep_t, m),
+ *_q = RLC_ALLOCA(ep_t, m),
+ *t0 = RLC_ALLOCA(ep_t, m), *t1 = RLC_ALLOCA(ep_t, m);
+ fp_t r0, r1;
+ bn_t n;
+ int i, j;
+
+ fp_null(r0);
+ fp_null(r1);
+ bn_null(r);
+
+ RLC_TRY {
+ fp_new(r0);
+ fp_new(r1);
+ bn_new(n);
+ if (_p == NULL || _q == NULL || t0 == NULL || t1 == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (i = 0; i < m; i++) {
+ ep_null(_p[i]);
+ ep_null(_q[i]);
+ ep_null(t0[i]);
+ ep_null(t1[i]);
+ ep_new(_p[i]);
+ ep_new(_q[i]);
+ ep_new(t0[i]);
+ ep_new(t1[i]);
+ }
+
+ j = 0;
+ for (i = 0; i < m; i++) {
+ if (!ep_is_infty(p[i]) && !ep_is_infty(q[i])) {
+ ep_norm(_p[j], p[i]);
+ ep_norm(_q[j++], q[i]);
+ }
+ }
+
+ ep_curve_get_ord(n);
+ bn_sub_dig(n, n, 1);
+ fp_set_dig(r0, 1);
+ fp_set_dig(r1, 1);
+
+ if (j > 0) {
+ pp_mil_k1(r0, t0, _p, _q, j, n);
+ pp_mil_k1(r1, t1, _q, _p, j, n);
+ fp_inv(r1, r1);
+ }
+ fp_mul(r, r0, r1);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp_free(r0);
+ fp_free(r1);
+ bn_free(n);
+ for (i = 0; i < m; i++) {
+ ep_free(_p[i]);
+ ep_free(_q[i]);
+ ep_free(t0[i]);
+ ep_free(t1[i]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(_q);
+ RLC_FREE(t0);
+ RLC_FREE(t1);
+ }
+}
+
+#endif
diff --git a/src/pp/relic_pp_map_k16.c b/src/pp/relic_pp_map_k16.c
new file mode 100644
index 000000000..bdf0472ad
--- /dev/null
+++ b/src/pp/relic_pp_map_k16.c
@@ -0,0 +1,606 @@
+/*
+ * RELIC is an Efficient LIbrary for Cryptography
+ * Copyright (c) 2023 RELIC Authors
+ *
+ * This file is part of RELIC. RELIC is legal property of its developers,
+ * whose names are not listed here. Please refer to the COPYRIGHT file
+ * for contact information.
+ *
+ * RELIC is free software; you can redistribute it and/or modify it under the
+ * terms of the version 2.1 (or later) of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; or version 2.0 of the Apache
+ * License as published by the Apache Software Foundation. See the LICENSE files
+ * for more details.
+ *
+ * RELIC 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 LICENSE files for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public or the
+ * Apache License along with RELIC. If not, see
+ * or .
+ */
+
+/**
+ * @file
+ *
+ * Implementation of pairing computation for curves with embedding degree 16.
+ *
+ * @ingroup pp
+ */
+
+#include "relic_core.h"
+#include "relic_pp.h"
+#include "relic_util.h"
+
+/*============================================================================*/
+/* Private definitions */
+/*============================================================================*/
+
+/**
+ * Compute the Miller loop for pairings of type G_2 x G_1 over the bits of a
+ * given parameter represented in sparse form.
+ *
+ * @param[out] r - the result.
+ * @param[out] t - the resulting point.
+ * @param[in] q - the vector of first arguments in affine coordinates.
+ * @param[in] p - the vector of second arguments in affine coordinates.
+ * @param[in] n - the number of pairings to evaluate.
+ * @param[in] a - the loop parameter.
+ */
+static void pp_mil_k16(fp16_t r, ep4_t *t, ep4_t *q, ep_t *p, int m, bn_t a) {
+ fp16_t l;
+ ep_t *_p = RLC_ALLOCA(ep_t, m);
+ ep4_t *_q = RLC_ALLOCA(ep4_t, m);
+ int i, j;
+ size_t len = bn_bits(a) + 1;
+ int8_t s[RLC_FP_BITS + 1];
+
+ if (m == 0) {
+ return;
+ }
+
+ fp16_null(l);
+
+ RLC_TRY {
+ fp16_new(l);
+ if (_p == NULL || _q == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+
+ for (j = 0; j < m; j++) {
+ ep_null(_p[j]);
+ ep4_null(_q[j]);
+ ep_new(_p[j]);
+ ep4_new(_q[j]);
+ ep4_copy(t[j], q[j]);
+ ep4_neg(_q[j], q[j]);
+#if EP_ADD == BASIC
+ ep_neg(_p[j], p[j]);
+#else
+ fp_neg(_p[j]->x, p[j]->x);
+ fp_copy(_p[j]->y, p[j]->y);
+#endif
+ }
+
+ fp16_zero(l);
+ bn_rec_naf(s, &len, a, 2);
+ pp_dbl_k16(r, t[0], t[0], _p[0]);
+ for (j = 1; j < m; j++) {
+ pp_dbl_k16(l, t[j], t[j], _p[j]);
+ fp16_mul_dxs(r, r, l);
+ }
+ if (s[len - 2] > 0) {
+ for (j = 0; j < m; j++) {
+ pp_add_k16(l, t[j], q[j], _p[j]);
+ fp16_mul_dxs(r, r, l);
+ }
+ }
+ if (s[len - 2] < 0) {
+ for (j = 0; j < m; j++) {
+ pp_add_k16(l, t[j], _q[j], _p[j]);
+ fp16_mul_dxs(r, r, l);
+ }
+ }
+
+ for (i = len - 3; i >= 0; i--) {
+ fp16_sqr(r, r);
+ for (j = 0; j < m; j++) {
+ pp_dbl_k16(l, t[j], t[j], _p[j]);
+ fp16_mul_dxs(r, r, l);
+ if (s[i] > 0) {
+ pp_add_k16(l, t[j], q[j], _p[j]);
+ fp16_mul_dxs(r, r, l);
+ }
+ if (s[i] < 0) {
+ pp_add_k16(l, t[j], _q[j], _p[j]);
+ fp16_mul_dxs(r, r, l);
+ }
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(l);
+ for (j = 0; j < m; j++) {
+ ep_free(_p[j]);
+ ep4_free(_q[j]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(_q);
+ }
+}
+
+/**
+ * Compute the Miller loop for pairings of type G_1 x G_2 over the bits of a
+ * given parameter.
+ *
+ * @param[out] r - the result.
+ * @param[out] t - the resulting point.
+ * @param[in] p - the first pairing argument in affine coordinates.
+ * @param[in] q - the second pairing argument in affine coordinates.
+ * @param[in] n - the number of pairings to evaluate.
+ * @param[in] a - the loop parameter.
+ */
+static void pp_mil_lit_k16(fp16_t r, ep_t *t, ep_t *p, ep4_t *q, int m, bn_t a) {
+ fp16_t l;
+ ep4_t *_q = RLC_ALLOCA(ep4_t, m);
+ int j;
+
+ fp16_null(l);
+
+ RLC_TRY {
+ if (_q == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ fp16_new(l);
+
+ for (j = 0; j < m; j++) {
+ ep4_null(_q[j]);
+ ep4_new(_q[j]);
+ ep_copy(t[j], p[j]);
+ ep4_neg(_q[j], q[j]);
+ }
+
+ fp16_zero(l);
+ for (int i = bn_bits(a) - 2; i >= 0; i--) {
+ fp16_sqr(r, r);
+ for (j = 0; j < m; j++) {
+ pp_dbl_lit_k16(l, t[j], t[j], _q[j]);
+ fp16_mul(r, r, l);
+ if (bn_get_bit(a, i)) {
+ pp_add_lit_k16(l, t[j], p[j], q[j]);
+ fp16_mul(r, r, l);
+ }
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(l);
+ for (j = 0; j < m; j++) {
+ ep4_free(_q[j]);
+ }
+ RLC_FREE(_q);
+ }
+}
+
+/**
+ * Compute the final lines for optimal ate pairings.
+ *
+ * @param[out] r - the result.
+ * @param[out] t - the resulting point.
+ * @param[in] q - the first point of the pairing, in G_2.
+ * @param[in] p - the second point of the pairing, in G_1.
+ * @param[in] a - the loop parameter.
+ */
+static void pp_fin_k16_oatep(fp16_t r, ep4_t t, ep4_t q, ep_t p) {
+ ep4_t q1, q2;
+ fp16_t tmp;
+
+ fp16_null(tmp);
+ ep4_null(q1);
+ ep4_null(q2);
+
+ RLC_TRY {
+ ep4_new(q1);
+ ep4_new(q2);
+ fp16_new(tmp);
+ fp16_zero(tmp);
+
+#if EP_ADD == PROJC
+ fp_neg(p->x, p->x);
+#endif
+ ep4_frb(q1, q, 1);
+ pp_add_k16(tmp, t, q1, p);
+ fp16_frb(tmp, tmp, 3);
+ fp16_mul_dxs(r, r, tmp);
+
+ pp_dbl_k16(tmp, q2, q, p);
+ fp16_mul_dxs(r, r, tmp);
+ } RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ } RLC_FINALLY {
+ fp16_free(tmp);
+ ep4_free(q1);
+ ep4_free(q2);
+ }
+}
+
+/*============================================================================*/
+/* Public definitions */
+/*============================================================================*/
+
+#if PP_MAP == TATEP || !defined(STRIP)
+
+void pp_map_tatep_k16(fp16_t r, const ep_t p, const ep4_t q) {
+ ep_t _p[1], t[1];
+ ep4_t _q[1];
+ bn_t n;
+
+ ep_null(_p[0]);
+ ep_null(t[0]);
+ ep4_null(_q[0]);
+ bn_null(n);
+
+ RLC_TRY {
+ ep_new(_p[0]);
+ ep_new(t[0]);
+ ep4_new(_q[0]);
+ bn_new(n);
+
+ ep_norm(_p[0], p);
+ ep4_norm(_q[0], q);
+ ep_curve_get_ord(n);
+ fp16_set_dig(r, 1);
+
+ if (!ep_is_infty(p) && !ep4_is_infty(q)) {
+ pp_mil_lit_k16(r, t, _p, _q, 1, n);
+ pp_exp_k16(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep_free(_p[0]);
+ ep_free(t[0]);
+ ep4_free(_q[0]);
+ bn_free(n);
+ }
+}
+
+void pp_map_sim_tatep_k16(fp16_t r, const ep_t *p, const ep4_t *q, int m) {
+ ep_t *_p = RLC_ALLOCA(ep_t, m), *t = RLC_ALLOCA(ep_t, m);
+ ep4_t *_q = RLC_ALLOCA(ep4_t, m);
+ bn_t n;
+ int i, j;
+
+ bn_null(n);
+
+ RLC_TRY {
+ bn_new(n);
+ if (_p == NULL || _q == NULL || t == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (i = 0; i < m; i++) {
+ ep_null(_p[i]);
+ ep_null(t[i]);
+ ep4_null(_q[i]);
+ ep_new(_p[i]);
+ ep_new(t[i]);
+ ep4_new(_q[i]);
+ }
+
+ j = 0;
+ for (i = 0; i < m; i++) {
+ if (!ep_is_infty(p[i]) && !ep4_is_infty(q[i])) {
+ ep_norm(_p[j], p[i]);
+ ep4_norm(_q[j], q[i]);
+ j++;
+ }
+ }
+
+ ep_curve_get_ord(n);
+ fp16_set_dig(r, 1);
+ if (j > 0) {
+ pp_mil_lit_k16(r, t, _p, _q, j, n);
+ pp_exp_k16(r, r);
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(n);
+ for (i = 0; i < m; i++) {
+ ep_free(_p[i]);
+ ep_free(t[i]);
+ ep4_free(_q[i]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(t);
+ RLC_FREE(_q);
+ }
+}
+
+#endif
+
+#if PP_MAP == WEILP || !defined(STRIP)
+
+void pp_map_weilp_k16(fp16_t r, const ep_t p, const ep4_t q) {
+ ep_t _p[1], t0[1];
+ ep4_t _q[1], t1[1];
+ fp16_t r0, r1;
+ bn_t n;
+
+ ep_null(_p[0]);
+ ep_null(t0[0]);
+ ep4_null(_q[0]);
+ ep4_null(t1[0]);
+ fp16_null(r0);
+ fp16_null(r1);
+ bn_null(n);
+
+ RLC_TRY {
+ ep_new(_p[0]);
+ ep_new(t0[0]);
+ ep4_new(_q[0]);
+ ep4_new(t1[0]);
+ fp16_new(r0);
+ fp16_new(r1);
+ bn_new(n);
+
+ ep_norm(_p[0], p);
+ ep4_norm(_q[0], q);
+
+ ep_curve_get_ord(n);
+ bn_sub_dig(n, n, 1);
+ fp16_set_dig(r0, 1);
+ fp16_set_dig(r1, 1);
+
+ if (!ep_is_infty(_p[0]) && !ep4_is_infty(_q[0])) {
+ pp_mil_k16(r1, t1, _q, _p, 1, n);
+ pp_mil_lit_k16(r0, t0, _p, _q, 1, n);
+ fp16_inv(r1, r1);
+ fp16_mul(r0, r0, r1);
+ fp16_inv(r1, r0);
+ fp16_inv_cyc(r0, r0);
+ }
+ fp16_mul(r, r0, r1);
+ fp16_sqr(r, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep_free(_p[0]);
+ ep_free(t0[0]);
+ ep4_free(_q[0]);
+ ep4_free(t1[0]);
+ fp16_free(r0);
+ fp16_free(r1);
+ bn_free(n);
+ }
+}
+
+void pp_map_sim_weilp_k16(fp16_t r, const ep_t *p, const ep4_t *q, int m) {
+ ep_t *_p = RLC_ALLOCA(ep_t, m), *t0 = RLC_ALLOCA(ep_t, m);
+ ep4_t *_q = RLC_ALLOCA(ep4_t, m), *t1 = RLC_ALLOCA(ep4_t, m);
+ fp16_t r0, r1;
+ bn_t n;
+ int i, j;
+
+ fp16_null(r0);
+ fp16_null(r1);
+ bn_null(n);
+
+ RLC_TRY {
+ fp16_new(r0);
+ fp16_new(r1);
+ bn_new(n);
+ if (_p == NULL || _q == NULL || t0 == NULL || t1 == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (i = 0; i < m; i++) {
+ ep_null(_p[i]);
+ ep_null(t0[i]);
+ ep4_null(_q[i]);
+ ep4_null(t1[i]);
+ ep_new(_p[i]);
+ ep_new(t0[i]);
+ ep4_new(_q[i]);
+ ep4_new(t1[i]);
+ }
+
+ j = 0;
+ for (i = 0; i < m; i++) {
+ if (!ep_is_infty(p[i]) && !ep4_is_infty(q[i])) {
+ ep_norm(_p[j], p[i]);
+ ep4_norm(_q[j++], q[i]);
+ }
+ }
+
+ ep_curve_get_ord(n);
+ bn_sub_dig(n, n, 1);
+ fp16_set_dig(r0, 1);
+ fp16_set_dig(r1, 1);
+
+ if (j > 0) {
+ pp_mil_k16(r1, t1, _q, _p, j, n);
+ pp_mil_lit_k16(r0, t0, _p, _q, j, n);
+ fp16_inv(r1, r1);
+ fp16_mul(r0, r0, r1);
+ fp16_inv(r1, r0);
+ fp16_inv_cyc(r0, r0);
+ }
+ fp16_mul(r, r0, r1);
+ fp16_sqr(r, r);
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ fp16_free(r0);
+ fp16_free(r1);
+ bn_free(n);
+ for (i = 0; i < m; i++) {
+ ep_free(_p[i]);
+ ep_free(t0[i]);
+ ep4_free(_q[i]);
+ ep4_free(t1[i]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(_q);
+ RLC_FREE(t0);
+ RLC_FREE(t1);
+ }
+}
+
+#endif
+
+#if PP_MAP == OATEP || !defined(STRIP)
+
+void pp_map_oatep_k16(fp16_t r, const ep_t p, const ep4_t q) {
+ ep_t _p[1];
+ ep4_t t[1], _q[1];
+ bn_t a;
+
+ ep_null(_p[0]);
+ ep4_null(_q[0]);
+ ep4_null(t[0]);
+ bn_null(a);
+
+ RLC_TRY {
+ ep_new(_p[0]);
+ ep4_new(_q[0]);
+ ep4_new(t[0]);
+ bn_new(a);
+
+ fp_prime_get_par(a);
+ fp16_set_dig(r, 1);
+
+ ep_norm(_p[0], p);
+ ep4_norm(_q[0], q);
+
+ if (!ep_is_infty(_p[0]) && !ep4_is_infty(_q[0])) {
+ switch (ep_curve_is_pairf()) {
+ case EP_N16:
+ /* r = f_{|a|,Q}(P). */
+ pp_mil_k16(r, t, _q, _p, 1, a);
+ if (bn_sign(a) == RLC_NEG) {
+ /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
+ fp16_inv_cyc(r, r);
+ ep4_neg(t[0], t[0]);
+ }
+ pp_exp_k16(r, r);
+ break;
+ case EP_K16:
+ /* r = f_{|a|,Q}(P). */
+ pp_mil_k16(r, t, _q, _p, 1, a);
+ if (bn_sign(a) == RLC_NEG) {
+ /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
+ fp16_inv_cyc(r, r);
+ ep4_neg(t[0], t[0]);
+ }
+ fp16_frb(r, r, 3);
+ pp_fin_k16_oatep(r, t[0], _q[0], _p[0]);
+ pp_exp_k16(r, r);
+ break;
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep_free(_p[0]);
+ ep4_free(_q[0]);
+ ep4_free(t[0]);
+ bn_free(a);
+ }
+}
+
+void pp_map_sim_oatep_k16(fp16_t r, const ep_t *p, const ep4_t *q, int m) {
+ ep_t *_p = RLC_ALLOCA(ep_t, m);
+ ep4_t *t = RLC_ALLOCA(ep4_t, m), *_q = RLC_ALLOCA(ep4_t, m);
+ bn_t a;
+ int i, j;
+
+ RLC_TRY {
+ bn_null(a);
+ bn_new(a);
+ if (_p == NULL || _q == NULL || t == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (i = 0; i < m; i++) {
+ ep_null(_p[i]);
+ ep4_null(_q[i]);
+ ep4_null(t[i]);
+ ep_new(_p[i]);
+ ep4_new(_q[i]);
+ ep4_new(t[i]);
+ }
+
+ j = 0;
+ for (i = 0; i < m; i++) {
+ if (!ep_is_infty(p[i]) && !ep4_is_infty(q[i])) {
+ ep_norm(_p[j], p[i]);
+ ep4_norm(_q[j++], q[i]);
+ }
+ }
+
+ fp_prime_get_par(a);
+ fp16_set_dig(r, 1);
+
+ if (j > 0) {
+ switch (ep_curve_is_pairf()) {
+ case EP_N16:
+ /* r = f_{|a|,Q}(P). */
+ pp_mil_k16(r, t, _q, _p, j, a);
+ if (bn_sign(a) == RLC_NEG) {
+ /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
+ fp16_inv_cyc(r, r);
+ }
+ pp_exp_k16(r, r);
+ break;
+ case EP_K16:
+ /* r = f_{|a|,Q}(P). */
+ pp_mil_k16(r, t, _q, _p, j, a);
+ if (bn_sign(a) == RLC_NEG) {
+ /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
+ fp16_inv_cyc(r, r);
+ }
+ fp16_frb(r, r, 3);
+ for (i = 0; i < j; i++) {
+ if (bn_sign(a) == RLC_NEG) {
+ ep4_neg(t[i], t[i]);
+ }
+ pp_fin_k16_oatep(r, t[i], _q[i], _p[i]);
+ }
+ pp_exp_k16(r, r);
+ break;
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ bn_free(a);
+ for (i = 0; i < m; i++) {
+ ep_free(_p[i]);
+ ep4_free(_q[i]);
+ ep4_free(t[i]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(_q);
+ RLC_FREE(t);
+ }
+}
+
+#endif
diff --git a/src/pp/relic_pp_map_k18.c b/src/pp/relic_pp_map_k18.c
index 4ec9f6b39..95c61a73e 100644
--- a/src/pp/relic_pp_map_k18.c
+++ b/src/pp/relic_pp_map_k18.c
@@ -24,7 +24,7 @@
/**
* @file
*
- * Implementation of pairing computation for curves with embedding degree 12.
+ * Implementation of pairing computation for curves with embedding degree 18.
*
* @ingroup pp
*/
@@ -198,7 +198,7 @@ static void pp_mil_lit_k18(fp18_t r, ep_t *t, ep_t *p, ep3_t *q, int m, bn_t a)
* @param[in] p - the second point of the pairing, in G_1.
* @param[in] a - the loop parameter.
*/
-static void pp_fin_k18_oatep(fp18_t r, ep3_t t, ep3_t q, ep_t p) {
+static void pp_fin_k18_oatep(fp18_t r, ep3_t t, ep3_t q, ep_t p, int f) {
fp18_t u, v;
ep3_t _q;
ep_t _p;
@@ -214,28 +214,41 @@ static void pp_fin_k18_oatep(fp18_t r, ep3_t t, ep3_t q, ep_t p) {
ep3_new(_q);
ep3_null(_p);
- /* _q = 3*p*Q. */
- fp18_zero(u);
- fp18_zero(v);
+ /* Compute additional line function. */
+ fp18_zero(u);
+ fp18_zero(v);
- /* Compute additional line function. */
+ switch (ep_curve_is_pairf()) {
+ case EP_K18:
#if EP_ADD == BASIC
- ep_neg(_p, p);
+ ep_neg(_p, p);
#else
- fp_add(_p->x, p->x, p->x);
- fp_add(_p->x, _p->x, p->x);
- fp_neg(_p->y, p->y);
+ fp_add(_p->x, p->x, p->x);
+ fp_add(_p->x, _p->x, p->x);
+ fp_neg(_p->y, p->y);
#endif
-
- pp_dbl_k18(u, _q, q, _p);
- pp_add_k18(v, _q, q, p);
- pp_norm_k18(_q, _q);
- fp18_mul_dxs(u, u, v);
- fp18_frb(u, u, 1);
- fp18_mul(r, r, u);
- ep3_frb(_q, _q, 1);
- pp_add_k18(u, t, _q, p);
- fp18_mul_dxs(r, r, u);
+ /* _q = 3*p*Q. */
+ pp_dbl_k18(u, _q, q, _p);
+ pp_add_k18(v, _q, q, p);
+ pp_norm_k18(_q, _q);
+ fp18_mul_dxs(u, u, v);
+ fp18_frb(u, u, 1);
+ fp18_mul(r, r, u);
+ ep3_frb(_q, _q, 1);
+ pp_add_k18(u, t, _q, p);
+ fp18_mul_dxs(r, r, u);
+ break;
+ case EP_SG18:
+ if (f == 1) {
+ fp18_frb(u, r, 3);
+ fp18_mul(r, r, u);
+ }
+ ep3_frb(t, t, 3);
+ ep3_frb(_q, q, 2);
+ pp_add_k18(v, t, _q, p);
+ fp18_mul_dxs(r, r, v);
+ break;
+ }
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
@@ -522,7 +535,18 @@ void pp_map_oatep_k18(fp18_t r, const ep_t p, const ep3_t q) {
fp18_inv_cyc(r, r);
ep3_neg(t[0], t[0]);
}
- pp_fin_k18_oatep(r, t[0], _q[0], _p[0]);
+ pp_fin_k18_oatep(r, t[0], _q[0], _p[0], 0);
+ pp_exp_k18(r, r);
+ break;
+ case EP_SG18:
+ /* r = f_{|a|,Q}(P). */
+ pp_mil_k18(r, t, _q, _p, 1, a);
+ if (bn_sign(a) == RLC_NEG) {
+ /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
+ fp18_inv_cyc(r, r);
+ ep3_neg(t[0], t[0]);
+ }
+ pp_fin_k18_oatep(r, t[0], _q[0], _p[0], 1);
pp_exp_k18(r, r);
break;
}
@@ -584,7 +608,23 @@ void pp_map_sim_oatep_k18(fp18_t r, const ep_t *p, const ep3_t *q, int m) {
if (bn_sign(a) == RLC_NEG) {
ep3_neg(t[i], t[i]);
}
- pp_fin_k18_oatep(r, t[i], _q[i], _p[i]);
+ pp_fin_k18_oatep(r, t[i], _q[i], _p[i], 0);
+ }
+ pp_exp_k18(r, r);
+ break;
+ case EP_SG18:
+ /* r = f_{|a|,Q}(P). */
+ pp_mil_k18(r, t, _q, _p, j, a);
+ if (bn_sign(a) == RLC_NEG) {
+ /* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
+ fp18_inv_cyc(r, r);
+ }
+ for (i = 0; i < j; i++) {
+ if (bn_sign(a) == RLC_NEG) {
+ ep3_neg(t[i], t[i]);
+ }
+ /* Apply Frobenius only once. */
+ pp_fin_k18_oatep(r, t[i], _q[i], _p[i], i == 0);
}
pp_exp_k18(r, r);
break;
diff --git a/src/pp/relic_pp_map_k24.c b/src/pp/relic_pp_map_k24.c
index 91701eee0..87e09717e 100644
--- a/src/pp/relic_pp_map_k24.c
+++ b/src/pp/relic_pp_map_k24.c
@@ -24,7 +24,7 @@
/**
* @file
*
- * Implementation of pairing computation for curves with embedding degree 12.
+ * Implementation of pairing computation for curves with embedding degree 24.
*
* @ingroup pp
*/
@@ -168,7 +168,6 @@ void pp_map_k24(fp24_t r, const ep_t p, const ep4_t q) {
pp_mil_k24(r, t, _q, _p, 1, a);
if (bn_sign(a) == RLC_NEG) {
fp24_inv_cyc(r, r);
- ep4_neg(t[0], t[0]);
}
pp_exp_k24(r, r);
break;
diff --git a/src/pp/relic_pp_map_k48.c b/src/pp/relic_pp_map_k48.c
index e47e5028e..d1da3573d 100644
--- a/src/pp/relic_pp_map_k48.c
+++ b/src/pp/relic_pp_map_k48.c
@@ -37,55 +37,85 @@
/* Private definitions */
/*============================================================================*/
-static void pp_mil_k48(fp48_t r, const fp8_t qx, const fp8_t qy, const ep_t p,
- const bn_t a) {
+/**
+ * Compute the Miller loop for pairings of type G_2 x G_1 over the bits of a
+ * given parameter represented in sparse form.
+ *
+ * @param[out] r - the result.
+ * @param[out] t - the resulting point.
+ * @param[in] q - the vector of first arguments in affine coordinates.
+ * @param[in] p - the vector of second arguments in affine coordinates.
+ * @param[in] n - the number of pairings to evaluate.
+ * @param[in] a - the loop parameter.
+ */
+static void pp_mil_k48(fp48_t r, ep8_t *t, ep8_t *q, ep_t *p, int m, bn_t a) {
fp48_t l;
- ep_t _p;
- fp8_t rx, ry, rz, qn;
+ ep_t *_p = RLC_ALLOCA(ep_t, m);
+ ep8_t *_q = RLC_ALLOCA(ep8_t, m);
size_t len = bn_bits(a) + 1;
- int i;
+ int i, j;
int8_t s[RLC_FP_BITS + 1];
+ if (m == 0) {
+ return;
+ }
+
fp48_null(l);
- ep_null(_p);
- fp8_null(rx);
- fp8_null(ry);
- fp8_null(rz);
- fp8_null(qn);
RLC_TRY {
fp48_new(l);
- ep_new(_p);
- fp8_new(rx);
- fp8_new(ry);
- fp8_new(rz);
- fp8_new(qn);
-
- fp48_zero(l);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_set_dig(rz, 1);
+ if (_p == NULL || _q == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (j = 0; j < m; j++) {
+ ep_null(_p[j]);
+ ep8_null(_q[j]);
+ ep_new(_p[j]);
+ ep8_new(_q[j]);
+ ep8_copy(t[j], q[j]);
+ ep8_neg(_q[j], q[j]);
#if EP_ADD == BASIC
- ep_neg(_p, p);
+ ep_neg(_p[j], p[j]);
#else
- fp_add(_p->x, p->x, p->x);
- fp_add(_p->x, _p->x, p->x);
- fp_neg(_p->y, p->y);
+ fp_add(_p[j]->x, p[j]->x, p[j]->x);
+ fp_add(_p[j]->x, _p[j]->x, p[j]->x);
+ fp_neg(_p[j]->y, p[j]->y);
#endif
- fp8_neg(qn, qy);
+ }
+ fp48_zero(l);
bn_rec_naf(s, &len, a, 2);
- for (i = len - 2; i >= 0; i--) {
- fp48_sqr(r, r);
- pp_dbl_k48(l, rx, ry, rz, _p);
+ pp_dbl_k48(r, t[0], t[0], _p[0]);
+ for (j = 1; j < m; j++) {
+ pp_dbl_k48(l, t[j], t[j], _p[j]);
fp48_mul_dxs(r, r, l);
- if (s[i] > 0) {
- pp_add_k48(l, rx, ry, rz, qx, qy, p);
+ }
+ if (s[len - 2] > 0) {
+ for (j = 0; j < m; j++) {
+ pp_add_k48(l, t[j], q[j], p[j]);
+ fp48_mul_dxs(r, r, l);
+ }
+ }
+ if (s[len - 2] < 0) {
+ for (j = 0; j < m; j++) {
+ pp_add_k48(l, t[j], _q[j], p[j]);
fp48_mul_dxs(r, r, l);
}
- if (s[i] < 0) {
- pp_add_k48(l, rx, ry, rz, qx, qn, p);
+ }
+
+ for (i = len - 3; i >= 0; i--) {
+ fp48_sqr(r, r);
+ for (j = 0; j < m; j++) {
+ pp_dbl_k48(l, t[j], t[j], _p[j]);
fp48_mul_dxs(r, r, l);
+ if (s[i] > 0) {
+ pp_add_k48(l, t[j], q[j], p[j]);
+ fp48_mul_dxs(r, r, l);
+ }
+ if (s[i] < 0) {
+ pp_add_k48(l, t[j], _q[j], p[j]);
+ fp48_mul_dxs(r, r, l);
+ }
}
}
}
@@ -94,11 +124,12 @@ static void pp_mil_k48(fp48_t r, const fp8_t qx, const fp8_t qy, const ep_t p,
}
RLC_FINALLY {
fp48_free(l);
- ep_free(_p);
- fp8_free(rx);
- fp8_free(ry);
- fp8_free(rz);
- fp8_free(qn);
+ for (j = 0; j < m; j++) {
+ ep_free(_p[j]);
+ ep8_free(_q[j]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(_q);
}
}
@@ -106,22 +137,91 @@ static void pp_mil_k48(fp48_t r, const fp8_t qx, const fp8_t qy, const ep_t p,
/* Public definitions */
/*============================================================================*/
-void pp_map_k48(fp48_t r, const ep_t p, const fp8_t qx, const fp8_t qy) {
+#if PP_MAP == OATEP || !defined(STRIP)
+
+void pp_map_k48(fp48_t r, const ep_t p, const ep8_t q) {
+ ep_t _p[1];
+ ep8_t t[1], _q[1];
bn_t a;
+ ep_null(_p[0]);
+ ep8_null(_q[0]);
+ ep8_null(t[0]);
bn_null(a);
RLC_TRY {
+ ep_new(_p[0]);
+ ep8_new(_q[0]);
+ ep8_new(t[0]);
+ bn_new(a);
+
+ fp_prime_get_par(a);
+ fp48_set_dig(r, 1);
+
+ ep_norm(_p[0], p);
+ ep8_norm(_q[0], q);
+
+ if (!ep_is_infty(_p[0]) && !ep8_is_infty(_q[0])) {
+ switch (ep_curve_is_pairf()) {
+ case EP_B48:
+ /* r = f_{|a|,Q}(P). */
+ pp_mil_k48(r, t, _q, _p, 1, a);
+ if (bn_sign(a) == RLC_NEG) {
+ fp48_inv_cyc(r, r);
+ }
+ pp_exp_k48(r, r);
+ break;
+ }
+ }
+ }
+ RLC_CATCH_ANY {
+ RLC_THROW(ERR_CAUGHT);
+ }
+ RLC_FINALLY {
+ ep_free(_p[0]);
+ ep8_free(_q[0]);
+ ep8_free(t[0]);
+ bn_free(a);
+ }
+}
+
+void pp_map_sim_k48(fp48_t r, const ep_t *p, const ep8_t *q, int m) {
+ ep_t *_p = RLC_ALLOCA(ep_t, m);
+ ep8_t *t = RLC_ALLOCA(ep8_t, m), *_q = RLC_ALLOCA(ep8_t, m);
+ bn_t a;
+ int i, j;
+
+ RLC_TRY {
+ bn_null(a);
bn_new(a);
+ if (_p == NULL || _q == NULL || t == NULL) {
+ RLC_THROW(ERR_NO_MEMORY);
+ }
+ for (i = 0; i < m; i++) {
+ ep_null(_p[i]);
+ ep8_null(_q[i]);
+ ep8_null(t[i]);
+ ep_new(_p[i]);
+ ep8_new(_q[i]);
+ ep8_new(t[i]);
+ }
+
+ j = 0;
+ for (i = 0; i < m; i++) {
+ if (!ep_is_infty(p[i]) && !ep8_is_infty(q[i])) {
+ ep_norm(_p[j], p[i]);
+ ep8_norm(_q[j++], q[i]);
+ }
+ }
fp_prime_get_par(a);
fp48_set_dig(r, 1);
- if (!ep_is_infty(p) && !(fp8_is_zero(qx) && fp8_is_zero(qy))) {
+ if (j > 0) {
switch (ep_curve_is_pairf()) {
case EP_B48:
/* r = f_{|a|,Q}(P). */
- pp_mil_k48(r, qx, qy, p, a);
+ pp_mil_k48(r, t, _q, _p, j, a);
if (bn_sign(a) == RLC_NEG) {
fp48_inv_cyc(r, r);
}
@@ -135,5 +235,15 @@ void pp_map_k48(fp48_t r, const ep_t p, const fp8_t qx, const fp8_t qy) {
}
RLC_FINALLY {
bn_free(a);
+ for (i = 0; i < m; i++) {
+ ep_free(_p[i]);
+ ep8_free(_q[i]);
+ ep8_free(t[i]);
+ }
+ RLC_FREE(_p);
+ RLC_FREE(_q);
+ RLC_FREE(t);
}
}
+
+#endif
diff --git a/src/pp/relic_pp_norm.c b/src/pp/relic_pp_norm.c
index 80ffd8742..e63b0d62c 100644
--- a/src/pp/relic_pp_norm.c
+++ b/src/pp/relic_pp_norm.c
@@ -39,6 +39,10 @@
/* Public definitions */
/*============================================================================*/
+void pp_norm_k1(ep_t r, const ep_t p) {
+ ep_norm(r, p);
+}
+
void pp_norm_k2(ep_t r, const ep_t p) {
ep_norm(r, p);
}
@@ -82,6 +86,28 @@ void pp_norm_k12(ep2_t r, const ep2_t p) {
#endif
}
+void pp_norm_k16(ep4_t r, const ep4_t p) {
+ if (ep4_is_infty(p)) {
+ ep4_set_infty(r);
+ return;
+ }
+
+ if (p->coord == BASIC) {
+ /* If the point is represented in affine coordinates, we just copy it. */
+ ep4_copy(r, p);
+ }
+#if EP_ADD == PROJC || !defined(STRIP)
+ fp4_inv(r->z, p->z);
+ fp4_mul(r->x, p->x, r->z);
+ fp4_mul(r->y, p->y, r->z);
+ if (ep_curve_opt_b() == RLC_ZERO) {
+ fp4_mul(r->y, r->y, r->z);
+ }
+ fp4_set_dig(r->z, 1);
+ r->coord = BASIC;
+#endif
+}
+
void pp_norm_k18(ep3_t r, const ep3_t p) {
if (ep3_is_infty(p)) {
ep3_set_infty(r);
@@ -119,3 +145,22 @@ void pp_norm_k24(ep4_t r, const ep4_t p) {
r->coord = BASIC;
#endif
}
+
+void pp_norm_k48(ep8_t r, const ep8_t p) {
+ if (ep8_is_infty(p)) {
+ ep8_set_infty(r);
+ return;
+ }
+
+ if (p->coord == BASIC) {
+ /* If the point is represented in affine coordinates, we just copy it. */
+ ep8_copy(r, p);
+ }
+#if EP_ADD == PROJC || !defined(STRIP)
+ fp8_inv(r->z, p->z);
+ fp8_mul(r->x, p->x, r->z);
+ fp8_mul(r->y, p->y, r->z);
+ fp8_set_dig(r->z, 1);
+ r->coord = BASIC;
+#endif
+}
diff --git a/src/tmpl/relic_tmpl_map.h b/src/tmpl/relic_tmpl_map.h
index 311bf144a..2caaef1f7 100644
--- a/src/tmpl/relic_tmpl_map.h
+++ b/src/tmpl/relic_tmpl_map.h
@@ -172,7 +172,7 @@
* "Fast and simple constant-time hashing to the BLS12-381 Elliptic Curve"
*/
#define TMPL_MAP_SSWU(CUR, PFX, PTR_TY, COPY_COND) \
- static void CUR##_map_sswu(CUR##_t p, PFX##_t t) { \
+ static void CUR##_map_sswu(CUR##_t p, const PFX##_t t) { \
PFX##_t t0, t1, t2, t3; \
ctx_t *ctx = core_get(); \
PTR_TY *mBoverA = ctx->CUR##_map_c[0]; \
@@ -197,40 +197,40 @@
PFX##_sqr(t1, t0); /* t1 = u^2 * t^4 */ \
PFX##_add(t2, t1, t0); /* t2 = u^2 * t^4 + u * t^2 */ \
\
- /* handle the exceptional cases */ \
- /* XXX(rsw) should be done projectively */ \
- { \
- const int e1 = PFX##_is_zero(t2); \
- PFX##_neg(t3, u); /* t3 = -u */ \
- COPY_COND(t2, t3, e1); /* exception: -u instead of u^2t^4 + ut^2 */ \
- PFX##_inv(t2, t2); /* t2 = -1/u or 1/(u^2 * t^4 + u*t^2) */ \
- PFX##_add_dig(t3, t2, 1); /* t3 = 1 + t2 */ \
- COPY_COND(t2, t3, e1 == 0); /* only add 1 if t2 != -1/u */ \
- } \
- /* e1 goes out of scope */ \
- \
- /* compute x1, g(x1) */ \
- PFX##_mul(p->x, t2, mBoverA); /* -B / A * (1 + 1 / (u^2 * t^4 + u * t^2)) */ \
- PFX##_sqr(p->y, p->x); /* x^2 */ \
- PFX##_add(p->y, p->y, a); /* x^2 + a */ \
- PFX##_mul(p->y, p->y, p->x); /* x^3 + a x */ \
- PFX##_add(p->y, p->y, b); /* x^3 + a x + b */ \
- \
- /* compute x2, g(x2) */ \
- PFX##_mul(t2, t0, p->x); /* t2 = u * t^2 * x1 */ \
- PFX##_mul(t1, t0, t1); /* t1 = u^3 * t^6 */ \
- PFX##_mul(t3, t1, p->y); /* t5 = g(t2) = u^3 * t^6 * g(p->x) */ \
- \
- /* XXX(rsw) */ \
- /* This should be done in constant time and without computing 2 sqrts. */ \
- /* Avoiding a second sqrt relies on knowing the 2-adicity of the modulus. */ \
- if (!PFX##_srt(p->y, p->y)) { \
- /* try x2, g(x2) */ \
- PFX##_copy(p->x, t2); \
- if (!PFX##_srt(p->y, t3)) { \
- RLC_THROW(ERR_NO_VALID); \
- } \
- } \
+ /* handle the exceptional cases */ \
+ /* XXX(rsw) should be done projectively */ \
+ { \
+ const int e1 = PFX##_is_zero(t2); \
+ PFX##_neg(t3, u); /* t3 = -u */ \
+ /* exception: -u instead of u^2t^4 + ut^2 */ \
+ COPY_COND(t2, t3, e1); \
+ /* t2 = -1/u or 1/(u^2 * t^4 + u*t^2) */ \
+ PFX##_inv(t2, t2); \
+ PFX##_add_dig(t3, t2, 1); /* t3 = 1 + t2 */ \
+ COPY_COND(t2, t3, e1 == 0); /* only add 1 if t2 != -1/u */ \
+ } \
+ /* e1 goes out of scope */ \
+ /* compute x1, g(x1) */ \
+ /* -B / A * (1 + 1 / (u^2 * t^4 + u * t^2)) */ \
+ PFX##_mul(p->x, t2, mBoverA); \
+ PFX##_sqr(p->y, p->x); /* x^2 */ \
+ PFX##_add(p->y, p->y, a); /* x^2 + a */ \
+ PFX##_mul(p->y, p->y, p->x); /* x^3 + a x */ \
+ PFX##_add(p->y, p->y, b); /* x^3 + a x + b */ \
+ \
+ /* compute x2, g(x2) */ \
+ PFX##_mul(t2, t0, p->x); /* t2 = u * t^2 * x1 */ \
+ PFX##_mul(t1, t0, t1); /* t1 = u^3 * t^6 */ \
+ PFX##_mul(t3, t1, p->y); /* t5 = g(t2) = u^3 * t^6 * g(p->x) */ \
+ { \
+ /* try x2, g(x2) */ \
+ const int e1 = PFX##_is_sqr(p->y); \
+ COPY_COND(p->x, t2, e1 == 0); \
+ COPY_COND(p->y, t3, e1 == 0); \
+ } \
+ if (!PFX##_srt(p->y, p->y)) { \
+ RLC_THROW(ERR_NO_VALID); \
+ } \
PFX##_set_dig(p->z, 1); \
p->coord = BASIC; \
} \
@@ -248,8 +248,15 @@
* draft-irtf-cfrg-hash-to-curve-06, Section 6.6.1
*/
#define TMPL_MAP_SVDW(CUR, PFX, PTR_TY, COPY_COND) \
- static void CUR##_map_svdw(CUR##_t p, PFX##_t t) { \
+ static void CUR##_map_svdw(CUR##_t p, const PFX##_t t) { \
PFX##_t t1, t2, t3, t4; \
+ ctx_t *ctx = core_get(); \
+ PTR_TY *gU = ctx->CUR##_map_c[0]; \
+ PTR_TY *mUover2 = ctx->CUR##_map_c[1]; \
+ PTR_TY *c3 = ctx->CUR##_map_c[2]; \
+ PTR_TY *c4 = ctx->CUR##_map_c[3]; \
+ PTR_TY *u = ctx->CUR##_map_u; \
+ \
PFX##_null(t1); \
PFX##_null(t2); \
PFX##_null(t3); \
@@ -261,13 +268,6 @@
PFX##_new(t3); \
PFX##_new(t4); \
\
- ctx_t *ctx = core_get(); \
- PTR_TY *gU = ctx->CUR##_map_c[0]; \
- PTR_TY *mUover2 = ctx->CUR##_map_c[1]; \
- PTR_TY *c3 = ctx->CUR##_map_c[2]; \
- PTR_TY *c4 = ctx->CUR##_map_c[3]; \
- PTR_TY *u = ctx->CUR##_map_u; \
- \
/* start computing the map */ \
PFX##_sqr(t1, t); \
PFX##_mul(t1, t1, gU); \
@@ -290,26 +290,31 @@
PFX##_mul(t4, t4, t3); \
PFX##_mul(t4, t4, c3); \
\
- /* XXX(rsw) this should be constant time */ \
/* compute x1 and g(x1) */ \
PFX##_sub(p->x, mUover2, t4); \
CUR##_rhs(p->y, p); \
- if (!PFX##_srt(p->y, p->y)) { \
+ { \
+ const int e0 = PFX##_is_sqr(p->y); \
/* compute x2 and g(x2) */ \
- PFX##_add(p->x, mUover2, t4); \
- CUR##_rhs(p->y, p); \
- if (!PFX##_srt(p->y, p->y)) { \
- /* compute x3 and g(x3) */ \
- PFX##_sqr(p->x, t2); \
- PFX##_mul(p->x, p->x, t3); \
- PFX##_sqr(p->x, p->x); \
- PFX##_mul(p->x, p->x, c4); \
- PFX##_add(p->x, p->x, u); \
- CUR##_rhs(p->y, p); \
- if (!PFX##_srt(p->y, p->y)) { \
- RLC_THROW(ERR_NO_VALID); \
- } \
- } \
+ PFX##_add(t4, mUover2, t4); \
+ COPY_COND(p->x, t4, e0 == 0); \
+ CUR##_rhs(t1, p); \
+ COPY_COND(p->y, t1, e0 == 0); \
+ } \
+ { \
+ const int e1 = PFX##_is_sqr(p->y); \
+ /* compute x3 and g(x3) */ \
+ PFX##_sqr(t1, t2); \
+ PFX##_mul(t1, t1, t3); \
+ PFX##_sqr(t1, t1); \
+ PFX##_mul(t1, t1, c4); \
+ PFX##_add(t1, t1, u); \
+ COPY_COND(p->x, t1, e1 == 0); \
+ CUR##_rhs(t2, p); \
+ COPY_COND(p->y, t2, e1 == 0); \
+ } \
+ if (!PFX##_srt(p->y, p->y)) { \
+ RLC_THROW(ERR_NO_VALID); \
} \
PFX##_set_dig(p->z, 1); \
p->coord = BASIC; \
diff --git a/test/test_bn.c b/test/test_bn.c
index 85d2cf584..c10f08497 100644
--- a/test/test_bn.c
+++ b/test/test_bn.c
@@ -2251,7 +2251,7 @@ static int recoding(void) {
/* Check that subscalars have the right length. */
TEST_ASSERT(bn_bits(b) <= 1 + (bn_bits(v2[0]) >> 1), end);
TEST_ASSERT(bn_bits(c) <= 1 + (bn_bits(v2[0]) >> 1), end);
- /* Recover lambda parameter. */
+ /* Recover two candidates for the lambda parameter. */
if (bn_cmp_dig(v1[2], 1) == RLC_EQ) {
bn_gcd_ext(v1[0], v2[1], NULL, v1[1], v2[0]);
} else {
@@ -2268,17 +2268,16 @@ static int recoding(void) {
}
bn_mod(v1[0], v1[0], v2[0]);
bn_sub(v1[1], v2[0], v1[0]);
- if (bn_cmp(v1[1], v1[0]) == RLC_LT) {
- bn_copy(v1[0], v1[1]);
- }
/* Check if b + c * lambda = k (mod n). */
- bn_mul(c, c, v1[0]);
- bn_add(b, b, c);
- bn_mod(b, b, v2[0]);
- if (bn_sign(b) == RLC_NEG) {
- bn_add(b, b, v2[0]);
- }
- TEST_ASSERT(bn_cmp(a, b) == RLC_EQ, end);
+ bn_mul(v2[1], c, v1[0]);
+ bn_add(v2[1], v2[1], b);
+ bn_mod(v2[1], v2[1], v2[0]);
+ /* Now try the other candidate. */
+ bn_mul(v2[2], c, v1[1]);
+ bn_add(v2[2], v2[2], b);
+ bn_mod(v2[2], v2[2], v2[0]);
+ TEST_ASSERT(bn_cmp(a, v2[1]) == RLC_EQ ||
+ bn_cmp(a, v2[2]) == RLC_EQ, end);
}
} TEST_END;
#endif /* WITH_EP && EP_ENDOM */
diff --git a/test/test_cp.c b/test/test_cp.c
index 045807d7e..575e695ea 100644
--- a/test/test_cp.c
+++ b/test/test_cp.c
@@ -1283,9 +1283,7 @@ static int sokaka(void) {
cp_sokaka_gen(s);
- TEST_CASE
- ("sakai-ohgishi-kasahara authenticated key agreement is correct")
- {
+ TEST_CASE("sakai-ohgishi-kasahara auth key agreement is correct") {
TEST_ASSERT(cp_sokaka_gen_prv(k, ia, s) == RLC_OK, end);
TEST_ASSERT(cp_sokaka_key(k1, l, ia, k, ib) == RLC_OK, end);
TEST_ASSERT(cp_sokaka_gen_prv(k, ib, s) == RLC_OK, end);
diff --git a/test/test_ep.c b/test/test_ep.c
index db23f619f..e01ece13c 100644
--- a/test/test_ep.c
+++ b/test/test_ep.c
@@ -437,7 +437,7 @@ static int doubling(void) {
} TEST_END;
#endif
-#if EP_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == JACOB || !defined(STRIP)
TEST_CASE("point doubling in jacobian coordinates is correct") {
ep_rand(a);
/* a in projective coordinates. */
@@ -525,7 +525,7 @@ static int endomorphism(void) {
}
TEST_END;
-#if EB_ADD == BASIC || !defined(STRIP)
+#if EP_ADD == BASIC || !defined(STRIP)
TEST_CASE("endomorphism in affine coordinates is correct") {
ep_rand(a);
ep_psi(b, a);
@@ -537,11 +537,24 @@ static int endomorphism(void) {
TEST_END;
#endif
-#if EB_ADD == PROJC || !defined(STRIP)
+#if EP_ADD == PROJC || !defined(STRIP)
TEST_CASE("endomorphism in projective coordinates is correct") {
ep_rand(a);
ep_dbl_projc(a, a);
ep_psi(b, a);
+ ep_norm(a, a);
+ ep_mul(c, a, l);
+ ep_neg(a, b);
+ }
+ TEST_END;
+#endif
+
+#if EP_ADD == JACOB || !defined(STRIP)
+ TEST_CASE("endomorphism in jacobian coordinates is correct") {
+ ep_rand(a);
+ ep_dbl_jacob(a, a);
+ ep_psi(b, a);
+ ep_norm(a, a);
ep_mul(c, a, l);
ep_neg(a, b);
TEST_ASSERT(ep_cmp(b, c) == RLC_EQ ||
@@ -1337,17 +1350,14 @@ static int compression(void) {
static int hashing(void) {
int code = RLC_ERR;
ep_t a;
- ep_t b;
bn_t n;
uint8_t msg[5];
ep_null(a);
- ep_null(b);
bn_null(n);
RLC_TRY {
ep_new(a);
- ep_new(b);
bn_new(n);
ep_curve_get_ord(n);
@@ -1355,13 +1365,46 @@ static int hashing(void) {
TEST_CASE("point hashing is correct") {
rand_bytes(msg, sizeof(msg));
ep_map(a, msg, sizeof(msg));
- TEST_ASSERT(ep_is_infty(a) == 0, end);
- ep_map_dst(b, msg, sizeof(msg), (const uint8_t *)"RELIC", 5);
- TEST_ASSERT(ep_cmp(a, b) == RLC_EQ, end);
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 0, end);
+ ep_mul(a, a, n);
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 1, end);
+ }
+ TEST_END;
+
+#if EP_MAP == BASIC || !defined(STRIP)
+ TEST_CASE("basic point hashing is correct") {
+ rand_bytes(msg, sizeof(msg));
+ ep_map_basic(a, msg, sizeof(msg));
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 0, end);
+ ep_mul(a, a, n);
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 1, end);
+ }
+ TEST_END;
+#endif
+
+#if EP_MAP == SSWUM || !defined(STRIP)
+ TEST_CASE("simplified SWU point hashing is correct") {
+ rand_bytes(msg, sizeof(msg));
+ ep_map_sswum(a, msg, sizeof(msg));
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 0, end);
ep_mul(a, a, n);
- TEST_ASSERT(ep_is_infty(a) == 1, end);
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 1, end);
}
TEST_END;
+#endif
+
+#if EP_MAP == SWIFT || !defined(STRIP)
+ if (ep_curve_opt_a() == RLC_ZERO || ep_curve_opt_b() == RLC_ZERO) {
+ TEST_CASE("swift point hashing is correct") {
+ rand_bytes(msg, sizeof(msg));
+ ep_map_swift(a, msg, sizeof(msg));
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 0, end);
+ ep_mul(a, a, n);
+ TEST_ASSERT(ep_on_curve(a) && ep_is_infty(a) == 1, end);
+ }
+ TEST_END;
+#endif
+ }
}
RLC_CATCH_ANY {
RLC_ERROR(end);
@@ -1369,7 +1412,6 @@ static int hashing(void) {
code = RLC_OK;
end:
ep_free(a);
- ep_free(b);
bn_free(n);
return code;
}
@@ -1431,6 +1473,7 @@ int test(void) {
int main(void) {
int r0 = RLC_ERR, r1 = RLC_ERR, r2 = RLC_ERR, r3 = RLC_ERR;
+ int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
if (core_init() != RLC_OK) {
core_clean();
@@ -1442,6 +1485,7 @@ int main(void) {
#if defined(EP_PLAIN)
r0 = ep_param_set_any_plain();
if (r0 == RLC_OK) {
+ c0 = ep_param_get();
if (test() != RLC_OK) {
core_clean();
return 1;
@@ -1452,27 +1496,36 @@ int main(void) {
#if defined(EP_ENDOM)
r1 = ep_param_set_any_endom();
if (r1 == RLC_OK) {
- if (test() != RLC_OK) {
- core_clean();
- return 1;
+ c1 = ep_param_get();
+ if (c1 != c0) {
+ if (test() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
}
}
#endif
r2 = ep_param_set_any_pairf();
if (r2 == RLC_OK) {
- if (test() != RLC_OK) {
- core_clean();
- return 1;
+ c2 = ep_param_get();
+ if (c2 != c1) {
+ if (test() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
}
}
#if defined(EP_SUPER)
r3 = ep_param_set_any_super();
if (r3 == RLC_OK) {
- if (test() != RLC_OK) {
- core_clean();
- return 1;
+ c3 = ep_param_get();
+ if (c3 != c2) {
+ if (test() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
}
}
#endif
@@ -1490,6 +1543,11 @@ int main(void) {
}
}
+ (void)c0;
+ (void)c1;
+ (void)c2;
+ (void)c3;
+
util_banner("All tests have passed.\n", 0);
core_clean();
diff --git a/test/test_epx.c b/test/test_epx.c
index e63f21856..26c45ab68 100644
--- a/test/test_epx.c
+++ b/test/test_epx.c
@@ -1096,31 +1096,61 @@ static int compression2(void) {
static int hashing2(void) {
int code = RLC_ERR;
bn_t n;
- ep2_t p;
- ep2_t q;
+ ep2_t a;
uint8_t msg[5];
bn_null(n);
- ep2_null(p);
- ep2_null(q);
+ ep2_null(a);
RLC_TRY {
bn_new(n);
- ep2_new(p);
- ep2_new(q);
+ ep2_new(a);
ep2_curve_get_ord(n);
TEST_CASE("point hashing is correct") {
rand_bytes(msg, sizeof(msg));
- ep2_map(p, msg, sizeof(msg));
- TEST_ASSERT(ep2_is_infty(p) == 0, end);
- ep2_map_dst(q, msg, sizeof(msg), (const uint8_t *)"RELIC", 5);
- TEST_ASSERT(ep2_cmp(p, q) == RLC_EQ, end);
- ep2_mul(p, p, n);
- TEST_ASSERT(ep2_is_infty(p) == 1, end);
+ ep2_map(a, msg, sizeof(msg));
+ TEST_ASSERT(ep2_on_curve(a) == 1, end);
+ ep2_mul(a, a, n);
+ TEST_ASSERT(ep2_is_infty(a) == 1, end);
+ }
+ TEST_END;
+
+#if EP_MAP == BASIC || !defined(STRIP)
+ TEST_CASE("basic point hashing is correct") {
+ rand_bytes(msg, sizeof(msg));
+ ep2_map_basic(a, msg, sizeof(msg));
+ TEST_ASSERT(ep2_is_infty(a) == 0, end);
+ ep2_mul(a, a, n);
+ TEST_ASSERT(ep2_is_infty(a) == 1, end);
+ }
+ TEST_END;
+#endif
+
+#if EP_MAP == SSWUM || !defined(STRIP)
+ TEST_CASE("simplified SWU point hashing is correct") {
+ rand_bytes(msg, sizeof(msg));
+ ep2_map_sswum(a, msg, sizeof(msg));
+ TEST_ASSERT(ep2_is_infty(a) == 0, end);
+ ep2_mul(a, a, n);
+ TEST_ASSERT(ep2_is_infty(a) == 1, end);
}
TEST_END;
+#endif
+
+ if (ep_curve_is_pairf()) {
+ #if EP_MAP == SWIFT || !defined(STRIP)
+ TEST_CASE("swift point hashing is correct") {
+ rand_bytes(msg, sizeof(msg));
+ ep2_map_swift(a, msg, sizeof(msg));
+ TEST_ASSERT(ep2_is_infty(a) == 0, end);
+ ep2_mul(a, a, n);
+ TEST_ASSERT(ep2_is_infty(a) == 1, end);
+ }
+ TEST_END;
+ #endif
+ }
}
RLC_CATCH_ANY {
util_print("FATAL ERROR!\n");
@@ -1129,8 +1159,7 @@ static int hashing2(void) {
code = RLC_OK;
end:
bn_free(n);
- ep2_free(p);
- ep2_free(q);
+ ep2_free(a);
return code;
}
@@ -2316,23 +2345,25 @@ static int util4(void) {
} TEST_END;
TEST_CASE("reading and writing a point are consistent") {
- ep4_set_infty(a);
- l = ep4_size_bin(a, 0);
- ep4_write_bin(bin, l, a, 0);
- ep4_read_bin(b, bin, l);
- TEST_ASSERT(ep4_cmp(a, b) == RLC_EQ, end);
- ep4_rand(a);
- l = ep4_size_bin(a, 0);
- ep4_write_bin(bin, l, a, 0);
- ep4_read_bin(b, bin, l);
- TEST_ASSERT(ep4_cmp(a, b) == RLC_EQ, end);
- ep4_rand(a);
- ep4_dbl(a, a);
- l = ep4_size_bin(a, 0);
- ep4_norm(a, a);
- ep4_write_bin(bin, l, a, 0);
- ep4_read_bin(b, bin, l);
- TEST_ASSERT(ep4_cmp(a, b) == RLC_EQ, end);
+ for (int j = 0; j < 2; j++) {
+ ep4_set_infty(a);
+ l = ep4_size_bin(a, j);
+ ep4_write_bin(bin, l, a, j);
+ ep4_read_bin(b, bin, l);
+ TEST_ASSERT(ep4_cmp(a, b) == RLC_EQ, end);
+ ep4_rand(a);
+ l = ep4_size_bin(a, j);
+ ep4_write_bin(bin, l, a, j);
+ ep4_read_bin(b, bin, l);
+ TEST_ASSERT(ep4_cmp(a, b) == RLC_EQ, end);
+ ep4_rand(a);
+ ep4_dbl(a, a);
+ l = ep4_size_bin(a, j);
+ ep4_norm(a, a);
+ ep4_write_bin(bin, l, a, j);
+ ep4_read_bin(b, bin, l);
+ TEST_ASSERT(ep4_cmp(a, b) == RLC_EQ, end);
+ }
}
TEST_END;
}
@@ -3171,7 +3202,7 @@ static int hashing4(void) {
TEST_CASE("point hashing is correct") {
rand_bytes(msg, sizeof(msg));
ep4_map(p, msg, sizeof(msg));
- TEST_ASSERT(ep4_is_infty(p) == 0, end);
+ TEST_ASSERT(ep4_on_curve(p) == 1, end);
ep4_mul(p, p, n);
TEST_ASSERT(ep4_is_infty(p) == 1, end);
}
@@ -3232,164 +3263,1193 @@ static int frobenius4(void) {
return code;
}
-int main(void) {
- int r0, r1, r2;
-
- if (core_init() != RLC_OK) {
- core_clean();
- return 1;
- }
+static int memory8(void) {
+ err_t e = ERR_CAUGHT;
+ int code = RLC_ERR;
+ ep8_t a;
- util_banner("Tests for the EPX module", 0);
+ ep8_null(a);
- if (ep_param_set_any_pairf() == RLC_ERR) {
- RLC_THROW(ERR_NO_CURVE);
- core_clean();
- return 0;
+ RLC_TRY {
+ TEST_CASE("memory can be allocated") {
+ ep8_new(a);
+ ep8_free(a);
+ } TEST_END;
+ } RLC_CATCH(e) {
+ switch (e) {
+ case ERR_NO_MEMORY:
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ break;
+ }
}
+ (void)a;
+ code = RLC_OK;
+ end:
+ return code;
+}
- if ((r0 = ep2_curve_is_twist())) {
- ep_param_print();
+static int util8(void) {
+ int l, code = RLC_ERR;
+ ep8_t a, b, c;
+ uint8_t bin[16 * RLC_FP_BYTES + 1];
- util_banner("Utilities:", 1);
+ ep8_null(a);
+ ep8_null(b);
+ ep8_null(c);
- if (memory2() != RLC_OK) {
- core_clean();
- return 1;
- }
+ RLC_TRY {
+ ep8_new(a);
+ ep8_new(b);
+ ep8_new(c);
- if (util2() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("copy and comparison are consistent") {
+ ep8_rand(a);
+ ep8_rand(b);
+ ep8_rand(c);
+ /* Compare points in affine coordinates. */
+ if (ep8_cmp(a, c) != RLC_EQ) {
+ ep8_copy(c, a);
+ TEST_ASSERT(ep8_cmp(c, a) == RLC_EQ, end);
+ }
+ if (ep8_cmp(b, c) != RLC_EQ) {
+ ep8_copy(c, b);
+ TEST_ASSERT(ep8_cmp(b, c) == RLC_EQ, end);
+ }
+ /* Compare with one point in projective. */
+ ep8_dbl(c, a);
+ ep8_norm(c, c);
+ ep8_dbl(a, a);
+ TEST_ASSERT(ep8_cmp(c, a) == RLC_EQ, end);
+ TEST_ASSERT(ep8_cmp(a, c) == RLC_EQ, end);
+ /* Compare with two points in projective. */
+ ep8_dbl(c, c);
+ ep8_dbl(a, a);
+ TEST_ASSERT(ep8_cmp(c, a) == RLC_EQ, end);
+ TEST_ASSERT(ep8_cmp(a, c) == RLC_EQ, end);
}
+ TEST_END;
- util_banner("Arithmetic:", 1);
-
- if (addition2() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("negation and comparison are consistent") {
+ ep8_rand(a);
+ ep8_neg(b, a);
+ TEST_ASSERT(ep8_cmp(a, b) != RLC_EQ, end);
+ ep8_neg(b, b);
+ TEST_ASSERT(ep8_cmp(a, b) == RLC_EQ, end);
+ ep8_neg(b, a);
+ ep8_add(a, a, b);
+ ep8_set_infty(b);
+ TEST_ASSERT(ep8_cmp(a, b) == RLC_EQ, end);
}
+ TEST_END;
- if (subtraction2() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("assignment to random and comparison are consistent") {
+ ep8_rand(a);
+ ep8_set_infty(c);
+ TEST_ASSERT(ep8_cmp(a, c) != RLC_EQ, end);
+ TEST_ASSERT(ep8_cmp(c, a) != RLC_EQ, end);
}
+ TEST_END;
- if (doubling2() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("assignment to infinity and infinity test are consistent") {
+ ep8_set_infty(a);
+ TEST_ASSERT(ep8_is_infty(a), end);
}
+ TEST_END;
- if (multiplication2() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("validity test is correct") {
+ ep8_set_infty(a);
+ TEST_ASSERT(ep8_on_curve(a), end);
+ ep8_rand(a);
+ TEST_ASSERT(ep8_on_curve(a), end);
+ fp8_rand(a->x);
+ TEST_ASSERT(!ep8_on_curve(a), end);
}
+ TEST_END;
- if (fixed2() != RLC_OK) {
- core_clean();
- return 1;
- }
+ TEST_CASE("blinding is consistent") {
+ ep8_rand(a);
+ ep8_blind(a, a);
+ TEST_ASSERT(ep8_on_curve(a), end);
+ } TEST_END;
- if (simultaneous2() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("reading and writing a point are consistent") {
+ for (int j = 0; j < 2; j++) {
+ ep8_set_infty(a);
+ l = ep8_size_bin(a, j);
+ ep8_write_bin(bin, l, a, j);
+ ep8_read_bin(b, bin, l);
+ TEST_ASSERT(ep8_cmp(a, b) == RLC_EQ, end);
+ ep8_rand(a);
+ l = ep8_size_bin(a, j);
+ ep8_write_bin(bin, l, a, j);
+ ep8_read_bin(b, bin, l);
+ TEST_ASSERT(ep8_cmp(a, b) == RLC_EQ, end);
+ ep8_rand(a);
+ ep8_dbl(a, a);
+ l = ep8_size_bin(a, j);
+ ep8_norm(a, a);
+ ep8_write_bin(bin, l, a, j);
+ ep8_read_bin(b, bin, l);
+ TEST_ASSERT(ep8_cmp(a, b) == RLC_EQ, end);
+ }
}
+ TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ ep8_free(a);
+ ep8_free(b);
+ ep8_free(c);
+ return code;
+}
- if (compression2() != RLC_OK) {
- core_clean();
- return 1;
- }
+static int addition8(void) {
+ int code = RLC_ERR;
+ ep8_t a, b, c, d, e;
- if (hashing2() != RLC_OK) {
- core_clean();
- return 1;
- }
+ ep8_null(a);
+ ep8_null(b);
+ ep8_null(c);
+ ep8_null(d);
+ ep8_null(e);
- if (frobenius2() != RLC_OK) {
- core_clean();
- return 1;
- }
- }
+ RLC_TRY {
+ ep8_new(a);
+ ep8_new(b);
+ ep8_new(c);
+ ep8_new(d);
+ ep8_new(e);
- if ((r1 = ep3_curve_is_twist())) {
- ep_param_print();
+ TEST_CASE("point addition is commutative") {
+ ep8_rand(a);
+ ep8_rand(b);
+ ep8_add(d, a, b);
+ ep8_add(e, b, a);
+ TEST_ASSERT(ep8_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
- util_banner("Utilities:", 1);
+ TEST_CASE("point addition is associative") {
+ ep8_rand(a);
+ ep8_rand(b);
+ ep8_rand(c);
+ ep8_add(d, a, b);
+ ep8_add(d, d, c);
+ ep8_add(e, b, c);
+ ep8_add(e, e, a);
+ TEST_ASSERT(ep8_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
- if (memory3() != RLC_OK) {
- core_clean();
- return 1;
- }
+ TEST_CASE("point addition has identity") {
+ ep8_rand(a);
+ ep8_set_infty(d);
+ ep8_add(e, a, d);
+ TEST_ASSERT(ep8_cmp(e, a) == RLC_EQ, end);
+ ep8_add(e, d, a);
+ TEST_ASSERT(ep8_cmp(e, a) == RLC_EQ, end);
+ } TEST_END;
- if (util3() != RLC_OK) {
- core_clean();
- return 1;
- }
+ TEST_CASE("point addition has inverse") {
+ ep8_rand(a);
+ ep8_neg(d, a);
+ ep8_add(e, a, d);
+ TEST_ASSERT(ep8_is_infty(e), end);
+ } TEST_END;
- util_banner("Arithmetic:", 1);
+#if EP_ADD == BASIC || !defined(STRIP)
+ TEST_CASE("point addition in affine coordinates is correct") {
+ ep8_rand(a);
+ ep8_rand(b);
+ ep8_add(d, a, b);
+ ep8_add_basic(e, a, b);
+ TEST_ASSERT(ep8_cmp(e, d) == RLC_EQ, end);
+ } TEST_END;
+#endif
- if (addition3() != RLC_OK) {
- core_clean();
- return 1;
- }
+#if EP_ADD == PROJC || !defined(STRIP)
+#if !defined(EP_MIXED) || !defined(STRIP)
+ TEST_CASE("point addition in projective coordinates is correct") {
+ ep8_rand(a);
+ ep8_rand(b);
+ ep8_rand(c);
+ ep8_add_projc(a, a, b);
+ ep8_add_projc(b, b, c);
+ /* a and b in projective coordinates. */
+ ep8_add_projc(d, a, b);
+ /* normalize before mixing coordinates. */
+ ep8_norm(a, a);
+ ep8_norm(b, b);
+ ep8_add(e, a, b);
+ TEST_ASSERT(ep8_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+#endif
- if (subtraction3() != RLC_OK) {
- core_clean();
- return 1;
- }
+ TEST_CASE("point addition in mixed coordinates (z2 = 1) is correct") {
+ ep8_rand(a);
+ ep8_rand(b);
+ /* a in projective, b in affine coordinates. */
+ ep8_add_projc(a, a, b);
+ ep8_add_projc(d, a, b);
+ /* a in affine coordinates. */
+ ep8_norm(a, a);
+ ep8_add(e, a, b);
+ TEST_ASSERT(ep8_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
- if (doubling3() != RLC_OK) {
- core_clean();
- return 1;
- }
+ TEST_CASE("point addition in mixed coordinates (z1,z2 = 1) is correct") {
+ ep8_rand(a);
+ ep8_rand(b);
+ /* a and b in affine coordinates. */
+ ep8_add(d, a, b);
+ ep8_add_projc(e, a, b);
+ TEST_ASSERT(ep8_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+#endif
- if (multiplication3() != RLC_OK) {
- core_clean();
- return 1;
- }
+ }
+ RLC_CATCH_ANY {
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ ep8_free(a);
+ ep8_free(b);
+ ep8_free(c);
+ ep8_free(d);
+ ep8_free(e);
+ return code;
+}
- if (fixed3() != RLC_OK) {
- core_clean();
- return 1;
- }
+static int subtraction8(void) {
+ int code = RLC_ERR;
+ ep8_t a, b, c, d;
- if (simultaneous3() != RLC_OK) {
- core_clean();
- return 1;
+ ep8_null(a);
+ ep8_null(b);
+ ep8_null(c);
+ ep8_null(d);
+
+ RLC_TRY {
+ ep8_new(a);
+ ep8_new(b);
+ ep8_new(c);
+ ep8_new(d);
+
+ TEST_CASE("point subtraction is anti-commutative") {
+ ep8_rand(a);
+ ep8_rand(b);
+ ep8_sub(c, a, b);
+ ep8_sub(d, b, a);
+ ep8_neg(d, d);
+ TEST_ASSERT(ep8_cmp(c, d) == RLC_EQ, end);
}
+ TEST_END;
- if (hashing3() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("point subtraction has identity") {
+ ep8_rand(a);
+ ep8_set_infty(c);
+ ep8_sub(d, a, c);
+ TEST_ASSERT(ep8_cmp(d, a) == RLC_EQ, end);
}
+ TEST_END;
- if (frobenius3() != RLC_OK) {
- core_clean();
- return 1;
+ TEST_CASE("point subtraction has inverse") {
+ ep8_rand(a);
+ ep8_sub(c, a, a);
+ TEST_ASSERT(ep8_is_infty(c), end);
}
+ TEST_END;
}
+ RLC_CATCH_ANY {
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ ep8_free(a);
+ ep8_free(b);
+ ep8_free(c);
+ ep8_free(d);
+ return code;
+}
- if ((r2 = ep4_curve_is_twist())) {
- ep_param_print();
-
- util_banner("Utilities:", 1);
+static int doubling8(void) {
+ int code = RLC_ERR;
+ ep8_t a, b, c;
- if (memory4() != RLC_OK) {
- core_clean();
- return 1;
- }
+ ep8_null(a);
+ ep8_null(b);
+ ep8_null(c);
- if (util4() != RLC_OK) {
- core_clean();
- return 1;
- }
+ RLC_TRY {
+ ep8_new(a);
+ ep8_new(b);
+ ep8_new(c);
- util_banner("Arithmetic:", 1);
+ TEST_CASE("point doubling is correct") {
+ ep8_rand(a);
+ ep8_add(b, a, a);
+ ep8_dbl(c, a);
+ TEST_ASSERT(ep8_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
- if (addition4() != RLC_OK) {
- core_clean();
- return 1;
- }
+#if EP_ADD == BASIC || !defined(STRIP)
+ TEST_CASE("point doubling in affine coordinates is correct") {
+ ep8_rand(a);
+ ep8_dbl(b, a);
+ ep8_dbl_basic(c, a);
+ TEST_ASSERT(ep8_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_ADD == PROJC || !defined(STRIP)
+ TEST_CASE("point doubling in projective coordinates is correct") {
+ ep8_rand(a);
+ /* a in projective coordinates. */
+ ep8_dbl_projc(a, a);
+ ep8_dbl_projc(b, a);
+ ep8_norm(a, a);
+ ep8_dbl(c, a);
+ TEST_ASSERT(ep8_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("point doubling in mixed coordinates (z1 = 1) is correct") {
+ ep8_rand(a);
+ ep8_dbl_projc(b, a);
+ ep8_norm(b, b);
+ ep8_dbl(c, a);
+ TEST_ASSERT(ep8_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+#endif
+ }
+ RLC_CATCH_ANY {
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ ep8_free(a);
+ ep8_free(b);
+ ep8_free(c);
+ return code;
+}
+
+static int multiplication8(void) {
+ int code = RLC_ERR;
+ bn_t n, k;
+ ep8_t p, q, r;
+
+ bn_null(n);
+ bn_null(k);
+ ep8_null(p);
+ ep8_null(q);
+ ep8_null(r);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ ep8_new(p);
+ ep8_new(q);
+ ep8_new(r);
+
+ ep8_curve_get_gen(p);
+ ep8_curve_get_ord(n);
+
+ TEST_ONCE("generator has the right order") {
+ TEST_ASSERT(ep8_on_curve(p), end);
+ ep8_mul(r, p, n);
+ TEST_ASSERT(ep8_is_infty(r) == 1, end);
+ } TEST_END;
+
+ TEST_CASE("generator multiplication is correct") {
+ bn_zero(k);
+ ep8_mul_gen(r, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_gen(r, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ bn_rand_mod(k, n);
+ ep8_mul(q, p, k);
+ ep8_mul_gen(r, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_gen(r, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_rand_mod(k, n);
+ ep8_mul_gen(q, k);
+ bn_add(k, k, n);
+ ep8_mul_gen(r, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ } TEST_END;
+
+#if EP_MUL == BASIC || !defined(STRIP)
+ TEST_CASE("binary point multiplication is correct") {
+ bn_zero(k);
+ ep8_mul_basic(r, p, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_basic(r, p, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ ep8_rand(p);
+ ep8_mul(r, p, n);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_rand_mod(k, n);
+ ep8_mul(q, p, k);
+ ep8_mul_basic(r, p, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_basic(r, p, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_MUL == MONTY || !defined(STRIP)
+ TEST_CASE("sliding window point multiplication is correct") {
+ bn_zero(k);
+ ep8_mul_slide(r, p, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_slide(r, p, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ ep8_rand(p);
+ ep8_mul(r, p, n);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_rand_mod(k, n);
+ ep8_mul(q, p, k);
+ ep8_mul_slide(r, p, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_slide(r, p, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ }
+ TEST_END;
+#endif
+
+#if EP_MUL == MONTY || !defined(STRIP)
+ TEST_CASE("montgomery ladder point multiplication is correct") {
+ bn_zero(k);
+ ep8_mul_monty(r, p, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_monty(r, p, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ ep8_rand(p);
+ ep8_mul(r, p, n);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_rand_mod(k, n);
+ ep8_mul(q, p, k);
+ ep8_mul_monty(r, p, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_monty(r, p, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ }
+ TEST_END;
+#endif
+
+#if EP_MUL == LWNAF || !defined(STRIP)
+ TEST_CASE("left-to-right w-naf point multiplication is correct") {
+ bn_zero(k);
+ ep8_mul_lwnaf(r, p, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_lwnaf(r, p, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ ep8_rand(p);
+ ep8_mul(r, p, n);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_rand_mod(k, n);
+ ep8_mul(q, p, k);
+ ep8_mul_lwnaf(r, p, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_lwnaf(r, p, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ }
+ TEST_END;
+#endif
+
+ TEST_CASE("multiplication by digit is correct") {
+ ep8_mul_dig(r, p, 0);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ ep8_mul_dig(r, p, 1);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ bn_rand(k, RLC_POS, RLC_DIG);
+ ep8_mul(q, p, k);
+ ep8_mul_dig(r, p, k->dp[0]);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ }
+ TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k);
+ ep8_free(p);
+ ep8_free(q);
+ ep8_free(r);
+ return code;
+}
+
+static int fixed8(void) {
+ int code = RLC_ERR;
+ bn_t n, k;
+ ep8_t p, q, r, t[RLC_EPX_TABLE_MAX];
+
+ bn_null(n);
+ bn_null(k);
+ ep8_null(p);
+ ep8_null(q);
+ ep8_null(r);
+
+ for (int i = 0; i < RLC_EPX_TABLE_MAX; i++) {
+ ep8_null(t[i]);
+ }
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ ep8_new(p);
+ ep8_new(q);
+ ep8_new(r);
+
+ ep8_curve_get_gen(p);
+ ep8_curve_get_ord(n);
+
+ for (int i = 0; i < RLC_EP_TABLE; i++) {
+ ep8_new(t[i]);
+ }
+ TEST_CASE("fixed point multiplication is correct") {
+ ep8_rand(p);
+ ep8_mul_pre(t, p);
+ bn_zero(k);
+ ep8_mul_fix(r, t, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_fix(r, t, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ bn_rand_mod(k, n);
+ ep8_mul(q, p, k);
+ ep8_mul_fix(q, t, k);
+ ep8_mul(r, p, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_fix(r, t, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ } TEST_END;
+ for (int i = 0; i < RLC_EP_TABLE; i++) {
+ ep8_free(t[i]);
+ }
+
+#if EP_FIX == BASIC || !defined(STRIP)
+ for (int i = 0; i < RLC_EP_TABLE_BASIC; i++) {
+ ep8_new(t[i]);
+ }
+ TEST_CASE("binary fixed point multiplication is correct") {
+ ep8_rand(p);
+ ep8_mul_pre_basic(t, p);
+ bn_zero(k);
+ ep8_mul_fix_basic(r, t, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_fix_basic(r, t, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ bn_rand_mod(k, n);
+ ep8_mul(r, p, k);
+ ep8_mul_fix_basic(q, t, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_fix_basic(r, t, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ } TEST_END;
+ for (int i = 0; i < RLC_EP_TABLE_BASIC; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == COMBS || !defined(STRIP)
+ for (int i = 0; i < RLC_EP_TABLE_COMBS; i++) {
+ ep8_new(t[i]);
+ }
+ TEST_CASE("single-table comb fixed point multiplication is correct") {
+ ep8_rand(p);
+ ep8_mul_pre_combs(t, p);
+ bn_zero(k);
+ ep8_mul_fix_combs(r, t, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_fix_combs(r, t, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ bn_rand_mod(k, n);
+ ep8_mul(r, p, k);
+ ep8_mul_fix_combs(q, t, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_fix_combs(r, t, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ } TEST_END;
+ for (int i = 0; i < RLC_EP_TABLE_COMBS; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == COMBD || !defined(STRIP)
+ for (int i = 0; i < RLC_EP_TABLE_COMBD; i++) {
+ ep8_new(t[i]);
+ }
+ TEST_CASE("double-table comb fixed point multiplication is correct") {
+ ep8_rand(p);
+ ep8_mul_pre_combd(t, p);
+ bn_zero(k);
+ ep8_mul_fix_combd(r, t, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_fix_combd(r, t, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ bn_rand_mod(k, n);
+ ep8_mul(r, p, k);
+ ep8_mul_fix_combd(q, t, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_fix_combd(r, t, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ } TEST_END;
+ for (int i = 0; i < RLC_EP_TABLE_COMBD; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+
+#if EP_FIX == LWNAF || !defined(STRIP)
+ for (int i = 0; i < RLC_EP_TABLE_LWNAF; i++) {
+ ep8_new(t[i]);
+ }
+ TEST_CASE("left-to-right w-naf fixed point multiplication is correct") {
+ ep8_rand(p);
+ ep8_mul_pre_lwnaf(t, p);
+ bn_zero(k);
+ ep8_mul_fix_lwnaf(r, t, k);
+ TEST_ASSERT(ep8_is_infty(r), end);
+ bn_set_dig(k, 1);
+ ep8_mul_fix_lwnaf(r, t, k);
+ TEST_ASSERT(ep8_cmp(p, r) == RLC_EQ, end);
+ bn_rand_mod(k, n);
+ ep8_mul(r, p, k);
+ ep8_mul_fix_lwnaf(q, t, k);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ bn_neg(k, k);
+ ep8_mul_fix_lwnaf(r, t, k);
+ ep8_neg(r, r);
+ TEST_ASSERT(ep8_cmp(q, r) == RLC_EQ, end);
+ } TEST_END;
+ for (int i = 0; i < RLC_EP_TABLE_LWNAF; i++) {
+ ep8_free(t[i]);
+ }
+#endif
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ ep8_free(p);
+ ep8_free(q);
+ ep8_free(r);
+ bn_free(n);
+ bn_free(k);
+ return code;
+}
+
+static int simultaneous8(void) {
+ int code = RLC_ERR;
+ bn_t n, k[2];
+ ep8_t p[2], r;
+
+ bn_null(n);
+ bn_null(k[0]);
+ bn_null(k[1]);
+ ep8_null(p[0]);
+ ep8_null(p[1]);
+ ep8_null(r);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k[0]);
+ bn_new(k[1]);
+ ep8_new(p[0]);
+ ep8_new(p[1]);
+ ep8_new(r);
+
+ ep8_curve_get_gen(p[0]);
+ ep8_curve_get_ord(n);
+
+ TEST_CASE("simultaneous point multiplication is correct") {
+ bn_zero(k[0]);
+ bn_rand_mod(k[1], n);
+ ep8_mul(p[1], p[0], k[1]);
+ ep8_mul_sim(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_zero(k[1]);
+ ep8_mul(p[1], p[0], k[0]);
+ ep8_mul_sim(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_rand_mod(k[1], n);
+ ep8_mul_sim(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[0], k[0]);
+ ep8_mul_sim(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[1], k[1]);
+ ep8_mul_sim(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ ep8_mul_sim(r, p[0], k[0], p[1], k[1]);
+ ep8_mul_sim_lot(p[1], p, k, 2);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ } TEST_END;
+
+#if EP_SIM == BASIC || !defined(STRIP)
+ TEST_CASE("basic simultaneous point multiplication is correct") {
+ bn_zero(k[0]);
+ bn_rand_mod(k[1], n);
+ ep8_mul(p[1], p[0], k[1]);
+ ep8_mul_sim_basic(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_zero(k[1]);
+ ep8_mul(p[1], p[0], k[0]);
+ ep8_mul_sim_basic(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_rand_mod(k[1], n);
+ ep8_mul_sim_basic(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[0], k[0]);
+ ep8_mul_sim_basic(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[1], k[1]);
+ ep8_mul_sim_basic(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_SIM == TRICK || !defined(STRIP)
+ TEST_CASE("shamir's trick for simultaneous multiplication is correct") {
+ bn_zero(k[0]);
+ bn_rand_mod(k[1], n);
+ ep8_mul(p[1], p[0], k[1]);
+ ep8_mul_sim_trick(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_zero(k[1]);
+ ep8_mul(p[1], p[0], k[0]);
+ ep8_mul_sim_trick(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_rand_mod(k[1], n);
+ ep8_mul_sim_trick(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[0], k[0]);
+ ep8_mul_sim_trick(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[1], k[1]);
+ ep8_mul_sim_trick(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_SIM == INTER || !defined(STRIP)
+ TEST_CASE("interleaving for simultaneous multiplication is correct") {
+ bn_zero(k[0]);
+ bn_rand_mod(k[1], n);
+ ep8_mul(p[1], p[0], k[1]);
+ ep8_mul_sim_inter(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_zero(k[1]);
+ ep8_mul(p[1], p[0], k[0]);
+ ep8_mul_sim_inter(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_rand_mod(k[1], n);
+ ep8_mul_sim_inter(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[0], k[0]);
+ ep8_mul_sim_inter(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[1], k[1]);
+ ep8_mul_sim_inter(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_SIM == JOINT || !defined(STRIP)
+ TEST_CASE("jsf for simultaneous multiplication is correct") {
+ bn_zero(k[0]);
+ bn_rand_mod(k[1], n);
+ ep8_mul(p[1], p[0], k[1]);
+ ep8_mul_sim_joint(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_zero(k[1]);
+ ep8_mul(p[1], p[0], k[0]);
+ ep8_mul_sim_joint(r, p[0], k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_rand_mod(k[1], n);
+ ep8_mul_sim_joint(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[0], k[0]);
+ ep8_mul_sim_joint(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[1], k[1]);
+ ep8_mul_sim_joint(r, p[0], k[0], p[1], k[1]);
+ ep8_mul(p[0], p[0], k[0]);
+ ep8_mul(p[1], p[1], k[1]);
+ ep8_add(p[1], p[1], p[0]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+ TEST_CASE("simultaneous multiplication with generator is correct") {
+ bn_zero(k[0]);
+ bn_rand_mod(k[1], n);
+ ep8_mul(p[1], p[0], k[1]);
+ ep8_mul_sim_gen(r, k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_zero(k[1]);
+ ep8_mul_gen(p[1], k[0]);
+ ep8_mul_sim_gen(r, k[0], p[0], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_rand_mod(k[0], n);
+ bn_rand_mod(k[1], n);
+ ep8_mul_sim_gen(r, k[0], p[1], k[1]);
+ ep8_curve_get_gen(p[0]);
+ ep8_mul_sim(p[1], p[0], k[0], p[1], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[0], k[0]);
+ ep8_mul_sim_gen(r, k[0], p[1], k[1]);
+ ep8_curve_get_gen(p[0]);
+ ep8_mul_sim(p[1], p[0], k[0], p[1], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ bn_neg(k[1], k[1]);
+ ep8_mul_sim_gen(r, k[0], p[1], k[1]);
+ ep8_curve_get_gen(p[0]);
+ ep8_mul_sim(p[1], p[0], k[0], p[1], k[1]);
+ TEST_ASSERT(ep8_cmp(p[1], r) == RLC_EQ, end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k[0]);
+ bn_free(k[1]);
+ ep8_free(p[0]);
+ ep8_free(p[1]);
+ ep8_free(r);
+ return code;
+}
+
+static int hashing8(void) {
+ int code = RLC_ERR;
+ bn_t n;
+ ep8_t p;
+ uint8_t msg[5];
+
+ bn_null(n);
+ ep8_null(p);
+
+ RLC_TRY {
+ bn_new(n);
+ ep8_new(p);
+
+ ep8_curve_get_ord(n);
+
+ TEST_CASE("point hashing is correct") {
+ rand_bytes(msg, sizeof(msg));
+ ep8_map(p, msg, sizeof(msg));
+ TEST_ASSERT(ep8_on_curve(p) == 1, end);
+ ep8_mul(p, p, n);
+ TEST_ASSERT(ep8_is_infty(p) == 1, end);
+ }
+ TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ ep8_free(p);
+ return code;
+}
+
+static int frobenius8(void) {
+ int code = RLC_ERR;
+ ep8_t a, b, c;
+ bn_t d, n;
+
+ ep8_null(a);
+ ep8_null(b);
+ ep8_null(c);
+ bn_null(d);
+ bn_null(n);
+
+ RLC_TRY {
+ ep8_new(a);
+ ep8_new(b);
+ ep8_new(c);
+ bn_new(d);
+ bn_new(n);
+
+ ep8_curve_get_ord(n);
+
+ TEST_CASE("frobenius and point multiplication are consistent") {
+ ep8_rand(a);
+ ep8_frb(b, a, 1);
+ d->used = RLC_FP_DIGS;
+ dv_copy(d->dp, fp_prime_get(), RLC_FP_DIGS);
+ bn_mod(d, d, n);
+ ep8_mul(c, a, d);
+ TEST_ASSERT(ep8_cmp(c, b) == RLC_EQ, end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ ep8_free(a);
+ ep8_free(b);
+ ep8_free(c);
+ bn_free(d);
+ bn_free(n);
+ return code;
+}
+
+int main(void) {
+ int r0, r1, r2, r3;
+
+ if (core_init() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ util_banner("Tests for the EPX module", 0);
+
+ if (ep_param_set_any_pairf() == RLC_ERR) {
+ RLC_THROW(ERR_NO_CURVE);
+ core_clean();
+ return 0;
+ }
+
+ if ((r0 = ep2_curve_is_twist())) {
+ ep_param_print();
+
+ util_banner("Utilities:", 1);
+
+ if (memory2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (util2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ util_banner("Arithmetic:", 1);
+
+ if (addition2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (subtraction2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (doubling2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (multiplication2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (fixed2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (simultaneous2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (compression2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (hashing2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (frobenius2() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+ }
+
+ if ((r1 = ep3_curve_is_twist())) {
+ ep_param_print();
+
+ util_banner("Utilities:", 1);
+
+ if (memory3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (util3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ util_banner("Arithmetic:", 1);
+
+ if (addition3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (subtraction3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (doubling3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (multiplication3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (fixed3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (simultaneous3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (hashing3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (frobenius3() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+ }
+
+ if ((r2 = ep4_curve_is_twist())) {
+ ep_param_print();
+
+ util_banner("Utilities:", 1);
+
+ if (memory4() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (util4() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ util_banner("Arithmetic:", 1);
+
+ if (addition4() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
if (subtraction4() != RLC_OK) {
core_clean();
@@ -3427,7 +4487,65 @@ int main(void) {
}
}
- if (!r0 && !r1 && !r2) {
+ if ((r3 = ep8_curve_is_twist())) {
+ ep_param_print();
+
+ util_banner("Utilities:", 1);
+
+ if (memory8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (util8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ util_banner("Arithmetic:", 1);
+
+ if (addition8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (subtraction8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (doubling8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (multiplication8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (fixed8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (simultaneous8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (frobenius8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (hashing8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+ }
+
+ if (!r0 && !r1 && !r2 && !r3) {
RLC_THROW(ERR_NO_CURVE);
core_clean();
return 0;
diff --git a/test/test_fp.c b/test/test_fp.c
index 53cddcbfd..a25936fc5 100644
--- a/test/test_fp.c
+++ b/test/test_fp.c
@@ -799,6 +799,9 @@ static int inversion(void) {
fp_inv(b, a);
fp_mul(c, a, b);
TEST_ASSERT(fp_cmp_dig(c, 1) == RLC_EQ, end);
+ fp_set_dig(a, 1);
+ fp_inv(b, a);
+ TEST_ASSERT(fp_cmp_dig(b, 1) == RLC_EQ, end);
} TEST_END;
#if FP_INV == BASIC || !defined(STRIP)
@@ -935,6 +938,7 @@ static int symbol(void) {
TEST_ASSERT(fp_smb(a) == fp_smb_basic(a), end);
} TEST_END;
#endif
+
#if FP_SMB == DIVST || !defined(STRIP)
TEST_CASE("division step symbol computation is correct") {
fp_rand(a);
@@ -1060,6 +1064,19 @@ static int square_root(void) {
fp_new(b);
fp_new(c);
+ TEST_CASE("quadratic residuosity test is correct") {
+ fp_zero(a);
+ TEST_ASSERT(fp_is_sqr(a) == 1, end);
+ fp_rand(a);
+ fp_sqr(a, a);
+ TEST_ASSERT(fp_is_sqr(a) == 1, end);
+ do {
+ fp_rand(a);
+ } while(fp_srt(b, a) == 1);
+ TEST_ASSERT(fp_is_sqr(a) == 0, end);
+ }
+ TEST_END;
+
TEST_CASE("square root extraction is correct") {
fp_rand(a);
fp_sqr(c, a);
@@ -1071,6 +1088,10 @@ static int square_root(void) {
fp_sqr(c, b);
TEST_ASSERT(fp_cmp(c, a) == RLC_EQ, end);
}
+ do {
+ fp_rand(a);
+ } while(fp_is_sqr(a) == 1);
+ TEST_ASSERT(fp_srt(b, a) == 0, end);
}
TEST_END;
}
@@ -1085,21 +1106,101 @@ static int square_root(void) {
return code;
}
+static int cube_root(void) {
+ int code = RLC_ERR;
+ fp_t a, b, c, d;
+
+ fp_null(a);
+ fp_null(b);
+ fp_null(c);
+ fp_null(d);
+
+ RLC_TRY {
+ fp_new(a);
+ fp_new(b);
+ fp_new(c);
+ fp_new(d);
+
+ TEST_CASE("cubic residuosity test is correct") {
+ fp_zero(a);
+ TEST_ASSERT(fp_is_cub(a) == 1, end);
+ fp_rand(a);
+ fp_sqr(b, a);
+ fp_mul(a, a, b);
+ TEST_ASSERT(fp_is_cub(a) == 1, end);
+ /* If p = 2 mod 3, all elements are cubic residues. */
+ if (fp_prime_get_mod18() % 3 != 2) {
+ do {
+ fp_rand(a);
+ } while(fp_crt(b, a) == 1);
+ TEST_ASSERT(fp_is_cub(a) == 0, end);
+ }
+ }
+ TEST_END;
+
+ TEST_CASE("cube root extraction is correct") {
+ int r = 1;
+ fp_rand(a);
+ fp_sqr(c, a);
+ fp_mul(c, c, a);
+ TEST_ASSERT(fp_crt(b, c), end);
+ if (fp_prime_get_cnr()) {
+ fp_copy(d, fp_prime_get_crt());
+ while (fp_cmp_dig(d, 1) != RLC_EQ) {
+ fp_copy(c, d);
+ fp_sqr(d, d);
+ fp_mul(d, d, c);
+ }
+ if (fp_cmp(b, a) != RLC_EQ) {
+ fp_mul(b, b, c);
+ if (fp_cmp(b, a) != RLC_EQ) {
+ fp_mul(b, b, c);
+ if (fp_cmp(b, a) != RLC_EQ) {
+ r = 0;
+ }
+ }
+ }
+ TEST_ASSERT(r == 1, end);
+ }
+ fp_rand(a);
+ if (fp_crt(b, a)) {
+ fp_sqr(c, b);
+ fp_mul(c, c, b);
+ TEST_ASSERT(fp_cmp(c, a) == RLC_EQ, end);
+ }
+ }
+ TEST_END;
+ }
+ RLC_CATCH_ANY {
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp_free(a);
+ fp_free(b);
+ fp_free(c);
+ fp_free(d);
+ return code;
+}
+
static int digit(void) {
int code = RLC_ERR;
fp_t a, b, c, d;
dig_t g;
+ bn_t e;
fp_null(a);
fp_null(b);
fp_null(c);
fp_null(d);
+ bn_null(e);
RLC_TRY {
fp_new(a);
fp_new(b);
fp_new(c);
fp_new(d);
+ bn_new(e);
TEST_CASE("addition of a single digit is consistent") {
fp_rand(a);
@@ -1130,6 +1231,15 @@ static int digit(void) {
fp_mul_dig(d, a, g);
TEST_ASSERT(fp_cmp(c, d) == RLC_EQ, end);
} TEST_END;
+
+ TEST_CASE("exponentiation by a single digit is consistent") {
+ fp_rand(a);
+ bn_rand(e, RLC_POS, RLC_DIG);
+ fp_exp_dig(b, a, e->dp[0]);
+ fp_exp(c, a, e);
+ TEST_ASSERT(fp_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+
}
RLC_CATCH_ANY {
RLC_ERROR(end);
@@ -1140,6 +1250,7 @@ static int digit(void) {
fp_free(b);
fp_free(c);
fp_free(d);
+ bn_free(e);
return code;
}
@@ -1226,6 +1337,11 @@ int main(void) {
return 1;
}
+ if (cube_root() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
if (digit() != RLC_OK) {
core_clean();
return 1;
diff --git a/test/test_fpx.c b/test/test_fpx.c
index 378fe9cbb..2bac3ff4e 100644
--- a/test/test_fpx.c
+++ b/test/test_fpx.c
@@ -783,6 +783,19 @@ static int square_root2(void) {
fp2_new(b);
fp2_new(c);
+ TEST_CASE("quadratic residuosity test is correct") {
+ fp2_zero(a);
+ TEST_ASSERT(fp2_is_sqr(a) == 1, end);
+ fp2_rand(a);
+ fp2_sqr(a, a);
+ TEST_ASSERT(fp2_is_sqr(a) == 1, end);
+ do {
+ fp2_rand(a);
+ } while(fp2_srt(b, a) == 1);
+ TEST_ASSERT(fp2_is_sqr(a) == 0, end);
+ }
+ TEST_END;
+
TEST_CASE("square root extraction is correct") {
fp2_zero(a);
fp2_sqr(c, a);
@@ -813,6 +826,10 @@ static int square_root2(void) {
TEST_ASSERT(r, end);
TEST_ASSERT(fp2_cmp(b, a) == RLC_EQ ||
fp2_cmp(c, a) == RLC_EQ, end);
+ do {
+ fp2_rand(a);
+ } while(fp2_is_sqr(a) == 1);
+ TEST_ASSERT(fp2_srt(b, a) == 0, end);
} TEST_END;
}
RLC_CATCH_ANY {
@@ -1509,7 +1526,6 @@ static int exponentiation3(void) {
static int square_root3(void) {
int code = RLC_ERR;
fp3_t a, b, c;
- int r;
fp3_null(a);
fp3_null(b);
@@ -1520,14 +1536,36 @@ static int square_root3(void) {
fp3_new(b);
fp3_new(c);
+ TEST_CASE("quadratic residuosity test is correct") {
+ fp3_zero(a);
+ TEST_ASSERT(fp3_is_sqr(a) == 1, end);
+ fp3_rand(a);
+ fp3_sqr(a, a);
+ TEST_ASSERT(fp3_is_sqr(a) == 1, end);
+ do {
+ fp3_rand(a);
+ } while(fp3_srt(b, a) == 1);
+ TEST_ASSERT(fp3_is_sqr(a) == 0, end);
+ }
+ TEST_END;
+
TEST_CASE("square root extraction is correct") {
fp3_rand(a);
fp3_sqr(c, a);
- r = fp3_srt(b, c);
- fp3_sqr(b, b);
- TEST_ASSERT(r == 1, end);
- TEST_ASSERT(fp3_cmp(b, c) == RLC_EQ, end);
- } TEST_END;
+ TEST_ASSERT(fp3_srt(b, c), end);
+ fp3_neg(c, b);
+ TEST_ASSERT(fp3_cmp(b, a) == RLC_EQ || fp3_cmp(c, a) == RLC_EQ, end);
+ fp3_rand(a);
+ if (fp3_srt(b, a)) {
+ fp3_sqr(c, b);
+ TEST_ASSERT(fp3_cmp(c, a) == RLC_EQ, end);
+ }
+ do {
+ fp3_rand(a);
+ } while(fp3_is_sqr(a) == 1);
+ TEST_ASSERT(fp3_srt(b, a) == 0, end);
+ }
+ TEST_END;
}
RLC_CATCH_ANY {
util_print("FATAL ERROR!\n");
@@ -2156,6 +2194,19 @@ static int square_root4(void) {
fp4_new(b);
fp4_new(c);
+ TEST_CASE("quadratic residuosity test is correct") {
+ fp4_zero(a);
+ TEST_ASSERT(fp4_is_sqr(a) == 1, end);
+ fp4_rand(a);
+ fp4_sqr(a, a);
+ TEST_ASSERT(fp4_is_sqr(a) == 1, end);
+ do {
+ fp4_rand(a);
+ } while(fp4_srt(b, a) == 1);
+ TEST_ASSERT(fp4_is_sqr(a) == 0, end);
+ }
+ TEST_END;
+
TEST_CASE("square root extraction is correct") {
fp4_zero(a);
fp4_sqr(c, a);
@@ -3412,29 +3463,74 @@ static int exponentiation8(void) {
return code;
}
-static int memory12(void) {
- err_t e = ERR_CAUGHT;
+static int square_root8(void) {
int code = RLC_ERR;
- fp12_t a;
+ fp8_t a, b, c;
+ int r;
- fp12_null(a);
+ fp8_null(a);
+ fp8_null(b);
+ fp8_null(c);
RLC_TRY {
- TEST_CASE("memory can be allocated") {
- fp12_new(a);
- fp12_free(a);
- } TEST_END;
- } RLC_CATCH(e) {
- switch (e) {
- case ERR_NO_MEMORY:
- util_print("FATAL ERROR!\n");
- RLC_ERROR(end);
- break;
+ fp8_new(a);
+ fp8_new(b);
+ fp8_new(c);
+
+ TEST_CASE("quadratic residuosity test is correct") {
+ fp8_zero(a);
+ TEST_ASSERT(fp8_is_sqr(a) == 1, end);
+ fp8_rand(a);
+ fp8_sqr(a, a);
+ TEST_ASSERT(fp8_is_sqr(a) == 1, end);
+ do {
+ fp8_rand(a);
+ } while(fp8_srt(b, a) == 1);
+ TEST_ASSERT(fp8_is_sqr(a) == 0, end);
}
+ TEST_END;
+
+ TEST_CASE("square root extraction is correct") {
+ fp8_zero(a);
+ fp8_sqr(c, a);
+ r = fp8_srt(b, c);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp8_cmp(b, a) == RLC_EQ ||
+ fp8_cmp(c, a) == RLC_EQ, end);
+ fp4_rand(a[0]);
+ fp4_zero(a[1]);
+ fp8_sqr(c, a);
+ r = fp8_srt(b, c);
+ fp8_neg(c, b);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp8_cmp(b, a) == RLC_EQ ||
+ fp8_cmp(c, a) == RLC_EQ, end);
+ fp4_zero(a[0]);
+ fp4_rand(a[1]);
+ fp8_sqr(c, a);
+ r = fp8_srt(b, c);
+ fp8_neg(c, b);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp8_cmp(b, a) == RLC_EQ ||
+ fp8_cmp(c, a) == RLC_EQ, end);
+ fp8_rand(a);
+ fp8_sqr(c, a);
+ r = fp8_srt(b, c);
+ fp8_neg(c, b);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp8_cmp(b, a) == RLC_EQ ||
+ fp8_cmp(c, a) == RLC_EQ, end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
}
- (void)a;
code = RLC_OK;
end:
+ fp8_free(a);
+ fp8_free(b);
+ fp8_free(c);
return code;
}
@@ -3987,6 +4083,32 @@ static int exponentiation9(void) {
return code;
}
+static int memory12(void) {
+ err_t e = ERR_CAUGHT;
+ int code = RLC_ERR;
+ fp12_t a;
+
+ fp12_null(a);
+
+ RLC_TRY {
+ TEST_CASE("memory can be allocated") {
+ fp12_new(a);
+ fp12_free(a);
+ } TEST_END;
+ } RLC_CATCH(e) {
+ switch (e) {
+ case ERR_NO_MEMORY:
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ break;
+ }
+ }
+ (void)a;
+ code = RLC_OK;
+ end:
+ return code;
+}
+
static int util12(void) {
int code = RLC_ERR;
uint8_t bin[12 * RLC_FP_BYTES];
@@ -4761,17 +4883,17 @@ static int compression12(void) {
return code;
}
-static int memory18(void) {
+static int memory16(void) {
err_t e = ERR_CAUGHT;
int code = RLC_ERR;
- fp18_t a;
+ fp16_t a;
- fp18_null(a);
+ fp16_null(a);
RLC_TRY {
TEST_CASE("memory can be allocated") {
- fp18_new(a);
- fp18_free(a);
+ fp16_new(a);
+ fp16_free(a);
} TEST_END;
} RLC_CATCH(e) {
switch (e) {
@@ -4787,110 +4909,99 @@ static int memory18(void) {
return code;
}
-static int util18(void) {
+static int util16(void) {
int code = RLC_ERR;
- uint8_t bin[18 * RLC_FP_BYTES];
- fp18_t a, b, c;
+ uint8_t bin[16 * RLC_FP_BYTES];
+ fp16_t a, b, c;
dig_t d;
- fp18_null(a);
- fp18_null(b);
- fp18_null(c);
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
RLC_TRY {
- fp18_new(a);
- fp18_new(b);
- fp18_new(c);
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
TEST_CASE("comparison is consistent") {
- fp18_rand(a);
- fp18_rand(b);
- if (fp18_cmp(a, b) != RLC_EQ) {
- TEST_ASSERT(fp18_cmp(b, a) == RLC_NE, end);
+ fp16_rand(a);
+ fp16_rand(b);
+ if (fp16_cmp(a, b) != RLC_EQ) {
+ TEST_ASSERT(fp16_cmp(b, a) == RLC_NE, end);
}
}
TEST_END;
TEST_CASE("copy and comparison are consistent") {
- fp18_rand(a);
- fp18_rand(b);
- fp18_rand(c);
- if (fp18_cmp(a, c) != RLC_EQ) {
- fp18_copy(c, a);
- TEST_ASSERT(fp18_cmp(c, a) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_rand(c);
+ if (fp16_cmp(a, c) != RLC_EQ) {
+ fp16_copy(c, a);
+ TEST_ASSERT(fp16_cmp(c, a) == RLC_EQ, end);
}
- if (fp18_cmp(b, c) != RLC_EQ) {
- fp18_copy(c, b);
- TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
+ if (fp16_cmp(b, c) != RLC_EQ) {
+ fp16_copy(c, b);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
}
}
TEST_END;
TEST_CASE("negation is consistent") {
- fp18_rand(a);
- fp18_neg(b, a);
- if (fp18_cmp(a, b) != RLC_EQ) {
- TEST_ASSERT(fp18_cmp(b, a) == RLC_NE, end);
+ fp16_rand(a);
+ fp16_neg(b, a);
+ if (fp16_cmp(a, b) != RLC_EQ) {
+ TEST_ASSERT(fp16_cmp(b, a) == RLC_NE, end);
}
- fp18_neg(b, b);
- TEST_ASSERT(fp18_cmp(a, b) == RLC_EQ, end);
- }
- TEST_END;
-
- TEST_CASE("assignment to zero and comparison are consistent") {
- do {
- fp18_rand(a);
- } while (fp18_is_zero(a));
- fp18_zero(c);
- TEST_ASSERT(fp18_cmp(a, c) == RLC_NE, end);
- TEST_ASSERT(fp18_cmp(c, a) == RLC_NE, end);
+ fp16_neg(b, b);
+ TEST_ASSERT(fp16_cmp(a, b) == RLC_EQ, end);
}
TEST_END;
TEST_CASE("assignment to zero and comparison are consistent") {
do {
- fp18_rand(a);
- } while (fp18_is_zero(a));
- fp18_zero(c);
- TEST_ASSERT(fp18_cmp(a, c) == RLC_NE, end);
- TEST_ASSERT(fp18_cmp(c, a) == RLC_NE, end);
+ fp16_rand(a);
+ } while (fp16_is_zero(a));
+ fp16_zero(c);
+ TEST_ASSERT(fp16_cmp(a, c) == RLC_NE, end);
+ TEST_ASSERT(fp16_cmp(c, a) == RLC_NE, end);
}
TEST_END;
-
TEST_CASE("assignment to random and comparison are consistent") {
do {
- fp18_rand(a);
- } while (fp18_is_zero(a));
- fp18_zero(c);
- TEST_ASSERT(fp18_cmp(a, c) == RLC_NE, end);
+ fp16_rand(a);
+ } while (fp16_is_zero(a));
+ fp16_zero(c);
+ TEST_ASSERT(fp16_cmp(a, c) == RLC_NE, end);
}
TEST_END;
TEST_CASE("assignment to zero and zero test are consistent") {
- fp18_zero(a);
- TEST_ASSERT(fp18_is_zero(a), end);
+ fp16_zero(a);
+ TEST_ASSERT(fp16_is_zero(a), end);
}
TEST_END;
TEST_CASE("assignment to a constant and comparison are consistent") {
- rand_bytes((uint8_t *)&d, (RLC_DIG / 8));
- fp18_set_dig(a, d);
- TEST_ASSERT(fp18_cmp_dig(a, d) == RLC_EQ, end);
+ rand_bytes((uint8_t *)&d, (RLC_DIG / 16));
+ fp16_set_dig(a, d);
+ TEST_ASSERT(fp16_cmp_dig(a, d) == RLC_EQ, end);
}
TEST_END;
TEST_CASE("reading and writing a finite field element are consistent") {
- fp18_rand(a);
- fp18_write_bin(bin, sizeof(bin), a, 0);
- fp18_read_bin(b, bin, sizeof(bin));
- TEST_ASSERT(fp18_cmp(a, b) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_write_bin(bin, sizeof(bin), a, 0);
+ fp16_read_bin(b, bin, sizeof(bin));
+ TEST_ASSERT(fp16_cmp(a, b) == RLC_EQ, end);
}
TEST_END;
TEST_CASE("getting the size of a finite field element is correct") {
- fp18_rand(a);
- TEST_ASSERT(fp18_size_bin(a, 0) == 18 * RLC_FP_BYTES, end);
+ fp16_rand(a);
+ TEST_ASSERT(fp16_size_bin(a, 0) == 16 * RLC_FP_BYTES, end);
}
TEST_END;
}
@@ -4899,60 +5010,60 @@ static int util18(void) {
}
code = RLC_OK;
end:
- fp18_free(a);
- fp18_free(b);
- fp18_free(c);
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
return code;
}
-static int addition18(void) {
+static int addition16(void) {
int code = RLC_ERR;
- fp18_t a, b, c, d, e;
+ fp16_t a, b, c, d, e;
- fp18_null(a);
- fp18_null(b);
- fp18_null(c);
- fp18_null(d);
- fp18_null(e);
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+ fp16_null(d);
+ fp16_null(e);
RLC_TRY {
- fp18_new(a);
- fp18_new(b);
- fp18_new(c);
- fp18_new(d);
- fp18_new(e);
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+ fp16_new(d);
+ fp16_new(e);
TEST_CASE("addition is commutative") {
- fp18_rand(a);
- fp18_rand(b);
- fp18_add(d, a, b);
- fp18_add(e, b, a);
- TEST_ASSERT(fp18_cmp(d, e) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_add(d, a, b);
+ fp16_add(e, b, a);
+ TEST_ASSERT(fp16_cmp(d, e) == RLC_EQ, end);
} TEST_END;
TEST_CASE("addition is associative") {
- fp18_rand(a);
- fp18_rand(b);
- fp18_rand(c);
- fp18_add(d, a, b);
- fp18_add(d, d, c);
- fp18_add(e, b, c);
- fp18_add(e, a, e);
- TEST_ASSERT(fp18_cmp(d, e) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_rand(c);
+ fp16_add(d, a, b);
+ fp16_add(d, d, c);
+ fp16_add(e, b, c);
+ fp16_add(e, a, e);
+ TEST_ASSERT(fp16_cmp(d, e) == RLC_EQ, end);
} TEST_END;
TEST_CASE("addition has identity") {
- fp18_rand(a);
- fp18_zero(d);
- fp18_add(e, a, d);
- TEST_ASSERT(fp18_cmp(e, a) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_zero(d);
+ fp16_add(e, a, d);
+ TEST_ASSERT(fp16_cmp(e, a) == RLC_EQ, end);
} TEST_END;
TEST_CASE("addition has inverse") {
- fp18_rand(a);
- fp18_neg(d, a);
- fp18_add(e, a, d);
- TEST_ASSERT(fp18_is_zero(e), end);
+ fp16_rand(a);
+ fp16_neg(d, a);
+ fp16_add(e, a, d);
+ TEST_ASSERT(fp16_is_zero(e), end);
} TEST_END;
}
RLC_CATCH_ANY {
@@ -4961,46 +5072,51 @@ static int addition18(void) {
}
code = RLC_OK;
end:
- fp18_free(a);
- fp18_free(b);
- fp18_free(c);
- fp18_free(d);
- fp18_free(e);
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ fp16_free(d);
+ fp16_free(e);
return code;
}
-static int subtraction18(void) {
+static int subtraction16(void) {
int code = RLC_ERR;
- fp18_t a, b, c, d;
+ fp16_t a, b, c, d;
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+ fp16_null(d);
RLC_TRY {
- fp18_new(a);
- fp18_new(b);
- fp18_new(c);
- fp18_new(d);
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+ fp16_new(d);
TEST_CASE("subtraction is anti-commutative") {
- fp18_rand(a);
- fp18_rand(b);
- fp18_sub(c, a, b);
- fp18_sub(d, b, a);
- fp18_neg(d, d);
- TEST_ASSERT(fp18_cmp(c, d) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_sub(c, a, b);
+ fp16_sub(d, b, a);
+ fp16_neg(d, d);
+ TEST_ASSERT(fp16_cmp(c, d) == RLC_EQ, end);
}
TEST_END;
TEST_CASE("subtraction has identity") {
- fp18_rand(a);
- fp18_zero(c);
- fp18_sub(d, a, c);
- TEST_ASSERT(fp18_cmp(d, a) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_zero(c);
+ fp16_sub(d, a, c);
+ TEST_ASSERT(fp16_cmp(d, a) == RLC_EQ, end);
}
TEST_END;
TEST_CASE("subtraction has inverse") {
- fp18_rand(a);
- fp18_sub(c, a, a);
- TEST_ASSERT(fp18_is_zero(c), end);
+ fp16_rand(a);
+ fp16_sub(c, a, a);
+ TEST_ASSERT(fp16_is_zero(c), end);
}
TEST_END;
}
@@ -5010,35 +5126,735 @@ static int subtraction18(void) {
}
code = RLC_OK;
end:
- fp18_free(a);
- fp18_free(b);
- fp18_free(c);
- fp18_free(d);
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ fp16_free(d);
return code;
}
-static int multiplication18(void) {
+static int doubling16(void) {
int code = RLC_ERR;
- fp18_t a, b, c, d, e, f;
+ fp16_t a, b, c;
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
RLC_TRY {
- fp18_new(a);
- fp18_new(b);
- fp18_new(c);
- fp18_new(d);
- fp18_new(e);
- fp18_new(f);
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
- TEST_CASE("multiplication is commutative") {
- fp18_rand(a);
- fp18_rand(b);
- fp18_mul(d, a, b);
- fp18_mul(e, b, a);
- TEST_ASSERT(fp18_cmp(d, e) == RLC_EQ, end);
+ TEST_CASE("doubling is correct") {
+ fp16_rand(a);
+ fp16_dbl(b, a);
+ fp16_add(c, a, a);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
} TEST_END;
-
- TEST_CASE("multiplication is associative") {
- fp18_rand(a);
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ return code;
+}
+
+static int multiplication16(void) {
+ int code = RLC_ERR;
+ fp16_t a, b, c, d, e, f;
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+ fp16_null(d);
+ fp16_null(e);
+ fp16_null(f);
+
+ RLC_TRY {
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+ fp16_new(d);
+ fp16_new(e);
+ fp16_new(f);
+
+ TEST_CASE("multiplication is commutative") {
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_mul(d, a, b);
+ fp16_mul(e, b, a);
+ TEST_ASSERT(fp16_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("multiplication is associative") {
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_rand(c);
+ fp16_mul(d, a, b);
+ fp16_mul(d, d, c);
+ fp16_mul(e, b, c);
+ fp16_mul(e, a, e);
+ TEST_ASSERT(fp16_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("multiplication is distributive") {
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_rand(c);
+ fp16_add(d, a, b);
+ fp16_mul(d, c, d);
+ fp16_mul(e, c, a);
+ fp16_mul(f, c, b);
+ fp16_add(e, e, f);
+ TEST_ASSERT(fp16_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("multiplication has identity") {
+ fp16_set_dig(d, 1);
+ fp16_mul(e, a, d);
+ TEST_ASSERT(fp16_cmp(e, a) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("multiplication has zero property") {
+ fp16_zero(d);
+ fp16_mul(e, a, d);
+ TEST_ASSERT(fp16_is_zero(e), end);
+ } TEST_END;
+
+ TEST_CASE("multiplication by adjoined root is correct") {
+ fp16_rand(a);
+ fp16_zero(b);
+ fp8_set_dig(b[1], 1);
+ fp16_mul(c, a, b);
+ fp16_mul_art(d, a);
+ TEST_ASSERT(fp16_cmp(c, d) == RLC_EQ, end);
+ } TEST_END;
+
+#if FPX_RDC == BASIC | !defined(STRIP)
+ TEST_CASE("basic multiplication is correct") {
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_mul(c, a, b);
+ fp16_mul_basic(d, a, b);
+ TEST_ASSERT(fp16_cmp(c, d) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if FPX_RDC == LAZYR || !defined(STRIP)
+ TEST_CASE("lazy-reduced multiplication is correct") {
+ fp16_rand(a);
+ fp16_rand(b);
+ fp16_mul(c, a, b);
+ fp16_mul_lazyr(d, a, b);
+ TEST_ASSERT(fp16_cmp(c, d) == RLC_EQ, end);
+ } TEST_END;
+#endif
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ fp16_free(d);
+ fp16_free(e);
+ fp16_free(f);
+ return code;
+}
+
+static int squaring16(void) {
+ int code = RLC_ERR;
+ fp16_t a, b, c;
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+
+ RLC_TRY {
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+
+ TEST_CASE("squaring is correct") {
+ fp16_rand(a);
+ fp16_mul(b, a, a);
+ fp16_sqr(c, a);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+
+#if FPX_RDC == BASIC | !defined(STRIP)
+ TEST_CASE("basic squaring is correct") {
+ fp16_rand(a);
+ fp16_sqr(b, a);
+ fp16_sqr_basic(c, a);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if FPX_RDC == LAZYR || !defined(STRIP)
+ TEST_CASE("lazy-reduced squaring is correct") {
+ fp16_rand(a);
+ fp16_sqr(b, a);
+ fp16_sqr_lazyr(c, a);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+#endif
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ return code;
+}
+
+static int cyclotomic16(void) {
+ int code = RLC_ERR;
+ fp16_t a, b, c;
+ bn_t f;
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+ bn_null(f);
+
+ RLC_TRY {
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+ bn_new(f);
+
+ TEST_CASE("cyclotomic test is correct") {
+ fp16_rand(a);
+ fp16_conv_cyc(a, a);
+ TEST_ASSERT(fp16_test_cyc(a) == 1, end);
+ } TEST_END;
+
+ TEST_CASE("cyclotomic squaring is correct") {
+ fp16_rand(a);
+ fp16_conv_cyc(a, a);
+ fp16_sqr(b, a);
+ fp16_sqr_cyc(c, a);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("cyclotomic exponentiation is correct") {
+ fp16_rand(a);
+ fp16_conv_cyc(a, a);
+ bn_zero(f);
+ fp16_exp_cyc(c, a, f);
+ TEST_ASSERT(fp16_cmp_dig(c, 1) == RLC_EQ, end);
+ bn_set_dig(f, 1);
+ fp16_exp_cyc(c, a, f);
+ TEST_ASSERT(fp16_cmp(c, a) == RLC_EQ, end);
+ bn_rand(f, RLC_POS, RLC_FP_BITS);
+ fp16_exp(b, a, f);
+ fp16_exp_cyc(c, a, f);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ bn_rand(f, RLC_POS, RLC_FP_BITS);
+ fp16_exp_cyc(b, a, f);
+ bn_neg(f, f);
+ fp16_exp_cyc(c, a, f);
+ fp16_inv_cyc(c, c);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ bn_free(f);
+ return code;
+}
+
+static int inversion16(void) {
+ int code = RLC_ERR;
+ fp16_t a, b, c, d[2];
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+ fp16_null(d[0]);
+ fp16_null(d[1]);
+
+ RLC_TRY {
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+ fp16_new(d[0]);
+ fp16_new(d[1]);
+
+ TEST_CASE("inversion is correct") {
+ do {
+ fp16_rand(a);
+ } while (fp16_is_zero(a));
+ fp16_inv(b, a);
+ fp16_mul(c, a, b);
+ TEST_ASSERT(fp16_cmp_dig(c, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("inversion of a unitary element is correct") {
+ do {
+ fp16_rand(a);
+ } while (fp16_is_zero(a));
+ fp16_conv_cyc(a, a);
+ fp16_inv(b, a);
+ fp16_inv_cyc(c, a);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("simultaneous inversion is correct") {
+ do {
+ fp16_rand(a);
+ fp16_rand(b);
+ } while (fp16_is_zero(a) || fp16_is_zero(b));
+ fp16_copy(d[0], a);
+ fp16_copy(d[1], b);
+ fp16_inv(a, a);
+ fp16_inv(b, b);
+ fp16_inv_sim(d, d, 2);
+ TEST_ASSERT(fp16_cmp(d[0], a) == RLC_EQ &&
+ fp16_cmp(d[1], b) == RLC_EQ, end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ fp16_free(d[0]);
+ fp16_free(d[1]);
+ return code;
+}
+
+static int exponentiation16(void) {
+ int code = RLC_ERR;
+ fp16_t a, b, c;
+ bn_t d;
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+ bn_null(d);
+
+ RLC_TRY {
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+ bn_new(d);
+
+ TEST_CASE("exponentiation is correct") {
+ fp16_rand(a);
+ bn_zero(d);
+ fp16_exp(c, a, d);
+ TEST_ASSERT(fp16_cmp_dig(c, 1) == RLC_EQ, end);
+ bn_set_dig(d, 1);
+ fp16_exp(c, a, d);
+ TEST_ASSERT(fp16_cmp(c, a) == RLC_EQ, end);
+ bn_rand(d, RLC_POS, RLC_FP_BITS);
+ fp16_exp(b, a, d);
+ bn_neg(d, d);
+ fp16_exp(c, a, d);
+ fp16_inv(c, c);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("frobenius and exponentiation are consistent") {
+ fp16_rand(a);
+ fp16_frb(b, a, 0);
+ TEST_ASSERT(fp16_cmp(a, b) == RLC_EQ, end);
+ fp16_frb(b, a, 1);
+ d->sign = RLC_POS;
+ d->used = RLC_FP_DIGS;
+ dv_copy(d->dp, fp_prime_get(), RLC_FP_DIGS);
+ fp16_exp(c, a, d);
+ TEST_ASSERT(fp16_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ bn_free(d);
+ return code;
+}
+
+static int square_root16(void) {
+ int code = RLC_ERR;
+ fp16_t a, b, c;
+ int r;
+
+ fp16_null(a);
+ fp16_null(b);
+ fp16_null(c);
+
+ RLC_TRY {
+ fp16_new(a);
+ fp16_new(b);
+ fp16_new(c);
+
+ TEST_CASE("quadratic residuosity test is correct") {
+ fp16_zero(a);
+ TEST_ASSERT(fp16_is_sqr(a) == 1, end);
+ fp16_rand(a);
+ fp16_sqr(a, a);
+ TEST_ASSERT(fp16_is_sqr(a) == 1, end);
+ do {
+ fp16_rand(a);
+ } while(fp16_srt(b, a) == 1);
+ TEST_ASSERT(fp16_is_sqr(a) == 0, end);
+ }
+ TEST_END;
+
+ TEST_CASE("square root extraction is correct") {
+ fp16_zero(a);
+ fp16_sqr(c, a);
+ r = fp16_srt(b, c);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp16_cmp(b, a) == RLC_EQ ||
+ fp16_cmp(c, a) == RLC_EQ, end);
+ fp8_rand(a[0]);
+ fp8_zero(a[1]);
+ fp16_sqr(c, a);
+ r = fp16_srt(b, c);
+ fp16_neg(c, b);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp16_cmp(b, a) == RLC_EQ ||
+ fp16_cmp(c, a) == RLC_EQ, end);
+ fp8_zero(a[0]);
+ fp8_rand(a[1]);
+ fp16_sqr(c, a);
+ r = fp16_srt(b, c);
+ fp16_neg(c, b);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp16_cmp(b, a) == RLC_EQ ||
+ fp16_cmp(c, a) == RLC_EQ, end);
+ fp16_rand(a);
+ fp16_sqr(c, a);
+ r = fp16_srt(b, c);
+ fp16_neg(c, b);
+ TEST_ASSERT(r, end);
+ TEST_ASSERT(fp16_cmp(b, a) == RLC_EQ ||
+ fp16_cmp(c, a) == RLC_EQ, end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp16_free(a);
+ fp16_free(b);
+ fp16_free(c);
+ return code;
+}
+
+static int memory18(void) {
+ err_t e = ERR_CAUGHT;
+ int code = RLC_ERR;
+ fp18_t a;
+
+ fp18_null(a);
+
+ RLC_TRY {
+ TEST_CASE("memory can be allocated") {
+ fp18_new(a);
+ fp18_free(a);
+ } TEST_END;
+ } RLC_CATCH(e) {
+ switch (e) {
+ case ERR_NO_MEMORY:
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ break;
+ }
+ }
+ (void)a;
+ code = RLC_OK;
+ end:
+ return code;
+}
+
+static int util18(void) {
+ int code = RLC_ERR;
+ uint8_t bin[18 * RLC_FP_BYTES];
+ fp18_t a, b, c;
+ dig_t d;
+
+ fp18_null(a);
+ fp18_null(b);
+ fp18_null(c);
+
+ RLC_TRY {
+ fp18_new(a);
+ fp18_new(b);
+ fp18_new(c);
+
+ TEST_CASE("comparison is consistent") {
+ fp18_rand(a);
+ fp18_rand(b);
+ if (fp18_cmp(a, b) != RLC_EQ) {
+ TEST_ASSERT(fp18_cmp(b, a) == RLC_NE, end);
+ }
+ }
+ TEST_END;
+
+ TEST_CASE("copy and comparison are consistent") {
+ fp18_rand(a);
+ fp18_rand(b);
+ fp18_rand(c);
+ if (fp18_cmp(a, c) != RLC_EQ) {
+ fp18_copy(c, a);
+ TEST_ASSERT(fp18_cmp(c, a) == RLC_EQ, end);
+ }
+ if (fp18_cmp(b, c) != RLC_EQ) {
+ fp18_copy(c, b);
+ TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
+ }
+ }
+ TEST_END;
+
+ TEST_CASE("negation is consistent") {
+ fp18_rand(a);
+ fp18_neg(b, a);
+ if (fp18_cmp(a, b) != RLC_EQ) {
+ TEST_ASSERT(fp18_cmp(b, a) == RLC_NE, end);
+ }
+ fp18_neg(b, b);
+ TEST_ASSERT(fp18_cmp(a, b) == RLC_EQ, end);
+ }
+ TEST_END;
+
+ TEST_CASE("assignment to zero and comparison are consistent") {
+ do {
+ fp18_rand(a);
+ } while (fp18_is_zero(a));
+ fp18_zero(c);
+ TEST_ASSERT(fp18_cmp(a, c) == RLC_NE, end);
+ TEST_ASSERT(fp18_cmp(c, a) == RLC_NE, end);
+ }
+ TEST_END;
+
+ TEST_CASE("assignment to zero and comparison are consistent") {
+ do {
+ fp18_rand(a);
+ } while (fp18_is_zero(a));
+ fp18_zero(c);
+ TEST_ASSERT(fp18_cmp(a, c) == RLC_NE, end);
+ TEST_ASSERT(fp18_cmp(c, a) == RLC_NE, end);
+ }
+ TEST_END;
+
+
+ TEST_CASE("assignment to random and comparison are consistent") {
+ do {
+ fp18_rand(a);
+ } while (fp18_is_zero(a));
+ fp18_zero(c);
+ TEST_ASSERT(fp18_cmp(a, c) == RLC_NE, end);
+ }
+ TEST_END;
+
+ TEST_CASE("assignment to zero and zero test are consistent") {
+ fp18_zero(a);
+ TEST_ASSERT(fp18_is_zero(a), end);
+ }
+ TEST_END;
+
+ TEST_CASE("assignment to a constant and comparison are consistent") {
+ rand_bytes((uint8_t *)&d, (RLC_DIG / 8));
+ fp18_set_dig(a, d);
+ TEST_ASSERT(fp18_cmp_dig(a, d) == RLC_EQ, end);
+ }
+ TEST_END;
+
+ TEST_CASE("reading and writing a finite field element are consistent") {
+ fp18_rand(a);
+ fp18_write_bin(bin, sizeof(bin), a, 0);
+ fp18_read_bin(b, bin, sizeof(bin));
+ TEST_ASSERT(fp18_cmp(a, b) == RLC_EQ, end);
+ }
+ TEST_END;
+
+ TEST_CASE("getting the size of a finite field element is correct") {
+ fp18_rand(a);
+ TEST_ASSERT(fp18_size_bin(a, 0) == 18 * RLC_FP_BYTES, end);
+ }
+ TEST_END;
+ }
+ RLC_CATCH_ANY {
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp18_free(a);
+ fp18_free(b);
+ fp18_free(c);
+ return code;
+}
+
+static int addition18(void) {
+ int code = RLC_ERR;
+ fp18_t a, b, c, d, e;
+
+ fp18_null(a);
+ fp18_null(b);
+ fp18_null(c);
+ fp18_null(d);
+ fp18_null(e);
+
+ RLC_TRY {
+ fp18_new(a);
+ fp18_new(b);
+ fp18_new(c);
+ fp18_new(d);
+ fp18_new(e);
+
+ TEST_CASE("addition is commutative") {
+ fp18_rand(a);
+ fp18_rand(b);
+ fp18_add(d, a, b);
+ fp18_add(e, b, a);
+ TEST_ASSERT(fp18_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("addition is associative") {
+ fp18_rand(a);
+ fp18_rand(b);
+ fp18_rand(c);
+ fp18_add(d, a, b);
+ fp18_add(d, d, c);
+ fp18_add(e, b, c);
+ fp18_add(e, a, e);
+ TEST_ASSERT(fp18_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("addition has identity") {
+ fp18_rand(a);
+ fp18_zero(d);
+ fp18_add(e, a, d);
+ TEST_ASSERT(fp18_cmp(e, a) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("addition has inverse") {
+ fp18_rand(a);
+ fp18_neg(d, a);
+ fp18_add(e, a, d);
+ TEST_ASSERT(fp18_is_zero(e), end);
+ } TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp18_free(a);
+ fp18_free(b);
+ fp18_free(c);
+ fp18_free(d);
+ fp18_free(e);
+ return code;
+}
+
+static int subtraction18(void) {
+ int code = RLC_ERR;
+ fp18_t a, b, c, d;
+
+ RLC_TRY {
+ fp18_new(a);
+ fp18_new(b);
+ fp18_new(c);
+ fp18_new(d);
+
+ TEST_CASE("subtraction is anti-commutative") {
+ fp18_rand(a);
+ fp18_rand(b);
+ fp18_sub(c, a, b);
+ fp18_sub(d, b, a);
+ fp18_neg(d, d);
+ TEST_ASSERT(fp18_cmp(c, d) == RLC_EQ, end);
+ }
+ TEST_END;
+
+ TEST_CASE("subtraction has identity") {
+ fp18_rand(a);
+ fp18_zero(c);
+ fp18_sub(d, a, c);
+ TEST_ASSERT(fp18_cmp(d, a) == RLC_EQ, end);
+ }
+ TEST_END;
+
+ TEST_CASE("subtraction has inverse") {
+ fp18_rand(a);
+ fp18_sub(c, a, a);
+ TEST_ASSERT(fp18_is_zero(c), end);
+ }
+ TEST_END;
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ fp18_free(a);
+ fp18_free(b);
+ fp18_free(c);
+ fp18_free(d);
+ return code;
+}
+
+static int multiplication18(void) {
+ int code = RLC_ERR;
+ fp18_t a, b, c, d, e, f;
+
+ RLC_TRY {
+ fp18_new(a);
+ fp18_new(b);
+ fp18_new(c);
+ fp18_new(d);
+ fp18_new(e);
+ fp18_new(f);
+
+ TEST_CASE("multiplication is commutative") {
+ fp18_rand(a);
+ fp18_rand(b);
+ fp18_mul(d, a, b);
+ fp18_mul(e, b, a);
+ TEST_ASSERT(fp18_cmp(d, e) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("multiplication is associative") {
+ fp18_rand(a);
fp18_rand(b);
fp18_rand(c);
fp18_mul(d, a, b);
@@ -5271,38 +6087,40 @@ static int cyclotomic18(void) {
} TEST_END;
#endif
- TEST_CASE("cyclotomic exponentiation is correct") {
- fp18_rand(a);
- fp18_conv_cyc(a, a);
- pp_exp_k18(a, a);
- bn_zero(f);
- fp18_exp_cyc(c, a, f);
- TEST_ASSERT(fp18_cmp_dig(c, 1) == RLC_EQ, end);
- bn_set_dig(f, 1);
- fp18_exp_cyc(c, a, f);
- TEST_ASSERT(fp18_cmp(c, a) == RLC_EQ, end);
- bn_rand(f, RLC_POS, RLC_FP_BITS);
- fp18_exp(b, a, f);
- fp18_exp_cyc(c, a, f);
- TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
- bn_rand(f, RLC_POS, RLC_FP_BITS);
- fp18_exp_cyc(b, a, f);
- bn_neg(f, f);
- fp18_exp_cyc(c, a, f);
- fp18_inv_cyc(c, c);
- TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
- /* Try sparse exponents as well. */
- bn_set_2b(f, RLC_FP_BITS - 1);
- bn_set_bit(f, RLC_FP_BITS / 2, 1);
- bn_set_bit(f, 0, 1);
- fp18_rand(a);
- fp18_conv_cyc(a, a);
- fp18_exp_cyc(b, a, f);
- bn_neg(f, f);
- fp18_exp_cyc(c, a, f);
- fp18_inv_cyc(c, c);
- TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
- } TEST_END;
+ if (ep_curve_is_pairf() == EP_K18) {
+ TEST_CASE("cyclotomic exponentiation is correct") {
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ pp_exp_k18(a, a);
+ bn_zero(f);
+ fp18_exp_cyc(c, a, f);
+ TEST_ASSERT(fp18_cmp_dig(c, 1) == RLC_EQ, end);
+ bn_set_dig(f, 1);
+ fp18_exp_cyc(c, a, f);
+ TEST_ASSERT(fp18_cmp(c, a) == RLC_EQ, end);
+ bn_rand(f, RLC_POS, RLC_FP_BITS);
+ fp18_exp(b, a, f);
+ fp18_exp_cyc(c, a, f);
+ TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
+ bn_rand(f, RLC_POS, RLC_FP_BITS);
+ fp18_exp_cyc(b, a, f);
+ bn_neg(f, f);
+ fp18_exp_cyc(c, a, f);
+ fp18_inv_cyc(c, c);
+ TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
+ /* Try sparse exponents as well. */
+ bn_set_2b(f, RLC_FP_BITS - 1);
+ bn_set_bit(f, RLC_FP_BITS / 2, 1);
+ bn_set_bit(f, 0, 1);
+ fp18_rand(a);
+ fp18_conv_cyc(a, a);
+ fp18_exp_cyc(b, a, f);
+ bn_neg(f, f);
+ fp18_exp_cyc(c, a, f);
+ fp18_inv_cyc(c, c);
+ TEST_ASSERT(fp18_cmp(b, c) == RLC_EQ, end);
+ } TEST_END;
+ }
TEST_CASE("sparse cyclotomic exponentiation is correct") {
int g[3] = {0, 0, RLC_FP_BITS - 1};
@@ -7763,6 +8581,8 @@ int main(void) {
}
}
+ fp_param_print();
+
/* Only execute these if there is an assigned quadratic non-residue. */
if (fp_prime_get_qnr()) {
util_print("\n-- Quadratic extension: %d as QNR\n", fp_prime_get_qnr());
@@ -7885,7 +8705,7 @@ int main(void) {
core_clean();
return 1;
}
-
+
if (square_root3() != RLC_OK) {
core_clean();
return 1;
@@ -7962,7 +8782,7 @@ int main(void) {
}
/* Fp^6 is defined as a cubic extension of Fp^2. */
- if (fp_prime_get_qnr()) {
+ if (fp_prime_get_qnr() && fp_prime_get_cnr()) {
util_print("\n-- Sextic extension: (i + %d) as CNR\n",
fp2_field_get_qnr());
util_banner("Utilities:", 1);
@@ -8070,6 +8890,11 @@ int main(void) {
core_clean();
return 1;
}
+
+ if (square_root8() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
}
/* Only execute these if there is an assigned cubic non-residue. */
@@ -8126,7 +8951,7 @@ int main(void) {
}
}
- if (fp_prime_get_qnr() && (ep_param_embed() >= 12)) {
+ if (fp_prime_get_qnr() && fp_prime_get_cnr() && (ep_param_embed() >= 12)) {
util_banner("Dodecic extension:", 0);
util_banner("Utilities:", 1);
@@ -8181,7 +9006,68 @@ int main(void) {
core_clean();
return 1;
}
+ }
+
+ if (fp_prime_get_qnr() && (ep_param_embed() >= 16)) {
+ util_banner("Sextadecic extension:", 0);
+ util_banner("Utilities:", 1);
+
+ if (memory16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (util16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ util_banner("Arithmetic:", 1);
+
+ if (addition16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (subtraction16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (doubling16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (multiplication16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (squaring16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (cyclotomic16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (inversion16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (exponentiation16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+ if (square_root16() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
}
if (fp_prime_get_cnr() && (ep_param_embed() >= 18)) {
diff --git a/test/test_pc.c b/test/test_pc.c
index 0e30ae3f8..7890526b3 100644
--- a/test/test_pc.c
+++ b/test/test_pc.c
@@ -653,7 +653,7 @@ static int memory2(void) {
int util2(void) {
int l, code = RLC_ERR;
g2_t a, b, c;
- uint8_t bin[8 * RLC_PC_BYTES + 1];
+ uint8_t bin[16 * RLC_PC_BYTES + 1];
g2_null(a);
g2_null(b);
@@ -1181,8 +1181,6 @@ static int validity2(void) {
return code;
}
-#if FP_PRIME != 509
-
static int hashing2(void) {
int code = RLC_ERR;
g2_t a;
@@ -1216,8 +1214,6 @@ static int hashing2(void) {
return code;
}
-#endif
-
static int memory(void) {
err_t e = ERR_CAUGHT;
int code = RLC_ERR;
@@ -1749,11 +1745,9 @@ int test2(void) {
return RLC_ERR;
}
-#if FP_PRIME != 509
if (hashing2() != RLC_OK) {
return RLC_ERR;
}
-#endif
return RLC_OK;
}
diff --git a/test/test_pp.c b/test/test_pp.c
index 886bdf0e5..c120930eb 100644
--- a/test/test_pp.c
+++ b/test/test_pp.c
@@ -35,6 +35,455 @@
#include "relic_test.h"
#include "relic_bench.h"
+static int addition1(void) {
+ int code = RLC_ERR;
+ bn_t k, n;
+ ep_t p, q, r, s;
+ fp_t e1, e2, e3;
+
+ bn_null(k);
+ bn_null(n);
+ ep_null(p);
+ ep_null(q);
+ ep_null(r);
+ ep_null(s);
+ fp_null(e1);
+ fp_null(e2);
+ fp_null(e3);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ ep_new(p);
+ ep_new(q);
+ ep_new(r);
+ ep_new(s);
+ fp_new(e1);
+ fp_new(e2);
+ fp_new(e3);
+
+ ep_curve_get_ord(n);
+
+ TEST_CASE("miller addition is correct") {
+ ep_rand(p);
+ ep_rand(q);
+ ep_rand(r);
+ ep_copy(s, r);
+ pp_add_k1(e1, e2, r, q, p);
+ pp_norm_k1(r, r);
+ ep_add(s, s, q);
+ ep_norm(s, s);
+ TEST_ASSERT(ep_cmp(r, s) == RLC_EQ, end);
+ } TEST_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ TEST_CASE("miller addition in affine coordinates is correct") {
+ ep_rand(p);
+ ep_rand(q);
+ ep_rand(r);
+ ep_copy(s, r);
+ fp_zero(e1);
+ fp_zero(e2);
+ pp_add_k1(e1, e2, r, q, p);
+ fp_inv(e2, e2);
+ fp_mul(e1, e1, e2);
+ pp_add_k1_basic(e2, e3, s, q, p);
+ fp_inv(e3, e3);
+ fp_mul(e2, e2, e3);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+ TEST_CASE("miller addition in projective coordinates is correct") {
+ ep_rand(p);
+ ep_rand(q);
+ ep_rand(r);
+ ep_copy(s, r);
+ fp_zero(e1);
+ fp_zero(e2);
+ pp_add_k1(e1, e2, r, q, p);
+ fp_inv(e2, e2);
+ fp_mul(e1, e1, e2);
+ pp_exp_k1(e1, e1);
+ pp_add_k1_projc(e2, e3, s, q, p);
+ fp_inv(e3, e3);
+ fp_mul(e2, e2, e3);
+ pp_exp_k1(e2, e2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif /* EP_ADD = PROJC */
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k);
+ ep_free(p);
+ ep_free(q);
+ ep_free(r);
+ ep_free(s);
+ fp_free(e1);
+ fp_free(e2);
+ fp_free(e3);
+ return code;
+}
+
+static int doubling1(void) {
+ int code = RLC_ERR;
+ bn_t k, n;
+ ep_t p, q, r, s;
+ fp_t e1, e2, e3;
+
+ bn_null(k);
+ bn_null(n);
+ ep_null(p);
+ ep_null(q);
+ ep_null(r);
+ ep_null(s);
+ fp_null(e1);
+ fp_null(e2);
+ fp_null(e3);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ ep_new(p);
+ ep_new(q);
+ ep_new(r);
+ ep_new(s);
+ fp_new(e1);
+ fp_new(e2);
+ fp_new(e3);
+
+ ep_curve_get_ord(n);
+
+ TEST_CASE("miller doubling is correct") {
+ ep_rand(p);
+ ep_rand(q);
+ ep_rand(r);
+ pp_dbl_k1(e1, e2, r, q, p);
+ pp_norm_k1(r, r);
+ ep_dbl(s, q);
+ ep_norm(s, s);
+ TEST_ASSERT(ep_cmp(r, s) == RLC_EQ, end);
+ } TEST_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ TEST_CASE("miller doubling in affine coordinates is correct") {
+ ep_rand(p);
+ ep_rand(q);
+ ep_rand(r);
+ fp_zero(e1);
+ fp_zero(e2);
+ pp_dbl_k1(e1, e2, r, q, p);
+ fp_inv(e2, e2);
+ fp_mul(e1, e1, e2);
+ pp_exp_k1(e1, e1);
+ pp_dbl_k1_basic(e2, e3, r, q, p);
+ fp_inv(e3, e3);
+ fp_mul(e2, e2, e3);
+ pp_exp_k1(e2, e2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+ TEST_CASE("miller doubling in projective coordinates is correct") {
+ ep_rand(p);
+ ep_rand(q);
+ ep_rand(r);
+ fp_zero(e1);
+ fp_zero(e2);
+ pp_dbl_k1(e1, e2, r, q, p);
+ fp_inv(e2, e2);
+ fp_mul(e1, e1, e2);
+ pp_exp_k1(e1, e1);
+ pp_dbl_k1_projc(e2, e3, r, q, p);
+ fp_inv(e3, e3);
+ fp_mul(e2, e2, e3);
+ pp_exp_k1(e2, e2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif /* EP_ADD = PROJC */
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k);
+ ep_free(p);
+ ep_free(q);
+ ep_free(r);
+ ep_free(s);
+ fp_free(e1);
+ fp_free(e2);
+ fp_free(e3);
+ return code;
+}
+
+static int pairing1(void) {
+ int j, code = RLC_ERR;
+ bn_t k, n;
+ ep_t p[2], q[2], r;
+ fp_t e1, e2;
+
+ bn_null(k);
+ bn_null(n);
+ ep_null(r);
+ fp_null(e1);
+ fp_null(e2);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ ep_new(r);
+ fp_new(e1);
+ fp_new(e2);
+
+ for (j = 0; j < 2; j++) {
+ ep_null(p[j]);
+ ep_null(q[j]);
+ ep_new(p[j]);
+ ep_new(q[j]);
+ }
+
+ ep_curve_get_ord(n);
+ TEST_CASE("pairing non-degeneracy is correct") {
+ ep_set_infty(p[0]);
+ pp_map_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_set_infty(q[0]);
+ pp_map_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ pp_map_k1(e1, p[0], p[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_dbl(q[0], p[0]);
+ ep_norm(q[0], q[0]);
+ pp_map_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("pairing is bilinear") {
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ ep_psi(q[0], q[0]);
+ bn_rand_mod(k, n);
+ ep_mul(r, q[0], k);
+ pp_map_k1(e1, p[0], r);
+ pp_map_k1(e2, p[0], q[0]);
+ fp_exp(e2, e2, k);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_mul(p[0], p[0], k);
+ pp_map_k1(e2, p[0], q[0]);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_k1(e2, p[0], q[0]);
+ fp_sqr(e1, e1);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(q[0], q[0]);
+ pp_map_k1(e2, p[0], q[0]);
+ fp_sqr(e1, e1);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep_rand(q[i % 2]);
+ ep_psi(q[i % 2], q[i % 2]);
+ pp_map_k1(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep_rand(q[1 - (i % 2)]);
+ pp_map_sim_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(q[i % 2]);
+ pp_map_sim_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ ep_psi(q[0], q[0]);
+ pp_map_k1(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep_rand(q[1]);
+ ep_psi(q[1], q[1]);
+ pp_map_k1(e2, p[1], q[1]);
+ fp_mul(e1, e1, e2);
+ pp_map_sim_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+#if PP_MAP == TATEP || PP_MAP == OATEP || !defined(STRIP)
+ TEST_CASE("tate pairing non-degeneracy is correct") {
+ ep_set_infty(p[0]);
+ pp_map_tatep_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_set_infty(q[0]);
+ pp_map_tatep_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_dbl(q[0], p[0]);
+ ep_norm(q[0], q[0]);
+ /* If does not work for all multiples of P, but works for 2P. */
+ pp_map_tatep_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_psi(q[0], p[0]);
+ pp_map_tatep_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("tate pairing is bilinear") {
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ ep_psi(q[0], q[0]);
+ bn_rand_mod(k, n);
+ ep_mul(r, q[0], k);
+ pp_map_tatep_k1(e1, p[0], r);
+ pp_map_tatep_k1(e2, p[0], q[0]);
+ fp_exp(e2, e2, k);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_mul(p[0], p[0], k);
+ pp_map_tatep_k1(e2, p[0], q[0]);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_tatep_k1(e2, p[0], q[0]);
+ fp_sqr(e1, e1);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(q[0], q[0]);
+ pp_map_tatep_k1(e2, p[0], q[0]);
+ fp_sqr(e1, e1);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("tate multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep_rand(q[i % 2]);
+ ep_psi(q[i % 2], q[i % 2]);
+ pp_map_tatep_k1(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_tatep_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep_rand(q[1 - (i % 2)]);
+ pp_map_sim_tatep_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(q[i % 2]);
+ pp_map_sim_tatep_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ pp_map_tatep_k1(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep_rand(q[1]);
+ pp_map_tatep_k1(e2, p[1], q[1]);
+ fp_mul(e1, e1, e2);
+ pp_map_sim_tatep_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if PP_MAP == WEIL || !defined(STRIP)
+ TEST_CASE("weil pairing non-degeneracy is correct") {
+ ep_set_infty(p[0]);
+ pp_map_weilp_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_set_infty(q[0]);
+ pp_map_weilp_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ pp_map_weilp_k1(e1, p[0], p[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ pp_map_weilp_k1(e1, p[0], q[0]);
+ TEST_ASSERT(fp_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("weil pairing is bilinear") {
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ ep_psi(q[0], q[0]);
+ bn_rand_mod(k, n);
+ ep_mul(r, q[0], k);
+ pp_map_weilp_k1(e1, p[0], r);
+ pp_map_weilp_k1(e2, p[0], q[0]);
+ fp_exp(e2, e2, k);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_mul(p[0], p[0], k);
+ pp_map_weilp_k1(e2, p[0], q[0]);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_weilp_k1(e2, p[0], q[0]);
+ fp_sqr(e1, e1);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(q[0], q[0]);
+ pp_map_weilp_k1(e2, p[0], q[0]);
+ fp_sqr(e1, e1);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("weil multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep_rand(q[i % 2]);
+ pp_map_weilp_k1(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_weilp_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep_rand(q[1 - (i % 2)]);
+ pp_map_sim_weilp_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(q[i % 2]);
+ pp_map_sim_weilp_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ pp_map_weilp_k1(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep_rand(q[1]);
+ pp_map_weilp_k1(e2, p[1], q[1]);
+ fp_mul(e1, e1, e2);
+ pp_map_sim_weilp_k1(e2, p, q, 2);
+ TEST_ASSERT(fp_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k);
+ ep_free(r);
+ fp_free(e1);
+ fp_free(e2);
+
+ for (j = 0; j < 2; j++) {
+ ep_free(p[j]);
+ ep2_free(q[j]);
+ }
+
+ return code;
+}
+
static int addition2(void) {
int code = RLC_ERR;
bn_t k, n;
@@ -327,29 +776,29 @@ static int pairing2(void) {
} TEST_END;
TEST_CASE("multi-pairing is correct") {
- ep_rand(p[i % 2]);
- ep_rand(q[i % 2]);
- pp_map_k2(e1, p[i % 2], q[i % 2]);
- ep_rand(p[1 - (i % 2)]);
- ep_set_infty(q[1 - (i % 2)]);
- pp_map_sim_k2(e2, p, q, 2);
- TEST_ASSERT(fp2_cmp(e1, e2) == RLC_EQ, end);
- ep_set_infty(p[1 - (i % 2)]);
- ep_rand(q[1 - (i % 2)]);
- pp_map_sim_k2(e2, p, q, 2);
- TEST_ASSERT(fp2_cmp(e1, e2) == RLC_EQ, end);
- ep_set_infty(q[i % 2]);
- pp_map_sim_k2(e2, p, q, 2);
- TEST_ASSERT(fp2_cmp_dig(e2, 1) == RLC_EQ, end);
- ep_rand(p[0]);
- ep_rand(q[0]);
- pp_map_k2(e1, p[0], q[0]);
- ep_rand(p[1]);
- ep_rand(q[1]);
- pp_map_k2(e2, p[1], q[1]);
- fp2_mul(e1, e1, e2);
- pp_map_sim_k2(e2, p, q, 2);
- TEST_ASSERT(fp2_cmp(e1, e2) == RLC_EQ, end);
+ ep_rand(p[i % 2]);
+ ep_rand(q[i % 2]);
+ pp_map_k2(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_k2(e2, p, q, 2);
+ TEST_ASSERT(fp2_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep_rand(q[1 - (i % 2)]);
+ pp_map_sim_k2(e2, p, q, 2);
+ TEST_ASSERT(fp2_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(q[i % 2]);
+ pp_map_sim_k2(e2, p, q, 2);
+ TEST_ASSERT(fp2_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep_rand(q[0]);
+ pp_map_k2(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep_rand(q[1]);
+ pp_map_k2(e2, p[1], q[1]);
+ fp2_mul(e1, e1, e2);
+ pp_map_sim_k2(e2, p, q, 2);
+ TEST_ASSERT(fp2_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
#if PP_MAP == TATEP || PP_MAP == OATEP || !defined(STRIP)
@@ -549,7 +998,7 @@ static int doubling8(void) {
fp_neg(p->y, p->y);
pp_dbl_k8_basic(e2, r, q, p);
pp_exp_k8(e2, e2);
-#if EP_ADD == PROJC
+#if EP_ADD == PROJC || EP_ADD == JACOB
/* Precompute. */
fp_neg(p->y, p->y);
fp_neg(p->x, p->x);
@@ -1177,187 +1626,724 @@ static int pairing12(void) {
TEST_CASE("tate pairing is bilinear") {
ep_rand(p[0]);
- ep2_rand(q[0]);
+ ep2_rand(q[0]);
+ bn_rand_mod(k, n);
+ ep2_mul(r, q[0], k);
+ pp_map_tatep_k12(e1, p[0], r);
+ pp_map_tatep_k12(e2, p[0], q[0]);
+ fp12_exp(e2, e2, k);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_mul(p[0], p[0], k);
+ pp_map_tatep_k12(e2, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_tatep_k12(e2, p[0], q[0]);
+ fp12_sqr(e1, e1);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep2_dbl(q[0], q[0]);
+ pp_map_tatep_k12(e2, p[0], q[0]);
+ fp12_sqr(e1, e1);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("tate multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep2_rand(q[i % 2]);
+ pp_map_tatep_k12(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep2_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_tatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep2_rand(q[1 - (i % 2)]);
+ pp_map_sim_tatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep2_set_infty(q[i % 2]);
+ pp_map_sim_tatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep2_rand(q[0]);
+ pp_map_tatep_k12(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep2_rand(q[1]);
+ pp_map_tatep_k12(e2, p[1], q[1]);
+ fp12_mul(e1, e1, e2);
+ pp_map_sim_tatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_neg(p[1], p[0]);
+ ep2_copy(q[1], q[0]);
+ pp_map_sim_tatep_k12(e1, p, q, 2);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if PP_MAP == WEIL || !defined(STRIP)
+ TEST_CASE("weil pairing non-degeneracy is correct") {
+ ep_rand(p[0]);
+ ep2_rand(q[0]);
+ pp_map_weilp_k12(e1, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) != RLC_EQ, end);
+ ep_set_infty(p[0]);
+ pp_map_weilp_k12(e1, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep2_set_infty(q[0]);
+ pp_map_weilp_k12(e1, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("weil pairing is bilinear") {
+ ep_rand(p[0]);
+ ep2_rand(q[0]);
+ bn_rand_mod(k, n);
+ ep2_mul(r, q[0], k);
+ pp_map_weilp_k12(e1, p[0], r);
+ pp_map_weilp_k12(e2, p[0], q[0]);
+ fp12_exp(e2, e2, k);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_mul(p[0], p[0], k);
+ pp_map_weilp_k12(e2, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_weilp_k12(e2, p[0], q[0]);
+ fp12_sqr(e1, e1);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep2_dbl(q[0], q[0]);
+ pp_map_weilp_k12(e2, p[0], q[0]);
+ fp12_sqr(e1, e1);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("weil multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep2_rand(q[i % 2]);
+ pp_map_weilp_k12(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep2_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_weilp_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep2_rand(q[1 - (i % 2)]);
+ pp_map_sim_weilp_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep2_set_infty(q[i % 2]);
+ pp_map_sim_weilp_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep2_rand(q[0]);
+ pp_map_weilp_k12(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep2_rand(q[1]);
+ pp_map_weilp_k12(e2, p[1], q[1]);
+ fp12_mul(e1, e1, e2);
+ pp_map_sim_weilp_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_neg(p[1], p[0]);
+ ep2_copy(q[1], q[0]);
+ pp_map_sim_weilp_k12(e1, p, q, 2);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if PP_MAP == OATEP || !defined(STRIP)
+ TEST_CASE("optimal ate pairing non-degeneracy is correct") {
+ ep_rand(p[0]);
+ ep2_rand(q[0]);
+ pp_map_oatep_k12(e1, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) != RLC_EQ, end);
+ ep_set_infty(p[0]);
+ pp_map_oatep_k12(e1, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep2_set_infty(q[0]);
+ pp_map_oatep_k12(e1, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("optimal ate pairing is bilinear") {
+ ep_rand(p[0]);
+ ep2_rand(q[0]);
+ bn_rand_mod(k, n);
+ ep2_mul(r, q[0], k);
+ pp_map_oatep_k12(e1, p[0], r);
+ ep_mul(p[0], p[0], k);
+ pp_map_oatep_k12(e2, p[0], q[0]);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_oatep_k12(e2, p[0], q[0]);
+ fp12_sqr(e1, e1);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep2_dbl(q[0], q[0]);
+ pp_map_oatep_k12(e2, p[0], q[0]);
+ fp12_sqr(e1, e1);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("optimal ate multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep2_rand(q[i % 2]);
+ pp_map_oatep_k12(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep2_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_oatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep2_rand(q[1 - (i % 2)]);
+ pp_map_sim_oatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep2_set_infty(q[i % 2]);
+ pp_map_sim_oatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep2_rand(q[0]);
+ pp_map_oatep_k12(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep2_rand(q[1]);
+ pp_map_oatep_k12(e2, p[1], q[1]);
+ fp12_mul(e1, e1, e2);
+ pp_map_sim_oatep_k12(e2, p, q, 2);
+ TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep_neg(p[1], p[0]);
+ ep2_copy(q[1], q[0]);
+ pp_map_sim_oatep_k12(e1, p, q, 2);
+ TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+#endif
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k);
+ fp12_free(e1);
+ fp12_free(e2);
+ ep2_free(r);
+
+ for (j = 0; j < 2; j++) {
+ ep_free(p[j]);
+ ep2_free(q[j]);
+ }
+ return code;
+}
+
+static int doubling16(void) {
+ int code = RLC_ERR;
+ bn_t k, n;
+ ep_t p;
+ ep4_t q, r, s;
+ fp16_t e1, e2;
+
+ bn_null(k);
+ bn_null(n);
+ ep_null(p);
+ ep4_null(q);
+ ep4_null(r);
+ ep4_null(s);
+ fp16_null(e1);
+ fp16_null(e2);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ ep_new(p);
+ ep4_new(q);
+ ep4_new(r);
+ ep4_new(s);
+ fp16_new(e1);
+ fp16_new(e2);
+
+ ep_curve_get_ord(n);
+
+ TEST_CASE("miller doubling is correct") {
+ ep_rand(p);
+ ep4_rand(q);
+ ep4_rand(r);
+ pp_dbl_k16(e1, r, q, p);
+ pp_norm_k16(r, r);
+ ep4_dbl(s, q);
+ ep4_norm(s, s);
+ TEST_ASSERT(ep4_cmp(r, s) == RLC_EQ, end);
+ } TEST_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ TEST_CASE("miller doubling in affine coordinates is correct") {
+ ep_rand(p);
+ ep4_rand(q);
+ ep4_rand(r);
+ fp16_zero(e1);
+ fp16_zero(e2);
+ fp_neg(p->y, p->y);
+ pp_dbl_k16_basic(e2, r, q, p);
+ pp_exp_k16(e2, e2);
+#if EP_ADD == PROJC || EP_ADD == JACOB
+ /* Precompute. */
+ fp_neg(p->y, p->y);
+ fp_neg(p->x, p->x);
+#endif
+ pp_dbl_k16(e1, r, q, p);
+ pp_exp_k16(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+ TEST_CASE("miller doubling in projective coordinates is correct") {
+ ep_rand(p);
+ ep4_rand(q);
+ ep4_rand(r);
+ fp16_zero(e1);
+ fp16_zero(e2);
+ /* Precompute. */
+ fp_neg(p->x, p->x);
+ pp_dbl_k16_projc(e2, r, q, p);
+ pp_exp_k16(e2, e2);
+#if EP_ADD == BASIC
+ /* Revert and fix precomputing. */
+ fp_neg(p->x, p->x);
+ fp_neg(p->y, p->y);
+#endif
+ pp_dbl_k16(e1, r, q, p);
+ pp_exp_k16(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+#if PP_EXT == BASIC || !defined(STRIP)
+ TEST_CASE("basic projective miller doubling is correct") {
+ ep_rand(p);
+ ep4_rand(q);
+ ep4_rand(r);
+ fp16_zero(e1);
+ fp16_zero(e2);
+ pp_dbl_k16_projc(e1, r, q, p);
+ pp_dbl_k16_projc_basic(e2, r, q, p);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if PP_EXT == LAZYR || !defined(STRIP)
+ TEST_CASE("lazy-reduced projective miller doubling is consistent") {
+ ep_rand(p);
+ ep4_rand(q);
+ ep4_rand(r);
+ fp16_zero(e1);
+ fp16_zero(e2);
+ pp_dbl_k16_projc(e1, r, q, p);
+ pp_dbl_k16_projc_lazyr(e2, r, q, p);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+#endif /* EP_ADD = PROJC */
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k);
+ ep_free(p);
+ ep4_free(q);
+ ep4_free(r);
+ ep4_free(s);
+ fp16_free(e1);
+ fp16_free(e2);
+ return code;
+}
+
+static int addition16(void) {
+ int code = RLC_ERR;
+ bn_t k, n;
+ ep_t p;
+ ep4_t q, r, s;
+ fp16_t e1, e2;
+
+ bn_null(k);
+ bn_null(n);
+ ep_null(p);
+ ep4_null(q);
+ ep4_null(r);
+ ep4_null(s);
+ fp16_null(e1);
+ fp16_null(e2);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ ep_new(p);
+ ep4_new(q);
+ ep4_new(r);
+ ep4_new(s);
+ fp16_new(e1);
+ fp16_new(e2);
+
+ ep_curve_get_ord(n);
+
+ TEST_CASE("miller addition is correct") {
+ ep_rand(p);
+ ep4_curve_get_gen(q);
+ ep4_dbl(r, q);
+ ep4_norm(r, r);
+ ep4_copy(s, r);
+ pp_add_k16(e1, r, q, p);
+ pp_norm_k16(r, r);
+ ep4_add(s, s, q);
+ ep4_norm(s, s);
+ TEST_ASSERT(ep4_cmp(r, s) == RLC_EQ, end);
+ } TEST_END;
+
+#if EP_ADD == BASIC || !defined(STRIP)
+ TEST_CASE("miller addition in affine coordinates is correct") {
+ ep_rand(p);
+ ep4_curve_get_gen(q);
+ ep4_dbl(r, q);
+ ep4_norm(r, r);
+ ep4_copy(s, r);
+ fp16_zero(e1);
+ fp16_zero(e2);
+#if EP_ADD == PROJC
+ /* Precompute. */
+ fp_neg(p->x, p->x);
+#else
+ fp_neg(p->y, p->y);
+#endif
+ pp_add_k16(e1, r, q, p);
+ pp_exp_k16(e1, e1);
+#if EP_ADD == PROJC
+ /* Revert precompute. */
+ fp_neg(p->x, p->x);
+ fp_neg(p->y, p->y);
+#endif
+ pp_add_k16_basic(e2, s, q, p);
+ pp_exp_k16(e2, e2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
+ TEST_CASE("miller addition in projective coordinates is correct") {
+ ep_rand(p);
+ ep4_curve_get_gen(q);
+ ep4_dbl(r, q);
+ ep4_norm(r, r);
+ ep4_copy(s, r);
+ fp16_zero(e1);
+ fp16_zero(e2);
+#if EP_ADD == PROJC
+ /* Precompute. */
+ fp_neg(p->x, p->x);
+#else
+ fp_neg(p->y, p->y);
+#endif
+ pp_add_k16(e1, r, q, p);
+ pp_exp_k16(e1, e1);
+#if EP_ADD == BASIC
+ fp_neg(p->x, p->x);
+ fp_neg(p->y, p->y);
+#endif
+ pp_add_k16_projc(e2, s, q, p);
+ pp_exp_k16(e2, e2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+#endif
+ }
+ RLC_CATCH_ANY {
+ util_print("FATAL ERROR!\n");
+ RLC_ERROR(end);
+ }
+ code = RLC_OK;
+ end:
+ bn_free(n);
+ bn_free(k);
+ ep_free(p);
+ ep4_free(q);
+ ep4_free(r);
+ ep4_free(s);
+ fp16_free(e1);
+ fp16_free(e2);
+ return code;
+}
+
+static int pairing16(void) {
+ int j, code = RLC_ERR;
+ bn_t k, n;
+ ep_t p[2];
+ ep4_t q[2], r;
+ fp16_t e1, e2;
+
+ bn_null(k);
+ bn_null(n);
+ fp16_null(e1);
+ fp16_null(e2);
+ ep4_null(r);
+
+ RLC_TRY {
+ bn_new(n);
+ bn_new(k);
+ fp16_new(e1);
+ fp16_new(e2);
+ ep4_new(r);
+
+ for (j = 0; j < 2; j++) {
+ ep_null(p[j]);
+ ep4_null(q[j]);
+ ep_new(p[j]);
+ ep4_new(q[j]);
+ }
+
+ ep_curve_get_ord(n);
+
+ TEST_CASE("pairing non-degeneracy is correct") {
+ ep_rand(p[0]);
+ ep4_rand(q[0]);
+ pp_map_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) != RLC_EQ, end);
+ ep_set_infty(p[0]);
+ pp_map_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep4_set_infty(q[0]);
+ pp_map_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("pairing is bilinear") {
+ ep_rand(p[0]);
+ ep4_rand(q[0]);
+ bn_rand_mod(k, n);
+ ep4_mul(r, q[0], k);
+ pp_map_k16(e1, p[0], r);
+ pp_map_k16(e2, p[0], q[0]);
+ fp16_exp(e2, e2, k);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep_mul(p[0], p[0], k);
+ pp_map_k16(e2, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_dbl(q[0], q[0]);
+ pp_map_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep4_rand(q[i % 2]);
+ pp_map_k16(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep4_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep4_rand(q[1 - (i % 2)]);
+ pp_map_sim_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_set_infty(q[i % 2]);
+ pp_map_sim_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep4_rand(q[0]);
+ pp_map_k16(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep4_rand(q[1]);
+ pp_map_k16(e2, p[1], q[1]);
+ fp16_mul(e1, e1, e2);
+ pp_map_sim_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ } TEST_END;
+
+#if PP_MAP == TATEP || !defined(STRIP)
+ TEST_CASE("tate pairing non-degeneracy is correct") {
+ ep_rand(p[0]);
+ ep4_rand(q[0]);
+ pp_map_tatep_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) != RLC_EQ, end);
+ ep_set_infty(p[0]);
+ pp_map_tatep_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep4_set_infty(q[0]);
+ pp_map_tatep_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
+
+ TEST_CASE("tate pairing is bilinear") {
+ ep_rand(p[0]);
+ ep4_rand(q[0]);
bn_rand_mod(k, n);
- ep2_mul(r, q[0], k);
- pp_map_tatep_k12(e1, p[0], r);
- pp_map_tatep_k12(e2, p[0], q[0]);
- fp12_exp(e2, e2, k);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep4_mul(r, q[0], k);
+ pp_map_tatep_k16(e1, p[0], r);
+ pp_map_tatep_k16(e2, p[0], q[0]);
+ fp16_exp(e2, e2, k);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_mul(p[0], p[0], k);
- pp_map_tatep_k12(e2, p[0], q[0]);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ pp_map_tatep_k16(e2, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_dbl(p[0], p[0]);
- pp_map_tatep_k12(e2, p[0], q[0]);
- fp12_sqr(e1, e1);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep2_dbl(q[0], q[0]);
- pp_map_tatep_k12(e2, p[0], q[0]);
- fp12_sqr(e1, e1);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ pp_map_tatep_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_dbl(q[0], q[0]);
+ pp_map_tatep_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
TEST_CASE("tate multi-pairing is correct") {
ep_rand(p[i % 2]);
- ep2_rand(q[i % 2]);
- pp_map_tatep_k12(e1, p[i % 2], q[i % 2]);
+ ep4_rand(q[i % 2]);
+ pp_map_tatep_k16(e1, p[i % 2], q[i % 2]);
ep_rand(p[1 - (i % 2)]);
- ep2_set_infty(q[1 - (i % 2)]);
- pp_map_sim_tatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep4_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_tatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_set_infty(p[1 - (i % 2)]);
- ep2_rand(q[1 - (i % 2)]);
- pp_map_sim_tatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep2_set_infty(q[i % 2]);
- pp_map_sim_tatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep4_rand(q[1 - (i % 2)]);
+ pp_map_sim_tatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_set_infty(q[i % 2]);
+ pp_map_sim_tatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp_dig(e2, 1) == RLC_EQ, end);
ep_rand(p[0]);
- ep2_rand(q[0]);
- pp_map_tatep_k12(e1, p[0], q[0]);
+ ep4_rand(q[0]);
+ pp_map_tatep_k16(e1, p[0], q[0]);
ep_rand(p[1]);
- ep2_rand(q[1]);
- pp_map_tatep_k12(e2, p[1], q[1]);
- fp12_mul(e1, e1, e2);
- pp_map_sim_tatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep_neg(p[1], p[0]);
- ep2_copy(q[1], q[0]);
- pp_map_sim_tatep_k12(e1, p, q, 2);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep4_rand(q[1]);
+ pp_map_tatep_k16(e2, p[1], q[1]);
+ fp16_mul(e1, e1, e2);
+ pp_map_sim_tatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
#endif
#if PP_MAP == WEIL || !defined(STRIP)
TEST_CASE("weil pairing non-degeneracy is correct") {
ep_rand(p[0]);
- ep2_rand(q[0]);
- pp_map_weilp_k12(e1, p[0], q[0]);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) != RLC_EQ, end);
+ ep4_rand(q[0]);
+ pp_map_weilp_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) != RLC_EQ, end);
ep_set_infty(p[0]);
- pp_map_weilp_k12(e1, p[0], q[0]);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ pp_map_weilp_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
ep_rand(p[0]);
- ep2_set_infty(q[0]);
- pp_map_weilp_k12(e1, p[0], q[0]);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep4_set_infty(q[0]);
+ pp_map_weilp_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
} TEST_END;
TEST_CASE("weil pairing is bilinear") {
ep_rand(p[0]);
- ep2_rand(q[0]);
+ ep4_rand(q[0]);
bn_rand_mod(k, n);
- ep2_mul(r, q[0], k);
- pp_map_weilp_k12(e1, p[0], r);
- pp_map_weilp_k12(e2, p[0], q[0]);
- fp12_exp(e2, e2, k);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep4_mul(r, q[0], k);
+ pp_map_weilp_k16(e1, p[0], r);
+ pp_map_weilp_k16(e2, p[0], q[0]);
+ fp16_exp(e2, e2, k);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_mul(p[0], p[0], k);
- pp_map_weilp_k12(e2, p[0], q[0]);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ pp_map_weilp_k16(e2, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_dbl(p[0], p[0]);
- pp_map_weilp_k12(e2, p[0], q[0]);
- fp12_sqr(e1, e1);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep2_dbl(q[0], q[0]);
- pp_map_weilp_k12(e2, p[0], q[0]);
- fp12_sqr(e1, e1);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ pp_map_weilp_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_dbl(q[0], q[0]);
+ pp_map_weilp_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
TEST_CASE("weil multi-pairing is correct") {
ep_rand(p[i % 2]);
- ep2_rand(q[i % 2]);
- pp_map_weilp_k12(e1, p[i % 2], q[i % 2]);
+ ep4_rand(q[i % 2]);
+ pp_map_weilp_k16(e1, p[i % 2], q[i % 2]);
ep_rand(p[1 - (i % 2)]);
- ep2_set_infty(q[1 - (i % 2)]);
- pp_map_sim_weilp_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep4_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_weilp_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_set_infty(p[1 - (i % 2)]);
- ep2_rand(q[1 - (i % 2)]);
- pp_map_sim_weilp_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep2_set_infty(q[i % 2]);
- pp_map_sim_weilp_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep4_rand(q[1 - (i % 2)]);
+ pp_map_sim_weilp_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_set_infty(q[i % 2]);
+ pp_map_sim_weilp_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp_dig(e2, 1) == RLC_EQ, end);
ep_rand(p[0]);
- ep2_rand(q[0]);
- pp_map_weilp_k12(e1, p[0], q[0]);
+ ep4_rand(q[0]);
+ pp_map_weilp_k16(e1, p[0], q[0]);
ep_rand(p[1]);
- ep2_rand(q[1]);
- pp_map_weilp_k12(e2, p[1], q[1]);
- fp12_mul(e1, e1, e2);
- pp_map_sim_weilp_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep_neg(p[1], p[0]);
- ep2_copy(q[1], q[0]);
- pp_map_sim_weilp_k12(e1, p, q, 2);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep4_rand(q[1]);
+ pp_map_weilp_k16(e2, p[1], q[1]);
+ fp16_mul(e1, e1, e2);
+ pp_map_sim_weilp_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
#endif
#if PP_MAP == OATEP || !defined(STRIP)
TEST_CASE("optimal ate pairing non-degeneracy is correct") {
ep_rand(p[0]);
- ep2_rand(q[0]);
- pp_map_oatep_k12(e1, p[0], q[0]);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) != RLC_EQ, end);
+ ep4_rand(q[0]);
+ pp_map_oatep_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) != RLC_EQ, end);
ep_set_infty(p[0]);
- pp_map_oatep_k12(e1, p[0], q[0]);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ pp_map_oatep_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
ep_rand(p[0]);
- ep2_set_infty(q[0]);
- pp_map_oatep_k12(e1, p[0], q[0]);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep4_set_infty(q[0]);
+ pp_map_oatep_k16(e1, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp_dig(e1, 1) == RLC_EQ, end);
} TEST_END;
TEST_CASE("optimal ate pairing is bilinear") {
ep_rand(p[0]);
- ep2_rand(q[0]);
+ ep4_rand(q[0]);
bn_rand_mod(k, n);
- ep2_mul(r, q[0], k);
- pp_map_oatep_k12(e1, p[0], r);
+ ep4_mul(r, q[0], k);
+ pp_map_oatep_k16(e1, p[0], r);
ep_mul(p[0], p[0], k);
- pp_map_oatep_k12(e2, p[0], q[0]);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ pp_map_oatep_k16(e2, p[0], q[0]);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_dbl(p[0], p[0]);
- pp_map_oatep_k12(e2, p[0], q[0]);
- fp12_sqr(e1, e1);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep2_dbl(q[0], q[0]);
- pp_map_oatep_k12(e2, p[0], q[0]);
- fp12_sqr(e1, e1);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ pp_map_oatep_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_dbl(q[0], q[0]);
+ pp_map_oatep_k16(e2, p[0], q[0]);
+ fp16_sqr(e1, e1);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
TEST_CASE("optimal ate multi-pairing is correct") {
ep_rand(p[i % 2]);
- ep2_rand(q[i % 2]);
- pp_map_oatep_k12(e1, p[i % 2], q[i % 2]);
+ ep4_rand(q[i % 2]);
+ pp_map_oatep_k16(e1, p[i % 2], q[i % 2]);
ep_rand(p[1 - (i % 2)]);
- ep2_set_infty(q[1 - (i % 2)]);
- pp_map_sim_oatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
+ ep4_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_oatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
ep_set_infty(p[1 - (i % 2)]);
- ep2_rand(q[1 - (i % 2)]);
- pp_map_sim_oatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep2_set_infty(q[i % 2]);
- pp_map_sim_oatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep4_rand(q[1 - (i % 2)]);
+ pp_map_sim_oatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
+ ep4_set_infty(q[i % 2]);
+ pp_map_sim_oatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp_dig(e2, 1) == RLC_EQ, end);
ep_rand(p[0]);
- ep2_rand(q[0]);
- pp_map_oatep_k12(e1, p[0], q[0]);
+ ep4_rand(q[0]);
+ pp_map_oatep_k16(e1, p[0], q[0]);
ep_rand(p[1]);
- ep2_rand(q[1]);
- pp_map_oatep_k12(e2, p[1], q[1]);
- fp12_mul(e1, e1, e2);
- pp_map_sim_oatep_k12(e2, p, q, 2);
- TEST_ASSERT(fp12_cmp(e1, e2) == RLC_EQ, end);
- ep_neg(p[1], p[0]);
- ep2_copy(q[1], q[0]);
- pp_map_sim_oatep_k12(e1, p, q, 2);
- TEST_ASSERT(fp12_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep4_rand(q[1]);
+ pp_map_oatep_k16(e2, p[1], q[1]);
+ fp16_mul(e1, e1, e2);
+ pp_map_sim_oatep_k16(e2, p, q, 2);
+ TEST_ASSERT(fp16_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
#endif
}
@@ -1369,13 +2355,13 @@ static int pairing12(void) {
end:
bn_free(n);
bn_free(k);
- fp12_free(e1);
- fp12_free(e2);
- ep2_free(r);
+ fp16_free(e1);
+ fp16_free(e2);
+ ep4_free(r);
for (j = 0; j < 2; j++) {
ep_free(p[j]);
- ep2_free(q[j]);
+ ep4_free(q[j]);
}
return code;
}
@@ -2223,41 +3209,19 @@ static int pairing24(void) {
return code;
}
-/* Put test vectors here until we implement E(Fp^8). */
-#define QX000 "266A6ACAA4B8DDCFBF97F09DFBEB01999BFBFF872276FA7700114F761E8971C6C25A53CC77E96BCC9579F63D8A39D641B8070B07EF40E93C301A5B49CE87110CC30E044BEE5A2D43"
-#define QX001 "5009EEB2A67C52B79D0727B408A193FFCE76B4F80C8DCF4D61ECEE5471601CD7A94341F697CE9D375DB5470EA055B73C256CCC0AC12F52EAD276C26E001DDCE02DE634BEFCB9CC7C"
-#define QX010 "11A8DDB59724C01696BE52862B5AC2C7E1C0C42EFCAF456A80F6C6D9F95F89649D5575DE3BA8D28D1012E14308DE1D8F15CE1617611F961032B0B5DFA27EF3E3670B9B537ACC66B9"
-#define QX011 "4E8BDED03587581A173AD008DFF600EB24054E4CDDCA8D7BFABA2898822DB5ED701BF59BD3F108AD7C714B6A6C7ECB11A1BC5DEEC1D49AE7FCA597C43943A66441B03164975D9BE0"
-#define QX100 "29E2751CAC7D0FBA8E12CC818BDE6F2A7173D3C2ED74EC1991B936071DEB1AED1E07CDF71EA3501BEB4645C86BDC8A575898303FF6A058C7062F079F594E5B865626D0C031CF7E44"
-#define QX101 "2F3A1BE54DFFB814DA4AE6311B9B1EEE6198CDB9F36CE92084272416462F4D0AC9ACAC025FDA6D3D0D1C239FE8CE4B7F22A1D0F65582DDA36EEB328843FDE5C0BDA02E871796CC8E"
-#define QX110 "2FEE7B15EB22B05476A462374860140DCC9F00910E0555918D6357F6E32E623B88B893647AD07B615F364093D6F6D2A7B7614590A8833385B5A833563C0DD6C89AF89D06428E8AFE"
-#define QX111 "005082322BB5E610DC0E61E3D01B8BFF23D195117F58B1FA68EC04A6769FEB754A58742C7F729E2A684386C40EFB871CB3D32A040966155649DC45C49E6FB5DEE58DB1586CBFD33E"
-
-#define QY000 "3B603A4C408A402FB885B607C4A661BF92354D22F46945F222C6F51CCDEBF4006640346AE6BFD60F7E22240D4BF83EFDA1B575267A89597D7BC54FA4899BFBAAC4138E30C8DA55C0"
-#define QY001 "35D3ECCC1F3C69A921E57CCDEA6C794A5ED01A53E19208854EA3B10D519CCCE64A30007CD7A57673567F2FFA070E5CE01C4E5C8BF1C61225DAC36A93C6524F4D0350C6358C67F85B"
-#define QY010 "4228DA69A29E14E2CF00EC8FDD877CA9049DA161778A6ACE8DC275D4CE94C90AD9176280703AD9C6714A4865EF6160ED2FA7A5FC601025CF096AB6CF21B8FAA41421C7913DECF3B5"
-#define QY011 "5273C1679E18D316C6988820E06335094FCCCD5E8FD870492EB96FCBC5B5494B2B9D0869C18309FF2D49CD80CF6E6FE1A660027A6E924831F8D5A070645A7B794BA7AE72507809AE"
-#define QY100 "0ABD2F582F0D4C3C89770C13F02FF17CDEA5B22CDD661B6F82905ADCDC44E59900C5D09F8CAC90760CCC57D1987DE4BA21F34455E5B7394B68A7883E3F8D918AF308F0C3E6F98F4B"
-#define QY101 "36FAE1DE9DD31FFE238526F618C14E5CB61EEA8E8E6D82235E43E45E306C5E60B4E5499BF4663516CE1202EF6CDE3B2E098E406B3186937483FC104A173707C6419F460A23ADF628"
-#define QY110 "09E1BB455FCB47E98C5263B5098E2D148EC2EDEE5634B8F94F10AF9221D09BD60D28920342C11B1987A24B7F56AC4F5E290E7EA483727ED16FFC88C0F5EAD00892FDA66BA68FACE4"
-#define QY111 "4F781C32F5CAFD446F299BE6BC600BF3482DF6ECAF4ABE3D410A7255B18A88DB77CC539CAC4A0D30A00690CCA8CC7661BCE042D0AC40FF8DC9171847A8E42696E4EF9DD8A5907A3D"
-
static int doubling48(void) {
int code = RLC_ERR;
bn_t k, n;
ep_t p;
- fp8_t qx, qy, qz, rx, ry, rz;
+ ep8_t q, r, s;
fp48_t e1, e2;
bn_null(k);
bn_null(n);
ep_null(p);
- fp8_null(qx);
- fp8_null(qy);
- fp8_null(qz);
- fp8_null(rx);
- fp8_null(ry);
- fp8_null(rz);
+ ep8_null(q);
+ ep8_null(r);
+ ep8_null(s);
fp48_null(e1);
fp48_null(e2);
@@ -2265,70 +3229,40 @@ static int doubling48(void) {
bn_new(n);
bn_new(k);
ep_new(p);
- fp8_new(qx);
- fp8_new(qy);
- fp8_new(qz);
- fp8_new(rx);
- fp8_new(ry);
- fp8_new(rz);
+ ep8_new(q);
+ ep8_new(r);
+ ep8_new(s);
fp48_new(e1);
fp48_new(e2);
- fp_read_str(qx[0][0][0], QX000, strlen(QX000), 16);
- fp_read_str(qx[0][0][1], QX001, strlen(QX001), 16);
- fp_read_str(qx[0][1][0], QX010, strlen(QX010), 16);
- fp_read_str(qx[0][1][1], QX011, strlen(QX011), 16);
- fp_read_str(qx[1][0][0], QX100, strlen(QX100), 16);
- fp_read_str(qx[1][0][1], QX101, strlen(QX101), 16);
- fp_read_str(qx[1][1][0], QX110, strlen(QX110), 16);
- fp_read_str(qx[1][1][1], QX111, strlen(QX111), 16);
-
- fp_read_str(qy[0][0][0], QY000, strlen(QY000), 16);
- fp_read_str(qy[0][0][1], QY001, strlen(QY001), 16);
- fp_read_str(qy[0][1][0], QY010, strlen(QY010), 16);
- fp_read_str(qy[0][1][1], QY011, strlen(QY011), 16);
- fp_read_str(qy[1][0][0], QY100, strlen(QY100), 16);
- fp_read_str(qy[1][0][1], QY101, strlen(QY101), 16);
- fp_read_str(qy[1][1][0], QY110, strlen(QY110), 16);
- fp_read_str(qy[1][1][1], QY111, strlen(QY111), 16);
-
- fp8_set_dig(qz, 1);
-
ep_curve_get_ord(n);
TEST_CASE("miller doubling is correct") {
ep_rand(p);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
- pp_dbl_k48_projc(e1, rx, ry, rz, p);
- fp8_inv(rz, rz);
- fp8_mul(rx, rx, rz);
- fp8_mul(ry, ry, rz);
- pp_dbl_k48_basic(e2, qx, qy, p);
- TEST_ASSERT(fp8_cmp(rx, qx) == RLC_EQ && fp8_cmp(ry, qy) == RLC_EQ, end);
+ ep8_rand(q);
+ ep8_rand(r);
+ pp_dbl_k48(e1, r, q, p);
+ pp_norm_k48(r, r);
+ ep8_dbl(s, q);
+ ep8_norm(s, s);
+ TEST_ASSERT(ep8_cmp(r, s) == RLC_EQ, end);
} TEST_END;
#if EP_ADD == BASIC || !defined(STRIP)
TEST_CASE("miller doubling in affine coordinates is correct") {
ep_rand(p);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
+ ep8_rand(q);
fp48_zero(e1);
fp48_zero(e2);
fp_neg(p->y, p->y);
- pp_dbl_k48_basic(e2, rx, ry, p);
+ pp_dbl_k48_basic(e2, r, q, p);
pp_exp_k48(e2, e2);
#if EP_ADD == PROJC
/* Precompute. */
fp_dbl(p->z, p->x);
fp_add(p->x, p->z, p->x);
#endif
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
- pp_dbl_k48(e1, rx, ry, rz, p);
+ pp_dbl_k48(e1, r, q, p);
pp_exp_k48(e1, e1);
TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
@@ -2337,25 +3271,20 @@ static int doubling48(void) {
#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
TEST_CASE("miller doubling in projective coordinates is correct") {
ep_rand(p);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
+ ep8_rand(q);
fp48_zero(e1);
fp48_zero(e2);
/* Precompute. */
fp_neg(p->y, p->y);
fp_dbl(p->z, p->x);
fp_add(p->x, p->z, p->x);
- pp_dbl_k48_projc(e2, rx, ry, rz, p);
+ pp_dbl_k48_projc(e2, r, q, p);
pp_exp_k48(e2, e2);
#if EP_ADD == BASIC
/* Revert precomputing. */
fp_hlv(p->x, p->z);
#endif
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
- pp_dbl_k48(e1, rx, ry, rz, p);
+ pp_dbl_k48(e1, r, q, p);
pp_exp_k48(e1, e1);
TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
@@ -2370,12 +3299,9 @@ static int doubling48(void) {
bn_free(n);
bn_free(k);
ep_free(p);
- fp8_free(qx);
- fp8_free(qy);
- fp8_free(qz);
- fp8_free(rx);
- fp8_free(ry);
- fp8_free(rz);
+ ep8_free(q);
+ ep8_free(r);
+ ep8_free(s);
fp48_free(e1);
fp48_free(e2);
return code;
@@ -2385,18 +3311,15 @@ static int addition48(void) {
int code = RLC_ERR;
bn_t k, n;
ep_t p;
- fp8_t qx, qy, qz, rx, ry, rz;
+ ep8_t q, r, s;
fp48_t e1, e2;
bn_null(k);
bn_null(n);
ep_null(p);
- fp8_null(qx);
- fp8_null(qy);
- fp8_null(qz);
- fp8_null(rx);
- fp8_null(ry);
- fp8_null(rz);
+ ep8_null(q);
+ ep8_null(r);
+ ep8_null(s);
fp48_null(e1);
fp48_null(e2);
@@ -2404,104 +3327,53 @@ static int addition48(void) {
bn_new(n);
bn_new(k);
ep_new(p);
- fp8_new(qx);
- fp8_new(qy);
- fp8_new(qz);
- fp8_new(rx);
- fp8_new(ry);
- fp8_new(rz);
+ ep8_new(q);
+ ep8_new(r);
+ ep8_new(s);
fp48_new(e1);
fp48_new(e2);
- fp_read_str(qx[0][0][0], QX000, strlen(QX000), 16);
- fp_read_str(qx[0][0][1], QX001, strlen(QX001), 16);
- fp_read_str(qx[0][1][0], QX010, strlen(QX010), 16);
- fp_read_str(qx[0][1][1], QX011, strlen(QX011), 16);
- fp_read_str(qx[1][0][0], QX100, strlen(QX100), 16);
- fp_read_str(qx[1][0][1], QX101, strlen(QX101), 16);
- fp_read_str(qx[1][1][0], QX110, strlen(QX110), 16);
- fp_read_str(qx[1][1][1], QX111, strlen(QX111), 16);
-
- fp_read_str(qy[0][0][0], QY000, strlen(QY000), 16);
- fp_read_str(qy[0][0][1], QY001, strlen(QY001), 16);
- fp_read_str(qy[0][1][0], QY010, strlen(QY010), 16);
- fp_read_str(qy[0][1][1], QY011, strlen(QY011), 16);
- fp_read_str(qy[1][0][0], QY100, strlen(QY100), 16);
- fp_read_str(qy[1][0][1], QY101, strlen(QY101), 16);
- fp_read_str(qy[1][1][0], QY110, strlen(QY110), 16);
- fp_read_str(qy[1][1][1], QY111, strlen(QY111), 16);
-
- fp8_set_dig(qz, 1);
-
ep_curve_get_ord(n);
TEST_CASE("miller addition is correct") {
ep_rand(p);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
- pp_dbl_k48(e1, rx, ry, rz, p);
- pp_add_k48_projc(e1, rx, ry, rz, qx, qy, p);
- fp8_inv(rz, rz);
- fp8_mul(rx, rx, rz);
- fp8_mul(ry, ry, rz);
- fp8_copy(e1[0][0], rx);
- fp8_copy(e1[0][1], ry);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
- pp_dbl_k48(e2, rx, ry, rz, p);
-#if EP_ADD == PROJC
- fp8_inv(rz, rz);
- fp8_mul(rx, rx, rz);
- fp8_mul(ry, ry, rz);
-#endif
- pp_add_k48_basic(e2, rx, ry, qx, qy, p);
- TEST_ASSERT(fp8_cmp(rx, e1[0][0]) == RLC_EQ && fp8_cmp(ry, e1[0][1]) == RLC_EQ, end);
+ ep8_rand(q);
+ ep8_rand(r);
+ ep8_copy(s, r);
+ pp_add_k48(e1, r, q, p);
+ pp_norm_k48(r, r);
+ ep8_add(s, s, q);
+ ep8_norm(s, s);
+ TEST_ASSERT(ep8_cmp(r, s) == RLC_EQ, end);
} TEST_END;
#if EP_ADD == BASIC || !defined(STRIP)
TEST_CASE("miller addition in affine coordinates is correct") {
ep_rand(p);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
+ ep8_rand(q);
+ ep8_rand(r);
+ ep8_copy(s, r);
fp48_zero(e1);
fp48_zero(e2);
- pp_dbl_k48(e1, rx, ry, rz, p);
- pp_add_k48(e1, rx, ry, rz, qx, qy, p);
+ pp_add_k48(e1, r, q, p);
pp_exp_k48(e1, e1);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
- pp_dbl_k48(e2, rx, ry, rz, p);
-#if EP_ADD == PROJC
- fp8_inv(rz, rz);
- fp8_mul(rx, rx, rz);
- fp8_mul(ry, ry, rz);
-#endif
- pp_add_k48_basic(e2, rx, ry, qx, qy, p);
+ pp_add_k48_basic(e2, s, q, p);
pp_exp_k48(e2, e2);
TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
#endif
-#if EP_ADD == BASIC || !defined(STRIP)
+#if EP_ADD == PROJC || EP_ADD == JACOB || !defined(STRIP)
TEST_CASE("miller addition in projective coordinates is correct") {
ep_rand(p);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
+ ep8_rand(q);
+ ep8_rand(r);
+ ep8_copy(s, r);
fp48_zero(e1);
fp48_zero(e2);
- pp_dbl_k48(e1, rx, ry, rz, p);
- pp_add_k48(e1, rx, ry, rz, qx, qy, p);
+ pp_add_k48(e1, r, q, p);
pp_exp_k48(e1, e1);
- fp8_copy(rx, qx);
- fp8_copy(ry, qy);
- fp8_copy(rz, qz);
- pp_dbl_k48(e2, rx, ry, rz, p);
- pp_add_k48_projc(e2, rx, ry, rz, qx, qy, p);
+ pp_add_k48_projc(e2, s, q, p);
pp_exp_k48(e2, e2);
TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
@@ -2516,87 +3388,108 @@ static int addition48(void) {
bn_free(n);
bn_free(k);
ep_free(p);
- fp8_free(qx);
- fp8_free(qy);
- fp8_free(qz);
- fp8_free(rx);
- fp8_free(ry);
- fp8_free(rz);
+ ep8_free(q);
+ ep8_free(r);
+ ep8_free(s);
fp48_free(e1);
fp48_free(e2);
return code;
}
static int pairing48(void) {
- int code = RLC_ERR;
+ int j, code = RLC_ERR;
bn_t k, n;
- ep_t p;
- fp8_t qx, qy, qz;
+ ep_t p[2];
+ ep8_t q[2], r;
fp48_t e1, e2;
bn_null(k);
bn_null(n);
- ep_null(p);
- fp8_null(qx);
- fp8_null(qy);
- fp8_null(qz);
fp48_null(e1);
fp48_null(e2);
+ ep8_null(r);
RLC_TRY {
bn_new(n);
bn_new(k);
- ep_new(p);
- fp8_new(qx);
- fp8_new(qy);
- fp8_new(qz);
fp48_new(e1);
fp48_new(e2);
+ ep8_new(r);
- ep_curve_get_ord(n);
+ for (j = 0; j < 2; j++) {
+ ep_null(p[j]);
+ ep8_null(q[j]);
+ ep_new(p[j]);
+ ep8_new(q[j]);
+ }
- fp_read_str(qx[0][0][0], QX000, strlen(QX000), 16);
- fp_read_str(qx[0][0][1], QX001, strlen(QX001), 16);
- fp_read_str(qx[0][1][0], QX010, strlen(QX010), 16);
- fp_read_str(qx[0][1][1], QX011, strlen(QX011), 16);
- fp_read_str(qx[1][0][0], QX100, strlen(QX100), 16);
- fp_read_str(qx[1][0][1], QX101, strlen(QX101), 16);
- fp_read_str(qx[1][1][0], QX110, strlen(QX110), 16);
- fp_read_str(qx[1][1][1], QX111, strlen(QX111), 16);
-
- fp_read_str(qy[0][0][0], QY000, strlen(QY000), 16);
- fp_read_str(qy[0][0][1], QY001, strlen(QY001), 16);
- fp_read_str(qy[0][1][0], QY010, strlen(QY010), 16);
- fp_read_str(qy[0][1][1], QY011, strlen(QY011), 16);
- fp_read_str(qy[1][0][0], QY100, strlen(QY100), 16);
- fp_read_str(qy[1][0][1], QY101, strlen(QY101), 16);
- fp_read_str(qy[1][1][0], QY110, strlen(QY110), 16);
- fp_read_str(qy[1][1][1], QY111, strlen(QY111), 16);
+ ep_curve_get_ord(n);
TEST_CASE("pairing non-degeneracy is correct") {
- ep_rand(p);
- pp_map_k48(e1, p, qx, qy);
+ ep_rand(p[0]);
+ ep8_rand(q[0]);
+ pp_map_k48(e1, p[0], q[0]);
TEST_ASSERT(fp48_cmp_dig(e1, 1) != RLC_EQ, end);
+ ep_set_infty(p[0]);
+ pp_map_k48(e1, p[0], q[0]);
+ TEST_ASSERT(fp48_cmp_dig(e1, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep8_set_infty(q[0]);
+ pp_map_k48(e1, p[0], q[0]);
+ TEST_ASSERT(fp48_cmp_dig(e1, 1) == RLC_EQ, end);
} TEST_END;
TEST_CASE("pairing is bilinear") {
- ep_rand(p);
+ ep_rand(p[0]);
+ ep8_rand(q[0]);
bn_rand_mod(k, n);
- pp_map_k48(e1, p, qx, qy);
- ep_mul(p, p, k);
- pp_map_k48(e2, p, qx, qy);
- fp48_exp(e1, e1, k);
+ ep8_mul(r, q[0], k);
+ pp_map_k48(e1, p[0], r);
+ pp_map_k48(e2, p[0], q[0]);
+ fp48_exp(e2, e2, k);
+ TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
+ ep_mul(p[0], p[0], k);
+ pp_map_k48(e2, p[0], q[0]);
+ TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
+ ep_dbl(p[0], p[0]);
+ pp_map_k48(e2, p[0], q[0]);
+ fp48_sqr(e1, e1);
TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
- fp8_set_dig(qz, 1);
- pp_dbl_k48(e2, qx, qy, qz, p);
- fp8_inv(qz, qz);
- fp8_mul(qx, qx, qz);
- fp8_mul(qy, qy, qz);
- fp8_set_dig(qz, 1);
- pp_map_k48(e2, p, qx, qy);
+ ep8_dbl(q[0], q[0]);
+ pp_map_k48(e2, p[0], q[0]);
fp48_sqr(e1, e1);
TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
} TEST_END;
+
+ TEST_CASE("multi-pairing is correct") {
+ ep_rand(p[i % 2]);
+ ep8_rand(q[i % 2]);
+ pp_map_k48(e1, p[i % 2], q[i % 2]);
+ ep_rand(p[1 - (i % 2)]);
+ ep8_set_infty(q[1 - (i % 2)]);
+ pp_map_sim_k48(e2, p, q, 2);
+ TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
+ ep_set_infty(p[1 - (i % 2)]);
+ ep8_rand(q[1 - (i % 2)]);
+ pp_map_sim_k48(e2, p, q, 2);
+ TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
+ ep8_set_infty(q[i % 2]);
+ pp_map_sim_k48(e2, p, q, 2);
+ TEST_ASSERT(fp48_cmp_dig(e2, 1) == RLC_EQ, end);
+ ep_rand(p[0]);
+ ep8_rand(q[0]);
+ pp_map_k48(e1, p[0], q[0]);
+ ep_rand(p[1]);
+ ep8_rand(q[1]);
+ pp_map_k48(e2, p[1], q[1]);
+ fp48_mul(e1, e1, e2);
+ pp_map_sim_k48(e2, p, q, 2);
+ TEST_ASSERT(fp48_cmp(e1, e2) == RLC_EQ, end);
+ ep_neg(p[1], p[0]);
+ ep8_copy(q[1], q[0]);
+ pp_map_sim_k48(e1, p, q, 2);
+ TEST_ASSERT(fp48_cmp_dig(e1, 1) == RLC_EQ, end);
+ } TEST_END;
}
RLC_CATCH_ANY {
util_print("FATAL ERROR!\n");
@@ -2606,12 +3499,14 @@ static int pairing48(void) {
end:
bn_free(n);
bn_free(k);
- ep_free(p);
- fp8_free(qx);
- fp8_free(qy);
- fp8_free(qz);
fp48_free(e1);
fp48_free(e2);
+ ep8_free(r);
+
+ for (j = 0; j < 2; j++) {
+ ep_free(p[j]);
+ ep8_free(q[j]);
+ }
return code;
}
@@ -3033,6 +3928,23 @@ int main(void) {
util_banner("Arithmetic", 1);
+ if (ep_param_embed() == 1) {
+ if (doubling1() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (addition1() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (pairing1() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+ }
+
if (ep_param_embed() == 2) {
if (doubling2() != RLC_OK) {
core_clean();
@@ -3067,35 +3979,35 @@ int main(void) {
}
}
- if (ep_param_embed() == 24) {
- if (doubling24() != RLC_OK) {
+ if (ep_param_embed() == 12) {
+ if (doubling12() != RLC_OK) {
core_clean();
return 1;
}
- if (addition24() != RLC_OK) {
+ if (addition12() != RLC_OK) {
core_clean();
return 1;
}
- if (pairing24() != RLC_OK) {
+ if (pairing12() != RLC_OK) {
core_clean();
return 1;
}
}
- if (ep_param_embed() == 12) {
- if (doubling12() != RLC_OK) {
+ if (ep_param_embed() == 16) {
+ if (doubling16() != RLC_OK) {
core_clean();
return 1;
}
- if (addition12() != RLC_OK) {
+ if (addition16() != RLC_OK) {
core_clean();
return 1;
}
- if (pairing12() != RLC_OK) {
+ if (pairing16() != RLC_OK) {
core_clean();
return 1;
}
@@ -3118,6 +4030,23 @@ int main(void) {
}
}
+ if (ep_param_embed() == 24) {
+ if (doubling24() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (addition24() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+
+ if (pairing24() != RLC_OK) {
+ core_clean();
+ return 1;
+ }
+ }
+
if (ep_param_embed() == 48) {
if (doubling48() != RLC_OK) {
core_clean();
@@ -3156,4 +4085,4 @@ int main(void) {
core_clean();
return 0;
-}
+}
\ No newline at end of file
diff --git a/tools/relic-gen-label.sh b/tools/relic-gen-label.sh
index 992f547d7..87b462e27 100755
--- a/tools/relic-gen-label.sh
+++ b/tools/relic-gen-label.sh
@@ -172,6 +172,13 @@ echo "#define ep4_t RLC_PREFIX(ep4_t)"
echo
REDEF2 epx ep4
+echo "#undef ep8_st"
+echo "#undef ep8_t"
+echo "#define ep8_st RLC_PREFIX(ep8_st)"
+echo "#define ep8_t RLC_PREFIX(ep8_t)"
+echo
+REDEF2 epx ep8
+
echo "#undef fp2_st"
echo "#undef fp2_t"
echo "#undef dv2_t"
diff --git a/tools/run-pairings.sh b/tools/run-pairings.sh
index c6b4988d5..0f091790f 100755
--- a/tools/run-pairings.sh
+++ b/tools/run-pairings.sh
@@ -9,5 +9,9 @@ for script in preset/x64-pbc-*; do
../$script ../
make
./bin/test_fpx && ./bin/test_pc
+ if [ $? -ne 0 ]; then
+ echo "FAILED: target-$file"
+ exit 1
+ fi
cd ..
done