Blame SOURCES/ecc-curves.c

66e42d
/* ecc-curves.c  -  Elliptic Curve parameter mangement
66e42d
 * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
66e42d
 * Copyright (C) 2013 g10 Code GmbH
66e42d
 *
66e42d
 * This file is part of Libgcrypt.
66e42d
 *
66e42d
 * Libgcrypt is free software; you can redistribute it and/or modify
66e42d
 * it under the terms of the GNU Lesser General Public License as
66e42d
 * published by the Free Software Foundation; either version 2.1 of
66e42d
 * the License, or (at your option) any later version.
66e42d
 *
66e42d
 * Libgcrypt is distributed in the hope that it will be useful,
66e42d
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
66e42d
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
66e42d
 * GNU Lesser General Public License for more details.
66e42d
 *
66e42d
 * You should have received a copy of the GNU Lesser General Public
66e42d
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
66e42d
 */
66e42d
66e42d
#include <config.h>
66e42d
#include <stdio.h>
66e42d
#include <stdlib.h>
66e42d
#include <string.h>
66e42d
#include <errno.h>
66e42d
66e42d
#include "g10lib.h"
66e42d
#include "mpi.h"
66e42d
#include "cipher.h"
66e42d
#include "context.h"
66e42d
#include "ec-context.h"
66e42d
#include "pubkey-internal.h"
66e42d
#include "ecc-common.h"
66e42d
66e42d
66e42d
/* This tables defines aliases for curve names.  */
66e42d
static const struct
66e42d
{
66e42d
  const char *name;  /* Our name.  */
66e42d
  const char *other; /* Other name. */
66e42d
} curve_aliases[] =
66e42d
  {
66e42d
    { "Curve25519", "1.3.6.1.4.1.3029.1.5.1" },
66e42d
    { "Ed25519",    "1.3.6.1.4.1.11591.15.1" },
66e42d
66e42d
    { "NIST P-224", "secp224r1" },
66e42d
    { "NIST P-224", "1.3.132.0.33" },        /* SECP OID.  */
66e42d
    { "NIST P-224", "nistp224"   },          /* rfc5656.  */
66e42d
66e42d
    { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1.  */
66e42d
    { "NIST P-256", "prime256v1" },
66e42d
    { "NIST P-256", "secp256r1"  },
66e42d
    { "NIST P-256", "nistp256"   },          /* rfc5656.  */
66e42d
66e42d
    { "NIST P-384", "secp384r1" },
66e42d
    { "NIST P-384", "1.3.132.0.34" },
66e42d
    { "NIST P-384", "nistp384"   },          /* rfc5656.  */
66e42d
66e42d
    { "NIST P-521", "secp521r1" },
66e42d
    { "NIST P-521", "1.3.132.0.35" },
66e42d
    { "NIST P-521", "nistp521"   },          /* rfc5656.  */
66e42d
66e42d
    { "GOST2001-test", "1.2.643.2.2.35.0" },
66e42d
    { "GOST2001-CryptoPro-A", "1.2.643.2.2.35.1" },
66e42d
    { "GOST2001-CryptoPro-B", "1.2.643.2.2.35.2" },
66e42d
    { "GOST2001-CryptoPro-C", "1.2.643.2.2.35.3" },
66e42d
    { "GOST2001-CryptoPro-A", "GOST2001-CryptoPro-XchA" },
66e42d
    { "GOST2001-CryptoPro-C", "GOST2001-CryptoPro-XchB" },
66e42d
    { "GOST2001-CryptoPro-A", "1.2.643.2.2.36.0" },
66e42d
    { "GOST2001-CryptoPro-C", "1.2.643.2.2.36.1" },
66e42d
66e42d
    { "GOST2012-tc26-A", "1.2.643.7.1.2.1.2.1" },
66e42d
    { "GOST2012-tc26-B", "1.2.643.7.1.2.1.2.2" },
66e42d
66e42d
    { "secp256k1", "1.3.132.0.10" },
66e42d
66e42d
    { NULL, NULL}
66e42d
  };
66e42d
66e42d
66e42d
typedef struct
66e42d
{
66e42d
  const char *desc;           /* Description of the curve.  */
66e42d
  unsigned int nbits;         /* Number of bits.  */
66e42d
  unsigned int fips:1;        /* True if this is a FIPS140-2 approved curve. */
66e42d
66e42d
  /* The model describing this curve.  This is mainly used to select
66e42d
     the group equation. */
66e42d
  enum gcry_mpi_ec_models model;
66e42d
66e42d
  /* The actual ECC dialect used.  This is used for curve specific
66e42d
     optimizations and to select encodings etc. */
66e42d
  enum ecc_dialects dialect;
66e42d
66e42d
  const char *p;              /* The prime defining the field.  */
66e42d
  const char *a, *b;          /* The coefficients.  For Twisted Edwards
66e42d
                                 Curves b is used for d.  For Montgomery
66e42d
                                 Curves (a,b) has ((A-2)/4,B^-1).  */
66e42d
  const char *n;              /* The order of the base point.  */
66e42d
  const char *g_x, *g_y;      /* Base point.  */
66e42d
  const char *h;              /* Cofactor.  */
66e42d
} ecc_domain_parms_t;
66e42d
66e42d
66e42d
/* This static table defines all available curves.  */
66e42d
static const ecc_domain_parms_t domain_parms[] =
66e42d
  {
66e42d
    {
66e42d
      /* (-x^2 + y^2 = 1 + dx^2y^2) */
66e42d
      "Ed25519", 256, 0,
66e42d
      MPI_EC_EDWARDS, ECC_DIALECT_ED25519,
66e42d
      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
66e42d
      "-0x01",
66e42d
      "-0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A",
66e42d
      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
66e42d
      "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
66e42d
      "0x6666666666666666666666666666666666666666666666666666666666666658",
66e42d
      "0x08"
66e42d
    },
66e42d
    {
66e42d
      /* (y^2 = x^3 + 486662*x^2 + x) */
66e42d
      "Curve25519", 256, 0,
66e42d
      MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD,
66e42d
      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
66e42d
      "0x01DB41",
66e42d
      "0x01",
66e42d
      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000009",
66e42d
      "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9",
66e42d
      "0x08"
66e42d
    },
66e42d
    {
66e42d
      "NIST P-224", 224, 1,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0xffffffffffffffffffffffffffffffff000000000000000000000001",
66e42d
      "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
66e42d
      "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
66e42d
      "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
66e42d
66e42d
      "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
66e42d
      "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "NIST P-256", 256, 1,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
66e42d
      "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
66e42d
      "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
66e42d
      "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
66e42d
66e42d
      "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
66e42d
      "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "NIST P-384", 384, 1,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
66e42d
      "ffffffff0000000000000000ffffffff",
66e42d
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
66e42d
      "ffffffff0000000000000000fffffffc",
66e42d
      "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
66e42d
      "c656398d8a2ed19d2a85c8edd3ec2aef",
66e42d
      "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
66e42d
      "581a0db248b0a77aecec196accc52973",
66e42d
66e42d
      "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
66e42d
      "5502f25dbf55296c3a545e3872760ab7",
66e42d
      "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
66e42d
      "0a60b1ce1d7e819d7a431d7c90ea0e5f",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "NIST P-521", 521, 1,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
66e42d
      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
66e42d
      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
66e42d
      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
66e42d
      "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
66e42d
      "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
66e42d
      "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
66e42d
      "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
66e42d
66e42d
      "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d"
66e42d
      "3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
66e42d
      "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e"
66e42d
      "662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
66e42d
      "0x01"
66e42d
    },
66e42d
66e42d
    {
66e42d
      "GOST2001-test", 256, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0x8000000000000000000000000000000000000000000000000000000000000431",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000007",
66e42d
      "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e",
66e42d
      "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3",
66e42d
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000002",
66e42d
      "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "GOST2001-CryptoPro-A", 256, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97",
66e42d
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd94",
66e42d
      "0x00000000000000000000000000000000000000000000000000000000000000a6",
66e42d
      "0xffffffffffffffffffffffffffffffff6c611070995ad10045841b09b761b893",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000001",
66e42d
      "0x8d91e471e0989cda27df505a453f2b7635294f2ddf23e3b122acc99c9e9f1e14",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "GOST2001-CryptoPro-B", 256, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0x8000000000000000000000000000000000000000000000000000000000000c99",
66e42d
      "0x8000000000000000000000000000000000000000000000000000000000000c96",
66e42d
      "0x3e1af419a269a5f866a7d3c25c3df80ae979259373ff2b182f49d4ce7e1bbc8b",
66e42d
      "0x800000000000000000000000000000015f700cfff1a624e5e497161bcc8a198f",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000001",
66e42d
      "0x3fa8124359f96680b83d1c3eb2c070e5c545c9858d03ecfb744bf8d717717efc",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "GOST2001-CryptoPro-C", 256, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b",
66e42d
      "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598",
66e42d
      "0x000000000000000000000000000000000000000000000000000000000000805a",
66e42d
      "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000000",
66e42d
      "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "GOST2012-test", 511, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d"
66e42d
      "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000007",
66e42d
      "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4"
66e42d
      "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc",
66e42d
      "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d"
66e42d
      "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df",
66e42d
66e42d
      "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762"
66e42d
      "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a",
66e42d
      "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2"
66e42d
      "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "GOST2012-tc26-A", 512, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
66e42d
        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7",
66e42d
      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
66e42d
        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc4",
66e42d
      "0xe8c2505dedfc86ddc1bd0b2b6667f1da34b82574761cb0e879bd081cfd0b6265"
66e42d
        "ee3cb090f30d27614cb4574010da90dd862ef9d4ebee4761503190785a71c760",
66e42d
      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
66e42d
        "27e69532f48d89116ff22b8d4e0560609b4b38abfad2b85dcacdb1411f10b275",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000000"
66e42d
        "0000000000000000000000000000000000000000000000000000000000000003",
66e42d
      "0x7503cfe87a836ae3a61b8816e25450e6ce5e1c93acf1abc1778064fdcbefa921"
66e42d
        "df1626be4fd036e93d75e6a50e3a41e98028fe5fc235f5b889a589cb5215f2a4",
66e42d
      "0x01"
66e42d
    },
66e42d
    {
66e42d
      "GOST2012-tc26-B", 512, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0x8000000000000000000000000000000000000000000000000000000000000000"
66e42d
        "000000000000000000000000000000000000000000000000000000000000006f",
66e42d
      "0x8000000000000000000000000000000000000000000000000000000000000000"
66e42d
        "000000000000000000000000000000000000000000000000000000000000006c",
66e42d
      "0x687d1b459dc841457e3e06cf6f5e2517b97c7d614af138bcbf85dc806c4b289f"
66e42d
        "3e965d2db1416d217f8b276fad1ab69c50f78bee1fa3106efb8ccbc7c5140116",
66e42d
      "0x8000000000000000000000000000000000000000000000000000000000000001"
66e42d
        "49a1ec142565a545acfdb77bd9d40cfa8b996712101bea0ec6346c54374f25bd",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000000"
66e42d
        "0000000000000000000000000000000000000000000000000000000000000002",
66e42d
      "0x1a8f7eda389b094c2c071e3647a8940f3c123b697578c213be6dd9e6c8ec7335"
66e42d
        "dcb228fd1edf4a39152cbcaaf8c0398828041055f94ceeec7e21340780fe41bd",
66e42d
      "0x01"
66e42d
    },
66e42d
66e42d
    {
66e42d
      "secp256k1", 256, 0,
66e42d
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
66e42d
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000000",
66e42d
      "0x0000000000000000000000000000000000000000000000000000000000000007",
66e42d
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
66e42d
      "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
66e42d
      "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
66e42d
      "0x01"
66e42d
    },
66e42d
66e42d
    { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
66e42d
  };
66e42d
66e42d
66e42d
66e42d

66e42d
/* Return a copy of POINT.  */
66e42d
static gcry_mpi_point_t
66e42d
point_copy (gcry_mpi_point_t point)
66e42d
{
66e42d
  gcry_mpi_point_t newpoint;
66e42d
66e42d
  if (point)
66e42d
    {
66e42d
      newpoint = mpi_point_new (0);
66e42d
      point_set (newpoint, point);
66e42d
    }
66e42d
  else
66e42d
    newpoint = NULL;
66e42d
  return newpoint;
66e42d
}
66e42d
66e42d
66e42d
/* Helper to scan a hex string. */
66e42d
static gcry_mpi_t
66e42d
scanval (const char *string)
66e42d
{
66e42d
  gpg_err_code_t rc;
66e42d
  gcry_mpi_t val;
66e42d
66e42d
  rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
66e42d
  if (rc)
66e42d
    log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc));
66e42d
  return val;
66e42d
}
66e42d
66e42d
66e42d
/* Return the index of the domain_parms table for a curve with NAME.
66e42d
   Return -1 if not found.  */
66e42d
static int
66e42d
find_domain_parms_idx (const char *name)
66e42d
{
66e42d
  int idx, aliasno;
66e42d
66e42d
  /* First check our native curves.  */
66e42d
  for (idx = 0; domain_parms[idx].desc; idx++)
66e42d
    if (!strcmp (name, domain_parms[idx].desc))
66e42d
      return idx;
66e42d
66e42d
  /* If not found consult the alias table.  */
66e42d
  if (!domain_parms[idx].desc)
66e42d
    {
66e42d
      for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
66e42d
        if (!strcmp (name, curve_aliases[aliasno].other))
66e42d
          break;
66e42d
      if (curve_aliases[aliasno].name)
66e42d
        {
66e42d
          for (idx = 0; domain_parms[idx].desc; idx++)
66e42d
            if (!strcmp (curve_aliases[aliasno].name, domain_parms[idx].desc))
66e42d
              return idx;
66e42d
        }
66e42d
    }
66e42d
66e42d
  return -1;
66e42d
}
66e42d
66e42d
66e42d
/* Generate the crypto system setup.  This function takes the NAME of
66e42d
   a curve or the desired number of bits and stores at R_CURVE the
66e42d
   parameters of the named curve or those of a suitable curve.  If
66e42d
   R_NBITS is not NULL, the chosen number of bits is stored there.
66e42d
   NULL may be given for R_CURVE, if the value is not required and for
66e42d
   example only a quick test for availability is desired.  Note that
66e42d
   the curve fields should be initialized to zero because fields which
66e42d
   are not NULL are skipped.  */
66e42d
gpg_err_code_t
66e42d
_gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
66e42d
                         elliptic_curve_t *curve, unsigned int *r_nbits)
66e42d
{
66e42d
  int idx;
66e42d
  const char *resname = NULL; /* Set to a found curve name.  */
66e42d
66e42d
  if (name)
66e42d
    idx = find_domain_parms_idx (name);
66e42d
  else
66e42d
    {
66e42d
      for (idx = 0; domain_parms[idx].desc; idx++)
66e42d
        if (nbits == domain_parms[idx].nbits
66e42d
            && domain_parms[idx].model == MPI_EC_WEIERSTRASS)
66e42d
          break;
66e42d
      if (!domain_parms[idx].desc)
66e42d
        idx = -1;
66e42d
    }
66e42d
  if (idx < 0)
66e42d
    return GPG_ERR_UNKNOWN_CURVE;
66e42d
66e42d
  resname = domain_parms[idx].desc;
66e42d
66e42d
  /* In fips mode we only support NIST curves.  Note that it is
66e42d
     possible to bypass this check by specifying the curve parameters
66e42d
     directly.  */
66e42d
  if (fips_mode () && !domain_parms[idx].fips )
66e42d
    return GPG_ERR_NOT_SUPPORTED;
66e42d
66e42d
  switch (domain_parms[idx].model)
66e42d
    {
66e42d
    case MPI_EC_WEIERSTRASS:
66e42d
    case MPI_EC_EDWARDS:
66e42d
    case MPI_EC_MONTGOMERY:
66e42d
      break;
66e42d
    default:
66e42d
      return GPG_ERR_BUG;
66e42d
    }
66e42d
66e42d
66e42d
  if (r_nbits)
66e42d
    *r_nbits = domain_parms[idx].nbits;
66e42d
66e42d
  if (curve)
66e42d
    {
66e42d
      curve->model = domain_parms[idx].model;
66e42d
      curve->dialect = domain_parms[idx].dialect;
66e42d
      if (!curve->p)
66e42d
        curve->p = scanval (domain_parms[idx].p);
66e42d
      if (!curve->a)
66e42d
        {
66e42d
          curve->a = scanval (domain_parms[idx].a);
66e42d
          if (curve->a->sign)
66e42d
            mpi_add (curve->a, curve->p, curve->a);
66e42d
        }
66e42d
      if (!curve->b)
66e42d
        {
66e42d
          curve->b = scanval (domain_parms[idx].b);
66e42d
          if (curve->b->sign)
66e42d
            mpi_add (curve->b, curve->p, curve->b);
66e42d
        }
66e42d
      if (!curve->n)
66e42d
        curve->n = scanval (domain_parms[idx].n);
66e42d
      if (!curve->h)
66e42d
        curve->h = scanval (domain_parms[idx].h);
66e42d
      if (!curve->G.x)
66e42d
        curve->G.x = scanval (domain_parms[idx].g_x);
66e42d
      if (!curve->G.y)
66e42d
        curve->G.y = scanval (domain_parms[idx].g_y);
66e42d
      if (!curve->G.z)
66e42d
        curve->G.z = mpi_alloc_set_ui (1);
66e42d
      if (!curve->name)
66e42d
        curve->name = resname;
66e42d
    }
66e42d
66e42d
  return 0;
66e42d
}
66e42d
66e42d
66e42d
/* Give the name of the curve NAME, store the curve parameters into P,
66e42d
   A, B, G, N, and H if they point to NULL value.  Note that G is returned
66e42d
   in standard uncompressed format.  Also update MODEL and DIALECT if
66e42d
   they are not NULL. */
66e42d
gpg_err_code_t
66e42d
_gcry_ecc_update_curve_param (const char *name,
66e42d
                              enum gcry_mpi_ec_models *model,
66e42d
                              enum ecc_dialects *dialect,
66e42d
                              gcry_mpi_t *p, gcry_mpi_t *a, gcry_mpi_t *b,
66e42d
                              gcry_mpi_t *g, gcry_mpi_t *n, gcry_mpi_t *h)
66e42d
{
66e42d
  int idx;
66e42d
66e42d
  idx = find_domain_parms_idx (name);
66e42d
  if (idx < 0)
66e42d
    return GPG_ERR_UNKNOWN_CURVE;
66e42d
66e42d
  if (g)
66e42d
    {
66e42d
      char *buf;
66e42d
      size_t len;
66e42d
66e42d
      len = 4;
66e42d
      len += strlen (domain_parms[idx].g_x+2);
66e42d
      len += strlen (domain_parms[idx].g_y+2);
66e42d
      len++;
66e42d
      buf = xtrymalloc (len);
66e42d
      if (!buf)
66e42d
        return gpg_err_code_from_syserror ();
66e42d
      strcpy (stpcpy (stpcpy (buf, "0x04"), domain_parms[idx].g_x+2),
66e42d
              domain_parms[idx].g_y+2);
66e42d
      _gcry_mpi_release (*g);
66e42d
      *g = scanval (buf);
66e42d
      xfree (buf);
66e42d
    }
66e42d
  if (model)
66e42d
    *model = domain_parms[idx].model;
66e42d
  if (dialect)
66e42d
    *dialect = domain_parms[idx].dialect;
66e42d
  if (p)
66e42d
    {
66e42d
      _gcry_mpi_release (*p);
66e42d
      *p = scanval (domain_parms[idx].p);
66e42d
    }
66e42d
  if (a)
66e42d
    {
66e42d
      _gcry_mpi_release (*a);
66e42d
      *a = scanval (domain_parms[idx].a);
66e42d
    }
66e42d
  if (b)
66e42d
    {
66e42d
      _gcry_mpi_release (*b);
66e42d
      *b = scanval (domain_parms[idx].b);
66e42d
    }
66e42d
  if (n)
66e42d
    {
66e42d
      _gcry_mpi_release (*n);
66e42d
      *n = scanval (domain_parms[idx].n);
66e42d
    }
66e42d
  if (h)
66e42d
    {
66e42d
      _gcry_mpi_release (*h);
66e42d
      *h = scanval (domain_parms[idx].h);
66e42d
    }
66e42d
  return 0;
66e42d
}
66e42d
66e42d
66e42d
/* Return the name matching the parameters in PKEY.  This works only
66e42d
   with curves described by the Weierstrass equation. */
66e42d
const char *
66e42d
_gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits)
66e42d
{
66e42d
  gpg_err_code_t rc;
66e42d
  const char *result = NULL;
66e42d
  elliptic_curve_t E;
66e42d
  gcry_mpi_t mpi_g = NULL;
66e42d
  gcry_mpi_t tmp = NULL;
66e42d
  int idx;
66e42d
66e42d
  memset (&E, 0, sizeof E);
66e42d
66e42d
  if (r_nbits)
66e42d
    *r_nbits = 0;
66e42d
66e42d
  if (!keyparms)
66e42d
    {
66e42d
      idx = iterator;
66e42d
      if (idx >= 0 && idx < DIM (domain_parms))
66e42d
        {
66e42d
          result = domain_parms[idx].desc;
66e42d
          if (r_nbits)
66e42d
            *r_nbits = domain_parms[idx].nbits;
66e42d
        }
66e42d
      return result;
66e42d
    }
66e42d
66e42d
66e42d
  /*
66e42d
   * Extract the curve parameters..
66e42d
   */
66e42d
  rc = gpg_err_code (sexp_extract_param (keyparms, NULL, "-pabgnh",
66e42d
                                         &E.p, &E.a, &E.b, &mpi_g, &E.n, &E.h,
66e42d
                                         NULL));
66e42d
  if (rc == GPG_ERR_NO_OBJ)
66e42d
    {
66e42d
      /* This might be the second use case of checking whether a
66e42d
         specific curve given by name is supported.  */
66e42d
      gcry_sexp_t l1;
66e42d
      char *name;
66e42d
66e42d
      l1 = sexp_find_token (keyparms, "curve", 5);
66e42d
      if (!l1)
66e42d
        goto leave;  /* No curve name parameter.  */
66e42d
66e42d
      name = sexp_nth_string (l1, 1);
66e42d
      sexp_release (l1);
66e42d
      if (!name)
66e42d
        goto leave;  /* Name missing or out of core. */
66e42d
66e42d
      idx = find_domain_parms_idx (name);
66e42d
      xfree (name);
66e42d
      if (idx >= 0)  /* Curve found.  */
66e42d
        {
66e42d
          result = domain_parms[idx].desc;
66e42d
          if (r_nbits)
66e42d
            *r_nbits = domain_parms[idx].nbits;
66e42d
        }
66e42d
      return result;
66e42d
    }
66e42d
66e42d
  if (rc)
66e42d
    goto leave;
66e42d
66e42d
  if (mpi_g)
66e42d
    {
66e42d
      _gcry_mpi_point_init (&E.G);
66e42d
      if (_gcry_ecc_os2ec (&E.G, mpi_g))
66e42d
        goto leave;
66e42d
    }
66e42d
66e42d
  for (idx = 0; domain_parms[idx].desc; idx++)
66e42d
    {
66e42d
      mpi_free (tmp);
66e42d
      tmp = scanval (domain_parms[idx].p);
66e42d
      if (!mpi_cmp (tmp, E.p))
66e42d
        {
66e42d
          mpi_free (tmp);
66e42d
          tmp = scanval (domain_parms[idx].a);
66e42d
          if (!mpi_cmp (tmp, E.a))
66e42d
            {
66e42d
              mpi_free (tmp);
66e42d
              tmp = scanval (domain_parms[idx].b);
66e42d
              if (!mpi_cmp (tmp, E.b))
66e42d
                {
66e42d
                  mpi_free (tmp);
66e42d
                  tmp = scanval (domain_parms[idx].n);
66e42d
                  if (!mpi_cmp (tmp, E.n))
66e42d
                    {
66e42d
                      mpi_free (tmp);
66e42d
                      tmp = scanval (domain_parms[idx].h);
66e42d
                      if (!mpi_cmp (tmp, E.h))
66e42d
                        {
66e42d
                          mpi_free (tmp);
66e42d
                          tmp = scanval (domain_parms[idx].g_x);
66e42d
                          if (!mpi_cmp (tmp, E.G.x))
66e42d
                            {
66e42d
                              mpi_free (tmp);
66e42d
                              tmp = scanval (domain_parms[idx].g_y);
66e42d
                              if (!mpi_cmp (tmp, E.G.y))
66e42d
                                {
66e42d
                                  result = domain_parms[idx].desc;
66e42d
                                  if (r_nbits)
66e42d
                                    *r_nbits = domain_parms[idx].nbits;
66e42d
                                  goto leave;
66e42d
                                }
66e42d
                            }
66e42d
                        }
66e42d
                    }
66e42d
                }
66e42d
            }
66e42d
        }
66e42d
    }
66e42d
66e42d
 leave:
66e42d
  _gcry_mpi_release (tmp);
66e42d
  _gcry_mpi_release (E.p);
66e42d
  _gcry_mpi_release (E.a);
66e42d
  _gcry_mpi_release (E.b);
66e42d
  _gcry_mpi_release (mpi_g);
66e42d
  _gcry_mpi_point_free_parts (&E.G);
66e42d
  _gcry_mpi_release (E.n);
66e42d
  _gcry_mpi_release (E.h);
66e42d
  return result;
66e42d
}
66e42d
66e42d
66e42d
/* Helper to extract an MPI from key parameters.  */
66e42d
static gpg_err_code_t
66e42d
mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name)
66e42d
{
66e42d
  gcry_err_code_t ec = 0;
66e42d
  gcry_sexp_t l1;
66e42d
66e42d
  l1 = sexp_find_token (keyparam, name, 0);
66e42d
  if (l1)
66e42d
    {
66e42d
      *r_a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
66e42d
      sexp_release (l1);
66e42d
      if (!*r_a)
66e42d
        ec = GPG_ERR_INV_OBJ;
66e42d
    }
66e42d
  return ec;
66e42d
}
66e42d
66e42d
/* Helper to extract a point from key parameters.  If no parameter
66e42d
   with NAME is found, the functions tries to find a non-encoded point
66e42d
   by appending ".x", ".y" and ".z" to NAME.  ".z" is in this case
66e42d
   optional and defaults to 1.  EC is the context which at this point
66e42d
   may not be fully initialized. */
66e42d
static gpg_err_code_t
66e42d
point_from_keyparam (gcry_mpi_point_t *r_a,
66e42d
                     gcry_sexp_t keyparam, const char *name, mpi_ec_t ec)
66e42d
{
66e42d
  gcry_err_code_t rc;
66e42d
  gcry_sexp_t l1;
66e42d
  gcry_mpi_point_t point;
66e42d
66e42d
  l1 = sexp_find_token (keyparam, name, 0);
66e42d
  if (l1)
66e42d
    {
66e42d
      gcry_mpi_t a;
66e42d
66e42d
      a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE);
66e42d
      sexp_release (l1);
66e42d
      if (!a)
66e42d
        return GPG_ERR_INV_OBJ;
66e42d
66e42d
      point = mpi_point_new (0);
66e42d
      if (ec && ec->dialect == ECC_DIALECT_ED25519)
66e42d
        rc = _gcry_ecc_eddsa_decodepoint (a, ec, point, NULL, NULL);
66e42d
      else
66e42d
        rc = _gcry_ecc_os2ec (point, a);
66e42d
      mpi_free (a);
66e42d
      if (rc)
66e42d
        {
66e42d
          mpi_point_release (point);
66e42d
          return rc;
66e42d
        }
66e42d
    }
66e42d
  else
66e42d
    {
66e42d
      char *tmpname;
66e42d
      gcry_mpi_t x = NULL;
66e42d
      gcry_mpi_t y = NULL;
66e42d
      gcry_mpi_t z = NULL;
66e42d
66e42d
      tmpname = xtrymalloc (strlen (name) + 2 + 1);
66e42d
      if (!tmpname)
66e42d
        return gpg_err_code_from_syserror ();
66e42d
      strcpy (stpcpy (tmpname, name), ".x");
66e42d
      rc = mpi_from_keyparam (&x, keyparam, tmpname);
66e42d
      if (rc)
66e42d
        {
66e42d
          xfree (tmpname);
66e42d
          return rc;
66e42d
        }
66e42d
      strcpy (stpcpy (tmpname, name), ".y");
66e42d
      rc = mpi_from_keyparam (&y, keyparam, tmpname);
66e42d
      if (rc)
66e42d
        {
66e42d
          mpi_free (x);
66e42d
          xfree (tmpname);
66e42d
          return rc;
66e42d
        }
66e42d
      strcpy (stpcpy (tmpname, name), ".z");
66e42d
      rc = mpi_from_keyparam (&z, keyparam, tmpname);
66e42d
      if (rc)
66e42d
        {
66e42d
          mpi_free (y);
66e42d
          mpi_free (x);
66e42d
          xfree (tmpname);
66e42d
          return rc;
66e42d
        }
66e42d
      if (!z)
66e42d
        z = mpi_set_ui (NULL, 1);
66e42d
      if (x && y)
66e42d
        point = mpi_point_snatch_set (NULL, x, y, z);
66e42d
      else
66e42d
        {
66e42d
          mpi_free (x);
66e42d
          mpi_free (y);
66e42d
          mpi_free (z);
66e42d
          point = NULL;
66e42d
        }
66e42d
      xfree (tmpname);
66e42d
    }
66e42d
66e42d
  if (point)
66e42d
    *r_a = point;
66e42d
  return 0;
66e42d
}
66e42d
66e42d
66e42d
/* This function creates a new context for elliptic curve operations.
66e42d
   Either KEYPARAM or CURVENAME must be given.  If both are given and
66e42d
   KEYPARAM has no curve parameter, CURVENAME is used to add missing
66e42d
   parameters.  On success 0 is returned and the new context stored at
66e42d
   R_CTX.  On error NULL is stored at R_CTX and an error code is
66e42d
   returned.  The context needs to be released using
66e42d
   gcry_ctx_release.  */
66e42d
gpg_err_code_t
66e42d
_gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
66e42d
                  gcry_sexp_t keyparam, const char *curvename)
66e42d
{
66e42d
  gpg_err_code_t errc;
66e42d
  gcry_ctx_t ctx = NULL;
66e42d
  enum gcry_mpi_ec_models model = MPI_EC_WEIERSTRASS;
66e42d
  enum ecc_dialects dialect = ECC_DIALECT_STANDARD;
66e42d
  gcry_mpi_t p = NULL;
66e42d
  gcry_mpi_t a = NULL;
66e42d
  gcry_mpi_t b = NULL;
66e42d
  gcry_mpi_point_t G = NULL;
66e42d
  gcry_mpi_t n = NULL;
66e42d
  gcry_mpi_t h = NULL;
66e42d
  gcry_mpi_point_t Q = NULL;
66e42d
  gcry_mpi_t d = NULL;
66e42d
  int flags = 0;
66e42d
  gcry_sexp_t l1;
66e42d
66e42d
  *r_ctx = NULL;
66e42d
66e42d
  if (keyparam)
66e42d
    {
66e42d
      /* Parse an optional flags list.  */
66e42d
      l1 = sexp_find_token (keyparam, "flags", 0);
66e42d
      if (l1)
66e42d
        {
66e42d
          errc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
66e42d
          sexp_release (l1);
66e42d
          l1 = NULL;
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
        }
66e42d
66e42d
      /* Check whether a curve name was given.  */
66e42d
      l1 = sexp_find_token (keyparam, "curve", 5);
66e42d
66e42d
      /* If we don't have a curve name or if override parameters have
66e42d
         explicitly been requested, parse them.  */
66e42d
      if (!l1 || (flags & PUBKEY_FLAG_PARAM))
66e42d
        {
66e42d
          errc = mpi_from_keyparam (&p, keyparam, "p");
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
          errc = mpi_from_keyparam (&a, keyparam, "a");
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
          errc = mpi_from_keyparam (&b, keyparam, "b");
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
          errc = point_from_keyparam (&G, keyparam, "g", NULL);
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
          errc = mpi_from_keyparam (&n, keyparam, "n");
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
          errc = mpi_from_keyparam (&h, keyparam, "h");
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
        }
66e42d
    }
66e42d
  else
66e42d
    l1 = NULL; /* No curvename.  */
66e42d
66e42d
  /* Check whether a curve parameter is available and use that to fill
66e42d
     in missing values.  If no curve parameter is available try an
66e42d
     optional provided curvename.  If only the curvename has been
66e42d
     given use that one. */
66e42d
  if (l1 || curvename)
66e42d
    {
66e42d
      char *name;
66e42d
      elliptic_curve_t *E;
66e42d
66e42d
      if (l1)
66e42d
        {
66e42d
          name = sexp_nth_string (l1, 1);
66e42d
          sexp_release (l1);
66e42d
          if (!name)
66e42d
            {
66e42d
              errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
66e42d
              goto leave;
66e42d
            }
66e42d
        }
66e42d
      else
66e42d
        name = NULL;
66e42d
66e42d
      E = xtrycalloc (1, sizeof *E);
66e42d
      if (!E)
66e42d
        {
66e42d
          errc = gpg_err_code_from_syserror ();
66e42d
          xfree (name);
66e42d
          goto leave;
66e42d
        }
66e42d
66e42d
      errc = _gcry_ecc_fill_in_curve (0, name? name : curvename, E, NULL);
66e42d
      xfree (name);
66e42d
      if (errc)
66e42d
        {
66e42d
          xfree (E);
66e42d
          goto leave;
66e42d
        }
66e42d
66e42d
      model = E->model;
66e42d
      dialect = E->dialect;
66e42d
66e42d
      if (!p)
66e42d
        {
66e42d
          p = E->p;
66e42d
          E->p = NULL;
66e42d
        }
66e42d
      if (!a)
66e42d
        {
66e42d
          a = E->a;
66e42d
          E->a = NULL;
66e42d
        }
66e42d
      if (!b)
66e42d
        {
66e42d
          b = E->b;
66e42d
          E->b = NULL;
66e42d
        }
66e42d
      if (!G)
66e42d
        {
66e42d
          G = mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z);
66e42d
          E->G.x = NULL;
66e42d
          E->G.y = NULL;
66e42d
          E->G.z = NULL;
66e42d
        }
66e42d
      if (!n)
66e42d
        {
66e42d
          n = E->n;
66e42d
          E->n = NULL;
66e42d
        }
66e42d
      if (!h)
66e42d
        {
66e42d
          h = E->h;
66e42d
          E->h = NULL;
66e42d
        }
66e42d
      _gcry_ecc_curve_free (E);
66e42d
      xfree (E);
66e42d
    }
66e42d
66e42d
66e42d
  errc = _gcry_mpi_ec_p_new (&ctx, model, dialect, flags, p, a, b);
66e42d
  if (!errc)
66e42d
    {
66e42d
      mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
66e42d
66e42d
      if (b)
66e42d
        {
66e42d
          mpi_free (ec->b);
66e42d
          ec->b = b;
66e42d
          b = NULL;
66e42d
        }
66e42d
      if (G)
66e42d
        {
66e42d
          ec->G = G;
66e42d
          G = NULL;
66e42d
        }
66e42d
      if (n)
66e42d
        {
66e42d
          ec->n = n;
66e42d
          n = NULL;
66e42d
        }
66e42d
      if (h)
66e42d
        {
66e42d
          ec->h = h;
66e42d
          h = NULL;
66e42d
        }
66e42d
66e42d
      /* Now that we know the curve name we can look for the public key
66e42d
         Q.  point_from_keyparam needs to know the curve parameters so
66e42d
         that it is able to use the correct decompression.  Parsing
66e42d
         the private key D could have been done earlier but it is less
66e42d
         surprising if we do it here as well.  */
66e42d
      if (keyparam)
66e42d
        {
66e42d
          errc = point_from_keyparam (&Q, keyparam, "q", ec);
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
          errc = mpi_from_keyparam (&d, keyparam, "d");
66e42d
          if (errc)
66e42d
            goto leave;
66e42d
        }
66e42d
66e42d
      if (Q)
66e42d
        {
66e42d
          ec->Q = Q;
66e42d
          Q = NULL;
66e42d
        }
66e42d
      if (d)
66e42d
        {
66e42d
          ec->d = d;
66e42d
          d = NULL;
66e42d
        }
66e42d
66e42d
      *r_ctx = ctx;
66e42d
      ctx = NULL;
66e42d
    }
66e42d
66e42d
 leave:
66e42d
  _gcry_ctx_release (ctx);
66e42d
  mpi_free (p);
66e42d
  mpi_free (a);
66e42d
  mpi_free (b);
66e42d
  _gcry_mpi_point_release (G);
66e42d
  mpi_free (n);
66e42d
  mpi_free (h);
66e42d
  _gcry_mpi_point_release (Q);
66e42d
  mpi_free (d);
66e42d
  return errc;
66e42d
}
66e42d
66e42d
66e42d
/* Return the parameters of the curve NAME as an S-expression.  */
66e42d
gcry_sexp_t
66e42d
_gcry_ecc_get_param_sexp (const char *name)
66e42d
{
66e42d
  unsigned int nbits;
66e42d
  elliptic_curve_t E;
66e42d
  mpi_ec_t ctx;
66e42d
  gcry_mpi_t g_x, g_y;
66e42d
  gcry_mpi_t pkey[7];
66e42d
  gcry_sexp_t result;
66e42d
  int i;
66e42d
66e42d
  memset (&E, 0, sizeof E);
66e42d
  if (_gcry_ecc_fill_in_curve (0, name, &E, &nbits))
66e42d
    return NULL;
66e42d
66e42d
  g_x = mpi_new (0);
66e42d
  g_y = mpi_new (0);
66e42d
  ctx = _gcry_mpi_ec_p_internal_new (MPI_EC_WEIERSTRASS,
66e42d
                                     ECC_DIALECT_STANDARD,
66e42d
                                     0,
66e42d
                                     E.p, E.a, NULL);
66e42d
  if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
66e42d
    log_fatal ("ecc get param: Failed to get affine coordinates\n");
66e42d
  _gcry_mpi_ec_free (ctx);
66e42d
  _gcry_mpi_point_free_parts (&E.G);
66e42d
66e42d
  pkey[0] = E.p;
66e42d
  pkey[1] = E.a;
66e42d
  pkey[2] = E.b;
66e42d
  pkey[3] = _gcry_ecc_ec2os (g_x, g_y, E.p);
66e42d
  pkey[4] = E.n;
66e42d
  pkey[5] = E.h;
66e42d
  pkey[6] = NULL;
66e42d
66e42d
  mpi_free (g_x);
66e42d
  mpi_free (g_y);
66e42d
66e42d
  if (sexp_build (&result, NULL,
66e42d
                  "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)))",
66e42d
                  pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], pkey[5]))
66e42d
    result = NULL;
66e42d
66e42d
  for (i=0; pkey[i]; i++)
66e42d
    _gcry_mpi_release (pkey[i]);
66e42d
66e42d
  return result;
66e42d
}
66e42d
66e42d
66e42d
/* Return an MPI (or opaque MPI) described by NAME and the context EC.
66e42d
   If COPY is true a copy is returned, if not a const MPI may be
66e42d
   returned.  In any case mpi_free must be used.  */
66e42d
gcry_mpi_t
66e42d
_gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
66e42d
{
66e42d
  if (!*name)
66e42d
    return NULL;
66e42d
66e42d
  if (!strcmp (name, "p") && ec->p)
66e42d
    return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
66e42d
  if (!strcmp (name, "a") && ec->a)
66e42d
    return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a);
66e42d
  if (!strcmp (name, "b") && ec->b)
66e42d
    return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b);
66e42d
  if (!strcmp (name, "n") && ec->n)
66e42d
    return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n);
66e42d
  if (!strcmp (name, "h") && ec->h)
66e42d
    return mpi_is_const (ec->h) && !copy? ec->h : mpi_copy (ec->h);
66e42d
  if (!strcmp (name, "d") && ec->d)
66e42d
    return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d);
66e42d
66e42d
  /* Return a requested point coordinate.  */
66e42d
  if (!strcmp (name, "g.x") && ec->G && ec->G->x)
66e42d
    return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x);
66e42d
  if (!strcmp (name, "g.y") && ec->G && ec->G->y)
66e42d
    return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y);
66e42d
  if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
66e42d
    return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
66e42d
  if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
4bbd51
    return mpi_is_const (ec->Q->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
66e42d
66e42d
  /* If the base point has been requested, return it in standard
66e42d
     encoding.  */
66e42d
  if (!strcmp (name, "g") && ec->G)
66e42d
    return _gcry_mpi_ec_ec2os (ec->G, ec);
66e42d
66e42d
  /* If the public key has been requested, return it by default in
66e42d
     standard uncompressed encoding or if requested in other
66e42d
     encodings.  */
66e42d
  if (*name == 'q' && (!name[1] || name[1] == '@'))
66e42d
    {
66e42d
      /* If only the private key is given, compute the public key.  */
66e42d
      if (!ec->Q)
66e42d
        ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL);
66e42d
66e42d
      if (!ec->Q)
66e42d
        return NULL;
66e42d
66e42d
      if (name[1] != '@')
66e42d
        return _gcry_mpi_ec_ec2os (ec->Q, ec);
66e42d
66e42d
      if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_EDWARDS)
66e42d
        {
66e42d
          unsigned char *encpk;
66e42d
          unsigned int encpklen;
66e42d
66e42d
          if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0,
66e42d
                                            &encpk, &encpklen))
66e42d
            return mpi_set_opaque (NULL, encpk, encpklen*8);
66e42d
        }
66e42d
    }
66e42d
66e42d
  return NULL;
66e42d
}
66e42d
66e42d
66e42d
/* Return a point described by NAME and the context EC.  */
66e42d
gcry_mpi_point_t
66e42d
_gcry_ecc_get_point (const char *name, mpi_ec_t ec)
66e42d
{
66e42d
  if (!strcmp (name, "g") && ec->G)
66e42d
    return point_copy (ec->G);
66e42d
  if (!strcmp (name, "q"))
66e42d
    {
66e42d
      /* If only the private key is given, compute the public key.  */
66e42d
      if (!ec->Q)
66e42d
        ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL);
66e42d
66e42d
      if (ec->Q)
66e42d
        return point_copy (ec->Q);
66e42d
    }
66e42d
66e42d
  return NULL;
66e42d
}
66e42d
66e42d
66e42d
/* Store the MPI NEWVALUE into the context EC under NAME. */
66e42d
gpg_err_code_t
66e42d
_gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
66e42d
{
66e42d
  gpg_err_code_t rc = 0;
66e42d
66e42d
  if (!*name)
66e42d
    ;
66e42d
  else if (!strcmp (name, "p"))
66e42d
    {
66e42d
      mpi_free (ec->p);
66e42d
      ec->p = mpi_copy (newvalue);
66e42d
      _gcry_mpi_ec_get_reset (ec);
66e42d
    }
66e42d
  else if (!strcmp (name, "a"))
66e42d
    {
66e42d
      mpi_free (ec->a);
66e42d
      ec->a = mpi_copy (newvalue);
66e42d
      _gcry_mpi_ec_get_reset (ec);
66e42d
    }
66e42d
  else if (!strcmp (name, "b"))
66e42d
    {
66e42d
      mpi_free (ec->b);
66e42d
      ec->b = mpi_copy (newvalue);
66e42d
    }
66e42d
  else if (!strcmp (name, "n"))
66e42d
    {
66e42d
      mpi_free (ec->n);
66e42d
      ec->n = mpi_copy (newvalue);
66e42d
    }
66e42d
  else if (!strcmp (name, "h"))
66e42d
    {
66e42d
      mpi_free (ec->h);
66e42d
      ec->h = mpi_copy (newvalue);
66e42d
    }
66e42d
  else if (*name == 'q' && (!name[1] || name[1] == '@'))
66e42d
    {
66e42d
      if (newvalue)
66e42d
        {
66e42d
          if (!ec->Q)
66e42d
            ec->Q = mpi_point_new (0);
66e42d
          if (ec->dialect == ECC_DIALECT_ED25519)
66e42d
            rc = _gcry_ecc_eddsa_decodepoint (newvalue, ec, ec->Q, NULL, NULL);
66e42d
          else
66e42d
            rc = _gcry_ecc_os2ec (ec->Q, newvalue);
66e42d
        }
66e42d
      if (rc || !newvalue)
66e42d
        {
66e42d
          _gcry_mpi_point_release (ec->Q);
66e42d
          ec->Q = NULL;
66e42d
        }
66e42d
      /* Note: We assume that Q matches d and thus do not reset d.  */
66e42d
    }
66e42d
  else if (!strcmp (name, "d"))
66e42d
    {
66e42d
      mpi_free (ec->d);
66e42d
      ec->d = mpi_copy (newvalue);
66e42d
      if (ec->d)
66e42d
        {
66e42d
          /* We need to reset the public key because it may not
66e42d
             anymore match.  */
66e42d
          _gcry_mpi_point_release (ec->Q);
66e42d
          ec->Q = NULL;
66e42d
        }
66e42d
    }
66e42d
  else
66e42d
   rc = GPG_ERR_UNKNOWN_NAME;
66e42d
66e42d
  return rc;
66e42d
}
66e42d
66e42d
66e42d
/* Store the point NEWVALUE into the context EC under NAME.  */
66e42d
gpg_err_code_t
66e42d
_gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec)
66e42d
{
66e42d
  if (!strcmp (name, "g"))
66e42d
    {
66e42d
      _gcry_mpi_point_release (ec->G);
66e42d
      ec->G = point_copy (newvalue);
66e42d
    }
66e42d
  else if (!strcmp (name, "q"))
66e42d
    {
66e42d
      _gcry_mpi_point_release (ec->Q);
66e42d
      ec->Q = point_copy (newvalue);
66e42d
    }
66e42d
  else
66e42d
    return GPG_ERR_UNKNOWN_NAME;
66e42d
66e42d
  return 0;
66e42d
}