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