/* Converts a point P(px, py) from affine coordinates to Jacobian * projective coordinates R(rx, ry, rz). Assumes input is already * field-encoded using field_enc, and returns output that is still * field-encoded. */ mp_err ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group) { mp_err res = MP_OKAY; if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) { MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); } else { MP_CHECKOK(mp_copy(px, rx)); MP_CHECKOK(mp_copy(py, ry)); MP_CHECKOK(mp_set_int(rz, 1)); if (group->meth->field_enc) { MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth)); } } CLEANUP: return res; }
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical. * Uses mixed Modified_Jacobian-affine coordinates. Assumes input is * already field-encoded using field_enc, and returns output that is still * field-encoded. */ mp_err ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz, const mp_int *paz4, const mp_int *qx, const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz, mp_int *raz4, mp_int scratch[], const ECGroup *group) { mp_err res = MP_OKAY; mp_int *A, *B, *C, *D, *C2, *C3; A = &scratch[0]; B = &scratch[1]; C = &scratch[2]; D = &scratch[3]; C2 = &scratch[4]; C3 = &scratch[5]; #if MAX_SCRATCH < 6 #error "Scratch array defined too small " #endif /* If either P or Q is the point at infinity, then return the other * point */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group)); MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth)); MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth)); MP_CHECKOK(group->meth-> field_mul(raz4, &group->curvea, raz4, group->meth)); goto CLEANUP; } if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) { MP_CHECKOK(mp_copy(px, rx)); MP_CHECKOK(mp_copy(py, ry)); MP_CHECKOK(mp_copy(pz, rz)); MP_CHECKOK(mp_copy(paz4, raz4)); goto CLEANUP; } /* A = qx * pz^2, B = qy * pz^3 */ MP_CHECKOK(group->meth->field_sqr(pz, A, group->meth)); MP_CHECKOK(group->meth->field_mul(A, pz, B, group->meth)); MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth)); MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth)); /* C = A - px, D = B - py */ MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth)); MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth)); /* C2 = C^2, C3 = C^3 */ MP_CHECKOK(group->meth->field_sqr(C, C2, group->meth)); MP_CHECKOK(group->meth->field_mul(C, C2, C3, group->meth)); /* rz = pz * C */ MP_CHECKOK(group->meth->field_mul(pz, C, rz, group->meth)); /* C = px * C^2 */ MP_CHECKOK(group->meth->field_mul(px, C2, C, group->meth)); /* A = D^2 */ MP_CHECKOK(group->meth->field_sqr(D, A, group->meth)); /* rx = D^2 - (C^3 + 2 * (px * C^2)) */ MP_CHECKOK(group->meth->field_add(C, C, rx, group->meth)); MP_CHECKOK(group->meth->field_add(C3, rx, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(A, rx, rx, group->meth)); /* C3 = py * C^3 */ MP_CHECKOK(group->meth->field_mul(py, C3, C3, group->meth)); /* ry = D * (px * C^2 - rx) - py * C^3 */ MP_CHECKOK(group->meth->field_sub(C, rx, ry, group->meth)); MP_CHECKOK(group->meth->field_mul(D, ry, ry, group->meth)); MP_CHECKOK(group->meth->field_sub(ry, C3, ry, group->meth)); /* raz4 = a * rz^4 */ MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth)); MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth)); MP_CHECKOK(group->meth-> field_mul(raz4, &group->curvea, raz4, group->meth)); CLEANUP: 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; }
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is * (qx, qy, 1). Elliptic curve points P, Q, and R can all 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 equation (2) from Brown, Hankerson, Lopez, and * Menezes. Software Implementation of the NIST Elliptic Curves Over Prime * Fields. */ mp_err ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py, const mp_int *pz, const mp_int *qx, const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group) { mp_err res = MP_OKAY; mp_int A, B, C, D, C2, C3; MP_DIGITS(&A) = 0; MP_DIGITS(&B) = 0; MP_DIGITS(&C) = 0; MP_DIGITS(&D) = 0; MP_DIGITS(&C2) = 0; MP_DIGITS(&C3) = 0; MP_CHECKOK(mp_init(&A)); MP_CHECKOK(mp_init(&B)); MP_CHECKOK(mp_init(&C)); MP_CHECKOK(mp_init(&D)); MP_CHECKOK(mp_init(&C2)); MP_CHECKOK(mp_init(&C3)); /* If either P or Q is the point at infinity, then return the other * point */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group)); goto CLEANUP; } if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) { MP_CHECKOK(mp_copy(px, rx)); MP_CHECKOK(mp_copy(py, ry)); MP_CHECKOK(mp_copy(pz, rz)); goto CLEANUP; } /* A = qx * pz^2, B = qy * pz^3 */ MP_CHECKOK(group->meth->field_sqr(pz, &A, group->meth)); MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth)); MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth)); MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth)); /* C = A - px, D = B - py */ MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth)); MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth)); if (mp_cmp_z(&C) == 0) { /* P == Q or P == -Q */ if (mp_cmp_z(&D) == 0) { /* P == Q */ /* It is cheaper to double (qx, qy, 1) than (px, py, pz). */ MP_DIGIT(&D, 0) = 1; /* Set D to 1. */ MP_CHECKOK(ec_GFp_pt_dbl_jac(qx, qy, &D, rx, ry, rz, group)); } else { /* P == -Q */ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); } goto CLEANUP; } /* C2 = C^2, C3 = C^3 */ MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth)); MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth)); /* rz = pz * C */ MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth)); /* C = px * C^2 */ MP_CHECKOK(group->meth->field_mul(px, &C2, &C, group->meth)); /* A = D^2 */ MP_CHECKOK(group->meth->field_sqr(&D, &A, group->meth)); /* rx = D^2 - (C^3 + 2 * (px * C^2)) */ MP_CHECKOK(group->meth->field_add(&C, &C, rx, group->meth)); MP_CHECKOK(group->meth->field_add(&C3, rx, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(&A, rx, rx, group->meth)); /* C3 = py * C^3 */ MP_CHECKOK(group->meth->field_mul(py, &C3, &C3, group->meth)); /* ry = D * (px * C^2 - rx) - py * C^3 */ MP_CHECKOK(group->meth->field_sub(&C, rx, ry, group->meth)); MP_CHECKOK(group->meth->field_mul(&D, ry, ry, group->meth)); MP_CHECKOK(group->meth->field_sub(ry, &C3, ry, group->meth)); CLEANUP: mp_clear(&A); mp_clear(&B); mp_clear(&C); mp_clear(&D); mp_clear(&C2); mp_clear(&C3); return res; }
/* Performs basic tests of elliptic curve cryptography over prime fields. * If tests fail, then it prints an error message, aborts, and returns an * error code. Otherwise, returns 0. */ int ectest_curve_GFp(ECGroup *group, int ectestPrint, int ectestTime, int generic) { mp_int one, order_1, gx, gy, rx, ry, n; int size; mp_err res; char s[1000]; /* initialize values */ MP_CHECKOK(mp_init(&one)); MP_CHECKOK(mp_init(&order_1)); MP_CHECKOK(mp_init(&gx)); MP_CHECKOK(mp_init(&gy)); MP_CHECKOK(mp_init(&rx)); MP_CHECKOK(mp_init(&ry)); MP_CHECKOK(mp_init(&n)); MP_CHECKOK(mp_set_int(&one, 1)); MP_CHECKOK(mp_sub(&group->order, &one, &order_1)); /* encode base point */ if (group->meth->field_dec) { MP_CHECKOK(group->meth->field_dec(&group->genx, &gx, group->meth)); MP_CHECKOK(group->meth->field_dec(&group->geny, &gy, group->meth)); } else { MP_CHECKOK(mp_copy(&group->genx, &gx)); MP_CHECKOK(mp_copy(&group->geny, &gy)); } if (ectestPrint) { /* output base point */ printf(" base point P:\n"); MP_CHECKOK(mp_toradix(&gx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&gy, s, 16)); printf(" %s\n", s); if (group->meth->field_enc) { printf(" base point P (encoded):\n"); MP_CHECKOK(mp_toradix(&group->genx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&group->geny, s, 16)); printf(" %s\n", s); } } #ifdef ECL_ENABLE_GFP_PT_MUL_AFF /* multiply base point by order - 1 and check for negative of base * point */ MP_CHECKOK(ec_GFp_pt_mul_aff(&order_1, &group->genx, &group->geny, &rx, &ry, group)); if (ectestPrint) { printf(" (order-1)*P (affine):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth)); if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) { printf(" Error: invalid result (expected (- base point)).\n"); res = MP_NO; goto CLEANUP; } #endif #ifdef ECL_ENABLE_GFP_PT_MUL_AFF /* multiply base point by order - 1 and check for negative of base * point */ MP_CHECKOK(ec_GFp_pt_mul_jac(&order_1, &group->genx, &group->geny, &rx, &ry, group)); if (ectestPrint) { printf(" (order-1)*P (jacobian):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth)); if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) { printf(" Error: invalid result (expected (- base point)).\n"); res = MP_NO; goto CLEANUP; } #endif /* multiply base point by order - 1 and check for negative of base * point */ MP_CHECKOK(ECPoint_mul(group, &order_1, NULL, NULL, &rx, &ry)); if (ectestPrint) { printf(" (order-1)*P (ECPoint_mul):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { printf(" Error: invalid result (expected (- base point)).\n"); res = MP_NO; goto CLEANUP; } /* multiply base point by order - 1 and check for negative of base * point */ MP_CHECKOK(ECPoint_mul(group, &order_1, &gx, &gy, &rx, &ry)); if (ectestPrint) { printf(" (order-1)*P (ECPoint_mul):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { printf(" Error: invalid result (expected (- base point)).\n"); res = MP_NO; goto CLEANUP; } #ifdef ECL_ENABLE_GFP_PT_MUL_AFF /* multiply base point by order and check for point at infinity */ MP_CHECKOK(ec_GFp_pt_mul_aff(&group->order, &group->genx, &group->geny, &rx, &ry, group)); if (ectestPrint) { printf(" (order)*P (affine):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { printf(" Error: invalid result (expected point at infinity).\n"); res = MP_NO; goto CLEANUP; } #endif #ifdef ECL_ENABLE_GFP_PT_MUL_JAC /* multiply base point by order and check for point at infinity */ MP_CHECKOK(ec_GFp_pt_mul_jac(&group->order, &group->genx, &group->geny, &rx, &ry, group)); if (ectestPrint) { printf(" (order)*P (jacobian):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { printf(" Error: invalid result (expected point at infinity).\n"); res = MP_NO; goto CLEANUP; } #endif /* multiply base point by order and check for point at infinity */ MP_CHECKOK(ECPoint_mul(group, &group->order, NULL, NULL, &rx, &ry)); if (ectestPrint) { printf(" (order)*P (ECPoint_mul):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { printf(" Error: invalid result (expected point at infinity).\n"); res = MP_NO; goto CLEANUP; } /* multiply base point by order and check for point at infinity */ MP_CHECKOK(ECPoint_mul(group, &group->order, &gx, &gy, &rx, &ry)); if (ectestPrint) { printf(" (order)*P (ECPoint_mul):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { printf(" Error: invalid result (expected point at infinity).\n"); res = MP_NO; goto CLEANUP; } /* check that (order-1)P + (order-1)P + P == (order-1)P */ MP_CHECKOK(ECPoints_mul(group, &order_1, &order_1, &gx, &gy, &rx, &ry)); MP_CHECKOK(ECPoints_mul(group, &one, &one, &rx, &ry, &rx, &ry)); if (ectestPrint) { printf(" (order-1)*P + (order-1)*P + P == (order-1)*P (ECPoints_mul):\n"); MP_CHECKOK(mp_toradix(&rx, s, 16)); printf(" %s\n", s); MP_CHECKOK(mp_toradix(&ry, s, 16)); printf(" %s\n", s); } MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { printf(" Error: invalid result (expected (- base point)).\n"); res = MP_NO; goto CLEANUP; } /* test validate_point function */ if (ECPoint_validate(group, &gx, &gy) != MP_YES) { printf(" Error: validate point on base point failed.\n"); res = MP_NO; goto CLEANUP; } MP_CHECKOK(mp_add_d(&gy, 1, &ry)); if (ECPoint_validate(group, &gx, &ry) != MP_NO) { printf(" Error: validate point on invalid point passed.\n"); res = MP_NO; goto CLEANUP; } if (ectestTime) { /* compute random scalar */ size = mpl_significant_bits(&group->meth->irr); if (size < MP_OKAY) { goto CLEANUP; } MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS)); MP_CHECKOK(group->meth->field_mod(&n, &n, group->meth)); /* timed test */ if (generic) { #ifdef ECL_ENABLE_GFP_PT_MUL_AFF M_TimeOperation(MP_CHECKOK(ec_GFp_pt_mul_aff(&n, &group->genx, &group->geny, &rx, &ry, group)), 100); #endif M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)), 100); M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100); } else { M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)), 100); M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, &gx, &gy, &rx, &ry)), 100); M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100); } } CLEANUP: mp_clear(&one); mp_clear(&order_1); mp_clear(&gx); mp_clear(&gy); mp_clear(&rx); mp_clear(&ry); mp_clear(&n); if (res != MP_OKAY) { printf(" Error: exiting with error value %i\n", res); } return res; }
/* Computes R = P + Q based on IEEE P1363 A.10.1. Elliptic curve points P, * Q, and R can all be identical. Uses affine coordinates. Assumes input * is already field-encoded using field_enc, and returns output that is * still field-encoded. */ mp_err ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy, mp_int *rx, mp_int *ry, const ECGroup *group) { mp_err res = MP_OKAY; mp_int lambda, temp, tempx, tempy; MP_DIGITS(&lambda) = 0; MP_DIGITS(&temp) = 0; MP_DIGITS(&tempx) = 0; MP_DIGITS(&tempy) = 0; MP_CHECKOK(mp_init(&lambda)); MP_CHECKOK(mp_init(&temp)); MP_CHECKOK(mp_init(&tempx)); MP_CHECKOK(mp_init(&tempy)); /* if P = inf, then R = Q */ if (ec_GFp_pt_is_inf_aff(px, py) == 0) { MP_CHECKOK(mp_copy(qx, rx)); MP_CHECKOK(mp_copy(qy, ry)); res = MP_OKAY; goto CLEANUP; } /* if Q = inf, then R = P */ if (ec_GFp_pt_is_inf_aff(qx, qy) == 0) { MP_CHECKOK(mp_copy(px, rx)); MP_CHECKOK(mp_copy(py, ry)); res = MP_OKAY; goto CLEANUP; } /* if px != qx, then lambda = (py-qy) / (px-qx) */ if (mp_cmp(px, qx) != 0) { MP_CHECKOK(group->meth->field_sub(py, qy, &tempy, group->meth)); MP_CHECKOK(group->meth->field_sub(px, qx, &tempx, group->meth)); MP_CHECKOK(group->meth->field_div(&tempy, &tempx, &lambda, group->meth)); } else { /* if py != qy or qy = 0, then R = inf */ if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) { mp_zero(rx); mp_zero(ry); res = MP_OKAY; goto CLEANUP; } /* lambda = (3qx^2+a) / (2qy) */ MP_CHECKOK(group->meth->field_sqr(qx, &tempx, group->meth)); MP_CHECKOK(mp_set_int(&temp, 3)); if (group->meth->field_enc) { MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth)); } MP_CHECKOK(group->meth->field_mul(&tempx, &temp, &tempx, group->meth)); MP_CHECKOK(group->meth->field_add(&tempx, &group->curvea, &tempx, group->meth)); MP_CHECKOK(mp_set_int(&temp, 2)); if (group->meth->field_enc) { MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth)); } MP_CHECKOK(group->meth->field_mul(qy, &temp, &tempy, group->meth)); MP_CHECKOK(group->meth->field_div(&tempx, &tempy, &lambda, group->meth)); } /* rx = lambda^2 - px - qx */ MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth)); MP_CHECKOK(group->meth->field_sub(&tempx, px, &tempx, group->meth)); MP_CHECKOK(group->meth->field_sub(&tempx, qx, &tempx, group->meth)); /* ry = (x1-x2) * lambda - y1 */ MP_CHECKOK(group->meth->field_sub(qx, &tempx, &tempy, group->meth)); MP_CHECKOK(group->meth->field_mul(&tempy, &lambda, &tempy, group->meth)); MP_CHECKOK(group->meth->field_sub(&tempy, qy, &tempy, group->meth)); MP_CHECKOK(mp_copy(&tempx, rx)); MP_CHECKOK(mp_copy(&tempy, ry)); CLEANUP: mp_clear(&lambda); mp_clear(&temp); mp_clear(&tempx); mp_clear(&tempy); return res; }
/* Validates a point on a GFp curve. */ mp_err ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group) { mp_err res = MP_NO; mp_int accl, accr, tmp, pxt, pyt; MP_DIGITS(&accl) = 0; MP_DIGITS(&accr) = 0; MP_DIGITS(&tmp) = 0; MP_DIGITS(&pxt) = 0; MP_DIGITS(&pyt) = 0; MP_CHECKOK(mp_init(&accl)); MP_CHECKOK(mp_init(&accr)); MP_CHECKOK(mp_init(&tmp)); MP_CHECKOK(mp_init(&pxt)); MP_CHECKOK(mp_init(&pyt)); /* 1: Verify that publicValue is not the point at infinity */ if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) { res = MP_NO; goto CLEANUP; } /* 2: Verify that the coordinates of publicValue are elements * of the field. */ if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) || (MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) { res = MP_NO; goto CLEANUP; } /* 3: Verify that publicValue is on the curve. */ if (group->meth->field_enc) { group->meth->field_enc(px, &pxt, group->meth); group->meth->field_enc(py, &pyt, group->meth); } else { MP_CHECKOK(mp_copy(px, &pxt)); MP_CHECKOK(mp_copy(py, &pyt)); } /* left-hand side: y^2 */ MP_CHECKOK(group->meth->field_sqr(&pyt, &accl, group->meth)); /* right-hand side: x^3 + a*x + b = (x^2 + a)*x + b by Horner's rule */ MP_CHECKOK(group->meth->field_sqr(&pxt, &tmp, group->meth)); MP_CHECKOK(group->meth->field_add(&tmp, &group->curvea, &tmp, group->meth)); MP_CHECKOK(group->meth->field_mul(&tmp, &pxt, &accr, group->meth)); MP_CHECKOK(group->meth->field_add(&accr, &group->curveb, &accr, group->meth)); /* check LHS - RHS == 0 */ MP_CHECKOK(group->meth->field_sub(&accl, &accr, &accr, group->meth)); if (mp_cmp_z(&accr) != 0) { res = MP_NO; goto CLEANUP; } /* 4: Verify that the order of the curve times the publicValue * is the point at infinity. */ MP_CHECKOK(ECPoint_mul(group, &group->order, px, py, &pxt, &pyt)); if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) { res = MP_NO; goto CLEANUP; } res = MP_YES; CLEANUP: mp_clear(&accl); mp_clear(&accr); mp_clear(&tmp); mp_clear(&pxt); mp_clear(&pyt); return res; }
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical. * Uses mixed Modified_Jacobian-affine coordinates. Assumes input is * already field-encoded using field_enc, and returns output that is still * field-encoded. */ mp_err ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz, const mp_int *paz4, const mp_int *qx, const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz, mp_int *raz4, const ECGroup *group) { mp_err res = MP_OKAY; mp_int A, B, C, D, C2, C3; MP_DIGITS(&A) = 0; MP_DIGITS(&B) = 0; MP_DIGITS(&C) = 0; MP_DIGITS(&D) = 0; MP_DIGITS(&C2) = 0; MP_DIGITS(&C3) = 0; MP_CHECKOK(mp_init(&A)); MP_CHECKOK(mp_init(&B)); MP_CHECKOK(mp_init(&C)); MP_CHECKOK(mp_init(&D)); MP_CHECKOK(mp_init(&C2)); MP_CHECKOK(mp_init(&C3)); /* If either P or Q is the point at infinity, then return the other * point */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group)); MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth)); MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth)); MP_CHECKOK(group->meth-> field_mul(raz4, &group->curvea, raz4, group->meth)); goto CLEANUP; } if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) { MP_CHECKOK(mp_copy(px, rx)); MP_CHECKOK(mp_copy(py, ry)); MP_CHECKOK(mp_copy(pz, rz)); MP_CHECKOK(mp_copy(paz4, raz4)); goto CLEANUP; } /* A = qx * pz^2, B = qy * pz^3 */ MP_CHECKOK(group->meth->field_sqr(pz, &A, group->meth)); MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth)); MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth)); MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth)); /* C = A - px, D = B - py */ MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth)); MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth)); /* C2 = C^2, C3 = C^3 */ MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth)); MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth)); /* rz = pz * C */ MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth)); /* C = px * C^2 */ MP_CHECKOK(group->meth->field_mul(px, &C2, &C, group->meth)); /* A = D^2 */ MP_CHECKOK(group->meth->field_sqr(&D, &A, group->meth)); /* rx = D^2 - (C^3 + 2 * (px * C^2)) */ MP_CHECKOK(group->meth->field_add(&C, &C, rx, group->meth)); MP_CHECKOK(group->meth->field_add(&C3, rx, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(&A, rx, rx, group->meth)); /* C3 = py * C^3 */ MP_CHECKOK(group->meth->field_mul(py, &C3, &C3, group->meth)); /* ry = D * (px * C^2 - rx) - py * C^3 */ MP_CHECKOK(group->meth->field_sub(&C, rx, ry, group->meth)); MP_CHECKOK(group->meth->field_mul(&D, ry, ry, group->meth)); MP_CHECKOK(group->meth->field_sub(ry, &C3, ry, group->meth)); /* raz4 = a * rz^4 */ MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth)); MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth)); MP_CHECKOK(group->meth-> field_mul(raz4, &group->curvea, raz4, group->meth)); CLEANUP: mp_clear(&A); mp_clear(&B); mp_clear(&C); mp_clear(&D); mp_clear(&C2); mp_clear(&C3); return res; }