sl@0: /* crypto/bn/bn_mont.c */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: /* ==================================================================== sl@0: * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * sl@0: * 1. Redistributions of source code must retain the above copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in sl@0: * the documentation and/or other materials provided with the sl@0: * distribution. sl@0: * sl@0: * 3. All advertising materials mentioning features or use of this sl@0: * software must display the following acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" sl@0: * sl@0: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to sl@0: * endorse or promote products derived from this software without sl@0: * prior written permission. For written permission, please contact sl@0: * openssl-core@openssl.org. sl@0: * sl@0: * 5. Products derived from this software may not be called "OpenSSL" sl@0: * nor may "OpenSSL" appear in their names without prior written sl@0: * permission of the OpenSSL Project. sl@0: * sl@0: * 6. Redistributions of any form whatsoever must retain the following sl@0: * acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit (http://www.openssl.org/)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY sl@0: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR sl@0: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR sl@0: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, sl@0: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT sl@0: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; sl@0: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, sl@0: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) sl@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED sl@0: * OF THE POSSIBILITY OF SUCH DAMAGE. sl@0: * ==================================================================== sl@0: * sl@0: * This product includes cryptographic software written by Eric Young sl@0: * (eay@cryptsoft.com). This product includes software written by Tim sl@0: * Hudson (tjh@cryptsoft.com). sl@0: * sl@0: */ sl@0: sl@0: /* sl@0: * Details about Montgomery multiplication algorithms can be found at sl@0: * http://security.ece.orst.edu/publications.html, e.g. sl@0: * http://security.ece.orst.edu/koc/papers/j37acmon.pdf and sl@0: * sections 3.8 and 4.2 in http://security.ece.orst.edu/koc/papers/r01rsasw.pdf sl@0: */ sl@0: sl@0: #include sl@0: #include "cryptlib.h" sl@0: #include "bn_lcl.h" sl@0: sl@0: #define MONT_WORD /* use the faster word-based algorithm */ sl@0: sl@0: EXPORT_C int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, sl@0: BN_MONT_CTX *mont, BN_CTX *ctx) sl@0: { sl@0: BIGNUM *tmp; sl@0: int ret=0; sl@0: sl@0: BN_CTX_start(ctx); sl@0: tmp = BN_CTX_get(ctx); sl@0: if (tmp == NULL) goto err; sl@0: sl@0: bn_check_top(tmp); sl@0: if (a == b) sl@0: { sl@0: if (!BN_sqr(tmp,a,ctx)) goto err; sl@0: } sl@0: else sl@0: { sl@0: if (!BN_mul(tmp,a,b,ctx)) goto err; sl@0: } sl@0: /* reduce from aRR to aR */ sl@0: if (!BN_from_montgomery(r,tmp,mont,ctx)) goto err; sl@0: bn_check_top(r); sl@0: ret=1; sl@0: err: sl@0: BN_CTX_end(ctx); sl@0: return(ret); sl@0: } sl@0: sl@0: EXPORT_C int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont, sl@0: BN_CTX *ctx) sl@0: { sl@0: int retn=0; sl@0: sl@0: #ifdef MONT_WORD sl@0: BIGNUM *n,*r; sl@0: BN_ULONG *ap,*np,*rp,n0,v,*nrp; sl@0: int al,nl,max,i,x,ri; sl@0: sl@0: BN_CTX_start(ctx); sl@0: if ((r = BN_CTX_get(ctx)) == NULL) goto err; sl@0: sl@0: if (!BN_copy(r,a)) goto err; sl@0: n= &(mont->N); sl@0: sl@0: ap=a->d; sl@0: /* mont->ri is the size of mont->N in bits (rounded up sl@0: to the word size) */ sl@0: al=ri=mont->ri/BN_BITS2; sl@0: sl@0: nl=n->top; sl@0: if ((al == 0) || (nl == 0)) { r->top=0; return(1); } sl@0: sl@0: max=(nl+al+1); /* allow for overflow (no?) XXX */ sl@0: if (bn_wexpand(r,max) == NULL) goto err; sl@0: sl@0: r->neg=a->neg^n->neg; sl@0: np=n->d; sl@0: rp=r->d; sl@0: nrp= &(r->d[nl]); sl@0: sl@0: /* clear the top words of T */ sl@0: #if 1 sl@0: for (i=r->top; id[i]=0; sl@0: #else sl@0: memset(&(r->d[r->top]),0,(max-r->top)*sizeof(BN_ULONG)); sl@0: #endif sl@0: sl@0: r->top=max; sl@0: n0=mont->n0; sl@0: sl@0: #ifdef BN_COUNT sl@0: fprintf(stderr,"word BN_from_montgomery %d * %d\n",nl,nl); sl@0: #endif sl@0: for (i=0; i= v) sl@0: continue; sl@0: else sl@0: { sl@0: if (((++nrp[0])&BN_MASK2) != 0) continue; sl@0: if (((++nrp[1])&BN_MASK2) != 0) continue; sl@0: for (x=2; (((++nrp[x])&BN_MASK2) == 0); x++) ; sl@0: } sl@0: } sl@0: bn_correct_top(r); sl@0: sl@0: /* mont->ri will be a multiple of the word size and below code sl@0: * is kind of BN_rshift(ret,r,mont->ri) equivalent */ sl@0: if (r->top <= ri) sl@0: { sl@0: ret->top=0; sl@0: retn=1; sl@0: goto err; sl@0: } sl@0: al=r->top-ri; sl@0: sl@0: # define BRANCH_FREE 1 sl@0: # if BRANCH_FREE sl@0: if (bn_wexpand(ret,ri) == NULL) goto err; sl@0: x=0-(((al-ri)>>(sizeof(al)*8-1))&1); sl@0: ret->top=x=(ri&~x)|(al&x); /* min(ri,al) */ sl@0: ret->neg=r->neg; sl@0: sl@0: rp=ret->d; sl@0: ap=&(r->d[ri]); sl@0: sl@0: { sl@0: size_t m1,m2; sl@0: sl@0: v=bn_sub_words(rp,ap,np,ri); sl@0: /* this ----------------^^ works even in alri) nrp=rp; else nrp=ap; */ sl@0: /* in other words if subtraction result is real, then sl@0: * trick unconditional memcpy below to perform in-place sl@0: * "refresh" instead of actual copy. */ sl@0: m1=0-(size_t)(((al-ri)>>(sizeof(al)*8-1))&1); /* al>(sizeof(al)*8-1))&1); /* al>ri */ sl@0: m1|=m2; /* (al!=ri) */ sl@0: m1|=(0-(size_t)v); /* (al!=ri || v) */ sl@0: m1&=~m2; /* (al!=ri || v) && !al>ri */ sl@0: nrp=(BN_ULONG *)(((size_t)rp&~m1)|((size_t)ap&m1)); sl@0: } sl@0: sl@0: /* 'itop=al; sl@0: ret->neg=r->neg; sl@0: sl@0: rp=ret->d; sl@0: ap=&(r->d[ri]); sl@0: al-=4; sl@0: for (i=0; iri); sl@0: sl@0: if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err; sl@0: BN_mask_bits(t2,mont->ri); sl@0: sl@0: if (!BN_mul(t1,t2,&mont->N,ctx)) goto err; sl@0: if (!BN_add(t2,a,t1)) goto err; sl@0: if (!BN_rshift(ret,t2,mont->ri)) goto err; sl@0: #endif /* MONT_WORD */ sl@0: sl@0: #if !defined(BRANCH_FREE) || BRANCH_FREE==0 sl@0: if (BN_ucmp(ret, &(mont->N)) >= 0) sl@0: { sl@0: if (!BN_usub(ret,ret,&(mont->N))) goto err; sl@0: } sl@0: #endif sl@0: retn=1; sl@0: bn_check_top(ret); sl@0: err: sl@0: BN_CTX_end(ctx); sl@0: return(retn); sl@0: } sl@0: sl@0: EXPORT_C BN_MONT_CTX *BN_MONT_CTX_new(void) sl@0: { sl@0: BN_MONT_CTX *ret; sl@0: sl@0: if ((ret=(BN_MONT_CTX *)OPENSSL_malloc(sizeof(BN_MONT_CTX))) == NULL) sl@0: return(NULL); sl@0: sl@0: BN_MONT_CTX_init(ret); sl@0: ret->flags=BN_FLG_MALLOCED; sl@0: return(ret); sl@0: } sl@0: sl@0: EXPORT_C void BN_MONT_CTX_init(BN_MONT_CTX *ctx) sl@0: { sl@0: ctx->ri=0; sl@0: BN_init(&(ctx->RR)); sl@0: BN_init(&(ctx->N)); sl@0: BN_init(&(ctx->Ni)); sl@0: ctx->flags=0; sl@0: } sl@0: sl@0: EXPORT_C void BN_MONT_CTX_free(BN_MONT_CTX *mont) sl@0: { sl@0: if(mont == NULL) sl@0: return; sl@0: sl@0: BN_free(&(mont->RR)); sl@0: BN_free(&(mont->N)); sl@0: BN_free(&(mont->Ni)); sl@0: if (mont->flags & BN_FLG_MALLOCED) sl@0: OPENSSL_free(mont); sl@0: } sl@0: sl@0: EXPORT_C int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) sl@0: { sl@0: int ret = 0; sl@0: BIGNUM *Ri,*R; sl@0: sl@0: BN_CTX_start(ctx); sl@0: if((Ri = BN_CTX_get(ctx)) == NULL) goto err; sl@0: R= &(mont->RR); /* grab RR as a temp */ sl@0: if (!BN_copy(&(mont->N),mod)) goto err; /* Set N */ sl@0: mont->N.neg = 0; sl@0: sl@0: #ifdef MONT_WORD sl@0: { sl@0: BIGNUM tmod; sl@0: BN_ULONG buf[2]; sl@0: sl@0: mont->ri=(BN_num_bits(mod)+(BN_BITS2-1))/BN_BITS2*BN_BITS2; sl@0: BN_zero(R); sl@0: if (!(BN_set_bit(R,BN_BITS2))) goto err; /* R */ sl@0: sl@0: buf[0]=mod->d[0]; /* tmod = N mod word size */ sl@0: buf[1]=0; sl@0: tmod.d=buf; sl@0: tmod.top = buf[0] != 0 ? 1 : 0; sl@0: tmod.dmax=2; sl@0: tmod.neg=0; sl@0: /* Ri = R^-1 mod N*/ sl@0: if ((BN_mod_inverse(Ri,R,&tmod,ctx)) == NULL) sl@0: goto err; sl@0: if (!BN_lshift(Ri,Ri,BN_BITS2)) goto err; /* R*Ri */ sl@0: if (!BN_is_zero(Ri)) sl@0: { sl@0: if (!BN_sub_word(Ri,1)) goto err; sl@0: } sl@0: else /* if N mod word size == 1 */ sl@0: { sl@0: if (!BN_set_word(Ri,BN_MASK2)) goto err; /* Ri-- (mod word size) */ sl@0: } sl@0: if (!BN_div(Ri,NULL,Ri,&tmod,ctx)) goto err; sl@0: /* Ni = (R*Ri-1)/N, sl@0: * keep only least significant word: */ sl@0: mont->n0 = (Ri->top > 0) ? Ri->d[0] : 0; sl@0: } sl@0: #else /* !MONT_WORD */ sl@0: { /* bignum version */ sl@0: mont->ri=BN_num_bits(&mont->N); sl@0: BN_zero(R); sl@0: if (!BN_set_bit(R,mont->ri)) goto err; /* R = 2^ri */ sl@0: /* Ri = R^-1 mod N*/ sl@0: if ((BN_mod_inverse(Ri,R,&mont->N,ctx)) == NULL) sl@0: goto err; sl@0: if (!BN_lshift(Ri,Ri,mont->ri)) goto err; /* R*Ri */ sl@0: if (!BN_sub_word(Ri,1)) goto err; sl@0: /* Ni = (R*Ri-1) / N */ sl@0: if (!BN_div(&(mont->Ni),NULL,Ri,&mont->N,ctx)) goto err; sl@0: } sl@0: #endif sl@0: sl@0: /* setup RR for conversions */ sl@0: BN_zero(&(mont->RR)); sl@0: if (!BN_set_bit(&(mont->RR),mont->ri*2)) goto err; sl@0: if (!BN_mod(&(mont->RR),&(mont->RR),&(mont->N),ctx)) goto err; sl@0: sl@0: ret = 1; sl@0: err: sl@0: BN_CTX_end(ctx); sl@0: return ret; sl@0: } sl@0: sl@0: EXPORT_C BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from) sl@0: { sl@0: if (to == from) return(to); sl@0: sl@0: if (!BN_copy(&(to->RR),&(from->RR))) return NULL; sl@0: if (!BN_copy(&(to->N),&(from->N))) return NULL; sl@0: if (!BN_copy(&(to->Ni),&(from->Ni))) return NULL; sl@0: to->ri=from->ri; sl@0: to->n0=from->n0; sl@0: return(to); sl@0: } sl@0: sl@0: EXPORT_C BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock, sl@0: const BIGNUM *mod, BN_CTX *ctx) sl@0: { sl@0: int got_write_lock = 0; sl@0: BN_MONT_CTX *ret; sl@0: sl@0: CRYPTO_r_lock(lock); sl@0: if (!*pmont) sl@0: { sl@0: CRYPTO_r_unlock(lock); sl@0: CRYPTO_w_lock(lock); sl@0: got_write_lock = 1; sl@0: sl@0: if (!*pmont) sl@0: { sl@0: ret = BN_MONT_CTX_new(); sl@0: if (ret && !BN_MONT_CTX_set(ret, mod, ctx)) sl@0: BN_MONT_CTX_free(ret); sl@0: else sl@0: *pmont = ret; sl@0: } sl@0: } sl@0: sl@0: ret = *pmont; sl@0: sl@0: if (got_write_lock) sl@0: CRYPTO_w_unlock(lock); sl@0: else sl@0: CRYPTO_r_unlock(lock); sl@0: sl@0: return ret; sl@0: }