Пример #1
0
void ep_dbl_projc(ep_t r, const ep_t p) {
	if (ep_is_infty(p)) {
		ep_set_infty(r);
		return;
	}

	if (fp_is_zero(p->x)) {
		ep_set_infty(r);
		return;
	}
	ep_dbl_projc_imp(r, p);
}
Пример #2
0
void ep_sub_basic(ep_t r, const ep_t p, const ep_t q) {
	ep_t t;

	ep_null(t);

	if (p == q) {
		ep_set_infty(r);
		return;
	}

	TRY {
		ep_new(t);

		ep_neg_basic(t, q);
		ep_add_basic(r, p, t);

		r->norm = 1;
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		ep_free(t);
	}
}
Пример #3
0
void ep_dbl_basic(ep_t r, const ep_t p) {
	if (ep_is_infty(p)) {
		ep_set_infty(r);
		return;
	}
	ep_dbl_basic_imp(r, NULL, p);
}
Пример #4
0
void ep_curve_init(void) {
	ctx_t *ctx = core_get();
#ifdef EP_PRECO
	for (int i = 0; i < RELIC_EP_TABLE; i++) {
		ctx->ep_ptr[i] = &(ctx->ep_pre[i]);
	}
#endif
#if ALLOC == STATIC
	fp_new(ctx->ep_g.x);
	fp_new(ctx->ep_g.y);
	fp_new(ctx->ep_g.z);
#ifdef EP_PRECO
	for (int i = 0; i < RELIC_EP_TABLE; i++) {
		fp_new(ctx->ep_pre[i].x);
		fp_new(ctx->ep_pre[i].y);
		fp_new(ctx->ep_pre[i].z);
	}
#endif
#endif
	ep_set_infty(&ctx->ep_g);
	bn_init(&ctx->ep_r, FP_DIGS);
	bn_init(&ctx->ep_h, FP_DIGS);
#if defined(EP_ENDOM) && (EP_MUL == LWNAF || EP_FIX == COMBS || EP_FIX == LWNAF || !defined(STRIP))
	for (int i = 0; i < 3; i++) {
		bn_init(&(ctx->ep_v1[i]), FP_DIGS);
		bn_init(&(ctx->ep_v2[i]), FP_DIGS);
	}
#endif
}
Пример #5
0
void ep_dbl_slp_basic(ep_t r, fp_t s, const ep_t p) {
	if (ep_is_infty(p)) {
		ep_set_infty(r);
		return;
	}

	ep_dbl_basic_imp(r, s, p);
}
Пример #6
0
void ep_neg_projc(ep_t r, const ep_t p) {
	if (ep_is_infty(p)) {
		ep_set_infty(r);
		return;
	}

	if (r != p) {
		fp_copy(r->x, p->x);
		fp_copy(r->z, p->z);
	}

	fp_neg(r->y, p->y);

	r->norm = p->norm;
}
Пример #7
0
void ep_read_bin(ep_t a, const uint8_t *bin, int len) {
	if (len == 1) {
		if (bin[0] == 0) {
			ep_set_infty(a);
			return;
		} else {
			THROW(ERR_NO_BUFFER);
			return;
		}
	}

	if (len != (FP_BYTES + 1) && len != (2 * FP_BYTES + 1)) {
		THROW(ERR_NO_BUFFER);
		return;
	}

	a->norm = 1;
	fp_set_dig(a->z, 1);
	fp_read_bin(a->x, bin + 1, FP_BYTES);
	if (len == FP_BYTES + 1) {
		switch(bin[0]) {
			case 2:
				fp_zero(a->y);
				break;
			case 3:
				fp_zero(a->y);
				fp_set_bit(a->y, 0, 1);
				break;
			default:
				THROW(ERR_NO_VALID);
				break;
		}
		ep_upk(a, a);
	}

	if (len == 2 * FP_BYTES + 1) {
		if (bin[0] == 4) {
			fp_read_bin(a->y, bin + FP_BYTES + 1, FP_BYTES);
		} else {
			THROW(ERR_NO_VALID);
		}
	}
}
Пример #8
0
/**
 * 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.
 */
void ep_mul_sim_endom(ep_t r, const ep_t p, const bn_t k, const ep_t q,
		const bn_t m, const ep_t *t) {
	int len, len0, len1, len2, len3, i, n, sk0, sk1, sl0, sl1, w, g = 0;
	int8_t naf0[FP_BITS + 1], naf1[FP_BITS + 1], *t0, *t1;
	int8_t naf2[FP_BITS + 1], naf3[FP_BITS + 1], *t2, *t3;
	bn_t k0, k1, l0, l1;
	bn_t ord, v1[3], v2[3];
	ep_t u;
	ep_t tab0[1 << (EP_WIDTH - 2)];
	ep_t tab1[1 << (EP_WIDTH - 2)];

	bn_null(ord);
	bn_null(k0);
	bn_null(k1);
	bn_null(l0);
	bn_null(l1);
	ep_null(u);

	for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) {
		ep_null(tab0[i]);
		ep_null(tab1[i]);
	}

	bn_new(ord);
	bn_new(k0);
	bn_new(k1);
	bn_new(l0);
	bn_new(l1);
	ep_new(u);

	TRY {
		for (i = 0; i < 3; i++) {
			bn_null(v1[i]);
			bn_null(v2[i]);
			bn_new(v1[i]);
			bn_new(v2[i]);
		}

		ep_curve_get_ord(ord);
		ep_curve_get_v1(v1);
		ep_curve_get_v2(v2);

		bn_rec_glv(k0, k1, k, ord, (const bn_t *)v1, (const bn_t *)v2);
		sk0 = bn_sign(k0);
		sk1 = bn_sign(k1);
		bn_abs(k0, k0);
		bn_abs(k1, k1);

		bn_rec_glv(l0, l1, m, ord, (const bn_t *)v1, (const bn_t *)v2);
		sl0 = bn_sign(l0);
		sl1 = bn_sign(l1);
		bn_abs(l0, l0);
		bn_abs(l1, l1);

		g = (t == NULL ? 0 : 1);
		if (!g) {
			for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) {
				ep_new(tab0[i]);
			}
			ep_tab(tab0, p, EP_WIDTH);
			t = (const ep_t *)tab0;
		}

		/* Prepare the precomputation table. */
		for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) {
			ep_new(tab1[i]);
		}
		/* Compute the precomputation table. */
		ep_tab(tab1, q, EP_WIDTH);

		/* Compute the w-TNAF representation of k and l */
		if (g) {
			w = EP_DEPTH;
		} else {
			w = EP_WIDTH;
		}
		len0 = len1 = len2 = len3 = FP_BITS + 1;
		bn_rec_naf(naf0, &len0, k0, w);
		bn_rec_naf(naf1, &len1, k1, w);
		bn_rec_naf(naf2, &len2, l0, EP_WIDTH);
		bn_rec_naf(naf3, &len3, l1, EP_WIDTH);

		len = MAX(MAX(len0, len1), MAX(len2, len3));
		t0 = naf0 + len - 1;
		t1 = naf1 + len - 1;
		t2 = naf2 + len - 1;
		t3 = naf3 + len - 1;
		for (i = len0; i < len; i++) {
			naf0[i] = 0;
		}
		for (i = len1; i < len; i++) {
			naf1[i] = 0;
		}
		for (i = len2; i < len; i++) {
			naf2[i] = 0;
		}
		for (i = len3; i < len; i++) {
			naf3[i] = 0;
		}

		ep_set_infty(r);
		for (i = len - 1; i >= 0; i--, t0--, t1--, t2--, t3--) {
			ep_dbl(r, r);

			n = *t0;
			if (n > 0) {
				if (sk0 == BN_POS) {
					ep_add(r, r, t[n / 2]);
				} else {
					ep_sub(r, r, t[n / 2]);
				}
			}
			if (n < 0) {
				if (sk0 == BN_POS) {
					ep_sub(r, r, t[-n / 2]);
				} else {
					ep_add(r, r, t[-n / 2]);
				}
			}
			n = *t1;
			if (n > 0) {
				ep_copy(u, t[n / 2]);
				fp_mul(u->x, u->x, ep_curve_get_beta());
				if (sk1 == BN_NEG) {
					ep_neg(u, u);
				}
				ep_add(r, r, u);
			}
			if (n < 0) {
				ep_copy(u, t[-n / 2]);
				fp_mul(u->x, u->x, ep_curve_get_beta());
				if (sk1 == BN_NEG) {
					ep_neg(u, u);
				}
				ep_sub(r, r, u);
			}

			n = *t2;
			if (n > 0) {
				if (sl0 == BN_POS) {
					ep_add(r, r, tab1[n / 2]);
				} else {
					ep_sub(r, r, tab1[n / 2]);
				}
			}
			if (n < 0) {
				if (sl0 == BN_POS) {
					ep_sub(r, r, tab1[-n / 2]);
				} else {
					ep_add(r, r, tab1[-n / 2]);
				}
			}
			n = *t3;
			if (n > 0) {
				ep_copy(u, tab1[n / 2]);
				fp_mul(u->x, u->x, ep_curve_get_beta());
				if (sl1 == BN_NEG) {
					ep_neg(u, u);
				}
				ep_add(r, r, u);
			}
			if (n < 0) {
				ep_copy(u, tab1[-n / 2]);
				fp_mul(u->x, u->x, ep_curve_get_beta());
				if (sl1 == BN_NEG) {
					ep_neg(u, u);
				}
				ep_sub(r, r, u);
			}
		}
		/* Convert r to affine coordinates. */
		ep_norm(r, r);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		bn_free(ord);
		bn_free(k0);
		bn_free(k1);
		bn_free(l0);
		bn_free(l1);
		ep_free(u);

		if (!g) {
			for (i = 0; i < 1 << (EP_WIDTH - 2); i++) {
				ep_free(tab0[i]);
			}
		}
		/* Free the precomputation tables. */
		for (i = 0; i < 1 << (EP_WIDTH - 2); i++) {
			ep_free(tab1[i]);
		}
		for (i = 0; i < 3; i++) {
			bn_free(v1[i]);
			bn_free(v2[i]);
		}
	}
}
Пример #9
0
void ep_mul_sim_joint(ep_t r, const ep_t p, const bn_t k, const ep_t q,
		const bn_t m) {
	ep_t t[5];
	int u_i, len, offset;
	int8_t jsf[2 * (FP_BITS + 1)];
	int i;

	ep_null(t[0]);
	ep_null(t[1]);
	ep_null(t[2]);
	ep_null(t[3]);
	ep_null(t[4]);

	TRY {
		for (i = 0; i < 5; i++) {
			ep_new(t[i]);
		}

		ep_set_infty(t[0]);
		ep_copy(t[1], q);
		ep_copy(t[2], p);
		ep_add(t[3], p, q);
		ep_sub(t[4], p, q);
#if defined(EP_MIXED)
		ep_norm_sim(t + 3, (const ep_t *)t + 3, 2);
#endif

		len = 2 * (FP_BITS + 1);
		bn_rec_jsf(jsf, &len, k, m);

		ep_set_infty(r);

		offset = MAX(bn_bits(k), bn_bits(m)) + 1;
		for (i = len - 1; i >= 0; i--) {
			ep_dbl(r, r);
			if (jsf[i] != 0 && jsf[i] == -jsf[i + offset]) {
				u_i = jsf[i] * 2 + jsf[i + offset];
				if (u_i < 0) {
					ep_sub(r, r, t[4]);
				} else {
					ep_add(r, r, t[4]);
				}
			} else {
				u_i = jsf[i] * 2 + jsf[i + offset];
				if (u_i < 0) {
					ep_sub(r, r, t[-u_i]);
				} else {
					ep_add(r, r, t[u_i]);
				}
			}
		}
		ep_norm(r, r);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		for (i = 0; i < 5; i++) {
			ep_free(t[i]);
		}
	}
}
Пример #10
0
void ep_mul_sim_trick(ep_t r, const ep_t p, const bn_t k, const ep_t q,
		const bn_t m) {
	ep_t t0[1 << (EP_WIDTH / 2)], t1[1 << (EP_WIDTH / 2)], t[1 << EP_WIDTH];
	bn_t n;
	int l0, l1, w = EP_WIDTH / 2;
	uint8_t w0[CEIL(FP_BITS + 1, w)], w1[CEIL(FP_BITS + 1, w)];

	bn_null(n);

	for (int i = 0; i < 1 << EP_WIDTH; i++) {
		ep_null(t[i]);
	}

	for (int i = 0; i < 1 << (EP_WIDTH / 2); i++) {
		ep_null(t0[i]);
		ep_null(t1[i]);
	}

	TRY {
		bn_new(n);

		ep_curve_get_ord(n);

		for (int i = 0; i < (1 << w); i++) {
			ep_new(t0[i]);
			ep_new(t1[i]);
		}
		for (int i = 0; i < (1 << EP_WIDTH); i++) {
			ep_new(t[i]);
		}

		ep_set_infty(t0[0]);
		for (int i = 1; i < (1 << w); i++) {
			ep_add(t0[i], t0[i - 1], p);
		}

		ep_set_infty(t1[0]);
		for (int i = 1; i < (1 << w); i++) {
			ep_add(t1[i], t1[i - 1], q);
		}

		for (int i = 0; i < (1 << w); i++) {
			for (int j = 0; j < (1 << w); j++) {
				ep_add(t[(i << w) + j], t0[i], t1[j]);
			}
		}

#if defined(EP_MIXED)
		ep_norm_sim(t + 1, (const ep_t *)t + 1, (1 << (EP_WIDTH)) - 1);
#endif

		l0 = l1 = CEIL(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;
		}

		ep_set_infty(r);
		for (int i = MAX(l0, l1) - 1; i >= 0; i--) {
			for (int j = 0; j < w; j++) {
				ep_dbl(r, r);
			}
			ep_add(r, r, t[(w0[i] << w) + w1[i]]);
		}
		ep_norm(r, r);
	} CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		bn_free(n);
		for (int i = 0; i < (1 << w); i++) {
			ep_free(t0[i]);
			ep_free(t1[i]);
		}
		for (int i = 0; i < (1 << EP_WIDTH); i++) {
			ep_free(t[i]);
		}
	}
}
Пример #11
0
/**
 * 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 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 len, l0, l1, i, n0, n1, w, gen;
	int8_t naf0[FP_BITS + 1], naf1[FP_BITS + 1], *_k, *_m;
	ep_t t0[1 << (EP_WIDTH - 2)];
	ep_t t1[1 << (EP_WIDTH - 2)];

	for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) {
		ep_null(t0[i]);
		ep_null(t1[i]);
	}

	TRY {
		gen = (t == NULL ? 0 : 1);
		if (!gen) {
			for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) {
				ep_new(t0[i]);
			}
			ep_tab(t0, p, EP_WIDTH);
			t = (const ep_t *)t0;
		}

		/* Prepare the precomputation table. */
		for (i = 0; i < (1 << (EP_WIDTH - 2)); i++) {
			ep_new(t1[i]);
		}
		/* Compute the precomputation table. */
		ep_tab(t1, q, EP_WIDTH);

		/* Compute the w-TNAF representation of k. */
		if (gen) {
			w = EP_DEPTH;
		} else {
			w = EP_WIDTH;
		}
		l0 = l1 = FP_BITS + 1;
		bn_rec_naf(naf0, &l0, k, w);
		bn_rec_naf(naf1, &l1, m, EP_WIDTH);

		len = MAX(l0, l1);
		_k = naf0 + len - 1;
		_m = naf1 + len - 1;
		for (i = l0; i < len; i++)
			naf0[i] = 0;
		for (i = l1; i < len; i++)
			naf1[i] = 0;

		ep_set_infty(r);
		for (i = len - 1; i >= 0; i--, _k--, _m--) {
			ep_dbl(r, r);

			n0 = *_k;
			n1 = *_m;
			if (n0 > 0) {
				ep_add(r, r, t[n0 / 2]);
			}
			if (n0 < 0) {
				ep_sub(r, r, t[-n0 / 2]);
			}
			if (n1 > 0) {
				ep_add(r, r, t1[n1 / 2]);
			}
			if (n1 < 0) {
				ep_sub(r, r, t1[-n1 / 2]);
			}
		}
		/* Convert r to affine coordinates. */
		ep_norm(r, r);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		/* Free the precomputation tables. */
		if (!gen) {
			for (i = 0; i < 1 << (EP_WIDTH - 2); i++) {
				ep_free(t0[i]);
			}
		}
		for (i = 0; i < 1 << (EP_WIDTH - 2); i++) {
			ep_free(t1[i]);
		}
	}
}
Пример #12
0
/**
 * Adds two points represented in affine coordinates on an ordinary prime
 * elliptic curve.
 *
 * @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.
 */
static void ep_add_basic_imp(ep_t r, fp_t s, const ep_t p, const ep_t q) {
	fp_t t0, t1, t2;

	fp_null(t0);
	fp_null(t1);
	fp_null(t2);

	TRY {
		fp_new(t0);
		fp_new(t1);
		fp_new(t2);

		/* t0 = x2 - x1. */
		fp_sub(t0, q->x, p->x);
		/* t1 = y2 - y1. */
		fp_sub(t1, q->y, p->y);

		/* If t0 is zero. */
		if (fp_is_zero(t0)) {
			if (fp_is_zero(t1)) {
				/* If t1 is zero, q = p, should have doubled. */
				ep_dbl_basic(r, p);
			} else {
				/* If t1 is not zero and t0 is zero, q = -p and r = infinity. */
				ep_set_infty(r);
			}
		} else {
			/* t2 = 1/(x2 - x1). */
			fp_inv(t2, t0);
			/* t2 = lambda = (y2 - y1)/(x2 - x1). */
			fp_mul(t2, t1, t2);

			/* x3 = lambda^2 - x2 - x1. */
			fp_sqr(t1, t2);
			fp_sub(t0, t1, p->x);
			fp_sub(t0, t0, q->x);

			/* y3 = lambda * (x1 - x3) - y1. */
			fp_sub(t1, p->x, t0);
			fp_mul(t1, t2, t1);
			fp_sub(r->y, t1, p->y);

			fp_copy(r->x, t0);
			fp_copy(r->z, p->z);

			if (s != NULL) {
				fp_copy(s, t2);
			}

			r->norm = 1;
		}
		fp_free(t0);
		fp_free(t1);
		fp_free(t2);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		fp_free(t0);
		fp_free(t1);
		fp_free(t2);
	}
}
Пример #13
0
/**
 * Adds two points represented in projective coordinates on an ordinary prime
 * elliptic curve.
 *
 * @param[out] r			- the result.
 * @param[in] p				- the first point to add.
 * @param[in] q				- the second point to add.
 */
static void ep_add_projc_imp(ep_t r, const ep_t p, const ep_t q) {
#if defined(EP_MIXED) && defined(STRIP)
	/* If code size is a problem, leave only the mixed version. */
	ep_add_projc_mix(r, p, q);
#else /* General addition. */

#if defined(EP_MIXED) || !defined(STRIP)
	/* Test if z2 = 1 only if mixed coordinates are turned on. */
	if (q->norm) {
		ep_add_projc_mix(r, p, q);
		return;
	}
#endif

	fp_t t0, t1, t2, t3, t4, t5, t6;

	fp_null(t0);
	fp_null(t1);
	fp_null(t2);
	fp_null(t3);
	fp_null(t4);
	fp_null(t5);
	fp_null(t6);

	TRY {
		fp_new(t0);
		fp_new(t1);
		fp_new(t2);
		fp_new(t3);
		fp_new(t4);
		fp_new(t5);
		fp_new(t6);

		/* add-2007-bl formulas: 11M + 5S + 9add + 4*2 */
		/* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl */

		/* t0 = z1^2. */
		fp_sqr(t0, p->z);

		/* t1 = z2^2. */
		fp_sqr(t1, q->z);

		/* t2 = U1 = x1 * z2^2. */
		fp_mul(t2, p->x, t1);

		/* t3 = U2 = x2 * z1^2. */
		fp_mul(t3, q->x, t0);

		/* t6 = z1^2 + z2^2. */
		fp_add(t6, t0, t1);

		/* t0 = S2 = y2 * z1^3. */
		fp_mul(t0, t0, p->z);
		fp_mul(t0, t0, q->y);

		/* t1 = S1 = y1 * z2^3. */
		fp_mul(t1, t1, q->z);
		fp_mul(t1, t1, p->y);

		/* t3 = H = U2 - U1. */
		fp_sub(t3, t3, t2);

		/* t0 = R = 2 * (S2 - S1). */
		fp_sub(t0, t0, t1);
		fp_dbl(t0, t0);

		/* If E is zero. */
		if (fp_is_zero(t3)) {
			if (fp_is_zero(t0)) {
				/* If I is zero, p = q, should have doubled. */
				ep_dbl_projc(r, p);
			} else {
				/* If I is not zero, q = -p, r = infinity. */
				ep_set_infty(r);
			}
		} else {
			/* t4 = I = (2*H)^2. */
			fp_dbl(t4, t3);
			fp_sqr(t4, t4);

			/* t5 = J = H * I. */
			fp_mul(t5, t3, t4);

			/* t4 = V = U1 * I. */
			fp_mul(t4, t2, t4);

			/* x3 = R^2 - J - 2 * V. */
			fp_sqr(r->x, t0);
			fp_sub(r->x, r->x, t5);
			fp_dbl(t2, t4);
			fp_sub(r->x, r->x, t2);

			/* y3 = R * (V - x3) - 2 * S1 * J. */
			fp_sub(t4, t4, r->x);
			fp_mul(t4, t4, t0);
			fp_mul(t1, t1, t5);
			fp_dbl(t1, t1);
			fp_sub(r->y, t4, t1);

			/* z3 = ((z1 + z2)^2 - z1^2 - z2^2) * H. */
			fp_add(r->z, p->z, q->z);
			fp_sqr(r->z, r->z);
			fp_sub(r->z, r->z, t6);
			fp_mul(r->z, r->z, t3);
		}
		r->norm = 0;
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		fp_free(t0);
		fp_free(t1);
		fp_free(t2);
		fp_free(t3);
		fp_free(t4);
		fp_free(t5);
		fp_free(t6);
	}
#endif
}
Пример #14
0
/**
 * Adds a point represented in affine coordinates to a point represented in
 * projective coordinates.
 *
 * @param[out] r			- the result.
 * @param[in] p				- the projective point.
 * @param[in] q				- the affine point.
 */
static void ep_add_projc_mix(ep_t r, const ep_t p, const ep_t q) {
	fp_t t0, t1, t2, t3, t4, t5, t6;

	fp_null(t0);
	fp_null(t1);
	fp_null(t2);
	fp_null(t3);
	fp_null(t4);
	fp_null(t5);
	fp_null(t6);

	TRY {
		fp_new(t0);
		fp_new(t1);
		fp_new(t2);
		fp_new(t3);
		fp_new(t4);
		fp_new(t5);
		fp_new(t6);

		/* madd-2007-bl formulas: 7M + 4S + 9add + 1*4 + 3*2. */
		/* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-madd-2007-bl */

		if (!p->norm) {
			/* t0 = z1^2. */
			fp_sqr(t0, p->z);

			/* t3 = U2 = x2 * z1^2. */
			fp_mul(t3, q->x, t0);

			/* t1 = S2 = y2 * z1^3. */
			fp_mul(t1, t0, p->z);
			fp_mul(t1, t1, q->y);

			/* t3 = H = U2 - x1. */
			fp_sub(t3, t3, p->x);

			/* t1 = R = 2 * (S2 - y1). */
			fp_sub(t1, t1, p->y);
			fp_dbl(t1, t1);
		} else {
			/* H = x2 - x1. */
			fp_sub(t3, q->x, p->x);

			/* t1 = R = 2 * (y2 - y1). */
			fp_sub(t1, q->y, p->y);
			fp_dbl(t1, t1);
		}

		/* t2 = HH = H^2. */
		fp_sqr(t2, t3);

		/* If E is zero. */
		if (fp_is_zero(t3)) {
			if (fp_is_zero(t1)) {
				/* If I is zero, p = q, should have doubled. */
				ep_dbl_projc(r, p);
			} else {
				/* If I is not zero, q = -p, r = infinity. */
				ep_set_infty(r);
			}
		} else {
			/* t4 = I = 4*HH. */
			fp_dbl(t4, t2);
			fp_dbl(t4, t4);

			/* t5 = J = H * I. */
			fp_mul(t5, t3, t4);

			/* t4 = V = x1 * I. */
			fp_mul(t4, p->x, t4);

			/* x3 = R^2 - J - 2 * V. */
			fp_sqr(r->x, t1);
			fp_sub(r->x, r->x, t5);
			fp_dbl(t6, t4);
			fp_sub(r->x, r->x, t6);

			/* y3 = R * (V - x3) - 2 * Y1 * J. */
			fp_sub(t4, t4, r->x);
			fp_mul(t4, t4, t1);
			fp_mul(t1, p->y, t5);
			fp_dbl(t1, t1);
			fp_sub(r->y, t4, t1);

			if (!p->norm) {
				/* z3 = (z1 + H)^2 - z1^2 - HH. */
				fp_add(r->z, p->z, t3);
				fp_sqr(r->z, r->z);
				fp_sub(r->z, r->z, t0);
				fp_sub(r->z, r->z, t2);
			} else {
				/* z3 = 2 * H. */
				fp_dbl(r->z, t3);
			}
		}
		r->norm = 0;
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		fp_free(t0);
		fp_free(t1);
		fp_free(t2);
		fp_free(t3);
		fp_free(t4);
		fp_free(t5);
		fp_free(t6);
	}
}