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