Commit 46a64376 authored by Bodo Möller's avatar Bodo Möller
Browse files

Implement fixed-window exponentiation to mitigate hyper-threading

timing attacks.

BN_FLG_EXP_CONSTTIME requests this algorithm, and this done by default for
RSA/DSA/DH private key computations unless
RSA_FLAG_NO_EXP_CONSTTIME/DSA_FLAG_NO_EXP_CONSTTIME/
DH_FLAG_NO_EXP_CONSTTIME is set.

Submitted by: Matthew D Wood
Reviewed by: Bodo Moeller
parent 92c44685
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -799,6 +799,21 @@

 Changes between 0.9.7g and 0.9.7h  [XX xxx XXXX]

  *) Make a new fixed-window mod_exp implementation the default for
     RSA, DSA, and DH private-key operations to mitigate the
     hyper-threading timing attacks pointed out by Colin Percival
     (http://www.daemonology.net/hyperthreading-considered-harmful/),
     and potential related attacks.

     BN_mod_exp_mont_consttime() is the new exponentiation implementation,
     and this is automatically used by BN_mod_exp_mont() if the new flag
     BN_FLG_EXP_CONSTTIME is set for the exponent.  RSA, DSA, and DH
     will use this BN flag for private exponents unless the flag
     RSA_FLAG_NO_EXP_CONSTTIME, DSA_FLAG_NO_EXP_CONSTTIME, or
     DH_FLAG_NO_EXP_CONSTTIME, respectively, is set.

     [Matthew D Wood (Intel Corp), with some changes by Bodo Moeller]

  *) Change the client implementation for SSLv23_method() and
     SSLv23_client_method() so that is uses the SSL 3.0/TLS 1.0
     Client Hello message format if the SSL_OP_NO_SSLv2 option is set.
+2 −2
Original line number Diff line number Diff line
@@ -2365,7 +2365,7 @@ show_res:
				k,rsa_bits[k],rsa_results[k][0],
				rsa_results[k][1]);
		else
			fprintf(stdout,"rsa %4u bits %8.4fs %8.4fs %8.1f %8.1f\n",
			fprintf(stdout,"rsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
				rsa_bits[k],rsa_results[k][0],rsa_results[k][1],
				1.0/rsa_results[k][0],1.0/rsa_results[k][1]);
		}
@@ -2384,7 +2384,7 @@ show_res:
			fprintf(stdout,"+F3:%u:%u:%f:%f\n",
				k,dsa_bits[k],dsa_results[k][0],dsa_results[k][1]);
		else
			fprintf(stdout,"dsa %4u bits %8.4fs %8.4fs %8.1f %8.1f\n",
			fprintf(stdout,"dsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
				dsa_bits[k],dsa_results[k][0],dsa_results[k][1],
				1.0/dsa_results[k][0],1.0/dsa_results[k][1]);
		}
+30 −14
Original line number Diff line number Diff line
@@ -245,12 +245,23 @@ extern "C" {

#define BN_FLG_MALLOCED		0x01
#define BN_FLG_STATIC_DATA	0x02
#define BN_FLG_EXP_CONSTTIME	0x04 /* avoid leaking exponent information through timings
                            	      * (BN_mod_exp_mont() will call BN_mod_exp_mont_consttime) */
#ifndef OPENSSL_NO_DEPRECATED
#define BN_FLG_FREE		0x8000	/* used for debuging */
#endif
#define BN_set_flags(b,n)	((b)->flags|=(n))
#define BN_get_flags(b,n)	((b)->flags&(n))

#define BN_with_flags(dest,b,n)  ((dest)->d=(b)->d, \
                                  (dest)->top=(b)->top, \
                                  (dest)->dmax=(b)->dmax, \
                                  (dest)->neg=(b)->neg, \
                                  (dest)->flags=(((dest)->flags & BN_FLG_MALLOCED) \
                                                 |  ((b)->flags & ~BN_FLG_MALLOCED) \
                                                 |  BN_FLG_STATIC_DATA \
                                                 |  (n)))

/* Already declared in ossl_typ.h */
#if 0
typedef struct bignum_st BIGNUM;
@@ -439,6 +450,8 @@ int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
	const BIGNUM *m,BN_CTX *ctx);
int	BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont);
int	BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
int	BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1,
@@ -728,9 +741,9 @@ void ERR_load_BN_strings(void);
/* Error codes for the BN functions. */

/* Function codes. */
#define BN_F_BNRAND					 114
#define BN_F_BNRAND					 127
#define BN_F_BN_BLINDING_CONVERT_EX			 100
#define BN_F_BN_BLINDING_CREATE_PARAM			 133
#define BN_F_BN_BLINDING_CREATE_PARAM			 128
#define BN_F_BN_BLINDING_INVERT_EX			 101
#define BN_F_BN_BLINDING_NEW				 102
#define BN_F_BN_BLINDING_UPDATE				 103
@@ -738,28 +751,32 @@ void ERR_load_BN_strings(void);
#define BN_F_BN_BN2HEX					 105
#define BN_F_BN_CTX_GET					 116
#define BN_F_BN_CTX_NEW					 106
#define BN_F_BN_CTX_START				 130
#define BN_F_BN_CTX_START				 129
#define BN_F_BN_DIV					 107
#define BN_F_BN_DIV_RECP				 131
#define BN_F_BN_DIV_RECP				 130
#define BN_F_BN_EXP					 123
#define BN_F_BN_EXPAND2					 108
#define BN_F_BN_EXPAND_INTERNAL				 120
#define BN_F_BN_GF2M_MOD				 126
#define BN_F_BN_GF2M_MOD_DIV				 123
#define BN_F_BN_GF2M_MOD_EXP				 127
#define BN_F_BN_GF2M_MOD_MUL				 124
#define BN_F_BN_GF2M_MOD_SOLVE_QUAD			 128
#define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR			 129
#define BN_F_BN_GF2M_MOD_SQR				 125
#define BN_F_BN_GF2M_MOD_SQRT				 132
#define BN_F_BN_GF2M_MOD				 131
#define BN_F_BN_GF2M_MOD_EXP				 132
#define BN_F_BN_GF2M_MOD_MUL				 133
#define BN_F_BN_GF2M_MOD_SOLVE_QUAD			 134
#define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR			 135
#define BN_F_BN_GF2M_MOD_SQR				 136
#define BN_F_BN_GF2M_MOD_SQRT				 137
#define BN_F_BN_MOD_EXP2_MONT				 118
#define BN_F_BN_MOD_EXP_MONT				 109
#define BN_F_BN_MOD_EXP_MONT_CONSTTIME			 124
#define BN_F_BN_MOD_EXP_MONT_WORD			 117
#define BN_F_BN_MOD_EXP_RECP				 125
#define BN_F_BN_MOD_EXP_SIMPLE				 126
#define BN_F_BN_MOD_INVERSE				 110
#define BN_F_BN_MOD_LSHIFT_QUICK			 119
#define BN_F_BN_MOD_MUL_RECIPROCAL			 111
#define BN_F_BN_MOD_SQRT				 121
#define BN_F_BN_MPI2BN					 112
#define BN_F_BN_NEW					 113
#define BN_F_BN_RAND					 114
#define BN_F_BN_RAND_RANGE				 122
#define BN_F_BN_USUB					 115

@@ -775,10 +792,9 @@ void ERR_load_BN_strings(void);
#define BN_R_INVALID_LENGTH				 106
#define BN_R_INVALID_RANGE				 115
#define BN_R_NOT_A_SQUARE				 111
#define BN_R_NOT_IMPLEMENTED				 116
#define BN_R_NOT_INITIALIZED				 107
#define BN_R_NO_INVERSE					 108
#define BN_R_NO_SOLUTION				 117
#define BN_R_NO_SOLUTION				 116
#define BN_R_P_IS_NOT_PRIME				 112
#define BN_R_TOO_MANY_ITERATIONS			 113
#define BN_R_TOO_MANY_TEMPORARY_VARIABLES		 109
+5 −2
Original line number Diff line number Diff line
@@ -83,10 +83,10 @@ static ERR_STRING_DATA BN_str_functs[]=
{ERR_FUNC(BN_F_BN_CTX_START),	"BN_CTX_start"},
{ERR_FUNC(BN_F_BN_DIV),	"BN_div"},
{ERR_FUNC(BN_F_BN_DIV_RECP),	"BN_div_recp"},
{ERR_FUNC(BN_F_BN_EXP),	"BN_exp"},
{ERR_FUNC(BN_F_BN_EXPAND2),	"bn_expand2"},
{ERR_FUNC(BN_F_BN_EXPAND_INTERNAL),	"BN_EXPAND_INTERNAL"},
{ERR_FUNC(BN_F_BN_GF2M_MOD),	"BN_GF2m_mod"},
{ERR_FUNC(BN_F_BN_GF2M_MOD_DIV),	"BN_GF2m_mod_div"},
{ERR_FUNC(BN_F_BN_GF2M_MOD_EXP),	"BN_GF2m_mod_exp"},
{ERR_FUNC(BN_F_BN_GF2M_MOD_MUL),	"BN_GF2m_mod_mul"},
{ERR_FUNC(BN_F_BN_GF2M_MOD_SOLVE_QUAD),	"BN_GF2m_mod_solve_quad"},
@@ -95,13 +95,17 @@ static ERR_STRING_DATA BN_str_functs[]=
{ERR_FUNC(BN_F_BN_GF2M_MOD_SQRT),	"BN_GF2m_mod_sqrt"},
{ERR_FUNC(BN_F_BN_MOD_EXP2_MONT),	"BN_mod_exp2_mont"},
{ERR_FUNC(BN_F_BN_MOD_EXP_MONT),	"BN_mod_exp_mont"},
{ERR_FUNC(BN_F_BN_MOD_EXP_MONT_CONSTTIME),	"BN_mod_exp_mont_consttime"},
{ERR_FUNC(BN_F_BN_MOD_EXP_MONT_WORD),	"BN_mod_exp_mont_word"},
{ERR_FUNC(BN_F_BN_MOD_EXP_RECP),	"BN_mod_exp_recp"},
{ERR_FUNC(BN_F_BN_MOD_EXP_SIMPLE),	"BN_mod_exp_simple"},
{ERR_FUNC(BN_F_BN_MOD_INVERSE),	"BN_mod_inverse"},
{ERR_FUNC(BN_F_BN_MOD_LSHIFT_QUICK),	"BN_mod_lshift_quick"},
{ERR_FUNC(BN_F_BN_MOD_MUL_RECIPROCAL),	"BN_mod_mul_reciprocal"},
{ERR_FUNC(BN_F_BN_MOD_SQRT),	"BN_mod_sqrt"},
{ERR_FUNC(BN_F_BN_MPI2BN),	"BN_mpi2bn"},
{ERR_FUNC(BN_F_BN_NEW),	"BN_new"},
{ERR_FUNC(BN_F_BN_RAND),	"BN_rand"},
{ERR_FUNC(BN_F_BN_RAND_RANGE),	"BN_rand_range"},
{ERR_FUNC(BN_F_BN_USUB),	"BN_usub"},
{0,NULL}
@@ -120,7 +124,6 @@ static ERR_STRING_DATA BN_str_reasons[]=
{ERR_REASON(BN_R_INVALID_LENGTH)         ,"invalid length"},
{ERR_REASON(BN_R_INVALID_RANGE)          ,"invalid range"},
{ERR_REASON(BN_R_NOT_A_SQUARE)           ,"not a square"},
{ERR_REASON(BN_R_NOT_IMPLEMENTED)        ,"not implemented"},
{ERR_REASON(BN_R_NOT_INITIALIZED)        ,"not initialized"},
{ERR_REASON(BN_R_NO_INVERSE)             ,"no inverse"},
{ERR_REASON(BN_R_NO_SOLUTION)            ,"no solution"},
+242 −2
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@
 * [including the GNU Public Licence.]
 */
/* ====================================================================
 * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
 * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -113,6 +113,7 @@
#include "cryptlib.h"
#include "bn_lcl.h"

/* maximum precomputation table size for *variable* sliding windows */
#define TABLE_SIZE	32

/* this one works - simple but works */
@@ -121,6 +122,13 @@ int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
	int i,bits,ret=0;
	BIGNUM *v,*rr;

	if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
		{
		/* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
		BNerr(BN_F_BN_EXP,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
		return -1;
		}

	BN_CTX_start(ctx);
	if ((r == a) || (r == p))
		rr = BN_CTX_get(ctx);
@@ -205,7 +213,7 @@ int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
	if (BN_is_odd(m))
		{
#  ifdef MONT_EXP_WORD
		if (a->top == 1 && !a->neg)
		if (a->top == 1 && !a->neg && (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) == 0))
			{
			BN_ULONG A = a->d[0];
			ret=BN_mod_exp_mont_word(r,A,p,m,ctx,NULL);
@@ -237,6 +245,13 @@ int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
	BIGNUM *val[TABLE_SIZE];
	BN_RECP_CTX recp;

	if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
		{
		/* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
		BNerr(BN_F_BN_MOD_EXP_RECP,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
		return -1;
		}

	bits=BN_num_bits(p);

	if (bits == 0)
@@ -364,6 +379,11 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
	BIGNUM *val[TABLE_SIZE];
	BN_MONT_CTX *mont=NULL;

	if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
		{
		return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, in_mont);
		}

	bn_check_top(a);
	bn_check_top(p);
	bn_check_top(m);
@@ -495,6 +515,212 @@ err:
	return(ret);
	}


/* BN_mod_exp_mont_consttime() stores the precomputed powers in a specific layout
 * so that accessing any of these table values shows the same access pattern as far
 * as cache lines are concerned.  The following functions are used to transfer a BIGNUM
 * from/to that table. */

static int MOD_EXP_CTIME_COPY_TO_PREBUF(BIGNUM *b, int top, unsigned char *buf, int idx, int width)
	{
	size_t i, j;

	if (bn_wexpand(b, top) == NULL)
		return 0;
	while (b->top < top)
		{
		b->d[b->top++] = 0;
		}
	
	for (i = 0, j=idx; i < top * sizeof b->d[0]; i++, j+=width)
		{
		buf[j] = ((unsigned char*)b->d)[i];
		}

	bn_correct_top(b);
	return 1;
	}

static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, unsigned char *buf, int idx, int width)
	{
	size_t i, j;

	if (bn_wexpand(b, top) == NULL)
		return 0;

	for (i=0, j=idx; i < top * sizeof b->d[0]; i++, j+=width)
		{
		((unsigned char*)b->d)[i] = buf[j];
		}

	b->top = top;
	bn_correct_top(b);
	return 1;
	}	

/* Given a pointer value, compute the next address that is a cache line multiple. */
#define MOD_EXP_CTIME_ALIGN(x_) \
	((unsigned char*)(x_) + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - (((BN_ULONG)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK))))

/* This variant of BN_mod_exp_mont() uses fixed windows and the special
 * precomputation memory layout to limit data-dependency to a minimum
 * to protect secret exponents (cf. the hyper-threading timing attacks
 * pointed out by Colin Percival,
 * http://www.daemonology.net/hyperthreading-considered-harmful/)
 */
int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
		    const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
	{
	int i,bits,ret=0,idx,window,wvalue;
	int top;
 	BIGNUM *r;
	const BIGNUM *aa;
	BN_MONT_CTX *mont=NULL;

	int numPowers;
	unsigned char *powerbufFree=NULL;
	int powerbufLen = 0;
	unsigned char *powerbuf=NULL;
	BIGNUM *computeTemp=NULL, *am=NULL;

	bn_check_top(a);
	bn_check_top(p);
	bn_check_top(m);

	top = m->top;

	if (!(m->d[0] & 1))
		{
		BNerr(BN_F_BN_MOD_EXP_MONT_CONSTTIME,BN_R_CALLED_WITH_EVEN_MODULUS);
		return(0);
		}
	bits=BN_num_bits(p);
	if (bits == 0)
		{
		ret = BN_one(rr);
		return ret;
		}

 	/* Initialize BIGNUM context and allocate intermediate result */
	BN_CTX_start(ctx);
	r = BN_CTX_get(ctx);
	if (r == NULL) goto err;

	/* Allocate a montgomery context if it was not supplied by the caller.
	 * If this is not done, things will break in the montgomery part.
 	 */
	if (in_mont != NULL)
		mont=in_mont;
	else
		{
		if ((mont=BN_MONT_CTX_new()) == NULL) goto err;
		if (!BN_MONT_CTX_set(mont,m,ctx)) goto err;
		}

	/* Get the window size to use with size of p. */
	window = BN_window_bits_for_ctime_exponent_size(bits);

	/* Allocate a buffer large enough to hold all of the pre-computed
	 * powers of a.
	 */
	numPowers = 1 << window;
	powerbufLen = sizeof(m->d[0])*top*numPowers;
	if ((powerbufFree=(unsigned char*)OPENSSL_malloc(powerbufLen+MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH)) == NULL)
		goto err;
		
	powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree);
	memset(powerbuf, 0, powerbufLen);

 	/* Initialize the intermediate result. Do this early to save double conversion,
	 * once each for a^0 and intermediate result.
	 */
 	if (!BN_to_montgomery(r,BN_value_one(),mont,ctx)) goto err;
	if (!MOD_EXP_CTIME_COPY_TO_PREBUF(r, top, powerbuf, 0, numPowers)) goto err;

	/* Initialize computeTemp as a^1 with montgomery precalcs */
	computeTemp = BN_CTX_get(ctx);
	am = BN_CTX_get(ctx);
	if (computeTemp==NULL || am==NULL) goto err;

	if (a->neg || BN_ucmp(a,m) >= 0)
		{
		if (!BN_mod(am,a,m,ctx))
			goto err;
		aa= am;
		}
	else
		aa=a;
	if (!BN_to_montgomery(am,aa,mont,ctx)) goto err;
	if (!BN_copy(computeTemp, am)) goto err;
	if (!MOD_EXP_CTIME_COPY_TO_PREBUF(am, top, powerbuf, 1, numPowers)) goto err;

	/* If the window size is greater than 1, then calculate
	 * val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1)
	 * (even powers could instead be computed as (a^(i/2))^2
	 * to use the slight performance advantage of sqr over mul).
	 */
	if (window > 1)
		{
		for (i=2; i<numPowers; i++)
			{
			/* Calculate a^i = a^(i-1) * a */
			if (!BN_mod_mul_montgomery(computeTemp,am,computeTemp,mont,ctx))
				goto err;
			if (!MOD_EXP_CTIME_COPY_TO_PREBUF(computeTemp, top, powerbuf, i, numPowers)) goto err;
			}
		}

 	/* Adjust the number of bits up to a multiple of the window size.
 	 * If the exponent length is not a multiple of the window size, then
 	 * this pads the most significant bits with zeros to normalize the
 	 * scanning loop to there's no special cases.
 	 *
 	 * * NOTE: Making the window size a power of two less than the native
	 * * word size ensures that the padded bits won't go past the last
 	 * * word in the internal BIGNUM structure. Going past the end will
 	 * * still produce the correct result, but causes a different branch
 	 * * to be taken in the BN_is_bit_set function.
 	 */
 	bits = ((bits+window-1)/window)*window;
 	idx=bits-1;	/* The top bit of the window */

 	/* Scan the exponent one window at a time starting from the most
 	 * significant bits.
 	 */
 	while (idx >= 0)
  		{
 		wvalue=0; /* The 'value' of the window */
 		
 		/* Scan the window, squaring the result as we go */
 		for (i=0; i<window; i++,idx--)
 			{
			if (!BN_mod_mul_montgomery(r,r,r,mont,ctx))	goto err;
			wvalue = (wvalue<<1)+BN_is_bit_set(p,idx);
  			}
 		
		/* Fetch the appropriate pre-computed value from the pre-buf */
		if (!MOD_EXP_CTIME_COPY_FROM_PREBUF(computeTemp, top, powerbuf, wvalue, numPowers)) goto err;

 		/* Multiply the result into the intermediate result */
 		if (!BN_mod_mul_montgomery(r,r,computeTemp,mont,ctx)) goto err;
  		}

 	/* Convert the final result from montgomery to standard format */
	if (!BN_from_montgomery(rr,r,mont,ctx)) goto err;
	ret=1;
err:
	if ((in_mont == NULL) && (mont != NULL)) BN_MONT_CTX_free(mont);
	if (powerbuf!=NULL)
		{
		OPENSSL_cleanse(powerbuf,powerbufLen);
		OPENSSL_free(powerbufFree);
		}
 	if (am!=NULL) BN_clear(am);
 	if (computeTemp!=NULL) BN_clear(computeTemp);
	BN_CTX_end(ctx);
	return(ret);
	}

int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
                         const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
	{
@@ -519,6 +745,13 @@ int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
#define BN_TO_MONTGOMERY_WORD(r, w, mont) \
		(BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx))

	if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
		{
		/* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
		BNerr(BN_F_BN_MOD_EXP_MONT_WORD,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
		return -1;
		}

	bn_check_top(p);
	bn_check_top(m);

@@ -648,6 +881,13 @@ int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
	/* Table of variables obtained from 'ctx' */
	BIGNUM *val[TABLE_SIZE];

	if (BN_get_flags(p, BN_FLG_EXP_CONSTTIME) != 0)
		{
		/* BN_FLG_EXP_CONSTTIME only supported by BN_mod_exp_mont() */
		BNerr(BN_F_BN_MOD_EXP_SIMPLE,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
		return -1;
		}

	bits=BN_num_bits(p);

	if (bits == 0)
Loading