Change internals of the EC library so that the functions
EC_GROUP_{set_generator,get_generator,get_order,get_cofactor} are
implemented directly in crypto/ec/ec_lib.c and not dispatched to
methods.

Also fix EC_GROUP_copy to copy the NID.
diff --git a/CHANGES b/CHANGES
index d8b1b62..ed2bcea 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,16 @@
 
  Changes between 0.9.7 and 0.9.8  [xx XXX 2002]
 
+  *) Change internals of the EC library so that the functions
+          EC_GROUP_set_generator()
+          EC_GROUP_get_generator()
+          EC_GROUP_get_order()
+          EC_GROUP_get_cofactor()
+     are implemented directly in crypto/ec/ec_lib.c and not dispatched
+     to methods, which would lead to unnecessary code duplication when
+     adding different types of curves.
+     [Nils Larsch with input by Bodo Moeller]
+
   *) Implement compute_wNAF (crypto/ec/ec_mult.c) without BIGNUM
      arithmetic, and such that modified wNAFs are generated
      (which avoid length expansion in many cases).
diff --git a/crypto/ec/ec.h b/crypto/ec/ec.h
index 05b454c..6baf39c 100644
--- a/crypto/ec/ec.h
+++ b/crypto/ec/ec.h
@@ -107,11 +107,16 @@
 void EC_GROUP_clear_free(EC_GROUP *);
 int EC_GROUP_copy(EC_GROUP *, const EC_GROUP *);
 
+const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
+
+int EC_GROUP_set_generator(EC_GROUP *, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor);
+EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
+int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *);
+int EC_GROUP_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *);
+
 void EC_GROUP_set_nid(EC_GROUP *, int);
 int EC_GROUP_get_nid(const EC_GROUP *);
 
-const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
-
 
 /* We don't have types for field specifications and field elements in general.
  * Otherwise we could declare
@@ -120,11 +125,6 @@
 int EC_GROUP_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
 int EC_GROUP_get_curve_GFp(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
 
-int EC_GROUP_set_generator(EC_GROUP *, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor);
-EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
-int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *);
-int EC_GROUP_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *);
-
 /* EC_GROUP_check() returns 1 if 'group' defines a valid group, 0 otherwise */
 int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx);
 /* EC_GROUP_check_discriminant() returns 1 if the discriminant of the
diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h
index ece0de8..79655e3 100644
--- a/crypto/ec/ec_lcl.h
+++ b/crypto/ec/ec_lcl.h
@@ -73,15 +73,6 @@
 	int (*group_set_curve_GFp)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
 	int (*group_get_curve_GFp)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
 
-	/* used by EC_GROUP_set_generator, EC_GROUP_get0_generator,
-	 * EC_GROUP_get_order, EC_GROUP_get_cofactor:
-	 */
-	int (*group_set_generator)(EC_GROUP *, const EC_POINT *generator,
-	        const BIGNUM *order, const BIGNUM *cofactor);
-	EC_POINT *(*group_get0_generator)(const EC_GROUP *);
-	int (*group_get_order)(const EC_GROUP *, BIGNUM *order, BN_CTX *);
-	int (*group_get_cofactor)(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *);
-
 	/* used by EC_GROUP_check: */
 	int (*group_check_discriminant)(const EC_GROUP *, BN_CTX *);
 
@@ -146,16 +137,24 @@
 struct ec_group_st {
 	const EC_METHOD *meth;
 
+	EC_POINT *generator; /* optional */
+	BIGNUM order, cofactor;
+
+	int nid; /* optional NID for named curve */
+
 	void *extra_data;
 	void *(*extra_data_dup_func)(void *);
 	void (*extra_data_free_func)(void *);
 	void (*extra_data_clear_free_func)(void *);
 
-	/* All members except 'meth' and 'extra_data...' are handled by
-	 * the method functions, even if they appear generic */
+	/* The following members are handled by the method functions,
+	 * even if they appear generic */
 	
 	BIGNUM field; /* Field specification.
-	               * For curves over GF(p), this is the modulus. */
+	               * For curves over GF(p), this is the modulus;
+	               * for curves over GF(2^m), this is the 
+	               * irreducible polynomial defining the field.
+	               */
 
 	BIGNUM a, b; /* Curve coefficients.
 	              * (Here the assumption is that BIGNUMs can be used
@@ -163,14 +162,13 @@
 	              * For characteristic  > 3,  the curve is defined
 	              * by a Weierstrass equation of the form
 	              *     y^2 = x^3 + a*x + b.
+	              * For characteristic  2,  the curve is defined by
+	              * an equation of the form
+	              *     y^2 + x*y = x^3 + a*x^2 + b.
 	              */
+
 	int a_is_minus3; /* enable optimized point arithmetics for special case */
 
-	EC_POINT *generator; /* optional */
-	BIGNUM order, cofactor;
-
-	int nid;
-
 	void *field_data1; /* method-specific (e.g., Montgomery structure) */
 	void *field_data2; /* method-specific */
 } /* EC_GROUP */;
@@ -213,11 +211,6 @@
 int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *);
 int ec_GFp_simple_group_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
 int ec_GFp_simple_group_get_curve_GFp(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
-int ec_GFp_simple_group_set_generator(EC_GROUP *, const EC_POINT *generator,
-	const BIGNUM *order, const BIGNUM *cofactor);
-EC_POINT *ec_GFp_simple_group_get0_generator(const EC_GROUP *);
-int ec_GFp_simple_group_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *);
-int ec_GFp_simple_group_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *);
 int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
 int ec_GFp_simple_point_init(EC_POINT *);
 void ec_GFp_simple_point_finish(EC_POINT *);
diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c
index a5153cd..0597087 100644
--- a/crypto/ec/ec_lib.c
+++ b/crypto/ec/ec_lib.c
@@ -94,6 +94,10 @@
 	ret->extra_data_free_func = 0;
 	ret->extra_data_clear_free_func = 0;
 
+	ret->generator = NULL;
+	BN_init(&ret->order);
+	BN_init(&ret->cofactor);
+
 	ret->nid = 0;	
 
 	if (!meth->group_init(ret))
@@ -113,6 +117,11 @@
 
 	EC_GROUP_free_extra_data(group);
 
+	if (group->generator != NULL)
+		EC_POINT_free(group->generator);
+	BN_free(&group->order);
+	BN_free(&group->cofactor);
+
 	OPENSSL_free(group);
 	}
  
@@ -126,6 +135,11 @@
 
 	EC_GROUP_clear_free_extra_data(group);
 
+	if (group->generator != NULL)
+		EC_POINT_clear_free(group->generator);
+	BN_clear_free(&group->order);
+	BN_clear_free(&group->cofactor);
+
 	memset(group, 0, sizeof *group);
 	OPENSSL_free(group);
 	}
@@ -161,6 +175,30 @@
 		dest->extra_data_clear_free_func = src->extra_data_clear_free_func;
 		}
 
+	if (src->generator != NULL)
+		{
+		if (dest->generator == NULL)
+			{
+			dest->generator = EC_POINT_new(dest);
+			if (dest->generator == NULL) return 0;
+			}
+		if (!EC_POINT_copy(dest->generator, src->generator)) return 0;
+		}
+	else
+		{
+		/* src->generator == NULL */
+		if (dest->generator != NULL)
+			{
+			EC_POINT_clear_free(dest->generator);
+			dest->generator = NULL;
+			}
+		}
+
+	if (!BN_copy(&dest->order, &src->order)) return 0;
+	if (!BN_copy(&dest->cofactor, &src->cofactor)) return 0;
+
+	dest->nid = src->nid;
+
 	return dest->meth->group_copy(dest, src);
 	}
 
@@ -171,6 +209,71 @@
 	}
 
 
+int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor)
+	{
+	if (generator == NULL)
+		{
+		ECerr(EC_F_EC_GROUP_SET_GENERATOR, ERR_R_PASSED_NULL_PARAMETER);
+		return 0   ;
+		}
+
+	if (group->generator == NULL)
+		{
+		group->generator = EC_POINT_new(group);
+		if (group->generator == NULL) return 0;
+		}
+	if (!EC_POINT_copy(group->generator, generator)) return 0;
+
+	if (order != NULL)
+		{ if (!BN_copy(&group->order, order)) return 0; }	
+	else
+		{ if (!BN_zero(&group->order)) return 0; }	
+
+	if (cofactor != NULL)
+		{ if (!BN_copy(&group->cofactor, cofactor)) return 0; }	
+	else
+		{ if (!BN_zero(&group->cofactor)) return 0; }	
+
+	return 1;
+	}
+
+
+EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group)
+	{
+	return group->generator;
+	}
+
+
+int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx)
+	{
+	if (!BN_copy(order, &group->order))
+		return 0;
+
+	return !BN_is_zero(order);
+	}
+
+
+int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx)
+	{
+	if (!BN_copy(cofactor, &group->cofactor))
+		return 0;
+
+	return !BN_is_zero(&group->cofactor);
+	}
+
+
+void EC_GROUP_set_nid(EC_GROUP *group, int nid)
+	{
+	group->nid = nid;
+	}
+
+
+int EC_GROUP_get_nid(const EC_GROUP *group)
+	{
+	return group->nid;
+	}
+
+
 int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
 	{
 	if (group->meth->group_set_curve_GFp == 0)
@@ -193,50 +296,6 @@
 	}
 
 
-int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor)
-	{
-	if (group->meth->group_set_generator == 0)
-		{
-		ECerr(EC_F_EC_GROUP_SET_GENERATOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
-		return 0;
-		}
-	return group->meth->group_set_generator(group, generator, order, cofactor);
-	}
-
-
-EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group)
-	{
-	if (group->meth->group_get0_generator == 0)
-		{
-		ECerr(EC_F_EC_GROUP_GET0_GENERATOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
-		return 0;
-		}
-	return group->meth->group_get0_generator(group);
-	}
-
-
-int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx)
-	{
-	if (group->meth->group_get_order == 0)
-		{
-		ECerr(EC_F_EC_GROUP_GET_ORDER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
-		return 0;
-		}
-	return group->meth->group_get_order(group, order, ctx);
-	}
-
-
-int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx)
-	{
-	if (group->meth->group_get_cofactor == 0)
-		{
-		ECerr(EC_F_EC_GROUP_GET_COFACTOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
-		return 0;
-		}
-	return group->meth->group_get_cofactor(group, cofactor, ctx);
-	}
-
-
 int EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
 	{
 	if (group->meth->group_check_discriminant == 0)
@@ -248,18 +307,6 @@
 	}
 
 
-void EC_GROUP_set_nid(EC_GROUP *group, int nid)
-	{
-	group->nid = nid;
-	}
-
-
-int EC_GROUP_get_nid(const EC_GROUP *group)
-	{
-	return group->nid;
-	}
-
-
 /* this has 'package' visibility */
 int EC_GROUP_set_extra_data(EC_GROUP *group, void *extra_data, void *(*extra_data_dup_func)(void *),
 	void (*extra_data_free_func)(void *), void (*extra_data_clear_free_func)(void *))
diff --git a/crypto/ec/ecp_mont.c b/crypto/ec/ecp_mont.c
index bad0a13..6f1eaa4 100644
--- a/crypto/ec/ecp_mont.c
+++ b/crypto/ec/ecp_mont.c
@@ -67,10 +67,6 @@
 		ec_GFp_mont_group_copy,
 		ec_GFp_mont_group_set_curve_GFp,
 		ec_GFp_simple_group_get_curve_GFp,
-		ec_GFp_simple_group_set_generator,
-		ec_GFp_simple_group_get0_generator,
-		ec_GFp_simple_group_get_order,
-		ec_GFp_simple_group_get_cofactor,
 		ec_GFp_simple_group_check_discriminant,
 		ec_GFp_simple_point_init,
 		ec_GFp_simple_point_finish,
diff --git a/crypto/ec/ecp_smpl.c b/crypto/ec/ecp_smpl.c
index 911a4e4..5adc907 100644
--- a/crypto/ec/ecp_smpl.c
+++ b/crypto/ec/ecp_smpl.c
@@ -69,10 +69,6 @@
 		ec_GFp_simple_group_copy,
 		ec_GFp_simple_group_set_curve_GFp,
 		ec_GFp_simple_group_get_curve_GFp,
-		ec_GFp_simple_group_set_generator,
-		ec_GFp_simple_group_get0_generator,
-		ec_GFp_simple_group_get_order,
-		ec_GFp_simple_group_get_cofactor,
 		ec_GFp_simple_group_check_discriminant,
 		ec_GFp_simple_point_init,
 		ec_GFp_simple_point_finish,
@@ -110,9 +106,6 @@
 	BN_init(&group->a);
 	BN_init(&group->b);
 	group->a_is_minus3 = 0;
-	group->generator = NULL;
-	BN_init(&group->order);
-	BN_init(&group->cofactor);
 	return 1;
 	}
 
@@ -122,10 +115,6 @@
 	BN_free(&group->field);
 	BN_free(&group->a);
 	BN_free(&group->b);
-	if (group->generator != NULL)
-		EC_POINT_free(group->generator);
-	BN_free(&group->order);
-	BN_free(&group->cofactor);
 	}
 
 
@@ -134,13 +123,6 @@
 	BN_clear_free(&group->field);
 	BN_clear_free(&group->a);
 	BN_clear_free(&group->b);
-	if (group->generator != NULL)
-		{
-		EC_POINT_clear_free(group->generator);
-		group->generator = NULL;
-		}
-	BN_clear_free(&group->order);
-	BN_clear_free(&group->cofactor);
 	}
 
 
@@ -152,28 +134,6 @@
 
 	dest->a_is_minus3 = src->a_is_minus3;
 
-	if (src->generator != NULL)
-		{
-		if (dest->generator == NULL)
-			{
-			dest->generator = EC_POINT_new(dest);
-			if (dest->generator == NULL) return 0;
-			}
-		if (!EC_POINT_copy(dest->generator, src->generator)) return 0;
-		}
-	else
-		{
-		/* src->generator == NULL */
-		if (dest->generator != NULL)
-			{
-			EC_POINT_clear_free(dest->generator);
-			dest->generator = NULL;
-			}
-		}
-
-	if (!BN_copy(&dest->order, &src->order)) return 0;
-	if (!BN_copy(&dest->cofactor, &src->cofactor)) return 0;
-
 	return 1;
 	}
 
@@ -284,61 +244,6 @@
 	}
 
 
-
-int ec_GFp_simple_group_set_generator(EC_GROUP *group, const EC_POINT *generator,
-	const BIGNUM *order, const BIGNUM *cofactor)
-	{
-	if (generator == NULL)
-		{
-		ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR, ERR_R_PASSED_NULL_PARAMETER);
-		return 0   ;
-		}
-
-	if (group->generator == NULL)
-		{
-		group->generator = EC_POINT_new(group);
-		if (group->generator == NULL) return 0;
-		}
-	if (!EC_POINT_copy(group->generator, generator)) return 0;
-
-	if (order != NULL)
-		{ if (!BN_copy(&group->order, order)) return 0; }	
-	else
-		{ if (!BN_zero(&group->order)) return 0; }	
-
-	if (cofactor != NULL)
-		{ if (!BN_copy(&group->cofactor, cofactor)) return 0; }	
-	else
-		{ if (!BN_zero(&group->cofactor)) return 0; }	
-
-	return 1;
-	}
-
-
-EC_POINT *ec_GFp_simple_group_get0_generator(const EC_GROUP *group)
-	{
-	return group->generator;
-	}
-
-
-int ec_GFp_simple_group_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx)
-	{
-	if (!BN_copy(order, &group->order))
-		return 0;
-
-	return !BN_is_zero(&group->order);
-	}
-
-
-int ec_GFp_simple_group_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx)
-	{
-	if (!BN_copy(cofactor, &group->cofactor))
-		return 0;
-
-	return !BN_is_zero(&group->cofactor);
-	}
-
-
 int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
 	{
 	int ret = 0;