예제 #1
0
파일: pubkey2c.c 프로젝트: kzlin129/tt-gpl
int main(int argc, char **argv)
{
	DSA *dsa;
	FILE *fp;
	int i;

	if (argc < 2)
		return 1;

	for (i = 0; i < argc-1; i++) { 
		if ( !(fp = fopen( argv[i+1], "r")))
			return 1;

		if ( !(dsa = PEM_read_DSA_PUBKEY(fp, NULL, NULL, NULL))) {
			fprintf(stderr, "Could not read public key from file\n");
			return 1;
		}

		print_mpi( stdout, i, "P", dsa->p );
		print_mpi( stdout, i, "Q", dsa->q );
		print_mpi( stdout, i, "G", dsa->g );
		print_mpi( stdout, i, "Y", dsa->pub_key );

		fclose( fp );
	}
	print_structs( stdout, argc-1 );
	fprintf(stdout, "static int const dsa_key_count = %d;\n", argc-1);

	return 0;
}
예제 #2
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;
}
예제 #3
0
int
main (int argc, char **argv)
{
  const char *pgm;
  int last_argc = -1;
  int print_config = 0;
  int i, c;
  int state = 0;
  char strbuf[4096];
  int stridx = 0;

  if (argc)
    {
      pgm = strrchr (*argv, '/');
      if (pgm)
        pgm++;
      else
        pgm = *argv;
      argc--; argv++;
    }
  else
    pgm = "?";

  while (argc && last_argc != argc )
    {
      last_argc = argc;
      if (!strcmp (*argv, "--"))
        {
          argc--; argv++;
          break;
        }
      else if (!strcmp (*argv, "--version")
               || !strcmp (*argv, "--help"))
        {
          printf ("%s " MPICALC_VERSION "\n"
                  "libgcrypt %s\n"
                  "Copyright (C) 1997, 2013  Werner Koch\n"
                  "License LGPLv2.1+: GNU LGPL version 2.1 or later "
                  "<http://gnu.org/licenses/old-licenses/lgpl-2.1.html>\n"
                  "This is free software: you are free to change and "
                  "redistribute it.\n"
                  "There is NO WARRANTY, to the extent permitted by law.\n"
                  "\n"
                  "Syntax: mpicalc [options]\n"
                  "Simple interactive big integer RPN calculator\n"
                  "\n"
                  "Options:\n"
                  "  --version           print version information\n"
                  "  --print-config      print the Libgcrypt config\n"
                  "  --disable-hwf NAME  disable feature NAME\n",
                  pgm, gcry_check_version (NULL));
          exit (0);
        }
      else if (!strcmp (*argv, "--print-config"))
        {
          argc--; argv++;
          print_config = 1;
        }
      else if (!strcmp (*argv, "--disable-hwf"))
        {
          argc--; argv++;
          if (argc)
            {
              if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
                fprintf (stderr, "%s: unknown hardware feature `%s'"
                         " - option ignored\n", pgm, *argv);
              argc--; argv++;
            }
        }
    }

  if (argc)
    {
      fprintf (stderr, "usage: %s [options]  (--help for help)\n", pgm);
      exit (1);
    }

  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
    {
      fprintf (stderr, "%s: Libgcrypt is too old (need %s, have %s)\n",
               pgm, NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
      exit (1);
    }
  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
  if (print_config)
    {
      gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
      exit (0);
    }

  for (i = 0; i < STACKSIZE; i++)
    stack[i] = NULL;
  stackidx = 0;

  while ((c = my_getc ()) != EOF)
    {
      if (!state) /* waiting */
	{
	  if (isdigit (c))
	    {
	      state = 1;
	      ungetc (c, stdin);
	      strbuf[0] = '0';
	      strbuf[1] = 'x';
	      stridx = 2;
	    }
	  else if (isspace (c))
	    ;
	  else
	    {
	      switch (c)
		{
                case '#':
                  state = 2;
                  break;
		case '+':
		  if ((c = my_getc ()) == '+')
		    do_inc ();
		  else
		    {
		      ungetc (c, stdin);
		      do_add ();
		    }
		  break;
                case '-':
		  if ((c = my_getc ()) == '-')
		    do_dec ();
		  else if (isdigit (c)
                           || (c >= 'A' && c <= 'F')
                           || (c >= 'a' && c <= 'f'))
		    {
		      state = 1;
		      ungetc (c, stdin);
		      strbuf[0] = '-';
		      strbuf[1] = '0';
		      strbuf[2] = 'x';
		      stridx = 3;
		    }
		  else
		    {
		      ungetc (c, stdin);
		      do_sub ();
		    }
		  break;
		case '*':
		  do_mul ();
		  break;
		case 'm':
		  do_mulm ();
		  break;
		case '/':
		  do_div ();
		  break;
		case '%':
		  do_rem ();
		  break;
		case '^':
		  do_powm ();
		  break;
		case '<':
		  do_lshift ();
		  break;
		case '>':
		  do_rshift ();
		  break;
		case 'I':
		  do_inv ();
		  break;
		case 'G':
		  do_gcd ();
		  break;
		case 'i':	/* dummy */
		  if (!stackidx)
		    fputs ("stack underflow\n", stderr);
		  else
		    {
		      mpi_release (stack[stackidx - 1]);
		      stackidx--;
		    }
		  break;
		case 'd':	/* duplicate the tos */
		  if (!stackidx)
		    fputs ("stack underflow\n", stderr);
		  else if (stackidx < STACKSIZE)
		    {
		      mpi_release (stack[stackidx]);
		      stack[stackidx] = mpi_copy (stack[stackidx - 1]);
		      stackidx++;
		    }
		  else
		    fputs ("stack overflow\n", stderr);
		  break;
		case 'r':	/* swap top elements */
		  if (stackidx < 2)
		    fputs ("stack underflow\n", stderr);
		  else if (stackidx < STACKSIZE)
		    {
		      gcry_mpi_t tmp = stack[stackidx-1];
                      stack[stackidx-1] = stack[stackidx - 2];
                      stack[stackidx-2] = tmp;
		    }
		  break;
                case 'b':
                  do_nbits ();
                  break;
                case 'P':
                  do_primecheck ();
                  break;
		case 'c':
		  for (i = 0; i < stackidx; i++)
                    {
                      mpi_release (stack[i]); stack[i] = NULL;
                    }
		  stackidx = 0;
		  break;
		case 'p':	/* print the tos */
		  if (!stackidx)
		    puts ("stack is empty");
		  else
		    {
		      print_mpi (stack[stackidx - 1]);
		      putchar ('\n');
		    }
		  break;
		case 'f':	/* print the stack */
		  for (i = stackidx - 1; i >= 0; i--)
		    {
		      printf ("[%2d]: ", i);
		      print_mpi (stack[i]);
		      putchar ('\n');
		    }
		  break;
                case '?':
                  print_help ();
                  break;
		default:
		  fputs ("invalid operator\n", stderr);
		}
	    }
	}
      else if (state == 1) /* In a number. */
	{
	  if (!isxdigit (c))
	    {
              /* Store the number */
	      state = 0;
	      ungetc (c, stdin);
	      if (stridx < sizeof strbuf)
		strbuf[stridx] = 0;

	      if (stackidx < STACKSIZE)
		{
		  if (!stack[stackidx])
		    stack[stackidx] = mpi_new (0);
		  if (scan_mpi (stack[stackidx], strbuf))
		    fputs ("invalid number\n", stderr);
		  else
		    stackidx++;
		}
	      else
		fputs ("stack overflow\n", stderr);
	    }
	  else
	    { /* Store a digit.  */
	      if (stridx < sizeof strbuf - 1)
		strbuf[stridx++] = c;
	      else if (stridx == sizeof strbuf - 1)
		{
		  strbuf[stridx] = 0;
		  fputs ("input too large - truncated\n", stderr);
		  stridx++;
		}
	    }
	}
      else if (state == 2) /* In a comment. */
        {
          if (c == '\n')
            state = 0;
        }

    }

  for (i = 0; i < stackidx; i++)
    mpi_release (stack[i]);
  return 0;
}
예제 #4
0
/* This is the same as basic_ec_math but uses more advanced
   features.  */
static void
basic_ec_math_simplified (void)
{
  gpg_error_t err;
  gcry_ctx_t ctx;
  gcry_mpi_point_t G, Q;
  gcry_mpi_t d;
  gcry_mpi_t x, y, z;
  gcry_sexp_t sexp;

  wherestr = "basic_ec_math_simplified";
  show ("checking basic math functions for EC (variant)\n");

  d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
  Q = gcry_mpi_point_new (0);

  err = gcry_mpi_ec_new (&ctx, NULL, "NIST P-192");
  if (err)
    die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err));
  G = gcry_mpi_ec_get_point ("g", ctx, 1);
  if (!G)
    die ("gcry_mpi_ec_get_point(G) failed\n");
  gcry_mpi_ec_mul (Q, d, G, ctx);

  x = gcry_mpi_new (0);
  y = gcry_mpi_new (0);
  z = gcry_mpi_new (0);
  gcry_mpi_point_get (x, y, z, Q);
  if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
      || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
      || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
    fail ("computed public key does not match\n");
  if (debug)
    {
      print_mpi ("Q.x", x);
      print_mpi ("Q.y", y);
      print_mpi ("Q.z", z);
    }

  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
    fail ("failed to get affine coordinates\n");
  if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
      || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
    fail ("computed affine coordinates of public key do not match\n");
  if (debug)
    {
      print_mpi ("q.x", x);
      print_mpi ("q.y", y);
    }

  gcry_mpi_release (z);
  gcry_mpi_release (y);
  gcry_mpi_release (x);

  /* Let us also check wheer we can update the context.  */
  err = gcry_mpi_ec_set_point ("g", G, ctx);
  if (err)
    die ("gcry_mpi_ec_set_point(G) failed\n");
  err = gcry_mpi_ec_set_mpi ("d", d, ctx);
  if (err)
    die ("gcry_mpi_ec_set_mpi(d) failed\n");

  /* FIXME: Below we need to check that the returned S-expression is
     as requested.  For now we use manual inspection using --debug.  */

  /* Does get_sexp return the private key?  */
  err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
  if (err)
    fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
  else if (verbose)
    print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
  gcry_sexp_release (sexp);

  /* Does get_sexp return the public key if requested?  */
  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 (verbose)
    print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
  gcry_sexp_release (sexp);

  /* Does get_sexp return the public key if after d has been deleted?  */
  err = gcry_mpi_ec_set_mpi ("d", NULL, ctx);
  if (err)
    die ("gcry_mpi_ec_set_mpi(d=NULL) failed\n");
  err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
  if (err)
    fail ("gcry_pubkey_get_sexp(0 w/o d) failed: %s\n", gpg_strerror (err));
  else if (verbose)
    print_sexp ("Result of gcry_pubkey_get_sexp (0 w/o d):\n", sexp);
  gcry_sexp_release (sexp);

  /* Does get_sexp return an error after d has been deleted?  */
  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);

  /* Does get_sexp return an error after d and Q have been deleted?  */
  err = gcry_mpi_ec_set_point ("q", NULL, ctx);
  if (err)
    die ("gcry_mpi_ec_set_point(q=NULL) failed\n");
  err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
  if (gpg_err_code (err) != GPG_ERR_BAD_CRYPT_CTX)
    fail ("gcry_pubkey_get_sexp(0 w/o Q,d) returned wrong error: %s\n",
          gpg_strerror (err));
  gcry_sexp_release (sexp);


  gcry_mpi_point_release (Q);
  gcry_mpi_release (d);
  gcry_mpi_point_release (G);
  gcry_ctx_release (ctx);
}
예제 #5
0
/* This tests checks that the low-level EC API yields the same result
   as using the high level API.  The values have been taken from a
   test run using the high level API.  */
static void
basic_ec_math (void)
{
  gpg_error_t err;
  gcry_ctx_t ctx;
  gcry_mpi_t P, A;
  gcry_mpi_point_t G, Q;
  gcry_mpi_t d;
  gcry_mpi_t x, y, z;

  wherestr = "basic_ec_math";
  show ("checking basic math functions for EC\n");

  P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff");
  A = hex2mpi ("0xfffffffffffffffffffffffffffffffefffffffffffffffc");
  G = make_point ("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
                  "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
                  "1");
  d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
  Q = gcry_mpi_point_new (0);

  err = ec_p_new (&ctx, P, A);
  if (err)
    die ("ec_p_new failed: %s\n", gpg_strerror (err));

  x = gcry_mpi_new (0);
  y = gcry_mpi_new (0);
  z = gcry_mpi_new (0);

  {
    /* A quick check that multiply by zero works.  */
    gcry_mpi_t tmp;

    tmp = gcry_mpi_new (0);
    gcry_mpi_ec_mul (Q, tmp, G, ctx);
    gcry_mpi_release (tmp);
    gcry_mpi_point_get (x, y, z, Q);
    if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 0)
        || gcry_mpi_cmp_ui (z, 0))
      fail ("multiply a point by zero failed\n");
  }

  gcry_mpi_ec_mul (Q, d, G, ctx);
  gcry_mpi_point_get (x, y, z, Q);
  if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
      || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
      || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
    fail ("computed public key does not match\n");
  if (debug)
    {
      print_mpi ("Q.x", x);
      print_mpi ("Q.y", y);
      print_mpi ("Q.z", z);
    }

  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
    fail ("failed to get affine coordinates\n");
  if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
      || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
    fail ("computed affine coordinates of public key do not match\n");
  if (debug)
    {
      print_mpi ("q.x", x);
      print_mpi ("q.y", y);
    }

  gcry_mpi_release (z);
  gcry_mpi_release (y);
  gcry_mpi_release (x);
  gcry_mpi_point_release (Q);
  gcry_mpi_release (d);
  gcry_mpi_point_release (G);
  gcry_mpi_release (A);
  gcry_mpi_release (P);
  gcry_ctx_release (ctx);
}
예제 #6
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);
}
예제 #7
0
/*
 * Test iterative X25519 computation through lower layer MPI routines.
 *
 * Input: K (as hex string), ITER, R (as hex string)
 *
 * where R is expected result of iterating X25519 by ITER times.
 *
 */
static void
test_it (int testno, const char *k_str, int iter, const char *result_str)
{
  gcry_ctx_t ctx;
  gpg_error_t err;
  void *buffer = NULL;
  size_t buflen;
  gcry_mpi_t mpi_k = NULL;
  gcry_mpi_t mpi_x = NULL;
  gcry_mpi_point_t P = NULL;
  gcry_mpi_point_t Q;
  int i;
  gcry_mpi_t mpi_kk = NULL;

  if (verbose > 1)
    info ("Running test %d: iteration=%d\n", testno, iter);

  gcry_mpi_ec_new (&ctx, NULL, "Curve25519");
  Q = gcry_mpi_point_new (0);

  if (!(buffer = hex2buffer (k_str, &buflen)) || buflen != 32)
    {
      fail ("error scanning MPI for test %d, %s: %s",
            testno, "k", "invalid hex string");
      goto leave;
    }
  reverse_buffer (buffer, buflen);
  if ((err = gcry_mpi_scan (&mpi_x, GCRYMPI_FMT_USG, buffer, buflen, NULL)))
    {
      fail ("error scanning MPI for test %d, %s: %s",
            testno, "x", gpg_strerror (err));
      goto leave;
    }

  xfree (buffer);
  buffer = NULL;

  P = gcry_mpi_point_set (NULL, mpi_x, NULL, GCRYMPI_CONST_ONE);

  mpi_k = gcry_mpi_copy (mpi_x);
  if (debug)
    print_mpi ("k", mpi_k);

  for (i = 0; i < iter; i++)
    {
      /*
       * Another variant of decodeScalar25519 thing.
       */
      mpi_kk = gcry_mpi_set (mpi_kk, mpi_k);
      gcry_mpi_set_bit (mpi_kk, 254);
      gcry_mpi_clear_bit (mpi_kk, 255);
      gcry_mpi_clear_bit (mpi_kk, 0);
      gcry_mpi_clear_bit (mpi_kk, 1);
      gcry_mpi_clear_bit (mpi_kk, 2);

      gcry_mpi_ec_mul (Q, mpi_kk, P, ctx);

      P = gcry_mpi_point_set (P, mpi_k, NULL, GCRYMPI_CONST_ONE);
      gcry_mpi_ec_get_affine (mpi_k, NULL, Q, ctx);

      if (debug)
        print_mpi ("k", mpi_k);
    }

  {
    unsigned char res[32];
    char *r, *r0;

    gcry_mpi_print (GCRYMPI_FMT_USG, res, 32, NULL, mpi_k);
    reverse_buffer (res, 32);

    r0 = r = xmalloc (65);
    if (!r0)
      {
        fail ("memory allocation for test %d", testno);
        goto leave;
      }

    for (i=0; i < 32; i++, r += 2)
      snprintf (r, 3, "%02x", res[i]);

    if (strcmp (result_str, r0))
      {
        fail ("curv25519 failed for test %d: %s",
              testno, "wrong value returned");
        info ("  expected: '%s'", result_str);
        info ("       got: '%s'", r0);
      }
    xfree (r0);
  }

 leave:
  gcry_mpi_release (mpi_kk);
  gcry_mpi_release (mpi_k);
  gcry_mpi_point_release (P);
  gcry_mpi_release (mpi_x);
  xfree (buffer);
  gcry_mpi_point_release (Q);
  gcry_ctx_release (ctx);
}