/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in * Montgomery projective coordinates. Uses algorithm Madd in appendix of * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over * GF(2^m) without precomputation". */ static mp_err gf2m_Madd(const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2, mp_int *z2, const ECGroup *group, int kmflag) { mp_err res = MP_OKAY; mp_int t1, t2; MP_DIGITS(&t1) = 0; MP_DIGITS(&t2) = 0; MP_CHECKOK(mp_init(&t1, kmflag)); MP_CHECKOK(mp_init(&t2, kmflag)); MP_CHECKOK(mp_copy(x, &t1)); MP_CHECKOK(group->meth->field_mul(x1, z2, x1, group->meth)); MP_CHECKOK(group->meth->field_mul(z1, x2, z1, group->meth)); MP_CHECKOK(group->meth->field_mul(x1, z1, &t2, group->meth)); MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth)); MP_CHECKOK(group->meth->field_sqr(z1, z1, group->meth)); MP_CHECKOK(group->meth->field_mul(z1, &t1, x1, group->meth)); MP_CHECKOK(group->meth->field_add(x1, &t2, x1, group->meth)); CLEANUP: mp_clear(&t1); mp_clear(&t2); return res; }
/* ** An attack against RSA CRT was described by Boneh, DeMillo, and Lipton in: ** "On the Importance of Eliminating Errors in Cryptographic Computations", ** http://theory.stanford.edu/~dabo/papers/faults.ps.gz ** ** As a defense against the attack, carry out the private key operation, ** followed up with a public key operation to invert the result. ** Verify that result against the input. */ static SECStatus rsa_PrivateKeyOpCRTCheckedPubKey(RSAPrivateKey *key, mp_int *m, mp_int *c) { mp_int n, e, v; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&n) = 0; MP_DIGITS(&e) = 0; MP_DIGITS(&v) = 0; CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&e) ); CHECK_MPI_OK( mp_init(&v) ); CHECK_SEC_OK( rsa_PrivateKeyOpCRTNoCheck(key, m, c) ); SECITEM_TO_MPINT(key->modulus, &n); SECITEM_TO_MPINT(key->publicExponent, &e); /* Perform a public key operation v = m ** e mod n */ CHECK_MPI_OK( mp_exptmod(m, &e, &n, &v) ); if (mp_cmp(&v, c) != 0) { rv = SECFailure; } cleanup: mp_clear(&n); mp_clear(&e); mp_clear(&v); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
static SECStatus init_blinding_params(RSABlindingParams *rsabp, RSAPrivateKey *key, mp_int *n, unsigned int modLen) { blindingParams * bp = rsabp->array; int i = 0; /* Initialize the list pointer for the element */ PR_INIT_CLIST(&rsabp->link); for (i = 0; i < RSA_BLINDING_PARAMS_MAX_CACHE_SIZE; ++i, ++bp) { bp->next = bp + 1; MP_DIGITS(&bp->f) = 0; MP_DIGITS(&bp->g) = 0; bp->counter = 0; } /* The last bp->next value was initialized with out * of rsabp->array pointer and must be set to NULL */ rsabp->array[RSA_BLINDING_PARAMS_MAX_CACHE_SIZE - 1].next = NULL; bp = rsabp->array; rsabp->bp = NULL; rsabp->free = bp; /* List elements are keyed using the modulus */ SECITEM_CopyItem(NULL, &rsabp->modulus, &key->modulus); return SECSuccess; }
/* Allocate memory for a new ECGroup object. */ ECGroup * ECGroup_new() { mp_err res = MP_OKAY; ECGroup *group; group = (ECGroup *) malloc(sizeof(ECGroup)); if (group == NULL) return NULL; group->constructed = MP_YES; group->meth = NULL; group->text = NULL; MP_DIGITS(&group->curvea) = 0; MP_DIGITS(&group->curveb) = 0; MP_DIGITS(&group->genx) = 0; MP_DIGITS(&group->geny) = 0; MP_DIGITS(&group->order) = 0; group->base_point_mul = NULL; group->points_mul = NULL; group->validate_point = NULL; group->extra1 = NULL; group->extra2 = NULL; group->extra_free = NULL; MP_CHECKOK(mp_init(&group->curvea)); MP_CHECKOK(mp_init(&group->curveb)); MP_CHECKOK(mp_init(&group->genx)); MP_CHECKOK(mp_init(&group->geny)); MP_CHECKOK(mp_init(&group->order)); CLEANUP: if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
/* Tests pre computation of Chudnovsky Jacobian points used in wNAF form */ mp_err testPreCompute(ECGroup *ecgroup) { ecfp_chud_pt precomp[16]; ecfp_aff_pt p; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; int i; mp_err res; mp_int x, y, ny, x2, y2; MP_DIGITS(&x) = 0; MP_DIGITS(&y) = 0; MP_DIGITS(&ny) = 0; MP_DIGITS(&x2) = 0; MP_DIGITS(&y2) = 0; MP_CHECKOK(mp_init(&x)); MP_CHECKOK(mp_init(&y)); MP_CHECKOK(mp_init(&ny)); MP_CHECKOK(mp_init(&x2)); MP_CHECKOK(mp_init(&y2)); ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(group->curvea, &(ecgroup->curvea), ecgroup); /* Perform precomputation */ group->precompute_chud(precomp, &p, group); M_TimeOperation(group->precompute_chud(precomp, &p, group), 10000); /* Calculate addition to compare against */ MP_CHECKOK(mp_copy(&ecgroup->genx, &x)); MP_CHECKOK(mp_copy(&ecgroup->geny, &y)); MP_CHECKOK(ecgroup->meth->field_neg(&y, &ny, ecgroup->meth)); ec_GFp_pt_dbl_aff(&x, &y, &x2, &y2, ecgroup); for (i = 0; i < 8; i++) { MP_CHECKOK(testChudPoint(&precomp[8 + i], &x, &y, ecgroup)); MP_CHECKOK(testChudPoint(&precomp[7 - i], &x, &ny, ecgroup)); ec_GFp_pt_add_aff(&x, &y, &x2, &y2, &x, &y, ecgroup); MP_CHECKOK(ecgroup->meth->field_neg(&y, &ny, ecgroup->meth)); } CLEANUP: if (res == MP_OKAY) printf(" Test Passed - Precomputation\n"); else printf("TEST FAILED - Precomputation\n"); mp_clear(&x); mp_clear(&y); mp_clear(&ny); mp_clear(&x2); mp_clear(&y2); return res; }
/* ** RSA Private key operation using CRT. */ static SECStatus rsa_PrivateKeyOpCRTNoCheck(RSAPrivateKey *key, mp_int *m, mp_int *c) { mp_int p, q, d_p, d_q, qInv; mp_int m1, m2, h, ctmp; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&d_p) = 0; MP_DIGITS(&d_q) = 0; MP_DIGITS(&qInv) = 0; MP_DIGITS(&m1) = 0; MP_DIGITS(&m2) = 0; MP_DIGITS(&h) = 0; MP_DIGITS(&ctmp) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&d_p) ); CHECK_MPI_OK( mp_init(&d_q) ); CHECK_MPI_OK( mp_init(&qInv) ); CHECK_MPI_OK( mp_init(&m1) ); CHECK_MPI_OK( mp_init(&m2) ); CHECK_MPI_OK( mp_init(&h) ); CHECK_MPI_OK( mp_init(&ctmp) ); /* copy private key parameters into mp integers */ SECITEM_TO_MPINT(key->prime1, &p); /* p */ SECITEM_TO_MPINT(key->prime2, &q); /* q */ SECITEM_TO_MPINT(key->exponent1, &d_p); /* d_p = d mod (p-1) */ SECITEM_TO_MPINT(key->exponent2, &d_q); /* d_q = d mod (q-1) */ SECITEM_TO_MPINT(key->coefficient, &qInv); /* qInv = q**-1 mod p */ /* 1. m1 = c**d_p mod p */ CHECK_MPI_OK( mp_mod(c, &p, &ctmp) ); CHECK_MPI_OK( mp_exptmod(&ctmp, &d_p, &p, &m1) ); /* 2. m2 = c**d_q mod q */ CHECK_MPI_OK( mp_mod(c, &q, &ctmp) ); CHECK_MPI_OK( mp_exptmod(&ctmp, &d_q, &q, &m2) ); /* 3. h = (m1 - m2) * qInv mod p */ CHECK_MPI_OK( mp_submod(&m1, &m2, &p, &h) ); CHECK_MPI_OK( mp_mulmod(&h, &qInv, &p, &h) ); /* 4. m = m2 + h * q */ CHECK_MPI_OK( mp_mul(&h, &q, m) ); CHECK_MPI_OK( mp_add(m, &m2, m) ); cleanup: mp_clear(&p); mp_clear(&q); mp_clear(&d_p); mp_clear(&d_q); mp_clear(&qInv); mp_clear(&m1); mp_clear(&m2); mp_clear(&h); mp_clear(&ctmp); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* Tests point addition of Jacobian + Affine -> Jacobian */ mp_err testPointAddJacAff(ECGroup *ecgroup) { mp_err res; mp_int pz, rx2, ry2, rz2; ecfp_jac_pt p, r; ecfp_aff_pt q; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; /* Init */ MP_DIGITS(&pz) = 0; MP_DIGITS(&rx2) = 0; MP_DIGITS(&ry2) = 0; MP_DIGITS(&rz2) = 0; MP_CHECKOK(mp_init(&pz)); MP_CHECKOK(mp_init(&rx2)); MP_CHECKOK(mp_init(&ry2)); MP_CHECKOK(mp_init(&rz2)); MP_CHECKOK(mp_set_int(&pz, 5)); /* Set p */ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(p.z, &pz, ecgroup); /* Set q */ ecfp_i2fp(q.x, &ecgroup->geny, ecgroup); ecfp_i2fp(q.y, &ecgroup->genx, ecgroup); /* Do calculations */ group->pt_add_jac_aff(&p, &q, &r, group); /* Do calculation in integer to compare against */ MP_CHECKOK(ec_GFp_pt_add_jac_aff (&ecgroup->genx, &ecgroup->geny, &pz, &ecgroup->geny, &ecgroup->genx, &rx2, &ry2, &rz2, ecgroup)); /* convert result R to affine coordinates */ ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup); MP_CHECKOK(testJacPoint(&r, &rx2, &ry2, ecgroup)); CLEANUP: if (res == MP_OKAY) printf(" Test Passed - Point Addition - Jacobian & Affine\n"); else printf("TEST FAILED - Point Addition - Jacobian & Affine\n"); mp_clear(&pz); mp_clear(&rx2); mp_clear(&ry2); mp_clear(&rz2); return res; }
/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62, * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the * random number generator. * * Parameters * - order: a buffer that holds the curve's group order * - len: the length in octets of the order buffer * - random: a buffer of 2 * len random bytes * - randomlen: the length in octets of the random buffer * * Return Value * Returns a buffer of len octets that holds the private key. The caller * is responsible for freeing the buffer with PORT_ZFree. */ static unsigned char * ec_GenerateRandomPrivateKey(const unsigned char *order, int len, const unsigned char *random, int randomlen, int kmflag) { SECStatus rv = SECSuccess; mp_err err; unsigned char *privKeyBytes = NULL; mp_int privKeyVal, order_1, one; MP_DIGITS(&privKeyVal) = 0; MP_DIGITS(&order_1) = 0; MP_DIGITS(&one) = 0; CHECK_MPI_OK( mp_init(&privKeyVal, kmflag) ); CHECK_MPI_OK( mp_init(&order_1, kmflag) ); CHECK_MPI_OK( mp_init(&one, kmflag) ); /* * Reduces the 2*len buffer of random bytes modulo the group order. */ if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup; if (randomlen != 2 * len) { randomlen = 2 * len; } /* No need to generate - random bytes are now supplied */ /* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/ memcpy(privKeyBytes, random, randomlen); CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) ); CHECK_MPI_OK( mp_set_int(&one, 1) ); CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) ); CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) ); CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) ); CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) ); memset(privKeyBytes+len, 0, len); cleanup: mp_clear(&privKeyVal); mp_clear(&order_1); mp_clear(&one); if (err < MP_OKAY) { MP_TO_SEC_ERROR(err); rv = SECFailure; } if (rv != SECSuccess && privKeyBytes) { #ifdef _KERNEL kmem_free(privKeyBytes, 2*len); #else free(privKeyBytes); #endif privKeyBytes = NULL; } return privKeyBytes; }
/* Tests the time required for a point multiplication */ mp_err testPointMulTime(ECGroup *ecgroup) { mp_err res = MP_OKAY; mp_int rx, ry, n; int size; MP_DIGITS(&rx) = 0; MP_DIGITS(&ry) = 0; MP_DIGITS(&n) = 0; MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&n)); /* compute random scalar */ size = mpl_significant_bits(&ecgroup->meth->irr); if (size < MP_OKAY) { res = MP_NO; goto CLEANUP; } MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS)); MP_CHECKOK(ecgroup->meth->field_mod(&n, &n, ecgroup->meth)); M_TimeOperation(ec_GFp_pt_mul_jac_fp (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry, ecgroup), 1000); M_TimeOperation(ec_GFp_point_mul_jac_4w_fp (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry, ecgroup), 1000); M_TimeOperation(ec_GFp_point_mul_wNAF_fp (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry, ecgroup), 1000); M_TimeOperation(ec_GFp_pt_mul_jac (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry, ecgroup), 100); CLEANUP: if (res == MP_OKAY) printf(" Test Passed - Point Multiplication Timing\n"); else printf("TEST FAILED - Point Multiplication Timing\n"); mp_clear(&rx); mp_clear(&ry); mp_clear(&n); return res; }
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k * P(x, * y). If x, y = NULL, then P is assumed to be the generator (base point) * of the group of points on the elliptic curve. Input and output values * are assumed to be NOT field-encoded. */ mp_err ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry) { mp_err res = MP_OKAY; mp_int kt; ARGCHK((k != NULL) && (group != NULL), MP_BADARG); MP_DIGITS(&kt) = 0; /* want scalar to be less than or equal to group order */ if (mp_cmp(k, &group->order) > 0) { MP_CHECKOK(mp_init(&kt, FLAG(k))); MP_CHECKOK(mp_mod(k, &group->order, &kt)); } else { MP_SIGN(&kt) = MP_ZPOS; MP_USED(&kt) = MP_USED(k); MP_ALLOC(&kt) = MP_ALLOC(k); MP_DIGITS(&kt) = MP_DIGITS(k); } if ((px == NULL) || (py == NULL)) { if (group->base_point_mul) { MP_CHECKOK(group->base_point_mul(&kt, rx, ry, group)); } else { MP_CHECKOK(group-> point_mul(&kt, &group->genx, &group->geny, rx, ry, group)); } } else { if (group->meth->field_enc) { MP_CHECKOK(group->meth->field_enc(px, rx, group->meth)); MP_CHECKOK(group->meth->field_enc(py, ry, group->meth)); MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group)); } else { MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group)); } } if (group->meth->field_dec) { MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth)); MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth)); } CLEANUP: if (MP_DIGITS(&kt) != MP_DIGITS(k)) { mp_clear(&kt); } return res; }
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + * k2 * P(x, y), where G is the generator (base point) of the group of * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL. * Input and output values are assumed to be NOT field-encoded. */ mp_err ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2, const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry) { mp_err res = MP_OKAY; mp_int k1t, k2t; const mp_int *k1p, *k2p; MP_DIGITS(&k1t) = 0; MP_DIGITS(&k2t) = 0; ARGCHK(group != NULL, MP_BADARG); /* want scalar to be less than or equal to group order */ if (k1 != NULL) { if (mp_cmp(k1, &group->order) >= 0) { MP_CHECKOK(mp_init(&k1t, FLAG(k1))); MP_CHECKOK(mp_mod(k1, &group->order, &k1t)); k1p = &k1t; } else { k1p = k1; } } else { k1p = k1; } if (k2 != NULL) { if (mp_cmp(k2, &group->order) >= 0) { MP_CHECKOK(mp_init(&k2t, FLAG(k2))); MP_CHECKOK(mp_mod(k2, &group->order, &k2t)); k2p = &k2t; } else { k2p = k2; } } else { k2p = k2; } /* if points_mul is defined, then use it */ if (group->points_mul) { res = group->points_mul(k1p, k2p, px, py, rx, ry, group); } else { res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group); } CLEANUP: mp_clear(&k1t); mp_clear(&k2t); return res; }
/* Field multiplication using Montgomery reduction. */ mp_err ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r, const GFMethod *meth) { mp_err res = MP_OKAY; #ifdef MP_MONT_USE_MP_MUL /* if MP_MONT_USE_MP_MUL is defined, then the function s_mp_mul_mont * is not implemented and we have to use mp_mul and s_mp_redc directly */ MP_CHECKOK(mp_mul(a, b, r)); MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1)); #else mp_int s; MP_DIGITS(&s) = 0; /* s_mp_mul_mont doesn't allow source and destination to be the same */ if ((a == r) || (b == r)) { MP_CHECKOK(mp_init(&s)); MP_CHECKOK(s_mp_mul_mont (a, b, &s, (mp_mont_modulus *) meth->extra1)); MP_CHECKOK(mp_copy(&s, r)); mp_clear(&s); } else { return s_mp_mul_mont(a, b, r, (mp_mont_modulus *) meth->extra1); } #endif CLEANUP: return res; }
/* * mpi_to_weave takes an array of bignums, a matrix in which each bignum * occupies all the columns of a row, and transposes it into a matrix in * which each bignum occupies a column of every row. The first row of the * input matrix becomes the first column of the output matrix. The n'th * row of input becomes the n'th column of output. The input data is said * to be "interleaved" or "woven" into the output matrix. * * The array of bignums is left in this woven form. Each time a single * bignum value is needed, it is recreated by fetching the n'th column, * forming a single row which is the new bignum. * * The purpose of this interleaving is make it impossible to determine which * of the bignums is being used in any one operation by examining the pattern * of cache misses. * * The weaving function does not transpose the entire input matrix in one call. * It transposes 4 rows of mp_ints into their respective columns of output. * * There are two different implementations of the weaving and unweaving code * in this file. One uses byte loads and stores. The second uses loads and * stores of mp_weave_word size values. The weaved forms of these two * implementations differ. Consequently, each one has its own explanation. * * Here is the explanation for the byte-at-a-time implementation. * * This implementation treats each mp_int bignum as an array of bytes, * rather than as an array of mp_digits. It stores those bytes as a * column of bytes in the output matrix. It doesn't care if the machine * uses big-endian or little-endian byte ordering within mp_digits. * The first byte of the mp_digit array becomes the first byte in the output * column, regardless of whether that byte is the MSB or LSB of the mp_digit. * * "bignums" is an array of mp_ints. * It points to four rows, four mp_ints, a subset of a larger array of mp_ints. * * "weaved" is the weaved output matrix. * The first byte of bignums[0] is stored in weaved[0]. * * "nBignums" is the total number of bignums in the array of which "bignums" * is a part. * * "nDigits" is the size in mp_digits of each mp_int in the "bignums" array. * mp_ints that use less than nDigits digits are logically padded with zeros * while being stored in the weaved array. */ mp_err mpi_to_weave(const mp_int *bignums, unsigned char *weaved, mp_size nDigits, /* in each mp_int of input */ mp_size nBignums) /* in the entire source array */ { mp_size i; unsigned char * endDest = weaved + (nDigits * nBignums * sizeof(mp_digit)); for (i=0; i < WEAVE_WORD_SIZE; i++) { mp_size used = MP_USED(&bignums[i]); unsigned char *pSrc = (unsigned char *)MP_DIGITS(&bignums[i]); unsigned char *endSrc = pSrc + (used * sizeof(mp_digit)); unsigned char *pDest = weaved + i; ARGCHK(MP_SIGN(&bignums[i]) == MP_ZPOS, MP_BADARG); ARGCHK(used <= nDigits, MP_BADARG); for (; pSrc < endSrc; pSrc++) { *pDest = *pSrc; pDest += nBignums; } while (pDest < endDest) { *pDest = 0; pDest += nBignums; } } return MP_OKAY; }
/* Reverse the operation above for one mp_int. * Reconstruct one mp_int from its column in the weaved array. * Every read accesses every element of the weaved array, in order to * avoid timing attacks based on patterns of memory accesses. */ mp_err weave_to_mpi(mp_int *a, /* out, result */ const mp_digit *weaved, /* in, byte matrix */ mp_size index, /* which column to read */ mp_size nDigits, /* number of mp_digits in each bignum */ mp_size nBignums) /* width of the matrix */ { /* these are indices, but need to be the same size as mp_digit * because of the CONST_TIME operations */ mp_digit i, j; mp_digit d; mp_digit *pDest = MP_DIGITS(a); MP_SIGN(a) = MP_ZPOS; MP_USED(a) = nDigits; assert(weaved != NULL); /* Fetch the proper column in constant time, indexing over the whole array */ for (i = 0; i < nDigits; ++i) { d = 0; for (j = 0; j < nBignums; ++j) { d |= weaved[i * nBignums + j] & CONST_TIME_EQ(j, index); } pDest[i] = d; } s_mp_clamp(a); return MP_OKAY; }
/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62, * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the * random number generator. * * Parameters * - order: a buffer that holds the curve's group order * - len: the length in octets of the order buffer * * Return Value * Returns a buffer of len octets that holds the private key. The caller * is responsible for freeing the buffer with PORT_ZFree. */ static unsigned char * ec_GenerateRandomPrivateKey(const unsigned char *order, int len, int kmflag) { SECStatus rv = SECSuccess; mp_err err; unsigned char *privKeyBytes = NULL; mp_int privKeyVal, order_1, one; MP_DIGITS(&privKeyVal) = 0; MP_DIGITS(&order_1) = 0; MP_DIGITS(&one) = 0; CHECK_MPI_OK( mp_init(&privKeyVal) ); CHECK_MPI_OK( mp_init(&order_1) ); CHECK_MPI_OK( mp_init(&one) ); /* Generates 2*len random bytes using the global random bit generator * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then * reduces modulo the group order. */ if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup; CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) ); CHECK_MPI_OK( mp_set_int(&one, 1) ); CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) ); CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) ); CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) ); CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) ); memset(privKeyBytes+len, 0, len); cleanup: mp_clear(&privKeyVal); mp_clear(&order_1); mp_clear(&one); if (err < MP_OKAY) { MP_TO_SEC_ERROR(err); rv = SECFailure; } if (rv != SECSuccess && privKeyBytes) { #ifdef _KERNEL kmem_free(privKeyBytes, 2*len); #else free(privKeyBytes); #endif privKeyBytes = NULL; } return privKeyBytes; }
/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G + * k2 * P(x, y), where G is the generator (base point) of the group of * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL. * Input and output values are assumed to be NOT field-encoded. */ mp_err ec_pts_mul_basic(const mp_int *k1, const mp_int *k2, const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *group) { mp_err res = MP_OKAY; mp_int sx, sy; ARGCHK(group != NULL, MP_BADARG); ARGCHK(!((k1 == NULL) && ((k2 == NULL) || (px == NULL) || (py == NULL))), MP_BADARG); /* if some arguments are not defined used ECPoint_mul */ if (k1 == NULL) { return ECPoint_mul(group, k2, px, py, rx, ry); } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) { return ECPoint_mul(group, k1, NULL, NULL, rx, ry); } MP_DIGITS(&sx) = 0; MP_DIGITS(&sy) = 0; MP_CHECKOK(mp_init(&sx, FLAG(k1))); MP_CHECKOK(mp_init(&sy, FLAG(k1))); MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy)); MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry)); if (group->meth->field_enc) { MP_CHECKOK(group->meth->field_enc(&sx, &sx, group->meth)); MP_CHECKOK(group->meth->field_enc(&sy, &sy, group->meth)); MP_CHECKOK(group->meth->field_enc(rx, rx, group->meth)); MP_CHECKOK(group->meth->field_enc(ry, ry, group->meth)); } MP_CHECKOK(group->point_add(&sx, &sy, rx, ry, rx, ry, group)); if (group->meth->field_dec) { MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth)); MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth)); } CLEANUP: mp_clear(&sx); mp_clear(&sy); return res; }
/* reverse the operation above for one entry. * b points to the offset into the weave array of the power we are * calculating */ mp_err weave_to_mpi(mp_int *a, const unsigned char *b, mp_size b_size, mp_size count) { mp_digit *pb = MP_DIGITS(a); mp_digit *end = &pb[b_size]; MP_SIGN(a) = MP_ZPOS; MP_USED(a) = b_size; for (; pb < end; pb++) { register mp_digit digit; digit = *b << 8; b += count; #define MPI_UNWEAVE_ONE_STEP digit |= *b; b += count; digit = digit << 8; switch (sizeof(mp_digit)) { case 32: MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP case 16: MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP case 8: MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP case 4: MPI_UNWEAVE_ONE_STEP MPI_UNWEAVE_ONE_STEP case 2: break; } digit |= *b; b += count; *pb = digit; } s_mp_clamp(a); return MP_OKAY; }
/* Test point doubling in Jacobian coordinates */ mp_err testPointDoubleJac(ECGroup *ecgroup) { mp_err res; mp_int pz, rx, ry, rz, rx2, ry2, rz2; ecfp_jac_pt p, p2; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; MP_DIGITS(&pz) = 0; MP_DIGITS(&rx) = 0; MP_DIGITS(&ry) = 0; MP_DIGITS(&rz) = 0; MP_DIGITS(&rx2) = 0; MP_DIGITS(&ry2) = 0; MP_DIGITS(&rz2) = 0; MP_CHECKOK(mp_init(&pz)); MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&rz)); MP_CHECKOK(mp_init(&rx2)); MP_CHECKOK(mp_init(&ry2)); MP_CHECKOK(mp_init(&rz2)); MP_CHECKOK(mp_set_int(&pz, 5)); /* Set p2 = 2P */ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(p.z, &pz, ecgroup); ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup); group->pt_dbl_jac(&p, &p2, group); M_TimeOperation(group->pt_dbl_jac(&p, &p2, group), 100000); /* Calculate doubling to compare against */ ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2, &rz2, ecgroup); ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup); /* Do comparison */ MP_CHECKOK(testJacPoint(&p2, &rx2, &ry2, ecgroup)); CLEANUP: if (res == MP_OKAY) printf(" Test Passed - Point Doubling - Jacobian\n"); else printf("TEST FAILED - Point Doubling - Jacobian\n"); mp_clear(&pz); mp_clear(&rx); mp_clear(&ry); mp_clear(&rz); mp_clear(&rx2); mp_clear(&ry2); mp_clear(&rz2); return res; }
/* Tests a point p in Jacobian coordinates, comparing against the * expected affine result (x, y). */ mp_err testJacPoint(ecfp_jac_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup) { char s[1000]; mp_int rx, ry, rz; mp_err res = MP_OKAY; MP_DIGITS(&rx) = 0; MP_DIGITS(&ry) = 0; MP_DIGITS(&rz) = 0; MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&rz)); ecfp_fp2i(&rx, p->x, ecgroup); ecfp_fp2i(&ry, p->y, ecgroup); ecfp_fp2i(&rz, p->z, ecgroup); /* convert result R to affine coordinates */ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup); /* Compare to expected result */ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) { printf(" Error: Jacobian Floating Point Incorrect.\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf("floating point result\nrx %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf("ry %s\n", s); MP_CHECKOK(mp_toradix(x, s, 16)); printf("integer result\nx %s\n", s); MP_CHECKOK(mp_toradix(y, s, 16)); printf("y %s\n", s); res = MP_NO; goto CLEANUP; } CLEANUP: mp_clear(&rx); mp_clear(&ry); mp_clear(&rz); return res; }
static SECStatus generate_blinding_params(struct RSABlindingParamsStr *rsabp, RSAPrivateKey *key, mp_int *n, unsigned int modLen) { SECStatus rv = SECSuccess; mp_int e, k; mp_err err = MP_OKAY; unsigned char *kb = NULL; MP_DIGITS(&e) = 0; MP_DIGITS(&k) = 0; CHECK_MPI_OK( mp_init(&e) ); CHECK_MPI_OK( mp_init(&k) ); SECITEM_TO_MPINT(key->publicExponent, &e); /* generate random k < n */ kb = PORT_Alloc(modLen); if (!kb) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto cleanup; } CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(kb, modLen) ); CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, modLen) ); /* k < n */ CHECK_MPI_OK( mp_mod(&k, n, &k) ); /* f = k**e mod n */ CHECK_MPI_OK( mp_exptmod(&k, &e, n, &rsabp->f) ); /* g = k**-1 mod n */ CHECK_MPI_OK( mp_invmod(&k, n, &rsabp->g) ); /* Initialize the counter for this (f, g) */ rsabp->counter = RSA_BLINDING_PARAMS_MAX_REUSE; cleanup: if (kb) PORT_ZFree(kb, modLen); mp_clear(&k); mp_clear(&e); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* Allocate memory for a new ECGroup object. */ ECGroup * ECGroup_new(int kmflag) { mp_err res = MP_OKAY; ECGroup *group; #ifdef _KERNEL group = (ECGroup *) kmem_alloc(sizeof(ECGroup), kmflag); #else group = (ECGroup *) malloc(sizeof(ECGroup)); #endif if (group == NULL) return NULL; group->constructed = MP_YES; group->meth = NULL; group->text = NULL; MP_DIGITS(&group->curvea) = 0; MP_DIGITS(&group->curveb) = 0; MP_DIGITS(&group->genx) = 0; MP_DIGITS(&group->geny) = 0; MP_DIGITS(&group->order) = 0; group->base_point_mul = NULL; group->points_mul = NULL; group->validate_point = NULL; group->extra1 = NULL; group->extra2 = NULL; group->extra_free = NULL; MP_CHECKOK(mp_init(&group->curvea, kmflag)); MP_CHECKOK(mp_init(&group->curveb, kmflag)); MP_CHECKOK(mp_init(&group->genx, kmflag)); MP_CHECKOK(mp_init(&group->geny, kmflag)); MP_CHECKOK(mp_init(&group->order, kmflag)); CLEANUP: if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }
static SECStatus generate_blinding_params(RSAPrivateKey *key, mp_int* f, mp_int* g, mp_int *n, unsigned int modLen) { SECStatus rv = SECSuccess; mp_int e, k; mp_err err = MP_OKAY; unsigned char *kb = NULL; MP_DIGITS(&e) = 0; MP_DIGITS(&k) = 0; CHECK_MPI_OK( mp_init(&e) ); CHECK_MPI_OK( mp_init(&k) ); SECITEM_TO_MPINT(key->publicExponent, &e); /* generate random k < n */ kb = PORT_Alloc(modLen); if (!kb) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto cleanup; } CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(kb, modLen) ); CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, modLen) ); /* k < n */ CHECK_MPI_OK( mp_mod(&k, n, &k) ); /* f = k**e mod n */ CHECK_MPI_OK( mp_exptmod(&k, &e, n, f) ); /* g = k**-1 mod n */ CHECK_MPI_OK( mp_invmod(&k, n, g) ); cleanup: if (kb) PORT_ZFree(kb, modLen); mp_clear(&k); mp_clear(&e); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* * FIPS 186-2 requires result from random output to be reduced mod q when * generating random numbers for DSA. * * Input: w, 2*qLen bytes * q, qLen bytes * Output: xj, qLen bytes */ static SECStatus fips186Change_ReduceModQForDSA(const PRUint8 *w, const PRUint8 *q, unsigned int qLen, PRUint8 * xj) { mp_int W, Q, Xj; mp_err err; SECStatus rv = SECSuccess; /* Initialize MPI integers. */ MP_DIGITS(&W) = 0; MP_DIGITS(&Q) = 0; MP_DIGITS(&Xj) = 0; CHECK_MPI_OK( mp_init(&W) ); CHECK_MPI_OK( mp_init(&Q) ); CHECK_MPI_OK( mp_init(&Xj) ); /* * Convert input arguments into MPI integers. */ CHECK_MPI_OK( mp_read_unsigned_octets(&W, w, 2*qLen) ); CHECK_MPI_OK( mp_read_unsigned_octets(&Q, q, qLen) ); /* * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3 * * xj = (w0 || w1) mod q */ CHECK_MPI_OK( mp_mod(&W, &Q, &Xj) ); CHECK_MPI_OK( mp_to_fixlen_octets(&Xj, xj, qLen) ); cleanup: mp_clear(&W); mp_clear(&Q); mp_clear(&Xj); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/*! c <- REDC( a * b ) mod N \param a < N i.e. "reduced" \param b < N i.e. "reduced" \param mmm modulus N and n0' of N */ mp_err s_mp_mul_mont(const mp_int *a, const mp_int *b, mp_int *c, mp_mont_modulus *mmm) { mp_digit *pb; mp_digit m_i; mp_err res; mp_size ib; /* "index b": index of current digit of B */ mp_size useda, usedb; ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); if (MP_USED(a) < MP_USED(b)) { const mp_int *xch = b; /* switch a and b, to do fewer outer loops */ b = a; a = xch; } MP_USED(c) = 1; MP_DIGIT(c, 0) = 0; ib = (MP_USED(&mmm->N) << 1) + 1; if ((res = s_mp_pad(c, ib)) != MP_OKAY) goto CLEANUP; useda = MP_USED(a); pb = MP_DIGITS(b); s_mpv_mul_d(MP_DIGITS(a), useda, *pb++, MP_DIGITS(c)); s_mp_setz(MP_DIGITS(c) + useda + 1, ib - (useda + 1)); m_i = MP_DIGIT(c, 0) * mmm->n0prime; s_mp_mul_d_add_offset(&mmm->N, m_i, c, 0); /* Outer loop: Digits of b */ usedb = MP_USED(b); for (ib = 1; ib < usedb; ib++) { mp_digit b_i = *pb++; /* Inner product: Digits of a */ if (b_i) s_mpv_mul_d_add_prop(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib); m_i = MP_DIGIT(c, ib) * mmm->n0prime; s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib); } if (usedb < MP_USED(&mmm->N)) { for (usedb = MP_USED(&mmm->N); ib < usedb; ++ib) { m_i = MP_DIGIT(c, ib) * mmm->n0prime; s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib); } } s_mp_clamp(c); s_mp_rshd(c, MP_USED(&mmm->N)); /* c /= R */ if (s_mp_cmp(c, &mmm->N) >= 0) { MP_CHECKOK(s_mp_sub(c, &mmm->N)); } res = MP_OKAY; CLEANUP: return res; }
/* Converts a point P(px, py, pz) from Jacobian projective coordinates to * affine coordinates R(rx, ry). P and R can share x and y coordinates. * Assumes input is already field-encoded using field_enc, and returns * output that is still field-encoded. */ mp_err ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz, mp_int *rx, mp_int *ry, const ECGroup *group) { mp_err res = MP_OKAY; mp_int z1, z2, z3; MP_DIGITS(&z1) = 0; MP_DIGITS(&z2) = 0; MP_DIGITS(&z3) = 0; MP_CHECKOK(mp_init(&z1)); MP_CHECKOK(mp_init(&z2)); MP_CHECKOK(mp_init(&z3)); /* if point at infinity, then set point at infinity and exit */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { MP_CHECKOK(ec_GFp_pt_set_inf_aff(rx, ry)); goto CLEANUP; } /* transform (px, py, pz) into (px / pz^2, py / pz^3) */ if (mp_cmp_d(pz, 1) == 0) { MP_CHECKOK(mp_copy(px, rx)); MP_CHECKOK(mp_copy(py, ry)); } else { MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth)); MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth)); MP_CHECKOK(group->meth->field_mul(&z1, &z2, &z3, group->meth)); MP_CHECKOK(group->meth->field_mul(px, &z2, rx, group->meth)); MP_CHECKOK(group->meth->field_mul(py, &z3, ry, group->meth)); } CLEANUP: mp_clear(&z1); mp_clear(&z2); mp_clear(&z3); return res; }
PRBool KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime) { mp_int p, q, y, r; mp_err err; int cmp = 1; /* default is false */ if (!Y || !prime || !subPrime) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&y) = 0; MP_DIGITS(&r) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&y) ); CHECK_MPI_OK( mp_init(&r) ); SECITEM_TO_MPINT(*prime, &p); SECITEM_TO_MPINT(*subPrime, &q); SECITEM_TO_MPINT(*Y, &y); /* compute r = y**q mod p */ CHECK_MPI_OK( mp_exptmod(&y, &q, &p, &r) ); /* compare to 1 */ cmp = mp_cmp_d(&r, 1); cleanup: mp_clear(&p); mp_clear(&q); mp_clear(&y); mp_clear(&r); if (err) { MP_TO_SEC_ERROR(err); return PR_FALSE; } return (cmp == 0) ? PR_TRUE : PR_FALSE; }
static SECStatus init_blinding_params(struct RSABlindingParamsStr *rsabp, RSAPrivateKey *key, mp_int *n, unsigned int modLen) { SECStatus rv = SECSuccess; mp_err err = MP_OKAY; MP_DIGITS(&rsabp->f) = 0; MP_DIGITS(&rsabp->g) = 0; /* initialize blinding parameters */ CHECK_MPI_OK( mp_init(&rsabp->f) ); CHECK_MPI_OK( mp_init(&rsabp->g) ); /* List elements are keyed using the modulus */ SECITEM_CopyItem(NULL, &rsabp->modulus, &key->modulus); CHECK_SEC_OK( generate_blinding_params(rsabp, key, n, modLen) ); return SECSuccess; cleanup: mp_clear(&rsabp->f); mp_clear(&rsabp->g); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* Tests point doubling in Chudnovsky Jacobian coordinates */ mp_err testPointDoubleChud(ECGroup *ecgroup) { mp_err res; mp_int px, py, pz, rx2, ry2, rz2; ecfp_aff_pt p; ecfp_chud_pt p2; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; MP_DIGITS(&rx2) = 0; MP_DIGITS(&ry2) = 0; MP_DIGITS(&rz2) = 0; MP_DIGITS(&px) = 0; MP_DIGITS(&py) = 0; MP_DIGITS(&pz) = 0; MP_CHECKOK(mp_init(&rx2)); MP_CHECKOK(mp_init(&ry2)); MP_CHECKOK(mp_init(&rz2)); MP_CHECKOK(mp_init(&px)); MP_CHECKOK(mp_init(&py)); MP_CHECKOK(mp_init(&pz)); /* Set p2 = 2P */ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup); group->pt_dbl_aff2chud(&p, &p2, group); /* Calculate doubling to compare against */ MP_CHECKOK(mp_set_int(&pz, 1)); ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2, &rz2, ecgroup); ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup); /* Do comparison and check az^4 */ MP_CHECKOK(testChudPoint(&p2, &rx2, &ry2, ecgroup)); CLEANUP: if (res == MP_OKAY) printf(" Test Passed - Point Doubling - Chudnovsky Jacobian\n"); else printf("TEST FAILED - Point Doubling - Chudnovsky Jacobian\n"); mp_clear(&rx2); mp_clear(&ry2); mp_clear(&rz2); mp_clear(&px); mp_clear(&py); mp_clear(&pz); return res; }
/* Reverse the operation above for one mp_int. * Reconstruct one mp_int from its column in the weaved array. * "pSrc" points to the offset into the weave array of the bignum we * are going to reconstruct. */ mp_err weave_to_mpi(mp_int *a, /* output, result */ const unsigned char *pSrc, /* input, byte matrix */ mp_size nDigits, /* per mp_int output */ mp_size nBignums) /* bignums in weaved matrix */ { unsigned char *pDest = (unsigned char *)MP_DIGITS(a); unsigned char *endDest = pDest + (nDigits * sizeof(mp_digit)); MP_SIGN(a) = MP_ZPOS; MP_USED(a) = nDigits; for (; pDest < endDest; pSrc += nBignums, pDest++) { *pDest = *pSrc; } s_mp_clamp(a); return MP_OKAY; }
/* Computes R = P - Q. Elliptic curve points P, Q, and R can all be * identical. Uses affine coordinates. Assumes input is already * field-encoded using field_enc, and returns output that is still * field-encoded. */ mp_err ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy, mp_int *rx, mp_int *ry, const ECGroup *group) { mp_err res = MP_OKAY; mp_int nqy; MP_DIGITS(&nqy) = 0; MP_CHECKOK(mp_init(&nqy)); /* nqy = -qy */ MP_CHECKOK(group->meth->field_neg(qy, &nqy, group->meth)); res = group->point_add(px, py, qx, &nqy, rx, ry, group); CLEANUP: mp_clear(&nqy); return res; }