diff --git a/ChangeLog b/ChangeLog
index 879011c380965e1cea0bbcd90e0bf4c2741df921..639ad9a07ba2a2c1f6bfa4ae19cff48bbf45fd61 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2014-08-24  Niels Möller  <nisse@lysator.liu.se>
 
+	* testsuite/ecdh-test.c: Test ecc_point_mul and ecc_point_mul_g,
+	using test data generated by ecc-ref.gp.
+	* testsuite/Makefile.in (TS_HOGWEED_SOURCES): Added ecdh-test.c.
+
 	* misc/ecc-ref.gp: Script to generate ECDH test data.
 
 2014-08-23  Niels Möller  <nisse@lysator.liu.se>
diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make
index 88e48d0341bf27c85047ed572765dd4813991908..59a9c0fa70c8d0445fb4c24c82fbbe48d7b88e03 100644
--- a/testsuite/.test-rules.make
+++ b/testsuite/.test-rules.make
@@ -220,6 +220,9 @@ ecdsa-verify-test$(EXEEXT): ecdsa-verify-test.$(OBJEXT)
 ecdsa-keygen-test$(EXEEXT): ecdsa-keygen-test.$(OBJEXT)
 	$(LINK) ecdsa-keygen-test.$(OBJEXT) $(TEST_OBJS) -o ecdsa-keygen-test$(EXEEXT)
 
+ecdh-test$(EXEEXT): ecdh-test.$(OBJEXT)
+	$(LINK) ecdh-test.$(OBJEXT) $(TEST_OBJS) -o ecdh-test$(EXEEXT)
+
 sha1-huge-test$(EXEEXT): sha1-huge-test.$(OBJEXT)
 	$(LINK) sha1-huge-test.$(OBJEXT) $(TEST_OBJS) -o sha1-huge-test$(EXEEXT)
 
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 27b35c1afb02e4f4a0f7b69774f0ac210b8a516e..6109a669cc0dd6c5226fb678f4c236ff7dd5d093 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -42,7 +42,8 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \
 		     curve25519-dh-test.c \
 		     ecc-mod-test.c ecc-modinv-test.c ecc-redc-test.c \
 		     ecc-mul-g-test.c ecc-mul-a-test.c \
-		     ecdsa-sign-test.c ecdsa-verify-test.c ecdsa-keygen-test.c
+		     ecdsa-sign-test.c ecdsa-verify-test.c \
+		     ecdsa-keygen-test.c ecdh-test.c
 
 TS_SOURCES = $(TS_NETTLE_SOURCES) $(TS_HOGWEED_SOURCES)
 CXX_SOURCES = cxx-test.cxx
diff --git a/testsuite/ecdh-test.c b/testsuite/ecdh-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..ed61e44ce26de95df9b4a3a27924f425bfb4a78f
--- /dev/null
+++ b/testsuite/ecdh-test.c
@@ -0,0 +1,148 @@
+/* ecdh-test.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/.
+*/
+
+#include "testutils.h"
+
+static void
+set_point (struct ecc_point *p,
+	   const char *x, const char *y)
+{
+  mpz_t X, Y;
+  mpz_init_set_str (X, x, 0);
+  mpz_init_set_str (Y, y, 0);
+  ecc_point_set (p, X, Y);
+  mpz_clear (X);
+  mpz_clear (Y);
+}
+  
+static void
+set_scalar (struct ecc_scalar *s,
+	    const char *x)
+{
+  mpz_t X;
+  mpz_init_set_str (X, x, 0);
+  ecc_scalar_set (s, X);
+  mpz_clear (X);
+}
+
+static void
+check_point (const char *label,
+	     const struct ecc_point *P,
+	     const struct ecc_point *R)
+{
+  mpz_t px, py, rx, ry;
+
+  mpz_init (px);
+  mpz_init (py);
+  mpz_init (rx);
+  mpz_init (ry);
+
+  ecc_point_get (P, px, py);
+  ecc_point_get (R, rx, ry);
+
+  /* FIXME: Should have a public point compare function */
+  if (mpz_cmp (px, rx) != 0 ||  mpz_cmp (py, ry) != 0)
+    {
+      fprintf (stderr, "Failed %s\np_x = ", label);
+      mpz_out_str (stderr, 10, px);
+      fprintf (stderr, "\nr_x = ");
+      mpz_out_str (stderr, 10, rx);
+      fprintf (stderr, " (expected)\np_y = ");
+      mpz_out_str (stderr, 10, py);
+      fprintf (stderr, "\nr_y = ");
+      mpz_out_str (stderr, 10, ry);
+      fprintf (stderr, " (expected)\n");
+      abort ();      
+    }
+  mpz_clear (px);
+  mpz_clear (py);
+  mpz_clear (rx);
+  mpz_clear (ry);
+}
+
+static void
+test_dh (const struct ecc_curve *ecc,
+	 const char *a_priv, const char *ax, const char *ay,
+	 const char *b_priv, const char *bx, const char *by,
+	 const char *sx, const char *sy)
+{
+  struct ecc_point A, B, S, T;
+  struct ecc_scalar A_priv, B_priv;
+
+  ecc_scalar_init (&A_priv, ecc);
+  set_scalar (&A_priv, a_priv);
+  ecc_point_init (&A, ecc);
+  set_point (&A, ax, ay);
+
+  ecc_scalar_init (&B_priv, ecc);
+  set_scalar (&B_priv, b_priv);
+  ecc_point_init (&B, ecc);
+  set_point (&B, bx, by);
+
+  ecc_point_init (&S, ecc);
+  set_point (&S, sx, sy);
+
+  ecc_point_init (&T, ecc);
+
+  ecc_point_mul_g (&T, &A_priv);
+  check_point ("a g", &T, &A);
+
+  ecc_point_mul (&T, &B_priv, &T);
+  check_point ("b (a g)", &T, &S);
+
+  ecc_point_mul_g (&T, &B_priv);
+  check_point ("b g", &T, &B);
+
+  ecc_point_mul (&T, &A_priv,  &T);
+  check_point ("a (b g)", &T, &S);
+
+  ecc_scalar_clear (&A_priv);
+  ecc_scalar_clear (&B_priv);
+
+  ecc_point_clear (&A);
+  ecc_point_clear (&B);
+  ecc_point_clear (&S);
+  ecc_point_clear (&T);  
+}
+
+void
+test_main(void)
+{
+  test_dh (&nettle_secp_192r1,
+	   "3406157206141798348095184987208239421004566462391397236532",
+	   "1050363442265225480786760666329560655512990381040021438562",
+	   "5298249600854377235107392014200406283816103564916230704184",
+	   "738368960171459956677260317271477822683777845013274506165",
+	   "2585840779771604687467445319428618542927556223024046979917",
+	   "293088185788565313717816218507714888251468410990708684573",
+	   "149293809021051532782730990145509724807636529827149481690",
+	   "2891131861147398318714693938158856874319184314120776776192");
+}