diff --git a/src/pp/relic_pp_exp_k18.c b/src/pp/relic_pp_exp_k18.c index 027398119..f70fe8122 100644 --- a/src/pp/relic_pp_exp_k18.c +++ b/src/pp/relic_pp_exp_k18.c @@ -258,6 +258,116 @@ void pp_exp_sg(fp18_t c, fp18_t a) { } } +/** + * Computes the final exponentiation of a pairing defined over an FM curve. + * + * @param[out] c - the result. + * @param[in] a - the extension field element to exponentiate. + */ +void pp_exp_fm(fp18_t c, fp18_t a) { + fp18_t t0, t1, t2, t3, t4; + const int *b; + bn_t x; + int l; + + bn_null(x); + fp18_null(t0); + fp18_null(t1); + fp18_null(t2); + fp18_null(t3); + fp18_null(t4); + + RLC_TRY { + bn_new(x); + fp18_new(t0); + fp18_new(t1); + fp18_new(t2); + fp18_new(t3); + fp18_new(t4); + + 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); + + /* Compute t0 = f^|u|. */ + fp18_exp_cyc_sps(t0, c, b, l, RLC_POS); + if (bn_sign(x) == RLC_POS) { + fp18_inv_cyc(t0, t0); + } + fp18_frb(t1, c, 1); + fp18_mul(t0, t0, t1); + + fp18_exp_cyc_sps(t1, t0, b, l, RLC_POS); + + fp18_frb(t2, t1, 3); + fp18_frb(t3, t0, 1); + if (bn_sign(x) == RLC_POS) { + fp18_inv_cyc(t3, t3); + fp18_mul(t2, t2, t3); + fp18_inv_cyc(t1, t1); + } else { + fp18_mul(t2, t2, t3); + fp18_inv_cyc(t2, t2); + } + fp18_mul(t1, t1, t2); + fp18_exp_cyc_sps(t1, t1, b, l, RLC_POS); + if (bn_sign(x) == RLC_NEG) { + fp18_inv_cyc(t1, t1); + } + + fp18_frb(t0, t0, 4); + fp18_mul(t0, t0, t2); + fp18_exp_cyc_sps(t3, t1, b, l, RLC_POS); + fp18_exp_cyc_sps(t3, t3, b, l, RLC_POS); + fp18_inv_cyc(t3, t3); + fp18_mul(t0, t0, t3); + + bn_sub_dig(x, x, 1); + bn_abs(x, x); + fp18_exp_cyc(t2, t0, x); + if (bn_sign(x) == RLC_NEG) { + fp18_sqr_cyc(t3, t2); + fp18_mul(t3, t3, t0); + } else { + fp18_inv_cyc(t3, t2); + fp18_sqr_cyc(t3, t3); + fp18_mul(t3, t3, t0); + } + + bn_div_dig(x, x, 3); + fp18_exp_cyc(t2, t2, x); + fp18_sqr_cyc(t4, t2); + fp18_mul(t4, t4, t2); + + fp_prime_get_par(x); + bn_add_dig(x, x, 1); + bn_abs(x, x); + fp18_exp_cyc(t0, t4, x); + fp18_exp_cyc(t0, t0, x); + fp18_mul(t4, t4, t0); + fp18_mul(t4, t4, t3); + + fp18_exp_cyc_sps(t0, t4, b, l, RLC_POS); + fp18_exp_cyc_sps(t0, t0, b, l, RLC_POS); + fp18_mul(t4, t4, t0); + fp18_mul(t2, t2, t4); + fp18_mul(c, c, t1); + fp18_mul(c, c, 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); + fp18_free(t4); + } +} + /*============================================================================*/ /* Public definitions */ /*============================================================================*/ @@ -270,5 +380,8 @@ void pp_exp_k18(fp18_t c, fp18_t a) { case EP_SG18: pp_exp_sg(c, a); break; + case EP_FM18: + pp_exp_fm(c, a); + break; } } diff --git a/src/pp/relic_pp_map_k18.c b/src/pp/relic_pp_map_k18.c index 95c61a73e..99f733ed9 100644 --- a/src/pp/relic_pp_map_k18.c +++ b/src/pp/relic_pp_map_k18.c @@ -549,6 +549,16 @@ void pp_map_oatep_k18(fp18_t r, const ep_t p, const ep3_t q) { pp_fin_k18_oatep(r, t[0], _q[0], _p[0], 1); pp_exp_k18(r, r); break; + case EP_FM18: + /* 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_exp_k18(r, r); + break; } } } @@ -628,6 +638,15 @@ void pp_map_sim_oatep_k18(fp18_t r, const ep_t *p, const ep3_t *q, int m) { } pp_exp_k18(r, r); break; + case EP_FM18: + /* 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); + } + pp_exp_k18(r, r); + break; } } }