/* * 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; }
mp_err mpp_divis_vector(mp_int *a, const mp_digit *vec, int size, int *which) { ARGCHK(a != NULL && vec != NULL && size > 0, MP_BADARG); return s_mpp_divp(a, vec, size, which); } /* end mpp_divis_vector() */
/* 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; }
/*! 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; }
mp_err mp_pkcs1v15_encrypt(char *msg, int mlen, mp_int *e, mp_int *modulus, char **out, int *olen, rnd_f rand) { int k; char *buf; mp_err res; mp_int mrep; ARGCHK(msg != NULL && mlen >= 0 && e != NULL && modulus != NULL && out != NULL && olen != NULL, MP_BADARG); k = mp_unsigned_bin_size(modulus); /* length of modulus, in bytes */ if((buf = malloc(k)) == NULL) return MP_MEM; /* Encode according to PKCS #1 v1.5 */ if((res = mp_pkcs1v15_encode(msg, mlen, buf, k, rand)) != MP_OKAY) goto CLEANUP; /* Convert encoded message to a big number for encryption */ if((res = mp_init(&mrep)) != MP_OKAY) goto CLEANUP; if((res = mp_os2ip(&mrep, buf, k)) != MP_OKAY) { mp_clear(&mrep); goto CLEANUP; } /* Now, encrypt... */ if((res = mp_rsaep(&mrep, e, modulus, &mrep)) != MP_OKAY) { mp_clear(&mrep); goto CLEANUP; } /* Unpack message representative... */ if((res = mp_i2osp(&mrep, buf, k)) != MP_OKAY) { mp_clear(&mrep); goto CLEANUP; } mp_clear(&mrep); *out = buf; *olen = k; return MP_OKAY; CLEANUP: memset(buf, 0, k); free(buf); return res; } /* end mp_pkcs1v15_encrypt() */
mp_err mpp_random_size(mp_int *a, mp_size prec) { mp_err res; ARGCHK(a != NULL && prec > 0, MP_BADARG); if((res = s_mp_pad(a, prec)) != MP_OKAY) return res; return mpp_random(a); } /* end mpp_random_size() */
mp_err mp_rsavp(mp_int *sig, mp_int *e, mp_int *modulus, mp_int *msg) { ARGCHK(sig != NULL && e != NULL && modulus != NULL && msg != NULL, MP_BADARG); if((mp_cmp_z(sig) < 0) || (mp_cmp(sig, modulus) >= 0)) { return MP_RANGE; } return mp_exptmod(sig, e, modulus, msg); } /* end mp_rsavp() */
mp_err mp_rsasp(mp_int *msg, mp_int *d, mp_int *modulus, mp_int *sig) { ARGCHK(msg != NULL && d != NULL && modulus != NULL && sig != NULL, MP_BADARG); if((mp_cmp_z(msg) < 0) || (mp_cmp(msg, modulus) >= 0)) { return MP_RANGE; } return mp_exptmod(msg, d, modulus, sig); } /* end mp_rsasp() */
mp_err mp_rsaep(mp_int *msg, mp_int *e, mp_int *modulus, mp_int *cipher) { ARGCHK(msg != NULL && e != NULL && modulus != NULL && cipher != NULL, MP_BADARG); /* Insure that message representative is in range of modulus */ if((mp_cmp_z(msg) < 0) || (mp_cmp(msg, modulus) >= 0)) { return MP_RANGE; } return mp_exptmod(msg, e, modulus, cipher); } /* end mp_rsaep() */
mp_err mp_rsadp(mp_int *cipher, mp_int *d, mp_int *modulus, mp_int *msg) { ARGCHK(cipher != NULL && d != NULL && modulus != NULL && msg != NULL, MP_BADARG); /* Insure that ciphertext representative is in range of modulus */ if((mp_cmp_z(cipher) < 0) || (mp_cmp(cipher, modulus) >= 0)) { return MP_RANGE; } return mp_exptmod(cipher, d, modulus, msg); } /* end mp_rsadp() */
/* 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; }
mp_err mp_pkcs1v15_decrypt(char *msg, int mlen, mp_int *d, mp_int *modulus, char **out, int *olen) { int k; char *buf; mp_err res; mp_int mrep; ARGCHK(msg != NULL && d != NULL && modulus != NULL && out != NULL && olen != NULL, MP_BADARG); k = mp_unsigned_bin_size(modulus); /* size of modulus, in bytes */ if(mlen != k) return MP_UNDEF; if((buf = malloc(k)) == NULL) return MP_MEM; /* Convert ciphertext to integer representative */ if((res = mp_init(&mrep)) != MP_OKAY) { free(buf); return res; } if((res = mp_os2ip(&mrep, msg, mlen)) != MP_OKAY) goto CLEANUP; /* Decrypt ... */ if((res = mp_rsadp(&mrep, d, modulus, &mrep)) != MP_OKAY) goto CLEANUP; if((res = mp_i2osp(&mrep, buf, k)) != MP_OKAY) goto CLEANUP; if((res = mp_pkcs1v15_decode(buf, k, buf, olen)) == MP_OKAY) { *out = buf; return MP_OKAY; } CLEANUP: memset(buf, 0, k - 1); free(buf); mp_clear(&mrep); return res; } /* end mp_pkcs1v15_decrypt() */
mp_err mpp_random(mp_int *a) { mp_digit next = 0; unsigned int ix, jx; ARGCHK(a != NULL, MP_BADARG); for(ix = 0; ix < USED(a); ix++) { for(jx = 0; jx < sizeof(mp_digit); jx++) { next = (next << CHAR_BIT) | (RANDOM() & UCHAR_MAX); } DIGIT(a, ix) = next; } return MP_OKAY; } /* end mpp_random() */
/* mpp_divis_primes(a, np) Test whether a is divisible by any of the first 'np' primes. If it is, returns MP_YES and sets *np to the value of the digit that did it. If not, returns MP_NO. */ mp_err mpp_divis_primes(mp_int *a, mp_digit *np) { int size, which; mp_err res; ARGCHK(a != NULL && np != NULL, MP_BADARG); size = (int)*np; if(size > prime_tab_size) size = prime_tab_size; res = mpp_divis_vector(a, prime_tab, size, &which); if(res == MP_YES) *np = prime_tab[which]; return res; } /* end mpp_divis_primes() */
mp_err mp_i2osp(mp_int *x, char *out, int len) { int xlen; ARGCHK(x != NULL && out != NULL && len > 0, MP_BADARG); if((xlen = mp_unsigned_bin_size(x)) > len) { return MP_RANGE; } xlen -= len; if(xlen > 0) memset(out, 0, xlen); mp_to_unsigned_bin(x, (unsigned char *)out + xlen); return MP_OKAY; } /* end mp_i2osp() */
mp_err mpl_bit_set(mp_int *a, int bit) { unsigned int ddigit,bbit; mp_err res; //int bob; ARGCHK(a != NULL, MP_BADARG); //bob=DIGIT_BIT; ddigit = bit / DIGIT_BIT; bbit = bit % DIGIT_BIT; if((res = s_mp_pad(a,ddigit+1)) != MP_OKAY) return res; DIGIT(a, ddigit) = DIGIT(a, ddigit) | (1 << bbit); return MP_OKAY; }
mp_err mpp_divis_d(mp_int *a, mp_digit d) { mp_err res; mp_digit rem; ARGCHK(a != NULL, MP_BADARG); if(d == 0) return MP_NO; if((res = mp_mod_d(a, d, &rem)) != MP_OKAY) return res; if(rem == 0) return MP_YES; else return MP_NO; } /* end mpp_divis_d() */
mp_err mpl_bit_clear(mp_int *a, int bit) { unsigned int ddigit,bbit; ARGCHK(a != NULL, MP_BADARG); ddigit = bit / DIGIT_BIT; bbit = bit % DIGIT_BIT; if( ddigit >= USED(a) ) //il faut clear un bit déjà clear... return MP_OKAY; DIGIT(a, ddigit) = DIGIT(a, ddigit) & ~(1 << bbit); //Enleve les espace inutiles si requis s_mp_clamp(a) return MP_OKAY; }
mp_err mp_pkcs1v15_encode(char *msg, int mlen, char *emsg, int emlen, rnd_f rand) { int poffset; ARGCHK(msg != NULL && mlen >= 0 && emsg != NULL && emlen > 0 && rand != NULL, MP_BADARG); if(mlen > emlen - 10) return MP_RANGE; emsg[0] = 0x02; poffset = emlen - mlen; /* offset of end of padding */ (rand)(emsg + 1, poffset - 2); /* generate random pad */ emsg[poffset - 1] = 0x00; /* zero separator */ memcpy(emsg + poffset, msg, mlen); return MP_OKAY; } /* end mp_pkcs1v15_encode() */
mp_err mp_pkcs1v15_decode(char *emsg, int emlen, char *msg, int *mlen) { int ix, jx, outlen; ARGCHK(emsg != NULL, MP_BADARG); /* If message is less than minimum length, it's an error */ if(emlen < 10) return MP_RANGE; /* Check the format of the packet, error if it's invalid */ if(emsg[0] != 0x02) return MP_UNDEF; /* Look for zero separator */ for(ix = 9; ix < emlen; ix++) if(emsg[ix] == 0x00) break; if(ix == emlen) return MP_UNDEF; /* Make sure padding bytes are valid */ for(jx = 1; jx < ix; jx++) if(emsg[jx] == 0) return MP_UNDEF; outlen = emlen - (ix + 1); if(msg != NULL && outlen > 0) memmove(msg, emsg + (ix + 1), outlen); if(mlen != NULL) *mlen = outlen; return MP_OKAY; } /* end mp_pkcs1v15_decode() */
/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic * curve points P and R can be identical. Uses mixed Modified-Jacobian * co-ordinates for doubling and Chudnovsky Jacobian coordinates for * additions. Assumes input is already field-encoded using field_enc, and * returns output that is still field-encoded. Uses 5-bit window NAF * method (algorithm 11) for scalar-point multiplication from Brown, * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic * Curves Over Prime Fields. */ mp_err ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *group) { mp_err res = MP_OKAY; mp_int precomp[16][2], rz, tpx, tpy; mp_int raz4; mp_int scratch[MAX_SCRATCH]; signed char *naf = NULL; int i, orderBitSize; MP_DIGITS(&rz) = 0; MP_DIGITS(&raz4) = 0; MP_DIGITS(&tpx) = 0; MP_DIGITS(&tpy) = 0; for (i = 0; i < 16; i++) { MP_DIGITS(&precomp[i][0]) = 0; MP_DIGITS(&precomp[i][1]) = 0; } for (i = 0; i < MAX_SCRATCH; i++) { MP_DIGITS(&scratch[i]) = 0; } ARGCHK(group != NULL, MP_BADARG); ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG); /* initialize precomputation table */ MP_CHECKOK(mp_init(&tpx, FLAG(n))); MP_CHECKOK(mp_init(&tpy, FLAG(n)));; MP_CHECKOK(mp_init(&rz, FLAG(n))); MP_CHECKOK(mp_init(&raz4, FLAG(n))); for (i = 0; i < 16; i++) { MP_CHECKOK(mp_init(&precomp[i][0], FLAG(n))); MP_CHECKOK(mp_init(&precomp[i][1], FLAG(n))); } for (i = 0; i < MAX_SCRATCH; i++) { MP_CHECKOK(mp_init(&scratch[i], FLAG(n))); } /* Set out[8] = P */ MP_CHECKOK(mp_copy(px, &precomp[8][0])); MP_CHECKOK(mp_copy(py, &precomp[8][1])); /* Set (tpx, tpy) = 2P */ MP_CHECKOK(group-> point_dbl(&precomp[8][0], &precomp[8][1], &tpx, &tpy, group)); /* Set 3P, 5P, ..., 15P */ for (i = 8; i < 15; i++) { MP_CHECKOK(group-> point_add(&precomp[i][0], &precomp[i][1], &tpx, &tpy, &precomp[i + 1][0], &precomp[i + 1][1], group)); } /* Set -15P, -13P, ..., -P */ for (i = 0; i < 8; i++) { MP_CHECKOK(mp_copy(&precomp[15 - i][0], &precomp[i][0])); MP_CHECKOK(group->meth-> field_neg(&precomp[15 - i][1], &precomp[i][1], group->meth)); } /* R = inf */ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); orderBitSize = mpl_significant_bits(&group->order); /* Allocate memory for NAF */ #ifdef _KERNEL naf = (signed char *) kmem_alloc((orderBitSize + 1), FLAG(n)); #else naf = (signed char *) malloc(sizeof(signed char) * (orderBitSize + 1)); if (naf == NULL) { res = MP_MEM; goto CLEANUP; } #endif /* Compute 5NAF */ ec_compute_wNAF(naf, orderBitSize, n, 5); /* wNAF method */ for (i = orderBitSize; i >= 0; i--) { /* R = 2R */ ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz, &raz4, scratch, group); if (naf[i] != 0) { ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4, &precomp[(naf[i] + 15) / 2][0], &precomp[(naf[i] + 15) / 2][1], rx, ry, &rz, &raz4, scratch, group); } } /* convert result S to affine coordinates */ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group)); CLEANUP: for (i = 0; i < MAX_SCRATCH; i++) { mp_clear(&scratch[i]); } for (i = 0; i < 16; i++) { mp_clear(&precomp[i][0]); mp_clear(&precomp[i][1]); } mp_clear(&tpx); mp_clear(&tpy); mp_clear(&rz); mp_clear(&raz4); #ifdef _KERNEL kmem_free(naf, (orderBitSize + 1)); #else free(naf); #endif 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. * Uses mixed Jacobian-affine coordinates. Input and output values are * assumed to be NOT field-encoded. Uses algorithm 15 (simultaneous * multiple point multiplication) from Brown, Hankerson, Lopez, Menezes. * Software Implementation of the NIST Elliptic Curves over Prime Fields. */ mp_err ec_GFp_pts_mul_jac(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 precomp[4][4][2]; mp_int rz; const mp_int *a, *b; unsigned int i, j; int ai, bi, d; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { MP_DIGITS(&precomp[i][j][0]) = 0; MP_DIGITS(&precomp[i][j][1]) = 0; } } MP_DIGITS(&rz) = 0; 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); } /* initialize precomputation table */ for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { MP_CHECKOK(mp_init(&precomp[i][j][0])); MP_CHECKOK(mp_init(&precomp[i][j][1])); } } /* fill precomputation table */ /* assign {k1, k2} = {a, b} such that len(a) >= len(b) */ if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) { a = k2; b = k1; if (group->meth->field_enc) { MP_CHECKOK(group->meth-> field_enc(px, &precomp[1][0][0], group->meth)); MP_CHECKOK(group->meth-> field_enc(py, &precomp[1][0][1], group->meth)); } else { MP_CHECKOK(mp_copy(px, &precomp[1][0][0])); MP_CHECKOK(mp_copy(py, &precomp[1][0][1])); } MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0])); MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1])); } else { a = k1; b = k2; MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0])); MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1])); if (group->meth->field_enc) { MP_CHECKOK(group->meth-> field_enc(px, &precomp[0][1][0], group->meth)); MP_CHECKOK(group->meth-> field_enc(py, &precomp[0][1][1], group->meth)); } else { MP_CHECKOK(mp_copy(px, &precomp[0][1][0])); MP_CHECKOK(mp_copy(py, &precomp[0][1][1])); } } /* precompute [*][0][*] */ mp_zero(&precomp[0][0][0]); mp_zero(&precomp[0][0][1]); MP_CHECKOK(group-> point_dbl(&precomp[1][0][0], &precomp[1][0][1], &precomp[2][0][0], &precomp[2][0][1], group)); MP_CHECKOK(group-> point_add(&precomp[1][0][0], &precomp[1][0][1], &precomp[2][0][0], &precomp[2][0][1], &precomp[3][0][0], &precomp[3][0][1], group)); /* precompute [*][1][*] */ for (i = 1; i < 4; i++) { MP_CHECKOK(group-> point_add(&precomp[0][1][0], &precomp[0][1][1], &precomp[i][0][0], &precomp[i][0][1], &precomp[i][1][0], &precomp[i][1][1], group)); } /* precompute [*][2][*] */ MP_CHECKOK(group-> point_dbl(&precomp[0][1][0], &precomp[0][1][1], &precomp[0][2][0], &precomp[0][2][1], group)); for (i = 1; i < 4; i++) { MP_CHECKOK(group-> point_add(&precomp[0][2][0], &precomp[0][2][1], &precomp[i][0][0], &precomp[i][0][1], &precomp[i][2][0], &precomp[i][2][1], group)); } /* precompute [*][3][*] */ MP_CHECKOK(group-> point_add(&precomp[0][1][0], &precomp[0][1][1], &precomp[0][2][0], &precomp[0][2][1], &precomp[0][3][0], &precomp[0][3][1], group)); for (i = 1; i < 4; i++) { MP_CHECKOK(group-> point_add(&precomp[0][3][0], &precomp[0][3][1], &precomp[i][0][0], &precomp[i][0][1], &precomp[i][3][0], &precomp[i][3][1], group)); } d = (mpl_significant_bits(a) + 1) / 2; /* R = inf */ MP_CHECKOK(mp_init(&rz)); MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); for (i = d; i-- > 0;) { ai = MP_GET_BIT(a, 2 * i + 1); ai <<= 1; ai |= MP_GET_BIT(a, 2 * i); bi = MP_GET_BIT(b, 2 * i + 1); bi <<= 1; bi |= MP_GET_BIT(b, 2 * i); /* R = 2^2 * R */ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); /* R = R + (ai * A + bi * B) */ MP_CHECKOK(ec_GFp_pt_add_jac_aff (rx, ry, &rz, &precomp[ai][bi][0], &precomp[ai][bi][1], rx, ry, &rz, group)); } MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, 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(&rz); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { mp_clear(&precomp[i][j][0]); mp_clear(&precomp[i][j][1]); } } return res; }
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters * a, b and p are the elliptic curve coefficients and the prime that * determines the field GFp. Elliptic curve points P and R can be * identical. Uses mixed Jacobian-affine coordinates. Assumes input is * already field-encoded using field_enc, and returns output that is still * field-encoded. Uses 4-bit window method. */ mp_err ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *group) { mp_err res = MP_OKAY; mp_int precomp[16][2], rz; int i, ni, d; MP_DIGITS(&rz) = 0; for (i = 0; i < 16; i++) { MP_DIGITS(&precomp[i][0]) = 0; MP_DIGITS(&precomp[i][1]) = 0; } ARGCHK(group != NULL, MP_BADARG); ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG); /* initialize precomputation table */ for (i = 0; i < 16; i++) { MP_CHECKOK(mp_init(&precomp[i][0])); MP_CHECKOK(mp_init(&precomp[i][1])); } /* fill precomputation table */ mp_zero(&precomp[0][0]); mp_zero(&precomp[0][1]); MP_CHECKOK(mp_copy(px, &precomp[1][0])); MP_CHECKOK(mp_copy(py, &precomp[1][1])); for (i = 2; i < 16; i++) { MP_CHECKOK(group-> point_add(&precomp[1][0], &precomp[1][1], &precomp[i - 1][0], &precomp[i - 1][1], &precomp[i][0], &precomp[i][1], group)); } d = (mpl_significant_bits(n) + 3) / 4; /* R = inf */ MP_CHECKOK(mp_init(&rz)); MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz)); for (i = d - 1; i >= 0; i--) { /* compute window ni */ ni = MP_GET_BIT(n, 4 * i + 3); ni <<= 1; ni |= MP_GET_BIT(n, 4 * i + 2); ni <<= 1; ni |= MP_GET_BIT(n, 4 * i + 1); ni <<= 1; ni |= MP_GET_BIT(n, 4 * i); /* R = 2^4 * R */ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group)); /* R = R + (ni * P) */ MP_CHECKOK(ec_GFp_pt_add_jac_aff (rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry, &rz, group)); } /* convert result S to affine coordinates */ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group)); CLEANUP: mp_clear(&rz); for (i = 0; i < 16; i++) { mp_clear(&precomp[i][0]); mp_clear(&precomp[i][1]); } return res; }
mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong, unsigned long * nTries) { mp_digit np; mp_err res; int i = 0; mp_int trial; mp_int q; mp_size num_tests; unsigned char *sieve; ARGCHK(start != 0, MP_BADARG); ARGCHK(nBits > 16, MP_RANGE); sieve = malloc(SIEVE_SIZE); ARGCHK(sieve != NULL, MP_MEM); MP_DIGITS(&trial) = 0; MP_DIGITS(&q) = 0; MP_CHECKOK( mp_init(&trial) ); MP_CHECKOK( mp_init(&q) ); /* values taken from table 4.4, HandBook of Applied Cryptography */ if (nBits >= 1300) { num_tests = 2; } else if (nBits >= 850) { num_tests = 3; } else if (nBits >= 650) { num_tests = 4; } else if (nBits >= 550) { num_tests = 5; } else if (nBits >= 450) { num_tests = 6; } else if (nBits >= 400) { num_tests = 7; } else if (nBits >= 350) { num_tests = 8; } else if (nBits >= 300) { num_tests = 9; } else if (nBits >= 250) { num_tests = 12; } else if (nBits >= 200) { num_tests = 15; } else if (nBits >= 150) { num_tests = 18; } else if (nBits >= 100) { num_tests = 27; } else num_tests = 50; if (strong) --nBits; MP_CHECKOK( mpl_set_bit(start, nBits - 1, 1) ); MP_CHECKOK( mpl_set_bit(start, 0, 1) ); for (i = mpl_significant_bits(start) - 1; i >= nBits; --i) { MP_CHECKOK( mpl_set_bit(start, i, 0) ); } /* start sieveing with prime value of 3. */ MP_CHECKOK(mpp_sieve(start, prime_tab + 1, prime_tab_size - 1, sieve, SIEVE_SIZE) ); #ifdef DEBUG_SIEVE res = 0; for (i = 0; i < SIEVE_SIZE; ++i) { if (!sieve[i]) ++res; } fprintf(stderr,"sieve found %d potential primes.\n", res); #define FPUTC(x,y) fputc(x,y) #else #define FPUTC(x,y) #endif res = MP_NO; for(i = 0; i < SIEVE_SIZE; ++i) { if (sieve[i]) /* this number is composite */ continue; MP_CHECKOK( mp_add_d(start, 2 * i, &trial) ); FPUTC('.', stderr); /* run a Fermat test */ res = mpp_fermat(&trial, 2); if (res != MP_OKAY) { if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } FPUTC('+', stderr); /* If that passed, run some Miller-Rabin tests */ res = mpp_pprime(&trial, num_tests); if (res != MP_OKAY) { if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } FPUTC('!', stderr); if (!strong) break; /* success !! */ /* At this point, we have strong evidence that our candidate is itself prime. If we want a strong prime, we need now to test q = 2p + 1 for primality... */ MP_CHECKOK( mp_mul_2(&trial, &q) ); MP_CHECKOK( mp_add_d(&q, 1, &q) ); /* Test q for small prime divisors ... */ np = prime_tab_size; res = mpp_divis_primes(&q, &np); if (res == MP_YES) { /* is composite */ mp_clear(&q); continue; } if (res != MP_NO) goto CLEANUP; /* And test with Fermat, as with its parent ... */ res = mpp_fermat(&q, 2); if (res != MP_YES) { mp_clear(&q); if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } /* And test with Miller-Rabin, as with its parent ... */ res = mpp_pprime(&q, num_tests); if (res != MP_YES) { mp_clear(&q); if (res == MP_NO) continue; /* was composite */ goto CLEANUP; } /* If it passed, we've got a winner */ mp_exch(&q, &trial); mp_clear(&q); break; } /* end of loop through sieved values */ if (res == MP_YES) mp_exch(&trial, start); CLEANUP: mp_clear(&trial); mp_clear(&q); if (nTries) *nTries += i; if (sieve != NULL) { memset(sieve, 0, SIEVE_SIZE); free (sieve); } return res; }
mp_err mpp_pprime(mp_int *a, int nt) { mp_err res; mp_int x, amo, m, z; /* "amo" = "a minus one" */ int iter; unsigned int jx; mp_size b; ARGCHK(a != NULL, MP_BADARG); MP_DIGITS(&x) = 0; MP_DIGITS(&amo) = 0; MP_DIGITS(&m) = 0; MP_DIGITS(&z) = 0; /* Initialize temporaries... */ MP_CHECKOK( mp_init(&amo)); /* Compute amo = a - 1 for what follows... */ MP_CHECKOK( mp_sub_d(a, 1, &amo) ); b = mp_trailing_zeros(&amo); if (!b) { /* a was even ? */ res = MP_NO; goto CLEANUP; } MP_CHECKOK( mp_init_size(&x, MP_USED(a)) ); MP_CHECKOK( mp_init(&z) ); MP_CHECKOK( mp_init(&m) ); MP_CHECKOK( mp_div_2d(&amo, b, &m, 0) ); /* Do the test nt times... */ for(iter = 0; iter < nt; iter++) { /* Choose a random value for x < a */ s_mp_pad(&x, USED(a)); mpp_random(&x); MP_CHECKOK( mp_mod(&x, a, &x) ); /* Compute z = (x ** m) mod a */ MP_CHECKOK( mp_exptmod(&x, &m, a, &z) ); if(mp_cmp_d(&z, 1) == 0 || mp_cmp(&z, &amo) == 0) { res = MP_YES; continue; } res = MP_NO; /* just in case the following for loop never executes. */ for (jx = 1; jx < b; jx++) { /* z = z^2 (mod a) */ MP_CHECKOK( mp_sqrmod(&z, a, &z) ); res = MP_NO; /* previous line set res to MP_YES */ if(mp_cmp_d(&z, 1) == 0) { break; } if(mp_cmp(&z, &amo) == 0) { res = MP_YES; break; } } /* end testing loop */ /* If the test passes, we will continue iterating, but a failed test means the candidate is definitely NOT prime, so we will immediately break out of this loop */ if(res == MP_NO) break; } /* end iterations loop */ CLEANUP: mp_clear(&m); mp_clear(&z); mp_clear(&x); mp_clear(&amo); return res; } /* end mpp_pprime() */
/* * on some platforms character stores into memory is very expensive since they * generate a read/modify/write operation on the bus. On those platforms * we need to do integer writes to the bus. Because of some unrolled code, * in this current code the size of mp_weave_word must be four. The code that * makes this assumption explicity is called out. (on some platforms a write * of 4 bytes still requires a single read-modify-write operation. * * This function is takes the identical parameters as the function above, * however it lays out the final array differently. Where the previous function * treats the mpi_int as an byte array, this function treats it as an array of * mp_digits where each digit is stored in big endian order. * * since we need to interleave on a byte by byte basis, we need to collect * several mpi structures together into a single uint32 before we write. We * also need to make sure the uint32 is arranged so that the first value of * the first array winds up in b[0]. This means construction of that uint32 * is endian specific (even though the layout of the mp_digits in the array * is always big endian). * * The final data is stored as follows : * * Our same logical array p array, m is sizeof(mp_digit), * N is still count and n is now b_size. If we define p[i].digit[j]0 as the * most significant byte of the word p[i].digit[j], p[i].digit[j]1 as * the next most significant byte of p[i].digit[j], ... and p[i].digit[j]m-1 * is the least significant byte. * Our array would look like: * p[0].digit[0]0 p[1].digit[0]0 ... p[N-2].digit[0]0 p[N-1].digit[0]0 * p[0].digit[0]1 p[1].digit[0]1 ... p[N-2].digit[0]1 p[N-1].digit[0]1 * . . * p[0].digit[0]m-1 p[1].digit[0]m-1 ... p[N-2].digit[0]m-1 p[N-1].digit[0]m-1 * p[0].digit[1]0 p[1].digit[1]0 ... p[N-2].digit[1]0 p[N-1].digit[1]0 * . . * . . * p[0].digit[n-1]m-2 p[1].digit[n-1]m-2 ... p[N-2].digit[n-1]m-2 p[N-1].digit[n-1]m-2 * p[0].digit[n-1]m-1 p[1].digit[n-1]m-1 ... p[N-2].digit[n-1]m-1 p[N-1].digit[n-1]m-1 * */ mp_err mpi_to_weave(const mp_int *a, unsigned char *b, mp_size b_size, mp_size count) { mp_size i; mp_digit *digitsa0; mp_digit *digitsa1; mp_digit *digitsa2; mp_digit *digitsa3; mp_size useda0; mp_size useda1; mp_size useda2; mp_size useda3; mp_weave_word *weaved = (mp_weave_word *)b; count = count/sizeof(mp_weave_word); /* this code pretty much depends on this ! */ #if MP_ARGCHK == 2 assert(WEAVE_WORD_SIZE == 4); assert(sizeof(mp_weave_word) == 4); #endif digitsa0 = MP_DIGITS(&a[0]); digitsa1 = MP_DIGITS(&a[1]); digitsa2 = MP_DIGITS(&a[2]); digitsa3 = MP_DIGITS(&a[3]); useda0 = MP_USED(&a[0]); useda1 = MP_USED(&a[1]); useda2 = MP_USED(&a[2]); useda3 = MP_USED(&a[3]); ARGCHK(MP_SIGN(&a[0]) == MP_ZPOS, MP_BADARG); ARGCHK(MP_SIGN(&a[1]) == MP_ZPOS, MP_BADARG); ARGCHK(MP_SIGN(&a[2]) == MP_ZPOS, MP_BADARG); ARGCHK(MP_SIGN(&a[3]) == MP_ZPOS, MP_BADARG); ARGCHK(useda0 <= b_size, MP_BADARG); ARGCHK(useda1 <= b_size, MP_BADARG); ARGCHK(useda2 <= b_size, MP_BADARG); ARGCHK(useda3 <= b_size, MP_BADARG); #define SAFE_FETCH(digit, used, word) ((word) < (used) ? (digit[word]) : 0) for (i=0; i < b_size; i++) { mp_digit d0 = SAFE_FETCH(digitsa0,useda0,i); mp_digit d1 = SAFE_FETCH(digitsa1,useda1,i); mp_digit d2 = SAFE_FETCH(digitsa2,useda2,i); mp_digit d3 = SAFE_FETCH(digitsa3,useda3,i); register mp_weave_word acc; /* * ONE_STEP takes the MSB of each of our current digits and places that * byte in the appropriate position for writing to the weaved array. * On little endian: * b3 b2 b1 b0 * On big endian: * b0 b1 b2 b3 * When the data is written it would always wind up: * b[0] = b0 * b[1] = b1 * b[2] = b2 * b[3] = b3 * * Once we've written the MSB, we shift the whole digit up left one * byte, putting the Next Most Significant Byte in the MSB position, * so we we repeat the next one step that byte will be written. * NOTE: This code assumes sizeof(mp_weave_word) and MP_WEAVE_WORD_SIZE * is 4. */ #ifdef MP_IS_LITTLE_ENDIAN #define MPI_WEAVE_ONE_STEP \ acc = (d0 >> (MP_DIGIT_BIT-8)) & 0x000000ff; d0 <<= 8; /*b0*/ \ acc |= (d1 >> (MP_DIGIT_BIT-16)) & 0x0000ff00; d1 <<= 8; /*b1*/ \ acc |= (d2 >> (MP_DIGIT_BIT-24)) & 0x00ff0000; d2 <<= 8; /*b2*/ \ acc |= (d3 >> (MP_DIGIT_BIT-32)) & 0xff000000; d3 <<= 8; /*b3*/ \ *weaved = acc; weaved += count; #else #define MPI_WEAVE_ONE_STEP \ acc = (d0 >> (MP_DIGIT_BIT-32)) & 0xff000000; d0 <<= 8; /*b0*/ \ acc |= (d1 >> (MP_DIGIT_BIT-24)) & 0x00ff0000; d1 <<= 8; /*b1*/ \ acc |= (d2 >> (MP_DIGIT_BIT-16)) & 0x0000ff00; d2 <<= 8; /*b2*/ \ acc |= (d3 >> (MP_DIGIT_BIT-8)) & 0x000000ff; d3 <<= 8; /*b3*/ \ *weaved = acc; weaved += count; #endif switch (sizeof(mp_digit)) { case 32: MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP case 16: MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP case 8: MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP case 4: MPI_WEAVE_ONE_STEP MPI_WEAVE_ONE_STEP case 2: MPI_WEAVE_ONE_STEP case 1: MPI_WEAVE_ONE_STEP break; } } return MP_OKAY; }
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters * a, b and p are the elliptic curve coefficients and the prime that * determines the field GFp. Elliptic curve points P and R can be * identical. Uses Jacobian coordinates. Uses 4-bit window method. */ mp_err ec_GFp_point_mul_jac_4w_fp(const mp_int *n, const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *ecgroup) { mp_err res = MP_OKAY; ecfp_jac_pt precomp[16], r; ecfp_aff_pt p; EC_group_fp *group; mp_int rz; int i, ni, d; ARGCHK(ecgroup != NULL, MP_BADARG); ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG); group = (EC_group_fp *) ecgroup->extra1; MP_DIGITS(&rz) = 0; MP_CHECKOK(mp_init(&rz)); /* init p, da */ ecfp_i2fp(p.x, px, ecgroup); ecfp_i2fp(p.y, py, ecgroup); ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup); /* Do precomputation */ group->precompute_jac(precomp, &p, group); /* Do main body of calculations */ d = (mpl_significant_bits(n) + 3) / 4; /* R = inf */ for (i = 0; i < group->numDoubles; i++) { r.z[i] = 0; } for (i = d - 1; i >= 0; i--) { /* compute window ni */ ni = MP_GET_BIT(n, 4 * i + 3); ni <<= 1; ni |= MP_GET_BIT(n, 4 * i + 2); ni <<= 1; ni |= MP_GET_BIT(n, 4 * i + 1); ni <<= 1; ni |= MP_GET_BIT(n, 4 * i); /* R = 2^4 * R */ group->pt_dbl_jac(&r, &r, group); group->pt_dbl_jac(&r, &r, group); group->pt_dbl_jac(&r, &r, group); group->pt_dbl_jac(&r, &r, group); /* R = R + (ni * P) */ group->pt_add_jac(&r, &precomp[ni], &r, group); } /* Convert back to integer */ ecfp_fp2i(rx, r.x, ecgroup); ecfp_fp2i(ry, r.y, ecgroup); ecfp_fp2i(&rz, r.z, ecgroup); /* convert result S to affine coordinates */ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, ecgroup)); CLEANUP: mp_clear(&rz); return res; }