diff --git a/ChangeLog b/ChangeLog
index 04a5dc6ac081dafbd8275a07751becc4dd6167a7..54a5a3468e382a920de0a2f36bf6b59c73a758ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2019-12-30  Niels Möller  <nisse@lysator.liu.se>
+
+	Preparation for ed448, based on patch by Daiki Ueno.
+	* eddsa-internal.h (struct ecc_eddsa): New struct for eddsa
+	parameters.
+	* ed25519-sha512.c (_nettle_ed25519_sha512): New parameter struct.
+	* eddsa-expand.c (_eddsa_expand_key): Replace input
+	struct nettle_hash with struct ecc_eddsa, and generalize for
+	ed448. Update all callers.
+	* eddsa-sign.c (_eddsa_sign): Likewise.
+	* eddsa-verify.c (_eddsa_verify): Likewise.
+	* eddsa-compress.c (_eddsa_compress): Store sign bit in most
+	significant bit of last byte, as specified by RFC 8032.
+	* eddsa-decompress.c (_eddsa_decompress): Corresponding update.
+	Also generalize to support ed448, and make validity checks
+	stricter.
+	* testsuite/eddsa-sign-test.c (test_ed25519_sign): New function.
+	(test_main): Use it.
+	* testsuite/eddsa-verify-test.c (test_ed25519): New function.
+	(test_main): Use it.
+
 2019-12-28  Niels Möller  <nisse@lysator.liu.se>
 
 	* bignum.h: Drop unreleted include of nettle-meta.h.
diff --git a/Makefile.in b/Makefile.in
index 412572f6a78779c91cf47810ea0eecf9aeed9d38..162b50b1c28eb7c6088e57027b0c50a0c6e2c214 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -191,7 +191,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  curve448-mul-g.c curve448-mul.c curve448-eh-to-x.c \
 		  eddsa-compress.c eddsa-decompress.c eddsa-expand.c \
 		  eddsa-hash.c eddsa-pubkey.c eddsa-sign.c eddsa-verify.c \
-		  ed25519-sha512-pubkey.c \
+		  ed25519-sha512.c ed25519-sha512-pubkey.c \
 		  ed25519-sha512-sign.c ed25519-sha512-verify.c
 
 OPT_SOURCES = fat-x86_64.c fat-arm.c mini-gmp.c
diff --git a/ed25519-sha512-pubkey.c b/ed25519-sha512-pubkey.c
index 7afb1ccd9714a8fb7706118cea45ec2e51678876..b4dfd1e01afeadbbb35b528c344ae7ebf2c73014 100644
--- a/ed25519-sha512-pubkey.c
+++ b/ed25519-sha512-pubkey.c
@@ -50,8 +50,8 @@ ed25519_sha512_public_key (uint8_t *pub, const uint8_t *priv)
 
 #define k scratch
 #define scratch_out (scratch + ecc->q.size)
-
-  _eddsa_expand_key (ecc, &nettle_sha512, &ctx, priv, digest, k);
+  sha512_init (&ctx);
+  _eddsa_expand_key (ecc, &_nettle_ed25519_sha512, &ctx, priv, digest, k);
   _eddsa_public_key (ecc, k, pub, scratch_out);
 
   gmp_free_limbs (scratch, itch);
diff --git a/ed25519-sha512-sign.c b/ed25519-sha512-sign.c
index 84cb1698a9d09f34ad8c34fe07d12c82cc4a8f7d..0205e6f0b0996b53d6eadb2ac47b25edaadbb170 100644
--- a/ed25519-sha512-sign.c
+++ b/ed25519-sha512-sign.c
@@ -53,11 +53,11 @@ ed25519_sha512_sign (const uint8_t *pub,
   struct sha512_ctx ctx;
   uint8_t digest[SHA512_DIGEST_SIZE];
 #define k1 (digest + ED25519_KEY_SIZE)
-
-  _eddsa_expand_key (ecc, &nettle_sha512, &ctx, priv, digest, k2);
+  sha512_init (&ctx);
+  _eddsa_expand_key (ecc, &_nettle_ed25519_sha512, &ctx, priv, digest, k2);
 
   sha512_update (&ctx, ED25519_KEY_SIZE, k1);
-  _eddsa_sign (ecc, &nettle_sha512, pub,
+  _eddsa_sign (ecc, &_nettle_ed25519_sha512, pub,
 	       &ctx,
 	       k2, length, msg, signature, scratch_out);
 
diff --git a/ed25519-sha512-verify.c b/ed25519-sha512-verify.c
index 1d6a8c2297422b0883485a84ab5e8a76c84719fa..bb90d0a1a75b4c7bbec588d75dc0db599e81e5a5 100644
--- a/ed25519-sha512-verify.c
+++ b/ed25519-sha512-verify.c
@@ -53,9 +53,11 @@ ed25519_sha512_verify (const uint8_t *pub,
   int res;
 #define A scratch
 #define scratch_out (scratch + 3*ecc->p.size)
+
+  sha512_init (&ctx);
   res = (_eddsa_decompress (ecc,
 			    A, pub, scratch_out)
-	 && _eddsa_verify (ecc, &nettle_sha512,
+	 && _eddsa_verify (ecc, &_nettle_ed25519_sha512,
 			   pub, A, &ctx,
 			   length, msg, signature,
 			   scratch_out));
diff --git a/ed25519-sha512.c b/ed25519-sha512.c
new file mode 100644
index 0000000000000000000000000000000000000000..c1dd683141e320e647a1e411df42aa7efcba0220
--- /dev/null
+++ b/ed25519-sha512.c
@@ -0,0 +1,47 @@
+/* ed25519-sha512.c
+
+   Copyright (C) 2019 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "eddsa-internal.h"
+
+#include "nettle-types.h"
+#include "sha2.h"
+
+const struct ecc_eddsa _nettle_ed25519_sha512 =
+  {
+    (nettle_hash_update_func *) sha512_update,
+    (nettle_hash_digest_func *) sha512_digest,
+    ~(mp_limb_t) 7,
+    (mp_limb_t) 1 << (254 % GMP_NUMB_BITS),
+  };
diff --git a/eddsa-compress.c b/eddsa-compress.c
index 547ba736dc7b4cdaa8dea83b840092b6b1867a5d..afa67195df3314ea2a43ecebd422144c5a5b239e 100644
--- a/eddsa-compress.c
+++ b/eddsa-compress.c
@@ -53,11 +53,11 @@ _eddsa_compress (const struct ecc_curve *ecc, uint8_t *r, mp_limb_t *p,
 #define yp (scratch + ecc->p.size)
 #define scratch_out (scratch + 2*ecc->p.size)
 
+  size_t nbytes = 1 + ecc->p.bit_size / 8;
   ecc->h_to_a (ecc, 0, xp, p, scratch_out);
   /* Encoding is the y coordinate and an appended "sign" bit, which is
-     the low bit of x. Bit order is not specified explicitly, but for
-     little-endian encoding, it makes most sense to append the bit
-     after the most significant bit of y. */
-  mpn_get_base256_le (r, 1 + ecc->p.bit_size / 8, yp, ecc->p.size);
-  r[ecc->p.bit_size / 8] += (xp[0] & 1) << (ecc->p.bit_size & 7);
+     the low bit of x. The sign bit is stored as the most significant
+     bit of the last byte. */
+  mpn_get_base256_le (r, nbytes, yp, ecc->p.size);
+  r[nbytes - 1] += (xp[0] & 1) << 7;
 }
diff --git a/eddsa-decompress.c b/eddsa-decompress.c
index f114b576fffe8827de8d18c25e4ca0016e0156f7..441ccfbfb18a0e0dc8797bdd481f62fd1b8bd878 100644
--- a/eddsa-decompress.c
+++ b/eddsa-decompress.c
@@ -33,6 +33,8 @@
 # include "config.h"
 #endif
 
+#include <assert.h>
+
 #include "eddsa.h"
 #include "eddsa-internal.h"
 
@@ -51,6 +53,8 @@ _eddsa_decompress (const struct ecc_curve *ecc, mp_limb_t *p,
 		   mp_limb_t *scratch)
 {
   mp_limb_t sign, cy;
+  mp_size_t nlimbs;
+  size_t nbytes;
   int res;
 
 #define xp p
@@ -62,23 +66,46 @@ _eddsa_decompress (const struct ecc_curve *ecc, mp_limb_t *p,
 #define tp (scratch + 2*ecc->p.size)
 #define scratch_out (scratch + 4*ecc->p.size)
 
-  sign = cp[ecc->p.bit_size / 8] >> (ecc->p.bit_size & 7);
-  if (sign > 1)
-    return 0;
-  mpn_set_base256_le (yp, ecc->p.size, cp, 1 + ecc->p.bit_size / 8);
-  /* Clear out the sign bit (if it fits) */
-  yp[ecc->p.size - 1] &= ~(mp_limb_t) 0
-    >> (ecc->p.size * GMP_NUMB_BITS - ecc->p.bit_size);
+  nbytes = 1 + ecc->p.bit_size / 8;
+  /* By RFC 8032, sign bit is always the most significant bit of the
+     last byte. */
+  sign = cp[nbytes-1] >> 7;
+
+  /* May need an extra limb. */
+  nlimbs = (nbytes * 8 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
+  assert (nlimbs <= ecc->p.size + 1);
+  mpn_set_base256_le (scratch, nlimbs, cp, nbytes);
+
+  /* Clear out the sign bit */
+  scratch[nlimbs - 1] &=
+    ((mp_limb_t) 1 << ((nbytes * 8 - 1) % GMP_NUMB_BITS)) - 1;
+  mpn_copyi (yp, scratch, ecc->p.size);
+
+  /* Check range. */
+  if (nlimbs > ecc->p.size)
+    res = (scratch[nlimbs - 1] == 0);
+  else
+    res = 1;
+
+  /* For a valid input, y < p, so subtraction should underflow. */
+  res &= mpn_sub_n (scratch, scratch, ecc->p.m, ecc->p.size);
+
   ecc_modp_sqr (ecc, y2, yp);
   ecc_modp_mul (ecc, vp, y2, ecc->b);
   ecc_modp_sub (ecc, vp, vp, ecc->unit);
-  ecc_modp_sub (ecc, up, ecc->unit, y2);
-  res = ecc->p.sqrt (&ecc->p, tp, up, vp, scratch_out);
+  /* The sign is different between curve25519 and curve448.  */
+  if (ecc->p.bit_size == 255)
+    ecc_modp_sub (ecc, up, ecc->unit, y2);
+  else
+    ecc_modp_sub (ecc, up, y2, ecc->unit);
+  res &= ecc->p.sqrt (&ecc->p, tp, up, vp, scratch_out);
 
   cy = mpn_sub_n (xp, tp, ecc->p.m, ecc->p.size);
   cnd_copy (cy, xp, tp, ecc->p.size);
   sign ^= xp[0] & 1;
   mpn_sub_n (tp, ecc->p.m, xp, ecc->p.size);
   cnd_copy (sign, xp, tp, ecc->p.size);
+  /* Fails if the square root is zero but (original) sign was 1 */
+  res &= mpn_sub_n (tp, xp, ecc->p.m, ecc->p.size);
   return res;
 }
diff --git a/eddsa-expand.c b/eddsa-expand.c
index 62a6437811acee47d927875a2cfbf78d0c8cdb4a..ca7fe717fe6110c2176c11512776fb8f3117dd43 100644
--- a/eddsa-expand.c
+++ b/eddsa-expand.c
@@ -41,13 +41,12 @@
 
 #include "ecc.h"
 #include "ecc-internal.h"
-#include "nettle-meta.h"
 
 /* Expands a private key, generating the secret scalar K2 and leaving
    the key K1 for nonce generation, at the end of the digest. */
 void
 _eddsa_expand_key (const struct ecc_curve *ecc,
-		   const struct nettle_hash *H,
+		   const struct ecc_eddsa *eddsa,
 		   void *ctx,
 		   const uint8_t *key,
 		   uint8_t *digest,
@@ -55,19 +54,19 @@ _eddsa_expand_key (const struct ecc_curve *ecc,
 {
   size_t nbytes = 1 + ecc->p.bit_size / 8;
 
-  assert (H->digest_size >= 2*nbytes);
-
-  H->init (ctx);
-  H->update (ctx, nbytes, key);
-  H->digest (ctx, 2*nbytes, digest);
-
-  mpn_set_base256_le (k2, ecc->p.size, digest, nbytes);
-  /* Clear low 3 bits */
-  k2[0] &= ~(mp_limb_t) 7;
-  /* Set bit number bit_size - 1 (bit 254 for curve25519) */
-  k2[(ecc->p.bit_size - 1) / GMP_NUMB_BITS]
-    |= (mp_limb_t) 1 << ((ecc->p.bit_size - 1) % GMP_NUMB_BITS);
-  /* Clear any higher bits. */
-  k2[ecc->p.size - 1] &= ~(mp_limb_t) 0
-    >> (GMP_NUMB_BITS * ecc->p.size - ecc->p.bit_size);
+  eddsa->update (ctx, nbytes, key);
+  eddsa->digest (ctx, 2*nbytes, digest);
+
+  /* For ed448, ignores the most significant byte. */
+  mpn_set_base256_le (k2, ecc->p.size, digest, (ecc->p.bit_size + 7) / 8);
+
+  /* Clear low c bits */
+  k2[0] &= eddsa->low_mask;
+
+  /* Clear higher bits. */
+  k2[ecc->p.size - 1] &= eddsa->high_bit - 1;
+
+  /* Set bit number bit_size - 1 (bit 254 for curve25519, bit 447 for
+     curve448) */
+  k2[ecc->p.size - 1] |= eddsa->high_bit;
 }
diff --git a/eddsa-internal.h b/eddsa-internal.h
index f0d357f64aaf8eadb7d511b68ed72c005846a766..9c0a1eca8fc71a8e9d6ca4faa87b731872154f33 100644
--- a/eddsa-internal.h
+++ b/eddsa-internal.h
@@ -33,7 +33,7 @@
 #define NETTLE_EDDSA_INTERNAL_H
 
 #include "nettle-types.h"
-#include "nettle-meta.h"
+#include "bignum.h"
 
 #define _eddsa_compress _nettle_eddsa_compress
 #define _eddsa_compress_itch _nettle_eddsa_compress_itch
@@ -53,6 +53,18 @@
 struct ecc_curve;
 struct ecc_modulo;
 
+struct ecc_eddsa
+{
+  /* Hash function to use */
+  nettle_hash_update_func *update;
+  nettle_hash_digest_func *digest;
+  /* For generating the secret scalar */
+  mp_limb_t low_mask;
+  mp_limb_t high_bit;
+};
+
+extern const struct ecc_eddsa _nettle_ed25519_sha512;
+
 mp_size_t
 _eddsa_compress_itch (const struct ecc_curve *ecc);
 void
@@ -75,7 +87,7 @@ _eddsa_sign_itch (const struct ecc_curve *ecc);
 
 void
 _eddsa_sign (const struct ecc_curve *ecc,
-	     const struct nettle_hash *H,
+	     const struct ecc_eddsa *eddsa,
 	     const uint8_t *pub,
 	     void *ctx,
 	     const mp_limb_t *k2,
@@ -89,7 +101,7 @@ _eddsa_verify_itch (const struct ecc_curve *ecc);
 
 int
 _eddsa_verify (const struct ecc_curve *ecc,
-	       const struct nettle_hash *H,
+	       const struct ecc_eddsa *eddsa,
 	       const uint8_t *pub,
 	       const mp_limb_t *A,
 	       void *ctx,
@@ -100,7 +112,7 @@ _eddsa_verify (const struct ecc_curve *ecc,
 
 void
 _eddsa_expand_key (const struct ecc_curve *ecc,
-		   const struct nettle_hash *H,
+		   const struct ecc_eddsa *eddsa,
 		   void *ctx,
 		   const uint8_t *key,
 		   uint8_t *digest,
diff --git a/eddsa-sign.c b/eddsa-sign.c
index 13ae47995e74b217202954d9f9e69627926cbdfc..5e39fe6906219825f0ccc813dc679d8743f0773e 100644
--- a/eddsa-sign.c
+++ b/eddsa-sign.c
@@ -50,7 +50,7 @@ _eddsa_sign_itch (const struct ecc_curve *ecc)
 
 void
 _eddsa_sign (const struct ecc_curve *ecc,
-	     const struct nettle_hash *H,
+	     const struct ecc_eddsa *eddsa,
 	     const uint8_t *pub,
 	     void *ctx,
 	     const mp_limb_t *k2,
@@ -71,18 +71,16 @@ _eddsa_sign (const struct ecc_curve *ecc,
   size = ecc->p.size;
   nbytes = 1 + ecc->p.bit_size / 8;
 
-  assert (H->digest_size >= 2 * nbytes);
-
-  H->update (ctx, length, msg);
-  H->digest (ctx, 2*nbytes, hash);
+  eddsa->update (ctx, length, msg);
+  eddsa->digest (ctx, 2*nbytes, hash);
   _eddsa_hash (&ecc->q, rp, hash);
   ecc->mul_g (ecc, P, rp, scratch_out);
   _eddsa_compress (ecc, signature, P, scratch_out);
 
-  H->update (ctx, nbytes, signature);
-  H->update (ctx, nbytes, pub);
-  H->update (ctx, length, msg);
-  H->digest (ctx, 2*nbytes, hash);
+  eddsa->update (ctx, nbytes, signature);
+  eddsa->update (ctx, nbytes, pub);
+  eddsa->update (ctx, length, msg);
+  eddsa->digest (ctx, 2*nbytes, hash);
   _eddsa_hash (&ecc->q, hp, hash);
 
   ecc_modq_mul (ecc, sp, hp, k2);
diff --git a/eddsa-verify.c b/eddsa-verify.c
index 8a623562057d4dd52f622e765d4519bfc2eb16e3..e482c9b99c0eb8d1d085cd6d1c5d754f1281e359 100644
--- a/eddsa-verify.c
+++ b/eddsa-verify.c
@@ -70,12 +70,13 @@ equal_h (const struct ecc_modulo *p,
 mp_size_t
 _eddsa_verify_itch (const struct ecc_curve *ecc)
 {
+  assert (_eddsa_decompress_itch (ecc) <= ecc->mul_itch);
   return 8*ecc->p.size + ecc->mul_itch;
 }
 
 int
 _eddsa_verify (const struct ecc_curve *ecc,
-	       const struct nettle_hash *H,
+	       const struct ecc_eddsa *eddsa,
 	       const uint8_t *pub,
 	       const mp_limb_t *A,
 	       void *ctx,
@@ -105,11 +106,10 @@ _eddsa_verify (const struct ecc_curve *ecc,
   if (mpn_cmp (sp, ecc->q.m, ecc->q.size) >= 0)
     return 0;
 
-  H->init (ctx);
-  H->update (ctx, nbytes, signature);
-  H->update (ctx, nbytes, pub);
-  H->update (ctx, length, msg);
-  H->digest (ctx, 2*nbytes, hash);
+  eddsa->update (ctx, nbytes, signature);
+  eddsa->update (ctx, nbytes, pub);
+  eddsa->update (ctx, length, msg);
+  eddsa->digest (ctx, 2*nbytes, hash);
   _eddsa_hash (&ecc->q, hp, hash);
 
   /* Compute h A + R - s G, which should be the neutral point */
diff --git a/testsuite/eddsa-sign-test.c b/testsuite/eddsa-sign-test.c
index c1da82282a7b73778c50be4edb8c7071bba43404..4cfc4dbb192188738b9483e1a1bfa2a390d269a0 100644
--- a/testsuite/eddsa-sign-test.c
+++ b/testsuite/eddsa-sign-test.c
@@ -36,7 +36,8 @@
 
 static void
 test_eddsa_sign (const struct ecc_curve *ecc,
-		 const struct nettle_hash *H,
+		 const struct ecc_eddsa *eddsa,
+		 void *ctx,
 		 const struct tstring *public,
 		 const struct tstring *private,
 		 const struct tstring *msg,
@@ -45,7 +46,6 @@ test_eddsa_sign (const struct ecc_curve *ecc,
   mp_limb_t *scratch = xalloc_limbs (_eddsa_sign_itch (ecc));
   size_t nbytes = 1 + ecc->p.bit_size / 8;
   uint8_t *signature = xalloc (2*nbytes);
-  void *ctx = xalloc (H->context_size);
   uint8_t *public_out = xalloc (nbytes);
   uint8_t *digest = xalloc (2*nbytes);
   const uint8_t *k1 = digest + nbytes;
@@ -55,7 +55,7 @@ test_eddsa_sign (const struct ecc_curve *ecc,
   ASSERT (private->length == nbytes);
   ASSERT (ref->length == 2*nbytes);
 
-  _eddsa_expand_key (ecc, H, ctx, private->data,
+  _eddsa_expand_key (ecc, eddsa, ctx, private->data,
 		     digest, k2);
   _eddsa_public_key (ecc, k2, public_out, scratch);
 
@@ -69,9 +69,9 @@ test_eddsa_sign (const struct ecc_curve *ecc,
       fprintf (stderr, "\n");
       abort ();
     }
-  H->update (ctx, nbytes, k1);
+  eddsa->update (ctx, nbytes, k1);
   
-  _eddsa_sign (ecc, H, public->data, ctx, k2,
+  _eddsa_sign (ecc, eddsa, public->data, ctx, k2,
 	       msg->length, msg->data, signature, scratch);
 
   if (!MEMEQ (2*nbytes, signature, ref->data))
@@ -95,50 +95,60 @@ test_eddsa_sign (const struct ecc_curve *ecc,
   
   free (scratch);
   free (signature);
-  free (ctx);
   free (digest);
   free (k2);
   free (public_out);
 }
 
-void test_main (void)
+static void
+test_ed25519_sign (const struct tstring *public,
+		   const struct tstring *private,
+		   const struct tstring *msg,
+		   const struct tstring *ref)
+{
+  struct sha512_ctx ctx;
+
+  sha512_init (&ctx);
+  test_eddsa_sign (&_nettle_curve25519, &_nettle_ed25519_sha512, &ctx,
+		   public, private, msg, ref);
+}
+
+void
+test_main (void)
 {
   /* Based on a few of the test vectors at
      http://ed25519.cr.yp.to/python/sign.input */
-  test_eddsa_sign (&_nettle_curve25519, &nettle_sha512,
-		   SHEX("d75a980182b10ab7 d54bfed3c964073a"
-			"0ee172f3daa62325 af021a68f707511a"),
-		   SHEX("9d61b19deffd5a60 ba844af492ec2cc4"
-			"4449c5697b326919 703bac031cae7f60"),
-		   SHEX(""),
-		   SHEX("e5564300c360ac72 9086e2cc806e828a"
-			"84877f1eb8e5d974 d873e06522490155"
-			"5fb8821590a33bac c61e39701cf9b46b"
-			"d25bf5f0595bbe24 655141438e7a100b"));
-  test_eddsa_sign (&_nettle_curve25519, &nettle_sha512,
-		   SHEX("3d4017c3e843895a 92b70aa74d1b7ebc"
-			"9c982ccf2ec4968c c0cd55f12af4660c"),
-		   SHEX("4ccd089b28ff96da 9db6c346ec114e0f"
-			"5b8a319f35aba624 da8cf6ed4fb8a6fb"),
-		   SHEX("72"),
-		   SHEX("92a009a9f0d4cab8 720e820b5f642540"
-			"a2b27b5416503f8f b3762223ebdb69da"
-			"085ac1e43e15996e 458f3613d0f11d8c"
-			"387b2eaeb4302aee b00d291612bb0c00"));
-  test_eddsa_sign (&_nettle_curve25519, &nettle_sha512,
-		   SHEX("1ed506485b09a645 0be7c9337d9fe87e"
-			"f99c96f8bd11cd63 1ca160d0fd73067e"),
-		   SHEX("f215d34fe2d757cf f9cf5c05430994de"
-			"587987ce45cb0459 f61ec6c825c62259"),
-		   SHEX("fbed2a7df418ec0e 8036312ec239fcee"
-			"6ef97dc8c2df1f2e 14adee287808b788"
-			"a6072143b851d975 c8e8a0299df846b1"
-			"9113e38cee83da71 ea8e9bd6f57bdcd3"
-			"557523f4feb616ca a595aea01eb0b3d4"
-			"90b99b525ea4fbb9 258bc7fbb0deea8f"
-			"568cb2"),
-		   SHEX("cbef65b6f3fd5809 69fc3340cfae4f7c"
-			"99df1340cce54626 183144ef46887163"
-			"4b0a5c0033534108 e1c67c0dc99d3014"
-			"f01084e98c95e101 4b309b1dbb2e6704"));
+  test_ed25519_sign (SHEX("d75a980182b10ab7 d54bfed3c964073a"
+			  "0ee172f3daa62325 af021a68f707511a"),
+		     SHEX("9d61b19deffd5a60 ba844af492ec2cc4"
+			  "4449c5697b326919 703bac031cae7f60"),
+		     SHEX(""),
+		     SHEX("e5564300c360ac72 9086e2cc806e828a"
+			  "84877f1eb8e5d974 d873e06522490155"
+			  "5fb8821590a33bac c61e39701cf9b46b"
+			  "d25bf5f0595bbe24 655141438e7a100b"));
+  test_ed25519_sign (SHEX("3d4017c3e843895a 92b70aa74d1b7ebc"
+			  "9c982ccf2ec4968c c0cd55f12af4660c"),
+		     SHEX("4ccd089b28ff96da 9db6c346ec114e0f"
+			  "5b8a319f35aba624 da8cf6ed4fb8a6fb"),
+		     SHEX("72"),
+		     SHEX("92a009a9f0d4cab8 720e820b5f642540"
+			  "a2b27b5416503f8f b3762223ebdb69da"
+			  "085ac1e43e15996e 458f3613d0f11d8c"
+			  "387b2eaeb4302aee b00d291612bb0c00"));
+  test_ed25519_sign (SHEX("1ed506485b09a645 0be7c9337d9fe87e"
+			  "f99c96f8bd11cd63 1ca160d0fd73067e"),
+		     SHEX("f215d34fe2d757cf f9cf5c05430994de"
+			  "587987ce45cb0459 f61ec6c825c62259"),
+		     SHEX("fbed2a7df418ec0e 8036312ec239fcee"
+			  "6ef97dc8c2df1f2e 14adee287808b788"
+			  "a6072143b851d975 c8e8a0299df846b1"
+			  "9113e38cee83da71 ea8e9bd6f57bdcd3"
+			  "557523f4feb616ca a595aea01eb0b3d4"
+			  "90b99b525ea4fbb9 258bc7fbb0deea8f"
+			  "568cb2"),
+		     SHEX("cbef65b6f3fd5809 69fc3340cfae4f7c"
+			  "99df1340cce54626 183144ef46887163"
+			  "4b0a5c0033534108 e1c67c0dc99d3014"
+			  "f01084e98c95e101 4b309b1dbb2e6704"));
 }
diff --git a/testsuite/eddsa-verify-test.c b/testsuite/eddsa-verify-test.c
index 770080591b1318ea69fea08f37c289059650aa0c..595fa4044739f1e2bb79ca865538f46bf3d4c1fa 100644
--- a/testsuite/eddsa-verify-test.c
+++ b/testsuite/eddsa-verify-test.c
@@ -36,7 +36,8 @@
 
 static void
 test_eddsa (const struct ecc_curve *ecc,
-	    const struct nettle_hash *H,
+	    const struct ecc_eddsa *eddsa,
+	    void *ctx,
 	    const uint8_t *pub,
 	    const struct tstring *msg,
 	    const uint8_t *signature)
@@ -46,13 +47,12 @@ test_eddsa (const struct ecc_curve *ecc,
   size_t nbytes = 1 + ecc->p.bit_size / 8;
   uint8_t *cmsg = xalloc (msg->length);
   uint8_t *csignature = xalloc (2*nbytes);
-  void *ctx = xalloc (H->context_size);
 
   if (!_eddsa_decompress (ecc, A, pub, scratch))
     die ("Invalid eddsa public key.\n");
 
   memcpy (csignature, signature, 2*nbytes);
-  if (!_eddsa_verify (ecc, H, pub, A, ctx,
+  if (!_eddsa_verify (ecc, eddsa, pub, A, ctx,
 		      msg->length, msg->data, csignature, scratch))
     {
       fprintf (stderr, "eddsa_verify failed with valid signature.\n");
@@ -69,7 +69,7 @@ test_eddsa (const struct ecc_curve *ecc,
 
   memcpy (csignature, signature, 2*nbytes);
   csignature[nbytes/3] ^= 0x40;
-  if (_eddsa_verify (ecc, H, pub, A, ctx,
+  if (_eddsa_verify (ecc, eddsa, pub, A, ctx,
 		     msg->length, msg->data, csignature, scratch))
     {
       fprintf (stderr,
@@ -80,7 +80,7 @@ test_eddsa (const struct ecc_curve *ecc,
   memcpy (csignature, signature, 2*nbytes);
   csignature[5*nbytes/3] ^= 0x8;
 
-  if (_eddsa_verify (ecc, H, pub, A, ctx,
+  if (_eddsa_verify (ecc, eddsa, pub, A, ctx,
 		     msg->length, msg->data, csignature, scratch))
     {
       fprintf (stderr,
@@ -90,7 +90,7 @@ test_eddsa (const struct ecc_curve *ecc,
 
   if (msg->length == 0)
     {
-      if (_eddsa_verify  (ecc, H, pub, A, ctx,
+      if (_eddsa_verify  (ecc, eddsa, pub, A, ctx,
 			  LDATA("foo"), signature, scratch))
 	{
 	  fprintf (stderr,
@@ -100,7 +100,7 @@ test_eddsa (const struct ecc_curve *ecc,
     }
   else
     {
-      if (_eddsa_verify  (ecc, H, pub, A, ctx,
+      if (_eddsa_verify  (ecc, eddsa, pub, A, ctx,
 			  msg->length - 1, msg->data,
 			  signature, scratch))
 	{
@@ -110,7 +110,7 @@ test_eddsa (const struct ecc_curve *ecc,
 	}
       memcpy (cmsg, msg->data, msg->length);
       cmsg[2*msg->length / 3] ^= 0x20;
-      if (_eddsa_verify  (ecc, H, pub, A, ctx,
+      if (_eddsa_verify  (ecc, eddsa, pub, A, ctx,
 			  msg->length, cmsg, signature, scratch))
 	{
 	  fprintf (stderr,
@@ -122,40 +122,49 @@ test_eddsa (const struct ecc_curve *ecc,
   free (scratch);
   free (cmsg);
   free (csignature);
-  free (ctx);
 }
 
+static void
+test_ed25519 (const uint8_t *pub,
+	      const struct tstring *msg,
+	      const uint8_t *signature)
+{
+  struct sha512_ctx ctx;
+
+  sha512_init (&ctx);
+  test_eddsa (&_nettle_curve25519, &_nettle_ed25519_sha512, &ctx,
+	      pub, msg, signature);
+}
+
+
 void
 test_main (void)
 {
-  test_eddsa (&_nettle_curve25519, &nettle_sha512,
-	      H("d75a980182b10ab7 d54bfed3c964073a"
-		"0ee172f3daa62325 af021a68f707511a"),
-	      SHEX(""),
-	      H("e5564300c360ac72 9086e2cc806e828a"
-		"84877f1eb8e5d974 d873e06522490155"
-		"5fb8821590a33bac c61e39701cf9b46b"
-		"d25bf5f0595bbe24 655141438e7a100b"));
-  test_eddsa (&_nettle_curve25519, &nettle_sha512,
-	      H("3d4017c3e843895a 92b70aa74d1b7ebc"
-		"9c982ccf2ec4968c c0cd55f12af4660c"),
-	      SHEX("72"),
-	      H("92a009a9f0d4cab8 720e820b5f642540"
-		"a2b27b5416503f8f b3762223ebdb69da"
-		"085ac1e43e15996e 458f3613d0f11d8c"
-		"387b2eaeb4302aee b00d291612bb0c00"));
-  test_eddsa (&_nettle_curve25519, &nettle_sha512,
-	      H("1ed506485b09a645 0be7c9337d9fe87e"
-		"f99c96f8bd11cd63 1ca160d0fd73067e"),
-	      SHEX("fbed2a7df418ec0e 8036312ec239fcee"
-		   "6ef97dc8c2df1f2e 14adee287808b788"
-		   "a6072143b851d975 c8e8a0299df846b1"
-		   "9113e38cee83da71 ea8e9bd6f57bdcd3"
-		   "557523f4feb616ca a595aea01eb0b3d4"
-		   "90b99b525ea4fbb9 258bc7fbb0deea8f"
-		   "568cb2"),
-	      H("cbef65b6f3fd5809 69fc3340cfae4f7c"
-		"99df1340cce54626 183144ef46887163"
-		"4b0a5c0033534108 e1c67c0dc99d3014"
-		"f01084e98c95e101 4b309b1dbb2e6704"));
+  test_ed25519 (H("d75a980182b10ab7 d54bfed3c964073a"
+		  "0ee172f3daa62325 af021a68f707511a"),
+		SHEX(""),
+		H("e5564300c360ac72 9086e2cc806e828a"
+		  "84877f1eb8e5d974 d873e06522490155"
+		  "5fb8821590a33bac c61e39701cf9b46b"
+		  "d25bf5f0595bbe24 655141438e7a100b"));
+  test_ed25519 (H("3d4017c3e843895a 92b70aa74d1b7ebc"
+		  "9c982ccf2ec4968c c0cd55f12af4660c"),
+		SHEX("72"),
+		H("92a009a9f0d4cab8 720e820b5f642540"
+		  "a2b27b5416503f8f b3762223ebdb69da"
+		  "085ac1e43e15996e 458f3613d0f11d8c"
+		  "387b2eaeb4302aee b00d291612bb0c00"));
+  test_ed25519 (H("1ed506485b09a645 0be7c9337d9fe87e"
+		  "f99c96f8bd11cd63 1ca160d0fd73067e"),
+		SHEX("fbed2a7df418ec0e 8036312ec239fcee"
+		     "6ef97dc8c2df1f2e 14adee287808b788"
+		     "a6072143b851d975 c8e8a0299df846b1"
+		     "9113e38cee83da71 ea8e9bd6f57bdcd3"
+		     "557523f4feb616ca a595aea01eb0b3d4"
+		     "90b99b525ea4fbb9 258bc7fbb0deea8f"
+		     "568cb2"),
+		H("cbef65b6f3fd5809 69fc3340cfae4f7c"
+		  "99df1340cce54626 183144ef46887163"
+		  "4b0a5c0033534108 e1c67c0dc99d3014"
+		  "f01084e98c95e101 4b309b1dbb2e6704"));
 }