/* * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the elliptic curve math library for prime field curves using floating point operations. * * The Initial Developer of the Original Code is * Sun Microsystems, Inc. * Portions created by the Initial Developer are Copyright (C) 2003 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Stephen Fung and * Douglas Stebila , Sun Microsystems Laboratories. * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #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; }