/**
 * Multiplies a point on a Barreto-Lynn-Soctt curve by the cofactor.
 *
 * @param[out] r			- the result.
 * @param[in] p				- the point to multiply.
 */
void ep2_mul_cof_b12(ep2_t r, ep2_t p) {
	bn_t x;
	ep2_t t0, t1, t2, t3;

	ep2_null(t0);
	ep2_null(t1);
	ep2_null(t2);
	ep2_null(t3);
	bn_null(x);

	TRY {
		ep2_new(t0);
		ep2_new(t1);
		ep2_new(t2);
		ep2_new(t3);
		bn_new(x);

		fp_param_get_var(x);

		/* Compute t0 = xP. */
		ep2_mul(t0, p, x);
		if (bn_sign(x) == BN_NEG) {
			ep2_neg(t0, t0);
		}
		/* Compute t1 = [x^2]P. */
		ep2_mul(t1, t0, x);
		if (bn_sign(x) == BN_NEG) {
			ep2_neg(t1, t1);
		}

		/* t2 = (x^2 - x - 1)P = x^2P - x*P - P. */
		ep2_sub(t2, t1, t0);
		ep2_sub(t2, t2, p);
		/* t3 = \psi(x - 1)P. */
		ep2_sub(t3, t0, p);
		ep2_norm(t3, t3);
		ep2_frb(t3, t3, 1);
		ep2_add(t2, t2, t3);
		/* t3 = \psi^2(2P). */
		ep2_dbl(t3, p);
		ep2_norm(t3, t3);
		ep2_frb(t3, t3, 2);
		ep2_add(t2, t2, t3);
		ep2_norm(r, t2);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		ep2_free(t0);
		ep2_free(t1);
		ep2_free(t2);
		ep2_free(t3);
		bn_free(x);
	}
}
Beispiel #2
0
void ep2_curve_get_vs(bn_t *v) {
	bn_t x, t;

	bn_null(x);
	bn_null(t);

	TRY {
		bn_new(x);
		bn_new(t);

		fp_param_get_var(x);

		bn_mul_dig(v[0], x, 3);
		bn_add_dig(v[0], v[0], 1);

		bn_copy(v[1], x);
		bn_copy(v[2], x);
		bn_copy(v[3], x);

		bn_sqr(x, x);
		bn_lsh(t, x, 1);
		bn_add(v[0], v[0], t);
		bn_add(v[3], v[3], t);
		bn_lsh(t, t, 1);
		bn_add(v[2], v[2], t);
		bn_lsh(t, t, 1);
		bn_add(v[1], v[1], t);

		fp_param_get_var(t);
		bn_mul(x, x, t);
		bn_mul_dig(t, x, 6);
		bn_add(v[2], v[2], t);
		bn_lsh(t, t, 1);
		bn_add(v[1], v[1], t);
		bn_neg(v[3], v[3]);
	} CATCH_ANY {
		THROW(ERR_CAUGHT);
	} FINALLY {
		bn_free(x);
		bn_free(t);
	}
}
/**
 * Multiplies a point on a Barreto-Naehrig curve by the cofactor.
 *
 * @param[out] r			- the result.
 * @param[in] p				- the point to multiply.
 */
void ep2_mul_cof_bn(ep2_t r, ep2_t p) {
	bn_t x;
	ep2_t t0, t1, t2;

	ep2_null(t0);
	ep2_null(t1);
	ep2_null(t2);
	bn_null(x);

	TRY {
		ep2_new(t0);
		ep2_new(t1);
		ep2_new(t2);
		bn_new(x);

		fp_param_get_var(x);

		/* Compute t0 = xP. */
		ep2_mul(t0, p, x);
		if (bn_sign(x) == BN_NEG) {
			ep2_neg(t0, t0);
		}

		/* Compute t1 = \psi(3xP). */
		ep2_dbl(t1, t0);
		ep2_add(t1, t1, t0);
		ep2_norm(t1, t1);
		ep2_frb(t1, t1, 1);

		/* Compute t2 = \psi^3(P) + t0 + t1 + \psi^2(xP). */
		ep2_frb(t2, p, 2);
		ep2_frb(t2, t2, 1);
		ep2_add(t2, t2, t0);
		ep2_add(t2, t2, t1);
		ep2_frb(t1, t0, 2);
		ep2_add(t2, t2, t1);

		ep2_norm(r, t2);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		ep2_free(t0);
		ep2_free(t1);
		ep2_free(t2);
		bn_free(x);
	}
}
Beispiel #4
0
void pp_map_sim_oatep_k12(fp12_t r, ep_t *p, ep2_t *q, int m) {
	ep_t _p[m];
	ep2_t t[m], _q[m];
	bn_t a;
	int i, j, len = FP_BITS, s[FP_BITS];

	TRY {
		bn_null(a);
		bn_new(a);
		for (i = 0; i < m; i++) {
			ep_null(_p[i]);
			ep2_null(_q[i]);
			ep2_null(t[i]);
			ep_new(_p[i]);
			ep2_new(_q[i]);
			ep2_new(t[i]);
		}

		j = 0;
		for (i = 0; i < m; i++) {
			if (!ep_is_infty(p[i]) && !ep2_is_infty(q[i])) {
				ep_norm(_p[j], p[i]);
				ep2_norm(_q[j++], q[i]);
			}
		}

		fp12_set_dig(r, 1);
		fp_param_get_var(a);
		bn_mul_dig(a, a, 6);
		bn_add_dig(a, a, 2);
		fp_param_get_map(s, &len);

		if (j > 0) {
			switch (ep_param_get()) {
				case BN_P158:
				case BN_P254:
				case BN_P256:
				case BN_P638:
					/* r = f_{|a|,Q}(P). */
					pp_mil_sps_k12(r, t, _q, _p, j, s, len);
					if (bn_sign(a) == BN_NEG) {
						/* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
						fp12_inv_uni(r, r);
					}
					for (i = 0; i < j; i++) {
						if (bn_sign(a) == BN_NEG) {
							ep2_neg(t[i], t[i]);
						}
						pp_fin_k12_oatep(r, t[i], _q[i], _p[i]);
					}
					pp_exp_k12(r, r);
					break;
				case B12_P638:
					/* r = f_{|a|,Q}(P). */
					pp_mil_sps_k12(r, t, _q, _p, j, s, len);
					if (bn_sign(a) == BN_NEG) {
						fp12_inv_uni(r, r);
					}
					pp_exp_k12(r, r);
					break;
			}
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		bn_free(a);
		for (i = 0; i < m; i++) {
			ep_free(_p[i]);
			ep2_free(_q[i]);
			ep2_free(t[i]);
		}
	}
}
Beispiel #5
0
void pp_map_oatep_k12(fp12_t r, ep_t p, ep2_t q) {
	ep_t _p[1];
	ep2_t t[1], _q[1];
	bn_t a;
	int len = FP_BITS, s[FP_BITS];

	ep_null(_p[0]);
	ep2_null(_q[0]);
	ep2_null(t[0]);
	bn_null(a);

	TRY {
		ep_new(_p[0]);
		ep2_new(_q[0]);
		ep2_new(t[0]);
		bn_new(a);

		fp_param_get_var(a);
		bn_mul_dig(a, a, 6);
		bn_add_dig(a, a, 2);
		fp_param_get_map(s, &len);
		fp12_set_dig(r, 1);

		ep_norm(_p[0], p);
		ep2_norm(_q[0], q);

		if (!ep_is_infty(_p[0]) && !ep2_is_infty(_q[0])) {
			switch (ep_param_get()) {
				case BN_P158:
				case BN_P254:
				case BN_P256:
				case BN_P638:
					/* r = f_{|a|,Q}(P). */
					pp_mil_sps_k12(r, t, _q, _p, 1, s, len);
					if (bn_sign(a) == BN_NEG) {
						/* f_{-a,Q}(P) = 1/f_{a,Q}(P). */
						fp12_inv_uni(r, r);
						ep2_neg(t[0], t[0]);
					}
					pp_fin_k12_oatep(r, t[0], _q[0], _p[0]);
					pp_exp_k12(r, r);
					break;
				case B12_P638:
					/* r = f_{|a|,Q}(P). */
					pp_mil_sps_k12(r, t, _q, _p, 1, s, len);
					if (bn_sign(a) == BN_NEG) {
						fp12_inv_uni(r, r);
						ep2_neg(t[0], t[0]);
					}
					pp_exp_k12(r, r);
					break;
			}
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		ep_free(_p[0]);
		ep2_free(_q[0]);
		ep2_free(t[0]);
		bn_free(a);
	}
}
Beispiel #6
0
void fp_param_set(int param) {
	bn_t t0, t1, t2, p;
	int f[10] = { 0 };

	bn_null(t0);
	bn_null(t1);
	bn_null(t2);
	bn_null(p);

	/* Suppress possible unused parameter warning. */
	(void) f;

	TRY {
		bn_new(t0);
		bn_new(t1);
		bn_new(t2);
		bn_new(p);

		core_get()->fp_id = param;

		switch (param) {
#if FP_PRIME == 158
			case BN_158:
				/* x = 4000000031. */
				fp_param_get_var(t0);
				/* p = 36 * x^4 + 36 * x^3 + 24 * x^2 + 6 * x + 1. */
				bn_set_dig(p, 1);
				bn_mul_dig(t1, t0, 6);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 24);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul(t1, t1, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				bn_mul(t0, t0, t0);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				fp_prime_set_dense(p);
				break;
#elif FP_PRIME == 160
			case SECG_160:
				/* p = 2^160 - 2^31 + 1. */
				f[0] = -1;
				f[1] = -31;
				f[2] = 160;
				fp_prime_set_pmers(f, 3);
				break;
			case SECG_160D:
				/* p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1.*/
				f[0] = -1;
				f[1] = -2;
				f[2] = -3;
				f[3] = -7;
				f[4] = -8;
				f[5] = -9;
				f[6] = -12;
				f[7] = -14;
				f[8] = -32;
				f[9] = 160;
				fp_prime_set_pmers(f, 10);
				break;
#elif FP_PRIME == 192
			case NIST_192:
				/* p = 2^192 - 2^64 - 1. */
				f[0] = -1;
				f[1] = -64;
				f[2] = 192;
				fp_prime_set_pmers(f, 3);
				break;
			case SECG_192:
				/* p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1.*/
				f[0] = -1;
				f[1] = -3;
				f[2] = -6;
				f[3] = -7;
				f[4] = -8;
				f[5] = -12;
				f[6] = -32;
				f[7] = 192;
				fp_prime_set_pmers(f, 8);
				break;
#elif FP_PRIME == 224
			case NIST_224:
				/* p = 2^224 - 2^96 + 1. */
				f[0] = 1;
				f[1] = -96;
				f[2] = 224;
				fp_prime_set_pmers(f, 3);
				break;
			case SECG_224:
				/* p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1.*/
				f[0] = -1;
				f[1] = -1;
				f[2] = -4;
				f[3] = -7;
				f[4] = -9;
				f[5] = -11;
				f[6] = -12;
				f[7] = -32;
				f[8] = 224;
				fp_prime_set_pmers(f, 9);
				break;
#elif FP_PRIME == 254
			case BN_254:
				/* x = -4080000000000001. */
				fp_param_get_var(t0);
				/* p = 36 * x^4 + 36 * x^3 + 24 * x^2 + 6 * x + 1. */
				bn_set_dig(p, 1);
				bn_mul_dig(t1, t0, 6);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 24);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul(t1, t1, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				bn_mul(t0, t0, t0);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				fp_prime_set_dense(p);
				break;
#elif FP_PRIME == 256
			case NIST_256:
				/* p = 2^256 - 2^224 + 2^192 + 2^96 - 1. */
				f[0] = -1;
				f[1] = 96;
				f[2] = 192;
				f[3] = -224;
				f[4] = 256;
				fp_prime_set_pmers(f, 5);
				break;
			case SECG_256:
				/* p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1. */
				f[0] = -1;
				f[1] = -4;
				f[2] = -6;
				f[3] = -7;
				f[4] = -8;
				f[5] = -9;
				f[6] = -32;
				f[7] = 256;
				fp_prime_set_pmers(f, 8);
				break;
			case BN_256:
				/* x = 6000000000001F2D. */
				fp_param_get_var(t0);
				/* p = 36 * x^4 + 36 * x^3 + 24 * x^2 + 6 * x + 1. */
				bn_set_dig(p, 1);
				bn_mul_dig(t1, t0, 6);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 24);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul(t1, t1, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				bn_mul(t0, t0, t0);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				fp_prime_set_dense(p);
				break;
#elif FP_PRIME == 384
			case NIST_384:
				/* p = 2^384 - 2^128 - 2^96 + 2^32 - 1. */
				f[0] = -1;
				f[1] = 32;
				f[2] = -96;
				f[3] = -128;
				f[4] = 384;
				fp_prime_set_pmers(f, 5);
				break;
#elif FP_PRIME == 477
			case B24_477:
				fp_param_get_var(t0);
				/* p = (u - 1)^2 * (u^8 - u^4 + 1) div 3 + u. */
				bn_sub_dig(p, t0, 1);
				bn_sqr(p, p);
				bn_sqr(t1, t0);
				bn_sqr(t1, t1);
				bn_sqr(t2, t1);
				bn_sub(t2, t2, t1);
				bn_add_dig(t2, t2, 1);
				bn_mul(p, p, t2);
				bn_div_dig(p, p, 3);
				bn_add(p, p, t0);
				fp_prime_set_dense(p);
				break;
#elif FP_PRIME == 508
			case KSS_508:
				fp_param_get_var(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);
				break;
#elif FP_PRIME == 521
			case NIST_521:
				/* p = 2^521 - 1. */
				f[0] = -1;
				f[1] = 521;
				fp_prime_set_pmers(f, 2);
				break;
#elif FP_PRIME == 638
			case BN_638:
				fp_param_get_var(t0);
				/* p = 36 * x^4 + 36 * x^3 + 24 * x^2 + 6 * x + 1. */
				bn_set_dig(p, 1);
				bn_mul_dig(t1, t0, 6);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 24);
				bn_add(p, p, t1);
				bn_mul(t1, t0, t0);
				bn_mul(t1, t1, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				bn_mul(t0, t0, t0);
				bn_mul(t1, t0, t0);
				bn_mul_dig(t1, t1, 36);
				bn_add(p, p, t1);
				fp_prime_set_dense(p);
				break;
			case B12_638:
				fp_param_get_var(t0);
				/* p = (x^2 - 2x + 1) * (x^4 - x^2 + 1)/3 + x. */
				bn_sqr(t1, t0);
				bn_sqr(p, t1);
				bn_sub(p, p, t1);
				bn_add_dig(p, p, 1);
				bn_sub(t1, t1, t0);
				bn_sub(t1, t1, t0);
				bn_add_dig(t1, t1, 1);
				bn_mul(p, p, t1);
				bn_div_dig(p, p, 3);
				bn_add(p, p, t0);
				fp_prime_set_dense(p);
				break;
#elif FP_PRIME == 1536
			case SS_1536:
				fp_param_get_var(t0);
				bn_read_str(p, SS_P1536, strlen(SS_P1536), 16);
				bn_mul(p, p, t0);
				bn_dbl(p, p);
				bn_sub_dig(p, p, 1);
				fp_prime_set_dense(p);
				break;
#else
			default:
				bn_gen_prime(p, FP_BITS);
				fp_prime_set_dense(p);
				core_get()->fp_id = 0;
				break;
#endif
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		bn_free(t0);
		bn_free(t1);
		bn_free(t2);
		bn_free(p);
	}
}
Beispiel #7
0
void fp_param_get_sps(int *s, int *len) {
	bn_t a;

	bn_null(a);

	if (*len < MAX_TERMS) {
		THROW(ERR_NO_BUFFER);
	}

	TRY {
		bn_new(a);

		*len = 0;

		switch (fp_param_get()) {
			case BN_158:
			case BN_254:
			case BN_256:
				fp_param_get_var(a);
				if (bn_sign(a) == BN_NEG) {
					bn_neg(a, a);
				}
				*len = bn_ham(a);
				for (int i = 0, j = 0; j < bn_bits(a); j++) {
					if (bn_test_bit(a, j)) {
						s[i++] = j;
					}
				}
				break;
			case B24_477:
				s[0] = 7;
				s[1] = -31;
				s[2] = -45;
				s[3] = 48;
				*len = 4;
				break;
			case KSS_508:
				s[0] = -12;
				s[1] = -46;
				s[2] = 51;
				s[3] = 64;
				*len = 4;
				break;
			case BN_638:
				s[0] = 0;
				s[1] = -68;
				s[2] = -128;
				s[3] = 158;
				*len = 4;
				break;
			case B12_638:
				s[0] = -5;
				s[1] = -93;
				s[2] = -105;
				s[3] = 107;
				*len = 4;
				break;
			case SS_1536:
				s[0] = 0;
				s[1] = 41;
				s[2] = 255;
				*len = 3;
				break;
			default:
				THROW(ERR_NO_VALID);
				break;
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		bn_free(a);
	}
}
Beispiel #8
0
/**
 * Computes the final exponentiation of a pairing defined over a Barreto-Naehrig
 * curve.
 *
 * @param[out] c			- the result.
 * @param[in] a				- the extension field element to exponentiate.
 */
static void pp_exp_bn(fp12_t c, fp12_t a) {
	fp12_t t0, t1, t2, t3;
	int l = MAX_TERMS + 1, b[MAX_TERMS + 1];
	bn_t x;

	fp12_null(t0);
	fp12_null(t1);
	fp12_null(t2);
	fp12_null(t3);
	bn_null(x);

	TRY {
		fp12_new(t0);
		fp12_new(t1);
		fp12_new(t2);
		fp12_new(t3);
		bn_new(x);

		/*
		 * New final exponentiation following Fuentes-Castañeda, Knapp and
		 * Rodríguez-Henríquez: Fast Hashing to G_2.
		 */
		fp_param_get_var(x);
		fp_param_get_sps(b, &l);

		/* First, compute m = f^(p^6 - 1)(p^2 + 1). */
		fp12_conv_cyc(c, a);

		/* Now compute m^((p^4 - p^2 + 1) / r). */
		/* t0 = m^2x. */
		fp12_exp_cyc_sps(t0, c, b, l);
		fp12_sqr_cyc(t0, t0);
		/* t1 = m^6x. */
		fp12_sqr_cyc(t1, t0);
		fp12_mul(t1, t1, t0);
		/* t2 = m^6x^2. */
		fp12_exp_cyc_sps(t2, t1, b, l);
		/* t3 = m^12x^3. */
		fp12_sqr_cyc(t3, t2);
		fp12_exp_cyc_sps(t3, t3, b, l);

		if (bn_sign(x) == BN_NEG) {
			fp12_inv_uni(t0, t0);
			fp12_inv_uni(t1, t1);
			fp12_inv_uni(t3, t3);
		}

		/* t3 = a = m^12x^3 * m^6x^2 * m^6x. */
		fp12_mul(t3, t3, t2);
		fp12_mul(t3, t3, t1);

		/* t0 = b = 1/(m^2x) * t3. */
		fp12_inv_uni(t0, t0);
		fp12_mul(t0, t0, t3);

		/* Compute t2 * t3 * m * b^p * a^p^2 * [b * 1/m]^p^3. */
		fp12_mul(t2, t2, t3);
		fp12_mul(t2, t2, c);
		fp12_inv_uni(c, c);
		fp12_mul(c, c, t0);
		fp12_frb(c, c, 3);
		fp12_mul(c, c, t2);
		fp12_frb(t0, t0, 1);
		fp12_mul(c, c, t0);
		fp12_frb(t3, t3, 2);
		fp12_mul(c, c, t3);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		fp12_free(t0);
		fp12_free(t1);
		fp12_free(t2);
		fp12_free(t3);
		bn_free(x);
	}
}
Beispiel #9
0
/**
 * Computes the final exponentiation of a pairing defined over a
 * Barreto-Lynn-Scott curve.
 *
 * @param[out] c			- the result.
 * @param[in] a				- the extension field element to exponentiate.
 */
static void pp_exp_b12(fp12_t c, fp12_t a) {
	fp12_t t[10];
	bn_t x;
	int l = MAX_TERMS + 1, b[MAX_TERMS + 1];

	bn_null(x);

	TRY {
		for (int i = 0; i < 10; i++) {
			fp12_null(t[i]);
			fp12_new(t[i]);
		}
		bn_new(x);

		fp_param_get_var(x);
		fp_param_get_sps(b, &l);

		/* First, compute m^(p^6 - 1)(p^2 + 1). */
		fp12_conv_cyc(c, a);

		/* v0 = f^-1. */
		fp12_inv_uni(t[0], c);

		/* v1 = f^-2. */
		fp12_sqr_cyc(t[1], t[0]);

		/* v2 = f^x. */
		fp12_exp_cyc_sps(t[2], c, b, l);

		if (bn_sign(x) == BN_NEG) {
			fp12_inv_uni(t[2], t[2]);
		}

		/* v3 = f^2x. */
		fp12_sqr_cyc(t[3], t[2]);

		/* v4 = f^(x - 2). */
		fp12_mul(t[4], t[2], t[1]);

		/* v5 = f^(x^2 - 2x). */
		fp12_exp_cyc_sps(t[5], t[4], b, l);

		if (bn_sign(x) == BN_NEG) {
			fp12_inv_uni(t[5], t[5]);
		}

		/* v6 = f^(x^3 - 2x^2). */
		fp12_exp_cyc_sps(t[6], t[5], b, l);

		if (bn_sign(x) == BN_NEG) {
			fp12_inv_uni(t[6], t[6]);
		}

		/* v7 = f^(x^4 - 2x^3 + 2x). */
		fp12_exp_cyc_sps(t[7], t[6], b, l);
		if (bn_sign(x) == BN_NEG) {
			fp12_inv_uni(t[7], t[7]);
		}
		fp12_mul(t[7], t[7], t[3]);

		/* v8 = f^(x^5 - 2x^4 + 2x^2). */
		fp12_exp_cyc_sps(t[8], t[7], b, l);
		if (bn_sign(x) == BN_NEG) {
			fp12_inv_uni(t[8], t[8]);
		}

		/* v7 = f^(x^4 - 2x^3 + 2x - 1)^p. */
		fp12_mul(t[7], t[7], t[0]);
		fp12_frb(t[7], t[7], 1);

		/* v6 = f^(x^3 - 2x^2 + x)^p^2. */
		fp12_mul(t[6], t[6], t[2]);
		fp12_frb(t[6], t[6], 2);

		/* v5 = f^(x^2 - 2x + 1)^p^3. */
		fp12_mul(t[5], t[5], c);
		fp12_frb(t[5], t[5], 1);
		fp12_frb(t[5], t[5], 2);

		/* v4 = f^(2 - x). */
		fp12_inv_uni(t[4], t[4]);

		/* Now compute f * v4 * v5 * v6 * v7 * v8. */
		fp12_mul(c, c, t[4]);
		fp12_mul(c, c, t[5]);
		fp12_mul(c, c, t[6]);
		fp12_mul(c, c, t[7]);
		fp12_mul(c, c, t[8]);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		for (int i = 0; i < 9; i++) {
			fp12_free(t[i]);
		}
		bn_free(x);
	}
}