Change array representation of binary polynomials to make GF2m part of
[openssl.git] / crypto / ec / ec2_smpl.c
index 34c3a953a5a55e20e87f980e88e9fcfe55ccb880..01d8483c3af1036a3222183854ab7cd9b2332724 100644 (file)
@@ -14,7 +14,7 @@
  *
  */
 /* ====================================================================
- * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -157,6 +157,7 @@ void ec_GF2m_simple_group_clear_finish(EC_GROUP *group)
        group->poly[2] = 0;
        group->poly[3] = 0;
        group->poly[4] = 0;
+       group->poly[5] = -1;
        }
 
 
@@ -174,6 +175,7 @@ int ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
        dest->poly[2] = src->poly[2];
        dest->poly[3] = src->poly[3];
        dest->poly[4] = src->poly[4];
+       dest->poly[5] = src->poly[5];
        bn_wexpand(&dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2);
        bn_wexpand(&dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2);
        for (i = dest->a.top; i < dest->a.dmax; i++) dest->a.d[i] = 0;
@@ -190,7 +192,7 @@ int ec_GF2m_simple_group_set_curve(EC_GROUP *group,
 
        /* group->field */
        if (!BN_copy(&group->field, p)) goto err;
-       i = BN_GF2m_poly2arr(&group->field, group->poly, 5);
+       i = BN_GF2m_poly2arr(&group->field, group->poly, 6) - 1;
        if ((i != 5) && (i != 3))
                {
                ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE, EC_R_UNSUPPORTED_FIELD);
@@ -281,7 +283,8 @@ int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
        ret = 1;
 
 err:
-       BN_CTX_end(ctx);
+       if (ctx != NULL)
+               BN_CTX_end(ctx);
        if (new_ctx != NULL)
                BN_CTX_free(new_ctx);
        return ret;
@@ -354,11 +357,11 @@ int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *group, EC_POINT
                }
 
        if (!BN_copy(&point->X, x)) goto err;
-       BN_set_sign(&point->X, 0);
+       BN_set_negative(&point->X, 0);
        if (!BN_copy(&point->Y, y)) goto err;
-       BN_set_sign(&point->Y, 0);
+       BN_set_negative(&point->Y, 0);
        if (!BN_copy(&point->Z, BN_value_one())) goto err;
-       BN_set_sign(&point->Z, 0);
+       BN_set_negative(&point->Z, 0);
        point->Z_is_one = 1;
        ret = 1;
 
@@ -389,12 +392,12 @@ int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_
        if (x != NULL)
                {
                if (!BN_copy(x, &point->X)) goto err;
-               BN_set_sign(x, 0);
+               BN_set_negative(x, 0);
                }
        if (y != NULL)
                {
                if (!BN_copy(y, &point->Y)) goto err;
-               BN_set_sign(y, 0);
+               BN_set_negative(y, 0);
                }
        ret = 1;
                
@@ -403,18 +406,94 @@ int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_
        }
 
 
-/* Include patented algorithms. */
-#include "ec2_smpt.c"
+/* Calculates and sets the affine coordinates of an EC_POINT from the given
+ * compressed coordinates.  Uses algorithm 2.3.4 of SEC 1. 
+ * Note that the simple implementation only uses affine coordinates.
+ *
+ * The method is from the following publication:
+ * 
+ *     Harper, Menezes, Vanstone:
+ *     "Public-Key Cryptosystems with Very Small Key Lengths",
+ *     EUROCRYPT '92, Springer-Verlag LNCS 658,
+ *     published February 1993
+ *
+ * US Patents 6,141,420 and 6,618,483 (Vanstone, Mullin, Agnew) describe
+ * the same method, but claim no priority date earlier than July 29, 1994
+ * (and additionally fail to cite the EUROCRYPT '92 publication as prior art).
+ */
+int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point,
+       const BIGNUM *x_, int y_bit, BN_CTX *ctx)
+       {
+       BN_CTX *new_ctx = NULL;
+       BIGNUM *tmp, *x, *y, *z;
+       int ret = 0, z0;
+
+       /* clear error queue */
+       ERR_clear_error();
+
+       if (ctx == NULL)
+               {
+               ctx = new_ctx = BN_CTX_new();
+               if (ctx == NULL)
+                       return 0;
+               }
+
+       y_bit = (y_bit != 0) ? 1 : 0;
+
+       BN_CTX_start(ctx);
+       tmp = BN_CTX_get(ctx);
+       x = BN_CTX_get(ctx);
+       y = BN_CTX_get(ctx);
+       z = BN_CTX_get(ctx);
+       if (z == NULL) goto err;
+
+       if (!BN_GF2m_mod_arr(x, x_, group->poly)) goto err;
+       if (BN_is_zero(x))
+               {
+               if (!BN_GF2m_mod_sqrt_arr(y, &group->b, group->poly, ctx)) goto err;
+               }
+       else
+               {
+               if (!group->meth->field_sqr(group, tmp, x, ctx)) goto err;
+               if (!group->meth->field_div(group, tmp, &group->b, tmp, ctx)) goto err;
+               if (!BN_GF2m_add(tmp, &group->a, tmp)) goto err;
+               if (!BN_GF2m_add(tmp, x, tmp)) goto err;
+               if (!BN_GF2m_mod_solve_quad_arr(z, tmp, group->poly, ctx))
+                       {
+                       unsigned long err = ERR_peek_last_error();
+                       
+                       if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NO_SOLUTION)
+                               {
+                               ERR_clear_error();
+                               ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
+                               }
+                       else
+                               ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB);
+                       goto err;
+                       }
+               z0 = (BN_is_odd(z)) ? 1 : 0;
+               if (!group->meth->field_mul(group, y, x, z, ctx)) goto err;
+               if (z0 != y_bit)
+                       {
+                       if (!BN_GF2m_add(y, y, x)) goto err;
+                       }
+               }
+
+       if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
+
+       ret = 1;
+
+ err:
+       BN_CTX_end(ctx);
+       if (new_ctx != NULL)
+               BN_CTX_free(new_ctx);
+       return ret;
+       }
 
 
 /* Converts an EC_POINT to an octet string.  
  * If buf is NULL, the encoded length will be returned.
  * If the length len of buf is smaller than required an error will be returned.
- *
- * The point compression section of this function is patented by Certicom Corp. 
- * under US Patent 6,141,420.  Point compression is disabled by default and can 
- * be enabled by defining the preprocessor macro OPENSSL_EC_BIN_PT_COMP at 
- * Configure-time.
  */
 size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
        unsigned char *buf, size_t len, BN_CTX *ctx)
@@ -425,14 +504,6 @@ size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, po
        BIGNUM *x, *y, *yxi;
        size_t field_len, i, skip;
 
-#ifndef OPENSSL_EC_BIN_PT_COMP
-       if ((form == POINT_CONVERSION_COMPRESSED) || (form == POINT_CONVERSION_HYBRID)) 
-               {
-               ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_DISABLED);
-               goto err;
-               }
-#endif
-
        if ((form != POINT_CONVERSION_COMPRESSED)
                && (form != POINT_CONVERSION_UNCOMPRESSED)
                && (form != POINT_CONVERSION_HYBRID))
@@ -487,13 +558,11 @@ size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, po
                if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err;
 
                buf[0] = form;
-#ifdef OPENSSL_EC_BIN_PT_COMP
                if ((form != POINT_CONVERSION_UNCOMPRESSED) && !BN_is_zero(x))
                        {
                        if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err;
                        if (BN_is_odd(yxi)) buf[0]++;
                        }
-#endif
 
                i = 1;