int BN_is_prime_fasttest(BIGNUM *a, int checks,
		void (*callback)(int,int,void *),
		BN_CTX *ctx_passed, BN_CTX *ctx2_passed, void *cb_arg,
		int do_trial_division)
	{
	int i,j,ret= -1;
	BIGNUM *check;
	BN_CTX *ctx=NULL,*ctx2=NULL;
	BN_MONT_CTX *mont=NULL;

	if (checks == BN_prime_checks)
		{
		int bits = BN_num_bits(a);
		checks = BN_prime_checks_for_size(bits);
		}

	if (!BN_is_odd(a))
		return(0);
	if (do_trial_division)
		{
		for (i = 1; i < NUMPRIMES; i++)
			if (BN_mod_word(a, primes[i]) == 0) 
				return 0;
		if (callback != NULL) callback(1,-1,cb_arg);
		}

	if (ctx_passed != NULL)
		ctx=ctx_passed;
	else
		if ((ctx=BN_CTX_new()) == NULL) goto err;
	if (ctx2_passed != NULL)
		ctx2=ctx2_passed;
	else
		if ((ctx2=BN_CTX_new()) == NULL) goto err;

	if ((mont=BN_MONT_CTX_new()) == NULL) goto err;

	check= &(ctx->bn[ctx->tos++]);

	/* Setup the montgomery structure */
	if (!BN_MONT_CTX_set(mont,a,ctx2)) goto err;

	for (i=0; i<checks; i++)
		{
		if (!BN_pseudo_rand(check,BN_num_bits(a),0,0)) goto err;
		if (BN_cmp(check, a) >= 0)
			BN_sub(check, check, a);
		if (BN_is_zero(check)) BN_one(check);
		j=witness(check,a,ctx,ctx2,mont);
		if (j == -1) goto err;
		if (j)
			{
			ret=0;
			goto err;
			}
		if (callback != NULL) callback(1,i,cb_arg);
		}
	ret=1;
err:
	ctx->tos--;
	if ((ctx_passed == NULL) && (ctx != NULL))
		BN_CTX_free(ctx);
	if ((ctx2_passed == NULL) && (ctx2 != NULL))
		BN_CTX_free(ctx2);
	if (mont != NULL) BN_MONT_CTX_free(mont);
		
	return(ret);
	}