ask_curve (int *algo, int both)
{
  struct {
    const char *name;
    int available;
    int expert_only;
    int fix_curve;
    const char *pretty_name;
  } curves[] = {
#if GPG_USE_EDDSA
    { "Curve25519",      0, 0, 1, "Curve 25519" },
#endif
#if GPG_USE_ECDSA || GPG_USE_ECDH
    { "NIST P-256",      0, 1, 0, },
    { "NIST P-384",      0, 0, 0, },
    { "NIST P-521",      0, 1, 0, },
    { "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" },
    { "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" },
    { "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" },
    { "secp256k1",       0, 1, 0  },
#endif
  };
  int idx;
  char *answer;
  char *result = NULL;
  gcry_sexp_t keyparms;

  tty_printf (_("Please select which elliptic curve you want:\n"));

 again:
  keyparms = NULL;
  for (idx=0; idx < DIM(curves); idx++)
    {
      int rc;

      curves[idx].available = 0;
      if (!opt.expert && curves[idx].expert_only)
        continue;

      /* FIXME: The strcmp below is a temporary hack during
         development.  It shall be removed as soon as we have proper
         Curve25519 support in Libgcrypt.  */
      gcry_sexp_release (keyparms);
      rc = gcry_sexp_build (&keyparms, NULL,
                            "(public-key(ecc(curve %s)))",
                            (!strcmp (curves[idx].name, "Curve25519")
                             ? "Ed25519" : curves[idx].name));
      if (rc)
        continue;
      if (!gcry_pk_get_curve (keyparms, 0, NULL))
        continue;
      if (both && curves[idx].fix_curve)
        {
          /* Both Curve 25519 keys are to be created.  Check that
             Libgcrypt also supports the real Curve25519.  */
          gcry_sexp_release (keyparms);
          rc = gcry_sexp_build (&keyparms, NULL,
                                "(public-key(ecc(curve %s)))",
                                 curves[idx].name);
          if (rc)
            continue;
          if (!gcry_pk_get_curve (keyparms, 0, NULL))
            continue;
        }

      curves[idx].available = 1;
      tty_printf ("   (%d) %s\n", idx + 1,
                  curves[idx].pretty_name?
                  curves[idx].pretty_name:curves[idx].name);
    }
  gcry_sexp_release (keyparms);


  for (;;)
    {
      answer = cpr_get ("keygen.curve", _("Your selection? "));
      cpr_kill_prompt ();
      idx = *answer? atoi (answer) : 1;
      if (*answer && !idx)
        {
          /* See whether the user entered the name of the curve.  */
          for (idx=0; idx < DIM(curves); idx++)
            {
              if (!opt.expert && curves[idx].expert_only)
                continue;
              if (!stricmp (curves[idx].name, answer)
                  || (curves[idx].pretty_name
                      && !stricmp (curves[idx].pretty_name, answer)))
                break;
            }
          if (idx == DIM(curves))
            idx = -1;
        }
      else
        idx--;
      xfree(answer);
      answer = NULL;
      if (idx < 0 || idx >= DIM (curves) || !curves[idx].available)
        tty_printf (_("Invalid selection.\n"));
      else
        {
          if (curves[idx].fix_curve)
            {
              log_info ("WARNING: Curve25519 is not yet part of the"
                        " OpenPGP standard.\n");

              if (!cpr_get_answer_is_yes("experimental_curve.override",
                                         "Use this curve anyway? (y/N) ")  )
                goto again;
            }

          /* If the user selected a signing algorithm and Curve25519
             we need to update the algo and and the curve name.  */
          if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
              && curves[idx].fix_curve)
            {
              *algo = PUBKEY_ALGO_EDDSA;
              result = xstrdup ("Ed25519");
            }
          else
            result = xstrdup (curves[idx].name);
          break;
        }
    }

  if (!result)
    result = xstrdup (curves[0].name);

  return result;
}