Ejemplo n.º 1
0
/**
 * Obtain a random point on the curve and its
 * additive inverse. Both returned values
 * must be freed using #GNUNET_CRYPTO_ecc_free().
 *
 * @param edc calculation context for ECC operations
 * @param[out] r set to a random point on the curve
 * @param[out] r_inv set to the additive inverse of @a r
 */
void
GNUNET_CRYPTO_ecc_rnd (struct GNUNET_CRYPTO_EccDlogContext *edc,
		       gcry_mpi_point_t *r,
		       gcry_mpi_point_t *r_inv)
{
  gcry_mpi_t fact;
  gcry_mpi_t n;
  gcry_mpi_point_t g;

  fact = GNUNET_CRYPTO_ecc_random_mod_n (edc);

  /* calculate 'r' */
  g = gcry_mpi_ec_get_point ("g", edc->ctx, 0);
  GNUNET_assert (NULL != g);
  *r = gcry_mpi_point_new (0);
  gcry_mpi_ec_mul (*r, fact, g, edc->ctx);

  /* calculate 'r_inv' */
  n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
  gcry_mpi_sub (fact, n, fact); /* fact = n - fact = - fact */
  *r_inv = gcry_mpi_point_new (0);
  gcry_mpi_ec_mul (*r_inv, fact, g, edc->ctx);

  gcry_mpi_release (n);
  gcry_mpi_release (fact);
  gcry_mpi_point_release (g);
}
Ejemplo n.º 2
0
/**
 * Multiply the generator g of the elliptic curve by @a val
 * to obtain the point on the curve representing @a val.
 * Afterwards, point addition will correspond to integer
 * addition.  #GNUNET_CRYPTO_ecc_dlog() can be used to
 * convert a point back to an integer (as long as the
 * integer is smaller than the MAX of the @a edc context).
 *
 * @param edc calculation context for ECC operations
 * @param val value to encode into a point
 * @return representation of the value as an ECC point,
 *         must be freed using #GNUNET_CRYPTO_ecc_free()
 */
gcry_mpi_point_t
GNUNET_CRYPTO_ecc_dexp (struct GNUNET_CRYPTO_EccDlogContext *edc,
			int val)
{
  gcry_mpi_t fact;
  gcry_mpi_t n;
  gcry_mpi_point_t g;
  gcry_mpi_point_t r;

  g = gcry_mpi_ec_get_point ("g", edc->ctx, 0);
  GNUNET_assert (NULL != g);
  fact = gcry_mpi_new (0);
  if (val < 0)
  {
    n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
    gcry_mpi_set_ui (fact, - val);
    gcry_mpi_sub (fact, n, fact);
    gcry_mpi_release (n);
  }
  else
  {
    gcry_mpi_set_ui (fact, val);
  }
  r = gcry_mpi_point_new (0);
  gcry_mpi_ec_mul (r, fact, g, edc->ctx);
  gcry_mpi_release (fact);
  gcry_mpi_point_release (g);
  return r;
}
Ejemplo n.º 3
0
/**
 * Generate a random value mod n.
 *
 * @param edc ECC context
 * @return random value mod n.
 */
gcry_mpi_t
GNUNET_CRYPTO_ecc_random_mod_n (struct GNUNET_CRYPTO_EccDlogContext *edc)
{
  gcry_mpi_t n;
  unsigned int highbit;
  gcry_mpi_t r;

  n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);

  /* check public key for number of bits, bail out if key is all zeros */
  highbit = 256; /* Curve25519 */
  while ( (! gcry_mpi_test_bit (n, highbit)) &&
          (0 != highbit) )
    highbit--;
  GNUNET_assert (0 != highbit);
  /* generate fact < n (without bias) */
  GNUNET_assert (NULL != (r = gcry_mpi_new (0)));
  do {
    gcry_mpi_randomize (r,
			highbit + 1,
			GCRY_STRONG_RANDOM);
  }
  while (gcry_mpi_cmp (r, n) >= 0);
  gcry_mpi_release (n);
  return r;
}
Ejemplo n.º 4
0
Archivo: gka.c Proyecto: totakura/gotr
void serialize_point(struct gotr_point *buf, const size_t len, const gcry_mpi_point_t p)
{
	gcry_sexp_t s;
	gcry_ctx_t ctx;
	gcry_error_t rc;
	gcry_mpi_t q;

	gotr_assert(buf && len >= SERIALIZED_POINT_LEN);

	rc = gcry_sexp_build(&s, NULL, "(public-key(ecc(curve " CURVE ")))");
	gotr_assert_gpgerr(rc);
	gotr_assert(NULL != s);

	rc = gcry_mpi_ec_new(&ctx, s, NULL);
	gotr_assert_gpgerr(rc);
	gcry_sexp_release(s);

	rc = gcry_mpi_ec_set_point("q", p, ctx);
	gotr_assert_gpgerr(rc);

	q = gcry_mpi_ec_get_mpi("q@eddsa", ctx, 0);
	gotr_assert(NULL != q);
	gcry_ctx_release(ctx);

	gotr_mpi_print_unsigned(buf, len, q);
	gcry_mpi_release(q);
}
Ejemplo n.º 5
0
/**
 * Do pre-calculation for ECC discrete logarithm for small factors.
 *
 * @param max maximum value the factor can be
 * @param mem memory to use (should be smaller than @a max), must not be zero.
 * @return @a max if dlog failed, otherwise the factor
 */
struct GNUNET_CRYPTO_EccDlogContext *
GNUNET_CRYPTO_ecc_dlog_prepare (unsigned int max,
				unsigned int mem)
{
  struct GNUNET_CRYPTO_EccDlogContext *edc;
  unsigned int K = ((max + (mem-1)) / mem);
  gcry_mpi_point_t g;
  struct GNUNET_PeerIdentity key;
  gcry_mpi_point_t gKi;
  gcry_mpi_t fact;
  gcry_mpi_t n;
  unsigned int i;

  GNUNET_assert (max < INT32_MAX);
  edc = GNUNET_new (struct GNUNET_CRYPTO_EccDlogContext);
  edc->max = max;
  edc->mem = mem;

  edc->map = GNUNET_CONTAINER_multipeermap_create (mem * 2,
						   GNUNET_NO);

  GNUNET_assert (0 == gcry_mpi_ec_new (&edc->ctx,
				       NULL,
				       CURVE));
  g = gcry_mpi_ec_get_point ("g", edc->ctx, 0);
  GNUNET_assert (NULL != g);
  fact = gcry_mpi_new (0);
  gKi = gcry_mpi_point_new (0);
  for (i=0;i<=mem;i++)
  {
    gcry_mpi_set_ui (fact, i * K);
    gcry_mpi_ec_mul (gKi, fact, g, edc->ctx);
    extract_pk (gKi, edc->ctx, &key);
    GNUNET_assert (GNUNET_OK ==
		   GNUNET_CONTAINER_multipeermap_put (edc->map,
						      &key,
						      (void*) (long) i + max,
						      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  }
  /* negative values */
  n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
  for (i=1;i<mem;i++)
  {
    gcry_mpi_set_ui (fact, i * K);
    gcry_mpi_sub (fact, n, fact);
    gcry_mpi_ec_mul (gKi, fact, g, edc->ctx);
    extract_pk (gKi, edc->ctx, &key);
    GNUNET_assert (GNUNET_OK ==
		   GNUNET_CONTAINER_multipeermap_put (edc->map,
						      &key,
						      (void*) (long) max - i,
						      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  }
  gcry_mpi_release (fact);
  gcry_mpi_release (n);
  gcry_mpi_point_release (gKi);
  gcry_mpi_point_release (g);
  return edc;
}
Ejemplo n.º 6
0
/**
 * Do some DLOG operations for testing.
 *
 * @param edc context for ECC operations
 * @param do_dlog #GNUNET_YES if we want to actually do the bencharked operation
 */
static void
test_dlog (struct GNUNET_CRYPTO_EccDlogContext *edc, 
           int do_dlog)
{
  gcry_mpi_t fact;
  gcry_mpi_t n;
  gcry_ctx_t ctx;
  gcry_mpi_point_t q;
  gcry_mpi_point_t g;
  unsigned int i;
  int x;
  int iret;

  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
  g = gcry_mpi_ec_get_point ("g", ctx, 0);
  GNUNET_assert (NULL != g);
  n = gcry_mpi_ec_get_mpi ("n", ctx, 0);
  q = gcry_mpi_point_new (0);
  fact = gcry_mpi_new (0);
  for (i=0;i<TEST_ITER;i++)
  {
    fprintf (stderr, ".");
    x = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
				  MAX_FACT);
    if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
				       2))
    {
      gcry_mpi_set_ui (fact, x);
      gcry_mpi_sub (fact, n, fact);
      x = - x;
    }
    else 
    {
      gcry_mpi_set_ui (fact, x);
    }
    gcry_mpi_ec_mul (q, fact, g, ctx);
    if ( (GNUNET_YES == do_dlog) &&
	 (x !=
	  (iret = GNUNET_CRYPTO_ecc_dlog (edc,
					  q))) )
    {
      fprintf (stderr, 
	       "DLOG failed for value %d (%d)\n", 
	       x,
	       iret);
      GNUNET_assert (0);
    }
  }
  gcry_mpi_release (fact);
  gcry_mpi_release (n);
  gcry_mpi_point_release (g);
  gcry_mpi_point_release (q);
  gcry_ctx_release (ctx);
  fprintf (stderr, "\n");
}
Ejemplo n.º 7
0
/**
 * Obtain a random scalar for point multiplication on the curve and
 * its multiplicative inverse.
 *
 * @param edc calculation context for ECC operations
 * @param[out] r set to a random scalar on the curve
 * @param[out] r_inv set to the multiplicative inverse of @a r
 */
void
GNUNET_CRYPTO_ecc_rnd_mpi (struct GNUNET_CRYPTO_EccDlogContext *edc,
                           gcry_mpi_t *r,
                           gcry_mpi_t *r_inv)
{
  gcry_mpi_t n;

  *r = GNUNET_CRYPTO_ecc_random_mod_n (edc);
  /* r_inv = n - r = - r */
  *r_inv = gcry_mpi_new (0);
  n = gcry_mpi_ec_get_mpi ("n", edc->ctx, 1);
  gcry_mpi_sub (*r_inv, n, *r);
}
Ejemplo n.º 8
0
static void
extract_pk (gcry_mpi_point_t pt,
            gcry_ctx_t ctx,
            struct GNUNET_PeerIdentity *pid)
{
  gcry_mpi_t q_y;

  GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", pt, ctx));
  q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
  GNUNET_assert (q_y);
  GNUNET_CRYPTO_mpi_print_unsigned (pid->public_key.q_y,
				    sizeof (pid->public_key.q_y),
                                    q_y);
  gcry_mpi_release (q_y);
}
Ejemplo n.º 9
0
/**
 * Convert point value to binary representation.
 *
 * @param edc calculation context for ECC operations
 * @param point computational point representation
 * @param[out] bin binary point representation
 */
void
GNUNET_CRYPTO_ecc_point_to_bin (struct GNUNET_CRYPTO_EccDlogContext *edc,
                                gcry_mpi_point_t point,
                                struct GNUNET_CRYPTO_EccPoint *bin)
{
  gcry_mpi_t q_y;

  GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", point, edc->ctx));
  q_y = gcry_mpi_ec_get_mpi ("q@eddsa", edc->ctx, 0);
  GNUNET_assert (q_y);
  GNUNET_CRYPTO_mpi_print_unsigned (bin->q_y,
				    sizeof (bin->q_y),
                                    q_y);
  gcry_mpi_release (q_y);
}
Ejemplo n.º 10
0
static int
get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc,
                 gcry_ctx_t ctx)
{
  gcry_mpi_t mpi;

  mpi = gcry_mpi_ec_get_mpi (name, ctx, 1);
  if (!mpi)
    {
      fail ("error getting parameter '%s' of curve '%s'\n", name, desc);
      return 1;
    }
  if (debug)
    print_mpi (name, mpi);
  if (cmp_mpihex (mpi, mpistring))
    {
      fail ("parameter '%s' of curve '%s' does not match\n", name, desc);
      gcry_mpi_release (mpi);
      return 1;
    }
  gcry_mpi_release (mpi);
  return 0;
}
Ejemplo n.º 11
0
/* Check the math used with Twisted Edwards curves.  */
static void
twistededwards_math (void)
{
  gpg_error_t err;
  gcry_ctx_t ctx;
  gcry_mpi_point_t G, Q;
  gcry_mpi_t k;
  gcry_mpi_t w, a, x, y, z, p, n, b, I;

  wherestr = "twistededwards_math";
  show ("checking basic Twisted Edwards math\n");

  err = gcry_mpi_ec_new (&ctx, NULL, "Ed25519");
  if (err)
    die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err));

  k = hex2mpi
    ("2D3501E723239632802454EE5DDC406EFB0BDF18486A5BDE9C0390A9C2984004"
     "F47252B628C953625B8DEB5DBCB8DA97AA43A1892D11FA83596F42E0D89CB1B6");
  G = gcry_mpi_ec_get_point ("g", ctx, 1);
  if (!G)
    die ("gcry_mpi_ec_get_point(G) failed\n");
  Q = gcry_mpi_point_new (0);


  w = gcry_mpi_new (0);
  a = gcry_mpi_new (0);
  x = gcry_mpi_new (0);
  y = gcry_mpi_new (0);
  z = gcry_mpi_new (0);
  I = gcry_mpi_new (0);
  p = gcry_mpi_ec_get_mpi ("p", ctx, 1);
  n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
  b = gcry_mpi_ec_get_mpi ("b", ctx, 1);

  /* Check: 2^{p-1} mod p == 1 */
  gcry_mpi_sub_ui (a, p, 1);
  gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, p);
  if (gcry_mpi_cmp_ui (w, 1))
    fail ("failed assertion: 2^{p-1} mod p == 1\n");

  /* Check: p % 4 == 1 */
  gcry_mpi_mod (w, p, GCRYMPI_CONST_FOUR);
  if (gcry_mpi_cmp_ui (w, 1))
    fail ("failed assertion: p % 4 == 1\n");

  /* Check: 2^{n-1} mod n == 1 */
  gcry_mpi_sub_ui (a, n, 1);
  gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, n);
  if (gcry_mpi_cmp_ui (w, 1))
    fail ("failed assertion: 2^{n-1} mod n == 1\n");

  /* Check: b^{(p-1)/2} mod p == p-1 */
  gcry_mpi_sub_ui (a, p, 1);
  gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_TWO, -1);
  gcry_mpi_powm (w, b, x, p);
  gcry_mpi_abs (w);
  if (gcry_mpi_cmp (w, a))
    fail ("failed assertion: b^{(p-1)/2} mod p == p-1\n");

  /* I := 2^{(p-1)/4} mod p */
  gcry_mpi_sub_ui (a, p, 1);
  gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_FOUR, -1);
  gcry_mpi_powm (I, GCRYMPI_CONST_TWO, x, p);

  /* Check: I^2 mod p == p-1 */
  gcry_mpi_powm (w, I, GCRYMPI_CONST_TWO, p);
  if (gcry_mpi_cmp (w, a))
    fail ("failed assertion: I^2 mod p == p-1\n");

  /* Check: G is on the curve */
  if (!gcry_mpi_ec_curve_point (G, ctx))
    fail ("failed assertion: G is on the curve\n");

  /* Check: nG == (0,1) */
  gcry_mpi_ec_mul (Q, n, G, ctx);
  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
    fail ("failed to get affine coordinates\n");
  if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 1))
    fail ("failed assertion: nG == (0,1)\n");

  /* Now two arbitrary point operations taken from the ed25519.py
     sample data.  */
  gcry_mpi_release (a);
  a = hex2mpi
    ("4f71d012df3c371af3ea4dc38385ca5bb7272f90cb1b008b3ed601c76de1d496"
     "e30cbf625f0a756a678d8f256d5325595cccc83466f36db18f0178eb9925edd3");
  gcry_mpi_ec_mul (Q, a, G, ctx);
  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
    fail ("failed to get affine coordinates\n");
  if (cmp_mpihex (x, ("157f7361c577aad36f67ed33e38dc7be"
                      "00014fecc2165ca5cee9eee19fe4d2c1"))
      || cmp_mpihex (y, ("5a69dbeb232276b38f3f5016547bb2a2"
                         "4025645f0b820e72b8cad4f0a909a092")))
    {
      fail ("sample point multiply failed:\n");
      print_mpi ("r", a);
      print_mpi ("Rx", x);
      print_mpi ("Ry", y);
    }

  gcry_mpi_release (a);
  a = hex2mpi
    ("2d3501e723239632802454ee5ddc406efb0bdf18486a5bde9c0390a9c2984004"
     "f47252b628c953625b8deb5dbcb8da97aa43a1892d11fa83596f42e0d89cb1b6");
  gcry_mpi_ec_mul (Q, a, G, ctx);
  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
    fail ("failed to get affine coordinates\n");
  if (cmp_mpihex (x, ("6218e309d40065fcc338b3127f468371"
                      "82324bd01ce6f3cf81ab44e62959c82a"))
      || cmp_mpihex (y, ("5501492265e073d874d9e5b81e7f8784"
                         "8a826e80cce2869072ac60c3004356e5")))
    {
      fail ("sample point multiply failed:\n");
      print_mpi ("r", a);
      print_mpi ("Rx", x);
      print_mpi ("Ry", y);
    }


  gcry_mpi_release (I);
  gcry_mpi_release (b);
  gcry_mpi_release (n);
  gcry_mpi_release (p);
  gcry_mpi_release (w);
  gcry_mpi_release (a);
  gcry_mpi_release (x);
  gcry_mpi_release (y);
  gcry_mpi_release (z);
  gcry_mpi_point_release (Q);
  gcry_mpi_point_release (G);
  gcry_mpi_release (k);
  gcry_ctx_release (ctx);
}
Ejemplo n.º 12
0
static void
context_param (void)
{
  gpg_error_t err;
  int idx;
  gcry_ctx_t ctx = NULL;
  gcry_mpi_t q, d;
  gcry_sexp_t keyparam;

  wherestr = "context_param";

  show ("checking standard curves\n");
  for (idx=0; test_curve[idx].desc; idx++)
    {
      gcry_ctx_release (ctx);
      err = gcry_mpi_ec_new (&ctx, NULL, test_curve[idx].desc);
      if (err)
        {
          fail ("can't create context for curve '%s': %s\n",
                test_curve[idx].desc, gpg_strerror (err));
          continue;
        }
      if (get_and_cmp_mpi ("p", test_curve[idx].p, test_curve[idx].desc, ctx))
        continue;
      if (get_and_cmp_mpi ("a", test_curve[idx].a, test_curve[idx].desc, ctx))
        continue;
      if (get_and_cmp_mpi ("b", test_curve[idx].b, test_curve[idx].desc, ctx))
        continue;
      if (get_and_cmp_mpi ("g.x",test_curve[idx].g_x, test_curve[idx].desc,ctx))
        continue;
      if (get_and_cmp_mpi ("g.y",test_curve[idx].g_y, test_curve[idx].desc,ctx))
        continue;
      if (get_and_cmp_mpi ("n", test_curve[idx].n, test_curve[idx].desc, ctx))
        continue;
      if (get_and_cmp_point ("g", test_curve[idx].g_x, test_curve[idx].g_y,
                             test_curve[idx].desc, ctx))
        continue;
      if (get_and_cmp_mpi ("h", test_curve[idx].h, test_curve[idx].desc, ctx))
        continue;

    }

  show ("checking sample public key (nistp256)\n");
  q = hex2mpi (sample_p256_q);
  err = gcry_sexp_build (&keyparam, NULL,
                        "(public-key(ecc(curve %s)(q %m)))",
                        "NIST P-256", q);
  if (err)
    die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
  gcry_mpi_release (q);

  /* We can't call gcry_pk_testkey because it is only implemented for
     private keys.  */
  /* err = gcry_pk_testkey (keyparam); */
  /* if (err) */
  /*   fail ("gcry_pk_testkey failed for sample public key: %s\n", */
  /*         gpg_strerror (err)); */

  gcry_ctx_release (ctx);
  err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
  if (err)
    fail ("gcry_mpi_ec_new failed for sample public key (nistp256): %s\n",
          gpg_strerror (err));
  else
    {
      gcry_sexp_t sexp;

      get_and_cmp_mpi ("q", sample_p256_q, "nistp256", ctx);
      get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "nistp256",
                         ctx);

      /* Delete Q.  */
      err = gcry_mpi_ec_set_mpi ("q", NULL, ctx);
      if (err)
        fail ("clearing Q for nistp256 failed: %s\n", gpg_strerror (err));
      if (gcry_mpi_ec_get_mpi ("q", ctx, 0))
        fail ("clearing Q for nistp256 did not work\n");

      /* Set Q again.  */
      q = hex2mpi (sample_p256_q);
      err = gcry_mpi_ec_set_mpi ("q", q, ctx);
      if (err)
        fail ("setting Q for nistp256 failed: %s\n", gpg_strerror (err));
      get_and_cmp_mpi ("q", sample_p256_q, "nistp256(2)", ctx);
      gcry_mpi_release (q);

      /* Get as s-expression.  */
      err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
      if (err)
        fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
      else if (debug)
        print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
      gcry_sexp_release (sexp);

      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx);
      if (err)
        fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n",
              gpg_strerror (err));
      else if (debug)
        print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
      gcry_sexp_release (sexp);

      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx);
      if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
        fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n",
              gpg_strerror (err));
      gcry_sexp_release (sexp);
    }

  show ("checking sample public key (Ed25519)\n");
  q = hex2mpi (sample_ed25519_q);
  gcry_sexp_release (keyparam);
  err = gcry_sexp_build (&keyparam, NULL,
                        "(public-key(ecc(curve %s)(flags eddsa)(q %m)))",
                        "Ed25519", q);
  if (err)
    die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
  gcry_mpi_release (q);

  /* We can't call gcry_pk_testkey because it is only implemented for
     private keys.  */
  /* err = gcry_pk_testkey (keyparam); */
  /* if (err) */
  /*   fail ("gcry_pk_testkey failed for sample public key: %s\n", */
  /*         gpg_strerror (err)); */

  gcry_ctx_release (ctx);
  err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
  if (err)
    fail ("gcry_mpi_ec_new failed for sample public key: %s\n",
          gpg_strerror (err));
  else
    {
      gcry_sexp_t sexp;

      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519", ctx);
      get_and_cmp_point ("q", sample_ed25519_q_x, sample_ed25519_q_y,
                         "Ed25519", ctx);
      get_and_cmp_mpi ("q@eddsa", sample_ed25519_q_eddsa, "Ed25519", ctx);

      /* Set d to see whether Q is correctly re-computed.  */
      d = hex2mpi (sample_ed25519_d);
      err = gcry_mpi_ec_set_mpi ("d", d, ctx);
      if (err)
        fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err));
      gcry_mpi_release (d);
      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(recompute Q)", ctx);

      /* Delete Q by setting d and then clearing d.  The clearing is
         required so that we can check whether Q has been cleared and
         because further tests only expect a public key.  */
      d = hex2mpi (sample_ed25519_d);
      err = gcry_mpi_ec_set_mpi ("d", d, ctx);
      if (err)
        fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err));
      gcry_mpi_release (d);
      err = gcry_mpi_ec_set_mpi ("d", NULL, ctx);
      if (err)
        fail ("setting d for Ed25519 failed(2): %s\n", gpg_strerror (err));
      if (gcry_mpi_ec_get_mpi ("q", ctx, 0))
        fail ("setting d for Ed25519 did not reset Q\n");

      /* Set Q again.  We need to use an opaque MPI here because
         sample_ed25519_q is in uncompressed format which can only be
         auto-detected if passed opaque.  */
      q = hex2mpiopa (sample_ed25519_q);
      err = gcry_mpi_ec_set_mpi ("q", q, ctx);
      if (err)
        fail ("setting Q for Ed25519 failed: %s\n", gpg_strerror (err));
      gcry_mpi_release (q);
      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(2)", ctx);

      /* Get as s-expression.  */
      err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
      if (err)
        fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
      else if (debug)
        print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
      gcry_sexp_release (sexp);

      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx);
      if (err)
        fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n",
              gpg_strerror (err));
      else if (debug)
        print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
      gcry_sexp_release (sexp);

      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx);
      if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
        fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n",
              gpg_strerror (err));
      gcry_sexp_release (sexp);

    }

  gcry_ctx_release (ctx);
  gcry_sexp_release (keyparam);
}