1 /* crypto/bn/bn_recp.c */
   2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
   3  * All rights reserved.
   4  *
   5  * This package is an SSL implementation written
   6  * by Eric Young (eay@cryptsoft.com).
   7  * The implementation was written so as to conform with Netscapes SSL.
   8  *
   9  * This library is free for commercial and non-commercial use as long as
  10  * the following conditions are aheared to.  The following conditions
  11  * apply to all code found in this distribution, be it the RC4, RSA,
  12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
  13  * included with this distribution is covered by the same copyright terms
  14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
  15  *
  16  * Copyright remains Eric Young's, and as such any Copyright notices in
  17  * the code are not to be removed.
  18  * If this package is used in a product, Eric Young should be given attribution
  19  * as the author of the parts of the library used.
  20  * This can be in the form of a textual message at program startup or
  21  * in documentation (online or textual) provided with the package.
  22  *
  23  * Redistribution and use in source and binary forms, with or without
  24  * modification, are permitted provided that the following conditions
  25  * are met:
  26  * 1. Redistributions of source code must retain the copyright
  27  *    notice, this list of conditions and the following disclaimer.
  28  * 2. Redistributions in binary form must reproduce the above copyright
  29  *    notice, this list of conditions and the following disclaimer in the
  30  *    documentation and/or other materials provided with the distribution.
  31  * 3. All advertising materials mentioning features or use of this software
  32  *    must display the following acknowledgement:
  33  *    "This product includes cryptographic software written by
  34  *     Eric Young (eay@cryptsoft.com)"
  35  *    The word 'cryptographic' can be left out if the rouines from the library
  36  *    being used are not cryptographic related :-).
  37  * 4. If you include any Windows specific code (or a derivative thereof) from
  38  *    the apps directory (application code) you must include an acknowledgement:
  39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
  40  *
  41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
  42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  51  * SUCH DAMAGE.
  52  *
  53  * The licence and distribution terms for any publically available version or
  54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
  55  * copied and put under another distribution licence
  56  * [including the GNU Public Licence.]
  57  */
  58 
  59 #include <stdio.h>
  60 #include "cryptlib.h"
  61 #include "bn_lcl.h"
  62 
  63 void BN_RECP_CTX_init(BN_RECP_CTX *recp)
  64         {
  65         BN_init(&(recp->N));
  66         BN_init(&(recp->Nr));
  67         recp->num_bits=0;
  68         recp->flags=0;
  69         }
  70 
  71 BN_RECP_CTX *BN_RECP_CTX_new(void)
  72         {
  73         BN_RECP_CTX *ret;
  74 
  75         if ((ret=(BN_RECP_CTX *)OPENSSL_malloc(sizeof(BN_RECP_CTX))) == NULL)
  76                 return(NULL);
  77 
  78         BN_RECP_CTX_init(ret);
  79         ret->flags=BN_FLG_MALLOCED;
  80         return(ret);
  81         }
  82 
  83 void BN_RECP_CTX_free(BN_RECP_CTX *recp)
  84         {
  85         if(recp == NULL)
  86             return;
  87 
  88         BN_free(&(recp->N));
  89         BN_free(&(recp->Nr));
  90         if (recp->flags & BN_FLG_MALLOCED)
  91                 OPENSSL_free(recp);
  92         }
  93 
  94 int BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *d, BN_CTX *ctx)
  95         {
  96         if (!BN_copy(&(recp->N),d)) return 0;
  97         BN_zero(&(recp->Nr));
  98         recp->num_bits=BN_num_bits(d);
  99         recp->shift=0;
 100         return(1);
 101         }
 102 
 103 int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
 104         BN_RECP_CTX *recp, BN_CTX *ctx)
 105         {
 106         int ret=0;
 107         BIGNUM *a;
 108         const BIGNUM *ca;
 109 
 110         BN_CTX_start(ctx);
 111         if ((a = BN_CTX_get(ctx)) == NULL) goto err;
 112         if (y != NULL)
 113                 {
 114                 if (x == y)
 115                         { if (!BN_sqr(a,x,ctx)) goto err; }
 116                 else
 117                         { if (!BN_mul(a,x,y,ctx)) goto err; }
 118                 ca = a;
 119                 }
 120         else
 121                 ca=x; /* Just do the mod */
 122 
 123         ret = BN_div_recp(NULL,r,ca,recp,ctx);
 124 err:
 125         BN_CTX_end(ctx);
 126         bn_check_top(r);
 127         return(ret);
 128         }
 129 
 130 int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m,
 131         BN_RECP_CTX *recp, BN_CTX *ctx)
 132         {
 133         int i,j,ret=0;
 134         BIGNUM *a,*b,*d,*r;
 135 
 136         BN_CTX_start(ctx);
 137         a=BN_CTX_get(ctx);
 138         b=BN_CTX_get(ctx);
 139         if (dv != NULL)
 140                 d=dv;
 141         else
 142                 d=BN_CTX_get(ctx);
 143         if (rem != NULL)
 144                 r=rem;
 145         else
 146                 r=BN_CTX_get(ctx);
 147         if (a == NULL || b == NULL || d == NULL || r == NULL) goto err;
 148 
 149         if (BN_ucmp(m,&(recp->N)) < 0)
 150                 {
 151                 BN_zero(d);
 152                 if (!BN_copy(r,m)) return 0;
 153                 BN_CTX_end(ctx);
 154                 return(1);
 155                 }
 156 
 157         /* We want the remainder
 158          * Given input of ABCDEF / ab
 159          * we need multiply ABCDEF by 3 digests of the reciprocal of ab
 160          *
 161          */
 162 
 163         /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */
 164         i=BN_num_bits(m);
 165         j=recp->num_bits<<1;
 166         if (j>i) i=j;
 167 
 168         /* Nr := round(2^i / N) */
 169         if (i != recp->shift)
 170                 recp->shift=BN_reciprocal(&(recp->Nr),&(recp->N),
 171                         i,ctx); /* BN_reciprocal returns i, or -1 for an error */
 172         if (recp->shift == -1) goto err;
 173 
 174         /* d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - BN_num_bits(N)))|
 175          *    = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - BN_num_bits(N)))|
 176          *   <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)|
 177          *    = |m/N|
 178          */
 179         if (!BN_rshift(a,m,recp->num_bits)) goto err;
 180         if (!BN_mul(b,a,&(recp->Nr),ctx)) goto err;
 181         if (!BN_rshift(d,b,i-recp->num_bits)) goto err;
 182         d->neg=0;
 183 
 184         if (!BN_mul(b,&(recp->N),d,ctx)) goto err;
 185         if (!BN_usub(r,m,b)) goto err;
 186         r->neg=0;
 187 
 188 #if 1
 189         j=0;
 190         while (BN_ucmp(r,&(recp->N)) >= 0)
 191                 {
 192                 if (j++ > 2)
 193                         {
 194                         BNerr(BN_F_BN_DIV_RECP,BN_R_BAD_RECIPROCAL);
 195                         goto err;
 196                         }
 197                 if (!BN_usub(r,r,&(recp->N))) goto err;
 198                 if (!BN_add_word(d,1)) goto err;
 199                 }
 200 #endif
 201 
 202         r->neg=BN_is_zero(r)?0:m->neg;
 203         d->neg=m->neg^recp->N.neg;
 204         ret=1;
 205 err:
 206         BN_CTX_end(ctx);
 207         bn_check_top(dv);
 208         bn_check_top(rem);
 209         return(ret);
 210         }
 211 
 212 /* len is the expected size of the result
 213  * We actually calculate with an extra word of precision, so
 214  * we can do faster division if the remainder is not required.
 215  */
 216 /* r := 2^len / m */
 217 int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx)
 218         {
 219         int ret= -1;
 220         BIGNUM *t;
 221 
 222         BN_CTX_start(ctx);
 223         if((t = BN_CTX_get(ctx)) == NULL) goto err;
 224 
 225         if (!BN_set_bit(t,len)) goto err;
 226 
 227         if (!BN_div(r,NULL,t,m,ctx)) goto err;
 228 
 229         ret=len;
 230 err:
 231         bn_check_top(r);
 232         BN_CTX_end(ctx);
 233         return(ret);
 234         }