/* 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 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; }
/* 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; }
/* 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; }
/* 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; }
/* Tests point doubling in Modified Jacobian coordinates */ mp_err testPointDoubleJm(ECGroup *ecgroup) { mp_err res; mp_int pz, paz4, rx2, ry2, rz2, raz4; ecfp_jm_pt p, r; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; MP_DIGITS(&pz) = 0; MP_DIGITS(&paz4) = 0; MP_DIGITS(&rx2) = 0; MP_DIGITS(&ry2) = 0; MP_DIGITS(&rz2) = 0; MP_DIGITS(&raz4) = 0; MP_CHECKOK(mp_init(&pz)); MP_CHECKOK(mp_init(&paz4)); MP_CHECKOK(mp_init(&rx2)); MP_CHECKOK(mp_init(&ry2)); MP_CHECKOK(mp_init(&rz2)); MP_CHECKOK(mp_init(&raz4)); /* Set p */ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup); /* paz4 = az^4 */ MP_CHECKOK(mp_set_int(&pz, 5)); mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4); mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4); mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4); ecfp_i2fp(p.z, &pz, ecgroup); ecfp_i2fp(p.az4, &paz4, ecgroup); group->pt_dbl_jm(&p, &r, group); M_TimeOperation(group->pt_dbl_jm(&p, &r, 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 and check az^4 */ MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup)); CLEANUP: if (res == MP_OKAY) printf(" Test Passed - Point Doubling - Modified Jacobian\n"); else printf("TEST FAILED - Point Doubling - Modified Jacobian\n"); mp_clear(&pz); mp_clear(&paz4); mp_clear(&rx2); mp_clear(&ry2); mp_clear(&rz2); mp_clear(&raz4); return res; }
/* Tests point addition in Modified Jacobian + Chudnovsky Jacobian -> * Modified Jacobian coordinates. */ mp_err testPointAddJmChud(ECGroup *ecgroup) { mp_err res; mp_int rx2, ry2, ix, iy, iz, test, pz, paz4, qx, qy, qz; ecfp_chud_pt q; ecfp_jm_pt p, r; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; MP_DIGITS(&qx) = 0; MP_DIGITS(&qy) = 0; MP_DIGITS(&qz) = 0; MP_DIGITS(&pz) = 0; MP_DIGITS(&paz4) = 0; MP_DIGITS(&iz) = 0; MP_DIGITS(&rx2) = 0; MP_DIGITS(&ry2) = 0; MP_DIGITS(&ix) = 0; MP_DIGITS(&iy) = 0; MP_DIGITS(&iz) = 0; MP_DIGITS(&test) = 0; MP_CHECKOK(mp_init(&qx)); MP_CHECKOK(mp_init(&qy)); MP_CHECKOK(mp_init(&qz)); MP_CHECKOK(mp_init(&pz)); MP_CHECKOK(mp_init(&paz4)); MP_CHECKOK(mp_init(&rx2)); MP_CHECKOK(mp_init(&ry2)); MP_CHECKOK(mp_init(&ix)); MP_CHECKOK(mp_init(&iy)); MP_CHECKOK(mp_init(&iz)); MP_CHECKOK(mp_init(&test)); /* Test Modified Jacobian form addition */ /* Set p */ ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup); /* paz4 = az^4 */ MP_CHECKOK(mp_set_int(&pz, 5)); mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4); mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4); mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4); ecfp_i2fp(p.z, &pz, ecgroup); ecfp_i2fp(p.az4, &paz4, ecgroup); /* Set q */ MP_CHECKOK(mp_set_int(&qz, 105)); ecfp_i2fp(q.x, &ecgroup->geny, ecgroup); ecfp_i2fp(q.y, &ecgroup->genx, ecgroup); ecfp_i2fp(q.z, &qz, ecgroup); mp_sqrmod(&qz, &ecgroup->meth->irr, &test); ecfp_i2fp(q.z2, &test, ecgroup); mp_mulmod(&test, &qz, &ecgroup->meth->irr, &test); ecfp_i2fp(q.z3, &test, ecgroup); /* Do calculation */ group->pt_add_jm_chud(&p, &q, &r, group); /* Calculate addition to compare against */ ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy, ecgroup); ec_GFp_pt_add_jac_aff(&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy, &ix, &iy, &iz, ecgroup); ec_GFp_pt_jac2aff(&ix, &iy, &iz, &rx2, &ry2, ecgroup); MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup)); CLEANUP: if (res == MP_OKAY) printf (" Test Passed - Point Addition - Modified & Chudnovsky Jacobian\n"); else printf ("TEST FAILED - Point Addition - Modified & Chudnovsky Jacobian\n"); mp_clear(&qx); mp_clear(&qy); mp_clear(&qz); mp_clear(&pz); mp_clear(&paz4); mp_clear(&rx2); mp_clear(&ry2); mp_clear(&ix); mp_clear(&iy); mp_clear(&iz); mp_clear(&test); return res; }
/* Tests a point p in Chudnovsky Jacobian coordinates, comparing against * the expected affine result (x, y). */ mp_err testChudPoint(ecfp_chud_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup) { char s[1000]; mp_int rx, ry, rz, rz2, rz3, test; mp_err res = MP_OKAY; /* Initialization */ MP_DIGITS(&rx) = 0; MP_DIGITS(&ry) = 0; MP_DIGITS(&rz) = 0; MP_DIGITS(&rz2) = 0; MP_DIGITS(&rz3) = 0; MP_DIGITS(&test) = 0; MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&rz)); MP_CHECKOK(mp_init(&rz2)); MP_CHECKOK(mp_init(&rz3)); MP_CHECKOK(mp_init(&test)); /* Convert to integers */ ecfp_fp2i(&rx, p->x, ecgroup); ecfp_fp2i(&ry, p->y, ecgroup); ecfp_fp2i(&rz, p->z, ecgroup); ecfp_fp2i(&rz2, p->z2, ecgroup); ecfp_fp2i(&rz3, p->z3, ecgroup); /* Verify z2, z3 are valid */ mp_sqrmod(&rz, &ecgroup->meth->irr, &test); if (mp_cmp(&test, &rz2) != 0) { printf(" Error: rzp2 not valid\n"); res = MP_NO; goto CLEANUP; } mp_mulmod(&test, &rz, &ecgroup->meth->irr, &test); if (mp_cmp(&test, &rz3) != 0) { printf(" Error: rzp2 not valid\n"); res = MP_NO; goto CLEANUP; } /* convert result R to affine coordinates */ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup); /* Compare against expected result */ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) { printf(" Error: Chudnovsky 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); mp_clear(&rz2); mp_clear(&rz3); mp_clear(&test); return res; }
/* Tests a point p in Modified Jacobian coordinates, comparing against the * expected affine result (x, y). */ mp_err testJmPoint(ecfp_jm_pt * r, mp_int *x, mp_int *y, ECGroup *ecgroup) { char s[1000]; mp_int rx, ry, rz, raz4, test; mp_err res = MP_OKAY; /* Initialization */ MP_DIGITS(&rx) = 0; MP_DIGITS(&ry) = 0; MP_DIGITS(&rz) = 0; MP_DIGITS(&raz4) = 0; MP_DIGITS(&test) = 0; MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&rz)); MP_CHECKOK(mp_init(&raz4)); MP_CHECKOK(mp_init(&test)); /* Convert to integer */ ecfp_fp2i(&rx, r->x, ecgroup); ecfp_fp2i(&ry, r->y, ecgroup); ecfp_fp2i(&rz, r->z, ecgroup); ecfp_fp2i(&raz4, r->az4, ecgroup); /* Verify raz4 = rz^4 * a */ mp_sqrmod(&rz, &ecgroup->meth->irr, &test); mp_sqrmod(&test, &ecgroup->meth->irr, &test); mp_mulmod(&test, &ecgroup->curvea, &ecgroup->meth->irr, &test); if (mp_cmp(&test, &raz4) != 0) { printf(" Error: a*z^4 not valid\n"); MP_CHECKOK(mp_toradix(&ecgroup->curvea, s, 16)); printf("a %s\n", s); MP_CHECKOK(mp_toradix(&rz, s, 16)); printf("rz %s\n", s); MP_CHECKOK(mp_toradix(&raz4, s, 16)); printf("raz4 %s\n", s); res = MP_NO; goto CLEANUP; } /* convert result R to affine coordinates */ ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup); /* Compare against expected result */ if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) { printf(" Error: Modified 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); mp_clear(&raz4); mp_clear(&test); 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; }
/* 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; }
/* Uses mixed Jacobian-affine coordinates to perform a point * multiplication: R = n * P, n scalar. Uses mixed Jacobian-affine * coordinates (Jacobian coordinates for doubles and affine coordinates * for additions; based on recommendation from Brown et al.). Not very * time efficient but quite space efficient, no precomputation needed. * group contains the elliptic curve coefficients and the prime that * determines the field GFp. Elliptic curve points P and R can be * identical. Performs calculations in floating point number format, since * this is faster than the integer operations on the ULTRASPARC III. * Uses left-to-right binary method (double & add) (algorithm 9) 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_jac_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_int sx, sy, sz; ecfp_aff_pt p; ecfp_jac_pt r; EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; int i, l; 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); /* Init r to point at infinity */ for (i = 0; i < group->numDoubles; i++) { r.z[i] = 0; } /* double and add method */ l = mpl_significant_bits(n) - 1; for (i = l; i >= 0; i--) { /* R = 2R */ group->pt_dbl_jac(&r, &r, group); /* if n_i = 1, then R = R + Q */ if (MP_GET_BIT(n, i) != 0) { group->pt_add_jac_aff(&r, &p, &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 (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; }