Blame SOURCES/ecc-curves.c

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