/* Converts a point P(px, py, pz) from Jacobian projective coordinates to * affine coordinates R(rx, ry). P and R can share x and y coordinates. * Assumes input is already field-encoded using field_enc, and returns * output that is still field-encoded. */ mp_err ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz, mp_int *rx, mp_int *ry, const ECGroup *group) { mp_err res = MP_OKAY; mp_int z1, z2, z3; MP_DIGITS(&z1) = 0; MP_DIGITS(&z2) = 0; MP_DIGITS(&z3) = 0; MP_CHECKOK(mp_init(&z1)); MP_CHECKOK(mp_init(&z2)); MP_CHECKOK(mp_init(&z3)); /* if point at infinity, then set point at infinity and exit */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { MP_CHECKOK(ec_GFp_pt_set_inf_aff(rx, ry)); goto CLEANUP; } /* transform (px, py, pz) into (px / pz^2, py / pz^3) */ if (mp_cmp_d(pz, 1) == 0) { MP_CHECKOK(mp_copy(px, rx)); MP_CHECKOK(mp_copy(py, ry)); } else { MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth)); MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth)); MP_CHECKOK(group->meth->field_mul(&z1, &z2, &z3, group->meth)); MP_CHECKOK(group->meth->field_mul(px, &z2, rx, group->meth)); MP_CHECKOK(group->meth->field_mul(py, &z3, ry, group->meth)); } CLEANUP: mp_clear(&z1); mp_clear(&z2); mp_clear(&z3); return res; }
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses * Modified Jacobian coordinates. * * Assumes input is already field-encoded using field_enc, and returns * output that is still field-encoded. * */ mp_err ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz, const mp_int *paz4, 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 *t0, *t1, *M, *S; t0 = &scratch[0]; t1 = &scratch[1]; M = &scratch[2]; S = &scratch[3]; #if MAX_SCRATCH < 4 #error "Scratch array defined too small " #endif /* Check for point at infinity */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { /* Set r = pt at infinity by setting rz = 0 */ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); goto CLEANUP; } /* M = 3 (px^2) + a*(pz^4) */ MP_CHECKOK(group->meth->field_sqr(px, t0, group->meth)); MP_CHECKOK(group->meth->field_add(t0, t0, M, group->meth)); MP_CHECKOK(group->meth->field_add(t0, M, t0, group->meth)); MP_CHECKOK(group->meth->field_add(t0, paz4, M, group->meth)); /* rz = 2 * py * pz */ MP_CHECKOK(group->meth->field_mul(py, pz, S, group->meth)); MP_CHECKOK(group->meth->field_add(S, S, rz, group->meth)); /* t0 = 2y^2 , t1 = 8y^4 */ MP_CHECKOK(group->meth->field_sqr(py, t0, group->meth)); MP_CHECKOK(group->meth->field_add(t0, t0, t0, group->meth)); MP_CHECKOK(group->meth->field_sqr(t0, t1, group->meth)); MP_CHECKOK(group->meth->field_add(t1, t1, t1, group->meth)); /* S = 4 * px * py^2 = 2 * px * t0 */ MP_CHECKOK(group->meth->field_mul(px, t0, S, group->meth)); MP_CHECKOK(group->meth->field_add(S, S, S, group->meth)); /* rx = M^2 - 2S */ MP_CHECKOK(group->meth->field_sqr(M, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth)); /* ry = M * (S - rx) - t1 */ MP_CHECKOK(group->meth->field_sub(S, rx, S, group->meth)); MP_CHECKOK(group->meth->field_mul(S, M, ry, group->meth)); MP_CHECKOK(group->meth->field_sub(ry, t1, ry, group->meth)); /* ra*z^4 = 2*t1*(apz4) */ MP_CHECKOK(group->meth->field_mul(paz4, t1, raz4, group->meth)); MP_CHECKOK(group->meth->field_add(raz4, raz4, raz4, 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; }
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses * Jacobian coordinates. * * Assumes input is already field-encoded using field_enc, and returns * output that is still field-encoded. * * This routine implements Point Doubling in the Jacobian Projective * space as described in the paper "Efficient elliptic curve exponentiation * using mixed coordinates", by H. Cohen, A Miyaji, T. Ono. */ mp_err ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py, const mp_int *pz, mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group) { mp_err res = MP_OKAY; mp_int t0, t1, M, S; MP_DIGITS(&t0) = 0; MP_DIGITS(&t1) = 0; MP_DIGITS(&M) = 0; MP_DIGITS(&S) = 0; MP_CHECKOK(mp_init(&t0)); MP_CHECKOK(mp_init(&t1)); MP_CHECKOK(mp_init(&M)); MP_CHECKOK(mp_init(&S)); /* P == inf or P == -P */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES || mp_cmp_z(py) == 0) { MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); goto CLEANUP; } if (mp_cmp_d(pz, 1) == 0) { /* M = 3 * px^2 + a */ MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth)); MP_CHECKOK(group->meth-> field_add(&t0, &group->curvea, &M, group->meth)); } else if (MP_SIGN(&group->curvea) == MP_NEG && MP_USED(&group->curvea) == 1 && MP_DIGIT(&group->curvea, 0) == 3) { /* M = 3 * (px + pz^2) * (px - pz^2) */ MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth)); MP_CHECKOK(group->meth->field_add(px, &M, &t0, group->meth)); MP_CHECKOK(group->meth->field_sub(px, &M, &t1, group->meth)); MP_CHECKOK(group->meth->field_mul(&t0, &t1, &M, group->meth)); MP_CHECKOK(group->meth->field_add(&M, &M, &t0, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &M, &M, group->meth)); } else { /* M = 3 * (px^2) + a * (pz^4) */ MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth)); MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth)); MP_CHECKOK(group->meth->field_sqr(&M, &M, group->meth)); MP_CHECKOK(group->meth-> field_mul(&M, &group->curvea, &M, group->meth)); MP_CHECKOK(group->meth->field_add(&M, &t0, &M, group->meth)); } /* rz = 2 * py * pz */ /* t0 = 4 * py^2 */ if (mp_cmp_d(pz, 1) == 0) { MP_CHECKOK(group->meth->field_add(py, py, rz, group->meth)); MP_CHECKOK(group->meth->field_sqr(rz, &t0, group->meth)); } else { MP_CHECKOK(group->meth->field_add(py, py, &t0, group->meth)); MP_CHECKOK(group->meth->field_mul(&t0, pz, rz, group->meth)); MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth)); } /* S = 4 * px * py^2 = px * (2 * py)^2 */ MP_CHECKOK(group->meth->field_mul(px, &t0, &S, group->meth)); /* rx = M^2 - 2 * S */ MP_CHECKOK(group->meth->field_add(&S, &S, &t1, group->meth)); MP_CHECKOK(group->meth->field_sqr(&M, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(rx, &t1, rx, group->meth)); /* ry = M * (S - rx) - 8 * py^4 */ MP_CHECKOK(group->meth->field_sqr(&t0, &t1, group->meth)); if (mp_isodd(&t1)) { MP_CHECKOK(mp_add(&t1, &group->meth->irr, &t1)); } MP_CHECKOK(mp_div_2(&t1, &t1)); MP_CHECKOK(group->meth->field_sub(&S, rx, &S, group->meth)); MP_CHECKOK(group->meth->field_mul(&M, &S, &M, group->meth)); MP_CHECKOK(group->meth->field_sub(&M, &t1, ry, group->meth)); CLEANUP: mp_clear(&t0); mp_clear(&t1); mp_clear(&M); mp_clear(&S); 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; }
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses * Modified Jacobian coordinates. * * Assumes input is already field-encoded using field_enc, and returns * output that is still field-encoded. * */ mp_err ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz, const mp_int *paz4, mp_int *rx, mp_int *ry, mp_int *rz, mp_int *raz4, const ECGroup *group) { mp_err res = MP_OKAY; mp_int t0, t1, M, S; MP_DIGITS(&t0) = 0; MP_DIGITS(&t1) = 0; MP_DIGITS(&M) = 0; MP_DIGITS(&S) = 0; MP_CHECKOK(mp_init(&t0)); MP_CHECKOK(mp_init(&t1)); MP_CHECKOK(mp_init(&M)); MP_CHECKOK(mp_init(&S)); /* Check for point at infinity */ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) { /* Set r = pt at infinity by setting rz = 0 */ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz)); goto CLEANUP; } /* M = 3 (px^2) + a*(pz^4) */ MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, paz4, &M, group->meth)); /* rz = 2 * py * pz */ MP_CHECKOK(group->meth->field_mul(py, pz, rz, group->meth)); MP_CHECKOK(group->meth->field_add(rz, rz, rz, group->meth)); /* t0 = 2y^2 , t1 = 8y^4 */ MP_CHECKOK(group->meth->field_sqr(py, &t0, group->meth)); MP_CHECKOK(group->meth->field_add(&t0, &t0, &t0, group->meth)); MP_CHECKOK(group->meth->field_sqr(&t0, &t1, group->meth)); MP_CHECKOK(group->meth->field_add(&t1, &t1, &t1, group->meth)); /* S = 4 * px * py^2 = 2 * px * t0 */ MP_CHECKOK(group->meth->field_mul(px, &t0, &S, group->meth)); MP_CHECKOK(group->meth->field_add(&S, &S, &S, group->meth)); /* rx = M^2 - 2S */ MP_CHECKOK(group->meth->field_sqr(&M, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(rx, &S, rx, group->meth)); MP_CHECKOK(group->meth->field_sub(rx, &S, rx, group->meth)); /* ry = M * (S - rx) - t1 */ MP_CHECKOK(group->meth->field_sub(&S, rx, ry, group->meth)); MP_CHECKOK(group->meth->field_mul(ry, &M, ry, group->meth)); MP_CHECKOK(group->meth->field_sub(ry, &t1, ry, group->meth)); /* ra*z^4 = 2*t1*(apz4) */ MP_CHECKOK(group->meth->field_mul(paz4, &t1, raz4, group->meth)); MP_CHECKOK(group->meth->field_add(raz4, raz4, raz4, group->meth)); CLEANUP: mp_clear(&t0); mp_clear(&t1); mp_clear(&M); mp_clear(&S); 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; }