RetroZilla/security/nss/lib/freebl/ecl/tests/ecp_fpt.c
2015-10-20 23:03:22 -04:00

1124 lines
29 KiB
C

/*
* ***** 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 <fungstep@hotmail.com> and
* Douglas Stebila <douglas@stebila.ca>, 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 <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
/* 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;
}