X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=crypto%2Fbn%2Fbn_gcd.c;h=ea6816a43fc32a6deb82a68f3fb552e3bf19fb0c;hb=077ff61eefeb9090bc135984df19b52da3032c29;hp=071bba3b4b3a0521359682c21e69e94e8d4f6f05;hpb=78414a6a897db42c9bcf06aa21c705811ab33921;p=oweals%2Fopenssl.git diff --git a/crypto/bn/bn_gcd.c b/crypto/bn/bn_gcd.c index 071bba3b4b..ea6816a43f 100644 --- a/crypto/bn/bn_gcd.c +++ b/crypto/bn/bn_gcd.c @@ -55,29 +55,82 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ +/* ==================================================================== + * 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 "cryptlib.h" #include "bn_lcl.h" -#ifndef NOPROTO static BIGNUM *euclid(BIGNUM *a, BIGNUM *b); -#else -static BIGNUM *euclid(); -#endif -int BN_gcd(r,in_a,in_b,ctx) -BIGNUM *r,*in_a,*in_b; -BN_CTX *ctx; +int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx) { BIGNUM *a,*b,*t; int ret=0; - a=ctx->bn[ctx->tos]; - b=ctx->bn[ctx->tos+1]; + bn_check_top(in_a); + bn_check_top(in_b); + + 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; + a->neg = 0; + b->neg = 0; if (BN_cmp(a,b) < 0) { t=a; a=b; b=t; } t=euclid(a,b); @@ -86,19 +139,22 @@ BN_CTX *ctx; if (BN_copy(r,t) == NULL) goto err; ret=1; err: + BN_CTX_end(ctx); return(ret); } -static BIGNUM *euclid(a,b) -BIGNUM *a,*b; +static BIGNUM *euclid(BIGNUM *a, BIGNUM *b) { BIGNUM *t; int shifts=0; - for (;;) + bn_check_top(a); + bn_check_top(b); + + /* 0 <= b <= a */ + while (!BN_is_zero(b)) { - if (BN_is_zero(b)) - break; + /* 0 < b <= a */ if (BN_is_odd(a)) { @@ -131,7 +187,9 @@ BIGNUM *a,*b; shifts++; } } + /* 0 <= b <= a */ } + if (shifts) { if (!BN_lshift(a,a,shifts)) goto err; @@ -141,54 +199,121 @@ err: return(NULL); } + /* solves ax == 1 (mod n) */ -BIGNUM *BN_mod_inverse(a, n, ctx) -BIGNUM *a; -BIGNUM *n; -BN_CTX *ctx; +BIGNUM *BN_mod_inverse(BIGNUM *in, + const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) { - BIGNUM *A,*B,*X,*Y,*M,*D,*R; - BIGNUM *ret=NULL,*T; + BIGNUM *A,*B,*X,*Y,*M,*D,*R=NULL; + BIGNUM *ret=NULL; int sign; - 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; - R=BN_new(); + bn_check_top(a); + bn_check_top(n); + + 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 + R=in; if (R == NULL) goto err; - BN_zero(X); - BN_one(Y); - if (BN_copy(A,a) == NULL) goto err; - if (BN_copy(B,n) == NULL) goto err; - sign=1; + BN_one(X); + BN_zero(Y); + if (BN_copy(B,a) == NULL) goto err; + if (BN_copy(A,n) == NULL) goto err; + A->neg = 0; + if (B->neg || (BN_ucmp(B, A) >= 0)) + { + if (!BN_nnmod(B, B, A, ctx)) goto err; + } + sign = -1; + /* From B = a mod |n|, A = |n| it follows that + * + * 0 <= B < A, + * X*a == B (mod |n|), + * -sign*Y*a == A (mod |n|). + */ while (!BN_is_zero(B)) { + BIGNUM *tmp; + + /* + * 0 < B < A, + * (*) X*a == B (mod |n|), + * -sign*Y*a == A (mod |n|) + */ + if (!BN_div(D,M,A,B,ctx)) goto err; - T=A; + /* Now + * A = D*B + M; + * thus we have + * (**) -sign*Y*a == D*B + M (mod |n|). + */ + + tmp=A; /* keep the BIGNUM object, the value does not matter */ + + /* (A, B) := (B, A mod B) ... */ A=B; B=M; - /* T has a struct, M does not */ + /* ... so we have 0 <= B < A again */ + + /* Since the former M is now B and the former B is now A, + * (**) translates into + * -sign*Y*a == D*A + B (mod |n|), + * i.e. + * -sign*Y*a - D*A == B (mod |n|). + * Similarly, (*) translates into + * X*a == A (mod |n|). + * + * Thus, + * -sign*Y*a - D*X*a == B (mod |n|), + * i.e. + * -sign*(Y + D*X)*a == B (mod |n|). + * + * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at + * X*a == B (mod |n|), + * -sign*Y*a == A (mod |n|). + * Note that X and Y stay non-negative all the time. + */ - if (!BN_mul(T,D,X)) goto err; - if (!BN_add(T,T,Y)) goto err; - M=Y; + if (!BN_mul(tmp,D,X,ctx)) goto err; + if (!BN_add(tmp,tmp,Y)) goto err; + M=Y; /* keep the BIGNUM object, the value does not matter */ Y=X; - X=T; - sign= -sign; + X=tmp; + sign = -sign; } + + /* + * The while loop ends when + * A == gcd(a,n); + * we have + * -sign*Y*a == A (mod |n|), + * where Y is non-negative. + */ + if (sign < 0) { if (!BN_sub(Y,n,Y)) goto err; } + /* Now Y*a == A (mod |n|). */ + if (BN_is_one(A)) - { if (!BN_mod(R,Y,n,ctx)) goto err; } + { + /* Y*a == 1 (mod |n|) */ + if (!BN_mod(R,Y,n,ctx)) goto err; + } else { BNerr(BN_F_BN_MOD_INVERSE,BN_R_NO_INVERSE); @@ -196,8 +321,8 @@ BN_CTX *ctx; } ret=R; err: - if ((ret == NULL) && (R != NULL)) BN_free(R); - ctx->tos-=6; + if ((ret == NULL) && (in == NULL)) BN_free(R); + BN_CTX_end(ctx); return(ret); }