Blame SOURCES/ecc-curves.c

e09bf5
/* ecc-curves.c  -  Elliptic Curve parameter mangement
e09bf5
 * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
e09bf5
 * Copyright (C) 2013 g10 Code GmbH
e09bf5
 *
e09bf5
 * This file is part of Libgcrypt.
e09bf5
 *
e09bf5
 * Libgcrypt is free software; you can redistribute it and/or modify
e09bf5
 * it under the terms of the GNU Lesser General Public License as
e09bf5
 * published by the Free Software Foundation; either version 2.1 of
e09bf5
 * the License, or (at your option) any later version.
e09bf5
 *
e09bf5
 * Libgcrypt is distributed in the hope that it will be useful,
e09bf5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
e09bf5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
e09bf5
 * GNU Lesser General Public License for more details.
e09bf5
 *
e09bf5
 * You should have received a copy of the GNU Lesser General Public
e09bf5
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
e09bf5
 */
e09bf5
e09bf5
#include <config.h>
e09bf5
#include <stdio.h>
e09bf5
#include <stdlib.h>
e09bf5
#include <string.h>
e09bf5
#include <errno.h>
e09bf5
e09bf5
#include "g10lib.h"
e09bf5
#include "mpi.h"
e09bf5
#include "mpi-internal.h"
e09bf5
#include "cipher.h"
e09bf5
#include "context.h"
e09bf5
#include "ec-context.h"
e09bf5
#include "pubkey-internal.h"
e09bf5
#include "ecc-common.h"
e09bf5
e09bf5
e09bf5
static gpg_err_code_t
e09bf5
point_from_keyparam (gcry_mpi_point_t *r_a,
e09bf5
                     gcry_sexp_t keyparam, const char *name, mpi_ec_t ec);
e09bf5
e09bf5
/* This tables defines aliases for curve names.  */
e09bf5
static const struct
e09bf5
{
e09bf5
  const char *name;  /* Our name.  */
e09bf5
  const char *other; /* Other name. */
e09bf5
} curve_aliases[] =
e09bf5
  {
e09bf5
    { "Ed25519",    "1.3.6.1.4.1.11591.15.1" }, /* OpenPGP */
e09bf5
    { "Ed25519",    "1.3.101.112" },         /* rfc8410 */
e09bf5
e09bf5
    { "Curve25519", "1.3.6.1.4.1.3029.1.5.1" }, /* OpenPGP */
e09bf5
    { "Curve25519", "1.3.101.110" },         /* rfc8410 */
e09bf5
    { "Curve25519", "X25519" },              /* rfc8410 */
e09bf5
e09bf5
    { "Ed448",      "1.3.101.113" },         /* rfc8410 */
e09bf5
    { "X448",       "1.3.101.111" },         /* rfc8410 */
e09bf5
e09bf5
    { "NIST P-224", "secp224r1" },
e09bf5
    { "NIST P-224", "1.3.132.0.33" },        /* SECP OID.  */
e09bf5
    { "NIST P-224", "nistp224"   },          /* rfc5656.  */
e09bf5
e09bf5
    { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1.  */
e09bf5
    { "NIST P-256", "prime256v1" },
e09bf5
    { "NIST P-256", "secp256r1"  },
e09bf5
    { "NIST P-256", "nistp256"   },          /* rfc5656.  */
e09bf5
e09bf5
    { "NIST P-384", "secp384r1" },
e09bf5
    { "NIST P-384", "1.3.132.0.34" },
e09bf5
    { "NIST P-384", "nistp384"   },          /* rfc5656.  */
e09bf5
e09bf5
    { "NIST P-521", "secp521r1" },
e09bf5
    { "NIST P-521", "1.3.132.0.35" },
e09bf5
    { "NIST P-521", "nistp521"   },          /* rfc5656.  */
e09bf5
e09bf5
    { "GOST2001-test", "1.2.643.2.2.35.0" },
e09bf5
    { "GOST2001-CryptoPro-A", "1.2.643.2.2.35.1" },
e09bf5
    { "GOST2001-CryptoPro-B", "1.2.643.2.2.35.2" },
e09bf5
    { "GOST2001-CryptoPro-C", "1.2.643.2.2.35.3" },
e09bf5
    { "GOST2001-CryptoPro-A", "GOST2001-CryptoPro-XchA" },
e09bf5
    { "GOST2001-CryptoPro-C", "GOST2001-CryptoPro-XchB" },
e09bf5
    { "GOST2001-CryptoPro-A", "1.2.643.2.2.36.0" },
e09bf5
    { "GOST2001-CryptoPro-C", "1.2.643.2.2.36.1" },
e09bf5
e09bf5
    { "GOST2012-256-tc26-A", "1.2.643.7.1.2.1.1.1" },
e09bf5
    { "GOST2001-CryptoPro-A", "1.2.643.7.1.2.1.1.2" },
e09bf5
    { "GOST2001-CryptoPro-A", "GOST2012-256-tc26-B" },
e09bf5
    { "GOST2001-CryptoPro-B", "1.2.643.7.1.2.1.1.3" },
e09bf5
    { "GOST2001-CryptoPro-B", "GOST2012-256-tc26-C" },
e09bf5
    { "GOST2001-CryptoPro-C", "1.2.643.7.1.2.1.1.4" },
e09bf5
    { "GOST2001-CryptoPro-C", "GOST2012-256-tc26-D" },
e09bf5
e09bf5
    { "GOST2012-512-test", "GOST2012-test" },
e09bf5
    { "GOST2012-512-test", "1.2.643.7.1.2.1.2.0" },
e09bf5
    { "GOST2012-512-tc26-A", "GOST2012-tc26-A" },
e09bf5
    { "GOST2012-512-tc26-B", "GOST2012-tc26-B" },
e09bf5
    { "GOST2012-512-tc26-A", "1.2.643.7.1.2.1.2.1" },
e09bf5
    { "GOST2012-512-tc26-B", "1.2.643.7.1.2.1.2.2" },
e09bf5
    { "GOST2012-512-tc26-C", "1.2.643.7.1.2.1.2.3" },
e09bf5
e09bf5
    { "secp256k1", "1.3.132.0.10" },
e09bf5
e09bf5
    { "sm2p256v1", "1.2.156.10197.1.301" },
e09bf5
e09bf5
    { NULL, NULL}
e09bf5
  };
e09bf5
e09bf5
e09bf5
typedef struct
e09bf5
{
e09bf5
  const char *desc;           /* Description of the curve.  */
e09bf5
  unsigned int nbits;         /* Number of bits.  */
e09bf5
  unsigned int fips:1;        /* True if this is a FIPS140-2 approved curve. */
e09bf5
e09bf5
  /* The model describing this curve.  This is mainly used to select
e09bf5
     the group equation. */
e09bf5
  enum gcry_mpi_ec_models model;
e09bf5
e09bf5
  /* The actual ECC dialect used.  This is used for curve specific
e09bf5
     optimizations and to select encodings etc. */
e09bf5
  enum ecc_dialects dialect;
e09bf5
e09bf5
  const char *p;              /* The prime defining the field.  */
e09bf5
  const char *a, *b;          /* The coefficients.  For Twisted Edwards
e09bf5
                                 Curves b is used for d.  For Montgomery
e09bf5
                                 Curves (a,b) has ((A-2)/4,B^-1).  */
e09bf5
  const char *n;              /* The order of the base point.  */
e09bf5
  const char *g_x, *g_y;      /* Base point.  */
e09bf5
  unsigned int h;             /* Cofactor.  */
e09bf5
} ecc_domain_parms_t;
e09bf5
e09bf5
e09bf5
/* This static table defines all available curves.  */
e09bf5
static const ecc_domain_parms_t domain_parms[] =
e09bf5
  {
e09bf5
    {
e09bf5
      /* (-x^2 + y^2 = 1 + dx^2y^2) */
e09bf5
      "Ed25519", 255, 0,
e09bf5
      MPI_EC_EDWARDS, ECC_DIALECT_ED25519,
e09bf5
      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
e09bf5
      "-0x01",
e09bf5
      "-0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A",
e09bf5
      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
e09bf5
      "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
e09bf5
      "0x6666666666666666666666666666666666666666666666666666666666666658",
e09bf5
      8
e09bf5
    },
e09bf5
    {
e09bf5
      /* (y^2 = x^3 + 486662*x^2 + x) */
e09bf5
      "Curve25519", 255, 0,
e09bf5
      MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD,
e09bf5
      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
e09bf5
      "0x01DB41",
e09bf5
      "0x01",
e09bf5
      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000009",
e09bf5
      "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9",
e09bf5
      8
e09bf5
      /* Note: As per RFC-7748 errata eid4730 the g_y value should be
e09bf5
       * "0x5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14"
e09bf5
       * but that breaks the keygrip.  The new value is recovered in
e09bf5
       * the function _gcry_ecc_fill_in_curve.  See bug #4712.
e09bf5
       */
e09bf5
    },
e09bf5
    {
e09bf5
      /* (x^2 + y^2 = 1 + dx^2y^2) */
e09bf5
      "Ed448", 448, 0,
e09bf5
      MPI_EC_EDWARDS, ECC_DIALECT_SAFECURVE,
e09bf5
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
e09bf5
      "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
e09bf5
      "0x01",
e09bf5
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
e09bf5
      "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6756",
e09bf5
      "0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
e09bf5
      "7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3",
e09bf5
      "0x4F1970C66BED0DED221D15A622BF36DA9E146570470F1767EA6DE324"
e09bf5
      "A3D3A46412AE1AF72AB66511433B80E18B00938E2626A82BC70CC05E",
e09bf5
      "0x693F46716EB6BC248876203756C9C7624BEA73736CA3984087789C1E"
e09bf5
      "05A0C2D73AD3FF1CE67C39C4FDBD132C4ED7C8AD9808795BF230FA14",
e09bf5
      4,
e09bf5
    },
e09bf5
    {
e09bf5
      /* (y^2 = x^3 + 156326*x^2 + x) */
e09bf5
      "X448", 448, 0,
e09bf5
      MPI_EC_MONTGOMERY, ECC_DIALECT_SAFECURVE,
e09bf5
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
e09bf5
      "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
e09bf5
      "0x98A9",
e09bf5
      "0x01",
e09bf5
      "0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
e09bf5
      "7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3",
e09bf5
      "0x00000000000000000000000000000000000000000000000000000000"
e09bf5
      "00000000000000000000000000000000000000000000000000000005",
e09bf5
      "0x7D235D1295F5B1F66C98AB6E58326FCECBAE5D34F55545D060F75DC2"
e09bf5
      "8DF3F6EDB8027E2346430D211312C4B150677AF76FD7223D457B5B1A",
e09bf5
      4,
e09bf5
    },
e09bf5
    {
e09bf5
      "NIST P-224", 224, 1,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xffffffffffffffffffffffffffffffff000000000000000000000001",
e09bf5
      "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
e09bf5
      "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
e09bf5
      "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
e09bf5
e09bf5
      "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
e09bf5
      "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "NIST P-256", 256, 1,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
e09bf5
      "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
e09bf5
      "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
e09bf5
      "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
e09bf5
e09bf5
      "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
e09bf5
      "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "NIST P-384", 384, 1,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
e09bf5
      "ffffffff0000000000000000ffffffff",
e09bf5
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
e09bf5
      "ffffffff0000000000000000fffffffc",
e09bf5
      "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
e09bf5
      "c656398d8a2ed19d2a85c8edd3ec2aef",
e09bf5
      "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
e09bf5
      "581a0db248b0a77aecec196accc52973",
e09bf5
e09bf5
      "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
e09bf5
      "5502f25dbf55296c3a545e3872760ab7",
e09bf5
      "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
e09bf5
      "0a60b1ce1d7e819d7a431d7c90ea0e5f",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "NIST P-521", 521, 1,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
e09bf5
      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
e09bf5
      "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
e09bf5
      "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
e09bf5
      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
      "fffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
e09bf5
e09bf5
      "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d"
e09bf5
      "3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
e09bf5
      "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e"
e09bf5
      "662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
e09bf5
      1
e09bf5
    },
e09bf5
e09bf5
    {
e09bf5
      "GOST2001-test", 256, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0x8000000000000000000000000000000000000000000000000000000000000431",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000007",
e09bf5
      "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e",
e09bf5
      "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3",
e09bf5
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000002",
e09bf5
      "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2001-CryptoPro-A", 256, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97",
e09bf5
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd94",
e09bf5
      "0x00000000000000000000000000000000000000000000000000000000000000a6",
e09bf5
      "0xffffffffffffffffffffffffffffffff6c611070995ad10045841b09b761b893",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000001",
e09bf5
      "0x8d91e471e0989cda27df505a453f2b7635294f2ddf23e3b122acc99c9e9f1e14",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2001-CryptoPro-B", 256, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0x8000000000000000000000000000000000000000000000000000000000000c99",
e09bf5
      "0x8000000000000000000000000000000000000000000000000000000000000c96",
e09bf5
      "0x3e1af419a269a5f866a7d3c25c3df80ae979259373ff2b182f49d4ce7e1bbc8b",
e09bf5
      "0x800000000000000000000000000000015f700cfff1a624e5e497161bcc8a198f",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000001",
e09bf5
      "0x3fa8124359f96680b83d1c3eb2c070e5c545c9858d03ecfb744bf8d717717efc",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2001-CryptoPro-C", 256, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b",
e09bf5
      "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598",
e09bf5
      "0x000000000000000000000000000000000000000000000000000000000000805a",
e09bf5
      "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000000",
e09bf5
      "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2012-256-A", 256, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97",
e09bf5
      "0xc2173f1513981673af4892c23035a27ce25e2013bf95aa33b22c656f277e7335",
e09bf5
      "0x295f9bae7428ed9ccc20e7c359a9d41a22fccd9108e17bf7ba9337a6f8ae9513",
e09bf5
      "0x400000000000000000000000000000000fd8cddfc87b6635c115af556c360c67",
e09bf5
      "0x91e38443a5e82c0d880923425712b2bb658b9196932e02c78b2582fe742daa28",
e09bf5
      "0x32879423ab1a0375895786c4bb46e9565fde0b5344766740af268adb32322e5c",
e09bf5
      4
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2012-512-test", 511, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d"
e09bf5
      "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000007",
e09bf5
      "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4"
e09bf5
      "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc",
e09bf5
      "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d"
e09bf5
      "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df",
e09bf5
e09bf5
      "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762"
e09bf5
      "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a",
e09bf5
      "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2"
e09bf5
      "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2012-512-tc26-A", 512, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7",
e09bf5
      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc4",
e09bf5
      "0xe8c2505dedfc86ddc1bd0b2b6667f1da34b82574761cb0e879bd081cfd0b6265"
e09bf5
        "ee3cb090f30d27614cb4574010da90dd862ef9d4ebee4761503190785a71c760",
e09bf5
      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
        "27e69532f48d89116ff22b8d4e0560609b4b38abfad2b85dcacdb1411f10b275",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000000"
e09bf5
        "0000000000000000000000000000000000000000000000000000000000000003",
e09bf5
      "0x7503cfe87a836ae3a61b8816e25450e6ce5e1c93acf1abc1778064fdcbefa921"
e09bf5
        "df1626be4fd036e93d75e6a50e3a41e98028fe5fc235f5b889a589cb5215f2a4",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2012-512-tc26-B", 512, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0x8000000000000000000000000000000000000000000000000000000000000000"
e09bf5
        "000000000000000000000000000000000000000000000000000000000000006f",
e09bf5
      "0x8000000000000000000000000000000000000000000000000000000000000000"
e09bf5
        "000000000000000000000000000000000000000000000000000000000000006c",
e09bf5
      "0x687d1b459dc841457e3e06cf6f5e2517b97c7d614af138bcbf85dc806c4b289f"
e09bf5
        "3e965d2db1416d217f8b276fad1ab69c50f78bee1fa3106efb8ccbc7c5140116",
e09bf5
      "0x8000000000000000000000000000000000000000000000000000000000000001"
e09bf5
        "49a1ec142565a545acfdb77bd9d40cfa8b996712101bea0ec6346c54374f25bd",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000000"
e09bf5
        "0000000000000000000000000000000000000000000000000000000000000002",
e09bf5
      "0x1a8f7eda389b094c2c071e3647a8940f3c123b697578c213be6dd9e6c8ec7335"
e09bf5
        "dcb228fd1edf4a39152cbcaaf8c0398828041055f94ceeec7e21340780fe41bd",
e09bf5
      1
e09bf5
    },
e09bf5
    {
e09bf5
      "GOST2012-512-tc26-C", 512, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7",
e09bf5
      "0xdc9203e514a721875485a529d2c722fb187bc8980eb866644de41c68e1430645"
e09bf5
        "46e861c0e2c9edd92ade71f46fcf50ff2ad97f951fda9f2a2eb6546f39689bd3",
e09bf5
      "0xb4c4ee28cebc6c2c8ac12952cf37f16ac7efb6a9f69f4b57ffda2e4f0de5ade0"
e09bf5
        "38cbc2fff719d2c18de0284b8bfef3b52b8cc7a5f5bf0a3c8d2319a5312557e1",
e09bf5
      "0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
e09bf5
        "c98cdba46506ab004c33a9ff5147502cc8eda9e7a769a12694623cef47f023ed",
e09bf5
      "0xe2e31edfc23de7bdebe241ce593ef5de2295b7a9cbaef021d385f7074cea043a"
e09bf5
        "a27272a7ae602bf2a7b9033db9ed3610c6fb85487eae97aac5bc7928c1950148",
e09bf5
      "0xf5ce40d95b5eb899abbccff5911cb8577939804d6527378b8c108c3d2090ff9be"
e09bf5
        "18e2d33e3021ed2ef32d85822423b6304f726aa854bae07d0396e9a9addc40f",
e09bf5
      4
e09bf5
    },
e09bf5
e09bf5
    {
e09bf5
      "secp256k1", 256, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000000",
e09bf5
      "0x0000000000000000000000000000000000000000000000000000000000000007",
e09bf5
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
e09bf5
      "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
e09bf5
      "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
e09bf5
      1
e09bf5
    },
e09bf5
e09bf5
    {
e09bf5
      "sm2p256v1", 256, 0,
e09bf5
      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
e09bf5
      "0xfffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",
e09bf5
      "0xfffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",
e09bf5
      "0x28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",
e09bf5
      "0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",
e09bf5
      "0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",
e09bf5
      "0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",
e09bf5
      1
e09bf5
    },
e09bf5
e09bf5
    { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
e09bf5
  };
e09bf5
e09bf5
e09bf5
e09bf5

e09bf5
/* Return a copy of POINT.  */
e09bf5
static gcry_mpi_point_t
e09bf5
point_copy (gcry_mpi_point_t point)
e09bf5
{
e09bf5
  gcry_mpi_point_t newpoint;
e09bf5
e09bf5
  if (point)
e09bf5
    {
e09bf5
      newpoint = mpi_point_new (0);
e09bf5
      point_set (newpoint, point);
e09bf5
    }
e09bf5
  else
e09bf5
    newpoint = NULL;
e09bf5
  return newpoint;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Helper to scan a hex string. */
e09bf5
static gcry_mpi_t
e09bf5
scanval (const char *string)
e09bf5
{
e09bf5
  gpg_err_code_t rc;
e09bf5
  gcry_mpi_t val;
e09bf5
e09bf5
  rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
e09bf5
  if (rc)
e09bf5
    log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc));
e09bf5
  return val;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Return the index of the domain_parms table for a curve with NAME.
e09bf5
   Return -1 if not found.  */
e09bf5
static int
e09bf5
find_domain_parms_idx (const char *name)
e09bf5
{
e09bf5
  int idx, aliasno;
e09bf5
e09bf5
  /* First check our native curves.  */
e09bf5
  for (idx = 0; domain_parms[idx].desc; idx++)
e09bf5
    if (!strcmp (name, domain_parms[idx].desc))
e09bf5
      return idx;
e09bf5
e09bf5
  /* If not found consult the alias table.  */
e09bf5
  if (!domain_parms[idx].desc)
e09bf5
    {
e09bf5
      for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
e09bf5
        if (!strcmp (name, curve_aliases[aliasno].other))
e09bf5
          break;
e09bf5
      if (curve_aliases[aliasno].name)
e09bf5
        {
e09bf5
          for (idx = 0; domain_parms[idx].desc; idx++)
e09bf5
            if (!strcmp (curve_aliases[aliasno].name, domain_parms[idx].desc))
e09bf5
              return idx;
e09bf5
        }
e09bf5
    }
e09bf5
e09bf5
  return -1;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Generate the crypto system setup.  This function takes the NAME of
e09bf5
   a curve or the desired number of bits and stores at R_CURVE the
e09bf5
   parameters of the named curve or those of a suitable curve.  If
e09bf5
   R_NBITS is not NULL, the chosen number of bits is stored there.
e09bf5
   NULL may be given for R_CURVE, if the value is not required and for
e09bf5
   example only a quick test for availability is desired.  Note that
e09bf5
   the curve fields should be initialized to zero because fields which
e09bf5
   are not NULL are skipped.  */
e09bf5
gpg_err_code_t
e09bf5
_gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
e09bf5
                         elliptic_curve_t *curve, unsigned int *r_nbits)
e09bf5
{
e09bf5
  int idx;
e09bf5
  const char *resname = NULL; /* Set to a found curve name.  */
e09bf5
e09bf5
  if (name)
e09bf5
    idx = find_domain_parms_idx (name);
e09bf5
  else
e09bf5
    {
e09bf5
      for (idx = 0; domain_parms[idx].desc; idx++)
e09bf5
        if (nbits == domain_parms[idx].nbits
e09bf5
            && domain_parms[idx].model == MPI_EC_WEIERSTRASS)
e09bf5
          break;
e09bf5
      if (!domain_parms[idx].desc)
e09bf5
        idx = -1;
e09bf5
    }
e09bf5
  if (idx < 0)
e09bf5
    return GPG_ERR_UNKNOWN_CURVE;
e09bf5
e09bf5
  resname = domain_parms[idx].desc;
e09bf5
e09bf5
  /* In fips mode we only support NIST curves.  Note that it is
e09bf5
     possible to bypass this check by specifying the curve parameters
e09bf5
     directly.  */
e09bf5
  if (fips_mode () && !domain_parms[idx].fips )
e09bf5
    return GPG_ERR_NOT_SUPPORTED;
e09bf5
e09bf5
  switch (domain_parms[idx].model)
e09bf5
    {
e09bf5
    case MPI_EC_WEIERSTRASS:
e09bf5
    case MPI_EC_EDWARDS:
e09bf5
    case MPI_EC_MONTGOMERY:
e09bf5
      break;
e09bf5
    default:
e09bf5
      return GPG_ERR_BUG;
e09bf5
    }
e09bf5
e09bf5
e09bf5
  if (r_nbits)
e09bf5
    *r_nbits = domain_parms[idx].nbits;
e09bf5
e09bf5
  if (curve)
e09bf5
    {
e09bf5
      curve->model = domain_parms[idx].model;
e09bf5
      curve->dialect = domain_parms[idx].dialect;
e09bf5
      if (!curve->p)
e09bf5
        curve->p = scanval (domain_parms[idx].p);
e09bf5
      if (!curve->a)
e09bf5
        {
e09bf5
          curve->a = scanval (domain_parms[idx].a);
e09bf5
          if (curve->a->sign)
e09bf5
            {
e09bf5
              mpi_resize (curve->a, curve->p->nlimbs);
e09bf5
              _gcry_mpih_sub_n (curve->a->d, curve->p->d,
e09bf5
                                curve->a->d, curve->p->nlimbs);
e09bf5
              curve->a->nlimbs = curve->p->nlimbs;
e09bf5
              curve->a->sign = 0;
e09bf5
            }
e09bf5
        }
e09bf5
      if (!curve->b)
e09bf5
        {
e09bf5
          curve->b = scanval (domain_parms[idx].b);
e09bf5
          if (curve->b->sign)
e09bf5
            {
e09bf5
              mpi_resize (curve->b, curve->p->nlimbs);
e09bf5
              _gcry_mpih_sub_n (curve->b->d, curve->p->d,
e09bf5
                                curve->b->d, curve->p->nlimbs);
e09bf5
              curve->b->nlimbs = curve->p->nlimbs;
e09bf5
              curve->b->sign = 0;
e09bf5
            }
e09bf5
        }
e09bf5
      if (!curve->n)
e09bf5
        curve->n = scanval (domain_parms[idx].n);
e09bf5
      if (!curve->G.x)
e09bf5
        curve->G.x = scanval (domain_parms[idx].g_x);
e09bf5
      if (!curve->G.y)
e09bf5
        curve->G.y = scanval (domain_parms[idx].g_y);
e09bf5
      curve->h = domain_parms[idx].h;
e09bf5
e09bf5
      /*
e09bf5
       * In the constants of domain_parms, we defined Curve25519
e09bf5
       * domain parameters as the ones in RFC-7748 before the errata
e09bf5
       * (eid4730).  To keep the computation having exact same values,
e09bf5
       * we recover the new value of g_y, here.
e09bf5
       */
e09bf5
      if (!strcmp (resname, "Curve25519"))
e09bf5
        mpi_sub (curve->G.y, curve->p, curve->G.y);
e09bf5
e09bf5
      if (!curve->G.z)
e09bf5
        curve->G.z = mpi_alloc_set_ui (1);
e09bf5
      if (!curve->name)
e09bf5
        curve->name = resname;
e09bf5
    }
e09bf5
e09bf5
  return 0;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Give the name of the curve NAME, store the curve parameters into P,
e09bf5
   A, B, G, and N if they point to NULL value.  Note that G is
e09bf5
   returned in standard uncompressed format.  Also update MODEL and
e09bf5
   DIALECT if they are not NULL. */
e09bf5
gpg_err_code_t
e09bf5
_gcry_ecc_update_curve_param (const char *name,
e09bf5
                              enum gcry_mpi_ec_models *model,
e09bf5
                              enum ecc_dialects *dialect,
e09bf5
                              gcry_mpi_t *p, gcry_mpi_t *a, gcry_mpi_t *b,
e09bf5
                              gcry_mpi_t *g, gcry_mpi_t *n)
e09bf5
{
e09bf5
  int idx;
e09bf5
e09bf5
  idx = find_domain_parms_idx (name);
e09bf5
  if (idx < 0)
e09bf5
    return GPG_ERR_UNKNOWN_CURVE;
e09bf5
e09bf5
  if (g)
e09bf5
    {
e09bf5
      char *buf;
e09bf5
      size_t len;
e09bf5
e09bf5
      len = 4;
e09bf5
      len += strlen (domain_parms[idx].g_x+2);
e09bf5
      len += strlen (domain_parms[idx].g_y+2);
e09bf5
      len++;
e09bf5
      buf = xtrymalloc (len);
e09bf5
      if (!buf)
e09bf5
        return gpg_err_code_from_syserror ();
e09bf5
      strcpy (stpcpy (stpcpy (buf, "0x04"), domain_parms[idx].g_x+2),
e09bf5
              domain_parms[idx].g_y+2);
e09bf5
      _gcry_mpi_release (*g);
e09bf5
      *g = scanval (buf);
e09bf5
      xfree (buf);
e09bf5
    }
e09bf5
  if (model)
e09bf5
    *model = domain_parms[idx].model;
e09bf5
  if (dialect)
e09bf5
    *dialect = domain_parms[idx].dialect;
e09bf5
  if (p)
e09bf5
    {
e09bf5
      _gcry_mpi_release (*p);
e09bf5
      *p = scanval (domain_parms[idx].p);
e09bf5
    }
e09bf5
  if (a)
e09bf5
    {
e09bf5
      _gcry_mpi_release (*a);
e09bf5
      *a = scanval (domain_parms[idx].a);
e09bf5
    }
e09bf5
  if (b)
e09bf5
    {
e09bf5
      _gcry_mpi_release (*b);
e09bf5
      *b = scanval (domain_parms[idx].b);
e09bf5
    }
e09bf5
  if (n)
e09bf5
    {
e09bf5
      _gcry_mpi_release (*n);
e09bf5
      *n = scanval (domain_parms[idx].n);
e09bf5
    }
e09bf5
  return 0;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Return the name matching the parameters in PKEY.  This works only
e09bf5
   with curves described by the Weierstrass equation. */
e09bf5
const char *
e09bf5
_gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits)
e09bf5
{
e09bf5
  gpg_err_code_t rc;
e09bf5
  const char *result = NULL;
e09bf5
  elliptic_curve_t E;
e09bf5
  gcry_mpi_point_t G = NULL;
e09bf5
  gcry_mpi_t tmp = NULL;
e09bf5
  int idx;
e09bf5
e09bf5
  memset (&E, 0, sizeof E);
e09bf5
e09bf5
  if (r_nbits)
e09bf5
    *r_nbits = 0;
e09bf5
e09bf5
  if (!keyparms)
e09bf5
    {
e09bf5
      idx = iterator;
e09bf5
      if (idx >= 0 && idx < DIM (domain_parms))
e09bf5
        {
e09bf5
          result = domain_parms[idx].desc;
e09bf5
          if (r_nbits)
e09bf5
            *r_nbits = domain_parms[idx].nbits;
e09bf5
        }
e09bf5
      return result;
e09bf5
    }
e09bf5
e09bf5
e09bf5
  /*
e09bf5
   * Extract the curve parameters..
e09bf5
   */
e09bf5
  rc = gpg_err_code (sexp_extract_param (keyparms, NULL, "pabn",
e09bf5
                                         &E.p, &E.a, &E.b, &E.n, NULL));
e09bf5
  if (rc == GPG_ERR_NO_OBJ)
e09bf5
    {
e09bf5
      /* This might be the second use case of checking whether a
e09bf5
         specific curve given by name is supported.  */
e09bf5
      gcry_sexp_t l1;
e09bf5
      char *name;
e09bf5
e09bf5
      l1 = sexp_find_token (keyparms, "curve", 5);
e09bf5
      if (!l1)
e09bf5
        goto leave;  /* No curve name parameter.  */
e09bf5
e09bf5
      name = sexp_nth_string (l1, 1);
e09bf5
      sexp_release (l1);
e09bf5
      if (!name)
e09bf5
        goto leave;  /* Name missing or out of core. */
e09bf5
e09bf5
      idx = find_domain_parms_idx (name);
e09bf5
      xfree (name);
e09bf5
      if (idx >= 0)  /* Curve found.  */
e09bf5
        {
e09bf5
          result = domain_parms[idx].desc;
e09bf5
          if (r_nbits)
e09bf5
            *r_nbits = domain_parms[idx].nbits;
e09bf5
        }
e09bf5
      return result;
e09bf5
    }
e09bf5
e09bf5
  if (rc)
e09bf5
    goto leave;
e09bf5
e09bf5
  rc = point_from_keyparam (&G, keyparms, "g", NULL);
e09bf5
  if (rc)
e09bf5
    goto leave;
e09bf5
e09bf5
  _gcry_mpi_point_init (&E.G);
e09bf5
  _gcry_mpi_point_set (&E.G, G->x, G->y, G->z);
e09bf5
e09bf5
  for (idx = 0; domain_parms[idx].desc; idx++)
e09bf5
    {
e09bf5
      mpi_free (tmp);
e09bf5
      tmp = scanval (domain_parms[idx].p);
e09bf5
      if (mpi_cmp (tmp, E.p))
e09bf5
        continue;
e09bf5
e09bf5
      mpi_free (tmp);
e09bf5
      tmp = scanval (domain_parms[idx].a);
e09bf5
      if (tmp->sign)
e09bf5
        {
e09bf5
          if (!mpi_cmpabs (tmp, E.a))
e09bf5
            /* For backward compatibility to <= libgcrypt 1.8, we
e09bf5
               allow this match to support existing keys in SEXP.  */
e09bf5
            ;
e09bf5
          else
e09bf5
            {
e09bf5
              mpi_resize (tmp, E.p->nlimbs);
e09bf5
              _gcry_mpih_sub_n (tmp->d, E.p->d,
e09bf5
                                tmp->d, E.p->nlimbs);
e09bf5
              tmp->nlimbs = E.p->nlimbs;
e09bf5
              tmp->sign = 0;
e09bf5
              if (mpi_cmp (tmp, E.a))
e09bf5
                continue;
e09bf5
            }
e09bf5
        }
e09bf5
      else if (mpi_cmp (tmp, E.a))
e09bf5
        continue;
e09bf5
e09bf5
      mpi_free (tmp);
e09bf5
      tmp = scanval (domain_parms[idx].b);
e09bf5
      if (tmp->sign)
e09bf5
        {
e09bf5
          if (!mpi_cmpabs (tmp, E.b))
e09bf5
            /* Same for backward compatibility, see above.  */
e09bf5
            ;
e09bf5
          else
e09bf5
            {
e09bf5
              mpi_resize (tmp, E.p->nlimbs);
e09bf5
              _gcry_mpih_sub_n (tmp->d, E.p->d,
e09bf5
                                tmp->d, E.p->nlimbs);
e09bf5
              tmp->nlimbs = E.p->nlimbs;
e09bf5
              tmp->sign = 0;
e09bf5
              if (mpi_cmp (tmp, E.b))
e09bf5
                continue;
e09bf5
            }
e09bf5
        }
e09bf5
      else if (mpi_cmp (tmp, E.b))
e09bf5
        continue;
e09bf5
e09bf5
      mpi_free (tmp);
e09bf5
      tmp = scanval (domain_parms[idx].n);
e09bf5
      if (mpi_cmp (tmp, E.n))
e09bf5
        continue;
e09bf5
e09bf5
      mpi_free (tmp);
e09bf5
      tmp = scanval (domain_parms[idx].g_x);
e09bf5
      if (mpi_cmp (tmp, E.G.x))
e09bf5
        continue;
e09bf5
e09bf5
      mpi_free (tmp);
e09bf5
      tmp = scanval (domain_parms[idx].g_y);
e09bf5
      if (mpi_cmp (tmp, E.G.y))
e09bf5
        continue;
e09bf5
e09bf5
      result = domain_parms[idx].desc;
e09bf5
      if (r_nbits)
e09bf5
        *r_nbits = domain_parms[idx].nbits;
e09bf5
      break;
e09bf5
    }
e09bf5
e09bf5
 leave:
e09bf5
  _gcry_mpi_point_release (G);
e09bf5
  _gcry_mpi_release (tmp);
e09bf5
  _gcry_mpi_release (E.p);
e09bf5
  _gcry_mpi_release (E.a);
e09bf5
  _gcry_mpi_release (E.b);
e09bf5
  _gcry_mpi_point_free_parts (&E.G);
e09bf5
  _gcry_mpi_release (E.n);
e09bf5
  return result;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Helper to extract an MPI from key parameters.  */
e09bf5
static gpg_err_code_t
e09bf5
mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name,
e09bf5
                   int opaque)
e09bf5
{
e09bf5
  gcry_err_code_t ec = 0;
e09bf5
  gcry_sexp_t l1;
e09bf5
e09bf5
  l1 = sexp_find_token (keyparam, name, 0);
e09bf5
  if (l1)
e09bf5
    {
e09bf5
      *r_a = sexp_nth_mpi (l1, 1, opaque? GCRYMPI_FMT_OPAQUE : GCRYMPI_FMT_USG);
e09bf5
      sexp_release (l1);
e09bf5
      if (!*r_a)
e09bf5
        ec = GPG_ERR_INV_OBJ;
e09bf5
    }
e09bf5
  return ec;
e09bf5
}
e09bf5
e09bf5
/* Helper to extract a point from key parameters.  If no parameter
e09bf5
   with NAME is found, the functions tries to find a non-encoded point
e09bf5
   by appending ".x", ".y" and ".z" to NAME.  ".z" is in this case
e09bf5
   optional and defaults to 1.  EC is the context which at this point
e09bf5
   may not be fully initialized. */
e09bf5
static gpg_err_code_t
e09bf5
point_from_keyparam (gcry_mpi_point_t *r_a,
e09bf5
                     gcry_sexp_t keyparam, const char *name, mpi_ec_t ec)
e09bf5
{
e09bf5
  gcry_err_code_t rc;
e09bf5
  gcry_sexp_t l1;
e09bf5
  gcry_mpi_point_t point;
e09bf5
e09bf5
  l1 = sexp_find_token (keyparam, name, 0);
e09bf5
  if (l1)
e09bf5
    {
e09bf5
      gcry_mpi_t a;
e09bf5
e09bf5
      a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE);
e09bf5
      sexp_release (l1);
e09bf5
      if (!a)
e09bf5
        return GPG_ERR_INV_OBJ;
e09bf5
e09bf5
      point = mpi_point_new (0);
e09bf5
      rc = _gcry_mpi_ec_decode_point (point, a, ec);
e09bf5
      mpi_free (a);
e09bf5
      if (rc)
e09bf5
        {
e09bf5
          mpi_point_release (point);
e09bf5
          return rc;
e09bf5
        }
e09bf5
    }
e09bf5
  else
e09bf5
    {
e09bf5
      char *tmpname;
e09bf5
      gcry_mpi_t x = NULL;
e09bf5
      gcry_mpi_t y = NULL;
e09bf5
      gcry_mpi_t z = NULL;
e09bf5
e09bf5
      tmpname = xtrymalloc (strlen (name) + 2 + 1);
e09bf5
      if (!tmpname)
e09bf5
        return gpg_err_code_from_syserror ();
e09bf5
      strcpy (stpcpy (tmpname, name), ".x");
e09bf5
      rc = mpi_from_keyparam (&x, keyparam, tmpname, 0);
e09bf5
      if (rc)
e09bf5
        {
e09bf5
          xfree (tmpname);
e09bf5
          return rc;
e09bf5
        }
e09bf5
      strcpy (stpcpy (tmpname, name), ".y");
e09bf5
      rc = mpi_from_keyparam (&y, keyparam, tmpname, 0);
e09bf5
      if (rc)
e09bf5
        {
e09bf5
          mpi_free (x);
e09bf5
          xfree (tmpname);
e09bf5
          return rc;
e09bf5
        }
e09bf5
      strcpy (stpcpy (tmpname, name), ".z");
e09bf5
      rc = mpi_from_keyparam (&z, keyparam, tmpname, 0);
e09bf5
      if (rc)
e09bf5
        {
e09bf5
          mpi_free (y);
e09bf5
          mpi_free (x);
e09bf5
          xfree (tmpname);
e09bf5
          return rc;
e09bf5
        }
e09bf5
      if (!z)
e09bf5
        z = mpi_set_ui (NULL, 1);
e09bf5
      if (x && y)
e09bf5
        point = mpi_point_snatch_set (NULL, x, y, z);
e09bf5
      else
e09bf5
        {
e09bf5
          mpi_free (x);
e09bf5
          mpi_free (y);
e09bf5
          mpi_free (z);
e09bf5
          point = NULL;
e09bf5
        }
e09bf5
      xfree (tmpname);
e09bf5
    }
e09bf5
e09bf5
  if (point)
e09bf5
    *r_a = point;
e09bf5
  return 0;
e09bf5
}
e09bf5
e09bf5
e09bf5
e09bf5
static gpg_err_code_t
e09bf5
mpi_ec_get_elliptic_curve (elliptic_curve_t *E, int *r_flags,
e09bf5
                           gcry_sexp_t keyparam, const char *curvename)
e09bf5
{
e09bf5
  gpg_err_code_t errc;
e09bf5
  unsigned int nbits;
e09bf5
  gcry_sexp_t l1;
e09bf5
e09bf5
  errc = _gcry_pk_util_get_nbits (keyparam, &nbits);
e09bf5
  if (errc)
e09bf5
    return errc;
e09bf5
e09bf5
  E->model = MPI_EC_WEIERSTRASS;
e09bf5
  E->dialect = ECC_DIALECT_STANDARD;
e09bf5
  E->h = 1;
e09bf5
e09bf5
  if (keyparam)
e09bf5
    {
e09bf5
      /* Parse an optional flags list.  */
e09bf5
      l1 = sexp_find_token (keyparam, "flags", 0);
e09bf5
      if (l1)
e09bf5
        {
e09bf5
          int flags = 0;
e09bf5
e09bf5
          errc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
e09bf5
          sexp_release (l1);
e09bf5
          l1 = NULL;
e09bf5
          if (errc)
e09bf5
            goto leave;
e09bf5
e09bf5
          *r_flags |= flags;
e09bf5
        }
e09bf5
e09bf5
      /* Parse the deprecated optional transient-key flag.  */
e09bf5
      l1 = sexp_find_token (keyparam, "transient-key", 0);
e09bf5
      if (l1)
e09bf5
        {
e09bf5
          *r_flags |= PUBKEY_FLAG_TRANSIENT_KEY;
e09bf5
          sexp_release (l1);
e09bf5
        }
e09bf5
e09bf5
      /* Check whether a curve name was given.  */
e09bf5
      l1 = sexp_find_token (keyparam, "curve", 5);
e09bf5
e09bf5
      /* If we don't have a curve name or if override parameters have
e09bf5
         explicitly been requested, parse them.  */
e09bf5
      if (!l1 || (*r_flags & PUBKEY_FLAG_PARAM))
e09bf5
        {
e09bf5
          gcry_mpi_point_t G = NULL;
e09bf5
          gcry_mpi_t cofactor = NULL;
e09bf5
e09bf5
          errc = mpi_from_keyparam (&E->p, keyparam, "p", 0);
e09bf5
          if (errc)
e09bf5
            goto leave;
e09bf5
          errc = mpi_from_keyparam (&E->a, keyparam, "a", 0);
e09bf5
          if (errc)
e09bf5
            goto leave;
e09bf5
          errc = mpi_from_keyparam (&E->b, keyparam, "b", 0);
e09bf5
          if (errc)
e09bf5
            goto leave;
e09bf5
          errc = point_from_keyparam (&G, keyparam, "g", NULL);
e09bf5
          if (errc)
e09bf5
            goto leave;
e09bf5
          if (G)
e09bf5
            {
e09bf5
              _gcry_mpi_point_init (&E->G);
e09bf5
              mpi_point_set (&E->G, G->x, G->y, G->z);
e09bf5
              mpi_point_set (G, NULL, NULL, NULL);
e09bf5
              mpi_point_release (G);
e09bf5
            }
e09bf5
          errc = mpi_from_keyparam (&E->n, keyparam, "n", 0);
e09bf5
          if (errc)
e09bf5
            goto leave;
e09bf5
          errc = mpi_from_keyparam (&cofactor, keyparam, "h", 0);
e09bf5
          if (errc)
e09bf5
            goto leave;
e09bf5
          if (cofactor)
e09bf5
            {
e09bf5
              mpi_get_ui (&E->h, cofactor);
e09bf5
              mpi_free (cofactor);
e09bf5
            }
e09bf5
        }
e09bf5
    }
e09bf5
  else
e09bf5
    l1 = NULL; /* No curvename.  */
e09bf5
e09bf5
  /* Check whether a curve parameter is available and use that to fill
e09bf5
     in missing values.  If no curve parameter is available try an
e09bf5
     optional provided curvename.  If only the curvename has been
e09bf5
     given use that one. */
e09bf5
  if (l1 || curvename || nbits)
e09bf5
    {
e09bf5
      char *name;
e09bf5
e09bf5
      if (l1)
e09bf5
        {
e09bf5
          name = sexp_nth_string (l1, 1);
e09bf5
          sexp_release (l1);
e09bf5
          if (!name)
e09bf5
            {
e09bf5
              errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
e09bf5
              goto leave;
e09bf5
            }
e09bf5
        }
e09bf5
      else
e09bf5
        name = NULL;
e09bf5
e09bf5
      errc = _gcry_ecc_fill_in_curve (nbits, name? name : curvename, E, NULL);
e09bf5
      xfree (name);
e09bf5
      if (errc)
e09bf5
        goto leave;
e09bf5
    }
e09bf5
e09bf5
 leave:
e09bf5
  return errc;
e09bf5
}
e09bf5
e09bf5
static gpg_err_code_t
e09bf5
mpi_ec_setup_elliptic_curve (mpi_ec_t ec, int flags,
e09bf5
                             elliptic_curve_t *E, gcry_sexp_t keyparam)
e09bf5
{
e09bf5
  gpg_err_code_t errc = 0;
e09bf5
e09bf5
  ec->G = mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z);
e09bf5
  E->G.x = NULL;
e09bf5
  E->G.y = NULL;
e09bf5
  E->G.z = NULL;
e09bf5
  ec->n = E->n;
e09bf5
  E->n = NULL;
e09bf5
  ec->h = E->h;
e09bf5
  ec->name = E->name;
e09bf5
e09bf5
  /* Now that we know the curve name we can look for the public key
e09bf5
     Q.  point_from_keyparam needs to know the curve parameters so
e09bf5
     that it is able to use the correct decompression.  Parsing
e09bf5
     the private key D could have been done earlier but it is less
e09bf5
     surprising if we do it here as well.  */
e09bf5
  if (keyparam)
e09bf5
    {
e09bf5
      int is_opaque_bytes = ((ec->dialect == ECC_DIALECT_ED25519
e09bf5
                              && (flags & PUBKEY_FLAG_EDDSA))
e09bf5
                             || (ec->dialect == ECC_DIALECT_SAFECURVE));
e09bf5
e09bf5
      errc = point_from_keyparam (&ec->Q, keyparam, "q", ec);
e09bf5
      if (errc)
e09bf5
        return errc;
e09bf5
      errc = mpi_from_keyparam (&ec->d, keyparam, "d", is_opaque_bytes);
e09bf5
e09bf5
      /* Size of opaque bytes should match size of P.  */
e09bf5
      if (!errc && ec->d && is_opaque_bytes)
e09bf5
        {
e09bf5
          unsigned int n = mpi_get_nbits (ec->d);
e09bf5
          unsigned int len;
e09bf5
e09bf5
          len = (ec->nbits+7)/8;
e09bf5
          /* EdDSA requires additional bit for sign.  */
e09bf5
          if ((ec->nbits%8) == 0 && ec->model == MPI_EC_EDWARDS)
e09bf5
            len++;
e09bf5
e09bf5
          if ((n+7)/8 != len)
e09bf5
            {
e09bf5
              if (ec->dialect == ECC_DIALECT_ED25519)
e09bf5
                {
e09bf5
                  /*
e09bf5
                   * GnuPG (<= 2.2) or OpenPGP implementations with no
e09bf5
                   * SOS support may remove zeros at the beginning.
e09bf5
                   * Recover those zeros.
e09bf5
                   */
e09bf5
                  /*
e09bf5
                   * Also, GnuPG (<= 2.2) may add additional zero at
e09bf5
                   * the beginning, when private key is moved from
e09bf5
                   * OpenPGP to gpg-agent.  Remove such a zero-prefix.
e09bf5
                   */
e09bf5
                  const unsigned char *buf;
e09bf5
                  unsigned char *value;
e09bf5
e09bf5
                  buf = mpi_get_opaque (ec->d, &n);
e09bf5
                  if (!buf)
e09bf5
                    return GPG_ERR_INV_OBJ;
e09bf5
e09bf5
                  value = xtrymalloc_secure (len);
e09bf5
                  if (!value)
e09bf5
                    return gpg_err_code_from_syserror ();
e09bf5
e09bf5
                  if ((n+7)/8 < len)
e09bf5
                    /* Recover zeros.  */
e09bf5
                    {
e09bf5
                      memset (value, 0, len - (n+7)/8);
e09bf5
                      memcpy (value + len - (n+7)/8, buf, (n+7)/8);
e09bf5
                    }
e09bf5
                  else if ((n+7)/8 == len + 1)
e09bf5
                    /* Remove a zero.  */
e09bf5
                    memcpy (value, buf+1, len);
e09bf5
                  else
e09bf5
                    {
e09bf5
                      xfree (value);
e09bf5
                      return GPG_ERR_INV_OBJ;
e09bf5
                    }
e09bf5
e09bf5
                  mpi_set_opaque (ec->d, value, len*8);
e09bf5
                }
e09bf5
              else
e09bf5
                {
e09bf5
                  if (DBG_CIPHER)
e09bf5
                    log_debug ("scalar size (%d) != prime size (%d)",
e09bf5
                               (n+7)/8, len);
e09bf5
e09bf5
                  errc = GPG_ERR_INV_OBJ;
e09bf5
                }
e09bf5
            }
e09bf5
        }
e09bf5
    }
e09bf5
e09bf5
  return errc;
e09bf5
}
e09bf5
e09bf5
gpg_err_code_t
e09bf5
_gcry_mpi_ec_internal_new (mpi_ec_t *r_ec, int *r_flags, const char *name_op,
e09bf5
                           gcry_sexp_t keyparam, const char *curvename)
e09bf5
{
e09bf5
  gpg_err_code_t errc;
e09bf5
  elliptic_curve_t E;
e09bf5
  mpi_ec_t ec;
e09bf5
e09bf5
  *r_ec = NULL;
e09bf5
e09bf5
  memset (&E, 0, sizeof E);
e09bf5
  errc = mpi_ec_get_elliptic_curve (&E, r_flags, keyparam, curvename);
e09bf5
  if (errc)
e09bf5
    goto leave;
e09bf5
e09bf5
  ec = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, *r_flags,
e09bf5
                                    E.p, E.a, E.b);
e09bf5
  if (!ec)
e09bf5
    goto leave;
e09bf5
e09bf5
  errc = mpi_ec_setup_elliptic_curve (ec, *r_flags, &E, keyparam);
e09bf5
  if (errc)
e09bf5
    {
e09bf5
      _gcry_mpi_ec_free (ec);
e09bf5
      goto leave;
e09bf5
    }
e09bf5
  else
e09bf5
    *r_ec = ec;
e09bf5
e09bf5
  if (!errc && DBG_CIPHER)
e09bf5
    {
e09bf5
      gcry_mpi_t mpi_q = NULL;
e09bf5
      gcry_sexp_t l1;
e09bf5
      char msg[80];
e09bf5
e09bf5
      l1 = sexp_find_token (keyparam, "q", 0);
e09bf5
      if (l1)
e09bf5
        {
e09bf5
          mpi_q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE);
e09bf5
          sexp_release (l1);
e09bf5
        }
e09bf5
e09bf5
      log_debug ("%s info: %s/%s%s\n", name_op,
e09bf5
                 _gcry_ecc_model2str (ec->model),
e09bf5
                 _gcry_ecc_dialect2str (ec->dialect),
e09bf5
                 (*r_flags & PUBKEY_FLAG_EDDSA)? "+EdDSA" : "");
e09bf5
      if (ec->name)
e09bf5
        log_debug  ("%s name: %s\n", name_op, ec->name);
e09bf5
      snprintf (msg, sizeof msg, "%s    p", name_op);
e09bf5
      log_printmpi (msg, ec->p);
e09bf5
      snprintf (msg, sizeof msg, "%s    a", name_op);
e09bf5
      log_printmpi (msg, ec->a);
e09bf5
      snprintf (msg, sizeof msg, "%s    b", name_op);
e09bf5
      log_printmpi (msg, ec->b);
e09bf5
      snprintf (msg, sizeof msg, "%s  g", name_op);
e09bf5
      log_printpnt (msg, ec->G, NULL);
e09bf5
      snprintf (msg, sizeof msg, "%s    n", name_op);
e09bf5
      log_printmpi (msg, ec->n);
e09bf5
      log_debug ("%s    h:+%02x\n", name_op, ec->h);
e09bf5
      if (mpi_q)
e09bf5
        {
e09bf5
          snprintf (msg, sizeof msg, "%s    q", name_op);
e09bf5
          log_printmpi (msg, mpi_q);
e09bf5
          mpi_free (mpi_q);
e09bf5
        }
e09bf5
      if (!fips_mode () && ec->d)
e09bf5
        {
e09bf5
          snprintf (msg, sizeof msg, "%s    d", name_op);
e09bf5
          log_printmpi (msg, ec->d);
e09bf5
        }
e09bf5
    }
e09bf5
e09bf5
 leave:
e09bf5
  _gcry_ecc_curve_free (&E);
e09bf5
  return errc;
e09bf5
}
e09bf5
e09bf5
/* This function creates a new context for elliptic curve operations.
e09bf5
   Either KEYPARAM or CURVENAME must be given.  If both are given and
e09bf5
   KEYPARAM has no curve parameter, CURVENAME is used to add missing
e09bf5
   parameters.  On success 0 is returned and the new context stored at
e09bf5
   R_CTX.  On error NULL is stored at R_CTX and an error code is
e09bf5
   returned.  The context needs to be released using
e09bf5
   gcry_ctx_release.  */
e09bf5
gpg_err_code_t
e09bf5
_gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
e09bf5
                  gcry_sexp_t keyparam, const char *curvename)
e09bf5
{
e09bf5
  gpg_err_code_t errc;
e09bf5
  elliptic_curve_t E;
e09bf5
  gcry_ctx_t ctx = NULL;
e09bf5
  int flags = 0;
e09bf5
  mpi_ec_t ec;
e09bf5
e09bf5
  *r_ctx = NULL;
e09bf5
e09bf5
  memset (&E, 0, sizeof E);
e09bf5
  errc = mpi_ec_get_elliptic_curve (&E, &flags, keyparam, curvename);
e09bf5
  if (errc)
e09bf5
    goto leave;
e09bf5
e09bf5
  errc = _gcry_mpi_ec_p_new (&ctx, E.model, E.dialect, flags, E.p, E.a, E.b);
e09bf5
  if (errc)
e09bf5
    goto leave;
e09bf5
e09bf5
  ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
e09bf5
  errc = mpi_ec_setup_elliptic_curve (ec, flags, &E, keyparam);
e09bf5
  if (errc)
e09bf5
    goto leave;
e09bf5
e09bf5
  *r_ctx = ctx;
e09bf5
  ctx = NULL;
e09bf5
e09bf5
 leave:
e09bf5
  _gcry_ecc_curve_free (&E);
e09bf5
  _gcry_ctx_release (ctx);
e09bf5
  return errc;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Return the parameters of the curve NAME as an S-expression.  */
e09bf5
gcry_sexp_t
e09bf5
_gcry_ecc_get_param_sexp (const char *name)
e09bf5
{
e09bf5
  unsigned int nbits;
e09bf5
  elliptic_curve_t E;
e09bf5
  mpi_ec_t ctx;
e09bf5
  gcry_mpi_t g_x, g_y;
e09bf5
  gcry_mpi_t pkey[5];
e09bf5
  gcry_sexp_t result;
e09bf5
  int i;
e09bf5
e09bf5
  memset (&E, 0, sizeof E);
e09bf5
  if (_gcry_ecc_fill_in_curve (0, name, &E, &nbits))
e09bf5
    return NULL;
e09bf5
e09bf5
  g_x = mpi_new (0);
e09bf5
  g_y = mpi_new (0);
e09bf5
  ctx = _gcry_mpi_ec_p_internal_new (E.model,
e09bf5
                                     E.dialect,
e09bf5
                                     0,
e09bf5
                                     E.p, E.a, E.b);
e09bf5
  if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
e09bf5
    log_fatal ("ecc get param: Failed to get affine coordinates\n");
e09bf5
  _gcry_mpi_ec_free (ctx);
e09bf5
  _gcry_mpi_point_free_parts (&E.G);
e09bf5
e09bf5
  pkey[0] = E.p;
e09bf5
  pkey[1] = E.a;
e09bf5
  pkey[2] = E.b;
e09bf5
  pkey[3] = _gcry_ecc_ec2os (g_x, g_y, E.p);
e09bf5
  pkey[4] = E.n;
e09bf5
e09bf5
  mpi_free (g_x);
e09bf5
  mpi_free (g_y);
e09bf5
e09bf5
  if (sexp_build (&result, NULL,
e09bf5
                  "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%u)))",
e09bf5
                  pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], E.h))
e09bf5
    result = NULL;
e09bf5
e09bf5
  for (i=0; i < DIM (pkey); i++)
e09bf5
    _gcry_mpi_release (pkey[i]);
e09bf5
e09bf5
  return result;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Return an MPI (or opaque MPI) described by NAME and the context EC.
e09bf5
   If COPY is true a copy is returned, if not a const MPI may be
e09bf5
   returned.  In any case mpi_free must be used.  */
e09bf5
gcry_mpi_t
e09bf5
_gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
e09bf5
{
e09bf5
  if (!*name)
e09bf5
    return NULL;
e09bf5
e09bf5
  if (!strcmp (name, "p") && ec->p)
e09bf5
    return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
e09bf5
  if (!strcmp (name, "a") && ec->a)
e09bf5
    return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a);
e09bf5
  if (!strcmp (name, "b") && ec->b)
e09bf5
    return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b);
e09bf5
  if (!strcmp (name, "n") && ec->n)
e09bf5
    return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n);
e09bf5
  if (!strcmp (name, "h"))
e09bf5
    {
e09bf5
      gcry_mpi_t h = _gcry_mpi_get_const (ec->h);
e09bf5
e09bf5
      return !copy? h : mpi_set (NULL, h);
e09bf5
    }
e09bf5
  if (!strcmp (name, "d") && ec->d)
e09bf5
    return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d);
e09bf5
e09bf5
  /* Return a requested point coordinate.  */
e09bf5
  if (!strcmp (name, "g.x") && ec->G && ec->G->x)
e09bf5
    return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x);
e09bf5
  if (!strcmp (name, "g.y") && ec->G && ec->G->y)
e09bf5
    return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y);
e09bf5
  if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
e09bf5
    return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
e09bf5
  if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
e09bf5
    return mpi_is_const (ec->Q->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
e09bf5
e09bf5
  /* If the base point has been requested, return it in standard
e09bf5
     encoding.  */
e09bf5
  if (!strcmp (name, "g") && ec->G)
e09bf5
    return _gcry_mpi_ec_ec2os (ec->G, ec);
e09bf5
e09bf5
  /* If the public key has been requested, return it by default in
e09bf5
     standard uncompressed encoding or if requested in other
e09bf5
     encodings.  */
e09bf5
  if (*name == 'q' && (!name[1] || name[1] == '@'))
e09bf5
    {
e09bf5
      /* If only the private key is given, compute the public key.  */
e09bf5
      if (!ec->Q)
e09bf5
        ec->Q = _gcry_ecc_compute_public (NULL, ec);
e09bf5
e09bf5
      if (!ec->Q)
e09bf5
        return NULL;
e09bf5
e09bf5
      if (name[1] != '@')
e09bf5
        return _gcry_mpi_ec_ec2os (ec->Q, ec);
e09bf5
e09bf5
      if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_EDWARDS)
e09bf5
        {
e09bf5
          unsigned char *encpk;
e09bf5
          unsigned int encpklen;
e09bf5
e09bf5
          if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0,
e09bf5
                                            &encpk, &encpklen))
e09bf5
            return mpi_set_opaque (NULL, encpk, encpklen*8);
e09bf5
        }
e09bf5
    }
e09bf5
e09bf5
  return NULL;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Return a point described by NAME and the context EC.  */
e09bf5
gcry_mpi_point_t
e09bf5
_gcry_ecc_get_point (const char *name, mpi_ec_t ec)
e09bf5
{
e09bf5
  if (!strcmp (name, "g") && ec->G)
e09bf5
    return point_copy (ec->G);
e09bf5
  if (!strcmp (name, "q"))
e09bf5
    {
e09bf5
      /* If only the private key is given, compute the public key.  */
e09bf5
      if (!ec->Q)
e09bf5
        ec->Q = _gcry_ecc_compute_public (NULL, ec);
e09bf5
e09bf5
      if (ec->Q)
e09bf5
        return point_copy (ec->Q);
e09bf5
    }
e09bf5
e09bf5
  return NULL;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Store the MPI NEWVALUE into the context EC under NAME. */
e09bf5
gpg_err_code_t
e09bf5
_gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
e09bf5
{
e09bf5
  gpg_err_code_t rc = 0;
e09bf5
e09bf5
  if (!*name)
e09bf5
    ;
e09bf5
  else if (!strcmp (name, "p"))
e09bf5
    {
e09bf5
      mpi_free (ec->p);
e09bf5
      ec->p = mpi_copy (newvalue);
e09bf5
      _gcry_mpi_ec_get_reset (ec);
e09bf5
    }
e09bf5
  else if (!strcmp (name, "a"))
e09bf5
    {
e09bf5
      mpi_free (ec->a);
e09bf5
      ec->a = mpi_copy (newvalue);
e09bf5
      _gcry_mpi_ec_get_reset (ec);
e09bf5
    }
e09bf5
  else if (!strcmp (name, "b"))
e09bf5
    {
e09bf5
      mpi_free (ec->b);
e09bf5
      ec->b = mpi_copy (newvalue);
e09bf5
    }
e09bf5
  else if (!strcmp (name, "n"))
e09bf5
    {
e09bf5
      mpi_free (ec->n);
e09bf5
      ec->n = mpi_copy (newvalue);
e09bf5
    }
e09bf5
  else if (!strcmp (name, "h"))
e09bf5
    {
e09bf5
      mpi_get_ui (&ec->h, newvalue);
e09bf5
    }
e09bf5
  else if (*name == 'q' && (!name[1] || name[1] == '@'))
e09bf5
    {
e09bf5
      if (newvalue)
e09bf5
        {
e09bf5
          if (!ec->Q)
e09bf5
            ec->Q = mpi_point_new (0);
e09bf5
          rc = _gcry_mpi_ec_decode_point (ec->Q, newvalue, ec);
e09bf5
        }
e09bf5
      if (rc || !newvalue)
e09bf5
        {
e09bf5
          _gcry_mpi_point_release (ec->Q);
e09bf5
          ec->Q = NULL;
e09bf5
        }
e09bf5
      /* Note: We assume that Q matches d and thus do not reset d.  */
e09bf5
    }
e09bf5
  else if (!strcmp (name, "d"))
e09bf5
    {
e09bf5
      mpi_free (ec->d);
e09bf5
      ec->d = mpi_copy (newvalue);
e09bf5
      if (ec->d)
e09bf5
        {
e09bf5
          /* We need to reset the public key because it may not
e09bf5
             anymore match.  */
e09bf5
          _gcry_mpi_point_release (ec->Q);
e09bf5
          ec->Q = NULL;
e09bf5
        }
e09bf5
    }
e09bf5
  else
e09bf5
   rc = GPG_ERR_UNKNOWN_NAME;
e09bf5
e09bf5
  return rc;
e09bf5
}
e09bf5
e09bf5
e09bf5
/* Store the point NEWVALUE into the context EC under NAME.  */
e09bf5
gpg_err_code_t
e09bf5
_gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec)
e09bf5
{
e09bf5
  if (!strcmp (name, "g"))
e09bf5
    {
e09bf5
      _gcry_mpi_point_release (ec->G);
e09bf5
      ec->G = point_copy (newvalue);
e09bf5
    }
e09bf5
  else if (!strcmp (name, "q"))
e09bf5
    {
e09bf5
      _gcry_mpi_point_release (ec->Q);
e09bf5
      ec->Q = point_copy (newvalue);
e09bf5
    }
e09bf5
  else
e09bf5
    return GPG_ERR_UNKNOWN_NAME;
e09bf5
e09bf5
  return 0;
e09bf5
}