int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
	{
	int top,al,bl;
	BIGNUM *rr;
#ifdef BN_RECURSION
	BIGNUM *t;
	int i,j,k;
#endif

#ifdef BN_COUNT
printf("BN_mul %d * %d\n",a->top,b->top);
#endif

	bn_check_top(a);
	bn_check_top(b);
	bn_check_top(r);

	al=a->top;
	bl=b->top;
	r->neg=a->neg^b->neg;

	if ((al == 0) || (bl == 0))
		{
		BN_zero(r);
		return(1);
		}
	top=al+bl;

	if ((r == a) || (r == b))
		rr= &(ctx->bn[ctx->tos+1]);
	else
		rr=r;

#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
	if (al == bl)
		{
#  ifdef BN_MUL_COMBA
/*		if (al == 4)
			{
			if (bn_wexpand(rr,8) == NULL) return(0);
			rr->top=8;
			bn_mul_comba4(rr->d,a->d,b->d);
			goto end;
			}
		else */ if (al == 8)
			{
			if (bn_wexpand(rr,16) == NULL) return(0);
			rr->top=16;
			bn_mul_comba8(rr->d,a->d,b->d);
			goto end;
			}
		else
#  endif
#ifdef BN_RECURSION
		if (al < BN_MULL_SIZE_NORMAL)
#endif
			{
			if (bn_wexpand(rr,top) == NULL) return(0);
			rr->top=top;
			bn_mul_normal(rr->d,a->d,al,b->d,bl);
			goto end;
			}
#  ifdef BN_RECURSION
		goto symetric;
#  endif
		}
#endif
#ifdef BN_RECURSION
	else if ((al < BN_MULL_SIZE_NORMAL) || (bl < BN_MULL_SIZE_NORMAL))
		{
		if (bn_wexpand(rr,top) == NULL) return(0);
		rr->top=top;
		bn_mul_normal(rr->d,a->d,al,b->d,bl);
		goto end;
		}
	else
		{
		i=(al-bl);
		if ((i ==  1) && !BN_get_flags(b,BN_FLG_STATIC_DATA))
			{
			bn_wexpand(b,al);
			b->d[bl]=0;
			bl++;
			goto symetric;
			}
		else if ((i ==  -1) && !BN_get_flags(a,BN_FLG_STATIC_DATA))
			{
			bn_wexpand(a,bl);
			a->d[al]=0;
			al++;
			goto symetric;
			}
		}
#endif

	/* asymetric and >= 4 */ 
	if (bn_wexpand(rr,top) == NULL) return(0);
	rr->top=top;
	bn_mul_normal(rr->d,a->d,al,b->d,bl);

#ifdef BN_RECURSION
	if (0)
		{
symetric:
		/* symetric and > 4 */
		/* 16 or larger */
		j=BN_num_bits_word((BN_ULONG)al);
		j=1<<(j-1);
		k=j+j;
		t= &(ctx->bn[ctx->tos]);
		if (al == j) /* exact multiple */
			{
			bn_wexpand(t,k*2);
			bn_wexpand(rr,k*2);
			bn_mul_recursive(rr->d,a->d,b->d,al,t->d);
			}
		else
			{
			bn_wexpand(a,k);
			bn_wexpand(b,k);
			bn_wexpand(t,k*4);
			bn_wexpand(rr,k*4);
			for (i=a->top; i<k; i++)
				a->d[i]=0;
			for (i=b->top; i<k; i++)
				b->d[i]=0;
			bn_mul_part_recursive(rr->d,a->d,b->d,al-j,j,t->d);
			}
		rr->top=top;
		}
#endif
#if defined(BN_MUL_COMBA) || defined(BN_RECURSION)
end:
#endif
	bn_fix_top(rr);
	if (r != rr) BN_copy(r,rr);
	return(1);
	}