A tweak to generate keys in a way that will enable the efficient point
compression, described in
http://tools.ietf.org/html/draft-jivsov-ecc-compact.
This request doesn't change any format/API, doesn't introduce
compression, and doesn't lower security.
However, because the method to generate compact ECC representation
depends on "compliant" key generation and keys migrate across software
packages, this change enables thus generated keys to be efficiently
represented, if and when the efficient representation is implemented and
supported.
The patch is for the openssl-1.0.1e; in a single function
EC_KEY_generate_key, file crypto/ec/ec_key.c.
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index 7fa2475..3a403a9 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -284,6 +284,46 @@ int EC_KEY_generate_key(EC_KEY *eckey)
if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx))
goto err;
+ {
+ /* We want the Q=(x,y) be a "compliant key" in terms of the http://tools.ietf.org/html/draft-jivsov-ecc-compact,
+ * which simply means that we choose either Q=(x,y) or -Q=(x,p-y) such that we end up with the min(y,p-y) as the y coordinate.
+ * Such a public key allows the most efficient compression: y can simply be dropped because without any loss of security.
+ * Given the x, we know that the y is a minimum of the two possibilities.
+ */
+ const EC_METHOD *meth = EC_GROUP_method_of(eckey->group);
+ const int is_prime = (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field);
+
+ if( is_prime ) {
+ BIGNUM *ec_p, *ec_a, *ec_b, *ec_p_y, *ec_x, *ec_y;
+
+ ec_p = BN_CTX_get(ctx);
+ ec_a = BN_CTX_get(ctx);
+ ec_b = BN_CTX_get(ctx);
+ ec_p_y = BN_CTX_get(ctx);
+ ec_x = BN_CTX_get(ctx);
+ ec_y = BN_CTX_get(ctx);
+
+ if ( ec_p == NULL || ec_a == NULL || ec_b == NULL || ec_p_y == NULL)
+ {
+ goto err;
+ }
+ if (!EC_GROUP_get_curve_GFp(eckey->group, ec_p, ec_a, ec_b, NULL)) {
+ goto err;
+ }
+ if (!EC_POINT_get_affine_coordinates_GFp(eckey->group, pub_key, ec_x, ec_y, ctx)) {
+ goto err;
+ }
+ BN_sub( ec_p_y, ec_p, ec_y );
+
+ if( BN_cmp( ec_p_y, ec_y ) < 0 ) {
+ /* will need conversion, 50% of the time */
+ BN_sub( priv_key, order, priv_key );
+ if (!EC_POINT_set_affine_coordinates_GFp(eckey->group, pub_key, ec_x, ec_p_y, ctx))
+ goto err;
+ }
+ }
+ }
+
eckey->priv_key = priv_key;
eckey->pub_key = pub_key;