diff -r 000000000000 -r 6474c204b198 security/nss/lib/freebl/ecl/tests/ecp_fpt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/security/nss/lib/freebl/ecl/tests/ecp_fpt.c Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,1088 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ecp_fp.h" +#include "mpprime.h" + +#include +#include +#include +#include + +/* Time k repetitions of operation op. */ +#define M_TimeOperation(op, k) { \ + double dStart, dNow, dUserTime; \ + struct rusage ru; \ + int i; \ + getrusage(RUSAGE_SELF, &ru); \ + dStart = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \ + for (i = 0; i < k; i++) { \ + { op; } \ + }; \ + getrusage(RUSAGE_SELF, &ru); \ + dNow = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \ + dUserTime = dNow-dStart; \ + if (dUserTime) printf(" %-45s\n k: %6i, t: %6.2f sec, k/t: %6.2f ops/sec\n", #op, k, dUserTime, k/dUserTime); \ +} + +/* Test curve using specific floating point field arithmetic. */ +#define M_TestCurve(name_c, name) { \ + printf("Testing %s using specific floating point implementation...\n", name_c); \ + ECGroup_free(ecgroup); \ + ecgroup = ECGroup_fromName(name); \ + if (ecgroup == NULL) { \ + printf(" Warning: could not construct group.\n"); \ + printf("%s failed.\n", name_c); \ + res = MP_NO; \ + goto CLEANUP; \ + } else { \ + MP_CHECKOK( testCurve(ecgroup)); \ + printf("%s passed.\n", name_c); \ + } \ +} + +/* Outputs a floating point double (currently not used) */ +void +d_output(const double *u, int len, char *name, const EC_group_fp * group) +{ + int i; + + printf("%s: ", name); + for (i = 0; i < len; i++) { + printf("+ %.2f * 2^%i ", u[i] / ecfp_exp[i], + group->doubleBitSize * i); + } + printf("\n"); +} + +/* 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; +} + +/* 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; +} + +/* 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 point addition in Jacobian coordinates */ +mp_err +testPointAddJac(ECGroup *ecgroup) +{ + mp_err res; + mp_int pz, qz, qx, qy, rx2, ry2, rz2; + ecfp_jac_pt p, q, r; + EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; + + /* Init */ + MP_DIGITS(&pz) = 0; + MP_DIGITS(&qx) = 0; + MP_DIGITS(&qy) = 0; + MP_DIGITS(&qz) = 0; + MP_DIGITS(&rx2) = 0; + MP_DIGITS(&ry2) = 0; + MP_DIGITS(&rz2) = 0; + MP_CHECKOK(mp_init(&pz)); + MP_CHECKOK(mp_init(&qx)); + MP_CHECKOK(mp_init(&qy)); + MP_CHECKOK(mp_init(&qz)); + MP_CHECKOK(mp_init(&rx2)); + MP_CHECKOK(mp_init(&ry2)); + MP_CHECKOK(mp_init(&rz2)); + + MP_CHECKOK(mp_set_int(&pz, 5)); + MP_CHECKOK(mp_set_int(&qz, 105)); + + /* 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); + ecfp_i2fp(q.z, &qz, ecgroup); + + /* Do calculations */ + group->pt_add_jac(&p, &q, &r, group); + + /* Do calculation in integer to compare against */ + ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy, + ecgroup); + MP_CHECKOK(ec_GFp_pt_add_jac_aff + (&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy, &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\n"); + else + printf("TEST FAILED - Point Addition - Jacobian\n"); + + mp_clear(&pz); + mp_clear(&qx); + mp_clear(&qy); + mp_clear(&qz); + mp_clear(&rx2); + mp_clear(&ry2); + mp_clear(&rz2); + + return res; +} + +/* Tests point addition in Chudnovsky Jacobian Coordinates */ +mp_err +testPointAddChud(ECGroup *ecgroup) +{ + mp_err res; + mp_int rx2, ry2, ix, iy, iz, test, pz, qx, qy, qz; + ecfp_chud_pt p, q, 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(&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(&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 Chudnovsky form addition */ + /* Set p */ + MP_CHECKOK(mp_set_int(&pz, 5)); + ecfp_i2fp(p.x, &ecgroup->genx, ecgroup); + ecfp_i2fp(p.y, &ecgroup->geny, ecgroup); + ecfp_i2fp(p.z, &pz, ecgroup); + mp_sqrmod(&pz, &ecgroup->meth->irr, &test); + ecfp_i2fp(p.z2, &test, ecgroup); + mp_mulmod(&test, &pz, &ecgroup->meth->irr, &test); + ecfp_i2fp(p.z3, &test, 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); + + group->pt_add_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(testChudPoint(&r, &rx2, &ry2, ecgroup)); + + CLEANUP: + if (res == MP_OKAY) + printf(" Test Passed - Point Addition - Chudnovsky Jacobian\n"); + else + printf("TEST FAILED - Point Addition - Chudnovsky Jacobian\n"); + + mp_clear(&qx); + mp_clear(&qy); + mp_clear(&qz); + mp_clear(&pz); + mp_clear(&rx2); + mp_clear(&ry2); + mp_clear(&ix); + mp_clear(&iy); + mp_clear(&iz); + mp_clear(&test); + + 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 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 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; +} + +/* 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 multiplication (various algorithms) */ +mp_err +testPointMul(ECGroup *ecgroup) +{ + mp_err res; + char s[1000]; + mp_int rx, ry, order_1; + + /* Init */ + MP_DIGITS(&rx) = 0; + MP_DIGITS(&ry) = 0; + MP_DIGITS(&order_1) = 0; + + MP_CHECKOK(mp_init(&rx)); + MP_CHECKOK(mp_init(&ry)); + MP_CHECKOK(mp_init(&order_1)); + + MP_CHECKOK(mp_set_int(&order_1, 1)); + MP_CHECKOK(mp_sub(&ecgroup->order, &order_1, &order_1)); + + /* Test Algorithm 1: Jacobian-Affine Double & Add */ + ec_GFp_pt_mul_jac_fp(&order_1, &ecgroup->genx, &ecgroup->geny, &rx, + &ry, ecgroup); + MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth)); + if ((mp_cmp(&rx, &ecgroup->genx) != 0) + || (mp_cmp(&ry, &ecgroup->geny) != 0)) { + printf + (" Error: ec_GFp_pt_mul_jac_fp invalid result (expected (- base point)).\n"); + MP_CHECKOK(mp_toradix(&rx, s, 16)); + printf("rx %s\n", s); + MP_CHECKOK(mp_toradix(&ry, s, 16)); + printf("ry %s\n", s); + res = MP_NO; + goto CLEANUP; + } + + ec_GFp_pt_mul_jac_fp(&ecgroup->order, &ecgroup->genx, &ecgroup->geny, + &rx, &ry, ecgroup); + if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { + printf + (" Error: ec_GFp_pt_mul_jac_fp invalid result (expected point at infinity.\n"); + MP_CHECKOK(mp_toradix(&rx, s, 16)); + printf("rx %s\n", s); + MP_CHECKOK(mp_toradix(&ry, s, 16)); + printf("ry %s\n", s); + res = MP_NO; + goto CLEANUP; + } + + /* Test Algorithm 2: 4-bit Window in Jacobian */ + ec_GFp_point_mul_jac_4w_fp(&order_1, &ecgroup->genx, &ecgroup->geny, + &rx, &ry, ecgroup); + MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth)); + if ((mp_cmp(&rx, &ecgroup->genx) != 0) + || (mp_cmp(&ry, &ecgroup->geny) != 0)) { + printf + (" Error: ec_GFp_point_mul_jac_4w_fp invalid result (expected (- base point)).\n"); + MP_CHECKOK(mp_toradix(&rx, s, 16)); + printf("rx %s\n", s); + MP_CHECKOK(mp_toradix(&ry, s, 16)); + printf("ry %s\n", s); + res = MP_NO; + goto CLEANUP; + } + + ec_GFp_point_mul_jac_4w_fp(&ecgroup->order, &ecgroup->genx, + &ecgroup->geny, &rx, &ry, ecgroup); + if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { + printf + (" Error: ec_GFp_point_mul_jac_4w_fp invalid result (expected point at infinity.\n"); + MP_CHECKOK(mp_toradix(&rx, s, 16)); + printf("rx %s\n", s); + MP_CHECKOK(mp_toradix(&ry, s, 16)); + printf("ry %s\n", s); + res = MP_NO; + goto CLEANUP; + } + + /* Test Algorithm 3: wNAF with modified Jacobian coordinates */ + ec_GFp_point_mul_wNAF_fp(&order_1, &ecgroup->genx, &ecgroup->geny, &rx, + &ry, ecgroup); + MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth)); + if ((mp_cmp(&rx, &ecgroup->genx) != 0) + || (mp_cmp(&ry, &ecgroup->geny) != 0)) { + printf + (" Error: ec_GFp_pt_mul_wNAF_fp invalid result (expected (- base point)).\n"); + MP_CHECKOK(mp_toradix(&rx, s, 16)); + printf("rx %s\n", s); + MP_CHECKOK(mp_toradix(&ry, s, 16)); + printf("ry %s\n", s); + res = MP_NO; + goto CLEANUP; + } + + ec_GFp_point_mul_wNAF_fp(&ecgroup->order, &ecgroup->genx, + &ecgroup->geny, &rx, &ry, ecgroup); + if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { + printf + (" Error: ec_GFp_pt_mul_wNAF_fp invalid result (expected point at infinity.\n"); + MP_CHECKOK(mp_toradix(&rx, s, 16)); + printf("rx %s\n", s); + MP_CHECKOK(mp_toradix(&ry, s, 16)); + printf("ry %s\n", s); + res = MP_NO; + goto CLEANUP; + } + + CLEANUP: + if (res == MP_OKAY) + printf(" Test Passed - Point Multiplication\n"); + else + printf("TEST FAILED - Point Multiplication\n"); + mp_clear(&rx); + mp_clear(&ry); + mp_clear(&order_1); + + return res; +} + +/* Tests point multiplication with a random scalar repeatedly, comparing + * for consistency within different algorithms. */ +mp_err +testPointMulRandom(ECGroup *ecgroup) +{ + mp_err res; + mp_int rx, ry, rx2, ry2, n; + int i, size; + EC_group_fp *group = (EC_group_fp *) ecgroup->extra1; + + MP_DIGITS(&rx) = 0; + MP_DIGITS(&ry) = 0; + MP_DIGITS(&rx2) = 0; + MP_DIGITS(&ry2) = 0; + MP_DIGITS(&n) = 0; + + MP_CHECKOK(mp_init(&rx)); + MP_CHECKOK(mp_init(&ry)); + MP_CHECKOK(mp_init(&rx2)); + MP_CHECKOK(mp_init(&ry2)); + MP_CHECKOK(mp_init(&n)); + + for (i = 0; i < 100; i++) { + /* 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, group->orderBitSize)); + MP_CHECKOK(mp_mod(&n, &ecgroup->order, &n)); + + ec_GFp_pt_mul_jac(&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry, + ecgroup); + ec_GFp_pt_mul_jac_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx2, + &ry2, ecgroup); + + if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) { + printf + (" Error: different results for Point Multiplication - Double & Add.\n"); + res = MP_NO; + goto CLEANUP; + } + + ec_GFp_point_mul_wNAF_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx, + &ry, ecgroup); + if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) { + printf + (" Error: different results for Point Multiplication - wNAF.\n"); + res = MP_NO; + goto CLEANUP; + } + + ec_GFp_point_mul_jac_4w_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx, + &ry, ecgroup); + if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) { + printf + (" Error: different results for Point Multiplication - 4 bit window.\n"); + res = MP_NO; + goto CLEANUP; + } + + } + + CLEANUP: + if (res == MP_OKAY) + printf(" Test Passed - Point Random Multiplication\n"); + else + printf("TEST FAILED - Point Random Multiplication\n"); + mp_clear(&rx); + mp_clear(&ry); + mp_clear(&rx2); + mp_clear(&ry2); + mp_clear(&n); + + return res; +} + +/* 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; +} + +/* 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; +} + +/* Given a curve using floating point arithmetic, test it. This method + * specifies which of the above tests to run. */ +mp_err +testCurve(ECGroup *ecgroup) +{ + int res = MP_OKAY; + + MP_CHECKOK(testPointAddJacAff(ecgroup)); + MP_CHECKOK(testPointAddJac(ecgroup)); + MP_CHECKOK(testPointAddChud(ecgroup)); + MP_CHECKOK(testPointAddJmChud(ecgroup)); + MP_CHECKOK(testPointDoubleJac(ecgroup)); + MP_CHECKOK(testPointDoubleChud(ecgroup)); + MP_CHECKOK(testPointDoubleJm(ecgroup)); + MP_CHECKOK(testPreCompute(ecgroup)); + MP_CHECKOK(testPointMul(ecgroup)); + MP_CHECKOK(testPointMulRandom(ecgroup)); + MP_CHECKOK(testPointMulTime(ecgroup)); + CLEANUP: + return res; +} + +/* Tests a number of curves optimized using floating point arithmetic */ +int +main(void) +{ + mp_err res = MP_OKAY; + ECGroup *ecgroup = NULL; + + /* specific arithmetic tests */ + M_TestCurve("SECG-160R1", ECCurve_SECG_PRIME_160R1); + M_TestCurve("SECG-192R1", ECCurve_SECG_PRIME_192R1); + M_TestCurve("SEGC-224R1", ECCurve_SECG_PRIME_224R1); + + CLEANUP: + ECGroup_free(ecgroup); + if (res != MP_OKAY) { + printf("Error: exiting with error value %i\n", res); + } + return res; +}