diff --git a/testsuite/.cvsignore b/testsuite/.cvsignore
index 64c77d5f3ae1168283695e647d3932752b15c966..a43aa2802e984b0ac9b5d8e3382f75f8103213ca 100644
--- a/testsuite/.cvsignore
+++ b/testsuite/.cvsignore
@@ -2,32 +2,18 @@
 Makefile
 Makefile.in
 aes-test
-aes-test.c
 arcfour-test
-arcfour-test.c
 bignum-test
-bignum-test.c
 blowfish-test
-blowfish-test.c
 cast128-test
-cast128-test.c
 cbc-test
-cbc-test.c
 des-compat-test
 des-test
-des-test.c
 des3-test
-des3-test.c
 md5-compat-test
-md5-compat-test.c
 md5-test
-md5-test.c
 serpent-test
-serpent-test.c
 sha1-test
-sha1-test.c
 sha256-test
-sha256-test.c
 twofish-test
-twofish-test.c
 yarrow-test
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index e5c287dd6e0c98b25ad89f666315ad1fe907d4e4..cd291cfa7fcd10bb7525807892d7171e76689b0c 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -2,32 +2,18 @@
 /Makefile
 /Makefile.in
 /aes-test
-/aes-test.c
 /arcfour-test
-/arcfour-test.c
 /bignum-test
-/bignum-test.c
 /blowfish-test
-/blowfish-test.c
 /cast128-test
-/cast128-test.c
 /cbc-test
-/cbc-test.c
 /des-compat-test
 /des-test
-/des-test.c
 /des3-test
-/des3-test.c
 /md5-compat-test
-/md5-compat-test.c
 /md5-test
-/md5-test.c
 /serpent-test
-/serpent-test.c
 /sha1-test
-/sha1-test.c
 /sha256-test
-/sha256-test.c
 /twofish-test
-/twofish-test.c
 /yarrow-test
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 25304fd87b98ec17cf38c248b8609987d98a287c..3229f03c9c851a4af5c03b95c3ec12439d5e1200 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -7,23 +7,23 @@ TS_PROGS = aes-test arcfour-test blowfish-test cast128-test \
 	   serpent-test twofish-test \
 	   cbc-test bignum-test yarrow-test
 
-M4_FILES = aes-test.m4 arcfour-test.m4 blowfish-test.m4 cast128-test.m4 \
-	   des-test.m4 des3-test.m4 \
-	   md5-test.m4 md5-compat-test.m4 sha1-test.m4 sha256-test.m4 \
-	   serpent-test.m4 twofish-test.m4 \
-	   cbc-test.m4 bignum-test.m4
+# M4_FILES = aes-test.m4 arcfour-test.m4 blowfish-test.m4 cast128-test.m4 \
+# 	   des-test.m4 des3-test.m4 \
+# 	   md5-test.m4 md5-compat-test.m4 sha1-test.m4 sha256-test.m4 \
+# 	   serpent-test.m4 twofish-test.m4 \
+# 	   cbc-test.m4 bignum-test.m4
 
 noinst_PROGRAMS = $(TS_PROGS)
 
 LDADD = testutils.o ../libnettle.a
-EXTRA_DIST = $(M4_FILES) macros.m4 testutils.c testutils.h \
+EXTRA_DIST = testutils.c testutils.h \
 	     run-tests rfc1750.txt
 
-# M4FLAGS = -P -s
-M4FLAGS = -P
-$(M4_FILES:.m4=.c): %.c: macros.m4 %.m4
-	$(M4) $(M4FLAGS) $^ > $@T
-	test -s $@T && mv -f $@T $@
+# # M4FLAGS = -P -s
+# M4FLAGS = -P
+# $(M4_FILES:.m4=.c): %.c: macros.m4 %.m4
+# 	$(M4) $(M4FLAGS) $^ > $@T
+# 	test -s $@T && mv -f $@T $@
 
 .PHONY: check run-tests
 
diff --git a/testsuite/aes-test.c b/testsuite/aes-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..42b3cda171d94d45f5505b5af28e4aae51d6ee33
--- /dev/null
+++ b/testsuite/aes-test.c
@@ -0,0 +1,100 @@
+#include "testutils.h"
+#include "aes.h"
+
+int
+main(int argc, char **argv)
+{
+  /* 128 bit keys */
+  test_cipher(&nettle_aes128, 
+	      HL("0001020305060708 0A0B0C0D0F101112"),
+	      HL("506812A45F08C889 B97F5980038B8359"),
+	      H("D8F532538289EF7D 06B506A4FD5BE9C9"));
+  
+  test_cipher(&nettle_aes128, 
+	      HL("14151617191A1B1C 1E1F202123242526"),
+	      HL("5C6D71CA30DE8B8B 00549984D2EC7D4B"),
+	      H("59AB30F4D4EE6E4F F9907EF65B1FB68C"));
+
+  test_cipher(&nettle_aes128, 
+	      HL("28292A2B2D2E2F30 323334353738393A"),
+	      HL("53F3F4C64F8616E4 E7C56199F48F21F6"),
+	      H("BF1ED2FCB2AF3FD4 1443B56D85025CB1"));
+  
+  test_cipher(&nettle_aes128, 
+	      HL("A0A1A2A3A5A6A7A8 AAABACADAFB0B1B2"),
+	      HL("F5F4F7F684878689 A6A7A0A1D2CDCCCF"),
+	      H("CE52AF650D088CA5 59425223F4D32694"));
+
+  /* 192 bit keys */
+  
+  test_cipher(&nettle_aes192, 
+	      HL("0001020305060708 0A0B0C0D0F101112"
+		"14151617191A1B1C"),
+	      HL("2D33EEF2C0430A8A 9EBF45E809C40BB6"),
+	      H("DFF4945E0336DF4C 1C56BC700EFF837F"));
+
+  /* 256 bit keys */
+  
+  test_cipher(&nettle_aes256,
+	      HL("0001020305060708 0A0B0C0D0F101112"
+		"14151617191A1B1C 1E1F202123242526"),
+	      HL("834EADFCCAC7E1B30664B1ABA44815AB"),
+	      H("1946DABF6A03A2A2 C3D0B05080AED6FC"));
+
+  /* This test case has been problematic with the CBC test case */
+  test_cipher(&nettle_aes256,
+	      HL("8d ae 93 ff fc 78 c9 44"
+		"2a bd 0c 1e 68 bc a6 c7"
+		"05 c7 84 e3 5a a9 11 8b"
+		"d3 16 aa 54 9b 44 08 9e"),
+	      HL("a5 ce 55 d4 21 15 a1 c6 4a a4 0c b2 ca a6 d1 37"),
+	      /* In the cbc test, I once got the bad value
+	       *   "b2 a0 6c d2 2f df 7d 2c  26 d2 42 88 8f 20 74 a2" */
+	      H("1f 94 fc 85 f2 36 21 06"
+		"4a ea e3 c9 cc 38 01 0e"));
+  
+  /* From draft NIST spec on AES modes.
+   *
+   * F.1 ECB Example Vectors
+   * F.1.1 ECB-AES128-Encrypt
+   */
+
+  test_cipher(&nettle_aes128,
+	      HL("2b7e151628aed2a6abf7158809cf4f3c"),
+	      HL("6bc1bee22e409f96e93d7e117393172a"
+		"ae2d8a571e03ac9c9eb76fac45af8e51"
+		"30c81c46a35ce411e5fbc1191a0a52ef"
+		"f69f2445df4f9b17ad2b417be66c3710"),
+	      H("3ad77bb40d7a3660a89ecaf32466ef97"
+		"f5d3d58503b9699de785895a96fdbaaf"
+		"43b1cd7f598ece23881b00e3ed030688"
+		"7b0c785e27e8ad3f8223207104725dd4"));
+
+  /* F.1.3 ECB-AES192-Encrypt */
+
+  test_cipher(&nettle_aes192,
+	      HL("8e73b0f7da0e6452c810f32b809079e5 62f8ead2522c6b7b"),
+	      HL("6bc1bee22e409f96e93d7e117393172a"
+		"ae2d8a571e03ac9c9eb76fac45af8e51"
+		"30c81c46a35ce411e5fbc1191a0a52ef"
+		"f69f2445df4f9b17ad2b417be66c3710"),
+	      H("bd334f1d6e45f25ff712a214571fa5cc"
+		"974104846d0ad3ad7734ecb3ecee4eef"
+		"ef7afd2270e2e60adce0ba2face6444e"
+		"9a4b41ba738d6c72fb16691603c18e0e"));
+
+  /* F.1.5 ECB-AES256-Encrypt */
+  test_cipher(&nettle_aes256,
+	      HL("603deb1015ca71be2b73aef0857d7781"
+		"1f352c073b6108d72d9810a30914dff4"),
+	      HL("6bc1bee22e409f96e93d7e117393172a"
+		"ae2d8a571e03ac9c9eb76fac45af8e51" 
+		"30c81c46a35ce411e5fbc1191a0a52ef"
+		"f69f2445df4f9b17ad2b417be66c3710"),
+	      H("f3eed1bdb5d2a03c064b5a7e3db181f8"
+		"591ccb10d410ed26dc5ba74a31362870"
+		"b6ed21b99ca6f4f9f153e7b1beafed1d"
+		"23304b7a39f9f3ff067d8d8f9e24ecc7"));
+
+  SUCCESS();
+}
diff --git a/testsuite/aes-test.m4 b/testsuite/aes-test.m4
deleted file mode 100644
index 6f1a637381ac85fe5565a2e5cc8f139d3354b55b..0000000000000000000000000000000000000000
--- a/testsuite/aes-test.m4
+++ /dev/null
@@ -1,244 +0,0 @@
-#include "aes.h"
-
-BEGIN_TEST
-
-struct aes_ctx ctx;
-
-uint8_t msg[AES_BLOCK_SIZE];
-uint8_t cipher[AES_BLOCK_SIZE];
-uint8_t clear[AES_BLOCK_SIZE];
-
-/* 128 bit keys */
-H(msg, "506812A45F08C889 B97F5980038B8359");
-
-aes_set_key(&ctx, 16,  H("0001020305060708 0A0B0C0D0F101112"));
-aes_encrypt(&ctx, AES_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(16, cipher, H("D8F532538289EF7D 06B506A4FD5BE9C9")))
-  FAIL;
-
-aes_decrypt(&ctx, AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(16, msg, clear))
-  FAIL;
-
-H(msg, "5C6D71CA30DE8B8B 00549984D2EC7D4B");
-
-aes_set_key(&ctx, 16,  H("14151617191A1B1C 1E1F202123242526"));
-aes_encrypt(&ctx, AES_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(16, cipher, H("59AB30F4D4EE6E4F F9907EF65B1FB68C")))
-  FAIL;
-
-aes_decrypt(&ctx, AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(16, msg, clear))
-  FAIL;
-
-H(msg, "53F3F4C64F8616E4 E7C56199F48F21F6");
-
-aes_set_key(&ctx, 16,  H("28292A2B2D2E2F30 323334353738393A"));
-aes_encrypt(&ctx, AES_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(16, cipher, H("BF1ED2FCB2AF3FD4 1443B56D85025CB1")))
-  FAIL;
-
-aes_decrypt(&ctx, AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(16, msg, clear))
-  FAIL;
-
-H(msg, "F5F4F7F684878689 A6A7A0A1D2CDCCCF");
-
-aes_set_key(&ctx, 16,  H("A0A1A2A3A5A6A7A8 AAABACADAFB0B1B2"));
-aes_encrypt(&ctx, AES_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(16, cipher, H("CE52AF650D088CA5 59425223F4D32694")))
-  FAIL;
-
-aes_decrypt(&ctx, AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(16, msg, clear))
-  FAIL;
-
-/* 192 bit keys */
-H(msg, "2D33EEF2C0430A8A 9EBF45E809C40BB6");
-
-aes_set_key(&ctx, 24,  H("0001020305060708 0A0B0C0D0F101112"
-			 "14151617191A1B1C"));
-aes_encrypt(&ctx, AES_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(16, cipher, H("DFF4945E0336DF4C 1C56BC700EFF837F")))
-  FAIL;
-
-aes_decrypt(&ctx, AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(16, msg, clear))
-  FAIL;
-
-/* 256 bit keys */
-H(msg, "834EADFCCAC7E1B30664B1ABA44815AB");
-
-aes_set_key(&ctx, 32,  H("0001020305060708 0A0B0C0D0F101112"
-			 "14151617191A1B1C 1E1F202123242526"));
-aes_encrypt(&ctx, AES_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(16, cipher, H("1946DABF6A03A2A2 C3D0B05080AED6FC")))
-  FAIL;
-
-aes_decrypt(&ctx, AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(16, msg, clear))
-  FAIL;
-
-/* This test case has been problematic with the CBC test case */
-H(msg, "a5 ce 55 d4 21 15 a1 c6 4a a4 0c b2 ca a6 d1 37");
-
-aes_set_key(&ctx, 32, H("8d ae 93 ff fc 78 c9 44"
-			"2a bd 0c 1e 68 bc a6 c7"
-			"05 c7 84 e3 5a a9 11 8b"
-			"d3 16 aa 54 9b 44 08 9e"));
-
-aes_encrypt(&ctx, AES_BLOCK_SIZE, cipher, msg);
-/* In the cbc test, I once got the bad value
- *   "b2 a0 6c d2 2f df 7d 2c  26 d2 42 88 8f 20 74 a2" */
-if (!MEMEQ(16, cipher, H("1f 94 fc 85 f2 36 21 06"
-			 "4a ea e3 c9 cc 38 01 0e")))
-  FAIL;
-
-aes_decrypt(&ctx, AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(16, msg, clear))
-  FAIL;
-
-/* From draft NIST spec on AES modes.
-
-F.1 ECB Example Vectors
-F.1.1 ECB-AES128-Encrypt
-
-Key	2b7e151628aed2a6abf7158809cf4f3c
-Block #1
-Plaintext	6bc1bee22e409f96e93d7e117393172a
-Input Block	6bc1bee22e409f96e93d7e117393172a
-Output Block	3ad77bb40d7a3660a89ecaf32466ef97
-Ciphertext	3ad77bb40d7a3660a89ecaf32466ef97
-Block #2
-Plaintext	ae2d8a571e03ac9c9eb76fac45af8e51
-Input Block	ae2d8a571e03ac9c9eb76fac45af8e51
-Output Block	f5d3d58503b9699de785895a96fdbaaf
-Ciphertext	f5d3d58503b9699de785895a96fdbaaf
-Block #3
-Plaintext	30c81c46a35ce411e5fbc1191a0a52ef
-Input Block	30c81c46a35ce411e5fbc1191a0a52ef
-Output Block	43b1cd7f598ece23881b00e3ed030688
-Ciphertext	43b1cd7f598ece23881b00e3ed030688
-Block #4
-Plaintext	f69f2445df4f9b17ad2b417be66c3710
-Input Block	f69f2445df4f9b17ad2b417be66c3710
-Output Block	7b0c785e27e8ad3f8223207104725dd4
-Ciphertext	7b0c785e27e8ad3f8223207104725dd4
-
-F.1.2 ECB-AES128-Decrypt
-Key	2b7e151628aed2a6abf7158809cf4f3c
-Block #1
-Ciphertext	3ad77bb40d7a3660a89ecaf32466ef97
-Input Block	3ad77bb40d7a3660a89ecaf32466ef97
-Output Block	6bc1bee22e409f96e93d7e117393172a
-Plaintext	6bc1bee22e409f96e93d7e117393172a
-Block #2
-Ciphertext	f5d3d58503b9699de785895a96fdbaaf
-Input Block	f5d3d58503b9699de785895a96fdbaaf
-Output Block	ae2d8a571e03ac9c9eb76fac45af8e51
-Plaintext	ae2d8a571e03ac9c9eb76fac45af8e51
-Block #3
-Ciphertext	43b1cd7f598ece23881b00e3ed030688
-Input Block	43b1cd7f598ece23881b00e3ed030688
-Output Block	30c81c46a35ce411e5fbc1191a0a52ef
-Plaintext	30c81c46a35ce411e5fbc1191a0a52ef
-Block #4
-Ciphertext	7b0c785e27e8ad3f8223207104725dd4
-Input Block	7b0c785e27e8ad3f8223207104725dd4
-Output Block	f69f2445df4f9b17ad2b417be66c3710
-Plaintext	f69f2445df4f9b17ad2b417be66c3710
-
-F.1.3 ECB-AES192-Encrypt
-Key	8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
-Block #1
-Plaintext	6bc1bee22e409f96e93d7e117393172a
-Input Block	6bc1bee22e409f96e93d7e117393172a
-Output Block	bd334f1d6e45f25ff712a214571fa5cc
-Ciphertext	bd334f1d6e45f25ff712a214571fa5cc
-Block #2
-Plaintext	ae2d8a571e03ac9c9eb76fac45af8e51
-Input Block	ae2d8a571e03ac9c9eb76fac45af8e51
-Output Block	974104846d0ad3ad7734ecb3ecee4eef
-Ciphertext	974104846d0ad3ad7734ecb3ecee4eef
-Block #3
-Plaintext	30c81c46a35ce411e5fbc1191a0a52ef
-Input Block	30c81c46a35ce411e5fbc1191a0a52ef
-Output Block	ef7afd2270e2e60adce0ba2face6444e
-Ciphertext	ef7afd2270e2e60adce0ba2face6444e
-Block #4
-Plaintext	f69f2445df4f9b17ad2b417be66c3710
-Input Block	f69f2445df4f9b17ad2b417be66c3710
-Output Block	9a4b41ba738d6c72fb16691603c18e0e
-Ciphertext	9a4b41ba738d6c72fb16691603c18e0e
-
-F.1.4 ECB-AES192-Decrypt
-Key	8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
-Block #1
-Ciphertext	bd334f1d6e45f25ff712a214571fa5cc
-Input Block	bd334f1d6e45f25ff712a214571fa5cc
-Output Block	6bc1bee22e409f96e93d7e117393172a
-Plaintext	6bc1bee22e409f96e93d7e117393172a
-Block #2
-Ciphertext	974104846d0ad3ad7734ecb3ecee4eef
-Input Block	974104846d0ad3ad7734ecb3ecee4eef
-Output Block	ae2d8a571e03ac9c9eb76fac45af8e51
-Plaintext	ae2d8a571e03ac9c9eb76fac45af8e51
-Block #3
-Ciphertext	ef7afd2270e2e60adce0ba2face6444e
-Input Block	ef7afd2270e2e60adce0ba2face6444e
-Output Block	30c81c46a35ce411e5fbc1191a0a52ef
-Plaintext	30c81c46a35ce411e5fbc1191a0a52ef
-Block #4
-Ciphertext	9a4b41ba738d6c72fb16691603c18e0e
-Input Block	9a4b41ba738d6c72fb16691603c18e0e
-Output Block	f69f2445df4f9b17ad2b417be66c3710
-Plaintext	f69f2445df4f9b17ad2b417be66c3710
-
-F.1.5 ECB-AES256-Encrypt
-Key	603deb1015ca71be2b73aef0857d7781
-	1f352c073b6108d72d9810a30914dff4
-Block #1
-Plaintext	6bc1bee22e409f96e93d7e117393172a
-Input Block	6bc1bee22e409f96e93d7e117393172a
-Output Block	f3eed1bdb5d2a03c064b5a7e3db181f8
-Ciphertext	f3eed1bdb5d2a03c064b5a7e3db181f8
-Block #2
-Plaintext	ae2d8a571e03ac9c9eb76fac45af8e51
-Input Block	ae2d8a571e03ac9c9eb76fac45af8e51
-Output Block	591ccb10d410ed26dc5ba74a31362870
-Ciphertext	591ccb10d410ed26dc5ba74a31362870
-Block #3
-Plaintext	30c81c46a35ce411e5fbc1191a0a52ef
-Input Block	30c81c46a35ce411e5fbc1191a0a52ef
-Output Block	b6ed21b99ca6f4f9f153e7b1beafed1d
-Ciphertext	b6ed21b99ca6f4f9f153e7b1beafed1d
-Block #4
-Plaintext	f69f2445df4f9b17ad2b417be66c3710
-Input Block	f69f2445df4f9b17ad2b417be66c3710
-Output Block	23304b7a39f9f3ff067d8d8f9e24ecc7
-Ciphertext	23304b7a39f9f3ff067d8d8f9e24ecc7
-
-F.1.6 ECB-AES256-Decrypt
-Key	603deb1015ca71be2b73aef0857d7781
-	1f352c073b6108d72d9810a30914dff4
-Block #1
-Ciphertext	f3eed1bdb5d2a03c064b5a7e3db181f8
-Input Block	f3eed1bdb5d2a03c064b5a7e3db181f8
-Output Block	6bc1bee22e409f96e93d7e117393172a
-Plaintext	6bc1bee22e409f96e93d7e117393172a
-Block #2
-Ciphertext	591ccb10d410ed26dc5ba74a31362870
-Input Block	591ccb10d410ed26dc5ba74a31362870
-Output Block	ae2d8a571e03ac9c9eb76fac45af8e51
-Plaintext	ae2d8a571e03ac9c9eb76fac45af8e51
-Block #3
-Ciphertext	b6ed21b99ca6f4f9f153e7b1beafed1d
-Input Block	b6ed21b99ca6f4f9f153e7b1beafed1d
-Output Block	30c81c46a35ce411e5fbc1191a0a52ef
-Plaintext	30c81c46a35ce411e5fbc1191a0a52ef
-Block #4
-Ciphertext	23304b7a39f9f3ff067d8d8f9e24ecc7
-Input Block	23304b7a39f9f3ff067d8d8f9e24ecc7
-Output Block	f69f2445df4f9b17ad2b417be66c3710
-Plaintext	f69f2445df4f9b17ad2b417be66c3710
-*/
diff --git a/testsuite/arcfour-test.c b/testsuite/arcfour-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..47886dfb870d5bd534bd522d94511f53a9f91cbf
--- /dev/null
+++ b/testsuite/arcfour-test.c
@@ -0,0 +1,13 @@
+#include "testutils.h"
+#include "arcfour.h"
+
+int
+main(int argc, char **argv)
+{
+  test_cipher(&nettle_arcfour128,
+	      HL("01234567 89ABCDEF 00000000 00000000"),
+	      HL("01234567 89ABCDEF"),
+	      H("69723659 1B5242B1"));
+
+  SUCCESS();
+}
diff --git a/testsuite/arcfour-test.m4 b/testsuite/arcfour-test.m4
deleted file mode 100644
index 3db86d678b7aab34bcb999f2f348de2aafdd33a6..0000000000000000000000000000000000000000
--- a/testsuite/arcfour-test.m4
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "arcfour.h"
-
-BEGIN_TEST
-
-struct arcfour_ctx ctx;
-const uint8_t *clear = H("01234567 89ABCDEF");
-uint8_t cipher[8];
-arcfour_set_key(&ctx, 16, H("01234567 89ABCDEF 00000000 00000000"));
-arcfour_crypt(&ctx, 8, cipher, clear);
-if (!MEMEQ(8, cipher, H("69723659 1B5242B1")))
-  FAIL;
diff --git a/testsuite/bignum-test.m4 b/testsuite/bignum-test.c
similarity index 76%
rename from testsuite/bignum-test.m4
rename to testsuite/bignum-test.c
index 7344cbeb4f26fd96174562a058bdf908488fec4c..905eef0e4c5bfe865dd06dce7e9e4e8787b81e18 100644
--- a/testsuite/bignum-test.m4
+++ b/testsuite/bignum-test.c
@@ -1,3 +1,4 @@
+#include "testutils.h"
 
 #if HAVE_CONFIG_H
 #include "config.h"
@@ -20,28 +21,30 @@ test_bignum(const char *hex, unsigned length, const uint8_t *base256)
   nettle_mpz_init_set_str_256(b, length, base256);
 
   if (mpz_cmp(a, b))
-    FAIL;
+    FAIL();
 
   buf = alloca(length + 1);
   memset(buf, 17, length + 1);
 
   nettle_mpz_get_str_256(length, buf, a);
   if (!MEMEQ(length, buf, base256))
-    FAIL;
+    FAIL();
 
   if (buf[length] != 17)
-    FAIL;
+    FAIL();
 
   mpz_clear(a); mpz_clear(b);
 }
 #endif /* HAVE_LIBGMP */
 
-BEGIN_TEST
-
+int
+main(int argc, char **argv)
+{
 #if HAVE_LIBGMP
-test_bignum("0", 0, "");
-test_bignum("010203040506", 7, H("00010203040506"));
-
+  test_bignum("0", 0, "");
+  test_bignum("010203040506", 7, H("00010203040506"));
+  SUCCESS();
 #else /* !HAVE_LIBGMP */
-SKIP
+  SKIP();
 #endif /* !HAVE_LIBGMP */
+}
diff --git a/testsuite/blowfish-test.m4 b/testsuite/blowfish-test.c
similarity index 81%
rename from testsuite/blowfish-test.m4
rename to testsuite/blowfish-test.c
index 0c6157af65485c555fa04e69632f40f869973c8e..9d160bd61edcbcf4f7eac7fc6dea82b79dd65e99 100644
--- a/testsuite/blowfish-test.m4
+++ b/testsuite/blowfish-test.c
@@ -1,23 +1,18 @@
+#include "testutils.h"
+#include "nettle-internal.h"
 #include "blowfish.h"
 
-BEGIN_TEST
-
-struct blowfish_ctx ctx;
-
-uint8_t msg[BLOWFISH_BLOCK_SIZE];
-uint8_t cipher[BLOWFISH_BLOCK_SIZE];
-uint8_t clear[BLOWFISH_BLOCK_SIZE];
-
-/* 208 bit key. Test from GNUPG. */
-blowfish_set_key(&ctx, 26, "abcdefghijklmnopqrstuvwxyz");
-blowfish_encrypt(&ctx, BLOWFISH_BLOCK_SIZE, cipher, "BLOWFISH");
-if (!MEMEQ(BLOWFISH_BLOCK_SIZE, cipher, H("32 4E D0 FE F4 13 A2 03")))
-  FAIL;
-
-blowfish_decrypt(&ctx, BLOWFISH_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(BLOWFISH_BLOCK_SIZE, "BLOWFISH", clear))
-  FAIL;
-
+int
+main(int argc, char **argv)
+{
+  /* 208 bit key. Test from GNUPG. */
+  test_cipher(&nettle_blowfish128,
+	      26, "abcdefghijklmnopqrstuvwxyz",
+	      BLOWFISH_BLOCK_SIZE, "BLOWFISH",
+	      H("32 4E D0 FE F4 13 A2 03"));
+
+  SUCCESS();
+}
 /* FIXME: All values below are bogus. */
 #if 0
 
diff --git a/testsuite/cast128-test.c b/testsuite/cast128-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..611733ecc8043d7d75fc3695139691ca881fde3c
--- /dev/null
+++ b/testsuite/cast128-test.c
@@ -0,0 +1,30 @@
+#include "testutils.h"
+#include "cast128.h"
+
+int
+main(int argc, char **argv)
+{
+  /* Test vectors from B.1. Single Plaintext-Key-Ciphertext Sets, RFC
+   * 2144 */
+
+  /* 128 bit key */
+  test_cipher(&nettle_cast128,
+	      HL("01 23 45 67 12 34 56 78"
+		 "23 45 67 89 34 56 78 9A"),
+	      HL("01 23 45 67 89 AB CD EF"),
+	      H("23 8B 4F E5 84 7E 44 B2"));
+  
+  /* 80 bit key */
+  test_cipher(&nettle_cast128,
+	      HL("01 23 45 67 12 34 56 78 23 45"),
+	      HL("01 23 45 67 89 AB CD EF"),
+	      H("EB 6A 71 1A 2C 02 27 1B"));
+
+  /* 40 bit key */
+  test_cipher(&nettle_cast128,
+	      HL("01 23 45 67 12"),
+	      HL("01 23 45 67 89 AB CD EF"),
+	      H("7A C8 16 D1 6E 9B 30 2E"));
+
+  SUCCESS();
+}
diff --git a/testsuite/cast128-test.m4 b/testsuite/cast128-test.m4
deleted file mode 100644
index e640cdd6ee249f32e77ca4b81f1a6977c49e9a86..0000000000000000000000000000000000000000
--- a/testsuite/cast128-test.m4
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "cast128.h"
-
-BEGIN_TEST
-
-struct cast128_ctx ctx;
-
-uint8_t msg[CAST128_BLOCK_SIZE];
-uint8_t cipher[CAST128_BLOCK_SIZE];
-uint8_t clear[CAST128_BLOCK_SIZE];
-
-/* Test vectors from B.1. Single Plaintext-Key-Ciphertext Sets, RFC
- * 2144 */
-
-/* 128 bit key */
-H(msg, "01 23 45 67 89 AB CD EF");
-
-cast128_set_key(&ctx, 16,  H("01 23 45 67 12 34 56 78"
-			     "23 45 67 89 34 56 78 9A"));
-cast128_encrypt(&ctx, CAST128_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(CAST128_BLOCK_SIZE, cipher, H("23 8B 4F E5 84 7E 44 B2")))
-  FAIL;
-
-cast128_decrypt(&ctx, CAST128_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(CAST128_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* 80 bit key */
-H(msg, "01 23 45 67 89 AB CD EF");
-
-cast128_set_key(&ctx, 10,  H("01 23 45 67 12 34 56 78 23 45"));
-cast128_encrypt(&ctx, CAST128_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(CAST128_BLOCK_SIZE, cipher, H("EB 6A 71 1A 2C 02 27 1B")))
-  FAIL;
-
-cast128_decrypt(&ctx, CAST128_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(CAST128_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* 40 bit key */
-H(msg, "01 23 45 67 89 AB CD EF");
-
-cast128_set_key(&ctx, 5,  H("01 23 45 67 12"));
-cast128_encrypt(&ctx, CAST128_BLOCK_SIZE, cipher, msg);
-if (!MEMEQ(CAST128_BLOCK_SIZE, cipher, H("7A C8 16 D1 6E 9B 30 2E")))
-  FAIL;
-
-cast128_decrypt(&ctx, CAST128_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(CAST128_BLOCK_SIZE, msg, clear))
-  FAIL;
-
diff --git a/testsuite/cbc-test.c b/testsuite/cbc-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..6e1a9463358fa0604279d841d22324b85af60e78
--- /dev/null
+++ b/testsuite/cbc-test.c
@@ -0,0 +1,259 @@
+#include "testutils.h"
+#include "aes.h"
+#include "cbc.h"
+
+int
+main(int argc, char **argv)
+{
+  uint8_t msg[2 * AES_BLOCK_SIZE] = "Listen, I'll say this only once!";
+
+  /* Intermediate values:
+   *   iv XOR first message block:
+   *       "a5 ce 55 d4 21 15 a1 c6 4a a4 0c b2 ca a6 d1 37"
+   *   First ciphertext block, c1:
+   *       "1f 94 fc 85 f2 36 21 06 4a ea e3 c9 cc 38 01 0e"
+   *   c1 XOR second message block:
+   *       "3f e0 94 ec 81 16 4e 68 26 93 c3 a6 a2 5b 64 2f"
+   *   Second ciphertext block, c1:
+   *       "7b f6 5f c5 02 59 2e 71 af bf 34 87 c0 36 2a 16"
+   */
+
+  test_cipher_cbc(&nettle_aes256,
+		  HL("8d ae 93 ff fc 78 c9 44"
+		     "2a bd 0c 1e 68 bc a6 c7"
+		     "05 c7 84 e3 5a a9 11 8b"
+		     "d3 16 aa 54 9b 44 08 9e"),
+		  2 * AES_BLOCK_SIZE, msg,
+		  H("1f 94 fc 85 f2 36 21 06"
+		    "4a ea e3 c9 cc 38 01 0e"
+		    "7b f6 5f c5 02 59 2e 71"
+		    "af bf 34 87 c0 36 2a 16"),
+		  H("e9 a7 26 a0 44 7b 8d e6  03 83 60 de ea d5 b0 4e"));
+
+  /* From NIST spec 800-38a on AES modes.
+   *
+   * F.2  CBC Example Vectors 
+   * F.2.1 CBC-AES128.Encrypt
+   */
+
+  /* Intermediate values, blcoks input to AES:
+   *
+   *   6bc0bce12a459991e134741a7f9e1925 
+   *   d86421fb9f1a1eda505ee1375746972c 
+   *   604ed7ddf32efdff7020d0238b7c2a5d 
+   *   8521f2fd3c8eef2cdc3da7e5c44ea206 
+   */
+   test_cipher_cbc(&nettle_aes128,
+		   HL("2b7e151628aed2a6abf7158809cf4f3c"),
+		   HL("6bc1bee22e409f96e93d7e117393172a"
+		      "ae2d8a571e03ac9c9eb76fac45af8e51"
+		      "30c81c46a35ce411e5fbc1191a0a52ef"
+		      "f69f2445df4f9b17ad2b417be66c3710"),
+		   H("7649abac8119b246cee98e9b12e9197d"
+		     "5086cb9b507219ee95db113a917678b2"
+		     "73bed6b8e3c1743b7116e69e22229516"
+		     "3ff1caa1681fac09120eca307586e1a7"),
+		   H("000102030405060708090a0b0c0d0e0f"));
+
+   /* F.2.3 CBC-AES192.Encrypt */
+
+   /* Intermediate values, blcoks input to AES:
+    *
+    *   6bc0bce12a459991e134741a7f9e1925 
+    *   e12f97e55dbfcfa1efcf7796da0fffb9
+    *   8411b1ef0e2109e5001cf96f256346b5 
+    *   a1840065cdb4e1f7d282fbd7db9d35f0
+    */
+
+   test_cipher_cbc(&nettle_aes192,
+		   HL("8e73b0f7da0e6452c810f32b809079e5"
+		      "62f8ead2522c6b7b"),
+		   HL("6bc1bee22e409f96e93d7e117393172a"
+		      "ae2d8a571e03ac9c9eb76fac45af8e51"
+		      "30c81c46a35ce411e5fbc1191a0a52ef"
+		      "f69f2445df4f9b17ad2b417be66c3710"),
+		   H("4f021db243bc633d7178183a9fa071e8"
+		     "b4d9ada9ad7dedf4e5e738763f69145a"
+		     "571b242012fb7ae07fa9baac3df102e0"
+		     "08b0e27988598881d920a9e64f5615cd"),
+		   H("000102030405060708090a0b0c0d0e0f"));
+   
+   /* F.2.5 CBC-AES256.Encrypt */
+
+   /* Intermediate values, blcoks input to AES:
+    *
+    *   6bc0bce12a459991e134741a7f9e1925 
+    *   5ba1c653c8e65d26e929c4571ad47587 
+    *   ac3452d0dd87649c8264b662dc7a7e92
+    *   cf6d172c769621d8081ba318e24f2371 
+    */
+
+   test_cipher_cbc(&nettle_aes256,
+		   HL("603deb1015ca71be2b73aef0857d7781"
+		      "1f352c073b6108d72d9810a30914dff4"),
+		   HL("6bc1bee22e409f96e93d7e117393172a"
+		      "ae2d8a571e03ac9c9eb76fac45af8e51"
+		      "30c81c46a35ce411e5fbc1191a0a52ef"
+		      "f69f2445df4f9b17ad2b417be66c3710"),
+		   H("f58c4c04d6e5f1ba779eabfb5f7bfbd6"
+		     "9cfc4e967edb808d679f777bc6702c7d"
+		     "39f23369a9d9bacfa530e26304231461"
+		     "b2eb05e2c39be9fcda6c19078c6a9d1b"),
+		   H("000102030405060708090a0b0c0d0e0f"));
+
+   SUCCESS();
+}
+
+/*
+IV 
+  000102030405060708090a0b0c0d0e0f 
+Block #1 
+Plaintext      6bc1bee22e409f96e93d7e117393172a 
+Input Block     6bc0bce12a459991e134741a7f9e1925 
+Output Block  7649abac8119b246cee98e9b12e9197d 
+Ciphertext 7649abac8119b246cee98e9b12e9197d 
+Block #2 
+Plaintext      ae2d8a571e03ac9c9eb76fac45af8e51 
+Input Block     d86421fb9f1a1eda505ee1375746972c 
+Output Block  5086cb9b507219ee95db113a917678b2 
+Ciphertext 5086cb9b507219ee95db113a917678b2 
+Block #3 
+Plaintext      30c81c46a35ce411e5fbc1191a0a52ef 
+Input Block     604ed7ddf32efdff7020d0238b7c2a5d 
+Output Block  73bed6b8e3c1743b7116e69e22229516 
+Ciphertext 73bed6b8e3c1743b7116e69e22229516 
+Block #4 
+Plaintext      f69f2445df4f9b17ad2b417be66c3710 
+Input Block     8521f2fd3c8eef2cdc3da7e5c44ea206 
+Output Block  3ff1caa1681fac09120eca307586e1a7 
+Ciphertext 3ff1caa1681fac09120eca307586e1a7 
+ F.2.2 CBC-AES128.Decrypt 
+Key 
+  2b7e151628aed2a6abf7158809cf4f3c 
+IV 
+  000102030405060708090a0b0c0d0e0f 
+Block #1 
+Ciphertext 7649abac8119b246cee98e9b12e9197d 
+Input Block     7649abac8119b246cee98e9b12e9197d 
+Output Block  6bc0bce12a459991e134741a7f9e1925 
+Plaintext      6bc1bee22e409f96e93d7e117393172a 
+Block #2 
+Ciphertext 5086cb9b507219ee95db113a917678b2 
+Input Block     5086cb9b507219ee95db113a917678b2 
+Output Block  d86421fb9f1a1eda505ee1375746972c 
+Plaintext      ae2d8a571e03ac9c9eb76fac45af8e51 
+Block #3 
+Ciphertext 73bed6b8e3c1743b7116e69e22229516 
+Input Block     73bed6b8e3c1743b7116e69e22229516 
+Output Block  604ed7ddf32efdff7020d0238b7c2a5d 
+Plaintext      30c81c46a35ce411e5fbc1191a0a52ef 
+Block #4 
+Ciphertext 3ff1caa1681fac09120eca307586e1a7 
+Input Block     3ff1caa1681fac09120eca307586e1a7 
+
+
+Output Block  8521f2fd3c8eef2cdc3da7e5c44ea206 
+Plaintext      f69f2445df4f9b17ad2b417be66c3710 
+ F.2.3 CBC-AES192.Encrypt 
+Key 
+  8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+IV 
+  000102030405060708090a0b0c0d0e0f 
+Block #1 
+Plaintext      6bc1bee22e409f96e93d7e117393172a 
+Input Block     6bc0bce12a459991e134741a7f9e1925 
+Output Block  4f021db243bc633d7178183a9fa071e8 
+Ciphertext 4f021db243bc633d7178183a9fa071e8 
+Block #2 
+Plaintext      ae2d8a571e03ac9c9eb76fac45af8e51 
+Input Block     e12f97e55dbfcfa1efcf7796da0fffb9 
+Output Block  b4d9ada9ad7dedf4e5e738763f69145a 
+Ciphertext b4d9ada9ad7dedf4e5e738763f69145a 
+Block #3 
+Plaintext      30c81c46a35ce411e5fbc1191a0a52ef 
+Input Block     8411b1ef0e2109e5001cf96f256346b5 
+Output Block  571b242012fb7ae07fa9baac3df102e0 
+Ciphertext 571b242012fb7ae07fa9baac3df102e0 
+Block #4 
+Plaintext      f69f2445df4f9b17ad2b417be66c3710 
+Input Block     a1840065cdb4e1f7d282fbd7db9d35f0 
+Output Block  08b0e27988598881d920a9e64f5615cd 
+Ciphertext 08b0e27988598881d920a9e64f5615cd 
+ F.2.4 CBC-AES192.Decrypt 
+Key 
+  8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
+IV 
+  000102030405060708090a0b0c0d0e0f 
+Block #1 
+Ciphertext 4f021db243bc633d7178183a9fa071e8 
+Input Block     4f021db243bc633d7178183a9fa071e8 
+Output Block  6bc0bce12a459991e134741a7f9e1925 
+Plaintext      6bc1bee22e409f96e93d7e117393172a 
+Block #2 
+Ciphertext b4d9ada9ad7dedf4e5e738763f69145a 
+Input Block     b4d9ada9ad7dedf4e5e738763f69145a 
+Output Block  e12f97e55dbfcfa1efcf7796da0fffb9 
+Plaintext      ae2d8a571e03ac9c9eb76fac45af8e51 
+Block #3 
+Ciphertext 571b242012fb7ae07fa9baac3df102e0 
+Input Block     571b242012fb7ae07fa9baac3df102e0 
+Output Block  8411b1ef0e2109e5001cf96f256346b5 
+Plaintext      30c81c46a35ce411e5fbc1191a0a52ef 
+Block #4 
+Ciphertext 08b0e27988598881d920a9e64f5615cd 
+Input Block     08b0e27988598881d920a9e64f5615cd 
+Output Block  a1840065cdb4e1f7d282fbd7db9d35f0 
+Plaintext      f69f2445df4f9b17ad2b417be66c3710 
+ F.2.5 CBC-AES256.Encrypt 
+Key 
+  603deb1015ca71be2b73aef0857d7781 
+1f352c073b6108d72d9810a30914dff4 
+  IV 
+  000102030405060708090a0b0c0d0e0f 
+Block #1 
+Plaintext      6bc1bee22e409f96e93d7e117393172a 
+Input Block     6bc0bce12a459991e134741a7f9e1925 
+Output Block  f58c4c04d6e5f1ba779eabfb5f7bfbd6 
+Ciphertext f58c4c04d6e5f1ba779eabfb5f7bfbd6 
+Block #2 
+Plaintext      ae2d8a571e03ac9c9eb76fac45af8e51 
+Input Block     5ba1c653c8e65d26e929c4571ad47587 
+Output Block  9cfc4e967edb808d679f777bc6702c7d 
+Ciphertext 9cfc4e967edb808d679f777bc6702c7d
+Block #3 
+Plaintext      30c81c46a35ce411e5fbc1191a0a52ef 
+Input Block     ac3452d0dd87649c8264b662dc7a7e92 
+Output Block  39f23369a9d9bacfa530e26304231461 
+Ciphertext 39f23369a9d9bacfa530e26304231461 
+Block #4 
+Plaintext      f69f2445df4f9b17ad2b417be66c3710 
+Input Block     cf6d172c769621d8081ba318e24f2371 
+Output Block  b2eb05e2c39be9fcda6c19078c6a9d1b 
+Ciphertext b2eb05e2c39be9fcda6c19078c6a9d1b
+ F.2.6 CBC-AES256.Decrypt 
+Key 
+  603deb1015ca71be2b73aef0857d7781 
+   1f352c073b6108d72d9810a30914dff4 
+IV 
+  000102030405060708090a0b0c0d0e0f 
+Block #1 
+Ciphertext f58c4c04d6e5f1ba779eabfb5f7bfbd6 
+Input Block     f58c4c04d6e5f1ba779eabfb5f7bfbd6 
+Output Block  6bc0bce12a459991e134741a7f9e1925 
+Plaintext      6bc1bee22e409f96e93d7e117393172a 
+Block #2 
+Ciphertext 9cfc4e967edb808d679f777bc6702c7d 
+Input Block     9cfc4e967edb808d679f777bc6702c7d 
+Output Block  5ba1c653c8e65d26e929c4571ad47587 
+Plaintext      ae2d8a571e03ac9c9eb76fac45af8e51 
+Block #3 
+Ciphertext 39f23369a9d9bacfa530e26304231461 
+Input Block     39f23369a9d9bacfa530e26304231461 
+Output Block  ac3452d0dd87649c8264b662dc7a7e92 
+Plaintext      30c81c46a35ce411e5fbc1191a0a52ef 
+Block #4 
+Ciphertext b2eb05e2c39be9fcda6c19078c6a9d1b 
+Input Block     b2eb05e2c39be9fcda6c19078c6a9d1b 
+Output Block  cf6d172c769621d8081ba318e24f2371 
+Plaintext      f69f2445df4f9b17ad2b417be66c3710 
+*/
diff --git a/testsuite/cbc-test.m4 b/testsuite/cbc-test.m4
deleted file mode 100644
index 8173e457cb2e65ba835b0197dda6ea241f78d6a1..0000000000000000000000000000000000000000
--- a/testsuite/cbc-test.m4
+++ /dev/null
@@ -1,44 +0,0 @@
-#include "aes.h"
-#include "cbc.h"
-
-BEGIN_TEST
-
-struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) ctx;
-
-uint8_t msg[2 * AES_BLOCK_SIZE] = "Listen, I'll say this only once!";
-uint8_t cipher[2 * AES_BLOCK_SIZE];
-uint8_t clear[2 * AES_BLOCK_SIZE];
-uint8_t iv[AES_BLOCK_SIZE];
-
-/* Intermediate values:
- *   iv XOR first message block:
- *       "a5 ce 55 d4 21 15 a1 c6 4a a4 0c b2 ca a6 d1 37"
- *   First ciphertext block, c1:
- *       "1f 94 fc 85 f2 36 21 06 4a ea e3 c9 cc 38 01 0e"
- *   c1 XOR second message block:
- *       "3f e0 94 ec 81 16 4e 68 26 93 c3 a6 a2 5b 64 2f"
- *   Second ciphertext block, c1:
- *       "7b f6 5f c5 02 59 2e 71 af bf 34 87 c0 36 2a 16"
- */
-H(iv, "e9 a7 26 a0 44 7b 8d e6  03 83 60 de ea d5 b0 4e");
-aes_set_key(&ctx.ctx, 32, H("8d ae 93 ff fc 78 c9 44"
-			    "2a bd 0c 1e 68 bc a6 c7"
-			    "05 c7 84 e3 5a a9 11 8b"
-			    "d3 16 aa 54 9b 44 08 9e"));
-
-CBC_SET_IV(&ctx, iv);
-CBC_ENCRYPT(&ctx, aes_encrypt, 2 * AES_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(2 * AES_BLOCK_SIZE, cipher, H("1f 94 fc 85 f2 36 21 06"
-					 "4a ea e3 c9 cc 38 01 0e"
-					 "7b f6 5f c5 02 59 2e 71"
-					 "af bf 34 87 c0 36 2a 16")))
-  FAIL;
-
-if (!MEMEQ(AES_BLOCK_SIZE, ctx.iv, cipher + AES_BLOCK_SIZE))
-  FAIL;
-
-CBC_SET_IV(&ctx, iv);
-CBC_DECRYPT(&ctx, aes_decrypt, 2 * AES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(2 * AES_BLOCK_SIZE, msg, clear))
-  FAIL;
diff --git a/testsuite/des-test.c b/testsuite/des-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ca8dd9ed99b50e6f5b7d618f3dbc43fb20c8144
--- /dev/null
+++ b/testsuite/des-test.c
@@ -0,0 +1,56 @@
+#include "testutils.h"
+#include "nettle-internal.h"
+#include "des.h"
+
+int
+main(int argc, char **argv)
+{
+  struct des_ctx ctx;
+  
+  /* From Applied Cryptography */
+  test_cipher(&nettle_des,
+	      HL("01234567 89ABCDEF"),
+	      HL("01234567 89ABCDE7"),
+	      H("C9574425 6A5ED31D"));
+
+  test_cipher(&nettle_des,
+	      HL("01 01 01 01 01 01 01 80"),
+	      HL("00 00 00 00 00 00 00 00"),
+	      H("9C C6 2D F4 3B 6E ED 74"));
+  
+  test_cipher(&nettle_des,
+	      HL("80 01 01 01 01 01 01 01"),
+	      HL("00 00 00 00 00 00 00 40"),
+	      H("A3 80 E0 2A 6B E5 46 96"));
+
+  test_cipher(&nettle_des,
+	      HL("08 19 2A 3B 4C 5D 6E 7F"),
+	      HL("00 00 00 00 00 00 00 00"),
+	      H("25 DD AC 3E 96 17 64 67"));
+
+  
+  test_cipher(&nettle_des,
+	      HL("01 23 45 67 89 AB CD EF"),
+	      DES_BLOCK_SIZE, "Now is t",
+	      H("3F A4 0E 8A 98 4D 48 15"));
+
+  /* Parity check */
+  if (des_set_key(&ctx, H("01 01 01 01 01 01 01 00"))
+      || (ctx.status != DES_BAD_PARITY))
+    FAIL();
+
+  /* Weak key check */
+  if (des_set_key(&ctx, H("01 01 01 01 01 01 01 01"))
+      || (ctx.status != DES_WEAK_KEY))
+    FAIL();
+
+  if (des_set_key(&ctx, H("01 FE 01 FE 01 FE 01 FE"))
+      || (ctx.status != DES_WEAK_KEY))
+    FAIL();
+
+  if (des_set_key(&ctx, H("FE E0 FE E0 FE F1 FE F1"))
+      || (ctx.status != DES_WEAK_KEY))
+    FAIL();
+
+  SUCCESS();
+}
diff --git a/testsuite/des-test.m4 b/testsuite/des-test.m4
deleted file mode 100644
index 8b75aff212a2418b3c22b1af3098a020dde3b919..0000000000000000000000000000000000000000
--- a/testsuite/des-test.m4
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "des.h"
-
-BEGIN_TEST
-
-struct des_ctx ctx;
-
-uint8_t msg[DES_BLOCK_SIZE];
-uint8_t cipher[DES_BLOCK_SIZE];
-uint8_t clear[DES_BLOCK_SIZE];
-
-/* From Applied Cryptography */
-H(msg, "01234567 89ABCDE7");
-
-if (!des_set_key(&ctx, H("01234567 89ABCDEF")))
-  FAIL;
-
-des_encrypt(&ctx, DES_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(DES_BLOCK_SIZE, cipher,
-	H("C9574425 6A5ED31D")))
-  FAIL;
-
-des_decrypt(&ctx, DES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(DES_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-
-H(msg, "00 00 00 00 00 00 00 00");
-
-if (!des_set_key(&ctx, H("01 01 01 01 01 01 01 80")))
-  FAIL;
-
-des_encrypt(&ctx, DES_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(DES_BLOCK_SIZE, cipher,
-	H("9C C6 2D F4 3B 6E ED 74")))
-  FAIL;
-
-des_decrypt(&ctx, DES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(DES_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-H(msg, "00 00 00 00 00 00 00 40");
-
-if (!des_set_key(&ctx, H("80 01 01 01 01 01 01 01")))
-  FAIL;
-
-des_encrypt(&ctx, DES_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(DES_BLOCK_SIZE, cipher,
-	H("A3 80 E0 2A 6B E5 46 96")))
-  FAIL;
-
-des_decrypt(&ctx, DES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(DES_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-H(msg, "00 00 00 00 00 00 00 00");
-
-if (!des_set_key(&ctx, H("08 19 2A 3B 4C 5D 6E 7F")))
-  FAIL;
-
-des_encrypt(&ctx, DES_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(DES_BLOCK_SIZE, cipher,
-	H("25 DD AC 3E 96 17 64 67")))
-  FAIL;
-
-des_decrypt(&ctx, DES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(DES_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-if (!des_set_key(&ctx, H("01 23 45 67 89 AB CD EF")))
-  FAIL;
-
-des_encrypt(&ctx, DES_BLOCK_SIZE, cipher, "Now is t");
-
-if (!MEMEQ(DES_BLOCK_SIZE, cipher,
-	H("3F A4 0E 8A 98 4D 48 15")))
-  FAIL;
-
-des_decrypt(&ctx, DES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(DES_BLOCK_SIZE, "Now is t", clear))
-  FAIL;
-
-/* Parity check */
-if (des_set_key(&ctx, H("01 01 01 01 01 01 01 00"))
-    || (ctx.status != DES_BAD_PARITY))
-  FAIL;
-
-/* Weak key check */
-if (des_set_key(&ctx, H("01 01 01 01 01 01 01 01"))
-    || (ctx.status != DES_WEAK_KEY))
-  FAIL;
-
-if (des_set_key(&ctx, H("01 FE 01 FE 01 FE 01 FE"))
-    || (ctx.status != DES_WEAK_KEY))
-  FAIL;
-
-if (des_set_key(&ctx, H("FE E0 FE E0 FE F1 FE F1"))
-    || (ctx.status != DES_WEAK_KEY))
-  FAIL;
-
diff --git a/testsuite/des3-test.c b/testsuite/des3-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..b3a4429199961a698783ade2aa645b7dc612b06f
--- /dev/null
+++ b/testsuite/des3-test.c
@@ -0,0 +1,21 @@
+#include "testutils.h"
+#include "nettle-internal.h"
+#include "des.h"
+
+int
+main(int argc, char **argv)
+{
+  /* Intermediate values:
+   *   After first DES encryption:  "cd ea 2a 20 c2 e0 9e 48"
+   *   After second DES decryption: "69 52 6e 95 8b ea 49 bd"
+   */
+
+  test_cipher(&nettle_des3,
+	      HL("3e 0b 10 b0 5d 49 c2 54"
+		 "6b 46 e0 75 8a 91 61 85"
+		 "cb 04 07 d3 20 16 cb a2"),
+	      DES_BLOCK_SIZE, "Now is t",
+	      H("0a 5d b5 2d 85 74 d1 c9"));
+
+  SUCCESS();
+}
diff --git a/testsuite/des3-test.m4 b/testsuite/des3-test.m4
deleted file mode 100644
index 86056f68dfe638992ed5dfd134e1218ac3a54375..0000000000000000000000000000000000000000
--- a/testsuite/des3-test.m4
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "des.h"
-
-BEGIN_TEST
-
-struct des3_ctx ctx;
-
-uint8_t msg[DES3_BLOCK_SIZE] = "Now is t";
-uint8_t cipher[DES3_BLOCK_SIZE];
-uint8_t clear[DES3_BLOCK_SIZE];
-
-/* Intermediate values:
- *   After first DES encryption:  "cd ea 2a 20 c2 e0 9e 48"
- *   After second DES decryption: "69 52 6e 95 8b ea 49 bd"
- */
-if (!des3_set_key(&ctx, H("3e 0b 10 b0 5d 49 c2 54"
-			  "6b 46 e0 75 8a 91 61 85"
-			  "cb 04 07 d3 20 16 cb a2")))
-  FAIL;
-
-des3_encrypt(&ctx, DES_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(DES_BLOCK_SIZE, cipher,
-	H("0a 5d b5 2d 85 74 d1 c9")))
-  FAIL;
-
-des3_decrypt(&ctx, DES_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(DES_BLOCK_SIZE, msg, clear))
-  FAIL;
diff --git a/testsuite/macros.m4 b/testsuite/macros.m4
deleted file mode 100644
index d5bcce7e3de570fb8d3ba10b75f55fd401fcbe23..0000000000000000000000000000000000000000
--- a/testsuite/macros.m4
+++ /dev/null
@@ -1,26 +0,0 @@
-m4_dnl nettle testsuite driver
-m4_changecom(/*, */)m4_dnl
-m4_dnl End of the C code
-m4_divert(1)m4_dnl
-  /* Avoid warnings for argc and argv unused */
-  (void) argc; (void) argv;
-  return 0;
-}
-m4_divert
-m4_define(`BEGIN_TEST',
-`
-m4_dnl Start of the C code.
-#include "testutils.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-int main (int argc, char **argv)
-{
-')m4_dnl
-m4_define(`H', `m4_ifelse(`$#',1,
-			  `decode_hex_dup($1)',
-			  `decode_hex($1, $2)')')m4_dnl
-m4_define(`MEMEQ', `(!memcmp ($2, $3, $1))')m4_dnl
-m4_define(`FAIL', `abort()')m4_dnl
-m4_define(`SKIP', `exit(77)')m4_dnl
diff --git a/testsuite/md5-compat-test.c b/testsuite/md5-compat-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..4304ea853e5b62b4eb562fbf5ed7ed42b42edb31
--- /dev/null
+++ b/testsuite/md5-compat-test.c
@@ -0,0 +1,60 @@
+#include "testutils.h"
+#include "md5-compat.h"
+
+int
+main(int argc, char **argv)
+{
+  MD5_CTX ctx;
+  unsigned char digest[MD5_DIGEST_SIZE];
+
+  MD5Init(&ctx);
+  MD5Final(digest, &ctx);
+  if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("D41D8CD98F00B204 E9800998ECF8427E")))
+    FAIL();
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, "a", 1);
+  MD5Final(digest, &ctx);
+
+  if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("0CC175B9C0F1B6A8 31C399E269772661")))
+    FAIL();
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, "abc", 3);
+  MD5Final(digest, &ctx);
+
+  if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("900150983cd24fb0 D6963F7D28E17F72")))
+    FAIL();
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, "message digest", 14);
+  MD5Final(digest, &ctx);
+
+  if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("F96B697D7CB7938D 525A2F31AAF161D0")))
+    FAIL();
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, "abcdefghijklmnopqrstuvwxyz", 26);
+  MD5Final(digest, &ctx);
+
+  if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("C3FCD3D76192E400 7DFB496CCA67E13B")))
+    FAIL();
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62);
+  MD5Final(digest, &ctx);
+
+  if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("D174AB98D277D9F5 A5611C2C9F419D9F")))
+    FAIL();
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, "1234567890123456789012345678901234567890"
+	    "1234567890123456789012345678901234567890",
+	    80);
+  MD5Final(digest, &ctx);
+
+  if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("57EDF4A22BE3C955 AC49DA2E2107B67A")))
+    FAIL();
+
+  SUCCESS();
+}
diff --git a/testsuite/md5-compat-test.m4 b/testsuite/md5-compat-test.m4
deleted file mode 100644
index 7ad598aaace054259a640e8dc9112a58ddafda67..0000000000000000000000000000000000000000
--- a/testsuite/md5-compat-test.m4
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "md5-compat.h"
-
-BEGIN_TEST
-
-MD5_CTX ctx;
-unsigned char digest[MD5_DIGEST_SIZE];
-
-MD5Init(&ctx);
-MD5Final(digest, &ctx);
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("D41D8CD98F00B204 E9800998ECF8427E")))
-  FAIL;
-
-MD5Init(&ctx);
-MD5Update(&ctx, "a", 1);
-MD5Final(digest, &ctx);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("0CC175B9C0F1B6A8 31C399E269772661")))
-  FAIL;
-
-MD5Init(&ctx);
-MD5Update(&ctx, "abc", 3);
-MD5Final(digest, &ctx);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("900150983cd24fb0 D6963F7D28E17F72")))
-  FAIL;
-
-MD5Init(&ctx);
-MD5Update(&ctx, "message digest", 14);
-MD5Final(digest, &ctx);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("F96B697D7CB7938D 525A2F31AAF161D0")))
-  FAIL;
-
-MD5Init(&ctx);
-MD5Update(&ctx, "abcdefghijklmnopqrstuvwxyz", 26);
-MD5Final(digest, &ctx);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("C3FCD3D76192E400 7DFB496CCA67E13B")))
-  FAIL;
-
-MD5Init(&ctx);
-MD5Update(&ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62);
-MD5Final(digest, &ctx);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("D174AB98D277D9F5 A5611C2C9F419D9F")))
-  FAIL;
-
-MD5Init(&ctx);
-MD5Update(&ctx, "1234567890123456789012345678901234567890"
-                "1234567890123456789012345678901234567890",
-          80);
-MD5Final(digest, &ctx);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("57EDF4A22BE3C955 AC49DA2E2107B67A")))
-  FAIL;
-
diff --git a/testsuite/md5-test.c b/testsuite/md5-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..a65958ab5dfd29b9e6bccd0fa0f287a1652fd5a9
--- /dev/null
+++ b/testsuite/md5-test.c
@@ -0,0 +1,34 @@
+#include "testutils.h"
+#include "md5.h"
+
+int
+main(int argc, char **argv)
+{
+  test_hash(&nettle_md5, 0, "",
+	    H("D41D8CD98F00B204 E9800998ECF8427E"));
+
+  test_hash(&nettle_md5, 1, "a",
+	    H("0CC175B9C0F1B6A8 31C399E269772661"));
+	    
+  test_hash(&nettle_md5, 3, "abc",
+	    H("900150983cd24fb0 D6963F7D28E17F72"));
+
+  test_hash(&nettle_md5, 14, "message digest",
+	    H("F96B697D7CB7938D 525A2F31AAF161D0"));
+  
+  test_hash(&nettle_md5, 26, "abcdefghijklmnopqrstuvwxyz",
+	    H("C3FCD3D76192E400 7DFB496CCA67E13B"));
+  
+  test_hash(&nettle_md5, 62,
+	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	    "abcdefghijklmnopqrstuvwxyz"
+	    "0123456789",
+	    H("D174AB98D277D9F5 A5611C2C9F419D9F"));
+
+  test_hash(&nettle_md5, 80,
+	    "1234567890123456789012345678901234567890"
+	    "1234567890123456789012345678901234567890",
+	    H("57EDF4A22BE3C955 AC49DA2E2107B67A"));
+
+  SUCCESS();
+}
diff --git a/testsuite/md5-test.m4 b/testsuite/md5-test.m4
deleted file mode 100644
index 0115bcc0c9c1395cbc99a15ba18f7cba6bf64525..0000000000000000000000000000000000000000
--- a/testsuite/md5-test.m4
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "md5.h"
-
-BEGIN_TEST
-
-struct md5_ctx ctx;
-uint8_t digest[MD5_DIGEST_SIZE];
-
-md5_init(&ctx);
-md5_digest(&ctx, MD5_DIGEST_SIZE, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("D41D8CD98F00B204 E9800998ECF8427E")))
-  FAIL;
-
-memset(digest, 0, MD5_DIGEST_SIZE);
-md5_digest(&ctx, MD5_DIGEST_SIZE - 1, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("D41D8CD98F00B204 E9800998ECF84200")))
-  FAIL;
-
-md5_update(&ctx, 1, "a");
-md5_digest(&ctx, MD5_DIGEST_SIZE, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("0CC175B9C0F1B6A8 31C399E269772661")))
-  FAIL;
-
-md5_update(&ctx, 3, "abc");
-md5_digest(&ctx, MD5_DIGEST_SIZE, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("900150983cd24fb0 D6963F7D28E17F72")))
-  FAIL;
-
-md5_update(&ctx, 14, "message digest");
-md5_digest(&ctx, MD5_DIGEST_SIZE, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("F96B697D7CB7938D 525A2F31AAF161D0")))
-  FAIL;
-
-md5_update(&ctx, 26, "abcdefghijklmnopqrstuvwxyz");
-md5_digest(&ctx, MD5_DIGEST_SIZE, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("C3FCD3D76192E400 7DFB496CCA67E13B")))
-  FAIL;
-
-md5_update(&ctx, 62, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
-md5_digest(&ctx, MD5_DIGEST_SIZE, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("D174AB98D277D9F5 A5611C2C9F419D9F")))
-  FAIL;
-
-md5_update(&ctx, 80, "1234567890123456789012345678901234567890"
-	            "1234567890123456789012345678901234567890");
-md5_digest(&ctx, MD5_DIGEST_SIZE, digest);
-
-if (!MEMEQ(MD5_DIGEST_SIZE, digest, H("57EDF4A22BE3C955 AC49DA2E2107B67A")))
-  FAIL;
-
diff --git a/testsuite/serpent-test.c b/testsuite/serpent-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..345417e4fa29e9f71551c4ba43dd5d39a15c5bd7
--- /dev/null
+++ b/testsuite/serpent-test.c
@@ -0,0 +1,57 @@
+#include "testutils.h"
+#include "serpent.h"
+
+int
+main(int argc, char **argv)
+{
+  /* The first test for each key size from the ecb_vk.txt and ecb_vt.txt
+   * files in the serpent package. */
+
+  /* 128 bit key */
+
+  /* vk, 1 */
+  test_cipher(&nettle_serpent128,
+	      HL("8000000000000000 0000000000000000"),
+	      HL("0000000000000000 0000000000000000"),
+	      H("49AFBFAD9D5A3405 2CD8FFA5986BD2DD"));
+
+  /* vt, 1 */
+  test_cipher(&nettle_serpent128,
+	      HL("0000000000000000 0000000000000000"),
+	      HL("8000000000000000 0000000000000000"),
+	      H("10B5FFB720B8CB90 02A1142B0BA2E94A"));
+
+  /* 192 bit key */
+
+  /* vk, 1 */
+  test_cipher(&nettle_serpent192,
+	      HL("8000000000000000 0000000000000000"
+		 "0000000000000000"),
+	      HL("0000000000000000 0000000000000000"),
+	      H("E78E5402C7195568 AC3678F7A3F60C66"));
+
+  /* vt, 1 */
+  test_cipher(&nettle_serpent192,
+	      HL("0000000000000000 0000000000000000"
+		 "0000000000000000"),
+	      HL("8000000000000000 0000000000000000"),
+	      H("B10B271BA25257E1 294F2B51F076D0D9"));
+
+  /* 256 bit key */
+
+  /* vk, 1 */
+  test_cipher(&nettle_serpent256,
+	      HL("8000000000000000 0000000000000000"
+		 "0000000000000000 0000000000000000"),
+	      HL("0000000000000000 0000000000000000"),
+	      H("ABED96E766BF28CB C0EBD21A82EF0819"));
+
+  /* vt, 1 */
+  test_cipher(&nettle_serpent256,
+	      HL("0000000000000000 0000000000000000"
+		 "0000000000000000 0000000000000000"),
+	      HL("8000000000000000 0000000000000000"),
+	      H("DA5A7992B1B4AE6F 8C004BC8A7DE5520"));
+
+  SUCCESS();
+}
diff --git a/testsuite/serpent-test.m4 b/testsuite/serpent-test.m4
deleted file mode 100644
index f51b54057030ae67aaecf7a5148cb1abc0ac0add..0000000000000000000000000000000000000000
--- a/testsuite/serpent-test.m4
+++ /dev/null
@@ -1,107 +0,0 @@
-#include "serpent.h"
-
-BEGIN_TEST
-
-struct serpent_ctx ctx;
-
-uint8_t msg[SERPENT_BLOCK_SIZE];
-uint8_t cipher[SERPENT_BLOCK_SIZE];
-uint8_t clear[SERPENT_BLOCK_SIZE];
-
-/* The first test for each key size from the ecb_vk.txt and ecb_vt.txt
- * files in the serpent package. */
-
-/* 128 bit key */
-
-/* vk, 1 */
-H(msg, "0000000000000000 0000000000000000");
-
-serpent_set_key(&ctx, 16, H("8000000000000000 0000000000000000"));
-serpent_encrypt(&ctx, SERPENT_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(SERPENT_BLOCK_SIZE, cipher,
-	H("49AFBFAD9D5A3405 2CD8FFA5986BD2DD")))
-  FAIL;
-
-serpent_decrypt(&ctx, SERPENT_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(SERPENT_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* vt, 1 */
-H(msg, "8000000000000000 0000000000000000");
-
-serpent_set_key(&ctx, 16, H("0000000000000000 0000000000000000"));
-serpent_encrypt(&ctx, SERPENT_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(SERPENT_BLOCK_SIZE, cipher,
-	H("10B5FFB720B8CB90 02A1142B0BA2E94A")))
-  FAIL;
-
-serpent_decrypt(&ctx, SERPENT_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(SERPENT_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* 192 bit key */
-
-/* vk, 1 */
-H(msg, "0000000000000000 0000000000000000");
-
-serpent_set_key(&ctx, 24, H("8000000000000000 0000000000000000"
-			    "0000000000000000"));
-serpent_encrypt(&ctx, SERPENT_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(SERPENT_BLOCK_SIZE, cipher,
-	H("E78E5402C7195568 AC3678F7A3F60C66")))
-  FAIL;
-
-serpent_decrypt(&ctx, SERPENT_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(SERPENT_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* vt, 1 */
-H(msg, "8000000000000000 0000000000000000");
-
-serpent_set_key(&ctx, 24, H("0000000000000000 0000000000000000"
-			    "0000000000000000"));
-serpent_encrypt(&ctx, SERPENT_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(SERPENT_BLOCK_SIZE, cipher,
-	H("B10B271BA25257E1 294F2B51F076D0D9")))
-  FAIL;
-
-serpent_decrypt(&ctx, SERPENT_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(SERPENT_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* 256 bit key */
-
-/* vk, 1 */
-H(msg, "0000000000000000 0000000000000000");
-
-serpent_set_key(&ctx, 32, H("8000000000000000 0000000000000000"
-			    "0000000000000000 0000000000000000"));
-serpent_encrypt(&ctx, SERPENT_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(SERPENT_BLOCK_SIZE, cipher,
-	H("ABED96E766BF28CB C0EBD21A82EF0819")))
-  FAIL;
-
-serpent_decrypt(&ctx, SERPENT_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(SERPENT_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* vt, 1 */
-H(msg, "8000000000000000 0000000000000000");
-
-serpent_set_key(&ctx, 32, H("0000000000000000 0000000000000000"
-			    "0000000000000000 0000000000000000"));
-serpent_encrypt(&ctx, SERPENT_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(SERPENT_BLOCK_SIZE, cipher,
-	H("DA5A7992B1B4AE6F 8C004BC8A7DE5520")))
-  FAIL;
-
-serpent_decrypt(&ctx, SERPENT_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(SERPENT_BLOCK_SIZE, msg, clear))
-  FAIL;
-
diff --git a/testsuite/sha1-test.c b/testsuite/sha1-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f602c97f491091eb0b762a113403935008e3a24
--- /dev/null
+++ b/testsuite/sha1-test.c
@@ -0,0 +1,33 @@
+#include "testutils.h"
+#include "sha.h"
+
+int
+main(int argc, char **argv)
+{
+  test_hash(&nettle_sha1, 0, "",
+	    H("DA39A3EE5E6B4B0D 3255BFEF95601890 AFD80709")); 
+
+  test_hash(&nettle_sha1, 1, "a",
+	    H("86F7E437FAA5A7FC E15D1DDCB9EAEAEA 377667B8")); 
+
+  test_hash(&nettle_sha1, 3, "abc",
+	    H("A9993E364706816A BA3E25717850C26C 9CD0D89D"));
+  
+  test_hash(&nettle_sha1, 26, "abcdefghijklmnopqrstuvwxyz",
+	    H("32D10C7B8CF96570 CA04CE37F2A19D84 240D3A89"));
+  
+  test_hash(&nettle_sha1, 14, "message digest",
+	    H("C12252CEDA8BE899 4D5FA0290A47231C 1D16AAE3")); 
+
+  test_hash(&nettle_sha1, 62,
+	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	    "abcdefghijklmnopqrstuvwxyz0123456789",
+	    H("761C457BF73B14D2 7E9E9265C46F4B4D DA11F940"));
+  
+  test_hash(&nettle_sha1,  80,
+	    "1234567890123456789012345678901234567890"
+	    "1234567890123456789012345678901234567890",
+	    H("50ABF5706A150990 A08B2C5EA40FA0E5 85554732"));
+
+  SUCCESS();
+}
diff --git a/testsuite/sha1-test.m4 b/testsuite/sha1-test.m4
deleted file mode 100644
index 22db4c59518d62d148d7e783ba3d84a07c225314..0000000000000000000000000000000000000000
--- a/testsuite/sha1-test.m4
+++ /dev/null
@@ -1,71 +0,0 @@
-#include "sha.h"
-
-BEGIN_TEST
-
-struct sha1_ctx ctx;
-uint8_t digest[SHA1_DIGEST_SIZE];
-
-sha1_init(&ctx);
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("DA39A3EE5E6B4B0D 3255BFEF95601890 AFD80709")))
-  FAIL;
-
-sha1_update(&ctx, 1, "a");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("86F7E437FAA5A7FC E15D1DDCB9EAEAEA 377667B8")))
-  FAIL;
-
-memset(digest, 0, SHA1_DIGEST_SIZE);
-sha1_update(&ctx, 1, "a");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE - 1, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("86F7E437FAA5A7FC E15D1DDCB9EAEAEA 37766700")))
-  FAIL;
-
-sha1_update(&ctx, 1, "a");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("86F7E437FAA5A7FC E15D1DDCB9EAEAEA 377667B8")))
-  FAIL;
-
-sha1_update(&ctx, 3, "abc");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("A9993E364706816A BA3E25717850C26C 9CD0D89D")))
-  FAIL;
-
-sha1_update(&ctx, 26, "abcdefghijklmnopqrstuvwxyz");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("32D10C7B8CF96570 CA04CE37F2A19D84 240D3A89")))
-  FAIL;
-
-sha1_update(&ctx, 14, "message digest");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("C12252CEDA8BE899 4D5FA0290A47231C 1D16AAE3")))
-  FAIL;
-
-sha1_update(&ctx, 62, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("761C457BF73B14D2 7E9E9265C46F4B4D DA11F940")))
-  FAIL;
-
-sha1_update(&ctx, 80, "1234567890123456789012345678901234567890"
-	              "1234567890123456789012345678901234567890");
-sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA1_DIGEST_SIZE, digest,
-	   H("50ABF5706A150990 A08B2C5EA40FA0E5 85554732")))
-  FAIL;
diff --git a/testsuite/sha256-test.c b/testsuite/sha256-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..89a0a23497ea423156c2a5a4e0e67cb0ca8592f2
--- /dev/null
+++ b/testsuite/sha256-test.c
@@ -0,0 +1,26 @@
+#include "testutils.h"
+#include "sha.h"
+
+int
+main(int argc, char **argv)
+{
+  test_hash(&nettle_sha256, 3, "abc",
+	    H("ba7816bf8f01cfea 414140de5dae2223"
+	      "b00361a396177a9c b410ff61f20015ad"));
+
+  test_hash(&nettle_sha256, 56,
+	    "abcdbcdecdefdefgefghfghighij"
+	    "hijkijkljklmklmnlmnomnopnopq",
+	    H("248d6a61d20638b8 e5c026930c3e6039"
+	      "a33ce45964ff2167 f6ecedd419db06c1"));
+
+  test_hash(&nettle_sha256, 112,
+	    "abcdefghbcdefghicdefghijdefg"
+	    "hijkefghijklfghijklmghijklmn"
+	    "hijklmnoijklmnopjklmnopqklmn"
+	    "opqrlmnopqrsmnopqrstnopqrstu",
+	    H("cf5b16a778af8380 036ce59e7b049237"
+	      "0b249b11e8f07a51 afac45037afee9d1"));
+
+    SUCCESS();
+}
diff --git a/testsuite/sha256-test.m4 b/testsuite/sha256-test.m4
deleted file mode 100644
index 9b2128f49c385b1873f220028bb675bec62658f4..0000000000000000000000000000000000000000
--- a/testsuite/sha256-test.m4
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "sha.h"
-
-BEGIN_TEST
-
-struct sha256_ctx ctx;
-uint8_t digest[SHA256_DIGEST_SIZE];
-
-sha256_init(&ctx);
-sha256_update(&ctx, 3, "abc");
-sha256_digest(&ctx, SHA256_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA256_DIGEST_SIZE, digest,
-	   H("ba7816bf8f01cfea 414140de5dae2223 b00361a396177a9c b410ff61f20015ad")))
-  FAIL;
-
-memset(digest, 0, SHA256_DIGEST_SIZE);
-sha256_update(&ctx, 3, "abc");
-sha256_digest(&ctx, SHA256_DIGEST_SIZE - 1, digest);
-
-if (!MEMEQ(SHA256_DIGEST_SIZE, digest,
-	   H("ba7816bf8f01cfea 414140de5dae2223 b00361a396177a9c b410ff61f2001500")))
-  FAIL;
-
-sha256_update(&ctx, 56, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
-sha256_digest(&ctx, SHA256_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA256_DIGEST_SIZE, digest,
-	   H("248d6a61d20638b8 e5c026930c3e6039 a33ce45964ff2167 f6ecedd419db06c1")))
-  FAIL;
-
-sha256_update(&ctx, 112, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"
-			 "ijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
-sha256_digest(&ctx, SHA256_DIGEST_SIZE, digest);
-
-if (!MEMEQ(SHA256_DIGEST_SIZE, digest,
-	   H("cf5b16a778af8380 036ce59e7b049237 0b249b11e8f07a51 afac45037afee9d1")))
-  FAIL;
diff --git a/testsuite/testutils.c b/testsuite/testutils.c
index ee0cd5e33db4f56daef049130127b2f8414cfd8b..152b4f35cdaf4b1775b6d43c6a72f5dac034cec1 100644
--- a/testsuite/testutils.c
+++ b/testsuite/testutils.c
@@ -2,15 +2,14 @@
 
 #include "testutils.h"
 
+#include "cbc.h"
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 
-int
-decode_hex(uint8_t *dst, const char *hex)
-{  
-  /* -1 means invalid */
-  const signed char hex_digits[0x100] =
+/* -1 means invalid */
+const signed char hex_digits[0x100] =
   {
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
@@ -29,29 +28,55 @@ decode_hex(uint8_t *dst, const char *hex)
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
   };
+
+unsigned
+decode_hex_length(const char *h)
+{
+  const unsigned char *hex = (const unsigned char *) h;
+  unsigned count;
+  unsigned i;
+  
+  for (count = i = 0; hex[i]; i++)
+    {
+      if (isspace(hex[i]))
+	continue;
+      if (hex_digits[hex[i]] < 0)
+	abort();
+      count++;
+    }
+
+  if (count % 2)
+    abort();
+  return count / 2;  
+}
+
+int
+decode_hex(uint8_t *dst, const char *h)
+{  
+  const unsigned char *hex = (const unsigned char *) h;
   unsigned i = 0;
-    
+  
   for (;;)
   {
     int high, low;
     
-    while (*hex && isspace((unsigned)*hex))
+    while (*hex && isspace(*hex))
       hex++;
 
     if (!*hex)
       return 1;
 
-    high = hex_digits[(unsigned)*hex++];
+    high = hex_digits[*hex++];
     if (high < 0)
       return 0;
 
-    while (*hex && isspace((unsigned)*hex))
+    while (*hex && isspace(*hex))
       hex++;
 
     if (!*hex)
       return 0;
 
-    low = hex_digits[(unsigned)*hex++];
+    low = hex_digits[*hex++];
     if (low < 0)
       return 0;
 
@@ -63,10 +88,9 @@ const uint8_t *
 decode_hex_dup(const char *hex)
 {
   uint8_t *p;
-  unsigned length = strlen(hex);
+  unsigned length = decode_hex_length(hex);
 
-  /* Allocates a little more than necessary. */
-  p = malloc(length/2);
+  p = malloc(length);
   if (!p)
     abort();
 
@@ -78,3 +102,90 @@ decode_hex_dup(const char *hex)
       return NULL;
     }
 }
+
+void
+test_cipher(const struct nettle_cipher *cipher,
+	    unsigned key_length,
+	    const uint8_t *key,
+	    unsigned length,
+	    const uint8_t *cleartext,
+	    const uint8_t *ciphertext)
+{
+  void *ctx = alloca(cipher->context_size);
+  uint8_t *data = alloca(length);
+
+  cipher->set_encrypt_key(ctx, key_length, key);
+  cipher->encrypt(ctx, length, data, cleartext);
+
+  if (!MEMEQ(length, data, ciphertext))
+    FAIL();
+
+  cipher->set_decrypt_key(ctx, key_length, key);
+  cipher->decrypt(ctx, length, data, data);
+
+  if (!MEMEQ(length, data, cleartext))
+    FAIL();
+}
+
+void
+test_cipher_cbc(const struct nettle_cipher *cipher,
+		unsigned key_length,
+		const uint8_t *key,
+		unsigned length,
+		const uint8_t *cleartext,
+		const uint8_t *ciphertext,
+		const uint8_t *iiv)
+{
+  void *ctx = alloca(cipher->context_size);
+  uint8_t *data = alloca(length);
+  uint8_t *iv = alloca(cipher->block_size);
+  
+  cipher->set_encrypt_key(ctx, key_length, key);
+  memcpy(iv, iiv, cipher->block_size);
+
+  cbc_encrypt(ctx, cipher->encrypt,
+	      cipher->block_size, iv,
+	      length, data, cleartext);
+
+  if (!MEMEQ(length, data, ciphertext))
+    FAIL();
+
+  cipher->set_decrypt_key(ctx, key_length, key);
+  memcpy(iv, iiv, cipher->block_size);
+
+  cbc_decrypt(ctx, cipher->decrypt,
+	      cipher->block_size, iv,
+	      length, data, data);
+
+  if (!MEMEQ(length, data, cleartext))
+    FAIL();
+}
+
+void
+test_hash(const struct nettle_hash *hash,
+	  unsigned length,
+	  const uint8_t *data,
+	  const uint8_t *digest)
+{
+  void *ctx = alloca(hash->context_size);
+  uint8_t *buffer = alloca(hash->digest_size);
+
+  hash->init(ctx);
+  hash->update(ctx, length, data);
+  hash->digest(ctx, hash->digest_size, buffer);
+
+  if (!MEMEQ(hash->digest_size, digest, buffer))
+    FAIL();
+
+  memset(buffer, 0, hash->digest_size);
+
+  hash->init(ctx);
+  hash->update(ctx, length, data);
+  hash->digest(ctx, hash->digest_size - 1, buffer);
+
+  if (!MEMEQ(hash->digest_size - 1, digest, buffer))
+    FAIL();
+
+  if (buffer[hash->digest_size - 1])
+    FAIL();
+}
diff --git a/testsuite/testutils.h b/testsuite/testutils.h
index fd231410de72a45ca0723c9f92b8eaa642c5730b..efdb6d66de8a989dc9e14cefcd9b4a62611b6057 100644
--- a/testsuite/testutils.h
+++ b/testsuite/testutils.h
@@ -3,7 +3,16 @@
 
 #include <inttypes.h>
 
+#include <string.h>
+#include <stdlib.h>
+
+#include "nettle-meta.h"
+
 /* Decodes a NUL-terminated hex string. */
+
+unsigned
+decode_hex_length(const char *hex);
+
 int
 decode_hex(uint8_t *dst, const char *hex);
 
@@ -11,5 +20,37 @@ decode_hex(uint8_t *dst, const char *hex);
 const uint8_t *
 decode_hex_dup(const char *hex);
 
+void
+test_cipher(const struct nettle_cipher *cipher,
+	    unsigned key_length,
+	    const uint8_t *key,
+	    unsigned length,
+	    const uint8_t *cleartext,
+	    const uint8_t *ciphertext);
+
+void
+test_cipher_cbc(const struct nettle_cipher *cipher,
+		unsigned key_length,
+		const uint8_t *key,
+		unsigned length,
+		const uint8_t *cleartext,
+		const uint8_t *ciphertext,
+		const uint8_t *iv);
+
+void
+test_hash(const struct nettle_hash *hash,
+	  unsigned length,
+	  const uint8_t *data,
+	  const uint8_t *digest);
+	  
+#define H2(d, s) decode_hex((d), (s))
+#define H(x) decode_hex_dup(x)
+#define HL(x) decode_hex_length(x), decode_hex_dup(x)
+
+#define MEMEQ(length, a, b) (!memcmp((a), (b), (length)))
+
+#define FAIL() abort()
+#define SKIP() exit(77)
+#define SUCCESS() return EXIT_SUCCESS
 
 #endif /* NETTLE_TESTUTILS_H_INCLUDED */
diff --git a/testsuite/twofish-test.c b/testsuite/twofish-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..935c05230b6599ad40f7f98ad34e0c3ab286d931
--- /dev/null
+++ b/testsuite/twofish-test.c
@@ -0,0 +1,28 @@
+#include "testutils.h"
+#include "twofish.h"
+
+int
+main(int argc, char **argv)
+{
+  /* 128 bit key */
+  test_cipher(&nettle_twofish128,
+	      HL("0000000000000000 0000000000000000"),
+	      HL("0000000000000000 0000000000000000"),
+	      H("9F589F5CF6122C32 B6BFEC2F2AE8C35A"));
+
+  /* 192 bit key */
+  test_cipher(&nettle_twofish192,
+	      HL("0123456789ABCDEF FEDCBA9876543210"
+		 "0011223344556677"),
+	      HL("0000000000000000 0000000000000000"),
+	      H("CFD1D2E5A9BE9CDF 501F13B892BD2248"));
+
+  /* 256 bit key */
+  test_cipher(&nettle_twofish256,
+	      HL("0123456789ABCDEF FEDCBA9876543210"
+		 "0011223344556677 8899AABBCCDDEEFF"),
+	      HL("0000000000000000 0000000000000000"),
+	      H("37527BE0052334B8 9F0CFCCAE87CFA20"));
+
+  SUCCESS();
+}
diff --git a/testsuite/twofish-test.m4 b/testsuite/twofish-test.m4
deleted file mode 100644
index 98840bf2bb61f3b7d7ef701a265bba527a95ff21..0000000000000000000000000000000000000000
--- a/testsuite/twofish-test.m4
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "twofish.h"
-
-BEGIN_TEST
-
-struct twofish_ctx ctx;
-
-uint8_t msg[TWOFISH_BLOCK_SIZE];
-uint8_t cipher[TWOFISH_BLOCK_SIZE];
-uint8_t clear[TWOFISH_BLOCK_SIZE];
-
-/* 128 bit key */
-H(msg, "0000000000000000 0000000000000000");
-
-twofish_set_key(&ctx, 16, H("0000000000000000 0000000000000000"));
-twofish_encrypt(&ctx, TWOFISH_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(TWOFISH_BLOCK_SIZE, cipher,
-	H("9F589F5CF6122C32 B6BFEC2F2AE8C35A")))
-  FAIL;
-
-twofish_decrypt(&ctx, TWOFISH_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(TWOFISH_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* 192 bit key */
-
-twofish_set_key(&ctx, 24, H("0123456789ABCDEF FEDCBA9876543210"
-			    "0011223344556677"));
-twofish_encrypt(&ctx, TWOFISH_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(TWOFISH_BLOCK_SIZE, cipher,
-	H("CFD1D2E5A9BE9CDF 501F13B892BD2248")))
-  FAIL;
-
-twofish_decrypt(&ctx, TWOFISH_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(TWOFISH_BLOCK_SIZE, msg, clear))
-  FAIL;
-
-/* 256 bit key */
-twofish_set_key(&ctx, 32, H("0123456789ABCDEF FEDCBA9876543210"
-			    "0011223344556677 8899AABBCCDDEEFF"));
-twofish_encrypt(&ctx, TWOFISH_BLOCK_SIZE, cipher, msg);
-
-if (!MEMEQ(TWOFISH_BLOCK_SIZE, cipher,
-	H("37527BE0052334B8 9F0CFCCAE87CFA20")))
-  FAIL;
-
-twofish_decrypt(&ctx, TWOFISH_BLOCK_SIZE, clear, cipher);
-if (!MEMEQ(TWOFISH_BLOCK_SIZE, msg, clear))
-  FAIL;