int BN_is_prime_fasttest(BIGNUM *a, int checks,
		void (*callback)(int,int,void *),
		BN_CTX *ctx_passed, void *cb_arg,
		int do_trial_division)
	{
	int i, j, ret = -1;
	int k;
	BN_CTX *ctx = NULL;
	BIGNUM *a1, *a1_odd, *check; /* taken from ctx */
	BN_MONT_CTX *mont = NULL;

	if (checks == BN_prime_checks)
		checks = BN_prime_checks_for_size(BN_num_bits(a));

	if (a->neg) /* for now, refuse to handle negative numbers */
		return -1;

	/* first look for small factors */
	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;
	a1 = &(ctx->bn[ctx->tos++]);
	a1_odd = &(ctx->bn[ctx->tos++]);
	check = &(ctx->bn[ctx->tos++]);;

	/* compute a1 := a - 1 */
	if (!BN_copy(a1, a))
		goto err;
	if (!BN_sub_word(a1, 1))
		goto err;
	if (BN_is_zero(a1))
		{
		ret = 0;
		goto err;
		}

	/* write  a1  as  a1_odd * 2^k */
	k = 1;
	while (!BN_is_bit_set(a1, k))
		k++;
	if (!BN_rshift(a1_odd, a1, k))
		goto err;

	/* Montgomery setup for computations mod a */
	mont = BN_MONT_CTX_new();
	if (mont == NULL)
		goto err;
	if (!BN_MONT_CTX_set(mont, a, ctx))
		goto err;
	
	for (i = 0; i < checks; i++)
		{
		if (!BN_pseudo_rand(check, BN_num_bits(a1), 0, 0))
			goto err;
		if (BN_cmp(check, a1) >= 0)
			if (!BN_sub(check, check, a1))
				goto err;
		if (!BN_add_word(check, 1))
			goto err;
		/* now 1 <= check < a */

		j = witness(check, a, a1, a1_odd, k, ctx, mont);
		if (j == -1) goto err;
		if (j)
			{
			ret=0;
			goto err;
			}
		if (callback != NULL) callback(1,i,cb_arg);
		}
	ret=1;
err:
	if (ctx_passed != NULL)
		ctx_passed->tos -= 3; /* a1, a1_odd, check */
	else if (ctx != NULL)
		BN_CTX_free(ctx);
	if (mont != NULL)
		BN_MONT_CTX_free(mont);

	return(ret);
	}