2003-08-19 Moritz Schulte <mo@g10code.com>
authorMoritz Schulte <mo@g10code.com>
Wed, 27 Aug 2003 16:41:22 +0000 (16:41 +0000)
committerMoritz Schulte <mo@g10code.com>
Wed, 27 Aug 2003 16:41:22 +0000 (16:41 +0000)
* cipher.c: Add support for Serpent
* serpent.c: New file.

2003-08-10  Moritz Schulte  <moritz@g10code.com>

* rsa.c (_gcry_rsa_blind, _gcry_rsa_unblind): Declare static.

cipher/ChangeLog
cipher/cipher.c
cipher/rsa.c
cipher/serpent.c [new file with mode: 0644]

index efab746..0d8011c 100644 (file)
@@ -1,3 +1,12 @@
+2003-08-19  Moritz Schulte  <mo@g10code.com>
+
+       * cipher.c: Add support for Serpent
+       * serpent.c: New file.
+
+2003-08-10  Moritz Schulte  <moritz@g10code.com>
+
+       * rsa.c (_gcry_rsa_blind, _gcry_rsa_unblind): Declare static.
+
 2003-08-09  Timo Schulz  <twoaday@freakmail.de>
 
        * random.c (getfnc_gather_random): Don't check NAME_OF_DEV_RANDOM
index 13b5040..73544d2 100644 (file)
@@ -64,6 +64,11 @@ static struct cipher_table_entry
     { &cipher_spec_twofish,    GCRY_CIPHER_TWOFISH },
     { &cipher_spec_twofish128, GCRY_CIPHER_TWOFISH128 },
 #endif
+#if USE_SERPENT
+    { &cipher_spec_serpent128, GCRY_CIPHER_SERPENT128 },
+    { &cipher_spec_serpent192, GCRY_CIPHER_SERPENT192 },
+    { &cipher_spec_serpent256, GCRY_CIPHER_SERPENT256 },
+#endif
     { NULL                    },
   };
 
index bd110b9..d62ae04 100644 (file)
@@ -444,7 +444,7 @@ _gcry_rsa_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *pk
 }
 
 /* Perform RSA blinding.  */
-gcry_mpi_t
+static gcry_mpi_t
 _gcry_rsa_blind (gcry_mpi_t x, gcry_mpi_t r, gcry_mpi_t e, gcry_mpi_t n)
 {
   /* A helper.  */
@@ -468,7 +468,7 @@ _gcry_rsa_blind (gcry_mpi_t x, gcry_mpi_t r, gcry_mpi_t e, gcry_mpi_t n)
 }
 
 /* Undo RSA blinding.  */
-gcry_mpi_t
+static gcry_mpi_t
 _gcry_rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n)
 {
   gcry_mpi_t y;
diff --git a/cipher/serpent.c b/cipher/serpent.c
new file mode 100644 (file)
index 0000000..f3fe2a5
--- /dev/null
@@ -0,0 +1,956 @@
+/* serpent.c - Implementation of the Serpent encryption algorithm.
+ *     Copyright (C) 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdio.h>
+
+#include "types.h"
+#include "g10lib.h"
+#include "cipher.h"
+#include "bithelp.h"
+
+/* Number of rounds per Serpent encrypt/decrypt operation.  */
+#define ROUNDS 32
+
+/* Magic number, used during generating of the subkeys.  */
+#define PHI 0x9E3779B9
+
+/* Internal types.  */
+typedef byte byte_t;
+typedef u32 u32_t;
+
+/* Serpent works on 128 bit blocks.  */
+typedef u32_t serpent_block_t[4];
+
+/* Serpent key, provided by the user.  If the original key is shorter
+   than 256 bits, it is padded.  */
+typedef u32_t serpent_key_t[8];
+
+/* The key schedule consists of 33 128 bit subkeys.  */
+typedef u32_t serpent_subkeys_t[ROUNDS + 1][4];
+
+/* A Serpent context.  */
+typedef struct serpent_context
+{
+  serpent_subkeys_t keys;      /* Generated subkeys.  */
+} serpent_context_t;
+
+#define byte_swap_32(x) \
+  (0 \
+   | (((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) \
+   | (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24));
+
+/* These are the S-Boxes of Serpent.  They are copied from Serpents
+   reference implementation (the optimized one, contained in
+   `floppy2') and are therefore:
+
+     Copyright (C) 1998 Ross Anderson, Eli Biham, Lars Knudsen.
+
+  To quote the Serpent homepage
+  (http://www.cl.cam.ac.uk/~rja14/serpent.html):
+
+  "Serpent is now completely in the public domain, and we impose no
+   restrictions on its use.  This was announced on the 21st August at
+   the First AES Candidate Conference. The optimised implementations
+   in the submission package are now under the GNU PUBLIC LICENSE
+   (GPL), although some comments in the code still say otherwise. You
+   are welcome to use Serpent for any application."  */
+
+#define SBOX0(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t05, t06, t07, t08, t09; \
+    register unsigned long t11, t12, t13, t14, t15, t17, t01; \
+    t01 = b   ^ c  ; \
+    t02 = a   | d  ; \
+    t03 = a   ^ b  ; \
+    z   = t02 ^ t01; \
+    t05 = c   | z  ; \
+    t06 = a   ^ d  ; \
+    t07 = b   | c  ; \
+    t08 = d   & t05; \
+    t09 = t03 & t07; \
+    y   = t09 ^ t08; \
+    t11 = t09 & y  ; \
+    t12 = c   ^ d  ; \
+    t13 = t07 ^ t11; \
+    t14 = b   & t06; \
+    t15 = t06 ^ t13; \
+    w   =     ~ t15; \
+    t17 = w   ^ t14; \
+    x   = t12 ^ t17; \
+  }
+
+#define SBOX0_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t08, t09, t10; \
+    register unsigned long t12, t13, t14, t15, t17, t18, t01; \
+    t01 = c   ^ d  ; \
+    t02 = a   | b  ; \
+    t03 = b   | c  ; \
+    t04 = c   & t01; \
+    t05 = t02 ^ t01; \
+    t06 = a   | t04; \
+    y   =     ~ t05; \
+    t08 = b   ^ d  ; \
+    t09 = t03 & t08; \
+    t10 = d   | y  ; \
+    x   = t09 ^ t06; \
+    t12 = a   | t05; \
+    t13 = x   ^ t12; \
+    t14 = t03 ^ t10; \
+    t15 = a   ^ c  ; \
+    z   = t14 ^ t13; \
+    t17 = t05 & t13; \
+    t18 = t14 | t17; \
+    w   = t15 ^ t18; \
+  }
+
+#define SBOX1(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t07, t08; \
+    register unsigned long t10, t11, t12, t13, t16, t17, t01; \
+    t01 = a   | d  ; \
+    t02 = c   ^ d  ; \
+    t03 =     ~ b  ; \
+    t04 = a   ^ c  ; \
+    t05 = a   | t03; \
+    t06 = d   & t04; \
+    t07 = t01 & t02; \
+    t08 = b   | t06; \
+    y   = t02 ^ t05; \
+    t10 = t07 ^ t08; \
+    t11 = t01 ^ t10; \
+    t12 = y   ^ t11; \
+    t13 = b   & d  ; \
+    z   =     ~ t10; \
+    x   = t13 ^ t12; \
+    t16 = t10 | x  ; \
+    t17 = t05 & t16; \
+    w   = c   ^ t17; \
+  }
+
+#define SBOX1_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t07, t08; \
+    register unsigned long t09, t10, t11, t14, t15, t17, t01; \
+    t01 = a   ^ b  ; \
+    t02 = b   | d  ; \
+    t03 = a   & c  ; \
+    t04 = c   ^ t02; \
+    t05 = a   | t04; \
+    t06 = t01 & t05; \
+    t07 = d   | t03; \
+    t08 = b   ^ t06; \
+    t09 = t07 ^ t06; \
+    t10 = t04 | t03; \
+    t11 = d   & t08; \
+    y   =     ~ t09; \
+    x   = t10 ^ t11; \
+    t14 = a   | y  ; \
+    t15 = t06 ^ x  ; \
+    z   = t01 ^ t04; \
+    t17 = c   ^ t15; \
+    w   = t14 ^ t17; \
+  }
+
+#define SBOX2(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t05, t06, t07, t08; \
+    register unsigned long t09, t10, t12, t13, t14, t01; \
+    t01 = a   | c  ; \
+    t02 = a   ^ b  ; \
+    t03 = d   ^ t01; \
+    w   = t02 ^ t03; \
+    t05 = c   ^ w  ; \
+    t06 = b   ^ t05; \
+    t07 = b   | t05; \
+    t08 = t01 & t06; \
+    t09 = t03 ^ t07; \
+    t10 = t02 | t09; \
+    x   = t10 ^ t08; \
+    t12 = a   | d  ; \
+    t13 = t09 ^ x  ; \
+    t14 = b   ^ t13; \
+    z   =     ~ t09; \
+    y   = t12 ^ t14; \
+  }
+
+#define SBOX2_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t06, t07, t08, t09; \
+    register unsigned long t10, t11, t12, t15, t16, t17, t01; \
+    t01 = a   ^ d  ; \
+    t02 = c   ^ d  ; \
+    t03 = a   & c  ; \
+    t04 = b   | t02; \
+    w   = t01 ^ t04; \
+    t06 = a   | c  ; \
+    t07 = d   | w  ; \
+    t08 =     ~ d  ; \
+    t09 = b   & t06; \
+    t10 = t08 | t03; \
+    t11 = b   & t07; \
+    t12 = t06 & t02; \
+    z   = t09 ^ t10; \
+    x   = t12 ^ t11; \
+    t15 = c   & z  ; \
+    t16 = w   ^ x  ; \
+    t17 = t10 ^ t15; \
+    y   = t16 ^ t17; \
+  }
+
+#define SBOX3(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t07, t08; \
+    register unsigned long t09, t10, t11, t13, t14, t15, t01; \
+    t01 = a   ^ c  ; \
+    t02 = a   | d  ; \
+    t03 = a   & d  ; \
+    t04 = t01 & t02; \
+    t05 = b   | t03; \
+    t06 = a   & b  ; \
+    t07 = d   ^ t04; \
+    t08 = c   | t06; \
+    t09 = b   ^ t07; \
+    t10 = d   & t05; \
+    t11 = t02 ^ t10; \
+    z   = t08 ^ t09; \
+    t13 = d   | z  ; \
+    t14 = a   | t07; \
+    t15 = b   & t13; \
+    y   = t08 ^ t11; \
+    w   = t14 ^ t15; \
+    x   = t05 ^ t04; \
+  }
+
+#define SBOX3_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t07, t09; \
+    register unsigned long t11, t12, t13, t14, t16, t01; \
+    t01 = c   | d  ; \
+    t02 = a   | d  ; \
+    t03 = c   ^ t02; \
+    t04 = b   ^ t02; \
+    t05 = a   ^ d  ; \
+    t06 = t04 & t03; \
+    t07 = b   & t01; \
+    y   = t05 ^ t06; \
+    t09 = a   ^ t03; \
+    w   = t07 ^ t03; \
+    t11 = w   | t05; \
+    t12 = t09 & t11; \
+    t13 = a   & y  ; \
+    t14 = t01 ^ t05; \
+    x   = b   ^ t12; \
+    t16 = b   | t13; \
+    z   = t14 ^ t16; \
+  }
+
+#define SBOX4(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t08, t09; \
+    register unsigned long t10, t11, t12, t13, t14, t15, t16, t01; \
+    t01 = a   | b  ; \
+    t02 = b   | c  ; \
+    t03 = a   ^ t02; \
+    t04 = b   ^ d  ; \
+    t05 = d   | t03; \
+    t06 = d   & t01; \
+    z   = t03 ^ t06; \
+    t08 = z   & t04; \
+    t09 = t04 & t05; \
+    t10 = c   ^ t06; \
+    t11 = b   & c  ; \
+    t12 = t04 ^ t08; \
+    t13 = t11 | t03; \
+    t14 = t10 ^ t09; \
+    t15 = a   & t05; \
+    t16 = t11 | t12; \
+    y   = t13 ^ t08; \
+    x   = t15 ^ t16; \
+    w   =     ~ t14; \
+  }
+
+#define SBOX4_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t07, t09; \
+    register unsigned long t10, t11, t12, t13, t15, t01; \
+    t01 = b   | d  ; \
+    t02 = c   | d  ; \
+    t03 = a   & t01; \
+    t04 = b   ^ t02; \
+    t05 = c   ^ d  ; \
+    t06 =     ~ t03; \
+    t07 = a   & t04; \
+    x   = t05 ^ t07; \
+    t09 = x   | t06; \
+    t10 = a   ^ t07; \
+    t11 = t01 ^ t09; \
+    t12 = d   ^ t04; \
+    t13 = c   | t10; \
+    z   = t03 ^ t12; \
+    t15 = a   ^ t04; \
+    y   = t11 ^ t13; \
+    w   = t15 ^ t09; \
+  }
+
+#define SBOX5(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t07, t08, t09; \
+    register unsigned long t10, t11, t12, t13, t14, t01; \
+    t01 = b   ^ d  ; \
+    t02 = b   | d  ; \
+    t03 = a   & t01; \
+    t04 = c   ^ t02; \
+    t05 = t03 ^ t04; \
+    w   =     ~ t05; \
+    t07 = a   ^ t01; \
+    t08 = d   | w  ; \
+    t09 = b   | t05; \
+    t10 = d   ^ t08; \
+    t11 = b   | t07; \
+    t12 = t03 | w  ; \
+    t13 = t07 | t10; \
+    t14 = t01 ^ t11; \
+    y   = t09 ^ t13; \
+    x   = t07 ^ t08; \
+    z   = t12 ^ t14; \
+  }
+
+#define SBOX5_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t07, t08, t09; \
+    register unsigned long t10, t12, t13, t15, t16, t01; \
+    t01 = a   & d  ; \
+    t02 = c   ^ t01; \
+    t03 = a   ^ d  ; \
+    t04 = b   & t02; \
+    t05 = a   & c  ; \
+    w   = t03 ^ t04; \
+    t07 = a   & w  ; \
+    t08 = t01 ^ w  ; \
+    t09 = b   | t05; \
+    t10 =     ~ b  ; \
+    x   = t08 ^ t09; \
+    t12 = t10 | t07; \
+    t13 = w   | x  ; \
+    z   = t02 ^ t12; \
+    t15 = t02 ^ t13; \
+    t16 = b   ^ d  ; \
+    y   = t16 ^ t15; \
+  }
+
+#define SBOX6(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t07, t08, t09, t10; \
+    register unsigned long t11, t12, t13, t15, t17, t18, t01; \
+    t01 = a   & d  ; \
+    t02 = b   ^ c  ; \
+    t03 = a   ^ d  ; \
+    t04 = t01 ^ t02; \
+    t05 = b   | c  ; \
+    x   =     ~ t04; \
+    t07 = t03 & t05; \
+    t08 = b   & x  ; \
+    t09 = a   | c  ; \
+    t10 = t07 ^ t08; \
+    t11 = b   | d  ; \
+    t12 = c   ^ t11; \
+    t13 = t09 ^ t10; \
+    y   =     ~ t13; \
+    t15 = x   & t03; \
+    z   = t12 ^ t07; \
+    t17 = a   ^ b  ; \
+    t18 = y   ^ t15; \
+    w   = t17 ^ t18; \
+  }
+
+#define SBOX6_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t07, t08, t09; \
+    register unsigned long t12, t13, t14, t15, t16, t17, t01; \
+    t01 = a   ^ c  ; \
+    t02 =     ~ c  ; \
+    t03 = b   & t01; \
+    t04 = b   | t02; \
+    t05 = d   | t03; \
+    t06 = b   ^ d  ; \
+    t07 = a   & t04; \
+    t08 = a   | t02; \
+    t09 = t07 ^ t05; \
+    x   = t06 ^ t08; \
+    w   =     ~ t09; \
+    t12 = b   & w  ; \
+    t13 = t01 & t05; \
+    t14 = t01 ^ t12; \
+    t15 = t07 ^ t13; \
+    t16 = d   | t02; \
+    t17 = a   ^ x  ; \
+    z   = t17 ^ t15; \
+    y   = t16 ^ t14; \
+  }
+
+#define SBOX7(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t05, t06, t08, t09, t10; \
+    register unsigned long t11, t13, t14, t15, t16, t17, t01; \
+    t01 = a   & c  ; \
+    t02 =     ~ d  ; \
+    t03 = a   & t02; \
+    t04 = b   | t01; \
+    t05 = a   & b  ; \
+    t06 = c   ^ t04; \
+    z   = t03 ^ t06; \
+    t08 = c   | z  ; \
+    t09 = d   | t05; \
+    t10 = a   ^ t08; \
+    t11 = t04 & z  ; \
+    x   = t09 ^ t10; \
+    t13 = b   ^ x  ; \
+    t14 = t01 ^ x  ; \
+    t15 = c   ^ t05; \
+    t16 = t11 | t13; \
+    t17 = t02 | t14; \
+    w   = t15 ^ t17; \
+    y   = a   ^ t16; \
+  }
+
+#define SBOX7_INVERSE(a, b, c, d, w, x, y, z) \
+  { \
+    register unsigned long t02, t03, t04, t06, t07, t08, t09; \
+    register unsigned long t10, t11, t13, t14, t15, t16, t01; \
+    t01 = a   & b  ; \
+    t02 = a   | b  ; \
+    t03 = c   | t01; \
+    t04 = d   & t02; \
+    z   = t03 ^ t04; \
+    t06 = b   ^ t04; \
+    t07 = d   ^ z  ; \
+    t08 =     ~ t07; \
+    t09 = t06 | t08; \
+    t10 = b   ^ d  ; \
+    t11 = a   | d  ; \
+    x   = a   ^ t09; \
+    t13 = c   ^ t06; \
+    t14 = c   & t11; \
+    t15 = d   | x  ; \
+    t16 = t01 | t10; \
+    w   = t13 ^ t15; \
+    y   = t14 ^ t16; \
+  }
+
+/* XOR BLOCK1 into BLOCK0.  */
+#define BLOCK_XOR(block0, block1) \
+  {                               \
+    block0[0] ^= block1[0];       \
+    block0[1] ^= block1[1];       \
+    block0[2] ^= block1[2];       \
+    block0[3] ^= block1[3];       \
+  }
+
+/* Copy BLOCK_SRC to BLOCK_DST.  */
+#define BLOCK_COPY(block_dst, block_src) \
+  {                                      \
+    block_dst[0] = block_src[0];         \
+    block_dst[1] = block_src[1];         \
+    block_dst[2] = block_src[2];         \
+    block_dst[3] = block_src[3];         \
+  }
+
+/* Apply SBOX number WHICH to to the block found in ARRAY0 at index
+   INDEX, writing the output to the block found in ARRAY1 at index
+   INDEX.  */
+#define SBOX(which, array0, array1, index)            \
+  SBOX##which (array0[index + 0], array0[index + 1],  \
+               array0[index + 2], array0[index + 3],  \
+               array1[index + 0], array1[index + 1],  \
+               array1[index + 2], array1[index + 3]);
+
+/* Apply inverse SBOX number WHICH to to the block found in ARRAY0 at
+   index INDEX, writing the output to the block found in ARRAY1 at
+   index INDEX.  */
+#define SBOX_INVERSE(which, array0, array1, index)              \
+  SBOX##which##_INVERSE (array0[index + 0], array0[index + 1],  \
+                         array0[index + 2], array0[index + 3],  \
+                         array1[index + 0], array1[index + 1],  \
+                         array1[index + 2], array1[index + 3]);
+
+/* Apply the linear transformation to BLOCK.  */
+#define LINEAR_TRANSFORMATION(block)                  \
+  {                                                   \
+    block[0] = rol (block[0], 13);                    \
+    block[2] = rol (block[2], 3);                     \
+    block[1] = block[1] ^ block[0] ^ block[2];        \
+    block[3] = block[3] ^ block[2] ^ (block[0] << 3); \
+    block[1] = rol (block[1], 1);                     \
+    block[3] = rol (block[3], 7);                     \
+    block[0] = block[0] ^ block[1] ^ block[3];        \
+    block[2] = block[2] ^ block[3] ^ (block[1] << 7); \
+    block[0] = rol (block[0], 5);                     \
+    block[2] = rol (block[2], 22);                    \
+  }
+
+/* Apply the inverse linear transformation to BLOCK.  */
+#define LINEAR_TRANSFORMATION_INVERSE(block)          \
+  {                                                   \
+    block[2] = ror (block[2], 22);                    \
+    block[0] = ror (block[0] , 5);                    \
+    block[2] = block[2] ^ block[3] ^ (block[1] << 7); \
+    block[0] = block[0] ^ block[1] ^ block[3];        \
+    block[3] = ror (block[3], 7);                     \
+    block[1] = ror (block[1], 1);                     \
+    block[3] = block[3] ^ block[2] ^ (block[0] << 3); \
+    block[1] = block[1] ^ block[0] ^ block[2];        \
+    block[2] = ror (block[2], 3);                     \
+    block[0] = ror (block[0], 13);                    \
+  }
+
+/* Apply a Serpent round to BLOCK, using the SBOX number WHICH and the
+   subkeys contained in SUBKEYS.  Use BLOCK_TMP as temporary storage.
+   This macro increments `round'.  */
+#define ROUND(which, subkeys, block, block_tmp) \
+  {                                             \
+    BLOCK_XOR (block, subkeys[round]);          \
+    round++;                                    \
+    SBOX (which, block, block_tmp, 0);          \
+    LINEAR_TRANSFORMATION (block_tmp);          \
+    BLOCK_COPY (block, block_tmp);              \
+  }
+
+/* Apply the last Serpent round to BLOCK, using the SBOX number WHICH
+   and the subkeys contained in SUBKEYS.  Use BLOCK_TMP as temporary
+   storage.  The result will be stored in BLOCK_TMP.  This macro
+   increments `round'.  */
+#define ROUND_LAST(which, subkeys, block, block_tmp) \
+  {                                                  \
+    BLOCK_XOR (block, subkeys[round]);               \
+    round++;                                         \
+    SBOX (which, block, block_tmp, 0);               \
+    BLOCK_XOR (block_tmp, subkeys[round]);           \
+    round++;                                         \
+  }
+
+/* Apply an inverse Serpent round to BLOCK, using the SBOX number
+   WHICH and the subkeys contained in SUBKEYS.  Use BLOCK_TMP as
+   temporary storage.  This macro increments `round'.  */
+#define ROUND_INVERSE(which, subkey, block, block_tmp) \
+  {                                                    \
+    LINEAR_TRANSFORMATION_INVERSE (block);             \
+    SBOX_INVERSE (which, block, block_tmp, 0);         \
+    BLOCK_XOR (block_tmp, subkey[round]);              \
+    round--;                                           \
+    BLOCK_COPY (block, block_tmp);                     \
+  }
+
+/* Apply the first Serpent round to BLOCK, using the SBOX number WHICH
+   and the subkeys contained in SUBKEYS.  Use BLOCK_TMP as temporary
+   storage.  The result will be stored in BLOCK_TMP.  This macro
+   increments `round'.  */
+#define ROUND_FIRST_INVERSE(which, subkeys, block, block_tmp) \
+  {                                                           \
+    BLOCK_XOR (block, subkeys[round]);                        \
+    round--;                                                  \
+    SBOX_INVERSE (which, block, block_tmp, 0);                \
+    BLOCK_XOR (block_tmp, subkeys[round]);                    \
+    round--;                                                  \
+  }
+
+/* Convert the user provided key KEY of KEY_LENGTH bytes into the
+   internally used format.  */
+static void
+serpent_key_prepare (const byte_t *key, unsigned int key_length,
+                    serpent_key_t key_prepared)
+{
+  int i;
+
+  /* Copy key.  */
+  for (i = 0; i < key_length / 4; i++)
+    {
+#ifdef WORDS_BIGENDIAN
+      key_prepared[i] = byte_swap_32 (((u32_t *) key)[i]);
+#else
+      key_prepared[i] = ((u32_t *) key)[i];
+#endif
+    }
+
+  if (i < 8)
+    {
+      /* Key must be padded according to the Serpent
+        specification.  */
+      key_prepared[i] = 0x00000001;
+
+      for (i++; i < 8; i++)
+       key_prepared[i] = 0;
+    }
+}
+
+/* Derive the 33 subkeys from KEY and store them in SUBKEYS.  */
+static void
+serpent_subkeys_generate (serpent_key_t key, serpent_subkeys_t subkeys)
+{
+  u32_t w_real[140];           /* The `prekey'.  */
+  u32_t k[132];
+  u32_t *w = &w_real[8];
+  int i, j;
+
+  /* Initialize with key values.  */
+  for (i = 0; i < 8; i++)
+    w[i - 8] = key[i];
+
+  /* Expand to intermediate key using the affine recurrence.  */
+  for (i = 0; i < 132; i++)
+    w[i] = rol (w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
+
+  /* Calculate subkeys via S-Boxes, in bitslice mode.  */
+  SBOX (3, w, k,   0);
+  SBOX (2, w, k,   4);
+  SBOX (1, w, k,   8);
+  SBOX (0, w, k,  12);
+  SBOX (7, w, k,  16);
+  SBOX (6, w, k,  20);
+  SBOX (5, w, k,  24);
+  SBOX (4, w, k,  28);
+  SBOX (3, w, k,  32);
+  SBOX (2, w, k,  36);
+  SBOX (1, w, k,  40);
+  SBOX (0, w, k,  44);
+  SBOX (7, w, k,  48);
+  SBOX (6, w, k,  52);
+  SBOX (5, w, k,  56);
+  SBOX (4, w, k,  60);
+  SBOX (3, w, k,  64);
+  SBOX (2, w, k,  68);
+  SBOX (1, w, k,  72);
+  SBOX (0, w, k,  76);
+  SBOX (7, w, k,  80);
+  SBOX (6, w, k,  84);
+  SBOX (5, w, k,  88);
+  SBOX (4, w, k,  92);
+  SBOX (3, w, k,  96);
+  SBOX (2, w, k, 100);
+  SBOX (1, w, k, 104);
+  SBOX (0, w, k, 108);
+  SBOX (7, w, k, 112);
+  SBOX (6, w, k, 116);
+  SBOX (5, w, k, 120);
+  SBOX (4, w, k, 124);
+  SBOX (3, w, k, 128);
+
+  /* Renumber subkeys.  */
+  for (i = 0; i < ROUNDS + 1; i++)
+    for (j = 0; j < 4; j++)
+      subkeys[i][j] = k[4 * i + j];
+}
+
+/* Initialize CONTEXT with the key KEY of KEY_LENGTH bits.  */
+static void
+serpent_setkey_internal (serpent_context_t *context,
+                        const byte_t *key, unsigned int key_length)
+{
+  serpent_key_t key_prepared;
+
+  serpent_key_prepare (key, key_length, key_prepared);
+  serpent_subkeys_generate (key_prepared, context->keys);
+  _gcry_burn_stack (272 * sizeof (u32_t));
+}
+
+/* Initialize CTX with the key KEY of KEY_LENGTH bytes.  */
+static gcry_err_code_t
+serpent_setkey (void *ctx,
+               const byte_t *key, unsigned int key_length)
+{
+  serpent_context_t *context = (serpent_context_t *) ctx;
+  static const char *serpent_test_ret;
+  static int serpent_init_done;
+  gcry_err_code_t ret = GPG_ERR_NO_ERROR;
+  
+  if (! serpent_init_done)
+    {
+      /* Execute a self-test the first time, Serpent is used.  */
+      static const char *serpent_test (void);
+      
+      serpent_test_ret = serpent_test ();
+      if (serpent_test_ret)
+       log_error ("Serpent test failure: %s\n", serpent_test_ret);
+      serpent_init_done = 1;
+    }
+
+  if (serpent_test_ret)
+    ret = GPG_ERR_SELFTEST_FAILED;
+  else
+    {
+      serpent_setkey_internal (context, key, key_length);
+      _gcry_burn_stack (sizeof (serpent_key_t));
+    }
+
+  return ret;
+}
+
+static void
+serpent_encrypt_internal (serpent_context_t *context,
+                         const serpent_block_t input, serpent_block_t output)
+{
+  serpent_block_t b, b_next;
+  int round = 0;
+
+#ifdef WORDS_BIGENDIAN
+  b[0] = byte_swap_32 (input[0]);
+  b[1] = byte_swap_32 (input[1]);
+  b[2] = byte_swap_32 (input[2]);
+  b[3] = byte_swap_32 (input[3]);
+#else
+  b[0] = input[0];
+  b[1] = input[1];
+  b[2] = input[2];
+  b[3] = input[3];
+#endif
+
+  ROUND (0, context->keys, b, b_next);
+  ROUND (1, context->keys, b, b_next);
+  ROUND (2, context->keys, b, b_next);
+  ROUND (3, context->keys, b, b_next);
+  ROUND (4, context->keys, b, b_next);
+  ROUND (5, context->keys, b, b_next);
+  ROUND (6, context->keys, b, b_next);
+  ROUND (7, context->keys, b, b_next);
+  ROUND (0, context->keys, b, b_next);
+  ROUND (1, context->keys, b, b_next);
+  ROUND (2, context->keys, b, b_next);
+  ROUND (3, context->keys, b, b_next);
+  ROUND (4, context->keys, b, b_next);
+  ROUND (5, context->keys, b, b_next);
+  ROUND (6, context->keys, b, b_next);
+  ROUND (7, context->keys, b, b_next);
+  ROUND (0, context->keys, b, b_next);
+  ROUND (1, context->keys, b, b_next);
+  ROUND (2, context->keys, b, b_next);
+  ROUND (3, context->keys, b, b_next);
+  ROUND (4, context->keys, b, b_next);
+  ROUND (5, context->keys, b, b_next);
+  ROUND (6, context->keys, b, b_next);
+  ROUND (7, context->keys, b, b_next);
+  ROUND (0, context->keys, b, b_next);
+  ROUND (1, context->keys, b, b_next);
+  ROUND (2, context->keys, b, b_next);
+  ROUND (3, context->keys, b, b_next);
+  ROUND (4, context->keys, b, b_next);
+  ROUND (5, context->keys, b, b_next);
+  ROUND (6, context->keys, b, b_next);
+
+  ROUND_LAST (7, context->keys, b, b_next);
+
+#ifdef WORDS_BIGENDIAN
+  output[0] = byte_swap_32 (b_next[0]);
+  output[1] = byte_swap_32 (b_next[1]);
+  output[2] = byte_swap_32 (b_next[2]);
+  output[3] = byte_swap_32 (b_next[3]);
+#else
+  output[0] = b_next[0];
+  output[1] = b_next[1];
+  output[2] = b_next[2];
+  output[3] = b_next[3];
+#endif
+}
+
+static void
+serpent_decrypt_internal (serpent_context_t *context,
+                         const serpent_block_t input, serpent_block_t output)
+{
+  serpent_block_t b, b_next;
+  int round = ROUNDS;
+
+  BLOCK_COPY (b_next, input);
+
+  ROUND_FIRST_INVERSE (7, context->keys, b_next, b);
+
+  ROUND_INVERSE (6, context->keys, b, b_next);
+  ROUND_INVERSE (5, context->keys, b, b_next);
+  ROUND_INVERSE (4, context->keys, b, b_next);
+  ROUND_INVERSE (3, context->keys, b, b_next);
+  ROUND_INVERSE (2, context->keys, b, b_next);
+  ROUND_INVERSE (1, context->keys, b, b_next);
+  ROUND_INVERSE (0, context->keys, b, b_next);
+  ROUND_INVERSE (7, context->keys, b, b_next);
+  ROUND_INVERSE (6, context->keys, b, b_next);
+  ROUND_INVERSE (5, context->keys, b, b_next);
+  ROUND_INVERSE (4, context->keys, b, b_next);
+  ROUND_INVERSE (3, context->keys, b, b_next);
+  ROUND_INVERSE (2, context->keys, b, b_next);
+  ROUND_INVERSE (1, context->keys, b, b_next);
+  ROUND_INVERSE (0, context->keys, b, b_next);
+  ROUND_INVERSE (7, context->keys, b, b_next);
+  ROUND_INVERSE (6, context->keys, b, b_next);
+  ROUND_INVERSE (5, context->keys, b, b_next);
+  ROUND_INVERSE (4, context->keys, b, b_next);
+  ROUND_INVERSE (3, context->keys, b, b_next);
+  ROUND_INVERSE (2, context->keys, b, b_next);
+  ROUND_INVERSE (1, context->keys, b, b_next);
+  ROUND_INVERSE (0, context->keys, b, b_next);
+  ROUND_INVERSE (7, context->keys, b, b_next);
+  ROUND_INVERSE (6, context->keys, b, b_next);
+  ROUND_INVERSE (5, context->keys, b, b_next);
+  ROUND_INVERSE (4, context->keys, b, b_next);
+  ROUND_INVERSE (3, context->keys, b, b_next);
+  ROUND_INVERSE (2, context->keys, b, b_next);
+  ROUND_INVERSE (1, context->keys, b, b_next);
+  ROUND_INVERSE (0, context->keys, b, b_next);
+
+  BLOCK_COPY (output, b_next);
+}
+
+static void
+serpent_encrypt (void *ctx, byte_t *buffer_out, const byte_t *buffer_in)
+{
+  serpent_context_t *context = (serpent_context_t *) ctx;
+
+  serpent_encrypt_internal (context,
+                           (const u32_t *) buffer_in, (u32_t *) buffer_out);
+  _gcry_burn_stack (2 * sizeof (serpent_block_t));
+}
+
+static void
+serpent_decrypt (void *ctx, byte *buffer_out, const byte *buffer_in)
+{
+  serpent_context_t *context = (serpent_context_t *) ctx;
+
+  serpent_decrypt_internal (context,
+                           (const u32_t *) buffer_in,
+                           (u32_t *) buffer_out);
+  _gcry_burn_stack (2 * sizeof (serpent_block_t));
+}
+
+\f
+
+/* Serpent test.  */
+
+static const char *
+serpent_test (void)
+{
+  serpent_context_t context;
+  unsigned char scratch[16];
+  unsigned int i;
+
+  static struct test
+  {
+    int key_length;
+    unsigned char key[32];
+    unsigned char text_plain[16];
+    unsigned char text_cipher[16];
+  } test_data[] =
+    {
+      {
+       16,
+       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+       "\xD2\x9D\x57\x6F\xCE\xA3\xA3\xA7\xED\x90\x99\xF2\x92\x73\xD7\x8E",
+       "\xB2\x28\x8B\x96\x8A\xE8\xB0\x86\x48\xD1\xCE\x96\x06\xFD\x99\x2D"
+      },
+      {
+       24,
+       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+       "\x00\x00\x00\x00\x00\x00\x00\x00",
+       "\xD2\x9D\x57\x6F\xCE\xAB\xA3\xA7\xED\x98\x99\xF2\x92\x7B\xD7\x8E",
+       "\x13\x0E\x35\x3E\x10\x37\xC2\x24\x05\xE8\xFA\xEF\xB2\xC3\xC3\xE9"
+      },
+      {
+       32,
+       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+       "\xD0\x95\x57\x6F\xCE\xA3\xE3\xA7\xED\x98\xD9\xF2\x90\x73\xD7\x8E",
+       "\xB9\x0E\xE5\x86\x2D\xE6\x91\x68\xF2\xBD\xD5\x12\x5B\x45\x47\x2B"
+      },
+      {
+       32,
+       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+       "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+       "\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00",
+       "\x20\x61\xA4\x27\x82\xBD\x52\xEC\x69\x1E\xC3\x83\xB0\x3B\xA7\x7C"
+      },
+      {
+       0
+      },
+    };
+
+  for (i = 0; test_data[i].key_length; i++)
+    {
+      serpent_setkey_internal (&context, test_data[i].key, test_data[i].key_length);
+      serpent_encrypt_internal (&context,
+                               (const u32_t *) test_data[i].text_plain,
+                               (u32_t *) scratch);
+      if (memcmp (scratch, test_data[i].text_cipher, sizeof (serpent_block_t)))
+       switch (test_data[i].key_length)
+         {
+         case 16:
+           return "Serpent-128 test encryption failed.";
+         case  24:
+           return "Serpent-192 test encryption failed.";
+         case 32:
+           return "Serpent-256 test encryption failed.";
+         }
+
+    serpent_decrypt_internal (&context,
+                             (const u32_t *) test_data[i].text_cipher,
+                             (u32_t *) scratch);
+    if (memcmp (scratch, test_data[i].text_plain, sizeof (serpent_block_t)))
+      switch (test_data[i].key_length)
+       {
+       case 16:
+         return "Serpent-128 test decryption failed.";
+       case  24:
+         return "Serpent-192 test decryption failed.";
+       case 32:
+         return "Serpent-256 test decryption failed.";
+       }
+    }
+
+  return NULL;
+}
+
+\f
+
+/* "SERPENT" is an alias for "SERPENT128".  */
+static const char *cipher_spec_serpent128_aliases[] =
+  {
+    "SERPENT",
+    NULL,
+  };
+
+gcry_cipher_spec_t cipher_spec_serpent128 =
+  {
+    "SERPENT128", cipher_spec_serpent128_aliases, NULL, 16, 128,
+    sizeof (serpent_context_t),
+    serpent_setkey, serpent_encrypt, serpent_decrypt,
+  };
+
+gcry_cipher_spec_t cipher_spec_serpent192 =
+  {
+    "SERPENT192", NULL, NULL, 16, 192,
+    sizeof (serpent_context_t),
+    serpent_setkey, serpent_encrypt, serpent_decrypt,
+  };
+
+gcry_cipher_spec_t cipher_spec_serpent256 =
+  {
+    "SERPENT256", NULL, NULL, 16, 256,
+    sizeof (serpent_context_t),
+    serpent_setkey, serpent_encrypt, serpent_decrypt,
+  };