Ejemplo n.º 1
0
/* tnX may not be negative but less than n */
static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
                                  int tna, int tnb, BN_ULONG *t) {
  int i, j, n2 = n * 2;
  int c1, c2, neg;
  BN_ULONG ln, lo, *p;

  if (n < 8) {
    bn_mul_normal(r, a, n + tna, b, n + tnb);
    return;
  }

  /* r=(a[0]-a[1])*(b[1]-b[0]) */
  c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
  c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
  neg = 0;
  switch (c1 * 3 + c2) {
    case -4:
      bn_sub_part_words(t, &(a[n]), a, tna, tna - n);       /* - */
      bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
      break;
    case -3:
    /* break; */
    case -2:
      bn_sub_part_words(t, &(a[n]), a, tna, tna - n);       /* - */
      bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
      neg = 1;
      break;
    case -1:
    case 0:
    case 1:
    /* break; */
    case 2:
      bn_sub_part_words(t, a, &(a[n]), tna, n - tna);       /* + */
      bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
      neg = 1;
      break;
    case 3:
    /* break; */
    case 4:
      bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
      bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
      break;
  }

  if (n == 8) {
    bn_mul_comba8(&(t[n2]), t, &(t[n]));
    bn_mul_comba8(r, a, b);
    bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
    memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
  } else {
    p = &(t[n2 * 2]);
    bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
    bn_mul_recursive(r, a, b, n, 0, 0, p);
    i = n / 2;
    /* If there is only a bottom half to the number,
     * just do it */
    if (tna > tnb) {
      j = tna - i;
    } else {
      j = tnb - i;
    }

    if (j == 0) {
      bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
      memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2));
    } else if (j > 0) {
      /* eg, n == 16, i == 8 and tn == 11 */
      bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
      memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
    } else {
      /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
      memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2);
      if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL &&
          tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
        bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
      } else {
        for (;;) {
          i /= 2;
          /* these simplified conditions work
           * exclusively because difference
           * between tna and tnb is 1 or 0 */
          if (i < tna || i < tnb) {
            bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i,
                                  tnb - i, p);
            break;
          } else if (i == tna || i == tnb) {
            bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i,
                             p);
            break;
          }
        }
      }
    }
  }

  /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
   * r[10] holds (a[0]*b[0])
   * r[32] holds (b[1]*b[1])
   */

  c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));

  if (neg) {
    /* if t[32] is negative */
    c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
  } else {
    /* Might have a carry */
    c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
  }

  /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
   * r[10] holds (a[0]*b[0])
   * r[32] holds (b[1]*b[1])
   * c1 holds the carry bits */
  c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
  if (c1) {
    p = &(r[n + n2]);
    lo = *p;
    ln = (lo + c1) & BN_MASK2;
    *p = ln;

    /* The overflow will stop before we over write
     * words we should not overwrite */
    if (ln < (BN_ULONG)c1) {
      do {
        p++;
        lo = *p;
        ln = (lo + 1) & BN_MASK2;
        *p = ln;
      } while (ln == 0);
    }
  }
}
Ejemplo n.º 2
0
Archivo: bn_sqr.c Proyecto: 274914765/C
/* r is 2*n words in size,
 * a and b are both n words in size.    (There's not actually a 'b' here ...)
 * n must be a power of 2.
 * We multiply and return the result.
 * t must be 2*n words in size
 * We calculate
 * a[0]*b[0]
 * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
 * a[1]*b[1]
 */
void bn_sqr_recursive (BN_ULONG * r, const BN_ULONG * a, int n2, BN_ULONG * t)
{
    int n = n2 / 2;

    int zero, c1;

    BN_ULONG ln, lo, *p;

#ifdef BN_COUNT
    fprintf (stderr, " bn_sqr_recursive %d * %d\n", n2, n2);
#endif
    if (n2 == 4)
    {
#ifndef BN_SQR_COMBA
        bn_sqr_normal (r, a, 4, t);
#else
        bn_sqr_comba4 (r, a);
#endif
        return;
    }
    else if (n2 == 8)
    {
#ifndef BN_SQR_COMBA
        bn_sqr_normal (r, a, 8, t);
#else
        bn_sqr_comba8 (r, a);
#endif
        return;
    }
    if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL)
    {
        bn_sqr_normal (r, a, n2, t);
        return;
    }
    /* r=(a[0]-a[1])*(a[1]-a[0]) */
    c1 = bn_cmp_words (a, &(a[n]), n);
    zero = 0;
    if (c1 > 0)
        bn_sub_words (t, a, &(a[n]), n);
    else if (c1 < 0)
        bn_sub_words (t, &(a[n]), a, n);
    else
        zero = 1;

    /* The result will always be negative unless it is zero */
    p = &(t[n2 * 2]);

    if (!zero)
        bn_sqr_recursive (&(t[n2]), t, n, p);
    else
        memset (&(t[n2]), 0, n2 * sizeof (BN_ULONG));
    bn_sqr_recursive (r, a, n, p);
    bn_sqr_recursive (&(r[n2]), &(a[n]), n, p);

    /* t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
     * r[10] holds (a[0]*b[0])
     * r[32] holds (b[1]*b[1])
     */

    c1 = (int) (bn_add_words (t, r, &(r[n2]), n2));

    /* t[32] is negative */
    c1 -= (int) (bn_sub_words (&(t[n2]), t, &(t[n2]), n2));

    /* t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
     * r[10] holds (a[0]*a[0])
     * r[32] holds (a[1]*a[1])
     * c1 holds the carry bits
     */
    c1 += (int) (bn_add_words (&(r[n]), &(r[n]), &(t[n2]), n2));
    if (c1)
    {
        p = &(r[n + n2]);
        lo = *p;
        ln = (lo + c1) & BN_MASK2;
        *p = ln;

        /* The overflow will stop before we over write
         * words we should not overwrite */
        if (ln < (BN_ULONG) c1)
        {
            do
            {
                p++;
                lo = *p;
                ln = (lo + 1) & BN_MASK2;
                *p = ln;
            }
            while (ln == 0);
        }
    }
}
Ejemplo n.º 3
0
/* BN_div computes  dv := num / divisor,  rounding towards zero, and sets up
 * rm  such that  dv*divisor + rm = num  holds.
 * Thus:
 *     dv->neg == num->neg ^ divisor->neg  (unless the result is zero)
 *     rm->neg == num->neg                 (unless the remainder is zero)
 * If 'dv' or 'rm' is NULL, the respective value is not returned.
 */
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
	   BN_CTX *ctx)
	{
	int norm_shift,i,loop;
	BIGNUM *tmp,wnum,*snum,*sdiv,*res;
	BN_ULONG *resp,*wnump;
	BN_ULONG d0,d1;
	int num_n,div_n;

	bn_check_top(dv);
	bn_check_top(rm);
	bn_check_top(num);
	bn_check_top(divisor);

	if (BN_is_zero(divisor))
		{
/*Begin: comment out , 17Aug2006, Chris */
#if 0
		BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO);
#endif
/*End: comment out , 17Aug2006, Chris */
		return(0);
		}

	if (BN_ucmp(num,divisor) < 0)
		{
		if (rm != NULL)
			{ if (BN_copy(rm,num) == NULL) return(0); }
		if (dv != NULL) BN_zero(dv);
		return(1);
		}

	BN_CTX_start(ctx);
	tmp=BN_CTX_get(ctx);
	snum=BN_CTX_get(ctx);
	sdiv=BN_CTX_get(ctx);
	if (dv == NULL)
		res=BN_CTX_get(ctx);
	else	res=dv;
	if (sdiv == NULL || res == NULL) goto err;

	/* First we normalise the numbers */
	norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2);
	if (!(BN_lshift(sdiv,divisor,norm_shift))) goto err;
	sdiv->neg=0;
	norm_shift+=BN_BITS2;
	if (!(BN_lshift(snum,num,norm_shift))) goto err;
	snum->neg=0;
	div_n=sdiv->top;
	num_n=snum->top;
	loop=num_n-div_n;
	/* Lets setup a 'window' into snum
	 * This is the part that corresponds to the current
	 * 'area' being divided */
	wnum.neg   = 0;
	wnum.d     = &(snum->d[loop]);
	wnum.top   = div_n;
	/* only needed when BN_ucmp messes up the values between top and max */
	wnum.dmax  = snum->dmax - loop; /* so we don't step out of bounds */

	/* Get the top 2 words of sdiv */
	/* div_n=sdiv->top; */
	d0=sdiv->d[div_n-1];
	d1=(div_n == 1)?0:sdiv->d[div_n-2];

	/* pointer to the 'top' of snum */
	wnump= &(snum->d[num_n-1]);

	/* Setup to 'res' */
	res->neg= (num->neg^divisor->neg);
	if (!bn_wexpand(res,(loop+1))) goto err;
	res->top=loop;
	resp= &(res->d[loop-1]);

	/* space for temp */
	if (!bn_wexpand(tmp,(div_n+1))) goto err;

	if (BN_ucmp(&wnum,sdiv) >= 0)
		{
		/* If BN_DEBUG_RAND is defined BN_ucmp changes (via
		 * bn_pollute) the const bignum arguments =>
		 * clean the values between top and max again */
		bn_clear_top2max(&wnum);
		bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n);
		*resp=1;
		}
	else
		res->top--;
	/* if res->top == 0 then clear the neg value otherwise decrease
	 * the resp pointer */
	if (res->top == 0)
		res->neg = 0;
	else
		resp--;

	for (i=0; i<loop-1; i++, wnump--, resp--)
		{
		BN_ULONG q,l0;
		/* the first part of the loop uses the top two words of
		 * snum and sdiv to calculate a BN_ULONG q such that
		 * | wnum - sdiv * q | < sdiv */
#if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM)
		BN_ULONG bn_div_3_words(BN_ULONG*,BN_ULONG,BN_ULONG);
		q=bn_div_3_words(wnump,d1,d0);
#else
		BN_ULONG n0,n1,rem=0;

		n0=wnump[0];
		n1=wnump[-1];
		if (n0 == d0)
			q=BN_MASK2;
		else 			/* n0 < d0 */
			{
#ifdef BN_LLONG
			BN_ULLONG t2;

#if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
			q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0);
#else
			q=bn_div_words(n0,n1,d0);
#ifdef BN_DEBUG_LEVITTE
			fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\
X) -> 0x%08X\n",
				n0, n1, d0, q);
#endif
#endif

#ifndef REMAINDER_IS_ALREADY_CALCULATED
			/*
			 * rem doesn't have to be BN_ULLONG. The least we
			 * know it's less that d0, isn't it?
			 */
			rem=(n1-q*d0)&BN_MASK2;
#endif
			t2=(BN_ULLONG)d1*q;

			for (;;)
				{
				if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2]))
					break;
				q--;
				rem += d0;
				if (rem < d0) break; /* don't let rem overflow */
				t2 -= d1;
				}
#else /* !BN_LLONG */
			BN_ULONG t2l,t2h,ql,qh;

			q=bn_div_words(n0,n1,d0);
#ifdef BN_DEBUG_LEVITTE
			fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\
X) -> 0x%08X\n",
				n0, n1, d0, q);
#endif
#ifndef REMAINDER_IS_ALREADY_CALCULATED
			rem=(n1-q*d0)&BN_MASK2;
#endif

#if defined(BN_UMULT_LOHI)
			BN_UMULT_LOHI(t2l,t2h,d1,q);
#elif defined(BN_UMULT_HIGH)
			t2l = d1 * q;
			t2h = BN_UMULT_HIGH(d1,q);
#else
			t2l=LBITS(d1); t2h=HBITS(d1);
			ql =LBITS(q);  qh =HBITS(q);
			mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */
#endif

			for (;;)
				{
				if ((t2h < rem) ||
					((t2h == rem) && (t2l <= wnump[-2])))
					break;
				q--;
				rem += d0;
				if (rem < d0) break; /* don't let rem overflow */
				if (t2l < d1) t2h--; t2l -= d1;
				}
#endif /* !BN_LLONG */
			}
#endif /* !BN_DIV3W */

		l0=bn_mul_words(tmp->d,sdiv->d,div_n,q);
		tmp->d[div_n]=l0;
		wnum.d--;
		/* ingore top values of the bignums just sub the two 
		 * BN_ULONG arrays with bn_sub_words */
		if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n+1))
			{
			/* Note: As we have considered only the leading
			 * two BN_ULONGs in the calculation of q, sdiv * q
			 * might be greater than wnum (but then (q-1) * sdiv
			 * is less or equal than wnum)
			 */
			q--;
			if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n))
				/* we can't have an overflow here (assuming
				 * that q != 0, but if q == 0 then tmp is
				 * zero anyway) */
				(*wnump)++;
			}
		/* store part of the result */
		*resp = q;
		}
	bn_correct_top(snum);
	if (rm != NULL)
		{
		/* Keep a copy of the neg flag in num because if rm==num
		 * BN_rshift() will overwrite it.
		 */
		int neg = num->neg;
		BN_rshift(rm,snum,norm_shift);
		if (!BN_is_zero(rm))
			rm->neg = neg;
		bn_check_top(rm);
		}
	BN_CTX_end(ctx);
	return(1);
err:
	bn_check_top(rm);
	BN_CTX_end(ctx);
	return(0);
	}
Ejemplo n.º 4
0
/* dnX may not be positive, but n2/2+dnX has to be */
static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
                             int dna, int dnb, BN_ULONG *t) {
  int n = n2 / 2, c1, c2;
  int tna = n + dna, tnb = n + dnb;
  unsigned int neg, zero;
  BN_ULONG ln, lo, *p;

  /* Only call bn_mul_comba 8 if n2 == 8 and the
   * two arrays are complete [steve]
   */
  if (n2 == 8 && dna == 0 && dnb == 0) {
    bn_mul_comba8(r, a, b);
    return;
  }

  /* Else do normal multiply */
  if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
    bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
    if ((dna + dnb) < 0) {
      memset(&r[2 * n2 + dna + dnb], 0, sizeof(BN_ULONG) * -(dna + dnb));
    }
    return;
  }

  /* r=(a[0]-a[1])*(b[1]-b[0]) */
  c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
  c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
  zero = neg = 0;
  switch (c1 * 3 + c2) {
    case -4:
      bn_sub_part_words(t, &(a[n]), a, tna, tna - n);       /* - */
      bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
      break;
    case -3:
      zero = 1;
      break;
    case -2:
      bn_sub_part_words(t, &(a[n]), a, tna, tna - n);       /* - */
      bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
      neg = 1;
      break;
    case -1:
    case 0:
    case 1:
      zero = 1;
      break;
    case 2:
      bn_sub_part_words(t, a, &(a[n]), tna, n - tna);       /* + */
      bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
      neg = 1;
      break;
    case 3:
      zero = 1;
      break;
    case 4:
      bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
      bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
      break;
  }

  if (n == 4 && dna == 0 && dnb == 0) {
    /* XXX: bn_mul_comba4 could take extra args to do this well */
    if (!zero) {
      bn_mul_comba4(&(t[n2]), t, &(t[n]));
    } else {
      memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG));
    }

    bn_mul_comba4(r, a, b);
    bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
  } else if (n == 8 && dna == 0 && dnb == 0) {
    /* XXX: bn_mul_comba8 could take extra args to do this well */
    if (!zero) {
      bn_mul_comba8(&(t[n2]), t, &(t[n]));
    } else {
      memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG));
    }

    bn_mul_comba8(r, a, b);
    bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
  } else {
    p = &(t[n2 * 2]);
    if (!zero) {
      bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
    } else {
      memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
    }
    bn_mul_recursive(r, a, b, n, 0, 0, p);
    bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
  }

  /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
   * r[10] holds (a[0]*b[0])
   * r[32] holds (b[1]*b[1]) */

  c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));

  if (neg) {
    /* if t[32] is negative */
    c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
  } else {
    /* Might have a carry */
    c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
  }

  /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
   * r[10] holds (a[0]*b[0])
   * r[32] holds (b[1]*b[1])
   * c1 holds the carry bits */
  c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
  if (c1) {
    p = &(r[n + n2]);
    lo = *p;
    ln = (lo + c1) & BN_MASK2;
    *p = ln;

    /* The overflow will stop before we over write
     * words we should not overwrite */
    if (ln < (BN_ULONG)c1) {
      do {
        p++;
        lo = *p;
        ln = (lo + 1) & BN_MASK2;
        *p = ln;
      } while (ln == 0);
    }
  }
}
Ejemplo n.º 5
0
/*-
 * a and b must be the same size, which is n2.
 * r needs to be n2 words and t needs to be n2*2
 * l is the low words of the output.
 * t needs to be n2*3
 */
void bn_mul_high(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, BN_ULONG *l, int n2,
                 BN_ULONG *t)
{
    int i, n;
    int c1, c2;
    int neg, oneg, zero;
    BN_ULONG ll, lc, *lp, *mp;

    n = n2 / 2;

    /* Calculate (al-ah)*(bh-bl) */
    neg = zero = 0;
    c1 = bn_cmp_words(&(a[0]), &(a[n]), n);
    c2 = bn_cmp_words(&(b[n]), &(b[0]), n);
    switch (c1 * 3 + c2) {
    case -4:
        bn_sub_words(&(r[0]), &(a[n]), &(a[0]), n);
        bn_sub_words(&(r[n]), &(b[0]), &(b[n]), n);
        break;
    case -3:
        zero = 1;
        break;
    case -2:
        bn_sub_words(&(r[0]), &(a[n]), &(a[0]), n);
        bn_sub_words(&(r[n]), &(b[n]), &(b[0]), n);
        neg = 1;
        break;
    case -1:
    case 0:
    case 1:
        zero = 1;
        break;
    case 2:
        bn_sub_words(&(r[0]), &(a[0]), &(a[n]), n);
        bn_sub_words(&(r[n]), &(b[0]), &(b[n]), n);
        neg = 1;
        break;
    case 3:
        zero = 1;
        break;
    case 4:
        bn_sub_words(&(r[0]), &(a[0]), &(a[n]), n);
        bn_sub_words(&(r[n]), &(b[n]), &(b[0]), n);
        break;
    }

    oneg = neg;
    /* t[10] = (a[0]-a[1])*(b[1]-b[0]) */
    /* r[10] = (a[1]*b[1]) */
# ifdef BN_MUL_COMBA
    if (n == 8) {
        bn_mul_comba8(&(t[0]), &(r[0]), &(r[n]));
        bn_mul_comba8(r, &(a[n]), &(b[n]));
    } else
# endif
    {
        bn_mul_recursive(&(t[0]), &(r[0]), &(r[n]), n, 0, 0, &(t[n2]));
        bn_mul_recursive(r, &(a[n]), &(b[n]), n, 0, 0, &(t[n2]));
    }

    /*-
     * s0 == low(al*bl)
     * s1 == low(ah*bh)+low((al-ah)*(bh-bl))+low(al*bl)+high(al*bl)
     * We know s0 and s1 so the only unknown is high(al*bl)
     * high(al*bl) == s1 - low(ah*bh+s0+(al-ah)*(bh-bl))
     * high(al*bl) == s1 - (r[0]+l[0]+t[0])
     */
    if (l != NULL) {
        lp = &(t[n2 + n]);
        bn_add_words(lp, &(r[0]), &(l[0]), n);
    } else {
        lp = &(r[0]);
    }

    if (neg)
        neg = (int)(bn_sub_words(&(t[n2]), lp, &(t[0]), n));
    else {
        bn_add_words(&(t[n2]), lp, &(t[0]), n);
        neg = 0;
    }

    if (l != NULL) {
        bn_sub_words(&(t[n2 + n]), &(l[n]), &(t[n2]), n);
    } else {
        lp = &(t[n2 + n]);
        mp = &(t[n2]);
        for (i = 0; i < n; i++)
            lp[i] = ((~mp[i]) + 1) & BN_MASK2;
    }

    /*-
     * s[0] = low(al*bl)
     * t[3] = high(al*bl)
     * t[10] = (a[0]-a[1])*(b[1]-b[0]) neg is the sign
     * r[10] = (a[1]*b[1])
     */
    /*-
     * R[10] = al*bl
     * R[21] = al*bl + ah*bh + (a[0]-a[1])*(b[1]-b[0])
     * R[32] = ah*bh
     */
    /*-
     * R[1]=t[3]+l[0]+r[0](+-)t[0] (have carry/borrow)
     * R[2]=r[0]+t[3]+r[1](+-)t[1] (have carry/borrow)
     * R[3]=r[1]+(carry/borrow)
     */
    if (l != NULL) {
        lp = &(t[n2]);
        c1 = (int)(bn_add_words(lp, &(t[n2 + n]), &(l[0]), n));
    } else {
        lp = &(t[n2 + n]);
        c1 = 0;
    }
    c1 += (int)(bn_add_words(&(t[n2]), lp, &(r[0]), n));
    if (oneg)
        c1 -= (int)(bn_sub_words(&(t[n2]), &(t[n2]), &(t[0]), n));
    else
        c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), &(t[0]), n));

    c2 = (int)(bn_add_words(&(r[0]), &(r[0]), &(t[n2 + n]), n));
    c2 += (int)(bn_add_words(&(r[0]), &(r[0]), &(r[n]), n));
    if (oneg)
        c2 -= (int)(bn_sub_words(&(r[0]), &(r[0]), &(t[n]), n));
    else
        c2 += (int)(bn_add_words(&(r[0]), &(r[0]), &(t[n]), n));

    if (c1 != 0) {              /* Add starting at r[0], could be +ve or -ve */
        i = 0;
        if (c1 > 0) {
            lc = c1;
            do {
                ll = (r[i] + lc) & BN_MASK2;
                r[i++] = ll;
                lc = (lc > ll);
            } while (lc);
        } else {
            lc = -c1;
            do {
                ll = r[i];
                r[i++] = (ll - lc) & BN_MASK2;
                lc = (lc > ll);
            } while (lc);
        }
    }
    if (c2 != 0) {              /* Add starting at r[1] */
        i = n;
        if (c2 > 0) {
            lc = c2;
            do {
                ll = (r[i] + lc) & BN_MASK2;
                r[i++] = ll;
                lc = (lc > ll);
            } while (lc);
        } else {
            lc = -c2;
            do {
                ll = r[i];
                r[i++] = (ll - lc) & BN_MASK2;
                lc = (lc > ll);
            } while (lc);
        }
    }
}
Ejemplo n.º 6
0
/*-
 * BN_div computes  dv := num / divisor,  rounding towards
 * zero, and sets up rm  such that  dv*divisor + rm = num  holds.
 * Thus:
 *     dv->neg == num->neg ^ divisor->neg  (unless the result is zero)
 *     rm->neg == num->neg                 (unless the remainder is zero)
 * If 'dv' or 'rm' is NULL, the respective value is not returned.
 */
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
           BN_CTX *ctx)
{
    int norm_shift, i, loop;
    BIGNUM *tmp, wnum, *snum, *sdiv, *res;
    BN_ULONG *resp, *wnump;
    BN_ULONG d0, d1;
    int num_n, div_n;
    int no_branch = 0;

    /*
     * Invalid zero-padding would have particularly bad consequences so don't
     * just rely on bn_check_top() here (bn_check_top() works only for
     * BN_DEBUG builds)
     */
    if ((num->top > 0 && num->d[num->top - 1] == 0) ||
        (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
        BNerr(BN_F_BN_DIV, BN_R_NOT_INITIALIZED);
        return 0;
    }

    bn_check_top(num);
    bn_check_top(divisor);

    if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0)
        || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) {
        no_branch = 1;
    }

    bn_check_top(dv);
    bn_check_top(rm);
    /*- bn_check_top(num); *//*
     * 'num' has been checked already
     */
    /*- bn_check_top(divisor); *//*
     * 'divisor' has been checked already
     */

    if (BN_is_zero(divisor)) {
        BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO);
        return (0);
    }

    if (!no_branch && BN_ucmp(num, divisor) < 0) {
        if (rm != NULL) {
            if (BN_copy(rm, num) == NULL)
                return (0);
        }
        if (dv != NULL)
            BN_zero(dv);
        return (1);
    }

    BN_CTX_start(ctx);
    tmp = BN_CTX_get(ctx);
    snum = BN_CTX_get(ctx);
    sdiv = BN_CTX_get(ctx);
    if (dv == NULL)
        res = BN_CTX_get(ctx);
    else
        res = dv;
    if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL)
        goto err;

    /* First we normalise the numbers */
    norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2);
    if (!(BN_lshift(sdiv, divisor, norm_shift)))
        goto err;
    sdiv->neg = 0;
    norm_shift += BN_BITS2;
    if (!(BN_lshift(snum, num, norm_shift)))
        goto err;
    snum->neg = 0;

    if (no_branch) {
        /*
         * Since we don't know whether snum is larger than sdiv, we pad snum
         * with enough zeroes without changing its value.
         */
        if (snum->top <= sdiv->top + 1) {
            if (bn_wexpand(snum, sdiv->top + 2) == NULL)
                goto err;
            for (i = snum->top; i < sdiv->top + 2; i++)
                snum->d[i] = 0;
            snum->top = sdiv->top + 2;
        } else {
            if (bn_wexpand(snum, snum->top + 1) == NULL)
                goto err;
            snum->d[snum->top] = 0;
            snum->top++;
        }
    }

    div_n = sdiv->top;
    num_n = snum->top;
    loop = num_n - div_n;
    /*
     * Lets setup a 'window' into snum This is the part that corresponds to
     * the current 'area' being divided
     */
    wnum.neg = 0;
    wnum.d = &(snum->d[loop]);
    wnum.top = div_n;
    /*
     * only needed when BN_ucmp messes up the values between top and max
     */
    wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */

    /* Get the top 2 words of sdiv */
    /* div_n=sdiv->top; */
    d0 = sdiv->d[div_n - 1];
    d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2];

    /* pointer to the 'top' of snum */
    wnump = &(snum->d[num_n - 1]);

    /* Setup to 'res' */
    res->neg = (num->neg ^ divisor->neg);
    if (!bn_wexpand(res, (loop + 1)))
        goto err;
    res->top = loop - no_branch;
    resp = &(res->d[loop - 1]);

    /* space for temp */
    if (!bn_wexpand(tmp, (div_n + 1)))
        goto err;

    if (!no_branch) {
        if (BN_ucmp(&wnum, sdiv) >= 0) {
            /*
             * If BN_DEBUG_RAND is defined BN_ucmp changes (via bn_pollute)
             * the const bignum arguments => clean the values between top and
             * max again
             */
            bn_clear_top2max(&wnum);
            bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n);
            *resp = 1;
        } else
            res->top--;
    }

    /*
     * if res->top == 0 then clear the neg value otherwise decrease the resp
     * pointer
     */
    if (res->top == 0)
        res->neg = 0;
    else
        resp--;

    for (i = 0; i < loop - 1; i++, wnump--, resp--) {
        BN_ULONG q, l0;
        /*
         * the first part of the loop uses the top two words of snum and sdiv
         * to calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv
         */
# if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM)
        BN_ULONG bn_div_3_words(BN_ULONG *, BN_ULONG, BN_ULONG);
        q = bn_div_3_words(wnump, d1, d0);
# else
        BN_ULONG n0, n1, rem = 0;

        n0 = wnump[0];
        n1 = wnump[-1];
        if (n0 == d0)
            q = BN_MASK2;
        else {                  /* n0 < d0 */

#  ifdef BN_LLONG
            BN_ULLONG t2;

#   if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
            q = (BN_ULONG)(((((BN_ULLONG) n0) << BN_BITS2) | n1) / d0);
#   else
            q = bn_div_words(n0, n1, d0);
#   endif

#   ifndef REMAINDER_IS_ALREADY_CALCULATED
            /*
             * rem doesn't have to be BN_ULLONG. The least we
             * know it's less that d0, isn't it?
             */
            rem = (n1 - q * d0) & BN_MASK2;
#   endif
            t2 = (BN_ULLONG) d1 *q;

            for (;;) {
                if (t2 <= ((((BN_ULLONG) rem) << BN_BITS2) | wnump[-2]))
                    break;
                q--;
                rem += d0;
                if (rem < d0)
                    break;      /* don't let rem overflow */
                t2 -= d1;
            }
#  else                         /* !BN_LLONG */
            BN_ULONG t2l, t2h;

            q = bn_div_words(n0, n1, d0);
#   ifndef REMAINDER_IS_ALREADY_CALCULATED
            rem = (n1 - q * d0) & BN_MASK2;
#   endif

#   if defined(BN_UMULT_LOHI)
            BN_UMULT_LOHI(t2l, t2h, d1, q);
#   elif defined(BN_UMULT_HIGH)
            t2l = d1 * q;
            t2h = BN_UMULT_HIGH(d1, q);
#   else
            {
                BN_ULONG ql, qh;
                t2l = LBITS(d1);
                t2h = HBITS(d1);
                ql = LBITS(q);
                qh = HBITS(q);
                mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */
            }
#   endif

            for (;;) {
                if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2])))
                    break;
                q--;
                rem += d0;
                if (rem < d0)
                    break;      /* don't let rem overflow */
                if (t2l < d1)
                    t2h--;
                t2l -= d1;
            }
#  endif                        /* !BN_LLONG */
        }
# endif                         /* !BN_DIV3W */

        l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q);
        tmp->d[div_n] = l0;
        wnum.d--;
        /*
         * ingore top values of the bignums just sub the two BN_ULONG arrays
         * with bn_sub_words
         */
        if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) {
            /*
             * Note: As we have considered only the leading two BN_ULONGs in
             * the calculation of q, sdiv * q might be greater than wnum (but
             * then (q-1) * sdiv is less or equal than wnum)
             */
            q--;
            if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n))
                /*
                 * we can't have an overflow here (assuming that q != 0, but
                 * if q == 0 then tmp is zero anyway)
                 */
                (*wnump)++;
        }
        /* store part of the result */
        *resp = q;
    }
    bn_correct_top(snum);
    if (rm != NULL) {
        /*
         * Keep a copy of the neg flag in num because if rm==num BN_rshift()
         * will overwrite it.
         */
        int neg = num->neg;
        BN_rshift(rm, snum, norm_shift);
        if (!BN_is_zero(rm))
            rm->neg = neg;
        bn_check_top(rm);
    }
    if (no_branch)
        bn_correct_top(res);
    BN_CTX_end(ctx);
    return (1);
 err:
    bn_check_top(rm);
    BN_CTX_end(ctx);
    return (0);
}
Ejemplo n.º 7
0
BN_ULONG bn_add_part_words(BN_ULONG *r,
                           const BN_ULONG *a, const BN_ULONG *b,
                           int cl, int dl)
{
    BN_ULONG c, l, t;

    assert(cl >= 0);
    c = bn_add_words(r, a, b, cl);

    if (dl == 0)
        return c;

    r += cl;
    a += cl;
    b += cl;

    if (dl < 0) {
        int save_dl = dl;
        while (c) {
            l = (c + b[0]) & BN_MASK2;
            c = (l < c);
            r[0] = l;
            if (++dl >= 0)
                break;

            l = (c + b[1]) & BN_MASK2;
            c = (l < c);
            r[1] = l;
            if (++dl >= 0)
                break;

            l = (c + b[2]) & BN_MASK2;
            c = (l < c);
            r[2] = l;
            if (++dl >= 0)
                break;

            l = (c + b[3]) & BN_MASK2;
            c = (l < c);
            r[3] = l;
            if (++dl >= 0)
                break;

            save_dl = dl;
            b += 4;
            r += 4;
        }
        if (dl < 0) {
            if (save_dl < dl) {
                switch (dl - save_dl) {
                case 1:
                    r[1] = b[1];
                    if (++dl >= 0)
                        break;
                case 2:
                    r[2] = b[2];
                    if (++dl >= 0)
                        break;
                case 3:
                    r[3] = b[3];
                    if (++dl >= 0)
                        break;
                }
                b += 4;
                r += 4;
            }
        }
        if (dl < 0) {
            for (;;) {
                r[0] = b[0];
                if (++dl >= 0)
                    break;
                r[1] = b[1];
                if (++dl >= 0)
                    break;
                r[2] = b[2];
                if (++dl >= 0)
                    break;
                r[3] = b[3];
                if (++dl >= 0)
                    break;

                b += 4;
                r += 4;
            }
        }
    } else {
        int save_dl = dl;
        while (c) {
            t = (a[0] + c) & BN_MASK2;
            c = (t < c);
            r[0] = t;
            if (--dl <= 0)
                break;

            t = (a[1] + c) & BN_MASK2;
            c = (t < c);
            r[1] = t;
            if (--dl <= 0)
                break;

            t = (a[2] + c) & BN_MASK2;
            c = (t < c);
            r[2] = t;
            if (--dl <= 0)
                break;

            t = (a[3] + c) & BN_MASK2;
            c = (t < c);
            r[3] = t;
            if (--dl <= 0)
                break;

            save_dl = dl;
            a += 4;
            r += 4;
        }
        if (dl > 0) {
            if (save_dl > dl) {
                switch (save_dl - dl) {
                case 1:
                    r[1] = a[1];
                    if (--dl <= 0)
                        break;
                case 2:
                    r[2] = a[2];
                    if (--dl <= 0)
                        break;
                case 3:
                    r[3] = a[3];
                    if (--dl <= 0)
                        break;
                }
                a += 4;
                r += 4;
            }
        }
        if (dl > 0) {
            for (;;) {
                r[0] = a[0];
                if (--dl <= 0)
                    break;
                r[1] = a[1];
                if (--dl <= 0)
                    break;
                r[2] = a[2];
                if (--dl <= 0)
                    break;
                r[3] = a[3];
                if (--dl <= 0)
                    break;

                a += 4;
                r += 4;
            }
        }
    }
    return c;
}
Ejemplo n.º 8
0
/* n+tn is the word length
 * t needs to be n*4 is size, as does r */
EXPORT_C void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
	     int tna, int tnb, BN_ULONG *t)
	{
	int i,j,n2=n*2;
	int c1,c2,neg,zero;
	BN_ULONG ln,lo,*p;

# ifdef BN_COUNT
	fprintf(stderr," bn_mul_part_recursive (%d+%d) * (%d+%d)\n",
		tna, n, tnb, n);
# endif
	if (n < 8)
		{
		bn_mul_normal(r,a,n+tna,b,n+tnb);
		return;
		}

	/* r=(a[0]-a[1])*(b[1]-b[0]) */
	c1=bn_cmp_part_words(a,&(a[n]),tna,n-tna);
	c2=bn_cmp_part_words(&(b[n]),b,tnb,tnb-n);
	zero=neg=0;
	switch (c1*3+c2)
		{
	case -4:
		bn_sub_part_words(t,      &(a[n]),a,      tna,tna-n); /* - */
		bn_sub_part_words(&(t[n]),b,      &(b[n]),tnb,n-tnb); /* - */
		break;
	case -3:
		zero=1;
		/* break; */
	case -2:
		bn_sub_part_words(t,      &(a[n]),a,      tna,tna-n); /* - */
		bn_sub_part_words(&(t[n]),&(b[n]),b,      tnb,tnb-n); /* + */
		neg=1;
		break;
	case -1:
	case 0:
	case 1:
		zero=1;
		/* break; */
	case 2:
		bn_sub_part_words(t,      a,      &(a[n]),tna,n-tna); /* + */
		bn_sub_part_words(&(t[n]),b,      &(b[n]),tnb,n-tnb); /* - */
		neg=1;
		break;
	case 3:
		zero=1;
		/* break; */
	case 4:
		bn_sub_part_words(t,      a,      &(a[n]),tna,n-tna);
		bn_sub_part_words(&(t[n]),&(b[n]),b,      tnb,tnb-n);
		break;
		}
		/* The zero case isn't yet implemented here. The speedup
		   would probably be negligible. */
# if 0
	if (n == 4)
		{
		bn_mul_comba4(&(t[n2]),t,&(t[n]));
		bn_mul_comba4(r,a,b);
		bn_mul_normal(&(r[n2]),&(a[n]),tn,&(b[n]),tn);
		memset(&(r[n2+tn*2]),0,sizeof(BN_ULONG)*(n2-tn*2));
		}
	else
# endif
	if (n == 8)
		{
		bn_mul_comba8(&(t[n2]),t,&(t[n]));
		bn_mul_comba8(r,a,b);
		bn_mul_normal(&(r[n2]),&(a[n]),tna,&(b[n]),tnb);
		memset(&(r[n2+tna+tnb]),0,sizeof(BN_ULONG)*(n2-tna-tnb));
		}
	else
		{
		p= &(t[n2*2]);
		bn_mul_recursive(&(t[n2]),t,&(t[n]),n,0,0,p);
		bn_mul_recursive(r,a,b,n,0,0,p);
		i=n/2;
		/* If there is only a bottom half to the number,
		 * just do it */
		if (tna > tnb)
			j = tna - i;
		else
			j = tnb - i;
		if (j == 0)
			{
			bn_mul_recursive(&(r[n2]),&(a[n]),&(b[n]),
				i,tna-i,tnb-i,p);
			memset(&(r[n2+i*2]),0,sizeof(BN_ULONG)*(n2-i*2));
			}
		else if (j > 0) /* eg, n == 16, i == 8 and tn == 11 */
				{
				bn_mul_part_recursive(&(r[n2]),&(a[n]),&(b[n]),
					i,tna-i,tnb-i,p);
				memset(&(r[n2+tna+tnb]),0,
					sizeof(BN_ULONG)*(n2-tna-tnb));
				}
		else /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
			{
			memset(&(r[n2]),0,sizeof(BN_ULONG)*n2);
			if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL
				&& tnb < BN_MUL_RECURSIVE_SIZE_NORMAL)
				{
				bn_mul_normal(&(r[n2]),&(a[n]),tna,&(b[n]),tnb);
				}
			else
				{
				for (;;)
					{
					i/=2;
					if (i <= tna && tna == tnb)
						{
						bn_mul_recursive(&(r[n2]),
							&(a[n]),&(b[n]),
							i,tna-i,tnb-i,p);
						break;
						}
					else if (i < tna || i < tnb)
						{
						bn_mul_part_recursive(&(r[n2]),
							&(a[n]),&(b[n]),
							i,tna-i,tnb-i,p);
						break;
						}
					}
				}
			}
		}

	/* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
	 * r[10] holds (a[0]*b[0])
	 * r[32] holds (b[1]*b[1])
	 */

	c1=(int)(bn_add_words(t,r,&(r[n2]),n2));

	if (neg) /* if t[32] is negative */
		{
		c1-=(int)(bn_sub_words(&(t[n2]),t,&(t[n2]),n2));
		}
	else
		{
		/* Might have a carry */
		c1+=(int)(bn_add_words(&(t[n2]),&(t[n2]),t,n2));
		}

	/* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
	 * r[10] holds (a[0]*b[0])
	 * r[32] holds (b[1]*b[1])
	 * c1 holds the carry bits
	 */
	c1+=(int)(bn_add_words(&(r[n]),&(r[n]),&(t[n2]),n2));
	if (c1)
		{
		p= &(r[n+n2]);
		lo= *p;
		ln=(lo+c1)&BN_MASK2;
		*p=ln;

		/* The overflow will stop before we over write
		 * words we should not overwrite */
		if (ln < (BN_ULONG)c1)
			{
			do	{
				p++;
				lo= *p;
				ln=(lo+1)&BN_MASK2;
				*p=ln;
				} while (ln == 0);
			}
		}
	}
Ejemplo n.º 9
0
EXPORT_C BN_ULONG bn_add_part_words(BN_ULONG *r,
	const BN_ULONG *a, const BN_ULONG *b,
	int cl, int dl)
	{
	BN_ULONG c, l, t;

	assert(cl >= 0);
	c = bn_add_words(r, a, b, cl);

	if (dl == 0)
		return c;

	r += cl;
	a += cl;
	b += cl;

	if (dl < 0)
		{
		int save_dl = dl;
#ifdef BN_COUNT
		fprintf(stderr, "  bn_add_part_words %d + %d (dl < 0, c = %d)\n", cl, dl, c);
#endif
		while (c)
			{
			l=(c+b[0])&BN_MASK2;
			c=(l < c);
			r[0]=l;
			if (++dl >= 0) break;

			l=(c+b[1])&BN_MASK2;
			c=(l < c);
			r[1]=l;
			if (++dl >= 0) break;

			l=(c+b[2])&BN_MASK2;
			c=(l < c);
			r[2]=l;
			if (++dl >= 0) break;

			l=(c+b[3])&BN_MASK2;
			c=(l < c);
			r[3]=l;
			if (++dl >= 0) break;

			save_dl = dl;
			b+=4;
			r+=4;
			}
		if (dl < 0)
			{
#ifdef BN_COUNT
			fprintf(stderr, "  bn_add_part_words %d + %d (dl < 0, c == 0)\n", cl, dl);
#endif
			if (save_dl < dl)
				{
				switch (dl - save_dl)
					{
				case 1:
					r[1] = b[1];
					if (++dl >= 0) break;
				case 2:
					r[2] = b[2];
					if (++dl >= 0) break;
				case 3:
					r[3] = b[3];
					if (++dl >= 0) break;
					}
				b += 4;
				r += 4;
				}
			}
		if (dl < 0)
			{
#ifdef BN_COUNT
			fprintf(stderr, "  bn_add_part_words %d + %d (dl < 0, copy)\n", cl, dl);
#endif
			for(;;)
				{
				r[0] = b[0];
				if (++dl >= 0) break;
				r[1] = b[1];
				if (++dl >= 0) break;
				r[2] = b[2];
				if (++dl >= 0) break;
				r[3] = b[3];
				if (++dl >= 0) break;

				b += 4;
				r += 4;
				}
			}
		}
	else
		{
		int save_dl = dl;
#ifdef BN_COUNT
		fprintf(stderr, "  bn_add_part_words %d + %d (dl > 0)\n", cl, dl);
#endif
		while (c)
			{
			t=(a[0]+c)&BN_MASK2;
			c=(t < c);
			r[0]=t;
			if (--dl <= 0) break;

			t=(a[1]+c)&BN_MASK2;
			c=(t < c);
			r[1]=t;
			if (--dl <= 0) break;

			t=(a[2]+c)&BN_MASK2;
			c=(t < c);
			r[2]=t;
			if (--dl <= 0) break;

			t=(a[3]+c)&BN_MASK2;
			c=(t < c);
			r[3]=t;
			if (--dl <= 0) break;

			save_dl = dl;
			a+=4;
			r+=4;
			}
#ifdef BN_COUNT
		fprintf(stderr, "  bn_add_part_words %d + %d (dl > 0, c == 0)\n", cl, dl);
#endif
		if (dl > 0)
			{
			if (save_dl > dl)
				{
				switch (save_dl - dl)
					{
				case 1:
					r[1] = a[1];
					if (--dl <= 0) break;
				case 2:
					r[2] = a[2];
					if (--dl <= 0) break;
				case 3:
					r[3] = a[3];
					if (--dl <= 0) break;
					}
				a += 4;
				r += 4;
				}
			}
		if (dl > 0)
			{
#ifdef BN_COUNT
			fprintf(stderr, "  bn_add_part_words %d + %d (dl > 0, copy)\n", cl, dl);
#endif
			for(;;)
				{
				r[0] = a[0];
				if (--dl <= 0) break;
				r[1] = a[1];
				if (--dl <= 0) break;
				r[2] = a[2];
				if (--dl <= 0) break;
				r[3] = a[3];
				if (--dl <= 0) break;

				a += 4;
				r += 4;
				}
			}
		}
	return c;
	}
Ejemplo n.º 10
0
// bn_mul_part_recursive sets |r| to |a| * |b|, using |t| as scratch space. |r|
// has length 4*|n|, |a| has length |n| + |tna|, |b| has length |n| + |tnb|, and
// |t| has length 8*|n|. |n| must be a power of two. Additionally, we must have
// 0 <= tna < n and 0 <= tnb < n, and |tna| and |tnb| must differ by at most
// one.
//
// TODO(davidben): Make this take |size_t| and perhaps the actual lengths of |a|
// and |b|.
static void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a,
                                  const BN_ULONG *b, int n, int tna, int tnb,
                                  BN_ULONG *t) {
  // |n| is a power of two.
  assert(n != 0 && (n & (n - 1)) == 0);
  // Check |tna| and |tnb| are in range.
  assert(0 <= tna && tna < n);
  assert(0 <= tnb && tnb < n);
  assert(-1 <= tna - tnb && tna - tnb <= 1);

  int n2 = n * 2;
  if (n < 8) {
    bn_mul_normal(r, a, n + tna, b, n + tnb);
    OPENSSL_memset(r + n2 + tna + tnb, 0, n2 - tna - tnb);
    return;
  }

  // Split |a| and |b| into a0,a1 and b0,b1, where a0 and b0 have size |n|. |a1|
  // and |b1| have size |tna| and |tnb|, respectively.
  // Split |t| into t0,t1,t2,t3, each of size |n|, with the remaining 4*|n| used
  // for recursive calls.
  // Split |r| into r0,r1,r2,r3. We must contribute a0*b0 to r0,r1, a0*a1+b0*b1
  // to r1,r2, and a1*b1 to r2,r3. The middle term we will compute as:
  //
  //   a0*a1 + b0*b1 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0

  // t0 = a0 - a1 and t1 = b1 - b0. The result will be multiplied, so we XOR
  // their sign masks, giving the sign of (a0 - a1)*(b1 - b0). t0 and t1
  // themselves store the absolute value.
  BN_ULONG neg = bn_abs_sub_part_words(t, a, &a[n], tna, n - tna, &t[n2]);
  neg ^= bn_abs_sub_part_words(&t[n], &b[n], b, tnb, tnb - n, &t[n2]);

  // Compute:
  // t2,t3 = t0 * t1 = |(a0 - a1)*(b1 - b0)|
  // r0,r1 = a0 * b0
  // r2,r3 = a1 * b1
  if (n == 8) {
    bn_mul_comba8(&t[n2], t, &t[n]);
    bn_mul_comba8(r, a, b);

    bn_mul_normal(&r[n2], &a[n], tna, &b[n], tnb);
    // |bn_mul_normal| only writes |tna| + |tna| words. Zero the rest.
    OPENSSL_memset(&r[n2 + tna + tnb], 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
  } else {
    BN_ULONG *p = &t[n2 * 2];
    bn_mul_recursive(&t[n2], t, &t[n], n, 0, 0, p);
    bn_mul_recursive(r, a, b, n, 0, 0, p);

    OPENSSL_memset(&r[n2], 0, sizeof(BN_ULONG) * n2);
    if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL &&
        tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
      bn_mul_normal(&r[n2], &a[n], tna, &b[n], tnb);
    } else {
      int i = n;
      for (;;) {
        i /= 2;
        if (i < tna || i < tnb) {
          // E.g., n == 16, i == 8 and tna == 11. |tna| and |tnb| are within one
          // of each other, so if |tna| is larger and tna > i, then we know
          // tnb >= i, and this call is valid.
          bn_mul_part_recursive(&r[n2], &a[n], &b[n], i, tna - i, tnb - i, p);
          break;
        }
        if (i == tna || i == tnb) {
          // If there is only a bottom half to the number, just do it. We know
          // the larger of |tna - i| and |tnb - i| is zero. The other is zero or
          // -1 by because of |tna| and |tnb| differ by at most one.
          bn_mul_recursive(&r[n2], &a[n], &b[n], i, tna - i, tnb - i, p);
          break;
        }

        // This loop will eventually terminate when |i| falls below
        // |BN_MUL_RECURSIVE_SIZE_NORMAL| because we know one of |tna| and |tnb|
        // exceeds that.
      }
    }
  }

  // t0,t1,c = r0,r1 + r2,r3 = a0*b0 + a1*b1
  BN_ULONG c = bn_add_words(t, r, &r[n2], n2);

  // t2,t3,c = t0,t1,c + neg*t2,t3 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0.
  // The second term is stored as the absolute value, so we do this with a
  // constant-time select.
  BN_ULONG c_neg = c - bn_sub_words(&t[n2 * 2], t, &t[n2], n2);
  BN_ULONG c_pos = c + bn_add_words(&t[n2], t, &t[n2], n2);
  bn_select_words(&t[n2], neg, &t[n2 * 2], &t[n2], n2);
  OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
                         crypto_word_t_too_small);
  c = constant_time_select_w(neg, c_neg, c_pos);

  // We now have our three components. Add them together.
  // r1,r2,c = r1,r2 + t2,t3,c
  c += bn_add_words(&r[n], &r[n], &t[n2], n2);

  // Propagate the carry bit to the end.
  for (int i = n + n2; i < n2 + n2; i++) {
    BN_ULONG old = r[i];
    r[i] = old + c;
    c = r[i] < old;
  }

  // The product should fit without carries.
  assert(c == 0);
}
Ejemplo n.º 11
0
// bn_mul_recursive sets |r| to |a| * |b|, using |t| as scratch space. |r| has
// length 2*|n2|, |a| has length |n2| + |dna|, |b| has length |n2| + |dnb|, and
// |t| has length 4*|n2|. |n2| must be a power of two. Finally, we must have
// -|BN_MUL_RECURSIVE_SIZE_NORMAL|/2 <= |dna| <= 0 and
// -|BN_MUL_RECURSIVE_SIZE_NORMAL|/2 <= |dnb| <= 0.
//
// TODO(davidben): Simplify and |size_t| the calling convention around lengths
// here.
static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
                             int n2, int dna, int dnb, BN_ULONG *t) {
  // |n2| is a power of two.
  assert(n2 != 0 && (n2 & (n2 - 1)) == 0);
  // Check |dna| and |dnb| are in range.
  assert(-BN_MUL_RECURSIVE_SIZE_NORMAL/2 <= dna && dna <= 0);
  assert(-BN_MUL_RECURSIVE_SIZE_NORMAL/2 <= dnb && dnb <= 0);

  // Only call bn_mul_comba 8 if n2 == 8 and the
  // two arrays are complete [steve]
  if (n2 == 8 && dna == 0 && dnb == 0) {
    bn_mul_comba8(r, a, b);
    return;
  }

  // Else do normal multiply
  if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
    bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
    if (dna + dnb < 0) {
      OPENSSL_memset(&r[2 * n2 + dna + dnb], 0,
                     sizeof(BN_ULONG) * -(dna + dnb));
    }
    return;
  }

  // Split |a| and |b| into a0,a1 and b0,b1, where a0 and b0 have size |n|.
  // Split |t| into t0,t1,t2,t3, each of size |n|, with the remaining 4*|n| used
  // for recursive calls.
  // Split |r| into r0,r1,r2,r3. We must contribute a0*b0 to r0,r1, a0*a1+b0*b1
  // to r1,r2, and a1*b1 to r2,r3. The middle term we will compute as:
  //
  //   a0*a1 + b0*b1 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0
  //
  // Note that we know |n| >= |BN_MUL_RECURSIVE_SIZE_NORMAL|/2 above, so
  // |tna| and |tnb| are non-negative.
  int n = n2 / 2, tna = n + dna, tnb = n + dnb;

  // t0 = a0 - a1 and t1 = b1 - b0. The result will be multiplied, so we XOR
  // their sign masks, giving the sign of (a0 - a1)*(b1 - b0). t0 and t1
  // themselves store the absolute value.
  BN_ULONG neg = bn_abs_sub_part_words(t, a, &a[n], tna, n - tna, &t[n2]);
  neg ^= bn_abs_sub_part_words(&t[n], &b[n], b, tnb, tnb - n, &t[n2]);

  // Compute:
  // t2,t3 = t0 * t1 = |(a0 - a1)*(b1 - b0)|
  // r0,r1 = a0 * b0
  // r2,r3 = a1 * b1
  if (n == 4 && dna == 0 && dnb == 0) {
    bn_mul_comba4(&t[n2], t, &t[n]);

    bn_mul_comba4(r, a, b);
    bn_mul_comba4(&r[n2], &a[n], &b[n]);
  } else if (n == 8 && dna == 0 && dnb == 0) {
    bn_mul_comba8(&t[n2], t, &t[n]);

    bn_mul_comba8(r, a, b);
    bn_mul_comba8(&r[n2], &a[n], &b[n]);
  } else {
    BN_ULONG *p = &t[n2 * 2];
    bn_mul_recursive(&t[n2], t, &t[n], n, 0, 0, p);
    bn_mul_recursive(r, a, b, n, 0, 0, p);
    bn_mul_recursive(&r[n2], &a[n], &b[n], n, dna, dnb, p);
  }

  // t0,t1,c = r0,r1 + r2,r3 = a0*b0 + a1*b1
  BN_ULONG c = bn_add_words(t, r, &r[n2], n2);

  // t2,t3,c = t0,t1,c + neg*t2,t3 = (a0 - a1)*(b1 - b0) + a1*b1 + a0*b0.
  // The second term is stored as the absolute value, so we do this with a
  // constant-time select.
  BN_ULONG c_neg = c - bn_sub_words(&t[n2 * 2], t, &t[n2], n2);
  BN_ULONG c_pos = c + bn_add_words(&t[n2], t, &t[n2], n2);
  bn_select_words(&t[n2], neg, &t[n2 * 2], &t[n2], n2);
  OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
                         crypto_word_t_too_small);
  c = constant_time_select_w(neg, c_neg, c_pos);

  // We now have our three components. Add them together.
  // r1,r2,c = r1,r2 + t2,t3,c
  c += bn_add_words(&r[n], &r[n], &t[n2], n2);

  // Propagate the carry bit to the end.
  for (int i = n + n2; i < n2 + n2; i++) {
    BN_ULONG old = r[i];
    r[i] = old + c;
    c = r[i] < old;
  }

  // The product should fit without carries.
  assert(c == 0);
}