Example #1
0
void
split_number(const struct number *n, BIGNUM *i, BIGNUM *f)
{
	u_long rem;

	bn_checkp(BN_copy(i, n->number));

	if (n->scale == 0 && f != NULL)
		bn_check(BN_zero(f));
	else if (n->scale < sizeof(factors)/sizeof(factors[0])) {
		rem = BN_div_word(i, factors[n->scale]);
		if (f != NULL)
			bn_check(BN_set_word(f, rem));
	} else {
		BIGNUM	*a, *p;
		BN_CTX	*ctx;

		a = BN_new();
		bn_checkp(a);
		p = BN_new();
		bn_checkp(p);
		ctx = BN_CTX_new();
		bn_checkp(ctx);

		bn_check(BN_set_word(a, 10));
		bn_check(BN_set_word(p, n->scale));
		bn_check(BN_exp(a, a, p, ctx));
		bn_check(BN_div(i, f, n->number, a, ctx));
		BN_CTX_free(ctx);
		BN_free(a);
		BN_free(p);
	}
}
Example #2
0
static void
bmod(void)
{
	struct number *a, *b, *r;
	BN_CTX *ctx;
	u_int scale;

	a = pop_number();
	if (a == NULL)
		return;
	b = pop_number();
	if (b == NULL) {
		push_number(a);
		return;
	}

	r = new_number();
	scale = max(a->scale, b->scale);
	r->scale = scale;

	if (BN_is_zero(a->number))
		warnx("remainder by zero");
	else {
		normalize(a, scale);
		normalize(b, scale);

		ctx = BN_CTX_new();
		bn_checkp(ctx);
		bn_check(BN_mod(r->number, b->number, a->number, ctx));
		BN_CTX_free(ctx);
	}
	push_number(r);
	free_number(a);
	free_number(b);
}
Example #3
0
static void
bsqrt(void)
{
	struct number	*n;
	struct number	*r;
	BIGNUM		*x, *y;
	u_int		scale, onecount;
	BN_CTX		*ctx;

	onecount = 0;
	n = pop_number();
	if (n == NULL) {
		return;
	}
	if (BN_is_zero(n->number)) {
		r = new_number();
		push_number(r);
	} else if (BN_is_negative(n->number))
		warnx("square root of negative number");
	else {
		scale = max(bmachine.scale, n->scale);
		normalize(n, 2*scale);
		x = BN_dup(n->number);
		bn_checkp(x);
		bn_check(BN_rshift(x, x, BN_num_bits(x)/2));
		y = BN_new();
		bn_checkp(y);
		ctx = BN_CTX_new();
		bn_checkp(ctx);
		for (;;) {
			bn_checkp(BN_copy(y, x));
			bn_check(BN_div(x, NULL, n->number, x, ctx));
			bn_check(BN_add(x, x, y));
			bn_check(BN_rshift1(x, x));
			if (bsqrt_stop(x, y, &onecount))
				break;
		}
		r = bmalloc(sizeof(*r));
		r->scale = scale;
		r->number = y;
		BN_free(x);
		BN_CTX_free(ctx);
		push_number(r);
	}

	free_number(n);
}
Example #4
0
static void
bdivmod(void)
{
	struct number *a, *b, *frac, *quotient, *rdiv, *remainder;
	BN_CTX *ctx;
	u_int scale;

	a = pop_number();
	if (a == NULL)
		return;
	b = pop_number();
	if (b == NULL) {
		push_number(a);
		return;
	}

	rdiv = new_number();
	quotient = new_number();
	remainder = new_number();
	scale = max(a->scale, b->scale);
	rdiv->scale = 0;
	remainder->scale = scale;
	quotient->scale = bmachine.scale;
	scale = max(a->scale, b->scale);

	if (BN_is_zero(a->number))
		warnx("divide by zero");
	else {
		normalize(a, scale);
		normalize(b, scale);

		ctx = BN_CTX_new();
		bn_checkp(ctx);
		/*
		 * Unlike other languages' divmod operations, dc is specified
		 * to return the remainder and the full quotient, rather than
		 * the remainder and the floored quotient.  bn(3) has no
		 * function to calculate both.  So we'll use BN_div to get the
		 * remainder and floored quotient, then calculate the full
		 * quotient from those.
		 *
		 * quotient = rdiv + remainder / divisor
		 */
		bn_check(BN_div(rdiv->number, remainder->number,
		    b->number, a->number, ctx));
		frac = div_number(remainder, a, bmachine.scale);
		normalize(rdiv, bmachine.scale);
		normalize(remainder, scale);
		bn_check(BN_add(quotient->number, rdiv->number, frac->number));
		free_number(frac);
		BN_CTX_free(ctx);
	}
	push_number(quotient);
	push_number(remainder);
	free_number(rdiv);
	free_number(a);
	free_number(b);
}
Example #5
0
struct number *
dup_number(const struct number *a)
{
	struct number *n;

	n = bmalloc(sizeof(*n));
	n->scale = a->scale;
	n->number = BN_dup(a->number);
	bn_checkp(n->number);
	return n;
}
Example #6
0
/* Multiply n by 10^s */
void
scale_number(BIGNUM *n, int s)
{
	unsigned int abs_scale;

	if (s == 0)
		return;

	abs_scale = s > 0 ? s : -s;

	if (abs_scale < sizeof(factors)/sizeof(factors[0])) {
		if (s > 0)
			bn_check(BN_mul_word(n, factors[abs_scale]));
		else
			BN_div_word(n, factors[abs_scale]);
	} else {
		BIGNUM *a, *p;
		BN_CTX *ctx;

		a = BN_new();
		bn_checkp(a);
		p = BN_new();
		bn_checkp(p);
		ctx = BN_CTX_new();
		bn_checkp(ctx);

		bn_check(BN_set_word(a, 10));
		bn_check(BN_set_word(p, abs_scale));
		bn_check(BN_exp(a, a, p, ctx));
		if (s > 0)
			bn_check(BN_mul(n, n, a, ctx));
		else
			bn_check(BN_div(n, NULL, n, a, ctx));
		BN_CTX_free(ctx);
		BN_free(a);
		BN_free(p);
	}
}
Example #7
0
static bool
bsqrt_stop(const BIGNUM *x, const BIGNUM *y, u_int *onecount)
{
	BIGNUM *r;
	bool ret;

	r = BN_new();
	bn_checkp(r);
	bn_check(BN_sub(r, x, y));
	if (BN_is_one(r))
		(*onecount)++;
	ret = BN_is_zero(r);
	BN_free(r);
	return (ret || *onecount > 1);
}
Example #8
0
void
bmul_number(struct number *r, struct number *a, struct number *b, u_int scale)
{
	BN_CTX *ctx;

	/* Create copies of the scales, since r might be equal to a or b */
	u_int ascale = a->scale;
	u_int bscale = b->scale;
	u_int rscale = ascale + bscale;

	ctx = BN_CTX_new();
	bn_checkp(ctx);
	bn_check(BN_mul(r->number, a->number, b->number, ctx));
	BN_CTX_free(ctx);

	r->scale = rscale;
	if (rscale > bmachine.scale && rscale > ascale && rscale > bscale)
		normalize(r, max(scale, max(ascale, bscale)));
}
Example #9
0
static void
bdivmod(void)
{
	struct number	*a, *b;
	struct number	*rdiv, *rmod;
	u_int		scale;
	BN_CTX		*ctx;

	a = pop_number();
	if (a == NULL) {
		return;
	}
	b = pop_number();
	if (b == NULL) {
		push_number(a);
		return;
	}

	rdiv = new_number();
	rmod = new_number();
	rdiv->scale = bmachine.scale;
	rmod->scale = max(b->scale, a->scale + bmachine.scale);
	scale = max(a->scale, b->scale);

	if (BN_is_zero(a->number))
		warnx("divide by zero");
	else {
		normalize(a, scale);
		normalize(b, scale + bmachine.scale);

		ctx = BN_CTX_new();
		bn_checkp(ctx);
		bn_check(BN_div(rdiv->number, rmod->number,
		    b->number, a->number, ctx));
		BN_CTX_free(ctx);
	}
	push_number(rdiv);
	push_number(rmod);
	free_number(a);
	free_number(b);
}
Example #10
0
void
print_ascii(FILE *f, const struct number *n)
{
	BIGNUM *v;
	int numbits, i, ch;

	v = BN_dup(n->number);
	bn_checkp(v);

	if (BN_cmp(v, &zero) < 0)
		bn_check(BN_sub(v, &zero, v));

	numbits = BN_num_bytes(v) * 8;
	while (numbits > 0) {
		ch = 0;
		for (i = 0; i < 8; i++)
			ch |= BN_is_bit_set(v, numbits-i-1) << (7 - i);
		putc(ch, f);
		numbits -= 8;
	}
	BN_free(v);
}
Example #11
0
static void
bdiv(void)
{
	struct number *a, *b, *r;
	BN_CTX *ctx;
	u_int scale;

	a = pop_number();
	if (a == NULL) {
		return;
	}
	b = pop_number();
	if (b == NULL) {
		push_number(a);
		return;
	}

	r = new_number();
	r->scale = bmachine.scale;
	scale = max(a->scale, b->scale);

	if (BN_is_zero(a->number))
		warnx("divide by zero");
	else {
		normalize(a, scale);
		normalize(b, scale + r->scale);

		ctx = BN_CTX_new();
		bn_checkp(ctx);
		bn_check(BN_div(r->number, NULL, b->number, a->number, ctx));
		BN_CTX_free(ctx);
	}
	push_number(r);
	free_number(a);
	free_number(b);
}
Example #12
0
static void
bexp(void)
{
	struct number	*a, *p;
	struct number	*r;
	bool		neg;
	u_int		rscale;

	p = pop_number();
	if (p == NULL)
		return;
	a = pop_number();
	if (a == NULL) {
		push_number(p);
		return;
	}

	if (p->scale != 0) {
		BIGNUM *i, *f;
		i = BN_new();
		bn_checkp(i);
		f = BN_new();
		bn_checkp(f);
		split_number(p, i, f);
		if (!BN_is_zero(f))
			warnx("Runtime warning: non-zero fractional part in exponent");
		BN_free(i);
		BN_free(f);
	}

	normalize(p, 0);

	neg = false;
	if (BN_is_negative(p->number)) {
		neg = true;
		negate(p);
		rscale = bmachine.scale;
	} else {
		/* Posix bc says min(a.scale * b, max(a.scale, scale) */
		u_long b;
		u_int m;

		b = BN_get_word(p->number);
		m = max(a->scale, bmachine.scale);
		rscale = a->scale * (u_int)b;
		if (rscale > m || (a->scale > 0 && (b == ULONG_MAX ||
		    b > UINT_MAX)))
			rscale = m;
	}

	if (BN_is_zero(p->number)) {
		r = new_number();
		bn_check(BN_one(r->number));
		normalize(r, rscale);
	} else {
		u_int ascale, mscale;

		ascale = a->scale;
		while (!BN_is_bit_set(p->number, 0)) {
			ascale *= 2;
			bmul_number(a, a, a, ascale);
			bn_check(BN_rshift1(p->number, p->number));
		}

		r = dup_number(a);
		bn_check(BN_rshift1(p->number, p->number));

		mscale = ascale;
		while (!BN_is_zero(p->number)) {
			ascale *= 2;
			bmul_number(a, a, a, ascale);
			if (BN_is_bit_set(p->number, 0)) {
				mscale += ascale;
				bmul_number(r, r, a, mscale);
			}
			bn_check(BN_rshift1(p->number, p->number));
		}

		if (neg) {
			BN_CTX *ctx;
			BIGNUM *one;

			one = BN_new();
			bn_checkp(one);
			bn_check(BN_one(one));
			ctx = BN_CTX_new();
			bn_checkp(ctx);
			scale_number(one, r->scale + rscale);

			if (BN_is_zero(r->number))
				warnx("divide by zero");
			else
				bn_check(BN_div(r->number, NULL, one,
				    r->number, ctx));
			BN_free(one);
			BN_CTX_free(ctx);
			r->scale = rscale;
		} else
			normalize(r, rscale);
	}
	push_number(r);
	free_number(a);
	free_number(p);
}
Example #13
0
static void
bexp(void)
{
	struct number	*a, *p;
	struct number	*r;
	bool		neg;
	u_int		scale;

	p = pop_number();
	if (p == NULL) {
		return;
	}
	a = pop_number();
	if (a == NULL) {
		push_number(p);
		return;
	}

	if (p->scale != 0)
		warnx("Runtime warning: non-zero scale in exponent");
	normalize(p, 0);

	neg = false;
	if (BN_cmp(p->number, &zero) < 0) {
		neg = true;
		negate(p);
		scale = bmachine.scale;
	} else {
		/* Posix bc says min(a.scale * b, max(a.scale, scale) */
		u_long	b;
		u_int	m;

		b = BN_get_word(p->number);
		m = max(a->scale, bmachine.scale);
		scale = a->scale * (u_int)b;
		if (scale > m || (a->scale > 0 && (b == BN_MASK2 ||
		    b > UINT_MAX)))
			scale = m;
	}

	if (BN_is_zero(p->number)) {
		r = new_number();
		bn_check(BN_one(r->number));
		normalize(r, scale);
	} else {
		while (!BN_is_bit_set(p->number, 0)) {
			bmul_number(a, a, a);
			bn_check(BN_rshift1(p->number, p->number));
		}

		r = dup_number(a);
		normalize(r, scale);
		bn_check(BN_rshift1(p->number, p->number));

		while (!BN_is_zero(p->number)) {
			bmul_number(a, a, a);
			if (BN_is_bit_set(p->number, 0))
				bmul_number(r, r, a);
			bn_check(BN_rshift1(p->number, p->number));
		}

		if (neg) {
			BN_CTX	*ctx;
			BIGNUM	*one;

			one = BN_new();
			bn_checkp(one);
			bn_check(BN_one(one));
			ctx = BN_CTX_new();
			bn_checkp(ctx);
			scale_number(one, r->scale + scale);
			normalize(r, scale);
			bn_check(BN_div(r->number, NULL, one, r->number, ctx));
			BN_free(one);
			BN_CTX_free(ctx);
		} else
			normalize(r, scale);
	}
	push_number(r);
	free_number(a);
	free_number(p);
}