/* 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. 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_point_mul_wNAF_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; mp_int sx, sy, sz; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; ecfp_chud_pt precomp[16]; ecfp_aff_pt p; ecfp_jm_pt r; signed char naf[group->orderBitSize + 1]; int i; MP_DIGITS(&sx) = 0; MP_DIGITS(&sy) = 0; MP_DIGITS(&sz) = 0; MP_CHECKOK(mp_init(&sx)); MP_CHECKOK(mp_init(&sy)); MP_CHECKOK(mp_init(&sz)); /* if n = 0 then r = inf */ if (mp_cmp_z(n) == 0) { mp_zero(rx); mp_zero(ry); res = MP_OKAY; goto CLEANUP; /* if n < 0 then out of range error */ } else if (mp_cmp_z(n) < 0) { res = MP_RANGE; goto CLEANUP; } /* Convert from integer to floating point */ ecfp_i2fp(p.x, px, ecgroup); ecfp_i2fp(p.y, py, ecgroup); ecfp_i2fp(group->curvea, &(ecgroup->curvea), ecgroup); /* Perform precomputation */ group->precompute_chud(precomp, &p, group); /* Compute 5NAF */ ec_compute_wNAF(naf, group->orderBitSize, n, 5); /* Init R = pt at infinity */ for (i = 0; i < group->numDoubles; i++) { r.z[i] = 0; } /* wNAF method */ for (i = group->orderBitSize; i >= 0; i--) { /* R = 2R */ group->pt_dbl_jm(&r, &r, group); if (naf[i] != 0) { group->pt_add_jm_chud(&r, &precomp[(naf[i] + 15) / 2], &r, group); } } /* Convert from floating point to integer */ ecfp_fp2i(&sx, r.x, ecgroup); ecfp_fp2i(&sy, r.y, ecgroup); ecfp_fp2i(&sz, r.z, ecgroup); /* convert result R to affine coordinates */ MP_CHECKOK(ec_GFp_pt_jac2aff(&sx, &sy, &sz, rx, ry, ecgroup)); CLEANUP: mp_clear(&sx); mp_clear(&sy); mp_clear(&sz); return res; }
/* 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; }
static void ec_GFp_nistp256_point_mul_public(const EC_GROUP *group, EC_RAW_POINT *r, const EC_SCALAR *g_scalar, const EC_RAW_POINT *p, const EC_SCALAR *p_scalar) { #define P256_WSIZE_PUBLIC 4 // Precompute multiples of |p|. p_pre_comp[i] is (2*i+1) * |p|. fe p_pre_comp[1 << (P256_WSIZE_PUBLIC-1)][3]; fe_from_generic(p_pre_comp[0][0], &p->X); fe_from_generic(p_pre_comp[0][1], &p->Y); fe_from_generic(p_pre_comp[0][2], &p->Z); fe p2[3]; point_double(p2[0], p2[1], p2[2], p_pre_comp[0][0], p_pre_comp[0][1], p_pre_comp[0][2]); for (size_t i = 1; i < OPENSSL_ARRAY_SIZE(p_pre_comp); i++) { point_add(p_pre_comp[i][0], p_pre_comp[i][1], p_pre_comp[i][2], p_pre_comp[i - 1][0], p_pre_comp[i - 1][1], p_pre_comp[i - 1][2], 0 /* not mixed */, p2[0], p2[1], p2[2]); } // Set up the coefficients for |p_scalar|. int8_t p_wNAF[257]; ec_compute_wNAF(group, p_wNAF, p_scalar, 256, P256_WSIZE_PUBLIC); // Set |ret| to the point at infinity. int skip = 1; // Save some point operations. fe ret[3] = {{0},{0},{0}}; for (int i = 256; i >= 0; i--) { if (!skip) { point_double(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2]); } // For the |g_scalar|, we use the precomputed table without the // constant-time lookup. if (i <= 31) { // First, look 32 bits upwards. uint64_t bits = get_bit(g_scalar->bytes, i + 224) << 3; bits |= get_bit(g_scalar->bytes, i + 160) << 2; bits |= get_bit(g_scalar->bytes, i + 96) << 1; bits |= get_bit(g_scalar->bytes, i + 32); point_add(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2], 1 /* mixed */, g_pre_comp[1][bits][0], g_pre_comp[1][bits][1], g_pre_comp[1][bits][2]); skip = 0; // Second, look at the current position. bits = get_bit(g_scalar->bytes, i + 192) << 3; bits |= get_bit(g_scalar->bytes, i + 128) << 2; bits |= get_bit(g_scalar->bytes, i + 64) << 1; bits |= get_bit(g_scalar->bytes, i); point_add(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2], 1 /* mixed */, g_pre_comp[0][bits][0], g_pre_comp[0][bits][1], g_pre_comp[0][bits][2]); } int digit = p_wNAF[i]; if (digit != 0) { assert(digit & 1); int idx = digit < 0 ? (-digit) >> 1 : digit >> 1; fe *y = &p_pre_comp[idx][1], tmp; if (digit < 0) { fe_opp(tmp, p_pre_comp[idx][1]); y = &tmp; } if (!skip) { point_add(ret[0], ret[1], ret[2], ret[0], ret[1], ret[2], 0 /* not mixed */, p_pre_comp[idx][0], *y, p_pre_comp[idx][2]); } else { fe_copy(ret[0], p_pre_comp[idx][0]); fe_copy(ret[1], *y); fe_copy(ret[2], p_pre_comp[idx][2]); skip = 0; } } }