Beispiel #1
0
void fp_invn_low(dig_t *c, const dig_t *a) {
	mp_size_t cn;
	align dig_t s[FP_DIGS], t[2 * FP_DIGS], u[FP_DIGS + 1];

#if FP_RDC == MONTY
	dv_zero(t + FP_DIGS, FP_DIGS);
	dv_copy(t, a, FP_DIGS);
	fp_rdcn_low(u, t);
#else
	fp_copy(u, a);
#endif

	dv_copy(s, fp_prime_get(), FP_DIGS);

	mpn_gcdext(t, c, &cn, u, FP_DIGS, s, FP_DIGS);
	if (cn < 0) {
		dv_zero(c - cn, FP_DIGS + cn);
		mpn_sub_n(c, fp_prime_get(), c, FP_DIGS);
	} else {
		dv_zero(c + cn, FP_DIGS - cn);
	}

#if FP_RDC == MONTY
	dv_zero(t, FP_DIGS);
	dv_copy(t + FP_DIGS, c, FP_DIGS);
	mpn_tdiv_qr(u, c, 0, t, 2 * FP_DIGS, fp_prime_get(), FP_DIGS);
#endif
}
Beispiel #2
0
/**
 * Multiplies two binary field elements using shift-and-add multiplication.
 *
 * @param c					- the result.
 * @param a					- the first binary field element.
 * @param b					- the second binary field element.
 * @param size				- the number of digits to multiply.
 */
static void fb_mul_basic_imp(dig_t *c, const dig_t *a, const dig_t *b, int size) {
	int i;
	dv_t s;

	dv_null(s);

	TRY {
		/* We need a temporary variable so that c can be a or b. */
		dv_new(s);
		dv_zero(s, 2 * FB_DIGS);

		dv_copy(s, b, size);
		dv_zero(c, 2 * size);

		if (a[0] & 1) {
			dv_copy(c, b, size);
		}
		for (i = 1; i <= (FB_DIGIT * size) - 1; i++) {
			fb_lsh1_low(s, s);
			fb_rdc(s, s);
			if (fb_get_bit(a, i)) {
				fb_add(c, c, s);
			}
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(s);
	}
}
Beispiel #3
0
void fp_prime_back(bn_t c, const fp_t a) {
	dv_t t;
	int i;

	dv_null(t);

	TRY {
		dv_new(t);

		bn_grow(c, FP_DIGS);
		for (i = 0; i < FP_DIGS; i++) {
			c->dp[i] = a[i];
		}
#if FP_RDC == MONTY
		dv_zero(t, 2 * FP_DIGS + 1);
		dv_copy(t, a, FP_DIGS);
		fp_rdc(c->dp, t);
#endif
		c->used = FP_DIGS;
		c->sign = BN_POS;
		bn_trim(c);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Beispiel #4
0
/**
 * Multiplies two binary field elements using right-to-left comb multiplication.
 *
 * @param c					- the result.
 * @param a					- the first binary field element.
 * @param b					- the second binary field element.
 * @param size				- the number of digits to multiply.
 */
static void fb_mul_rcomb_imp(dig_t *c, const dig_t *a, const dig_t *b, int size) {
	dv_t _b;

	dv_null(_b);

	TRY {
		dv_new(_b);
		dv_zero(c, 2 * size);

		for (int i = 0; i < size; i++)
			_b[i] = b[i];
		_b[size] = 0;

		for (int i = 0; i < FB_DIGIT; i++) {
			for (int j = 0; j < size; j++) {
				if (a[j] & ((dig_t)1 << i)) {
					fb_addd_low(c + j, c + j, _b, size + 1);
				}
			}
			if (i != FB_DIGIT - 1) {
				bn_lsh1_low(_b, _b, size + 1);
			}
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(_b);
	}
}
Beispiel #5
0
void fb_mul_lcomb(fb_t c, const fb_t a, const fb_t b) {
	dv_t t;
	dig_t carry;

	dv_null(t);

	TRY {
		dv_new(t);
		dv_zero(t, 2 * FB_DIGS);

		for (int i = FB_DIGIT - 1; i >= 0; i--) {
			for (int j = 0; j < FB_DIGS; j++) {
				if (a[j] & ((dig_t)1 << i)) {
					/* This cannot use fb_addn_low() because there is no
					 * guarantee that operands will be aligned. */
					fb_addd_low(t + j, t + j, b, FB_DIGS);
				}
			}
			if (i != 0) {
				carry = fb_lsh1_low(t, t);
				fb_lsh1_low(t + FB_DIGS, t + FB_DIGS);
				t[FB_DIGS] |= carry;
			}
		}

		fb_rdc(c, t);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Beispiel #6
0
void fp_mul_karat(fp_t c, const fp_t a, const fp_t b) {
	dv_t t;

	dv_null(t);

	TRY {
		/* We need a temporary variable so that c can be a or b. */
		dv_new(t);

		dv_zero(t, 2 * FP_DIGS);

		if (FP_DIGS > 1) {
			fp_mul_karat_imp(t, a, b, FP_DIGS, FP_KARAT);
		} else {
			fp_muln_low(t, a, b);
		}

		fp_rdc(c, t);
	} CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Beispiel #7
0
void fp_prime_conv_dig(fp_t c, dig_t a) {
	dv_t t;
	ctx_t *ctx = core_get();

	bn_null(t);

	TRY {
		dv_new(t);

#if FP_RDC == MONTY
		if (a != 1) {
			dv_zero(t, 2 * FP_DIGS + 1);
			t[FP_DIGS] = fp_mul1_low(t, ctx->conv.dp, a);
			fp_rdc(c, t);
		} else {
			dv_copy(c, ctx->one.dp, FP_DIGS);
		}
#else
		(void)ctx;
		fp_zero(c);
		c[0] = a;
#endif
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Beispiel #8
0
void fp_mul_basic(fp_t c, const fp_t a, const fp_t b) {
	int i;
	dv_t t;
	dig_t carry;

	dv_null(t);

	TRY {
		/* We need a temporary variable so that c can be a or b. */
		dv_new(t);
		dv_zero(t, 2 * FP_DIGS);
		for (i = 0; i < FP_DIGS; i++) {
			carry = fp_mula_low(t + i, b, *(a + i));
			*(t + i + FP_DIGS) = carry;
		}

		fp_rdc(c, t);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Beispiel #9
0
void fp2_nord_low(dv2_t c, dv2_t a) {
	dv2_t t;
	bn_t b;

	dv2_null(t);
	bn_null(b);

	TRY {
		dv2_new(t);
		bn_new(b);

#ifdef FP_QNRES
		/* If p = 3 mod 8, (1 + i) is a QNR/CNR. */
		/* (a_0 + a_1 * i) * (1 + i) = (a_0 - a_1) + (a_0 + a_1) * u. */
		dv_copy(t[0], a[1], 2 * FP_DIGS);
		fp_addc_low(c[1], a[0], a[1]);
		fp_subc_low(c[0], a[0], t[0]);
#else
		switch (fp_prime_get_mod8()) {
			case 3:
				/* If p = 3 mod 8, (1 + u) is a QNR, u^2 = -1. */
				/* (a_0 + a_1 * u) * (1 + u) = (a_0 - a_1) + (a_0 + a_1) * u. */
				dv_copy(t[0], a[1], 2 * FP_DIGS);
				fp_addc_low(c[1], a[0], a[1]);
				fp_subc_low(c[0], a[0], t[0]);
				break;
			case 1:
			case 5:
				/* If p = 1,5 mod 8, (u) is a QNR. */
				dv_copy(t[0], a[0], 2 * FP_DIGS);
				dv_zero(t[1], FP_DIGS);
				dv_copy(t[1] + FP_DIGS, fp_prime_get(), FP_DIGS);
				fp_subc_low(c[0], t[1], a[1]);
				for (int i = -1; i > fp_prime_get_qnr(); i--) {
					fp_subc_low(c[0], c[0], a[1]);
				}
				dv_copy(c[1], t[0], 2 * FP_DIGS);
				break;
			case 7:
				/* If p = 7 mod 8, (2 + u) is a QNR/CNR.   */
				fp2_addc_low(t, a, a);
				fp_subc_low(c[0], t[0], a[1]);
				fp_addc_low(c[1], t[1], a[0]);
				break;
			default:
				THROW(ERR_NO_VALID);
				break;
		}
#endif
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv2_free(t);
		bn_free(b);
	}
}
Beispiel #10
0
/**
 * Multiplies two binary field elements using left-to-right comb multiplication.
 *
 * @param c					- the result.
 * @param a					- the first binary field element.
 * @param b					- the second binary field element.
 * @param size				- the number of digits to multiply.
 */
static void fb_mul_lcomb_imp(dig_t *c, const dig_t *a, const dig_t *b, int size) {
	dv_zero(c, 2 * size);

	for (int i = FB_DIGIT - 1; i >= 0; i--) {
		for (int j = 0; j < size; j++) {
			if (a[j] & ((dig_t)1 << i)) {
				fb_addd_low(c + j, c + j, b, size);
			}
		}
		if (i != 0) {
			bn_lsh1_low(c, c, 2 * size);
		}
	}
}
Beispiel #11
0
void fb_mul_rcomb(fb_t c, const fb_t a, const fb_t b) {
	dv_t t, _b;
	dig_t carry;

	dv_null(t);
	dv_null(_b);

	TRY {
		dv_new(t);
		dv_new(_b);
		dv_zero(t, 2 * FB_DIGS);
		dv_zero(_b, FB_DIGS + 1);

		fb_copy(_b, b);

		for (int i = 0; i < FB_DIGIT; i++) {
			for (int j = 0; j < FB_DIGS; j++) {
				if (a[j] & ((dig_t)1 << i)) {
					fb_addd_low(t + j, t + j, _b, FB_DIGS + 1);
				}
			}
			if (i != FB_DIGIT - 1) {
				carry = fb_lsh1_low(_b, _b);
				_b[FB_DIGS] = (_b[FB_DIGS] << 1) | carry;
			}
		}

		fb_rdc(c, t);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
		dv_free(_b);
	}
}
Beispiel #12
0
void fb_mul_basic(fb_t c, const fb_t a, const fb_t b) {
	int i;
	dv_t s;
	fb_t t;

	dv_null(s);
	fb_null(t);

	TRY {
		/* We need a temporary variable so that c can be a or b. */
		fb_new(t);
		dv_new(s);
		fb_zero(t);
		dv_zero(s + FB_DIGS, FB_DIGS);
		fb_copy(s, b);

		if (a[0] & 1) {
			fb_copy(t, b);
		}
		for (i = 1; i < FB_BITS; i++) {
			/* We are already shifting a temporary value, so this is more efficient
			 * than calling fb_lsh(). */
			s[FB_DIGS] = fb_lsh1_low(s, s);
			fb_rdc(s, s);
			if (fb_get_bit(a, i)) {
				fb_add(t, t, s);
			}
		}

		if (fb_bits(t) > FB_BITS) {
			fb_poly_add(c, t);
		} else {
			fb_copy(c, t);
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		fb_free(t);
		fb_free(s);
	}
}
Beispiel #13
0
void fb_mul_karat(fb_t c, const fb_t a, const fb_t b) {
	dv_t t;

	dv_null(t);

	TRY {
		/* We need a temporary variable so that c can be a or b. */
		dv_new(t);
		dv_zero(t, 2 * FB_DIGS);

		fb_mul_karat_imp(t, a, b, FB_DIGS, FB_KARAT);

		fb_rdc(c, t);
	} CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Beispiel #14
0
void fp_sqr_basic(fp_t c, const fp_t a) {
	int i;
	dv_t t;

	dv_null(t);

	TRY {
		dv_new(t);
		dv_zero(t, 2 * RLC_FP_DIGS);

		for (i = 0; i < RLC_FP_DIGS; i++) {
			bn_sqra_low(t + (2 * i), a + i, RLC_FP_DIGS - i);
		}

		fp_rdc(c, t);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		fp_free(t);
	}
}
Beispiel #15
0
void fp_sqr_karat(fp_t c, const fp_t a) {
	dv_t t;

	dv_null(t);

	TRY {
		dv_new(t);
		dv_zero(t, 2 * RLC_FP_DIGS);

		if (RLC_FP_DIGS > 1) {
			fp_sqr_karat_imp(t, a, RLC_FP_DIGS, FP_KARAT);
		} else {
			fp_sqrn_low(t, a);
		}


		fp_rdc(c, t);
	} CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Beispiel #16
0
/**
 * Assigns the prime field modulus.
 *
 * @param[in] p			- the new prime field modulus.
 */
static void fp_prime_set(const bn_t p) {
	dv_t s, q;
	bn_t t;
	ctx_t *ctx = core_get();

	if (p->used != FP_DIGS) {
		THROW(ERR_NO_VALID);
	}

	dv_null(s);
	bn_null(t);
	dv_null(q);

	TRY {
		dv_new(s);
		bn_new(t);
		dv_new(q);

		bn_copy(&(ctx->prime), p);

		bn_mod_dig(&(ctx->mod8), &(ctx->prime), 8);

		switch (ctx->mod8) {
			case 3:
			case 7:
				ctx->qnr = -1;
				/* The current code for extensions of Fp^3 relies on qnr being
				 * also a cubic non-residue. */
				ctx->cnr = 0;
				break;
			case 1:
			case 5:
				ctx->qnr = ctx->cnr = -2;
				break;
			default:
				ctx->qnr = ctx->cnr = 0;
				THROW(ERR_NO_VALID);
				break;
		}
#ifdef FP_QNRES
		if (ctx->mod8 != 3) {
			THROW(ERR_NO_VALID);
		}
#endif

#if FP_RDC == MONTY || !defined(STRIP)
		bn_mod_pre_monty(t, &(ctx->prime));
		ctx->u = t->dp[0];
		dv_zero(s, 2 * FP_DIGS);
		s[2 * FP_DIGS] = 1;
		dv_zero(q, 2 * FP_DIGS + 1);
		dv_copy(q, ctx->prime.dp, FP_DIGS);
		bn_divn_low(t->dp, ctx->conv.dp, s, 2 * FP_DIGS + 1, q, FP_DIGS);
		ctx->conv.used = FP_DIGS;
		bn_trim(&(ctx->conv));
		bn_set_dig(&(ctx->one), 1);
		bn_lsh(&(ctx->one), &(ctx->one), ctx->prime.used * BN_DIGIT);
		bn_mod(&(ctx->one), &(ctx->one), &(ctx->prime));
#endif
		fp_prime_calc();
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		bn_free(t);
		dv_free(s);
		dv_free(q);
	}
}
void fb_invn_low(dig_t *c, const dig_t *a) {
	int j, d, lu, lv, lt, l1, l2, bu, bv;
	align dig_t _u[2 * FB_DIGS], _v[2 * FB_DIGS];
	align dig_t _g1[2 * FB_DIGS], _g2[2 * FB_DIGS];
	dig_t *t = NULL, *u = NULL, *v = NULL, *g1 = NULL, *g2 = NULL, carry;

	dv_zero(_g1, FB_DIGS + 1);
	dv_zero(_g2, FB_DIGS + 1);

	u = _u;
	v = _v;
	g1 = _g1;
	g2 = _g2;

	/* u = a, v = f, g1 = 1, g2 = 0. */
	dv_copy(u, a, FB_DIGS);
	dv_copy(v, fb_poly_get(), FB_DIGS);
	g1[0] = 1;

	lu = lv = FB_DIGS;
	l1 = l2 = 1;

	bu = fb_bits(u);
	bv = FB_BITS + 1;
	j = bu - bv;

	/* While (u != 1). */
	while (1) {
		/* If j < 0 then swap(u, v), swap(g1, g2), j = -j. */
		if (j < 0) {
			t = u;
			u = v;
			v = t;

			lt = lu;
			lu = lv;
			lv = lt;

			t = g1;
			g1 = g2;
			g2 = t;

			lt = l1;
			l1 = l2;
			l2 = lt;

			j = -j;
		}

		SPLIT(j, d, j, FB_DIG_LOG);

		/* u = u + v * z^j. */
		if (j > 0) {
			carry = fb_lsha_low(u + d, v, j, lv);
			u[d + lv] ^= carry;
		} else {
			fb_addd_low(u + d, u + d, v, lv);
		}

		/* g1 = g1 + g2 * z^j. */
		if (j > 0) {
			carry = fb_lsha_low(g1 + d, g2, j, l2);
			l1 = (l2 + d >= l1 ? l2 + d : l1);
			if (carry) {
				g1[d + l2] ^= carry;
				l1 = (l2 + d >= l1 ? l1 + 1 : l1);
			}
		} else {
			fb_addd_low(g1 + d, g1 + d, g2, l2);
			l1 = (l2 + d > l1 ? l2 + d : l1);
		}

		while (u[lu - 1] == 0)
			lu--;
		while (v[lv - 1] == 0)
			lv--;

		if (lu == 1 && u[0] == 1)
			break;

		/* j = deg(u) - deg(v). */
		lt = util_bits_dig(u[lu - 1]) - util_bits_dig(v[lv - 1]);
		j = ((lu - lv) << FB_DIG_LOG) + lt;
	}
	/* Return g1. */
	fb_copy(c, g1);
}
Beispiel #18
0
void bn_zero(bn_t a) {
	a->sign = BN_POS;
	a->used = 1;
	dv_zero(a->dp, a->alloc);
}
Beispiel #19
0
void fp2_nord_low(dv2_t c, dv2_t a) {
	dv2_t t;
	bn_t b;

	dv2_null(t);
	bn_null(b);

	TRY {
		dv2_new(t);
		bn_new(b);

#if FP_PRIME == 158
		fp_addc_low(t[0], a[0], a[0]);
		fp_addc_low(t[0], t[0], t[0]);
		fp_subc_low(t[0], t[0], a[1]);
		fp_addc_low(t[1], a[1], a[1]);
		fp_addc_low(t[1], t[1], t[1]);
		fp_addc_low(c[1], a[0], t[1]);
		dv_copy(c[0], t[0], 2 * FP_DIGS);
#elif defined(FP_QNRES)
		/* If p = 3 mod 8, (1 + i) is a QNR/CNR. */
		/* (a_0 + a_1 * i) * (1 + i) = (a_0 - a_1) + (a_0 + a_1) * u. */
		dv_copy(t[0], a[1], 2 * FP_DIGS);
		fp_addc_low(c[1], a[0], a[1]);
		fp_subc_low(c[0], a[0], t[0]);
#else
		switch (fp_prime_get_mod8()) {
			case 3:
				/* If p = 3 mod 8, (1 + u) is a QNR, u^2 = -1. */
				/* (a_0 + a_1 * u) * (1 + u) = (a_0 - a_1) + (a_0 + a_1) * u. */
				dv_copy(t[0], a[1], 2 * FP_DIGS);
				fp_addc_low(c[1], a[0], a[1]);
				fp_subc_low(c[0], a[0], t[0]);
				break;
			case 5:
				/* If p = 5 mod 8, (u) is a QNR. */
				dv_copy(t[0], a[0], 2 * FP_DIGS);
				dv_zero(t[1], FP_DIGS);
				dv_copy(t[1] + FP_DIGS, fp_prime_get(), FP_DIGS);
				fp_subc_low(c[0], t[1], a[1]);
				for (int i = -1; i > fp_prime_get_qnr(); i--) {
					fp_subc_low(c[0], c[0], a[1]);
				}
				dv_copy(c[1], t[0], 2 * FP_DIGS);
				break;
			case 7:
				/* If p = 7 mod 8, (2^lg_4(b-1) + u) is a QNR/CNR.   */
				/* (a_0 + a_1 * u)(2^lg_4(b-1) + u) =
				 * (2^lg_4(b-1)a_0 - a_1) + (a_0 + 2^lg_4(b-1)a_1 * u. */
				fp2_addc_low(t, a, a);
				fp_prime_back(b, ep_curve_get_b());
				for (int i = 1; i < bn_bits(b) / 2; i++) {
					fp2_addc_low(t, t, t);
				}
				fp_subc_low(c[0], t[0], a[1]);
				fp_addc_low(c[1], t[1], a[0]);
				break;
			default:
				THROW(ERR_NO_VALID);
				break;
		}
#endif
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv2_free(t);
		bn_free(b);
	}
}
Beispiel #20
0
void fp_rdcs_low(dig_t *c, dig_t *a, dig_t *m) {
	align dig_t q[2 * FP_DIGS], _q[2 * FP_DIGS];
	align dig_t _r[2 * FP_DIGS], r[2 * FP_DIGS], t[2 * FP_DIGS];
	int *sform, len;
	int first, i, j, b0, d0, b1, d1;
	dig_t carry;

	sform = fp_prime_get_sps(&len);

	SPLIT(b0, d0, FP_BITS, FP_DIG_LOG);
	first = (d0) + (b0 == 0 ? 0 : 1);

	/* q = floor(a/b^k) */
	dv_zero(q, 2 * FP_DIGS);
	bn_rshd_low(q, a, 2 * FP_DIGS, d0);
	if (b0 > 0) {
		bn_rshb_low(q, q, 2 * FP_DIGS, b0);
	}

	/* r = a - qb^k. */
	dv_copy(r, a, first);
	if (b0 > 0) {
		r[first - 1] &= MASK(b0);
	}

	carry = 0;
	while (!fp_is_zero(q)) {
		dv_zero(_q, 2 * FP_DIGS);
		for (i = len - 1; i > 0; i--) {
			j = (sform[i] < 0 ? -sform[i] : sform[i]);
			SPLIT(b1, d1, j, FP_DIG_LOG);
			dv_zero(t, 2 * FP_DIGS);
			bn_lshd_low(t, q, FP_DIGS, d1);
			if (b1 > 0) {
				bn_lshb_low(t, t, 2 * FP_DIGS, b1);
			}
			if (sform[i] > 0) {
				bn_subn_low(_q, _q, t, 2 * FP_DIGS);
			} else {
				bn_addn_low(_q, _q, t, 2 * FP_DIGS);
			}
		}
		if (sform[0] > 0) {
			bn_subn_low(_q, _q, q, 2 * FP_DIGS);
		} else {
			bn_addn_low(_q, _q, q, 2 * FP_DIGS);
		}
		bn_rshd_low(q, _q, 2 * FP_DIGS, d0);
		if (b0 > 0) {
			bn_rshb_low(q, q, 2 * FP_DIGS, b0);
		}

		dv_copy(_r, _q, first);
		if (b0 > 0) {
			_r[first - 1] &= MASK(b0);
		}
		fp_add(r, r, _r);
	}
	while (fp_cmpn_low(r, m) != CMP_LT) {
		fp_subn_low(r, r, m);
	}
	fp_copy(c, r);
}
Beispiel #21
0
/**
 * Computes the square of a multiple precision integer using recursive Karatsuba
 * squaring.
 *
 * @param[out] c			- the result.
 * @param[in] a				- the prime field element to square.
 * @param[in] size			- the number of digits to square.
 * @param[in] level			- the number of Karatsuba steps to apply.
 */
static void fp_sqr_karat_imp(dv_t c, const fp_t a, int size, int level) {
	int i, h, h1;
	dv_t t0, t1, a0a0, a1a1;
	dig_t carry;

	/* Compute half the digits of a or b. */
	h = size >> 1;
	h1 = size - h;

	dv_null(t0);
	dv_null(t1);
	dv_null(a0a0);
	dv_null(a1a1);

	TRY {
		/* Allocate the temp variables. */
		dv_new(t0);
		dv_new(t1);
		dv_new(a0a0);
		dv_new(a1a1);
		dv_zero(t0, 2 * h1);
		dv_zero(t1, 2 * (h1 + 1));
		dv_zero(a0a0, 2 * h);
		dv_zero(a1a1, 2 * h1);

		if (level <= 1) {
			/* a0a0 = a0 * a0 and a1a1 = a1 * a1 */
#if FP_SQR == BASIC
			for (i = 0; i < h; i++) {
				bn_sqra_low(a0a0 + (2 * i), a + i, h - i);
			}
			for (i = 0; i < h1; i++) {
				bn_sqra_low(a1a1 + (2 * i), a + h + i, h1 - i);
			}
#elif FP_SQR == COMBA || FP_SQR == INTEG
			bn_sqrn_low(a0a0, a, h);
			bn_sqrn_low(a1a1, a + h, h1);
#elif FP_SQR == MULTP
			bn_muln_low(a0a0, a, a, h);
			bn_muln_low(a1a1, a + h, a + h, h1);
#endif
		} else {
			fp_sqr_karat_imp(a0a0, a, h, level - 1);
			fp_sqr_karat_imp(a1a1, a + h, h1, level - 1);
		}

		/* t2 = a1 * a1 << 2*h digits + a0 * a0. */
		for (i = 0; i < 2 * h; i++) {
			c[i] = a0a0[i];
		}
		for (i = 0; i < 2 * h1; i++) {
			c[2 * h + i] = a1a1[i];
		}

		/* t = (a1 + a0) */
		carry = bn_addn_low(t0, a, a + h, h);
		carry = bn_add1_low(t0 + h, t0 + h, carry, 2);
		if (h1 > h) {
			carry = bn_add1_low(t0 + h, t0 + h, *(a + 2 * h), 2);
		}

		if (level <= 1) {
			/* a1a1 = (a1 + a0)*(a1 + a0) */
#if FP_SQR == BASIC
			for (i = 0; i < h1 + 1; i++) {
				bn_sqra_low(t1 + (2 * i), t0 + i, h1 + 1 - i);
			}
#elif FP_SQR == COMBA || FP_SQR == INTEG
			bn_sqrn_low(t1, t0, h1 + 1);
#elif FP_SQR == MULTP
			bn_muln_low(t1, t0, t0, h1 + 1);
#endif
		} else {
			fp_sqr_karat_imp(t1, t0, h1 + 1, level - 1);
		}

		/* t = t - (a0*a0 << h digits) */
		carry = bn_subn_low(t1, t1, a0a0, 2 * h);
		bn_sub1_low(t1 + 2 * h, t1 + 2 * h, carry, 2 * (h1 + 1) - 2 * h);

		/* t = t - (a1*a1 << h digits) */
		carry = bn_subn_low(t1, t1, a1a1, 2 * h1);
		bn_sub1_low(t1 + 2 * h, t1 + 2 * h, carry, 2 * (h1 + 1) - 2 * h);

		/* c = c + [(a1 + a0)*(a1 + a0) << digits] */
		c += h;
		carry = bn_addn_low(c, c, t1, 2 * (h1 + 1));
		c += 2 * (h1 + 1);
		carry = bn_add1_low(c, c, carry, 2 * size - h - 2 * (h1 + 1));
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t0);
		dv_free(t1);
		dv_free(a0a0);
		dv_free(a1a1);
	}
}
Beispiel #22
0
/**
 * Multiplies two prime field elements using recursive Karatsuba
 * multiplication.
 *
 * @param[out] c			- the result.
 * @param[in] a				- the first prime field element.
 * @param[in] b				- the second prime field element.
 * @param[in] size			- the number of digits to multiply.
 * @param[in] level			- the number of Karatsuba steps to apply.
 */
static void fp_mul_karat_imp(dv_t c, const fp_t a, const fp_t b, int size,
		int level) {
	int i, h, h1;
	dv_t a1, b1, a0b0, a1b1, t;
	dig_t carry;

	/* Compute half the digits of a or b. */
	h = size >> 1;
	h1 = size - h;

	dv_null(a1);
	dv_null(b1);
	dv_null(a0b0);
	dv_null(a1b1);

	TRY {
		/* Allocate the temp variables. */
		dv_new(a1);
		dv_new(b1);
		dv_new(a0b0);
		dv_new(a1b1);
		dv_new(t);
		dv_zero(a1, h1 + 1);
		dv_zero(b1, h1 + 1);
		dv_zero(a0b0, 2 * h);
		dv_zero(a1b1, 2 * h1);
		dv_zero(t, 2 * h1 + 1);

		/* a0b0 = a0 * b0 and a1b1 = a1 * b1 */
		if (level <= 1) {
#if FP_MUL == BASIC
			for (i = 0; i < h; i++) {
				carry = bn_mula_low(a0b0 + i, a, *(b + i), h);
				*(a0b0 + i + h) = carry;
			}
			for (i = 0; i < h1; i++) {
				carry = bn_mula_low(a1b1 + i, a + h, *(b + h + i), h1);
				*(a1b1 + i + h1) = carry;
			}
#elif FP_MUL == COMBA || FP_MUL == INTEG
			bn_muln_low(a0b0, a, b, h);
			bn_muln_low(a1b1, a + h, b + h, h1);
#endif
		} else {
			fp_mul_karat_imp(a0b0, a, b, h, level - 1);
			fp_mul_karat_imp(a1b1, a + h, b + h, h1, level - 1);
		}

		for (i = 0; i < 2 * h; i++) {
			c[i] = a0b0[i];
		}
		for (i = 0; i < 2 * h1 + 1; i++) {
			c[2 * h + i] = a1b1[i];
		}

		/* a1 = (a1 + a0) */
		carry = bn_addn_low(a1, a, a + h, h);
		bn_add1_low(a1 + h, a1 + h, carry, 2);
		if (h1 > h) {
			bn_add1_low(a1 + h, a1 + h, *(a + 2 * h), 2);
		}

		/* b1 = (b1 + b0) */
		carry = bn_addn_low(b1, b, b + h, h);
		bn_add1_low(b1 + h, b1 + h, carry, 2);
		if (h1 > h) {
			bn_add1_low(b1 + h, b1 + h, *(b + 2 * h), 2);
		}

		if (level <= 1) {
			/* t = (a1 + a0)*(b1 + b0) */
#if FP_MUL == BASIC
			for (i = 0; i < h1 + 1; i++) {
				carry = bn_mula_low(t + i, a1, *(b1 + i), h1 + 1);
				*(t + i + h1 + 1) = carry;
			}
#elif FP_MUL == COMBA || FP_MUL == INTEG
			bn_muln_low(t, a1, b1, h1 + 1);
#endif
		} else {
			fp_mul_karat_imp(t, a1, b1, h1 + 1, level - 1);
		}

		/* t = t - (a0*b0 << h digits) */
		carry = bn_subn_low(t, t, a0b0, 2 * h);
		bn_sub1_low(t + 2 * h, t + 2 * h, carry, 2 * (h1 + 1) - 2 * h);

		/* t = t - (a1*b1 << h digits) */
		carry = bn_subn_low(t, t, a1b1, 2 * h1);
		bn_sub1_low(t + 2 * h1, t + 2 * h1, carry, 2 * (h1 + 1) - 2 * h1);

		/* c = c + [(a1 + a0)*(b1 + b0) << digits] */
		c += h;
		carry = bn_addn_low(c, c, t, 2 * (h1 + 1));
		c += 2 * (h1 + 1);
		bn_add1_low(c, c, carry, 2 * size - h - 2 * (h1 + 1));
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(a1);
		dv_free(b1);
		dv_free(a0b0);
		dv_free(a1b1);
		dv_free(t);
	}
}
Beispiel #23
0
void fp_zero(fp_t a) {
	dv_zero(a, RLC_FP_DIGS);
}