int bn_usub_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { // |b| may have more words than |a| given non-minimal inputs, but all words // beyond |a->width| must then be zero. int b_width = b->width; if (b_width > a->width) { if (!bn_fits_in_words(b, a->width)) { OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3); return 0; } b_width = a->width; } if (!bn_wexpand(r, a->width)) { return 0; } BN_ULONG borrow = bn_sub_words(r->d, a->d, b->d, b_width); for (int i = b_width; i < a->width; i++) { // |r| and |a| may alias, so use a temporary. BN_ULONG tmp = a->d[i]; r->d[i] = a->d[i] - borrow; borrow = tmp < r->d[i]; } if (borrow) { OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3); return 0; } r->width = a->width; r->neg = 0; return 1; }
// bn_sqr_recursive sets |r| to |a|^2, using |t| as scratch space. |r| has // length 2*|n2|, |a| has length |n2|, and |t| has length 4*|n2|. |n2| must be // a power of two. static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, size_t n2, BN_ULONG *t) { // |n2| is a power of two. assert(n2 != 0 && (n2 & (n2 - 1)) == 0); if (n2 == 4) { bn_sqr_comba4(r, a); return; } if (n2 == 8) { bn_sqr_comba8(r, a); return; } if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) { bn_sqr_normal(r, a, n2, t); return; } // Split |a| into a0,a1, each of 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^2 to r0,r1, 2*a0*a1 to // r1,r2, and a1^2 to r2,r3. size_t n = n2 / 2; BN_ULONG *t_recursive = &t[n2 * 2]; // t0 = |a0 - a1|. bn_abs_sub_words(t, a, &a[n], n, &t[n]); // t2,t3 = t0^2 = |a0 - a1|^2 = a0^2 - 2*a0*a1 + a1^2 bn_sqr_recursive(&t[n2], t, n, t_recursive); // r0,r1 = a0^2 bn_sqr_recursive(r, a, n, t_recursive); // r2,r3 = a1^2 bn_sqr_recursive(&r[n2], &a[n], n, t_recursive); // t0,t1,c = r0,r1 + r2,r3 = a0^2 + a1^2 BN_ULONG c = bn_add_words(t, r, &r[n2], n2); // t2,t3,c = t0,t1,c - t2,t3 = 2*a0*a1 c -= bn_sub_words(&t[n2], t, &t[n2], n2); // 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 (size_t i = n + n2; i < n2 + n2; i++) { BN_ULONG old = r[i]; r[i] = old + c; c = r[i] < old; } // The square should fit without carries. assert(c == 0); }
void GFp_p384_elem_add(Elem r, const Elem a, const Elem b) { /* XXX: Not constant-time. */ if (!bn_add_words(r, a, b, P384_LIMBS)) { if (bn_cmp_words(r, Q, P384_LIMBS) < 0) { return; } } /* Either the addition resulted in a carry requiring 1 bit more than would * fit in |P384_LIMBS| limbs, or the addition result fit in |P384_LIMBS| * limbs but it was not less than |q|. Either way, it needs to be reduced. */ (void)bn_sub_words(r, r, Q, P384_LIMBS); }
/* unsigned subtraction of b from a, a must be larger than b. */ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max, min, dif; BN_ULONG t1, t2, borrow, *rp; const BN_ULONG *ap, *bp; bn_check_top(a); bn_check_top(b); max = a->top; min = b->top; dif = max - min; if (dif < 0) { /* hmm... should not be happening */ BNerr(BN_F_BN_USUB, BN_R_ARG2_LT_ARG3); return 0; } if (bn_wexpand(r, max) == NULL) return 0; ap = a->d; bp = b->d; rp = r->d; borrow = bn_sub_words(rp, ap, bp, min); ap += min; rp += min; while (dif) { dif--; t1 = *(ap++); t2 = (t1 - borrow) & BN_MASK2; *(rp++) = t2; borrow &= (t1 == 0); } r->top = max; r->neg = 0; bn_correct_top(r); return 1; }
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont) { BN_ULONG *ap, *np, *rp, n0, v, carry; int nl, max, i; const BIGNUM *n = &mont->N; nl = n->top; if (nl == 0) { ret->top = 0; return 1; } max = (2 * nl); /* carry is stored separately */ if (bn_wexpand(r, max) == NULL) { return 0; } r->neg ^= n->neg; np = n->d; rp = r->d; /* clear the top words of T */ if (max > r->top) { memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG)); } r->top = max; n0 = mont->n0[0]; for (carry = 0, i = 0; i < nl; i++, rp++) { v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); v = (v + carry + rp[nl]) & BN_MASK2; carry |= (v != rp[nl]); carry &= (v <= rp[nl]); rp[nl] = v; } if (bn_wexpand(ret, nl) == NULL) { return 0; } ret->top = nl; ret->neg = r->neg; rp = ret->d; ap = &(r->d[nl]); { BN_ULONG *nrp; uintptr_t m; v = bn_sub_words(rp, ap, np, nl) - carry; /* if subtraction result is real, then trick unconditional memcpy below to * perform in-place "refresh" instead of actual copy. */ m = (0u - (uintptr_t)v); nrp = (BN_ULONG *)(((uintptr_t)rp & ~m) | ((uintptr_t)ap & m)); for (i = 0, nl -= 4; i < nl; i += 4) { BN_ULONG t1, t2, t3, t4; t1 = nrp[i + 0]; t2 = nrp[i + 1]; t3 = nrp[i + 2]; ap[i + 0] = 0; t4 = nrp[i + 3]; ap[i + 1] = 0; rp[i + 0] = t1; ap[i + 2] = 0; rp[i + 1] = t2; ap[i + 3] = 0; rp[i + 2] = t3; rp[i + 3] = t4; } for (nl += 4; i < nl; i++) { rp[i] = nrp[i], ap[i] = 0; } } bn_correct_top(r); bn_correct_top(ret); return 1; }
static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont) { BIGNUM *n; BN_ULONG *ap, *np, *rp, n0, v, carry; int nl, max, i; n = &(mont->N); nl = n->top; if (nl == 0) { ret->top = 0; return (1); } max = (2 * nl); /* carry is stored separately */ if (bn_wexpand(r, max) == NULL) return (0); r->neg ^= n->neg; np = n->d; rp = r->d; /* clear the top words of T */ i = max - r->top; if (i) memset(&rp[r->top], 0, sizeof(*rp) * i); r->top = max; r->flags |= BN_FLG_FIXED_TOP; n0 = mont->n0[0]; /* * Add multiples of |n| to |r| until R = 2^(nl * BN_BITS2) divides it. On * input, we had |r| < |n| * R, so now |r| < 2 * |n| * R. Note that |r| * includes |carry| which is stored separately. */ for (carry = 0, i = 0; i < nl; i++, rp++) { v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); v = (v + carry + rp[nl]) & BN_MASK2; carry |= (v != rp[nl]); carry &= (v <= rp[nl]); rp[nl] = v; } if (bn_wexpand(ret, nl) == NULL) return (0); ret->top = nl; ret->flags |= BN_FLG_FIXED_TOP; ret->neg = r->neg; rp = ret->d; /* * Shift |nl| words to divide by R. We have |ap| < 2 * |n|. Note that |ap| * includes |carry| which is stored separately. */ ap = &(r->d[nl]); carry -= bn_sub_words(rp, ap, np, nl); /* * |carry| is -1 if |ap| - |np| underflowed or zero if it did not. Note * |carry| cannot be 1. That would imply the subtraction did not fit in * |nl| words, and we know at most one subtraction is needed. */ for (i = 0; i < nl; i++) { rp[i] = (carry & ap[i]) | (~carry & rp[i]); ap[i] = 0; } return (1); }
/* unsigned subtraction of b from a, a must be larger than b. */ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max,min,dif; register BN_ULONG t1,t2,*ap,*bp,*rp; int i,carry; #if defined(IRIX_CC_BUG) && !defined(LINT) int dummy; #endif bn_check_top(a); bn_check_top(b); max = a->top; min = b->top; dif = max - min; if (dif < 0) /* hmm... should not be happening */ { BNerr(BN_F_BN_USUB,BN_R_ARG2_LT_ARG3); return(0); } if (bn_wexpand(r,max) == NULL) return(0); ap=a->d; bp=b->d; rp=r->d; #if 1 carry=0; for (i = min; i != 0; i--) { t1= *(ap++); t2= *(bp++); if (carry) { carry=(t1 <= t2); t1=(t1-t2-1)&BN_MASK2; } else { carry=(t1 < t2); t1=(t1-t2)&BN_MASK2; } #if defined(IRIX_CC_BUG) && !defined(LINT) dummy=t1; #endif *(rp++)=t1&BN_MASK2; } #else carry=bn_sub_words(rp,ap,bp,min); ap+=min; bp+=min; rp+=min; #endif if (carry) /* subtracted */ { if (!dif) /* error: a < b */ return 0; while (dif) { dif--; t1 = *(ap++); t2 = (t1-1)&BN_MASK2; *(rp++) = t2; if (t1) break; } } #if 0 TINYCLR_SSL_MEMCPY(rp,ap,sizeof(*rp)*(max-i)); #else if (rp != ap) { for (;;) { if (!dif--) break; rp[0]=ap[0]; if (!dif--) break; rp[1]=ap[1]; if (!dif--) break; rp[2]=ap[2]; if (!dif--) break; rp[3]=ap[3]; rp+=4; ap+=4; } } #endif r->top=max; r->neg=0; bn_correct_top(r); return(1); }
/* dnX may not be positive, but n2/2+dnX has to be */ 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; # ifdef BN_MUL_COMBA # if 0 if (n2 == 4) { bn_mul_comba4(r, a, b); return; } # endif /* * 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; } # endif /* BN_MUL_COMBA */ /* 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; } # ifdef BN_MUL_COMBA 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, sizeof(*t) * 8); 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, sizeof(*t) * 16); bn_mul_comba8(r, a, b); bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n])); } else # endif /* BN_MUL_COMBA */ { p = &(t[n2 * 2]); if (!zero) bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p); else memset(&t[n2], 0, sizeof(*t) * n2); 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); } } }
/* tnX may not be negative but less than n */ 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: 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: 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: 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(*r) * (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(*r) * (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(*r) * (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(*r) * 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); } } }
BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) { BN_ULONG c, t; assert(cl >= 0); c = bn_sub_words(r, a, b, cl); if (dl == 0) return c; r += cl; a += cl; b += cl; if (dl < 0) { #ifdef BN_COUNT fprintf(stderr, " bn_sub_part_words %d + %d (dl < 0, c = %d)\n", cl, dl, c); #endif for (;;) { t = b[0]; r[0] = (0-t-c)&BN_MASK2; if (t != 0) c=1; if (++dl >= 0) break; t = b[1]; r[1] = (0-t-c)&BN_MASK2; if (t != 0) c=1; if (++dl >= 0) break; t = b[2]; r[2] = (0-t-c)&BN_MASK2; if (t != 0) c=1; if (++dl >= 0) break; t = b[3]; r[3] = (0-t-c)&BN_MASK2; if (t != 0) c=1; if (++dl >= 0) break; b += 4; r += 4; } } else { int save_dl = dl; #ifdef BN_COUNT fprintf(stderr, " bn_sub_part_words %d + %d (dl > 0, c = %d)\n", cl, dl, c); #endif while(c) { t = a[0]; r[0] = (t-c)&BN_MASK2; if (t != 0) c=0; if (--dl <= 0) break; t = a[1]; r[1] = (t-c)&BN_MASK2; if (t != 0) c=0; if (--dl <= 0) break; t = a[2]; r[2] = (t-c)&BN_MASK2; if (t != 0) c=0; if (--dl <= 0) break; t = a[3]; r[3] = (t-c)&BN_MASK2; if (t != 0) c=0; if (--dl <= 0) break; save_dl = dl; a += 4; r += 4; } if (dl > 0) { #ifdef BN_COUNT fprintf(stderr, " bn_sub_part_words %d + %d (dl > 0, c == 0)\n", cl, dl); #endif 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_sub_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; }
/* BN_div_no_branch is a special version of BN_div. It does not contain * branches that may leak sensitive information. */ static int BN_div_no_branch(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); */ /* 'num' has been checked in BN_div() */ bn_check_top(divisor); if (BN_is_zero(divisor)) { BNerr(BN_F_BN_DIV_NO_BRANCH,BN_R_DIV_BY_ZERO); return(0); } 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; /* 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-1; resp= &(res->d[loop-1]); /* space for temp */ if (!bn_wexpand(tmp,(div_n+1))) goto err; /* 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 TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_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; q=bn_div_words(n0,n1,d0); #ifdef BN_DEBUG_LEVITTE TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_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 { 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); } bn_correct_top(res); BN_CTX_end(ctx); return(1); err: bn_check_top(rm); BN_CTX_end(ctx); return(0); }
// r is 2*n2 words in size, // a and b are both n2 words in size. // n2 must be a power of 2. // We multiply and return the result. // t must be 2*n2 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] // dnX may not be positive, but n2/2+dnX has to be 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) { 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) { OPENSSL_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 { OPENSSL_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 { OPENSSL_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 { OPENSSL_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; *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; *p = ln; } while (ln == 0); } } }
// n+tn is the word length // t needs to be n*4 is size, as does r // tnX may not be negative but less than n 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) { 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); OPENSSL_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); OPENSSL_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); OPENSSL_memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); } else { // (j < 0) eg, n == 16, i == 8 and tn == 5 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 { 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; *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; *p = ln; } while (ln == 0); } } }
/* r is 2*n2 words in size, * a and b are both n2 words in size. * n2 must be a power of 2. * We multiply and return the result. * t must be 2*n2 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_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, BN_ULONG *t) { int n=n2/2,c1,c2; unsigned int neg,zero; BN_ULONG ln,lo,*p; # ifdef BN_COUNT printf(" bn_mul_recursive %d * %d\n",n2,n2); # endif # ifdef BN_MUL_COMBA # if 0 if (n2 == 4) { bn_mul_comba4(r,a,b); return; } # endif if (n2 == 8) { bn_mul_comba8(r,a,b); return; } # endif /* BN_MUL_COMBA */ if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) { /* This should not happen */ bn_mul_normal(r,a,n2,b,n2); return; } /* r=(a[0]-a[1])*(b[1]-b[0]) */ c1=bn_cmp_words(a,&(a[n]),n); c2=bn_cmp_words(&(b[n]),b,n); zero=neg=0; switch (c1*3+c2) { case -4: bn_sub_words(t, &(a[n]),a, n); /* - */ bn_sub_words(&(t[n]),b, &(b[n]),n); /* - */ break; case -3: zero=1; break; case -2: bn_sub_words(t, &(a[n]),a, n); /* - */ bn_sub_words(&(t[n]),&(b[n]),b, n); /* + */ neg=1; break; case -1: case 0: case 1: zero=1; break; case 2: bn_sub_words(t, a, &(a[n]),n); /* + */ bn_sub_words(&(t[n]),b, &(b[n]),n); /* - */ neg=1; break; case 3: zero=1; break; case 4: bn_sub_words(t, a, &(a[n]),n); bn_sub_words(&(t[n]),&(b[n]),b, n); break; } # ifdef BN_MUL_COMBA if (n == 4) { 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) { 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 # endif /* BN_MUL_COMBA */ { p= &(t[n2*2]); if (!zero) bn_mul_recursive(&(t[n2]),t,&(t[n]),n,p); else memset(&(t[n2]),0,n2*sizeof(BN_ULONG)); bn_mul_recursive(r,a,b,n,p); bn_mul_recursive(&(r[n2]),&(a[n]),&(b[n]),n,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); } } }
static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) { BN_ULONG c, t; assert(cl >= 0); c = bn_sub_words(r, a, b, cl); if (dl == 0) { return c; } r += cl; a += cl; b += cl; if (dl < 0) { for (;;) { t = b[0]; r[0] = 0 - t - c; if (t != 0) { c = 1; } if (++dl >= 0) { break; } t = b[1]; r[1] = 0 - t - c; if (t != 0) { c = 1; } if (++dl >= 0) { break; } t = b[2]; r[2] = 0 - t - c; if (t != 0) { c = 1; } if (++dl >= 0) { break; } t = b[3]; r[3] = 0 - t - c; if (t != 0) { c = 1; } if (++dl >= 0) { break; } b += 4; r += 4; } } else { int save_dl = dl; while (c) { t = a[0]; r[0] = t - c; if (t != 0) { c = 0; } if (--dl <= 0) { break; } t = a[1]; r[1] = t - c; if (t != 0) { c = 0; } if (--dl <= 0) { break; } t = a[2]; r[2] = t - c; if (t != 0) { c = 0; } if (--dl <= 0) { break; } t = a[3]; r[3] = t - c; if (t != 0) { c = 0; } 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; } OPENSSL_FALLTHROUGH; case 2: r[2] = a[2]; if (--dl <= 0) { break; } OPENSSL_FALLTHROUGH; 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; }
/* n+tn is the word length * t needs to be n*4 is size, as does r */ void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int tn, int n, BN_ULONG *t) { int c1,c2,i,j,n2=n*2; unsigned int neg; BN_ULONG ln,lo,*p; # ifdef BN_COUNT printf(" bn_mul_part_recursive %d * %d\n",tn+n,tn+n); # endif if (n < 8) { i=tn+n; bn_mul_normal(r,a,i,b,i); return; } /* r=(a[0]-a[1])*(b[1]-b[0]) */ c1=bn_cmp_words(a,&(a[n]),n); c2=bn_cmp_words(&(b[n]),b,n); neg=0; switch (c1*3+c2) { case -4: bn_sub_words(t, &(a[n]),a, n); /* - */ bn_sub_words(&(t[n]),b, &(b[n]),n); /* - */ break; case -3: case -2: bn_sub_words(t, &(a[n]),a, n); /* - */ bn_sub_words(&(t[n]),&(b[n]),b, n); /* + */ neg=1; break; case -1: case 0: case 1: case 2: bn_sub_words(t, a, &(a[n]),n); /* + */ bn_sub_words(&(t[n]),b, &(b[n]),n); /* - */ neg=1; break; case 3: case 4: bn_sub_words(t, a, &(a[n]),n); bn_sub_words(&(t[n]),&(b[n]),b, 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]),tn,&(b[n]),tn); memset(&(r[n2+tn*2]),0,sizeof(BN_ULONG)*(n2-tn*2)); } else { p= &(t[n2*2]); bn_mul_recursive(&(t[n2]),t,&(t[n]),n,p); bn_mul_recursive(r,a,b,n,p); i=n/2; /* If there is only a bottom half to the number, * just do it */ j=tn-i; if (j == 0) { bn_mul_recursive(&(r[n2]),&(a[n]),&(b[n]),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]), j,i,p); memset(&(r[n2+tn*2]),0, sizeof(BN_ULONG)*(n2-tn*2)); } else /* (j < 0) eg, n == 16, i == 8 and tn == 5 */ { memset(&(r[n2]),0,sizeof(BN_ULONG)*n2); if (tn < BN_MUL_RECURSIVE_SIZE_NORMAL) { bn_mul_normal(&(r[n2]),&(a[n]),tn,&(b[n]),tn); } else { for (;;) { i/=2; if (i < tn) { bn_mul_part_recursive(&(r[n2]), &(a[n]),&(b[n]), tn-i,i,p); break; } else if (i == tn) { bn_mul_recursive(&(r[n2]), &(a[n]),&(b[n]), 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); } } }
/*- * 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); res = (dv == NULL) ? BN_CTX_get(ctx) : dv; tmp = BN_CTX_get(ctx); snum = BN_CTX_get(ctx); sdiv = BN_CTX_get(ctx); if (sdiv == 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; wnum.flags = BN_FLG_STATIC_DATA; /* * 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' */ if (!bn_wexpand(res, (loop + 1))) goto err; res->neg = (num->neg ^ divisor->neg); 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--; } /* Increase the resp pointer so that we never create an invalid pointer. */ resp++; /* * 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--) { 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--; *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; }
/* unsigned subtraction of b from a, a must be larger than b. */ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max, min, dif; register BN_ULONG t1, t2, *rp; register const BN_ULONG *ap, *bp; int i, carry; bn_check_top(a); bn_check_top(b); max = a->top; min = b->top; dif = max - min; if (dif < 0) { /* hmm... should not be happening */ BNerr(BN_F_BN_USUB, BN_R_ARG2_LT_ARG3); return (0); } if (bn_wexpand(r, max) == NULL) return (0); ap = a->d; bp = b->d; rp = r->d; #if 1 carry = 0; for (i = min; i != 0; i--) { t1 = *(ap++); t2 = *(bp++); if (carry) { carry = (t1 <= t2); t1 = (t1 - t2 - 1) & BN_MASK2; } else { carry = (t1 < t2); t1 = (t1 - t2) & BN_MASK2; } *(rp++) = t1 & BN_MASK2; } #else carry = bn_sub_words(rp, ap, bp, min); ap += min; bp += min; rp += min; #endif if (carry) { /* subtracted */ if (!dif) /* error: a < b */ return 0; while (dif) { dif--; t1 = *(ap++); t2 = (t1 - 1) & BN_MASK2; *(rp++) = t2; if (t1) break; } } memcpy(rp, ap, sizeof(*rp) * dif); r->top = max; r->neg = 0; bn_correct_top(r); return (1); }
int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) { int retn=0; #ifdef MONT_WORD BIGNUM *n,*r; BN_ULONG *ap,*np,*rp,n0,v,*nrp; int al,nl,max,i,x,ri; BN_CTX_start(ctx); if ((r = BN_CTX_get(ctx)) == NULL) goto err; if (!BN_copy(r,a)) goto err; n= &(mont->N); ap=a->d; /* mont->ri is the size of mont->N in bits (rounded up to the word size) */ al=ri=mont->ri/BN_BITS2; nl=n->top; if ((al == 0) || (nl == 0)) { r->top=0; return(1); } max=(nl+al+1); /* allow for overflow (no?) XXX */ if (bn_wexpand(r,max) == NULL) goto err; r->neg=a->neg^n->neg; np=n->d; rp=r->d; nrp= &(r->d[nl]); /* clear the top words of T */ #if 1 for (i=r->top; i<max; i++) /* memset? XXX */ r->d[i]=0; #else memset(&(r->d[r->top]),0,(max-r->top)*sizeof(BN_ULONG)); #endif r->top=max; n0=mont->n0; #ifdef BN_COUNT fprintf(stderr,"word BN_from_montgomery %d * %d\n",nl,nl); #endif for (i=0; i<nl; i++) { #ifdef __TANDEM { long long t1; long long t2; long long t3; t1 = rp[0] * (n0 & 0177777); t2 = 037777600000l; t2 = n0 & t2; t3 = rp[0] & 0177777; t2 = (t3 * t2) & BN_MASK2; t1 = t1 + t2; v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1); } #else v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2); #endif nrp++; rp++; if (((nrp[-1]+=v)&BN_MASK2) >= v) continue; else { if (((++nrp[0])&BN_MASK2) != 0) continue; if (((++nrp[1])&BN_MASK2) != 0) continue; for (x=2; (((++nrp[x])&BN_MASK2) == 0); x++) ; } } bn_correct_top(r); /* mont->ri will be a multiple of the word size and below code * is kind of BN_rshift(ret,r,mont->ri) equivalent */ if (r->top <= ri) { ret->top=0; retn=1; goto err; } al=r->top-ri; # define BRANCH_FREE 1 # if BRANCH_FREE if (bn_wexpand(ret,ri) == NULL) goto err; x=0-(((al-ri)>>(sizeof(al)*8-1))&1); ret->top=x=(ri&~x)|(al&x); /* min(ri,al) */ ret->neg=r->neg; rp=ret->d; ap=&(r->d[ri]); { size_t m1,m2; v=bn_sub_words(rp,ap,np,ri); /* this ----------------^^ works even in al<ri case * thanks to zealous zeroing of top of the vector in the * beginning. */ /* if (al==ri && !v) || al>ri) nrp=rp; else nrp=ap; */ /* in other words if subtraction result is real, then * trick unconditional memcpy below to perform in-place * "refresh" instead of actual copy. */ m1=0-(size_t)(((al-ri)>>(sizeof(al)*8-1))&1); /* al<ri */ m2=0-(size_t)(((ri-al)>>(sizeof(al)*8-1))&1); /* al>ri */ m1|=m2; /* (al!=ri) */ m1|=(0-(size_t)v); /* (al!=ri || v) */ m1&=~m2; /* (al!=ri || v) && !al>ri */ nrp=(BN_ULONG *)(((size_t)rp&~m1)|((size_t)ap&m1)); } /* 'i<ri' is chosen to eliminate dependency on input data, even * though it results in redundant copy in al<ri case. */ for (i=0,ri-=4; i<ri; i+=4) { BN_ULONG t1,t2,t3,t4; t1=nrp[i+0]; t2=nrp[i+1]; t3=nrp[i+2]; ap[i+0]=0; t4=nrp[i+3]; ap[i+1]=0; rp[i+0]=t1; ap[i+2]=0; rp[i+1]=t2; ap[i+3]=0; rp[i+2]=t3; rp[i+3]=t4; } for (ri+=4; i<ri; i++) rp[i]=nrp[i], ap[i]=0; bn_correct_top(r); bn_correct_top(ret); # else if (bn_wexpand(ret,al) == NULL) goto err; ret->top=al; ret->neg=r->neg; rp=ret->d; ap=&(r->d[ri]); al-=4; for (i=0; i<al; i+=4) { BN_ULONG t1,t2,t3,t4; t1=ap[i+0]; t2=ap[i+1]; t3=ap[i+2]; t4=ap[i+3]; rp[i+0]=t1; rp[i+1]=t2; rp[i+2]=t3; rp[i+3]=t4; } al+=4; for (; i<al; i++) rp[i]=ap[i]; # endif #else /* !MONT_WORD */ BIGNUM *t1,*t2; BN_CTX_start(ctx); 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); if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err; BN_mask_bits(t2,mont->ri); if (!BN_mul(t1,t2,&mont->N,ctx)) goto err; if (!BN_add(t2,a,t1)) goto err; if (!BN_rshift(ret,t2,mont->ri)) goto err; #endif /* MONT_WORD */ #if !defined(BRANCH_FREE) || BRANCH_FREE==0 if (BN_ucmp(ret, &(mont->N)) >= 0) { if (!BN_usub(ret,ret,&(mont->N))) goto err; } #endif retn=1; bn_check_top(ret); err: BN_CTX_end(ctx); return(retn); }
// 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] static 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; if (n2 == 4) { bn_sqr_comba4(r, a); return; } else if (n2 == 8) { bn_sqr_comba8(r, a); 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 { OPENSSL_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; *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; *p = ln; } while (ln == 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; # ifdef BN_COUNT fprintf(stderr," bn_mul_high %d * %d\n",n2,n2); # endif 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]); c1=(int)(bn_add_words(lp,&(r[0]),&(l[0]),n)); } else { c1=0; 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); } } }
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_CTX *ctx) { int norm_shift,i,loop; BIGNUM *tmp,*snum,*sdiv,*res; #ifdef BN_ALLOC /* pcg */ BIGNUM wnum; #else BN_ULONG *wnum_d; #endif /* !BN_ALLOC */ BN_ULONG *resp,*wnump; BN_ULONG d0,d1; int num_n,div_n; /* Invalid zero-padding would have particularly bad consequences * in the case of 'num', so don't just rely on bn_check_top() for this one * (bn_check_top() works only for BN_DEBUG builds) */ if (num->top > 0 && num->d[num->top - 1] == 0) { BNerr(BN_F_BN_DIV,BN_R_NOT_INITIALIZED); return 0; } bn_check_top(num); if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0) || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) { return BN_div_no_branch(dv, rm, num, divisor, ctx); } bn_check_top(dv); bn_check_top(rm); /* bn_check_top(num); */ /* 'num' has been checked already */ bn_check_top(divisor); if (BN_is_zero(divisor)) { BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); 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_ext( ctx, BIGNUM_EXT_MUL1 ); /* pcg */ 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; 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 */ #ifdef BN_ALLOC /* pcg */ 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 */ #else wnum_d = &(snum->d[loop]); #endif /* BN_ALLOC */ /* 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( div_n+1 > BIGNUM_ALLOC_WORDS ) { assert( 0 ); goto err; } if (BN_ucmp_word(wnum_d,div_n,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; #if !defined( BN_UMULT_LOHI ) && !defined( BN_UMULT_HIGH ) /* pcg */ BN_ULONG ql,qh; #endif 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 { 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); } BN_CTX_end_ext( ctx, BIGNUM_EXT_MUL1 ); /* pcg */ return(1); err: bn_check_top(rm); BN_CTX_end_ext( ctx, BIGNUM_EXT_MUL1 ); /* pcg */ return(0); }
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont) { BIGNUM *n; BN_ULONG *ap, *np, *rp, n0, v, carry; int nl, max, i; n = &(mont->N); nl = n->top; if (nl == 0) { ret->top = 0; return (1); } max = (2 * nl); /* carry is stored separately */ if (bn_wexpand(r, max) == NULL) return (0); r->neg ^= n->neg; np = n->d; rp = r->d; /* clear the top words of T */ #if 1 for (i=r->top; i<max; i++) /* memset? XXX */ rp[i] = 0; #else memset(&(rp[r->top]), 0, (max - r->top) * sizeof(BN_ULONG)); #endif r->top = max; n0 = mont->n0[0]; #ifdef BN_COUNT fprintf(stderr, "word BN_from_montgomery_word %d * %d\n", nl, nl); #endif for (carry = 0, i = 0; i < nl; i++, rp++) { v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); v = (v + carry + rp[nl]) & BN_MASK2; carry |= (v != rp[nl]); carry &= (v <= rp[nl]); rp[nl] = v; } if (bn_wexpand(ret, nl) == NULL) return (0); ret->top = nl; ret->neg = r->neg; rp = ret->d; ap = &(r->d[nl]); #define BRANCH_FREE 1 #if BRANCH_FREE { BN_ULONG *nrp; size_t m; v = bn_sub_words(rp, ap, np, nl) - carry; /* if subtraction result is real, then * trick unconditional memcpy below to perform in-place * "refresh" instead of actual copy. */ m = (0 - (size_t)v); nrp = (BN_ULONG *)(((uintptr_t)rp & ~m)|((uintptr_t)ap & m)); for (i = 0, nl -= 4; i < nl; i += 4) { BN_ULONG t1, t2, t3, t4; t1 = nrp[i + 0]; t2 = nrp[i + 1]; t3 = nrp[i + 2]; ap[i + 0] = 0; t4 = nrp[i + 3]; ap[i + 1] = 0; rp[i + 0] = t1; ap[i + 2] = 0; rp[i + 1] = t2; ap[i + 3] = 0; rp[i + 2] = t3; rp[i + 3] = t4; } for (nl += 4; i < nl; i++) rp[i] = nrp[i], ap[i] = 0; } #else if (bn_sub_words (rp, ap, np, nl) - carry) memcpy(rp, ap, nl*sizeof(BN_ULONG)); #endif bn_correct_top(r); bn_correct_top(ret); bn_check_top(ret); return (1); }
static void bn_abs_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, size_t num, BN_ULONG *tmp) { BN_ULONG borrow = bn_sub_words(tmp, a, b, num); bn_sub_words(r, b, a, num); bn_select_words(r, 0 - borrow, r /* tmp < 0 */, tmp /* tmp >= 0 */, num); }
/* r is 2*n words in size, * a and b are both n words in size. * 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, BN_ULONG *a, int n2, BN_ULONG *t) { int n=n2/2; int zero,c1; BN_ULONG ln,lo,*p; #ifdef BN_COUNT printf(" 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,n*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); } } }
int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *field, BN_CTX *ctx) { #if BN_BITS2 != 64 int top = a->top, i; int carry = 0; BN_ULONG *r_d, *a_d = a->d; BN_ULONG t_d[BN_NIST_224_TOP], buf[BN_NIST_224_TOP]; i = BN_ucmp(field, a); if (i == 0) { BN_zero(r); return 1; } else if (i > 0) return (r == a)? 1 : (BN_copy(r ,a) != NULL); if (top == BN_NIST_224_TOP) return BN_usub(r, a, field); if (r != a) { if (!bn_wexpand(r, BN_NIST_224_TOP)) return 0; r_d = r->d; nist_cp_bn(r_d, a_d, BN_NIST_224_TOP); } else r_d = a_d; nist_cp_bn_0(buf, a_d + BN_NIST_224_TOP, top - BN_NIST_224_TOP, BN_NIST_224_TOP); nist_set_224(t_d, buf, 10, 9, 8, 7, 0, 0, 0); if (bn_add_words(r_d, r_d, t_d, BN_NIST_224_TOP)) ++carry; nist_set_224(t_d, buf, 0, 13, 12, 11, 0, 0, 0); if (bn_add_words(r_d, r_d, t_d, BN_NIST_224_TOP)) ++carry; nist_set_224(t_d, buf, 13, 12, 11, 10, 9, 8, 7); if (bn_sub_words(r_d, r_d, t_d, BN_NIST_224_TOP)) --carry; nist_set_224(t_d, buf, 0, 0, 0, 0, 13, 12, 11); if (bn_sub_words(r_d, r_d, t_d, BN_NIST_224_TOP)) --carry; if (carry > 0) while (carry) { if (bn_sub_words(r_d,r_d,_nist_p_224,BN_NIST_224_TOP)) --carry; } else if (carry < 0) while (carry) { if (bn_add_words(r_d,r_d,_nist_p_224,BN_NIST_224_TOP)) ++carry; } r->top = BN_NIST_224_TOP; bn_correct_top(r); if (BN_ucmp(r, field) >= 0) { bn_sub_words(r_d, r_d, _nist_p_224, BN_NIST_224_TOP); bn_correct_top(r); } bn_check_top(r); return 1; #else return 0; #endif }
BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) { BN_ULONG c, t; assert(cl >= 0); c = bn_sub_words(r, a, b, cl); if (dl == 0) return c; r += cl; a += cl; b += cl; if (dl < 0) { for (;;) { t = b[0]; r[0] = (0 - t - c) & BN_MASK2; if (t != 0) c = 1; if (++dl >= 0) break; t = b[1]; r[1] = (0 - t - c) & BN_MASK2; if (t != 0) c = 1; if (++dl >= 0) break; t = b[2]; r[2] = (0 - t - c) & BN_MASK2; if (t != 0) c = 1; if (++dl >= 0) break; t = b[3]; r[3] = (0 - t - c) & BN_MASK2; if (t != 0) c = 1; if (++dl >= 0) break; b += 4; r += 4; } } else { int save_dl = dl; while (c) { t = a[0]; r[0] = (t - c) & BN_MASK2; if (t != 0) c = 0; if (--dl <= 0) break; t = a[1]; r[1] = (t - c) & BN_MASK2; if (t != 0) c = 0; if (--dl <= 0) break; t = a[2]; r[2] = (t - c) & BN_MASK2; if (t != 0) c = 0; if (--dl <= 0) break; t = a[3]; r[3] = (t - c) & BN_MASK2; if (t != 0) c = 0; 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; /* fall thru */ case 2: r[2] = a[2]; if (--dl <= 0) break; /* fall thru */ 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; }
int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *field, BN_CTX *ctx) { #if BN_BITS2 != 64 int i, top = a->top; int carry = 0; register BN_ULONG *r_d, *a_d = a->d; BN_ULONG t_d[BN_NIST_384_TOP], buf[BN_NIST_384_TOP]; if (!_is_set_384_data) { CRYPTO_w_lock(CRYPTO_LOCK_BN); if (!_is_set_384_data) _init_384_data(); CRYPTO_w_unlock(CRYPTO_LOCK_BN); } i = BN_ucmp(field, a); if (i == 0) { BN_zero(r); return 1; } else if (i > 0) return (r == a)? 1 : (BN_copy(r ,a) != NULL); if (top == BN_NIST_384_TOP) return BN_usub(r, a, field); if (r != a) { if (!bn_wexpand(r, BN_NIST_384_TOP)) return 0; r_d = r->d; nist_cp_bn(r_d, a_d, BN_NIST_384_TOP); } else r_d = a_d; nist_cp_bn_0(buf, a_d + BN_NIST_384_TOP, top - BN_NIST_384_TOP, BN_NIST_384_TOP); /*S1*/ nist_set_256(t_d, buf, 0, 0, 0, 0, 0, 23-4, 22-4, 21-4); /* left shift */ { register BN_ULONG *ap,t,c; ap = t_d; c=0; for (i = BN_NIST_256_TOP; i != 0; --i) { t= *ap; *(ap++)=((t<<1)|c)&BN_MASK2; c=(t & BN_TBIT)?1:0; } } if (bn_add_words(r_d+(128/BN_BITS2), r_d+(128/BN_BITS2), t_d, BN_NIST_256_TOP)) ++carry; /*S2 */ if (bn_add_words(r_d, r_d, buf, BN_NIST_384_TOP)) ++carry; /*S3*/ nist_set_384(t_d,buf,20,19,18,17,16,15,14,13,12,23,22,21); if (bn_add_words(r_d, r_d, t_d, BN_NIST_384_TOP)) ++carry; /*S4*/ nist_set_384(t_d,buf,19,18,17,16,15,14,13,12,20,0,23,0); if (bn_add_words(r_d, r_d, t_d, BN_NIST_384_TOP)) ++carry; /*S5*/ nist_set_256(t_d, buf, 0, 0, 0, 0, 23-4, 22-4, 21-4, 20-4); if (bn_add_words(r_d+(128/BN_BITS2), r_d+(128/BN_BITS2), t_d, BN_NIST_256_TOP)) ++carry; /*S6*/ nist_set_384(t_d,buf,0,0,0,0,0,0,23,22,21,0,0,20); if (bn_add_words(r_d, r_d, t_d, BN_NIST_384_TOP)) ++carry; /*D1*/ nist_set_384(t_d,buf,22,21,20,19,18,17,16,15,14,13,12,23); if (bn_sub_words(r_d, r_d, t_d, BN_NIST_384_TOP)) --carry; /*D2*/ nist_set_384(t_d,buf,0,0,0,0,0,0,0,23,22,21,20,0); if (bn_sub_words(r_d, r_d, t_d, BN_NIST_384_TOP)) --carry; /*D3*/ nist_set_384(t_d,buf,0,0,0,0,0,0,0,23,23,0,0,0); if (bn_sub_words(r_d, r_d, t_d, BN_NIST_384_TOP)) --carry; if (carry) { if (carry > 0) bn_sub_words(r_d, r_d, _384_data + BN_NIST_384_TOP * --carry, BN_NIST_384_TOP); else { carry = -carry; bn_add_words(r_d, r_d, _384_data + BN_NIST_384_TOP * --carry, BN_NIST_384_TOP); } } r->top = BN_NIST_384_TOP; bn_correct_top(r); if (BN_ucmp(r, field) >= 0) { bn_sub_words(r_d, r_d, _nist_p_384, BN_NIST_384_TOP); bn_correct_top(r); } bn_check_top(r); return 1; #else return 0; #endif }
int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *field, BN_CTX *ctx) { int top = a->top, i; BN_ULONG carry = 0; register BN_ULONG *r_d, *a_d = a->d; BN_ULONG t_d[BN_NIST_192_TOP], buf[BN_NIST_192_TOP]; i = BN_ucmp(field, a); if (i == 0) { BN_zero(r); return 1; } else if (i > 0) return (r == a) ? 1 : (BN_copy(r ,a) != NULL); if (top == BN_NIST_192_TOP) return BN_usub(r, a, field); if (r != a) { if (!bn_wexpand(r, BN_NIST_192_TOP)) return 0; r_d = r->d; nist_cp_bn(r_d, a_d, BN_NIST_192_TOP); } else r_d = a_d; nist_cp_bn_0(buf, a_d + BN_NIST_192_TOP, top - BN_NIST_192_TOP, BN_NIST_192_TOP); #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma message save # pragma message disable BADSUBSCRIPT #endif nist_set_192(t_d, buf, 0, 3, 3); if (bn_add_words(r_d, r_d, t_d, BN_NIST_192_TOP)) ++carry; nist_set_192(t_d, buf, 4, 4, 0); if (bn_add_words(r_d, r_d, t_d, BN_NIST_192_TOP)) ++carry; #if defined(OPENSSL_SYS_VMS) && defined(__DECC) # pragma message restore #endif nist_set_192(t_d, buf, 5, 5, 5) if (bn_add_words(r_d, r_d, t_d, BN_NIST_192_TOP)) ++carry; while (carry) { if (bn_sub_words(r_d, r_d, _nist_p_192, BN_NIST_192_TOP)) --carry; } r->top = BN_NIST_192_TOP; bn_correct_top(r); if (BN_ucmp(r, field) >= 0) { bn_sub_words(r_d, r_d, _nist_p_192, BN_NIST_192_TOP); bn_correct_top(r); } bn_check_top(r); return 1; }
/* unsigned subtraction of b from a, a must be larger than b. */ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max,min; register BN_ULONG t1,t2,*ap,*bp,*rp; int i,carry; #if defined(IRIX_CC_BUG) && !defined(LINT) int dummy; #endif bn_check_top(a); bn_check_top(b); if (a->top < b->top) /* hmm... should not be happening */ { return(0); } max=a->top; min=b->top; if (bn_wexpand(r,max) == NULL) return(0); ap=a->d; bp=b->d; rp=r->d; #if 1 carry=0; for (i=0; i<min; i++) { t1= *(ap++); t2= *(bp++); if (carry) { carry=(t1 <= t2); t1=(t1-t2-1)&BN_MASK2; } else { carry=(t1 < t2); t1=(t1-t2)&BN_MASK2; } #if defined(IRIX_CC_BUG) && !defined(LINT) dummy=t1; #endif *(rp++)=t1&BN_MASK2; } #else carry=bn_sub_words(rp,ap,bp,min); ap+=min; bp+=min; rp+=min; i=min; #endif if (carry) /* subtracted */ { while (i < max) { i++; t1= *(ap++); t2=(t1-1)&BN_MASK2; *(rp++)=t2; if (t1 > t2) break; } } #if 0 memcpy(rp,ap,sizeof(*rp)*(max-i)); #else if (rp != ap) { for (;;) { if (i++ >= max) break; rp[0]=ap[0]; if (i++ >= max) break; rp[1]=ap[1]; if (i++ >= max) break; rp[2]=ap[2]; if (i++ >= max) break; rp[3]=ap[3]; rp+=4; ap+=4; } } #endif r->top=max; bn_fix_top(r); return(1); }