/* * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for * the curve whose parameters are encoded in params with base point G. */ SECStatus ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2, const SECItem *pointP, SECItem *pointQ) { mp_int Px, Py, Qx, Qy; mp_int Gx, Gy, order, irreducible, a, b; #if 0 /* currently don't support non-named curves */ unsigned int irr_arr[5]; #endif ECGroup *group = NULL; SECStatus rv = SECFailure; mp_err err = MP_OKAY; int len; #if EC_DEBUG int i; char mpstr[256]; printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len); for (i = 0; i < params->DEREncoding.len; i++) printf("%02x:", params->DEREncoding.data[i]); printf("\n"); if (k1 != NULL) { mp_tohex(k1, mpstr); printf("ec_points_mul: scalar k1: %s\n", mpstr); mp_todecimal(k1, mpstr); printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr); } if (k2 != NULL) { mp_tohex(k2, mpstr); printf("ec_points_mul: scalar k2: %s\n", mpstr); mp_todecimal(k2, mpstr); printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr); } if (pointP != NULL) { printf("ec_points_mul: pointP [len=%d]:", pointP->len); for (i = 0; i < pointP->len; i++) printf("%02x:", pointP->data[i]); printf("\n"); } #endif /* NOTE: We only support uncompressed points for now */ len = (params->fieldID.size + 7) >> 3; if (pointP != NULL) { if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || (pointP->len != (2 * len + 1))) { PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); return SECFailure; }; } MP_DIGITS(&Px) = 0; MP_DIGITS(&Py) = 0; MP_DIGITS(&Qx) = 0; MP_DIGITS(&Qy) = 0; MP_DIGITS(&Gx) = 0; MP_DIGITS(&Gy) = 0; MP_DIGITS(&order) = 0; MP_DIGITS(&irreducible) = 0; MP_DIGITS(&a) = 0; MP_DIGITS(&b) = 0; CHECK_MPI_OK( mp_init(&Px) ); CHECK_MPI_OK( mp_init(&Py) ); CHECK_MPI_OK( mp_init(&Qx) ); CHECK_MPI_OK( mp_init(&Qy) ); CHECK_MPI_OK( mp_init(&Gx) ); CHECK_MPI_OK( mp_init(&Gy) ); CHECK_MPI_OK( mp_init(&order) ); CHECK_MPI_OK( mp_init(&irreducible) ); CHECK_MPI_OK( mp_init(&a) ); CHECK_MPI_OK( mp_init(&b) ); if ((k2 != NULL) && (pointP != NULL)) { /* Initialize Px and Py */ CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) ); } /* construct from named params, if possible */ if (params->name != ECCurve_noName) { group = ECGroup_fromName(params->name); } #if 0 /* currently don't support non-named curves */ if (group == NULL) { /* Set up mp_ints containing the curve coefficients */ CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len, (mp_size) len) ); SECITEM_TO_MPINT( params->order, &order ); SECITEM_TO_MPINT( params->curve.a, &a ); SECITEM_TO_MPINT( params->curve.b, &b ); if (params->fieldID.type == ec_field_GFp) { SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible ); group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor); } else { SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible ); irr_arr[0] = params->fieldID.size; irr_arr[1] = params->fieldID.k1; irr_arr[2] = params->fieldID.k2; irr_arr[3] = params->fieldID.k3; irr_arr[4] = 0; group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor); } } #endif if (group == NULL) goto cleanup; if ((k2 != NULL) && (pointP != NULL)) { CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) ); } else { CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) ); } /* Construct the SECItem representation of point Q */ pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED; CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1, (mp_size) len) ); CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len, (mp_size) len) ); rv = SECSuccess; #if EC_DEBUG printf("ec_points_mul: pointQ [len=%d]:", pointQ->len); for (i = 0; i < pointQ->len; i++) printf("%02x:", pointQ->data[i]); printf("\n"); #endif cleanup: ECGroup_free(group); mp_clear(&Px); mp_clear(&Py); mp_clear(&Qx); mp_clear(&Qy); mp_clear(&Gx); mp_clear(&Gy); mp_clear(&order); mp_clear(&irreducible); mp_clear(&a); mp_clear(&b); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/* Construct ECGroup from hex parameters and name, if any. Called by * ECGroup_fromHex and ECGroup_fromName. */ ECGroup * ecgroup_fromNameAndHex(const ECCurveName name, const ECCurveParams * params) { mp_int irr, curvea, curveb, genx, geny, order; int bits; ECGroup *group = NULL; mp_err res = MP_OKAY; /* initialize values */ MP_DIGITS(&irr) = 0; MP_DIGITS(&curvea) = 0; MP_DIGITS(&curveb) = 0; MP_DIGITS(&genx) = 0; MP_DIGITS(&geny) = 0; MP_DIGITS(&order) = 0; MP_CHECKOK(mp_init(&irr)); MP_CHECKOK(mp_init(&curvea)); MP_CHECKOK(mp_init(&curveb)); MP_CHECKOK(mp_init(&genx)); MP_CHECKOK(mp_init(&geny)); MP_CHECKOK(mp_init(&order)); MP_CHECKOK(mp_read_radix(&irr, params->irr, 16)); MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16)); MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16)); MP_CHECKOK(mp_read_radix(&genx, params->genx, 16)); MP_CHECKOK(mp_read_radix(&geny, params->geny, 16)); MP_CHECKOK(mp_read_radix(&order, params->order, 16)); /* determine number of bits */ bits = mpl_significant_bits(&irr) - 1; if (bits < MP_OKAY) { res = bits; goto CLEANUP; } /* determine which optimizations (if any) to use */ if (params->field == ECField_GFp) { switch (name) { #ifdef NSS_ECC_MORE_THAN_SUITE_B #ifdef ECL_USE_FP case ECCurve_SECG_PRIME_160R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_secp160r1_fp(group)); break; #endif case ECCurve_SECG_PRIME_192R1: #ifdef ECL_USE_FP group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_nistp192_fp(group)); #else group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp192(group, name)); #endif break; case ECCurve_SECG_PRIME_224R1: #ifdef ECL_USE_FP group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_nistp224_fp(group)); #else group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp224(group, name)); #endif break; #endif /* NSS_ECC_MORE_THAN_SUITE_B */ case ECCurve_SECG_PRIME_256R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp256(group, name)); MP_CHECKOK(ec_group_set_gfp256_32(group, name)); break; case ECCurve_SECG_PRIME_521R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } MP_CHECKOK(ec_group_set_gfp521(group, name)); break; default: /* use generic arithmetic */ group = ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } } #ifdef NSS_ECC_MORE_THAN_SUITE_B } else if (params->field == ECField_GF2m) { group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor); if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } if ((name == ECCurve_NIST_K163) || (name == ECCurve_NIST_B163) || (name == ECCurve_SECG_CHAR2_163R1)) { MP_CHECKOK(ec_group_set_gf2m163(group, name)); } else if ((name == ECCurve_SECG_CHAR2_193R1) || (name == ECCurve_SECG_CHAR2_193R2)) { MP_CHECKOK(ec_group_set_gf2m193(group, name)); } else if ((name == ECCurve_NIST_K233) || (name == ECCurve_NIST_B233)) { MP_CHECKOK(ec_group_set_gf2m233(group, name)); } #endif } else { res = MP_UNDEF; goto CLEANUP; } /* set name, if any */ if ((group != NULL) && (params->text != NULL)) { group->text = strdup(params->text); if (group->text == NULL) { res = MP_MEM; } } CLEANUP: mp_clear(&irr); mp_clear(&curvea); mp_clear(&curveb); mp_clear(&genx); mp_clear(&geny); mp_clear(&order); if (res != MP_OKAY) { ECGroup_free(group); return NULL; } return group; }