From 9b141126d4b6f0636bc047e81b846c193ae26611 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ulf=20M=C3=B6ller?= Date: Sat, 5 Feb 2000 14:17:32 +0000 Subject: [PATCH] New functions BN_CTX_start(), BN_CTX_get(), BN_CTX_end() to access temporary BIGNUMs. BN_CTX still uses a fixed number of BIGNUMs, but the BN_CTX implementation could now easily be changed. --- CHANGES | 8 +++ crypto/bn/Makefile.ssl | 4 +- crypto/bn/bn.h | 7 ++ crypto/bn/bn_ctx.c | 123 ++++++++++++++++++++++++++++++++++++ crypto/bn/bn_div.c | 56 ++++++++++------ crypto/bn/bn_err.c | 2 + crypto/bn/bn_exp.c | 48 ++++++++------ crypto/bn/bn_exp2.c | 12 ++-- crypto/bn/bn_gcd.c | 28 ++++---- crypto/bn/bn_lib.c | 37 ----------- crypto/bn/bn_mont.c | 23 ++++--- crypto/bn/bn_mul.c | 23 ++++--- crypto/bn/bn_prime.c | 39 +++++++----- crypto/bn/bn_recp.c | 22 ++++--- crypto/bn/bn_sqr.c | 23 ++++--- crypto/bn/old/bn_wmul.c | 4 +- crypto/dh/dh_gen.c | 13 ++-- crypto/dh/dh_key.c | 4 +- crypto/dsa/dsa_gen.c | 25 ++++---- crypto/rsa/rsa_gen.c | 12 ++-- crypto/rsa/rsa_lib.c | 6 +- doc/crypto/BN_CTX_new.pod | 3 +- doc/crypto/BN_CTX_start.pod | 49 ++++++++++++++ doc/crypto/BN_add.pod | 1 + 24 files changed, 401 insertions(+), 171 deletions(-) create mode 100644 crypto/bn/bn_ctx.c create mode 100644 doc/crypto/BN_CTX_start.pod diff --git a/CHANGES b/CHANGES index eab6eca939..5480029ca3 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,14 @@ Changes between 0.9.4 and 0.9.5 [xx XXX 2000] + *) New functions BN_CTX_start(), BN_CTX_get() and BT_CTX_end() to + get temporary BIGNUMs from a BN_CTX. + [Ulf Möller] + + *) Correct return values in BN_mod_exp_mont() and BN_mod_exp2_mont() + for p == 0. + [Ulf Möller] + *) Change the SSLeay_add_all_*() functions to OpenSSL_add_all_*() and include a #define from the old name to the new. The original intent was that statically linked binaries could for example just call diff --git a/crypto/bn/Makefile.ssl b/crypto/bn/Makefile.ssl index 3427f9fa35..94da20bd5a 100644 --- a/crypto/bn/Makefile.ssl +++ b/crypto/bn/Makefile.ssl @@ -34,12 +34,12 @@ TEST=bntest.c exptest.c APPS= LIB=$(TOP)/libcrypto.a -LIBSRC= bn_add.c bn_div.c bn_exp.c bn_lib.c bn_mul.c \ +LIBSRC= bn_add.c bn_div.c bn_exp.c bn_lib.c bn_ctx.c bn_mul.c \ bn_print.c bn_rand.c bn_shift.c bn_word.c bn_blind.c \ bn_gcd.c bn_prime.c bn_err.c bn_sqr.c bn_asm.c bn_recp.c bn_mont.c \ bn_mpi.c bn_exp2.c -LIBOBJ= bn_add.o bn_div.o bn_exp.o bn_lib.o bn_mul.o \ +LIBOBJ= bn_add.o bn_div.o bn_exp.o bn_lib.o bn_ctx.o bn_mul.o \ bn_print.o bn_rand.o bn_shift.o bn_word.o bn_blind.o \ bn_gcd.o bn_prime.o bn_err.o bn_sqr.o $(BN_ASM) bn_recp.o bn_mont.o \ bn_mpi.o bn_exp2.o diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h index 63606e1ac5..8ac8acd116 100644 --- a/crypto/bn/bn.h +++ b/crypto/bn/bn.h @@ -245,6 +245,8 @@ typedef struct bignum_ctx int tos; BIGNUM bn[BN_CTX_NUM+1]; int flags; + int depth; + int pos[BN_CTX_NUM+1]; } BN_CTX; typedef struct bn_blinding_st @@ -335,6 +337,9 @@ char * BN_options(void); BN_CTX *BN_CTX_new(void); void BN_CTX_init(BN_CTX *c); void BN_CTX_free(BN_CTX *c); +void BN_CTX_start(BN_CTX *ctx); +BIGNUM *BN_CTX_get(BN_CTX *ctx); +void BN_CTX_end(BN_CTX *ctx); int BN_rand(BIGNUM *rnd, int bits, int top,int bottom); int BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom); int BN_num_bits(const BIGNUM *a); @@ -463,6 +468,7 @@ int BN_div_recp(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, #define BN_F_BN_BLINDING_UPDATE 103 #define BN_F_BN_BN2DEC 104 #define BN_F_BN_BN2HEX 105 +#define BN_F_BN_CTX_GET 116 #define BN_F_BN_CTX_NEW 106 #define BN_F_BN_DIV 107 #define BN_F_BN_EXPAND2 108 @@ -484,6 +490,7 @@ int BN_div_recp(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, #define BN_R_INVALID_LENGTH 106 #define BN_R_NOT_INITIALIZED 107 #define BN_R_NO_INVERSE 108 +#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 109 #ifdef __cplusplus } diff --git a/crypto/bn/bn_ctx.c b/crypto/bn/bn_ctx.c new file mode 100644 index 0000000000..8b079e237f --- /dev/null +++ b/crypto/bn/bn_ctx.c @@ -0,0 +1,123 @@ +/* crypto/bn/bn_ctx.c */ +/* Written by Ulf Moeller for the OpenSSL project. */ +/* ==================================================================== + * Copyright (c) 1998-2000 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include "cryptlib.h" +#include + + +BN_CTX *BN_CTX_new(void) + { + BN_CTX *ret; + + ret=(BN_CTX *)Malloc(sizeof(BN_CTX)); + if (ret == NULL) + { + BNerr(BN_F_BN_CTX_NEW,ERR_R_MALLOC_FAILURE); + return(NULL); + } + + BN_CTX_init(ret); + ret->flags=BN_FLG_MALLOCED; + return(ret); + } + +void BN_CTX_init(BN_CTX *ctx) + { + int i; + ctx->tos = 0; + ctx->flags = 0; + ctx->depth = 0; + for (i = 0; i < BN_CTX_NUM; i++) + BN_init(&(ctx->bn[i])); + } + +void BN_CTX_free(BN_CTX *ctx) + { + int i; + + if (ctx == NULL) return; + assert(ctx->depth == 0); + + for (i=0; i < BN_CTX_NUM; i++) + BN_clear_free(&(ctx->bn[i])); + if (ctx->flags & BN_FLG_MALLOCED) + Free(ctx); + } + +void BN_CTX_start(BN_CTX *ctx) + { + ctx->pos[ctx->depth++] = ctx->tos; + } + +BIGNUM *BN_CTX_get(BN_CTX *ctx) + { + if (ctx->tos >= BN_CTX_NUM) + { + BNerr(BN_F_BN_CTX_GET,BN_R_TOO_MANY_TEMPORARY_VARIABLES); + return NULL; + } + return (&(ctx->bn[ctx->tos++])); + } + +void BN_CTX_end(BN_CTX *ctx) + { + if (ctx == NULL) return; + assert(ctx->depth > 0); + ctx->depth--; + ctx->tos = ctx->pos[ctx->depth]; + } diff --git a/crypto/bn/bn_div.c b/crypto/bn/bn_div.c index 39d7602c30..3505221a96 100644 --- a/crypto/bn/bn_div.c +++ b/crypto/bn/bn_div.c @@ -62,11 +62,12 @@ #include "bn_lcl.h" /* The old slow way */ -#if 0 +#if 1 int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) { int i,nm,nd; + int ret = 0; BIGNUM *D; bn_check_top(m); @@ -85,14 +86,17 @@ int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, return(1); } - D= &(ctx->bn[ctx->tos]); - if (dv == NULL) dv= &(ctx->bn[ctx->tos+1]); - if (rem == NULL) rem= &(ctx->bn[ctx->tos+2]); + BN_CTX_start(ctx); + D = BN_CTX_get(ctx); + if (dv == NULL) dv = BN_CTX_get(ctx); + if (rem == NULL) rem = BN_CTX_get(ctx); + if (D == NULL || dv == NULL || rem == NULL) + goto end; nd=BN_num_bits(d); nm=BN_num_bits(m); - if (BN_copy(D,d) == NULL) return(0); - if (BN_copy(rem,m) == NULL) return(0); + if (BN_copy(D,d) == NULL) goto end; + if (BN_copy(rem,m) == NULL) goto end; /* The next 2 are needed so we can do a dv->d[0]|=1 later * since BN_lshift1 will only work once there is a value :-) */ @@ -100,21 +104,24 @@ int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, bn_wexpand(dv,1); dv->top=1; - if (!BN_lshift(D,D,nm-nd)) return(0); + if (!BN_lshift(D,D,nm-nd)) goto end; for (i=nm-nd; i>=0; i--) { - if (!BN_lshift1(dv,dv)) return(0); + if (!BN_lshift1(dv,dv)) goto end; if (BN_ucmp(rem,D) >= 0) { dv->d[0]|=1; - if (!BN_usub(rem,rem,D)) return(0); + if (!BN_usub(rem,rem,D)) goto end; } /* CAN IMPROVE (and have now :=) */ - if (!BN_rshift1(D,D)) return(0); + if (!BN_rshift1(D,D)) goto end; } rem->neg=BN_is_zero(rem)?0:m->neg; dv->neg=m->neg^d->neg; - return(1); + ret = 1; + end: + BN_CTX_end(ctx); + return(ret); } #else @@ -145,13 +152,15 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, return(1); } - tmp= &(ctx->bn[ctx->tos]); + BN_CTX_start(ctx); + tmp=BN_CTX_get(ctx); tmp->neg=0; - snum= &(ctx->bn[ctx->tos+1]); - sdiv= &(ctx->bn[ctx->tos+2]); + snum=BN_CTX_get(ctx); + sdiv=BN_CTX_get(ctx); if (dv == NULL) - res= &(ctx->bn[ctx->tos+3]); + res=BN_CTX_get(ctx); else res=dv; + if (res == NULL) goto err; /* First we normalise the numbers */ norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); @@ -329,8 +338,10 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_rshift(rm,snum,norm_shift); rm->neg=num->neg; } + BN_CTX_end(ctx); return(1); err: + BN_CX_end(ctx); return(0); } @@ -346,22 +357,27 @@ int BN_mod(BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) if (BN_ucmp(m,d) < 0) return((BN_copy(rem,m) == NULL)?0:1); - dv= &(ctx->bn[ctx->tos]); + BN_CTX_start(ctx); + dv=BN_CTX_get(ctx); - if (!BN_copy(rem,m)) return(0); + if (!BN_copy(rem,m)) goto err; nm=BN_num_bits(rem); nd=BN_num_bits(d); - if (!BN_lshift(dv,d,nm-nd)) return(0); + if (!BN_lshift(dv,d,nm-nd)) goto err; for (i=nm-nd; i>=0; i--) { if (BN_cmp(rem,dv) >= 0) { - if (!BN_sub(rem,rem,dv)) return(0); + if (!BN_sub(rem,rem,dv)) goto err; } - if (!BN_rshift1(dv,dv)) return(0); + if (!BN_rshift1(dv,dv)) goto err; } + BN_CTX_end(ctx); return(1); + err: + BN_CTX_end(ctx); + return(0); #else return(BN_div(NULL,rem,m,d,ctx)); #endif diff --git a/crypto/bn/bn_err.c b/crypto/bn/bn_err.c index 73e80774e5..de3aaeb034 100644 --- a/crypto/bn/bn_err.c +++ b/crypto/bn/bn_err.c @@ -71,6 +71,7 @@ static ERR_STRING_DATA BN_str_functs[]= {ERR_PACK(0,BN_F_BN_BLINDING_UPDATE,0), "BN_BLINDING_update"}, {ERR_PACK(0,BN_F_BN_BN2DEC,0), "BN_bn2dec"}, {ERR_PACK(0,BN_F_BN_BN2HEX,0), "BN_bn2hex"}, +{ERR_PACK(0,BN_F_BN_CTX_GET,0), "BN_CTX_GET"}, {ERR_PACK(0,BN_F_BN_CTX_NEW,0), "BN_CTX_new"}, {ERR_PACK(0,BN_F_BN_DIV,0), "BN_div"}, {ERR_PACK(0,BN_F_BN_EXPAND2,0), "bn_expand2"}, @@ -95,6 +96,7 @@ static ERR_STRING_DATA BN_str_reasons[]= {BN_R_INVALID_LENGTH ,"invalid length"}, {BN_R_NOT_INITIALIZED ,"not initialized"}, {BN_R_NO_INVERSE ,"no inverse"}, +{BN_R_TOO_MANY_TEMPORARY_VARIABLES ,"too many temporary variables"}, {0,NULL} }; diff --git a/crypto/bn/bn_exp.c b/crypto/bn/bn_exp.c index 2df1614ada..8593ed0f39 100644 --- a/crypto/bn/bn_exp.c +++ b/crypto/bn/bn_exp.c @@ -72,7 +72,8 @@ int BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) bn_check_top(b); bn_check_top(m); - t= &(ctx->bn[ctx->tos++]); + BN_CTX_start(ctx); + if ((t = BN_CTX_get(ctx)) == NULL) goto err; if (a == b) { if (!BN_sqr(t,a,ctx)) goto err; } else @@ -80,7 +81,7 @@ int BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) if (!BN_mod(ret,t,m,ctx)) goto err; r=1; err: - ctx->tos--; + BN_CTX_end(ctx); return(r); } @@ -91,8 +92,10 @@ int BN_mod_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, BN_CTX *ctx) int i,bits,ret=0; BIGNUM *v,*tmp; - v= &(ctx->bn[ctx->tos++]); - tmp= &(ctx->bn[ctx->tos++]); + BN_CTX_start(ctx); + v = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + if (v == NULL || tmp == NULL) goto err; if (BN_copy(v,a) == NULL) goto err; bits=BN_num_bits(p); @@ -113,7 +116,7 @@ int BN_mod_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, BN_CTX *ctx) } ret=1; err: - ctx->tos-=2; + BN_CTX_end(ctx); return(ret); } @@ -122,15 +125,15 @@ err: /* this one works - simple but works */ int BN_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BN_CTX *ctx) { - int i,bits,ret=0,tos; + int i,bits,ret=0; BIGNUM *v,*rr; - tos=ctx->tos; - v= &(ctx->bn[ctx->tos++]); + BN_CTX_start(ctx); if ((r == a) || (r == p)) - rr= &(ctx->bn[ctx->tos++]); + rr = BN_CTX_get(ctx); else - rr=r; + rr = r; + if ((v = BN_CTX_get(ctx)) == NULL) goto err; if (BN_copy(v,a) == NULL) goto err; bits=BN_num_bits(p); @@ -149,8 +152,8 @@ int BN_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BN_CTX *ctx) } ret=1; err: - ctx->tos=tos; if (r != rr) BN_copy(r,rr); + BN_CTX_end(ctx); return(ret); } @@ -193,7 +196,6 @@ int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BIGNUM val[TABLE_SIZE]; BN_RECP_CTX recp; - aa= &(ctx->bn[ctx->tos++]); bits=BN_num_bits(p); if (bits == 0) @@ -201,6 +203,10 @@ int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_one(r); return(1); } + + BN_CTX_start(ctx); + if ((aa = BN_CTX_get(ctx)) == NULL) goto err; + BN_RECP_CTX_init(&recp); if (BN_RECP_CTX_set(&recp,m,ctx) <= 0) goto err; @@ -289,7 +295,7 @@ int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, } ret=1; err: - ctx->tos--; + BN_CTX_end(ctx); for (i=0; ibn[ctx->tos++]); - r= &(ctx->bn[ctx->tos++]); bits=BN_num_bits(p); if (bits == 0) { - BN_one(r); + BN_one(rr); return(1); } + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + if (d == NULL || r == NULL) goto err; /* If this is not done, things will break in the montgomery * part */ @@ -432,7 +440,7 @@ int BN_mod_exp_mont(BIGNUM *rr, BIGNUM *a, const BIGNUM *p, ret=1; err: if ((in_mont == NULL) && (mont != NULL)) BN_MONT_CTX_free(mont); - ctx->tos-=2; + BN_CTX_end(ctx); for (i=0; ibn[ctx->tos++]); bits=BN_num_bits(p); if (bits == 0) @@ -457,6 +464,9 @@ int BN_mod_exp_simple(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, return(1); } + BN_CTX_start(ctx); + if ((d = BN_CTX_get(ctx)) == NULL) goto err; + BN_init(&(val[0])); ts=1; if (!BN_mod(&(val[0]),a,m,ctx)) goto err; /* 1 */ @@ -541,7 +551,7 @@ int BN_mod_exp_simple(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m, } ret=1; err: - ctx->tos--; + BN_CTX_end(ctx); for (i=0; ibn[ctx->tos++]); - r= &(ctx->bn[ctx->tos++]); bits1=BN_num_bits(p1); bits2=BN_num_bits(p2); if ((bits1 == 0) && (bits2 == 0)) { - BN_one(r); + BN_one(rr); return(1); } + + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + if (d == NULL || r == NULL) goto err; + bits=(bits1 > bits2)?bits1:bits2; /* If this is not done, things will break in the montgomery @@ -183,7 +187,7 @@ int BN_mod_exp2_mont(BIGNUM *rr, BIGNUM *a1, BIGNUM *p1, BIGNUM *a2, ret=1; err: if ((in_mont == NULL) && (mont != NULL)) BN_MONT_CTX_free(mont); - ctx->tos-=2; + BN_CTX_end(ctx); for (i=0; ibn[ctx->tos]); - b= &(ctx->bn[ctx->tos+1]); + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + if (a == NULL || b == NULL) goto err; if (BN_copy(a,in_a) == NULL) goto err; if (BN_copy(b,in_b) == NULL) goto err; @@ -82,6 +85,7 @@ int BN_gcd(BIGNUM *r, BIGNUM *in_a, BIGNUM *in_b, BN_CTX *ctx) if (BN_copy(r,t) == NULL) goto err; ret=1; err: + BN_CTX_end(ctx); return(ret); } @@ -142,20 +146,22 @@ err: /* solves ax == 1 (mod n) */ BIGNUM *BN_mod_inverse(BIGNUM *in, BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) { - BIGNUM *A,*B,*X,*Y,*M,*D,*R; + BIGNUM *A,*B,*X,*Y,*M,*D,*R=NULL; BIGNUM *T,*ret=NULL; int sign; bn_check_top(a); bn_check_top(n); - A= &(ctx->bn[ctx->tos]); - B= &(ctx->bn[ctx->tos+1]); - X= &(ctx->bn[ctx->tos+2]); - D= &(ctx->bn[ctx->tos+3]); - M= &(ctx->bn[ctx->tos+4]); - Y= &(ctx->bn[ctx->tos+5]); - ctx->tos+=6; + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + B = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + D = BN_CTX_get(ctx); + M = BN_CTX_get(ctx); + Y = BN_CTX_get(ctx); + if (Y == NULL) goto err; + if (in == NULL) R=BN_new(); else @@ -198,7 +204,7 @@ BIGNUM *BN_mod_inverse(BIGNUM *in, BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) ret=R; err: if ((ret == NULL) && (in == NULL)) BN_free(R); - ctx->tos-=6; + BN_CTX_end(ctx); return(ret); } diff --git a/crypto/bn/bn_lib.c b/crypto/bn/bn_lib.c index e734909968..8c62761d4c 100644 --- a/crypto/bn/bn_lib.c +++ b/crypto/bn/bn_lib.c @@ -304,43 +304,6 @@ BIGNUM *BN_new(void) return(ret); } - -BN_CTX *BN_CTX_new(void) - { - BN_CTX *ret; - - ret=(BN_CTX *)Malloc(sizeof(BN_CTX)); - if (ret == NULL) - { - BNerr(BN_F_BN_CTX_NEW,ERR_R_MALLOC_FAILURE); - return(NULL); - } - - BN_CTX_init(ret); - ret->flags=BN_FLG_MALLOCED; - return(ret); - } - -void BN_CTX_init(BN_CTX *ctx) - { - memset(ctx,0,sizeof(BN_CTX)); - ctx->tos=0; - ctx->flags=0; - } - -void BN_CTX_free(BN_CTX *c) - { - int i; - - if(c == NULL) - return; - - for (i=0; ibn[i])); - if (c->flags & BN_FLG_MALLOCED) - Free(c); - } - /* This is an internal function that should not be used in applications. * It ensures that 'b' has enough room for a 'bits' bit number. It is * mostly used by the various BIGNUM routines. If there is an error, diff --git a/crypto/bn/bn_mont.c b/crypto/bn/bn_mont.c index dd691112c2..35a30a0eeb 100644 --- a/crypto/bn/bn_mont.c +++ b/crypto/bn/bn_mont.c @@ -72,9 +72,10 @@ int BN_mod_mul_montgomery(BIGNUM *r, BIGNUM *a, BIGNUM *b, { BIGNUM *tmp,*tmp2; - tmp= &(ctx->bn[ctx->tos]); - tmp2= &(ctx->bn[ctx->tos]); - ctx->tos+=2; + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + if (tmp == NULL || tmp2 == NULL) goto err; bn_check_top(tmp); bn_check_top(tmp2); @@ -98,16 +99,20 @@ int BN_mod_mul_montgomery(BIGNUM *r, BIGNUM *a, BIGNUM *b, } /* reduce from aRR to aR */ if (!BN_from_montgomery(r,tmp,mont,ctx)) goto err; - ctx->tos-=2; + BN_CTX_end(ctx); return(1); err: return(0); } +#define BN_RECURSION_MONT + int BN_from_montgomery(BIGNUM *ret, BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) { int retn=0; + BN_CTX_start(ctx); + #ifdef BN_RECURSION_MONT if (mont->use_word) #endif @@ -116,7 +121,7 @@ int BN_from_montgomery(BIGNUM *ret, BIGNUM *a, BN_MONT_CTX *mont, BN_ULONG *ap,*np,*rp,n0,v,*nrp; int al,nl,max,i,x,ri; - r= &(ctx->bn[ctx->tos]); + if ((r = BN_CTX_get(ctx)) == NULL) goto err; if (!BN_copy(r,a)) goto err; n= &(mont->N); @@ -210,9 +215,9 @@ printf("word BN_from_montgomery %d * %d\n",nl,nl); { BIGNUM *t1,*t2; - t1=&(ctx->bn[ctx->tos]); - t2=&(ctx->bn[ctx->tos+1]); - ctx->tos+=2; + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t1 == NULL || t2 == NULL) goto err; if (!BN_copy(t1,a)) goto err; BN_mask_bits(t1,mont->ri); @@ -226,11 +231,11 @@ printf("word BN_from_montgomery %d * %d\n",nl,nl); if (BN_ucmp(ret,&mont->N) >= 0) BN_usub(ret,ret,&mont->N); - ctx->tos-=2; retn=1; } #endif err: + BN_CTX_end(ctx); return(retn); } diff --git a/crypto/bn/bn_mul.c b/crypto/bn/bn_mul.c index 54414993db..36e9c4d9ff 100644 --- a/crypto/bn/bn_mul.c +++ b/crypto/bn/bn_mul.c @@ -585,10 +585,13 @@ printf("BN_mul %d * %d\n",a->top,b->top); } top=al+bl; + BN_CTX_start(ctx); if ((r == a) || (r == b)) - rr= &(ctx->bn[ctx->tos+1]); + { + if ((rr = BN_CTX_get(ctx)) == NULL) goto err; + } else - rr=r; + rr = r; #if defined(BN_MUL_COMBA) || defined(BN_RECURSION) if (al == bl) @@ -596,14 +599,14 @@ printf("BN_mul %d * %d\n",a->top,b->top); # ifdef BN_MUL_COMBA /* if (al == 4) { - if (bn_wexpand(rr,8) == NULL) return(0); + if (bn_wexpand(rr,8) == NULL) goto err; 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); + if (bn_wexpand(rr,16) == NULL) goto err; rr->top=16; bn_mul_comba8(rr->d,a->d,b->d); goto end; @@ -614,7 +617,7 @@ printf("BN_mul %d * %d\n",a->top,b->top); if (al < BN_MULL_SIZE_NORMAL) #endif { - if (bn_wexpand(rr,top) == NULL) return(0); + if (bn_wexpand(rr,top) == NULL) goto err; rr->top=top; bn_mul_normal(rr->d,a->d,al,b->d,bl); goto end; @@ -627,7 +630,7 @@ printf("BN_mul %d * %d\n",a->top,b->top); #ifdef BN_RECURSION else if ((al < BN_MULL_SIZE_NORMAL) || (bl < BN_MULL_SIZE_NORMAL)) { - if (bn_wexpand(rr,top) == NULL) return(0); + if (bn_wexpand(rr,top) == NULL) goto err; rr->top=top; bn_mul_normal(rr->d,a->d,al,b->d,bl); goto end; @@ -653,7 +656,7 @@ printf("BN_mul %d * %d\n",a->top,b->top); #endif /* asymmetric and >= 4 */ - if (bn_wexpand(rr,top) == NULL) return(0); + if (bn_wexpand(rr,top) == NULL) goto err; rr->top=top; bn_mul_normal(rr->d,a->d,al,b->d,bl); @@ -666,7 +669,7 @@ symmetric: j=BN_num_bits_word((BN_ULONG)al); j=1<<(j-1); k=j+j; - t= &(ctx->bn[ctx->tos]); + t = BN_CTX_get(ctx); if (al == j) /* exact multiple */ { bn_wexpand(t,k*2); @@ -693,7 +696,11 @@ end: #endif bn_fix_top(rr); if (r != rr) BN_copy(r,rr); + BN_CTX_end(ctx); return(1); +err: + BN_CTX_end(ctx); + return(0); } void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb) diff --git a/crypto/bn/bn_prime.c b/crypto/bn/bn_prime.c index 25bafd1f9c..a5f01b92eb 100644 --- a/crypto/bn/bn_prime.c +++ b/crypto/bn/bn_prime.c @@ -244,19 +244,23 @@ int BN_is_prime_fasttest(const BIGNUM *a, int checks, else if ((ctx=BN_CTX_new()) == NULL) goto err; + BN_CTX_start(ctx); + /* A := abs(a) */ if (a->neg) { - BIGNUM *t = &(ctx->bn[ctx->tos++]); + BIGNUM *t; + if ((t = BN_CTX_get(ctx)) == NULL) goto err; BN_copy(t, a); t->neg = 0; A = t; } else A = a; - A1 = &(ctx->bn[ctx->tos++]); - A1_odd = &(ctx->bn[ctx->tos++]); - check = &(ctx->bn[ctx->tos++]);; + A1 = BN_CTX_get(ctx); + A1_odd = BN_CTX_get(ctx); + check = BN_CTX_get(ctx); + if (check == NULL) goto err; /* compute A1 := A - 1 */ if (!BN_copy(A1, A)) @@ -305,14 +309,12 @@ int BN_is_prime_fasttest(const BIGNUM *a, int checks, } ret=1; err: - if (ctx_passed != NULL) + if (ctx != NULL) { - ctx_passed->tos -= 3; /* A1, A1_odd, check */ - if (a != A) - --ctx_passed->tos; /* A */ + BN_CTX_end(ctx); + if (ctx_passed == NULL) + BN_CTX_free(ctx); } - else if (ctx != NULL) - BN_CTX_free(ctx); if (mont != NULL) BN_MONT_CTX_free(mont); @@ -380,7 +382,8 @@ static int probable_prime_dh(BIGNUM *rnd, int bits, BIGNUM *add, BIGNUM *rem, int i,ret=0; BIGNUM *t1; - t1= &(ctx->bn[ctx->tos++]); + BN_CTX_start(ctx); + if ((t1 = BN_CTX_get(ctx)) == NULL) goto err; if (!BN_rand(rnd,bits,0,1)) goto err; @@ -406,7 +409,7 @@ static int probable_prime_dh(BIGNUM *rnd, int bits, BIGNUM *add, BIGNUM *rem, } ret=1; err: - ctx->tos--; + BN_CTX_end(ctx); return(ret); } @@ -414,12 +417,14 @@ static int probable_prime_dh_safe(BIGNUM *p, int bits, BIGNUM *padd, BIGNUM *rem, BN_CTX *ctx) { int i,ret=0; - BIGNUM *t1,*qadd=NULL,*q=NULL; + BIGNUM *t1,*qadd,*q; bits--; - t1= &(ctx->bn[ctx->tos++]); - q= &(ctx->bn[ctx->tos++]); - qadd= &(ctx->bn[ctx->tos++]); + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + qadd = BN_CTX_get(ctx); + if (qadd == NULL) goto err; if (!BN_rshift1(qadd,padd)) goto err; @@ -455,6 +460,6 @@ static int probable_prime_dh_safe(BIGNUM *p, int bits, BIGNUM *padd, } ret=1; err: - ctx->tos-=3; + BN_CTX_end(ctx); return(ret); } diff --git a/crypto/bn/bn_recp.c b/crypto/bn/bn_recp.c index c1b0e230ea..e1919e3ce6 100644 --- a/crypto/bn/bn_recp.c +++ b/crypto/bn/bn_recp.c @@ -106,7 +106,8 @@ int BN_mod_mul_reciprocal(BIGNUM *r, BIGNUM *x, BIGNUM *y, BN_RECP_CTX *recp, int ret=0; BIGNUM *a; - a= &(ctx->bn[ctx->tos++]); + BN_CTX_start(ctx); + if ((a = BN_CTX_get(ctx)) == NULL) goto err; if (y != NULL) { if (x == y) @@ -120,33 +121,34 @@ int BN_mod_mul_reciprocal(BIGNUM *r, BIGNUM *x, BIGNUM *y, BN_RECP_CTX *recp, BN_div_recp(NULL,r,a,recp,ctx); ret=1; err: - ctx->tos--; + BN_CTX_end(ctx); return(ret); } int BN_div_recp(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BN_RECP_CTX *recp, BN_CTX *ctx) { - int i,j,tos,ret=0,ex; + int i,j,ret=0,ex; BIGNUM *a,*b,*d,*r; - tos=ctx->tos; - a= &(ctx->bn[ctx->tos++]); - b= &(ctx->bn[ctx->tos++]); + BN_CTX_start(ctx); + a=BN_CTX_get(ctx); + b=BN_CTX_get(ctx); if (dv != NULL) d=dv; else - d= &(ctx->bn[ctx->tos++]); + d=BN_CTX_get(ctx); if (rem != NULL) r=rem; else - r= &(ctx->bn[ctx->tos++]); + r=BN_CTX_get(ctx); + if (a == NULL || b == NULL || d == NULL || r == NULL) goto err; if (BN_ucmp(m,&(recp->N)) < 0) { BN_zero(d); BN_copy(r,m); - ctx->tos=tos; + BN_CTX_end(ctx); return(1); } @@ -200,7 +202,7 @@ int BN_div_recp(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BN_RECP_CTX *recp, d->neg=m->neg^recp->N.neg; ret=1; err: - ctx->tos=tos; + BN_CTX_end(ctx); return(ret); } diff --git a/crypto/bn/bn_sqr.c b/crypto/bn/bn_sqr.c index 1874c14628..fe00c5f69a 100644 --- a/crypto/bn/bn_sqr.c +++ b/crypto/bn/bn_sqr.c @@ -65,14 +65,13 @@ int BN_sqr(BIGNUM *r, BIGNUM *a, BN_CTX *ctx) { int max,al; + int ret = 0; BIGNUM *tmp,*rr; #ifdef BN_COUNT printf("BN_sqr %d * %d\n",a->top,a->top); #endif bn_check_top(a); - tmp= &(ctx->bn[ctx->tos]); - rr=(a != r)?r: (&ctx->bn[ctx->tos+1]); al=a->top; if (al <= 0) @@ -81,8 +80,13 @@ printf("BN_sqr %d * %d\n",a->top,a->top); return(1); } + BN_CTX_start(ctx); + rr=(a != r) ? r : BN_CTX_get(ctx); + tmp=BN_CTX_get(ctx); + if (tmp == NULL) goto err; + max=(al+al); - if (bn_wexpand(rr,max+1) == NULL) return(0); + if (bn_wexpand(rr,max+1) == NULL) goto err; r->neg=0; if (al == 4) @@ -120,18 +124,18 @@ printf("BN_sqr %d * %d\n",a->top,a->top); k=j+j; if (al == j) { - if (bn_wexpand(a,k*2) == NULL) return(0); - if (bn_wexpand(tmp,k*2) == NULL) return(0); + if (bn_wexpand(a,k*2) == NULL) goto err; + if (bn_wexpand(tmp,k*2) == NULL) goto err; bn_sqr_recursive(rr->d,a->d,al,tmp->d); } else { - if (bn_wexpand(tmp,max) == NULL) return(0); + if (bn_wexpand(tmp,max) == NULL) goto err; bn_sqr_normal(rr->d,a->d,al,tmp->d); } } #else - if (bn_wexpand(tmp,max) == NULL) return(0); + if (bn_wexpand(tmp,max) == NULL) goto err; bn_sqr_normal(rr->d,a->d,al,tmp->d); #endif } @@ -139,7 +143,10 @@ printf("BN_sqr %d * %d\n",a->top,a->top); rr->top=max; if ((max > 0) && (rr->d[max-1] == 0)) rr->top--; if (rr != r) BN_copy(r,rr); - return(1); + ret = 1; + err: + BN_CTX_end(ctx); + return(ret); } /* tmp must have 2*n words */ diff --git a/crypto/bn/old/bn_wmul.c b/crypto/bn/old/bn_wmul.c index a467b2f17a..3b484adf70 100644 --- a/crypto/bn/old/bn_wmul.c +++ b/crypto/bn/old/bn_wmul.c @@ -17,6 +17,7 @@ printf("bn_mull %d * %d\n",a->top,b->top); bn_check_top(a); bn_check_top(b); bn_check_top(r); + BN_CTX_start(ctx); al=a->top; bl=b->top; @@ -85,7 +86,7 @@ symetric: j=BN_num_bits_word((BN_ULONG)al); j=1<<(j-1); k=j+j; - t= &(ctx->bn[ctx->tos]); + t = BN_CTX_get(ctx); if (al == j) /* exact multiple */ { bn_wexpand(t,k*2); @@ -107,6 +108,7 @@ symetric: r->top=top; } end: + BN_CTX_end(ctx); bn_fix_top(r); return(1); } diff --git a/crypto/dh/dh_gen.c b/crypto/dh/dh_gen.c index f0ee43ed87..7a6a38fbb4 100644 --- a/crypto/dh/dh_gen.c +++ b/crypto/dh/dh_gen.c @@ -95,9 +95,10 @@ DH *DH_generate_parameters(int prime_len, int generator, if (ret == NULL) goto err; ctx=BN_CTX_new(); if (ctx == NULL) goto err; - t1= &(ctx->bn[0]); - t2= &(ctx->bn[1]); - ctx->tos=2; + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t1 == NULL || t2 == NULL) goto err; if (generator == DH_GENERATOR_2) { @@ -138,7 +139,11 @@ err: ok=0; } - if (ctx != NULL) BN_CTX_free(ctx); + if (ctx != NULL) + { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } if (!ok && (ret != NULL)) { DH_free(ret); diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c index 4e6a0fc0ef..0c7eeaf260 100644 --- a/crypto/dh/dh_key.c +++ b/crypto/dh/dh_key.c @@ -161,7 +161,8 @@ static int compute_key(unsigned char *key, BIGNUM *pub_key, DH *dh) int ret= -1; BN_CTX_init(&ctx); - tmp= &(ctx.bn[ctx.tos++]); + BN_CTX_start(&ctx); + tmp = BN_CTX_get(&ctx); if (dh->priv_key == NULL) { @@ -184,6 +185,7 @@ static int compute_key(unsigned char *key, BIGNUM *pub_key, DH *dh) ret=BN_bn2bin(tmp,key); err: + BN_CTX_end(&ctx); BN_CTX_free(&ctx); return(ret); } diff --git a/crypto/dsa/dsa_gen.c b/crypto/dsa/dsa_gen.c index 65602dda77..2294a362d9 100644 --- a/crypto/dsa/dsa_gen.c +++ b/crypto/dsa/dsa_gen.c @@ -116,14 +116,15 @@ DSA *DSA_generate_parameters(int bits, unsigned char *seed_in, int seed_len, if ((mont=BN_MONT_CTX_new()) == NULL) goto err; - r0= &(ctx2->bn[0]); - g= &(ctx2->bn[1]); - W= &(ctx2->bn[2]); - q= &(ctx2->bn[3]); - X= &(ctx2->bn[4]); - c= &(ctx2->bn[5]); - p= &(ctx2->bn[6]); - test= &(ctx2->bn[7]); + BN_CTX_start(ctx2); + r0 = BN_CTX_get(ctx2); + g = BN_CTX_get(ctx2); + W = BN_CTX_get(ctx2); + q = BN_CTX_get(ctx2); + X = BN_CTX_get(ctx2); + c = BN_CTX_get(ctx2); + p = BN_CTX_get(ctx2); + test = BN_CTX_get(ctx2); BN_lshift(test,BN_value_one(),bits-1); @@ -168,8 +169,6 @@ DSA *DSA_generate_parameters(int bits, unsigned char *seed_in, int seed_len, /* step 4 */ r = BN_is_prime_fasttest(q, DSS_prime_checks, callback, ctx3, cb_arg, seed_is_random); - if (ctx3->tos) - goto err; if (r > 0) break; if (r != 0) @@ -283,7 +282,11 @@ err: if (h_ret != NULL) *h_ret=h; } if (ctx != NULL) BN_CTX_free(ctx); - if (ctx2 != NULL) BN_CTX_free(ctx2); + if (ctx2 != NULL) + { + BN_CTX_end(ctx2); + BN_CTX_free(ctx2); + } if (ctx3 != NULL) BN_CTX_free(ctx3); if (mont != NULL) BN_MONT_CTX_free(mont); return(ok?ret:NULL); diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index 3ed6edd6a1..95e636d3f0 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -74,11 +74,12 @@ RSA *RSA_generate_key(int bits, unsigned long e_value, if (ctx == NULL) goto err; ctx2=BN_CTX_new(); if (ctx2 == NULL) goto err; - r0= &(ctx->bn[0]); - r1= &(ctx->bn[1]); - r2= &(ctx->bn[2]); - r3= &(ctx->bn[3]); - ctx->tos+=4; + BN_CTX_start(ctx); + r0 = BN_CTX_get(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + r3 = BN_CTX_get(ctx); + if (r3 == NULL) goto err; bitsp=(bits+1)/2; bitsq=bits-bitsp; @@ -181,6 +182,7 @@ err: RSAerr(RSA_F_RSA_GENERATE_KEY,ERR_LIB_BN); ok=0; } + BN_CTX_end(ctx); BN_CTX_free(ctx); BN_CTX_free(ctx2); diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index c6b1a5989d..074a4f5074 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -269,19 +269,19 @@ int RSA_blinding_on(RSA *rsa, BN_CTX *p_ctx) if (rsa->blinding != NULL) BN_BLINDING_free(rsa->blinding); - A= &(ctx->bn[0]); - ctx->tos++; + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); if (!BN_rand(A,BN_num_bits(rsa->n)-1,1,0)) goto err; if ((Ai=BN_mod_inverse(NULL,A,rsa->n,ctx)) == NULL) goto err; if (!rsa->meth->bn_mod_exp(A,A,rsa->e,rsa->n,ctx,rsa->_method_mod_n)) goto err; rsa->blinding=BN_BLINDING_new(A,Ai,rsa->n); - ctx->tos--; rsa->flags|=RSA_FLAG_BLINDING; BN_free(Ai); ret=1; err: + BN_CTX_end(ctx); if (ctx != p_ctx) BN_CTX_free(ctx); return(ret); } diff --git a/doc/crypto/BN_CTX_new.pod b/doc/crypto/BN_CTX_new.pod index 37a188e3c3..2a02da03b9 100644 --- a/doc/crypto/BN_CTX_new.pod +++ b/doc/crypto/BN_CTX_new.pod @@ -38,7 +38,8 @@ BN_CTX_init() and BN_CTX_free() have no return values. =head1 SEE ALSO -L, L, L +L, L, L, +L =head1 HISTORY diff --git a/doc/crypto/BN_CTX_start.pod b/doc/crypto/BN_CTX_start.pod new file mode 100644 index 0000000000..3e1032375f --- /dev/null +++ b/doc/crypto/BN_CTX_start.pod @@ -0,0 +1,49 @@ +=pod + +=head1 NAME + +BN_CTX_start, BN_CTX_get, BN_CTX_end - use temporary BIGNUM variables + +=head1 SYNOPSIS + + #include + + void BN_CTX_start(BN_CTX *ctx); + + BIGNUM *BN_CTX_get(BN_CTX *ctx); + + void BN_CTX_end(BN_CTX *ctx); + +=head1 DESCRIPTION + +These functions are used to obtain temporary B variables from +a B in order to save the overhead of repeatedly creating and +freeing Bs in functions that are called from inside a loop. + +A function must call BN_CTX_start() first. Then, BN_CTX_get() may be +called repeatedly to obtain temporary Bs. All BN_CTX_get() +calls must be made before calling any other functions that use the +B as an argument. + +Finally, BN_CTX_end() must be called before returning from the function. +When BN_CTX_end() is called, the B pointers obtained from +BN_CTX_get() become invalid. + +=head1 RETURN VALUES + +BN_CTX_start() and BN_CTX_end() return no values. + +BN_CTX_get() returns a pointer to the B, or B on error. +Once BN_CTX_get() has failed, the subsequent calls will return B +as well, so it is sufficient to check the return value of the last +BN_CTX_get() call. + +=head1 SEE ALSO + +L + +=head1 HISTORY + +BN_CTX_start(), BN_CTX_get() and BN_CTX_end() were added in OpenSSL 0.9.5. + +=cut diff --git a/doc/crypto/BN_add.pod b/doc/crypto/BN_add.pod index 2f6a3b448f..e4230851e4 100644 --- a/doc/crypto/BN_add.pod +++ b/doc/crypto/BN_add.pod @@ -40,6 +40,7 @@ B may be the same B as B or B. BN_sub() subtracts B from B and places the result in B (C). BN_mul() multiplies B and B and places the result in B (C). +B may be the same B as B or B. For multiplication by powers of 2, use L. BN_div() divides B by B and places the result in B and the -- 2.25.1