int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { const BIGNUM *tmp; int a_neg = a->neg, ret; // a + b a+b // a + -b a-b // -a + b b-a // -a + -b -(a+b) if (a_neg ^ b->neg) { // only one is negative if (a_neg) { tmp = a; a = b; b = tmp; } // we are now a - b if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) { return 0; } r->neg = 1; } else { if (!BN_usub(r, a, b)) { return 0; } r->neg = 0; } return 1; } ret = BN_uadd(r, a, b); r->neg = a_neg; return ret; }
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max; int add = 0, neg = 0; bn_check_top(a); bn_check_top(b); /*- * a - b a-b * a - -b a+b * -a - b -(a+b) * -a - -b b-a */ if (a->neg) { if (b->neg) { const BIGNUM *tmp; tmp = a; a = b; b = tmp; } else { add = 1; neg = 1; } } else { if (b->neg) { add = 1; neg = 0; } } if (add) { if (!BN_uadd(r, a, b)) return 0; r->neg = neg; return 1; } /* We are actually doing a - b :-) */ max = (a->top > b->top) ? a->top : b->top; if (bn_wexpand(r, max) == NULL) return 0; if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) return 0; r->neg = 1; } else { if (!BN_usub(r, a, b)) return 0; r->neg = 0; } bn_check_top(r); return 1; }
int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) { int i,nm,nd; int ret = 0; BIGNUM *D; bn_check_top(m); bn_check_top(d); if (BN_is_zero(d)) { BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); return(0); } if (BN_ucmp(m,d) < 0) { if (rem != NULL) { if (BN_copy(rem,m) == NULL) return(0); } if (dv != NULL) BN_zero(dv); return(1); } BN_CTX_start(ctx); D = BN_CTX_get(ctx); if (dv == NULL) dv = BN_CTX_get(ctx); if (rem == NULL) rem = BN_CTX_get(ctx); if (D == NULL || dv == NULL || rem == NULL) goto end; nd=BN_num_bits(d); nm=BN_num_bits(m); if (BN_copy(D,d) == NULL) goto end; if (BN_copy(rem,m) == NULL) goto end; /* The next 2 are needed so we can do a dv->d[0]|=1 later * since BN_lshift1 will only work once there is a value :-) */ BN_zero(dv); if(bn_wexpand(dv,1) == NULL) goto end; dv->top=1; if (!BN_lshift(D,D,nm-nd)) goto end; for (i=nm-nd; i>=0; i--) { if (!BN_lshift1(dv,dv)) goto end; if (BN_ucmp(rem,D) >= 0) { dv->d[0]|=1; if (!BN_usub(rem,rem,D)) goto end; } /* CAN IMPROVE (and have now :=) */ if (!BN_rshift1(D,D)) goto end; } rem->neg=BN_is_zero(rem)?0:m->neg; dv->neg=m->neg^d->neg; ret = 1; end: BN_CTX_end(ctx); return(ret); }
/* BN_mod_add variant that may be used if both a and b are non-negative * and less than m */ int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m) { if (!BN_uadd(r, a, b)) return 0; if (BN_ucmp(r, m) >= 0) return BN_usub(r, r, m); return 1; }
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int add = 0, neg = 0; const BIGNUM *tmp; // a - b a-b // a - -b a+b // -a - b -(a+b) // -a - -b b-a if (a->neg) { if (b->neg) { tmp = a; a = b; b = tmp; } else { add = 1; neg = 1; } } else { if (b->neg) { add = 1; neg = 0; } } if (add) { if (!BN_uadd(r, a, b)) { return 0; } r->neg = neg; return 1; } if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) { return 0; } r->neg = 1; } else { if (!BN_usub(r, a, b)) { return 0; } r->neg = 0; } return 1; }
int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y)) /* point is its own inverse */ return 1; return BN_usub(point->Y, group->field, point->Y); }
/* r can == a or b */ int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int a_neg = a->neg, ret; bn_check_top(a); bn_check_top(b); /*- * a + b a+b * a + -b a-b * -a + b b-a * -a + -b -(a+b) */ if (a_neg ^ b->neg) { /* only one is negative */ if (a_neg) { const BIGNUM *tmp; tmp = a; a = b; b = tmp; } /* we are now a - b */ if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) return 0; r->neg = 1; } else { if (!BN_usub(r, a, b)) return 0; r->neg = 0; } return 1; } ret = BN_uadd(r, a, b); r->neg = a_neg; bn_check_top(r); return ret; }
/* r can == a or b */ int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { const BIGNUM *tmp; bn_check_top(a); bn_check_top(b); /* a + b a+b * a + -b a-b * -a + b b-a * -a + -b -(a+b) */ if (a->neg ^ b->neg) { /* only one is negative */ if (a->neg) { tmp=a; a=b; b=tmp; } /* we are now a - b */ if (BN_ucmp(a,b) < 0) { if (!BN_usub(r,b,a)) return(0); r->neg=1; } else { if (!BN_usub(r,a,b)) return(0); r->neg=0; } return(1); } if (a->neg) /* both are neg */ r->neg=1; else r->neg=0; if (!BN_uadd(r,a,b)) return(0); return(1); }
static RSA * fermat_question_ask(const RSA *rsa) { BIGNUM *a = BN_new(), *b = BN_new(), *a2 = BN_new(), *b2 = BN_new(); BIGNUM *n = rsa->n; BIGNUM *tmp = BN_new(), *rem = BN_new(), *dssdelta = BN_new(); BN_CTX *ctx = BN_CTX_new(); RSA *ret = NULL; BN_sqrtmod(tmp, rem, n, ctx); /* Δ = |p - q| = |a + b - a + b| = |2b| > √N 2⁻¹⁰⁰ */ /* BN_rshift(dssdelta, tmp, 101); */ BN_one(dssdelta); BN_lshift(dssdelta, dssdelta, BN_num_bits(n) / 4 + 10); BN_copy(a, tmp); BN_sqr(a2, a, ctx); do { /* a² += 2a + 1 */ BN_lshift1(tmp, a); BN_uiadd1(tmp); BN_add(a2, a2, tmp); /* a += 1 */ BN_uiadd1(a); /* b² = a² - N */ BN_usub(b2, a2, n); /* b */ BN_sqrtmod(b, rem, b2, ctx); } while (!BN_is_zero(rem) && BN_cmp(b, dssdelta) < 1); if (BN_is_zero(rem)) { BN_uadd(a, a, b); ret = qa_RSA_recover(rsa, a, ctx); } BN_CTX_free(ctx); BN_free(a); BN_free(b); BN_free(a2); BN_free(b2); BN_free(dssdelta); BN_free(tmp); BN_free(rem); return ret; }
int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) { int retn = 0; #ifdef MONT_WORD BIGNUM *t; BN_CTX_start(ctx); if ((t = BN_CTX_get(ctx)) && BN_copy(t, a)) { retn = bn_from_montgomery_word(ret, t, mont); bn_correct_top(ret); bn_check_top(ret); } BN_CTX_end(ctx); #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; if (BN_ucmp(ret, &(mont->N)) >= 0) { if (!BN_usub(ret, ret, &(mont->N))) goto err; } retn = 1; bn_check_top(ret); err: BN_CTX_end(ctx); #endif /* MONT_WORD */ return (retn); }
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 }
int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x_, int y_bit, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BIGNUM *tmp1, *tmp2, *x, *y; int ret = 0; ERR_clear_error(); if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } y_bit = (y_bit != 0); BN_CTX_start(ctx); tmp1 = BN_CTX_get(ctx); tmp2 = BN_CTX_get(ctx); x = BN_CTX_get(ctx); y = BN_CTX_get(ctx); if (y == NULL) { goto err; } /* Recover y. We have a Weierstrass equation * y^2 = x^3 + a*x + b, * so y is one of the square roots of x^3 + a*x + b. */ /* tmp1 := x^3 */ if (!BN_nnmod(x, x_, &group->field, ctx)) { goto err; } if (group->meth->field_decode == 0) { /* field_{sqr,mul} work on standard representation */ if (!group->meth->field_sqr(group, tmp2, x_, ctx) || !group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) { goto err; } } else { if (!BN_mod_sqr(tmp2, x_, &group->field, ctx) || !BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) { goto err; } } /* tmp1 := tmp1 + a*x */ if (group->a_is_minus3) { if (!BN_mod_lshift1_quick(tmp2, x, &group->field) || !BN_mod_add_quick(tmp2, tmp2, x, &group->field) || !BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) { goto err; } } else { if (group->meth->field_decode) { if (!group->meth->field_decode(group, tmp2, &group->a, ctx) || !BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) { goto err; } } else { /* field_mul works on standard representation */ if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) { goto err; } } if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { goto err; } } /* tmp1 := tmp1 + b */ if (group->meth->field_decode) { if (!group->meth->field_decode(group, tmp2, &group->b, ctx) || !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { goto err; } } else { if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) { goto err; } } if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) { unsigned long err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { ERR_clear_error(); OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, EC_R_INVALID_COMPRESSED_POINT); } else { OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, ERR_R_BN_LIB); } goto err; } if (y_bit != BN_is_odd(y)) { if (BN_is_zero(y)) { int kron; kron = BN_kronecker(x, &group->field, ctx); if (kron == -2) { goto err; } if (kron == 1) { OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, EC_R_INVALID_COMPRESSION_BIT); } else { /* BN_mod_sqrt() should have cought this error (not a square) */ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, EC_R_INVALID_COMPRESSED_POINT); } goto err; } if (!BN_usub(y, &group->field, y)) { goto err; } } if (y_bit != BN_is_odd(y)) { OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, ERR_R_INTERNAL_ERROR); goto err; } if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; ret = 1; err: BN_CTX_end(ctx); if (new_ctx != NULL) BN_CTX_free(new_ctx); return ret; }
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_CTX *ctx) { int norm_shift,i,j,loop; BIGNUM *tmp,wnum,*snum,*sdiv,*res; BN_ULONG *resp,*wnump; BN_ULONG d0,d1; int num_n,div_n; bn_check_top(num); bn_check_top(divisor); if (BN_is_zero(divisor)) 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; tmp->neg=0; /* 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 */ BN_init(&wnum); wnum.d= &(snum->d[loop]); wnum.top= div_n; wnum.dmax= snum->dmax+1; /* a bit of a lie */ /* Get the top 2 words of sdiv */ /* i=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_usub(&wnum,&wnum,sdiv)) goto err; *resp=1; res->d[res->top-1]=1; } else res->top--; resp--; for (i=0; i<loop-1; i++) { BN_ULONG q,l0; BN_ULONG n0,n1,rem=0; n0=wnump[0]; n1=wnump[-1]; if (n0 == d0) q=BN_MASK2; else /* n0 < d0 */ { BN_ULONG t2l,t2h,ql,qh; q=bn_div_words(n0,n1,d0); rem=(n1-q*d0)&BN_MASK2; t2l=LBITS(d1); t2h=HBITS(d1); ql =LBITS(q); qh =HBITS(q); mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ 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; } } l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); wnum.d--; wnum.top++; tmp->d[div_n]=l0; for (j=div_n+1; j>0; j--) if (tmp->d[j-1]) break; tmp->top=j; j=wnum.top; if (!BN_sub(&wnum,&wnum,tmp)) goto err; snum->top=snum->top+wnum.top-j; if (wnum.neg) { q--; j=wnum.top; if (!BN_add(&wnum,&wnum,sdiv)) goto err; snum->top+=wnum.top-j; } *(resp--)=q; wnump--; } if (rm != NULL) { BN_rshift(rm,snum,norm_shift); rm->neg=num->neg; } BN_CTX_end(ctx); return(1); err: BN_CTX_end(ctx); return(0); }
int BN_from_montgomery(BIGNUM *ret, BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) { int retn=0; 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; if (bn_wexpand(ret,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 */ for (i=r->top; i<max; i++) /* memset? XXX */ r->d[i]=0; r->top=max; n0=mont->n0; for (i=0; i<nl; i++) { v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2); 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_fix_top(r); /* mont->ri will be a multiple of the word size */ ret->neg = r->neg; x=ri; rp=ret->d; ap= &(r->d[x]); if (r->top < x) al=0; else al=r->top-x; ret->top=al; 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]; if (BN_ucmp(ret, &(mont->N)) >= 0) { BN_usub(ret,ret,&(mont->N)); } retn=1; err: BN_CTX_end(ctx); return(retn); }
BIGNUM *BN_mod_inverse(BIGNUM *in, const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) { BIGNUM *A,*B,*X,*Y,*M,*D,*T,*R=NULL; BIGNUM *ret=NULL; int sign; if ((BN_get_flags(a, BN_FLG_CONSTTIME) != 0) || (BN_get_flags(n, BN_FLG_CONSTTIME) != 0)) { return BN_mod_inverse_no_branch(in, a, n, ctx); } bn_check_top(a); bn_check_top(n); BN_CTX_start(ctx); A = BN_CTX_get(ctx); B = BN_CTX_get(ctx); X = BN_CTX_get(ctx); D = BN_CTX_get(ctx); M = BN_CTX_get(ctx); Y = BN_CTX_get(ctx); T = BN_CTX_get(ctx); if (T == NULL) goto err; if (in == NULL) R=BN_new(); else R=in; if (R == NULL) goto err; BN_one(X); BN_zero(Y); if (BN_copy(B,a) == NULL) goto err; if (BN_copy(A,n) == NULL) goto err; A->neg = 0; if (B->neg || (BN_ucmp(B, A) >= 0)) { if (!BN_nnmod(B, B, A, ctx)) goto err; } sign = -1; /* From B = a mod |n|, A = |n| it follows that * * 0 <= B < A, * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). */ if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS <= 32 ? 450 : 2048))) { /* Binary inversion algorithm; requires odd modulus. * This is faster than the general algorithm if the modulus * is sufficiently small (about 400 .. 500 bits on 32-bit * sytems, but much more on 64-bit systems) */ int shift; while (!BN_is_zero(B)) { /* * 0 < B < |n|, * 0 < A <= |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|) */ /* Now divide B by the maximum possible power of two in the integers, * and divide X by the same value mod |n|. * When we're done, (1) still holds. */ shift = 0; while (!BN_is_bit_set(B, shift)) /* note that 0 < B */ { shift++; if (BN_is_odd(X)) { if (!BN_uadd(X, X, n)) goto err; } /* now X is even, so we can easily divide it by two */ if (!BN_rshift1(X, X)) goto err; } if (shift > 0) { if (!BN_rshift(B, B, shift)) goto err; } /* Same for A and Y. Afterwards, (2) still holds. */ shift = 0; while (!BN_is_bit_set(A, shift)) /* note that 0 < A */ { shift++; if (BN_is_odd(Y)) { if (!BN_uadd(Y, Y, n)) goto err; } /* now Y is even */ if (!BN_rshift1(Y, Y)) goto err; } if (shift > 0) { if (!BN_rshift(A, A, shift)) goto err; } /* We still have (1) and (2). * Both A and B are odd. * The following computations ensure that * * 0 <= B < |n|, * 0 < A < |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|), * * and that either A or B is even in the next iteration. */ if (BN_ucmp(B, A) >= 0) { /* -sign*(X + Y)*a == B - A (mod |n|) */ if (!BN_uadd(X, X, Y)) goto err; /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that * actually makes the algorithm slower */ if (!BN_usub(B, B, A)) goto err; } else { /* sign*(X + Y)*a == A - B (mod |n|) */ if (!BN_uadd(Y, Y, X)) goto err; /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ if (!BN_usub(A, A, B)) goto err; } } } else { /* general inversion algorithm */ while (!BN_is_zero(B)) { BIGNUM *tmp; /* * 0 < B < A, * (*) -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|) */ /* (D, M) := (A/B, A%B) ... */ if (BN_num_bits(A) == BN_num_bits(B)) { if (!BN_one(D)) goto err; if (!BN_sub(M,A,B)) goto err; } else if (BN_num_bits(A) == BN_num_bits(B) + 1) { /* A/B is 1, 2, or 3 */ if (!BN_lshift1(T,B)) goto err; if (BN_ucmp(A,T) < 0) { /* A < 2*B, so D=1 */ if (!BN_one(D)) goto err; if (!BN_sub(M,A,B)) goto err; } else { /* A >= 2*B, so D=2 or D=3 */ if (!BN_sub(M,A,T)) goto err; if (!BN_add(D,T,B)) goto err; /* use D (:= 3*B) as temp */ if (BN_ucmp(A,D) < 0) { /* A < 3*B, so D=2 */ if (!BN_set_word(D,2)) goto err; /* M (= A - 2*B) already has the correct value */ } else { /* only D=3 remains */ if (!BN_set_word(D,3)) goto err; /* currently M = A - 2*B, but we need M = A - 3*B */ if (!BN_sub(M,M,B)) goto err; } } } else { if (!BN_div(D,M,A,B,ctx)) goto err; } /* Now * A = D*B + M; * thus we have * (**) sign*Y*a == D*B + M (mod |n|). */ tmp=A; /* keep the BIGNUM object, the value does not matter */ /* (A, B) := (B, A mod B) ... */ A=B; B=M; /* ... so we have 0 <= B < A again */ /* Since the former M is now B and the former B is now A, * (**) translates into * sign*Y*a == D*A + B (mod |n|), * i.e. * sign*Y*a - D*A == B (mod |n|). * Similarly, (*) translates into * -sign*X*a == A (mod |n|). * * Thus, * sign*Y*a + D*sign*X*a == B (mod |n|), * i.e. * sign*(Y + D*X)*a == B (mod |n|). * * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). * Note that X and Y stay non-negative all the time. */ /* most of the time D is very small, so we can optimize tmp := D*X+Y */ if (BN_is_one(D)) { if (!BN_add(tmp,X,Y)) goto err; } else { if (BN_is_word(D,2)) { if (!BN_lshift1(tmp,X)) goto err; } else if (BN_is_word(D,4)) { if (!BN_lshift(tmp,X,2)) goto err; } else if (D->top == 1) { if (!BN_copy(tmp,X)) goto err; if (!BN_mul_word(tmp,D->d[0])) goto err; } else { if (!BN_mul(tmp,D,X,ctx)) goto err; } if (!BN_add(tmp,tmp,Y)) goto err; } M=Y; /* keep the BIGNUM object, the value does not matter */ Y=X; X=tmp; sign = -sign; } } /* * The while loop (Euclid's algorithm) ends when * A == gcd(a,n); * we have * sign*Y*a == A (mod |n|), * where Y is non-negative. */ if (sign < 0) { if (!BN_sub(Y,n,Y)) goto err; } /* Now Y*a == A (mod |n|). */ if (BN_is_one(A)) { /* Y*a == 1 (mod |n|) */ if (!Y->neg && BN_ucmp(Y,n) < 0) { if (!BN_copy(R,Y)) goto err; } else { if (!BN_nnmod(R,Y,n,ctx)) goto err; } } else { BNerr(BN_F_BN_MOD_INVERSE,BN_R_NO_INVERSE); goto err; } ret=R; err: if ((ret == NULL) && (in == NULL)) BN_free(R); BN_CTX_end(ctx); bn_check_top(ret); return(ret); }
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); }
int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, BN_RECP_CTX *recp, BN_CTX *ctx) { int i, j, ret = 0; BIGNUM *a, *b, *d, *r; BN_CTX_start(ctx); d = (dv != NULL) ? dv : BN_CTX_get(ctx); r = (rem != NULL) ? rem : BN_CTX_get(ctx); a = BN_CTX_get(ctx); b = BN_CTX_get(ctx); if (b == NULL) goto err; if (BN_ucmp(m, &(recp->N)) < 0) { BN_zero(d); if (!BN_copy(r, m)) { BN_CTX_end(ctx); return 0; } BN_CTX_end(ctx); return 1; } /* * We want the remainder Given input of ABCDEF / ab we need multiply * ABCDEF by 3 digests of the reciprocal of ab */ /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */ i = BN_num_bits(m); j = recp->num_bits << 1; if (j > i) i = j; /* Nr := round(2^i / N) */ if (i != recp->shift) recp->shift = BN_reciprocal(&(recp->Nr), &(recp->N), i, ctx); /* BN_reciprocal could have returned -1 for an error */ if (recp->shift == -1) goto err; /*- * d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - BN_num_bits(N)))| * = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - BN_num_bits(N)))| * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)| * = |m/N| */ if (!BN_rshift(a, m, recp->num_bits)) goto err; if (!BN_mul(b, a, &(recp->Nr), ctx)) goto err; if (!BN_rshift(d, b, i - recp->num_bits)) goto err; d->neg = 0; if (!BN_mul(b, &(recp->N), d, ctx)) goto err; if (!BN_usub(r, m, b)) goto err; r->neg = 0; j = 0; while (BN_ucmp(r, &(recp->N)) >= 0) { if (j++ > 2) { BNerr(BN_F_BN_DIV_RECP, BN_R_BAD_RECIPROCAL); goto err; } if (!BN_usub(r, r, &(recp->N))) goto err; if (!BN_add_word(d, 1)) goto err; } r->neg = BN_is_zero(r) ? 0 : m->neg; d->neg = m->neg ^ recp->N.neg; ret = 1; err: BN_CTX_end(ctx); bn_check_top(dv); bn_check_top(rem); return ret; }
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; if (bn_wexpand(ret,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_fix_top(r); /* mont->ri will be a multiple of the word size */ #if 0 BN_rshift(ret,r,mont->ri); #else ret->neg = r->neg; x=ri; rp=ret->d; ap= &(r->d[x]); if (r->top < x) al=0; else al=r->top-x; ret->top=al; 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 (BN_ucmp(ret, &(mont->N)) >= 0) { if (!BN_usub(ret,ret,&(mont->N))) goto err; } retn=1; err: BN_CTX_end(ctx); return(retn); }
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_CTX *ctx) { int norm_shift, i, j, loop; BIGNUM *tmp, wnum, *snum, *sdiv, *res; BN_ULONG *resp, *wnump; BN_ULONG d0, d1; int num_n, div_n; bn_check_top(num); bn_check_top(divisor); if(BN_is_zero(divisor)) { 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; } tmp->neg = 0; /* First we normalise the numbers */ norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2); BN_lshift(sdiv, divisor, norm_shift); sdiv->neg = 0; norm_shift += BN_BITS2; BN_lshift(snum, num, norm_shift); 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 */ BN_init(&wnum); wnum.d = &(snum->d[loop]); wnum.top = div_n; wnum.dmax = snum->dmax + 1; /* a bit of a lie */ /* Get the top 2 words of sdiv */ /* i=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_usub(&wnum, &wnum, sdiv)) { goto err; } *resp = 1; res->d[res->top - 1] = 1; } else { res->top--; } resp--; for(i = 0; i < loop - 1; i++) { BN_ULONG q, l0; #if defined(BN_DIV3W) && !defined(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, ql, qh; q = bn_div_words(n0, n1, d0); #ifndef REMAINDER_IS_ALREADY_CALCULATED rem = (n1 - q * d0)&BN_MASK2; #endif #ifdef 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); wnum.d--; wnum.top++; tmp->d[div_n] = l0; for(j = div_n + 1; j > 0; j--) if(tmp->d[j - 1]) { break; } tmp->top = j; j = wnum.top; BN_sub(&wnum, &wnum, tmp); snum->top = snum->top + wnum.top - j; if(wnum.neg) { q--; j = wnum.top; BN_add(&wnum, &wnum, sdiv); snum->top += wnum.top - j; } *(resp--) = q; wnump--; } if(rm != NULL) { BN_rshift(rm, snum, norm_shift); rm->neg = num->neg; } BN_CTX_end(ctx); return (1); err: BN_CTX_end(ctx); return (0); }
int BN_div_recp(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BN_RECP_CTX *recp, BN_CTX *ctx) { int i,j,ret=0; BIGNUM *a,*b,*d,*r; BN_CTX_start(ctx); a=BN_CTX_get(ctx); b=BN_CTX_get(ctx); if (dv != NULL) d=dv; else d=BN_CTX_get(ctx); if (rem != NULL) r=rem; else r=BN_CTX_get(ctx); if (a == NULL || b == NULL || d == NULL || r == NULL) goto err; if (BN_ucmp(m,&(recp->N)) < 0) { BN_zero(d); BN_copy(r,m); BN_CTX_end(ctx); return(1); } /* We want the remainder * Given input of ABCDEF / ab * we need multiply ABCDEF by 3 digests of the reciprocal of ab * */ i=BN_num_bits(m); j=recp->num_bits<<1; if (j>i) i=j; j>>=1; if (i != recp->shift) recp->shift=BN_reciprocal(&(recp->Nr),&(recp->N), i,ctx); if (!BN_rshift(a,m,j)) goto err; if (!BN_mul(b,a,&(recp->Nr),ctx)) goto err; if (!BN_rshift(d,b,i-j)) goto err; d->neg=0; if (!BN_mul(b,&(recp->N),d,ctx)) goto err; if (!BN_usub(r,m,b)) goto err; r->neg=0; #if 1 j=0; while (BN_ucmp(r,&(recp->N)) >= 0) { if (j++ > 2) goto err; if (!BN_usub(r,r,&(recp->N))) goto err; if (!BN_add_word(d,1)) goto err; } #endif r->neg=BN_is_zero(r)?0:m->neg; d->neg=m->neg^recp->N.neg; ret=1; err: BN_CTX_end(ctx); return(ret); }
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_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, BN_RECP_CTX *recp, BN_CTX *ctx) { int i,j,ret=0; BIGNUM *a,*b,*d,*r; BN_CTX_start(ctx); a=BN_CTX_get(ctx); b=BN_CTX_get(ctx); if (dv != NULL) d=dv; else d=BN_CTX_get(ctx); if (rem != NULL) r=rem; else r=BN_CTX_get(ctx); if (a == NULL || b == NULL || d == NULL || r == NULL) goto err; if (BN_ucmp(m,&(recp->N)) < 0) { if (!BN_zero(d)) return 0; if (!BN_copy(r,m)) return 0; BN_CTX_end(ctx); return(1); } /* We want the remainder * Given input of ABCDEF / ab * we need multiply ABCDEF by 3 digests of the reciprocal of ab * */ /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */ i=BN_num_bits(m); j=recp->num_bits<<1; if (j>i) i=j; /* Nr := round(2^i / N) */ if (i != recp->shift) recp->shift=BN_reciprocal(&(recp->Nr),&(recp->N), i,ctx); /* BN_reciprocal returns i, or -1 for an error */ if (recp->shift == -1) goto err; /* d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - BN_num_bits(N)))| * = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - BN_num_bits(N)))| * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)| * = |m/N| */ if (!BN_rshift(a,m,recp->num_bits)) goto err; if (!BN_mul(b,a,&(recp->Nr),ctx)) goto err; if (!BN_rshift(d,b,i-recp->num_bits)) goto err; d->neg=0; if (!BN_mul(b,&(recp->N),d,ctx)) goto err; if (!BN_usub(r,m,b)) goto err; r->neg=0; #if 1 j=0; while (BN_ucmp(r,&(recp->N)) >= 0) { if (j++ > 2) { BNerr(BN_F_BN_MOD_MUL_RECIPROCAL,BN_R_BAD_RECIPROCAL); goto err; } if (!BN_usub(r,r,&(recp->N))) goto err; if (!BN_add_word(d,1)) goto err; } #endif r->neg=BN_is_zero(r)?0:m->neg; d->neg=m->neg^recp->N.neg; ret=1; err: BN_CTX_end(ctx); return(ret); }
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; }
int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) { int ret = 0; BIGNUM *Ri, *R; BIGNUM tmod; BN_ULONG buf[2]; if (BN_is_zero(mod)) { OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); return 0; } BN_CTX_start(ctx); Ri = BN_CTX_get(ctx); if (Ri == NULL) { goto err; } R = &mont->RR; /* grab RR as a temp */ if (!BN_copy(&mont->N, mod)) { goto err; /* Set N */ } if (BN_get_flags(mod, BN_FLG_CONSTTIME)) { BN_set_flags(&mont->N, BN_FLG_CONSTTIME); } mont->N.neg = 0; BN_init(&tmod); tmod.d = buf; tmod.dmax = 2; tmod.neg = 0; BN_zero(R); if (!BN_set_bit(R, BN_MONT_CTX_N0_LIMBS * BN_BITS2)) { goto err; } tmod.top = 0; buf[0] = mod->d[0]; if (buf[0] != 0) { tmod.top = 1; } buf[1] = 0; if (BN_MONT_CTX_N0_LIMBS == 2 && mod->top > 1 && mod->d[1] != 0) { buf[1] = mod->d[1]; tmod.top = 2; } if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) { goto err; } if (!BN_lshift(Ri, Ri, BN_MONT_CTX_N0_LIMBS * BN_BITS2)) { goto err; /* R*Ri */ } const BIGNUM *Ri_dividend; if (!BN_is_zero(Ri)) { if (!BN_usub(Ri, Ri, BN_value_one())) { goto err; } Ri_dividend = Ri; } else { /* Ri == 0 so Ri - 1 == -1. -1 % tmod == 0xff..ff. */ static const BN_ULONG kMinusOneLimbs[BN_MONT_CTX_N0_LIMBS] = { BN_MASK2, #if BN_MONT_CTX_N0_LIMBS == 2 BN_MASK2 #endif }; STATIC_BIGNUM_DIAGNOSTIC_PUSH static const BIGNUM kMinusOne = STATIC_BIGNUM(kMinusOneLimbs); STATIC_BIGNUM_DIAGNOSTIC_POP Ri_dividend = &kMinusOne; } if (!BN_div(Ri, NULL, Ri_dividend, &tmod, ctx)) { goto err; } mont->n0[0] = 0; if (Ri->top > 0) { mont->n0[0] = Ri->d[0]; } mont->n0[1] = 0; if (BN_MONT_CTX_N0_LIMBS == 2 && Ri->top > 1) { mont->n0[1] = Ri->d[1]; } /* RR = (2^ri)^2 == 2^(ri*2) == 1 << (ri*2), which has its (ri*2)th bit set. */ int ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2; BN_zero(&(mont->RR)); if (!BN_set_bit(&(mont->RR), ri * 2)) { goto err; } if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx)) { goto err; } ret = 1; err: BN_CTX_end(ctx); return ret; }