diff --git a/ChangeLog b/ChangeLog
index 7031a01aeb2db91b3825fbfced45ff2cab983e99..10e19d04554e568465536afd2f726543c3e46d4a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2014-10-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* eddsa-verify.c (_eddsa_verify, eddsa_verify_itch): New file, new
+	functions.
+	* eddsa.h: Declare new functions.
+	* Makefile.in (hogweed_SOURCES): Added eddsa-verify.c.
+
 2014-10-08  Niels Möller  <nisse@lysator.liu.se>
 
 	* testsuite/eddsa-sign-test.c (test_eddsa_sign): Use
diff --git a/Makefile.in b/Makefile.in
index f3f2b38ca4766e36352f8d104cd9ff5d687ccb3b..7006211e1dfd70ac2710d36621295fc7401d977a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -177,7 +177,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  ecc-ecdsa-verify.c ecdsa-verify.c ecdsa-keygen.c \
 		  curve25519-mul-g.c curve25519-mul.c curve25519-eh-to-x.c \
 		  eddsa-compress.c eddsa-decompress.c eddsa-expand.c \
-		  eddsa-hash.c eddsa-sign.c \
+		  eddsa-hash.c eddsa-sign.c eddsa-verify.c \
 		  $(OPT_HOGWEED_SOURCES)
 
 HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \
diff --git a/eddsa-verify.c b/eddsa-verify.c
new file mode 100644
index 0000000000000000000000000000000000000000..85b751e94768e44873d4b684e772d665462c84f8
--- /dev/null
+++ b/eddsa-verify.c
@@ -0,0 +1,120 @@
+/* eddsa-verify.c
+
+   Copyright (C) 2014 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 <assert.h>
+
+#include "eddsa.h"
+
+#include "ecc.h"
+#include "ecc-internal.h"
+#include "nettle-meta.h"
+
+/* FIXME: Use mpn_zero_p. Also duplicated in ecc-ecdsa-verify.c. */
+static int
+zero_p (const mp_limb_t *xp, mp_size_t n)
+{
+  while (n > 0)
+    if (xp[--n] > 0)
+      return 0;
+  return 1;
+}
+
+mp_size_t
+_eddsa_verify_itch (const struct ecc_curve *ecc)
+{
+  return 8*ecc->p.size + ecc->mul_itch;
+}
+
+int
+_eddsa_verify (const struct ecc_curve *ecc,
+	       const struct nettle_hash *H,
+	       const uint8_t *pub,
+	       void *ctx,
+	       const mp_limb_t *A,
+	       size_t length,
+	       const uint8_t *msg,
+	       const uint8_t *signature,
+	       mp_limb_t *scratch)
+{
+  size_t nbytes;
+#define R scratch
+#define sp (scratch + 2*ecc->p.size)
+#define hp (scratch + 3*ecc->p.size)
+#define P (scratch + 5*ecc->p.size)
+#define scratch_out (scratch + 8*ecc->p.size)
+#define S R
+#define hash ((uint8_t *) P)
+
+  nbytes = 1 + ecc->p.bit_size / 8;
+
+  /* Could maybe save some storage by delaying the R and S operations,
+     but it makes sense to check them for validity up front. */
+  if (!_eddsa_decompress (ecc, R, signature, R+2*ecc->p.size))
+    return 0;
+
+  mpn_set_base256_le (sp, ecc->q.size, signature + nbytes, nbytes);
+  /* Check that s < q */
+  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_hash (&ecc->q, hp, hash);
+
+  /* Compute h A + R - s G, which should be the neutral point */
+  ecc->mul (ecc, P, hp, A, scratch_out);
+  /* FIXME: Introduce an ecc->add method? */
+  ecc_add_eh (ecc, P, P, R, scratch_out);
+  /* Produces s in the range 1 <= s <= q, with no carry. */
+  mpn_sub_n (hp, ecc->q.m, sp, ecc->q.size);
+  ecc->mul_g (ecc, S, hp, scratch_out);
+  ecc_add_ehh (ecc, P, P, S, scratch_out);
+
+  /* Zero point iff x == 0 (mod p) iff (x == 0 or x == p) */
+  /* FIXME: Needs to differentiate between (0,1) and (0,-1). Implement
+     point compare instead of the above ecc_add_ehh?
+  /* FIXME: Introduce zero_p method? */
+  return (zero_p (P, ecc->p.size)
+	  || mpn_cmp (P, ecc->p.m, ecc->p.size) == 0);
+
+#undef R
+#undef sp
+#undef hp
+#undef P
+#undef S
+}
diff --git a/eddsa.h b/eddsa.h
index d368432bcd5e9522246a98839763e9ab0828dbf7..582e969b850eb037c306281d5531d1f69207b8b9 100644
--- a/eddsa.h
+++ b/eddsa.h
@@ -50,6 +50,8 @@ extern "C" {
 #define _eddsa_expand_key _nettle_eddsa_expand_key
 #define _eddsa_sign _nettle_eddsa_sign
 #define _eddsa_sign_itch _nettle_eddsa_sign_itch
+#define _eddsa_verify _nettle_eddsa_verify
+#define _eddsa_verify_itch _nettle_eddsa_verify_itch
 
 #define ED25519_KEY_SIZE 32
 
@@ -87,6 +89,20 @@ _eddsa_sign (const struct ecc_curve *ecc,
 	     uint8_t *signature,
 	     mp_limb_t *scratch);
 
+mp_size_t
+_eddsa_verify_itch (const struct ecc_curve *ecc);
+
+int
+_eddsa_verify (const struct ecc_curve *ecc,
+	       const struct nettle_hash *H,
+	       const uint8_t *pub,
+	       void *ctx,
+	       const mp_limb_t *A,
+	       size_t length,
+	       const uint8_t *msg,
+	       const uint8_t *signature,
+	       mp_limb_t *scratch);
+
 mp_size_t
 _eddsa_expand_key_itch (const struct ecc_curve *ecc);