- {
- if (!BN_copy(&dest->X, &src->X)) return 0;
- if (!BN_copy(&dest->Y, &src->Y)) return 0;
- if (!BN_copy(&dest->Z, &src->Z)) return 0;
- dest->Z_is_one = src->Z_is_one;
-
- return 1;
- }
-
-
-/* TODO: 'set' and 'get' functions for EC_POINTs */
-
-
-size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
- unsigned char *buf, size_t len, BN_CTX *ctx);
-/* TODO */
-
-
-int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
- const unsigned char *buf, size_t len, BN_CTX *);
-/* TODO */
-
-
-int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
- {
- int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
- int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
- const BIGNUM *p;
- BN_CTX *new_ctx = NULL;
- BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
- int ret = 0;
-
- if (a == b)
- return EC_POINT_dbl(group, r, a, ctx);
- if (EC_POINT_is_at_infinity(group, a))
- return EC_POINT_copy(r, b);
- if (EC_POINT_is_at_infinity(group, b))
- return EC_POINT_copy(r, a);
-
- field_mul = group->meth->field_mul;
- field_sqr = group->meth->field_sqr;
- p = &group->field;
-
- if (ctx == NULL)
- {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL)
- return 0;
- }
- BN_CTX_start(ctx);
-
- n0 = BN_CTX_get(ctx);
- n1 = BN_CTX_get(ctx);
- n2 = BN_CTX_get(ctx);
- n3 = BN_CTX_get(ctx);
- n4 = BN_CTX_get(ctx);
- n5 = BN_CTX_get(ctx);
- n6 = BN_CTX_get(ctx);
- if (n6 == NULL) goto end;
-
- /* n1, n2 */
- if (b->Z_is_one)
- {
- if (!BN_copy(n1, &a->X)) goto end;
- if (!BN_copy(n2, &a->Y)) goto end;
- /* n1 = X_a */
- /* n2 = Y_a */
- }
- else
- {
- if (!field_sqr(group, n0, &b->Z, ctx)) goto end;
- if (!field_mul(group, n1, &a->X, n0, ctx)) goto end;
- /* n1 = X_a * Z_b^2 */
-
- if (!field_mul(group, n0, n0, &b->Z, ctx)) goto end;
- if (!field_mul(group, n2, &a->Y, n0, ctx)) goto end;
- /* n2 = Y_a * Z_b^3 */
- }
-
- /* n3, n4 */
- if (a->Z_is_one)
- {
- if (!BN_copy(n3, &b->X)) goto end;
- if (!BN_copy(n4, &b->Y)) goto end;
- /* n3 = X_b */
- /* n4 = Y_b */
- }
- else
- {
- if (!field_sqr(group, n0, &a->Z, ctx)) goto end;
- if (!field_mul(group, n3, &b->X, n0, ctx)) goto end;
- /* n3 = X_b * Z_a^2 */
-
- if (!field_mul(group, n0, n0, &a->Z, ctx)) goto end;
- if (!field_mul(group, n4, &b->Y, n0, ctx)) goto end;
- /* n4 = Y_b * Z_a^3 */
- }
-
- /* n5, n6 */
- if (!BN_mod_sub_quick(n5, n1, n3, p)) goto end;
- if (!BN_mod_sub_quick(n6, n2, n4, p)) goto end;
- /* n5 = n1 - n3 */
- /* n6 = n2 - n4 */
-
- if (BN_is_zero(n5))
- {
- if (BN_is_zero(n6))
- {
- /* a is the same point as b */
- BN_CTX_end(ctx);
- ctx = NULL;
- ret = EC_POINT_dbl(group, r, a, ctx);
- goto end;
- }
- else
- {
- /* a is the inverse of b */
- if (!BN_zero(&r->Z)) goto end;
- r->Z_is_one = 0;
- ret = 1;
- goto end;
- }
- }
-
- /* 'n7', 'n8' */
- if (!BN_mod_add_quick(n1, n1, n3, p)) goto end;
- if (!BN_mod_add_quick(n2, n2, n4, p)) goto end;
- /* 'n7' = n1 + n3 */
- /* 'n8' = n2 + n4 */
-
- /* Z_r */
- if (a->Z_is_one && b->Z_is_one)
- {
- if (!BN_copy(&r->Z, n5)) goto end;
- }
- else
- {
- if (a->Z_is_one)
- { if (!BN_copy(n0, &b->Z)) goto end; }
- else if (b->Z_is_one)
- { if (!BN_copy(n0, &a->Z)) goto end; }
- else
- { if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) goto end; }
- if (!field_mul(group, &r->Z, n0, n5, ctx)) goto end;
- }
- r->Z_is_one = 0;
- /* Z_r = Z_a * Z_b * n5 */
-
- /* X_r */
- if (!field_sqr(group, n0, n6, ctx)) goto end;
- if (!field_sqr(group, n4, n5, ctx)) goto end;
- if (!field_mul(group, n3, n1, n4, ctx)) goto end;
- if (!BN_mod_sub_quick(&r->X, n0, n3, p)) goto end;
- /* X_r = n6^2 - n5^2 * 'n7' */
-
- /* 'n9' */
- if (!BN_mod_lshift1_quick(n0, &r->X, p)) goto end;
- if (!BN_mod_sub_quick(n0, n3, n0, p)) goto end;
- /* n9 = n5^2 * 'n7' - 2 * X_r */
-
- /* Y_r */
- if (!field_mul(group, n0, n0, n6, ctx)) goto end;
- if (!field_mul(group, n5, n4, n5, ctx)) goto end; /* now n5 is n5^3 */
- if (!field_mul(group, n1, n2, n5, ctx)) goto end;
- if (!BN_mod_sub_quick(n0, n0, n1, p)) goto end;
- if (BN_is_odd(n0))
- if (!BN_add(n0, n0, p)) goto end;
- /* now 0 <= n0 < 2*p, and n0 is even */
- if (!BN_rshift1(&r->Y, n0)) goto end;
- /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
-
- ret = 1;
+{
+ if (!BN_copy(dest->X, src->X))
+ return 0;
+ if (!BN_copy(dest->Y, src->Y))
+ return 0;
+ if (!BN_copy(dest->Z, src->Z))
+ return 0;
+ dest->Z_is_one = src->Z_is_one;
+ dest->curve_name = src->curve_name;
+
+ return 1;
+}
+
+int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
+ EC_POINT *point)
+{
+ point->Z_is_one = 0;
+ BN_zero(point->Z);
+ return 1;
+}
+
+int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
+ EC_POINT *point,
+ const BIGNUM *x,
+ const BIGNUM *y,
+ const BIGNUM *z,
+ BN_CTX *ctx)
+{
+ BN_CTX *new_ctx = NULL;
+ int ret = 0;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ if (x != NULL) {
+ if (!BN_nnmod(point->X, x, group->field, ctx))
+ goto err;
+ if (group->meth->field_encode) {
+ if (!group->meth->field_encode(group, point->X, point->X, ctx))
+ goto err;
+ }
+ }
+
+ if (y != NULL) {
+ if (!BN_nnmod(point->Y, y, group->field, ctx))
+ goto err;
+ if (group->meth->field_encode) {
+ if (!group->meth->field_encode(group, point->Y, point->Y, ctx))
+ goto err;
+ }
+ }
+
+ if (z != NULL) {
+ int Z_is_one;
+
+ if (!BN_nnmod(point->Z, z, group->field, ctx))
+ goto err;
+ Z_is_one = BN_is_one(point->Z);
+ if (group->meth->field_encode) {
+ if (Z_is_one && (group->meth->field_set_to_one != 0)) {
+ if (!group->meth->field_set_to_one(group, point->Z, ctx))
+ goto err;
+ } else {
+ if (!group->
+ meth->field_encode(group, point->Z, point->Z, ctx))
+ goto err;
+ }
+ }
+ point->Z_is_one = Z_is_one;
+ }
+
+ ret = 1;
+
+ err:
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
+ const EC_POINT *point,
+ BIGNUM *x, BIGNUM *y,
+ BIGNUM *z, BN_CTX *ctx)
+{
+ BN_CTX *new_ctx = NULL;
+ int ret = 0;
+
+ if (group->meth->field_decode != 0) {
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ if (x != NULL) {
+ if (!group->meth->field_decode(group, x, point->X, ctx))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!group->meth->field_decode(group, y, point->Y, ctx))
+ goto err;
+ }
+ if (z != NULL) {
+ if (!group->meth->field_decode(group, z, point->Z, ctx))
+ goto err;
+ }
+ } else {
+ if (x != NULL) {
+ if (!BN_copy(x, point->X))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!BN_copy(y, point->Y))
+ goto err;
+ }
+ if (z != NULL) {
+ if (!BN_copy(z, point->Z))
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+ err:
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
+ EC_POINT *point,
+ const BIGNUM *x,
+ const BIGNUM *y, BN_CTX *ctx)
+{
+ if (x == NULL || y == NULL) {
+ /*
+ * unlike for projective coordinates, we do not tolerate this
+ */
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES,
+ ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y,
+ BN_value_one(), ctx);
+}
+
+int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point,
+ BIGNUM *x, BIGNUM *y,
+ BN_CTX *ctx)
+{
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *Z, *Z_1, *Z_2, *Z_3;
+ const BIGNUM *Z_;
+ int ret = 0;
+
+ if (EC_POINT_is_at_infinity(group, point)) {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
+ EC_R_POINT_AT_INFINITY);
+ return 0;
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ Z = BN_CTX_get(ctx);
+ Z_1 = BN_CTX_get(ctx);
+ Z_2 = BN_CTX_get(ctx);
+ Z_3 = BN_CTX_get(ctx);
+ if (Z_3 == NULL)
+ goto err;
+
+ /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */
+
+ if (group->meth->field_decode) {
+ if (!group->meth->field_decode(group, Z, point->Z, ctx))
+ goto err;
+ Z_ = Z;
+ } else {
+ Z_ = point->Z;
+ }
+
+ if (BN_is_one(Z_)) {
+ if (group->meth->field_decode) {
+ if (x != NULL) {
+ if (!group->meth->field_decode(group, x, point->X, ctx))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!group->meth->field_decode(group, y, point->Y, ctx))
+ goto err;
+ }
+ } else {
+ if (x != NULL) {
+ if (!BN_copy(x, point->X))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!BN_copy(y, point->Y))
+ goto err;
+ }
+ }
+ } else {
+ if (!group->meth->field_inv(group, Z_1, Z_, ctx)) {
+ ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
+ ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (group->meth->field_encode == 0) {
+ /* field_sqr works on standard representation */
+ if (!group->meth->field_sqr(group, Z_2, Z_1, ctx))
+ goto err;
+ } else {
+ if (!BN_mod_sqr(Z_2, Z_1, group->field, ctx))
+ goto err;
+ }
+
+ if (x != NULL) {
+ /*
+ * in the Montgomery case, field_mul will cancel out Montgomery
+ * factor in X:
+ */
+ if (!group->meth->field_mul(group, x, point->X, Z_2, ctx))
+ goto err;
+ }
+
+ if (y != NULL) {
+ if (group->meth->field_encode == 0) {
+ /*
+ * field_mul works on standard representation
+ */
+ if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx))
+ goto err;
+ } else {
+ if (!BN_mod_mul(Z_3, Z_2, Z_1, group->field, ctx))
+ goto err;
+ }
+
+ /*
+ * in the Montgomery case, field_mul will cancel out Montgomery
+ * factor in Y:
+ */
+ if (!group->meth->field_mul(group, y, point->Y, Z_3, ctx))
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+ err:
+ BN_CTX_end(ctx);
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *ctx)
+{
+ int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
+ const BIGNUM *, BN_CTX *);
+ int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
+ const BIGNUM *p;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
+ int ret = 0;
+
+ if (a == b)
+ return EC_POINT_dbl(group, r, a, ctx);
+ if (EC_POINT_is_at_infinity(group, a))
+ return EC_POINT_copy(r, b);
+ if (EC_POINT_is_at_infinity(group, b))
+ return EC_POINT_copy(r, a);
+
+ field_mul = group->meth->field_mul;
+ field_sqr = group->meth->field_sqr;
+ p = group->field;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ n4 = BN_CTX_get(ctx);
+ n5 = BN_CTX_get(ctx);
+ n6 = BN_CTX_get(ctx);
+ if (n6 == NULL)
+ goto end;
+
+ /*
+ * Note that in this function we must not read components of 'a' or 'b'
+ * once we have written the corresponding components of 'r'. ('r' might
+ * be one of 'a' or 'b'.)
+ */
+
+ /* n1, n2 */
+ if (b->Z_is_one) {
+ if (!BN_copy(n1, a->X))
+ goto end;
+ if (!BN_copy(n2, a->Y))
+ goto end;
+ /* n1 = X_a */
+ /* n2 = Y_a */
+ } else {
+ if (!field_sqr(group, n0, b->Z, ctx))
+ goto end;
+ if (!field_mul(group, n1, a->X, n0, ctx))
+ goto end;
+ /* n1 = X_a * Z_b^2 */
+
+ if (!field_mul(group, n0, n0, b->Z, ctx))
+ goto end;
+ if (!field_mul(group, n2, a->Y, n0, ctx))
+ goto end;
+ /* n2 = Y_a * Z_b^3 */
+ }
+
+ /* n3, n4 */
+ if (a->Z_is_one) {
+ if (!BN_copy(n3, b->X))
+ goto end;
+ if (!BN_copy(n4, b->Y))
+ goto end;
+ /* n3 = X_b */
+ /* n4 = Y_b */
+ } else {
+ if (!field_sqr(group, n0, a->Z, ctx))
+ goto end;
+ if (!field_mul(group, n3, b->X, n0, ctx))
+ goto end;
+ /* n3 = X_b * Z_a^2 */
+
+ if (!field_mul(group, n0, n0, a->Z, ctx))
+ goto end;
+ if (!field_mul(group, n4, b->Y, n0, ctx))
+ goto end;
+ /* n4 = Y_b * Z_a^3 */
+ }
+
+ /* n5, n6 */
+ if (!BN_mod_sub_quick(n5, n1, n3, p))
+ goto end;
+ if (!BN_mod_sub_quick(n6, n2, n4, p))
+ goto end;
+ /* n5 = n1 - n3 */
+ /* n6 = n2 - n4 */
+
+ if (BN_is_zero(n5)) {
+ if (BN_is_zero(n6)) {
+ /* a is the same point as b */
+ BN_CTX_end(ctx);
+ ret = EC_POINT_dbl(group, r, a, ctx);
+ ctx = NULL;
+ goto end;
+ } else {
+ /* a is the inverse of b */
+ BN_zero(r->Z);
+ r->Z_is_one = 0;
+ ret = 1;
+ goto end;
+ }
+ }
+
+ /* 'n7', 'n8' */
+ if (!BN_mod_add_quick(n1, n1, n3, p))
+ goto end;
+ if (!BN_mod_add_quick(n2, n2, n4, p))
+ goto end;
+ /* 'n7' = n1 + n3 */
+ /* 'n8' = n2 + n4 */
+
+ /* Z_r */
+ if (a->Z_is_one && b->Z_is_one) {
+ if (!BN_copy(r->Z, n5))
+ goto end;
+ } else {
+ if (a->Z_is_one) {
+ if (!BN_copy(n0, b->Z))
+ goto end;
+ } else if (b->Z_is_one) {
+ if (!BN_copy(n0, a->Z))
+ goto end;
+ } else {
+ if (!field_mul(group, n0, a->Z, b->Z, ctx))
+ goto end;
+ }
+ if (!field_mul(group, r->Z, n0, n5, ctx))
+ goto end;
+ }
+ r->Z_is_one = 0;
+ /* Z_r = Z_a * Z_b * n5 */
+
+ /* X_r */
+ if (!field_sqr(group, n0, n6, ctx))
+ goto end;
+ if (!field_sqr(group, n4, n5, ctx))
+ goto end;
+ if (!field_mul(group, n3, n1, n4, ctx))
+ goto end;
+ if (!BN_mod_sub_quick(r->X, n0, n3, p))
+ goto end;
+ /* X_r = n6^2 - n5^2 * 'n7' */
+
+ /* 'n9' */
+ if (!BN_mod_lshift1_quick(n0, r->X, p))
+ goto end;
+ if (!BN_mod_sub_quick(n0, n3, n0, p))
+ goto end;
+ /* n9 = n5^2 * 'n7' - 2 * X_r */
+
+ /* Y_r */
+ if (!field_mul(group, n0, n0, n6, ctx))
+ goto end;
+ if (!field_mul(group, n5, n4, n5, ctx))
+ goto end; /* now n5 is n5^3 */
+ if (!field_mul(group, n1, n2, n5, ctx))
+ goto end;
+ if (!BN_mod_sub_quick(n0, n0, n1, p))
+ goto end;
+ if (BN_is_odd(n0))
+ if (!BN_add(n0, n0, p))
+ goto end;
+ /* now 0 <= n0 < 2*p, and n0 is even */
+ if (!BN_rshift1(r->Y, n0))
+ goto end;
+ /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
+
+ ret = 1;