diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7298222
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/libgcrypt-1.8.5-hobbled.tar.xz
diff --git a/.libgcrypt.metadata b/.libgcrypt.metadata
new file mode 100644
index 0000000..04ef129
--- /dev/null
+++ b/.libgcrypt.metadata
@@ -0,0 +1 @@
+1edcc623a15ed87ff832e021b4cb77fd94eb66c9 SOURCES/libgcrypt-1.8.5-hobbled.tar.xz
diff --git a/SOURCES/curves.c b/SOURCES/curves.c
new file mode 100644
index 0000000..b68e0e2
--- /dev/null
+++ b/SOURCES/curves.c
@@ -0,0 +1,144 @@
+/* curves.c -  ECC curves regression tests
+ *	Copyright (C) 2011 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "../src/gcrypt-int.h"
+
+
+#define PGM "curves"
+#include "t-common.h"
+
+/* Number of curves defined in ../cipger/ecc.c */
+#define N_CURVES 14
+
+/* A real world sample public key.  */
+static char const sample_key_1[] =
+"(public-key\n"
+" (ecdsa\n"
+"  (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)\n"
+"  (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)\n"
+"  (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)\n"
+"  (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+        "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)\n"
+"  (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)\n"
+"  (h #000000000000000000000000000000000000000000000000000000000000000001#)\n"
+"  (q #0442B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146EE"
+      "86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E#)\n"
+"  ))";
+static char const sample_key_1_curve[] = "NIST P-256";
+static unsigned int sample_key_1_nbits = 256;
+
+
+
+static void
+list_curves (void)
+{
+  int idx;
+  const char *name;
+  unsigned int nbits;
+
+  for (idx=0; (name = gcry_pk_get_curve (NULL, idx, &nbits)); idx++)
+    {
+      if (verbose)
+        printf ("%s - %u bits\n", name, nbits);
+    }
+  if (idx != N_CURVES)
+    fail ("expected %d curves but got %d\n", N_CURVES, idx);
+  if (gcry_pk_get_curve (NULL, -1, NULL))
+    fail ("curve iteration failed\n");
+}
+
+
+static void
+check_matching (void)
+{
+  gpg_error_t err;
+  gcry_sexp_t key;
+  const char *name;
+  unsigned int nbits;
+
+  err = gcry_sexp_new (&key, sample_key_1, 0, 1);
+  if (err)
+    die ("parsing s-expression string failed: %s\n", gpg_strerror (err));
+  name = gcry_pk_get_curve (key, 0, &nbits);
+  if (!name)
+    fail ("curve name not found for sample_key_1\n");
+  else if (strcmp (name, sample_key_1_curve))
+    fail ("expected curve name %s but got %s for sample_key_1\n",
+          sample_key_1_curve, name);
+  else if (nbits != sample_key_1_nbits)
+    fail ("expected curve size %u but got %u for sample_key_1\n",
+          sample_key_1_nbits, nbits);
+
+  gcry_sexp_release (key);
+
+}
+
+
+static void
+check_get_params (void)
+{
+  gcry_sexp_t param;
+  const char *name;
+
+  param = gcry_pk_get_param (GCRY_PK_ECDSA, sample_key_1_curve);
+  if (!param)
+    fail ("error gerring parameters for `%s'\n", sample_key_1_curve);
+
+  name = gcry_pk_get_curve (param, 0, NULL);
+  if (!name)
+    fail ("get_param: curve name not found for sample_key_1\n");
+  else if (strcmp (name, sample_key_1_curve))
+    fail ("get_param: expected curve name %s but got %s for sample_key_1\n",
+          sample_key_1_curve, name);
+
+  gcry_sexp_release (param);
+
+}
+
+
+int
+main (int argc, char **argv)
+{
+  if (argc > 1 && !strcmp (argv[1], "--verbose"))
+    verbose = 1;
+  else if (argc > 1 && !strcmp (argv[1], "--debug"))
+    verbose = debug = 1;
+
+  if (!gcry_check_version (GCRYPT_VERSION))
+    die ("version mismatch\n");
+
+  xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (debug)
+    xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+  list_curves ();
+  check_matching ();
+  check_get_params ();
+
+  return error_count ? 1 : 0;
+}
diff --git a/SOURCES/ecc-curves.c b/SOURCES/ecc-curves.c
new file mode 100644
index 0000000..7378bae
--- /dev/null
+++ b/SOURCES/ecc-curves.c
@@ -0,0 +1,1207 @@
+/* ecc-curves.c  -  Elliptic Curve parameter mangement
+ * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "context.h"
+#include "ec-context.h"
+#include "pubkey-internal.h"
+#include "ecc-common.h"
+
+
+/* This tables defines aliases for curve names.  */
+static const struct
+{
+  const char *name;  /* Our name.  */
+  const char *other; /* Other name. */
+} curve_aliases[] =
+  {
+    { "Curve25519", "1.3.6.1.4.1.3029.1.5.1" },
+    { "Ed25519",    "1.3.6.1.4.1.11591.15.1" },
+
+    { "NIST P-224", "secp224r1" },
+    { "NIST P-224", "1.3.132.0.33" },        /* SECP OID.  */
+    { "NIST P-224", "nistp224"   },          /* rfc5656.  */
+
+    { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1.  */
+    { "NIST P-256", "prime256v1" },
+    { "NIST P-256", "secp256r1"  },
+    { "NIST P-256", "nistp256"   },          /* rfc5656.  */
+
+    { "NIST P-384", "secp384r1" },
+    { "NIST P-384", "1.3.132.0.34" },
+    { "NIST P-384", "nistp384"   },          /* rfc5656.  */
+
+    { "NIST P-521", "secp521r1" },
+    { "NIST P-521", "1.3.132.0.35" },
+    { "NIST P-521", "nistp521"   },          /* rfc5656.  */
+
+    { "GOST2001-test", "1.2.643.2.2.35.0" },
+    { "GOST2001-CryptoPro-A", "1.2.643.2.2.35.1" },
+    { "GOST2001-CryptoPro-B", "1.2.643.2.2.35.2" },
+    { "GOST2001-CryptoPro-C", "1.2.643.2.2.35.3" },
+    { "GOST2001-CryptoPro-A", "GOST2001-CryptoPro-XchA" },
+    { "GOST2001-CryptoPro-C", "GOST2001-CryptoPro-XchB" },
+    { "GOST2001-CryptoPro-A", "1.2.643.2.2.36.0" },
+    { "GOST2001-CryptoPro-C", "1.2.643.2.2.36.1" },
+
+    { "GOST2012-tc26-A", "1.2.643.7.1.2.1.2.1" },
+    { "GOST2012-tc26-B", "1.2.643.7.1.2.1.2.2" },
+
+    { "secp256k1", "1.3.132.0.10" },
+
+    { NULL, NULL}
+  };
+
+
+typedef struct
+{
+  const char *desc;           /* Description of the curve.  */
+  unsigned int nbits;         /* Number of bits.  */
+  unsigned int fips:1;        /* True if this is a FIPS140-2 approved curve. */
+
+  /* The model describing this curve.  This is mainly used to select
+     the group equation. */
+  enum gcry_mpi_ec_models model;
+
+  /* The actual ECC dialect used.  This is used for curve specific
+     optimizations and to select encodings etc. */
+  enum ecc_dialects dialect;
+
+  const char *p;              /* The prime defining the field.  */
+  const char *a, *b;          /* The coefficients.  For Twisted Edwards
+                                 Curves b is used for d.  For Montgomery
+                                 Curves (a,b) has ((A-2)/4,B^-1).  */
+  const char *n;              /* The order of the base point.  */
+  const char *g_x, *g_y;      /* Base point.  */
+  const char *h;              /* Cofactor.  */
+} ecc_domain_parms_t;
+
+
+/* This static table defines all available curves.  */
+static const ecc_domain_parms_t domain_parms[] =
+  {
+    {
+      /* (-x^2 + y^2 = 1 + dx^2y^2) */
+      "Ed25519", 256, 0,
+      MPI_EC_EDWARDS, ECC_DIALECT_ED25519,
+      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+      "-0x01",
+      "-0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A",
+      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
+      "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
+      "0x6666666666666666666666666666666666666666666666666666666666666658",
+      "0x08"
+    },
+    {
+      /* (y^2 = x^3 + 486662*x^2 + x) */
+      "Curve25519", 256, 0,
+      MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD,
+      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+      "0x01DB41",
+      "0x01",
+      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
+      "0x0000000000000000000000000000000000000000000000000000000000000009",
+      "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9",
+      "0x08"
+    },
+    {
+      "NIST P-224", 224, 1,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0xffffffffffffffffffffffffffffffff000000000000000000000001",
+      "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
+      "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+      "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
+
+      "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+      "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
+      "0x01"
+    },
+    {
+      "NIST P-256", 256, 1,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
+      "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
+      "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+      "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
+
+      "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+      "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
+      "0x01"
+    },
+    {
+      "NIST P-384", 384, 1,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000ffffffff",
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000fffffffc",
+      "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
+      "c656398d8a2ed19d2a85c8edd3ec2aef",
+      "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
+      "581a0db248b0a77aecec196accc52973",
+
+      "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
+      "5502f25dbf55296c3a545e3872760ab7",
+      "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
+      "0a60b1ce1d7e819d7a431d7c90ea0e5f",
+      "0x01"
+    },
+    {
+      "NIST P-521", 521, 1,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
+      "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
+      "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+      "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+
+      "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d"
+      "3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+      "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e"
+      "662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
+      "0x01"
+    },
+
+    {
+      "GOST2001-test", 256, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0x8000000000000000000000000000000000000000000000000000000000000431",
+      "0x0000000000000000000000000000000000000000000000000000000000000007",
+      "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e",
+      "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3",
+
+      "0x0000000000000000000000000000000000000000000000000000000000000002",
+      "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8",
+      "0x01"
+    },
+    {
+      "GOST2001-CryptoPro-A", 256, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97",
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd94",
+      "0x00000000000000000000000000000000000000000000000000000000000000a6",
+      "0xffffffffffffffffffffffffffffffff6c611070995ad10045841b09b761b893",
+      "0x0000000000000000000000000000000000000000000000000000000000000001",
+      "0x8d91e471e0989cda27df505a453f2b7635294f2ddf23e3b122acc99c9e9f1e14",
+      "0x01"
+    },
+    {
+      "GOST2001-CryptoPro-B", 256, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0x8000000000000000000000000000000000000000000000000000000000000c99",
+      "0x8000000000000000000000000000000000000000000000000000000000000c96",
+      "0x3e1af419a269a5f866a7d3c25c3df80ae979259373ff2b182f49d4ce7e1bbc8b",
+      "0x800000000000000000000000000000015f700cfff1a624e5e497161bcc8a198f",
+      "0x0000000000000000000000000000000000000000000000000000000000000001",
+      "0x3fa8124359f96680b83d1c3eb2c070e5c545c9858d03ecfb744bf8d717717efc",
+      "0x01"
+    },
+    {
+      "GOST2001-CryptoPro-C", 256, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b",
+      "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598",
+      "0x000000000000000000000000000000000000000000000000000000000000805a",
+      "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9",
+      "0x0000000000000000000000000000000000000000000000000000000000000000",
+      "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67",
+      "0x01"
+    },
+    {
+      "GOST2012-test", 511, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d"
+      "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373",
+      "0x0000000000000000000000000000000000000000000000000000000000000007",
+      "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4"
+      "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc",
+      "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d"
+      "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df",
+
+      "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762"
+      "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a",
+      "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2"
+      "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e",
+      "0x01"
+    },
+    {
+      "GOST2012-tc26-A", 512, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7",
+      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc4",
+      "0xe8c2505dedfc86ddc1bd0b2b6667f1da34b82574761cb0e879bd081cfd0b6265"
+        "ee3cb090f30d27614cb4574010da90dd862ef9d4ebee4761503190785a71c760",
+      "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+        "27e69532f48d89116ff22b8d4e0560609b4b38abfad2b85dcacdb1411f10b275",
+      "0x0000000000000000000000000000000000000000000000000000000000000000"
+        "0000000000000000000000000000000000000000000000000000000000000003",
+      "0x7503cfe87a836ae3a61b8816e25450e6ce5e1c93acf1abc1778064fdcbefa921"
+        "df1626be4fd036e93d75e6a50e3a41e98028fe5fc235f5b889a589cb5215f2a4",
+      "0x01"
+    },
+    {
+      "GOST2012-tc26-B", 512, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0x8000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000006f",
+      "0x8000000000000000000000000000000000000000000000000000000000000000"
+        "000000000000000000000000000000000000000000000000000000000000006c",
+      "0x687d1b459dc841457e3e06cf6f5e2517b97c7d614af138bcbf85dc806c4b289f"
+        "3e965d2db1416d217f8b276fad1ab69c50f78bee1fa3106efb8ccbc7c5140116",
+      "0x8000000000000000000000000000000000000000000000000000000000000001"
+        "49a1ec142565a545acfdb77bd9d40cfa8b996712101bea0ec6346c54374f25bd",
+      "0x0000000000000000000000000000000000000000000000000000000000000000"
+        "0000000000000000000000000000000000000000000000000000000000000002",
+      "0x1a8f7eda389b094c2c071e3647a8940f3c123b697578c213be6dd9e6c8ec7335"
+        "dcb228fd1edf4a39152cbcaaf8c0398828041055f94ceeec7e21340780fe41bd",
+      "0x01"
+    },
+
+    {
+      "secp256k1", 256, 0,
+      MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD,
+      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
+      "0x0000000000000000000000000000000000000000000000000000000000000000",
+      "0x0000000000000000000000000000000000000000000000000000000000000007",
+      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
+      "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
+      "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
+      "0x01"
+    },
+
+    { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+  };
+
+
+
+
+/* Return a copy of POINT.  */
+static gcry_mpi_point_t
+point_copy (gcry_mpi_point_t point)
+{
+  gcry_mpi_point_t newpoint;
+
+  if (point)
+    {
+      newpoint = mpi_point_new (0);
+      point_set (newpoint, point);
+    }
+  else
+    newpoint = NULL;
+  return newpoint;
+}
+
+
+/* Helper to scan a hex string. */
+static gcry_mpi_t
+scanval (const char *string)
+{
+  gpg_err_code_t rc;
+  gcry_mpi_t val;
+
+  rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+  if (rc)
+    log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc));
+  return val;
+}
+
+
+/* Return the index of the domain_parms table for a curve with NAME.
+   Return -1 if not found.  */
+static int
+find_domain_parms_idx (const char *name)
+{
+  int idx, aliasno;
+
+  /* First check our native curves.  */
+  for (idx = 0; domain_parms[idx].desc; idx++)
+    if (!strcmp (name, domain_parms[idx].desc))
+      return idx;
+
+  /* If not found consult the alias table.  */
+  if (!domain_parms[idx].desc)
+    {
+      for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
+        if (!strcmp (name, curve_aliases[aliasno].other))
+          break;
+      if (curve_aliases[aliasno].name)
+        {
+          for (idx = 0; domain_parms[idx].desc; idx++)
+            if (!strcmp (curve_aliases[aliasno].name, domain_parms[idx].desc))
+              return idx;
+        }
+    }
+
+  return -1;
+}
+
+
+/* Generate the crypto system setup.  This function takes the NAME of
+   a curve or the desired number of bits and stores at R_CURVE the
+   parameters of the named curve or those of a suitable curve.  If
+   R_NBITS is not NULL, the chosen number of bits is stored there.
+   NULL may be given for R_CURVE, if the value is not required and for
+   example only a quick test for availability is desired.  Note that
+   the curve fields should be initialized to zero because fields which
+   are not NULL are skipped.  */
+gpg_err_code_t
+_gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
+                         elliptic_curve_t *curve, unsigned int *r_nbits)
+{
+  int idx;
+  const char *resname = NULL; /* Set to a found curve name.  */
+
+  if (name)
+    idx = find_domain_parms_idx (name);
+  else
+    {
+      for (idx = 0; domain_parms[idx].desc; idx++)
+        if (nbits == domain_parms[idx].nbits
+            && domain_parms[idx].model == MPI_EC_WEIERSTRASS)
+          break;
+      if (!domain_parms[idx].desc)
+        idx = -1;
+    }
+  if (idx < 0)
+    return GPG_ERR_UNKNOWN_CURVE;
+
+  resname = domain_parms[idx].desc;
+
+  /* In fips mode we only support NIST curves.  Note that it is
+     possible to bypass this check by specifying the curve parameters
+     directly.  */
+  if (fips_mode () && !domain_parms[idx].fips )
+    return GPG_ERR_NOT_SUPPORTED;
+
+  switch (domain_parms[idx].model)
+    {
+    case MPI_EC_WEIERSTRASS:
+    case MPI_EC_EDWARDS:
+    case MPI_EC_MONTGOMERY:
+      break;
+    default:
+      return GPG_ERR_BUG;
+    }
+
+
+  if (r_nbits)
+    *r_nbits = domain_parms[idx].nbits;
+
+  if (curve)
+    {
+      curve->model = domain_parms[idx].model;
+      curve->dialect = domain_parms[idx].dialect;
+      if (!curve->p)
+        curve->p = scanval (domain_parms[idx].p);
+      if (!curve->a)
+        {
+          curve->a = scanval (domain_parms[idx].a);
+          if (curve->a->sign)
+            mpi_add (curve->a, curve->p, curve->a);
+        }
+      if (!curve->b)
+        {
+          curve->b = scanval (domain_parms[idx].b);
+          if (curve->b->sign)
+            mpi_add (curve->b, curve->p, curve->b);
+        }
+      if (!curve->n)
+        curve->n = scanval (domain_parms[idx].n);
+      if (!curve->h)
+        curve->h = scanval (domain_parms[idx].h);
+      if (!curve->G.x)
+        curve->G.x = scanval (domain_parms[idx].g_x);
+      if (!curve->G.y)
+        curve->G.y = scanval (domain_parms[idx].g_y);
+      if (!curve->G.z)
+        curve->G.z = mpi_alloc_set_ui (1);
+      if (!curve->name)
+        curve->name = resname;
+    }
+
+  return 0;
+}
+
+
+/* Give the name of the curve NAME, store the curve parameters into P,
+   A, B, G, N, and H if they point to NULL value.  Note that G is returned
+   in standard uncompressed format.  Also update MODEL and DIALECT if
+   they are not NULL. */
+gpg_err_code_t
+_gcry_ecc_update_curve_param (const char *name,
+                              enum gcry_mpi_ec_models *model,
+                              enum ecc_dialects *dialect,
+                              gcry_mpi_t *p, gcry_mpi_t *a, gcry_mpi_t *b,
+                              gcry_mpi_t *g, gcry_mpi_t *n, gcry_mpi_t *h)
+{
+  int idx;
+
+  idx = find_domain_parms_idx (name);
+  if (idx < 0)
+    return GPG_ERR_UNKNOWN_CURVE;
+
+  if (g)
+    {
+      char *buf;
+      size_t len;
+
+      len = 4;
+      len += strlen (domain_parms[idx].g_x+2);
+      len += strlen (domain_parms[idx].g_y+2);
+      len++;
+      buf = xtrymalloc (len);
+      if (!buf)
+        return gpg_err_code_from_syserror ();
+      strcpy (stpcpy (stpcpy (buf, "0x04"), domain_parms[idx].g_x+2),
+              domain_parms[idx].g_y+2);
+      _gcry_mpi_release (*g);
+      *g = scanval (buf);
+      xfree (buf);
+    }
+  if (model)
+    *model = domain_parms[idx].model;
+  if (dialect)
+    *dialect = domain_parms[idx].dialect;
+  if (p)
+    {
+      _gcry_mpi_release (*p);
+      *p = scanval (domain_parms[idx].p);
+    }
+  if (a)
+    {
+      _gcry_mpi_release (*a);
+      *a = scanval (domain_parms[idx].a);
+    }
+  if (b)
+    {
+      _gcry_mpi_release (*b);
+      *b = scanval (domain_parms[idx].b);
+    }
+  if (n)
+    {
+      _gcry_mpi_release (*n);
+      *n = scanval (domain_parms[idx].n);
+    }
+  if (h)
+    {
+      _gcry_mpi_release (*h);
+      *h = scanval (domain_parms[idx].h);
+    }
+  return 0;
+}
+
+
+/* Return the name matching the parameters in PKEY.  This works only
+   with curves described by the Weierstrass equation. */
+const char *
+_gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits)
+{
+  gpg_err_code_t rc;
+  const char *result = NULL;
+  elliptic_curve_t E;
+  gcry_mpi_t mpi_g = NULL;
+  gcry_mpi_t tmp = NULL;
+  int idx;
+
+  memset (&E, 0, sizeof E);
+
+  if (r_nbits)
+    *r_nbits = 0;
+
+  if (!keyparms)
+    {
+      idx = iterator;
+      if (idx >= 0 && idx < DIM (domain_parms))
+        {
+          result = domain_parms[idx].desc;
+          if (r_nbits)
+            *r_nbits = domain_parms[idx].nbits;
+        }
+      return result;
+    }
+
+
+  /*
+   * Extract the curve parameters..
+   */
+  rc = gpg_err_code (sexp_extract_param (keyparms, NULL, "-pabgnh",
+                                         &E.p, &E.a, &E.b, &mpi_g, &E.n, &E.h,
+                                         NULL));
+  if (rc == GPG_ERR_NO_OBJ)
+    {
+      /* This might be the second use case of checking whether a
+         specific curve given by name is supported.  */
+      gcry_sexp_t l1;
+      char *name;
+
+      l1 = sexp_find_token (keyparms, "curve", 5);
+      if (!l1)
+        goto leave;  /* No curve name parameter.  */
+
+      name = sexp_nth_string (l1, 1);
+      sexp_release (l1);
+      if (!name)
+        goto leave;  /* Name missing or out of core. */
+
+      idx = find_domain_parms_idx (name);
+      xfree (name);
+      if (idx >= 0)  /* Curve found.  */
+        {
+          result = domain_parms[idx].desc;
+          if (r_nbits)
+            *r_nbits = domain_parms[idx].nbits;
+        }
+      return result;
+    }
+
+  if (rc)
+    goto leave;
+
+  if (mpi_g)
+    {
+      _gcry_mpi_point_init (&E.G);
+      if (_gcry_ecc_os2ec (&E.G, mpi_g))
+        goto leave;
+    }
+
+  for (idx = 0; domain_parms[idx].desc; idx++)
+    {
+      mpi_free (tmp);
+      tmp = scanval (domain_parms[idx].p);
+      if (!mpi_cmp (tmp, E.p))
+        {
+          mpi_free (tmp);
+          tmp = scanval (domain_parms[idx].a);
+          if (!mpi_cmp (tmp, E.a))
+            {
+              mpi_free (tmp);
+              tmp = scanval (domain_parms[idx].b);
+              if (!mpi_cmp (tmp, E.b))
+                {
+                  mpi_free (tmp);
+                  tmp = scanval (domain_parms[idx].n);
+                  if (!mpi_cmp (tmp, E.n))
+                    {
+                      mpi_free (tmp);
+                      tmp = scanval (domain_parms[idx].h);
+                      if (!mpi_cmp (tmp, E.h))
+                        {
+                          mpi_free (tmp);
+                          tmp = scanval (domain_parms[idx].g_x);
+                          if (!mpi_cmp (tmp, E.G.x))
+                            {
+                              mpi_free (tmp);
+                              tmp = scanval (domain_parms[idx].g_y);
+                              if (!mpi_cmp (tmp, E.G.y))
+                                {
+                                  result = domain_parms[idx].desc;
+                                  if (r_nbits)
+                                    *r_nbits = domain_parms[idx].nbits;
+                                  goto leave;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+ leave:
+  _gcry_mpi_release (tmp);
+  _gcry_mpi_release (E.p);
+  _gcry_mpi_release (E.a);
+  _gcry_mpi_release (E.b);
+  _gcry_mpi_release (mpi_g);
+  _gcry_mpi_point_free_parts (&E.G);
+  _gcry_mpi_release (E.n);
+  _gcry_mpi_release (E.h);
+  return result;
+}
+
+
+/* Helper to extract an MPI from key parameters.  */
+static gpg_err_code_t
+mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name)
+{
+  gcry_err_code_t ec = 0;
+  gcry_sexp_t l1;
+
+  l1 = sexp_find_token (keyparam, name, 0);
+  if (l1)
+    {
+      *r_a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      sexp_release (l1);
+      if (!*r_a)
+        ec = GPG_ERR_INV_OBJ;
+    }
+  return ec;
+}
+
+/* Helper to extract a point from key parameters.  If no parameter
+   with NAME is found, the functions tries to find a non-encoded point
+   by appending ".x", ".y" and ".z" to NAME.  ".z" is in this case
+   optional and defaults to 1.  EC is the context which at this point
+   may not be fully initialized. */
+static gpg_err_code_t
+point_from_keyparam (gcry_mpi_point_t *r_a,
+                     gcry_sexp_t keyparam, const char *name, mpi_ec_t ec)
+{
+  gcry_err_code_t rc;
+  gcry_sexp_t l1;
+  gcry_mpi_point_t point;
+
+  l1 = sexp_find_token (keyparam, name, 0);
+  if (l1)
+    {
+      gcry_mpi_t a;
+
+      a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE);
+      sexp_release (l1);
+      if (!a)
+        return GPG_ERR_INV_OBJ;
+
+      point = mpi_point_new (0);
+      if (ec && ec->dialect == ECC_DIALECT_ED25519)
+        rc = _gcry_ecc_eddsa_decodepoint (a, ec, point, NULL, NULL);
+      else
+        rc = _gcry_ecc_os2ec (point, a);
+      mpi_free (a);
+      if (rc)
+        {
+          mpi_point_release (point);
+          return rc;
+        }
+    }
+  else
+    {
+      char *tmpname;
+      gcry_mpi_t x = NULL;
+      gcry_mpi_t y = NULL;
+      gcry_mpi_t z = NULL;
+
+      tmpname = xtrymalloc (strlen (name) + 2 + 1);
+      if (!tmpname)
+        return gpg_err_code_from_syserror ();
+      strcpy (stpcpy (tmpname, name), ".x");
+      rc = mpi_from_keyparam (&x, keyparam, tmpname);
+      if (rc)
+        {
+          xfree (tmpname);
+          return rc;
+        }
+      strcpy (stpcpy (tmpname, name), ".y");
+      rc = mpi_from_keyparam (&y, keyparam, tmpname);
+      if (rc)
+        {
+          mpi_free (x);
+          xfree (tmpname);
+          return rc;
+        }
+      strcpy (stpcpy (tmpname, name), ".z");
+      rc = mpi_from_keyparam (&z, keyparam, tmpname);
+      if (rc)
+        {
+          mpi_free (y);
+          mpi_free (x);
+          xfree (tmpname);
+          return rc;
+        }
+      if (!z)
+        z = mpi_set_ui (NULL, 1);
+      if (x && y)
+        point = mpi_point_snatch_set (NULL, x, y, z);
+      else
+        {
+          mpi_free (x);
+          mpi_free (y);
+          mpi_free (z);
+          point = NULL;
+        }
+      xfree (tmpname);
+    }
+
+  if (point)
+    *r_a = point;
+  return 0;
+}
+
+
+/* This function creates a new context for elliptic curve operations.
+   Either KEYPARAM or CURVENAME must be given.  If both are given and
+   KEYPARAM has no curve parameter, CURVENAME is used to add missing
+   parameters.  On success 0 is returned and the new context stored at
+   R_CTX.  On error NULL is stored at R_CTX and an error code is
+   returned.  The context needs to be released using
+   gcry_ctx_release.  */
+gpg_err_code_t
+_gcry_mpi_ec_new (gcry_ctx_t *r_ctx,
+                  gcry_sexp_t keyparam, const char *curvename)
+{
+  gpg_err_code_t errc;
+  gcry_ctx_t ctx = NULL;
+  enum gcry_mpi_ec_models model = MPI_EC_WEIERSTRASS;
+  enum ecc_dialects dialect = ECC_DIALECT_STANDARD;
+  gcry_mpi_t p = NULL;
+  gcry_mpi_t a = NULL;
+  gcry_mpi_t b = NULL;
+  gcry_mpi_point_t G = NULL;
+  gcry_mpi_t n = NULL;
+  gcry_mpi_t h = NULL;
+  gcry_mpi_point_t Q = NULL;
+  gcry_mpi_t d = NULL;
+  int flags = 0;
+  gcry_sexp_t l1;
+
+  *r_ctx = NULL;
+
+  if (keyparam)
+    {
+      /* Parse an optional flags list.  */
+      l1 = sexp_find_token (keyparam, "flags", 0);
+      if (l1)
+        {
+          errc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+          sexp_release (l1);
+          l1 = NULL;
+          if (errc)
+            goto leave;
+        }
+
+      /* Check whether a curve name was given.  */
+      l1 = sexp_find_token (keyparam, "curve", 5);
+
+      /* If we don't have a curve name or if override parameters have
+         explicitly been requested, parse them.  */
+      if (!l1 || (flags & PUBKEY_FLAG_PARAM))
+        {
+          errc = mpi_from_keyparam (&p, keyparam, "p");
+          if (errc)
+            goto leave;
+          errc = mpi_from_keyparam (&a, keyparam, "a");
+          if (errc)
+            goto leave;
+          errc = mpi_from_keyparam (&b, keyparam, "b");
+          if (errc)
+            goto leave;
+          errc = point_from_keyparam (&G, keyparam, "g", NULL);
+          if (errc)
+            goto leave;
+          errc = mpi_from_keyparam (&n, keyparam, "n");
+          if (errc)
+            goto leave;
+          errc = mpi_from_keyparam (&h, keyparam, "h");
+          if (errc)
+            goto leave;
+        }
+    }
+  else
+    l1 = NULL; /* No curvename.  */
+
+  /* Check whether a curve parameter is available and use that to fill
+     in missing values.  If no curve parameter is available try an
+     optional provided curvename.  If only the curvename has been
+     given use that one. */
+  if (l1 || curvename)
+    {
+      char *name;
+      elliptic_curve_t *E;
+
+      if (l1)
+        {
+          name = sexp_nth_string (l1, 1);
+          sexp_release (l1);
+          if (!name)
+            {
+              errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
+              goto leave;
+            }
+        }
+      else
+        name = NULL;
+
+      E = xtrycalloc (1, sizeof *E);
+      if (!E)
+        {
+          errc = gpg_err_code_from_syserror ();
+          xfree (name);
+          goto leave;
+        }
+
+      errc = _gcry_ecc_fill_in_curve (0, name? name : curvename, E, NULL);
+      xfree (name);
+      if (errc)
+        {
+          xfree (E);
+          goto leave;
+        }
+
+      model = E->model;
+      dialect = E->dialect;
+
+      if (!p)
+        {
+          p = E->p;
+          E->p = NULL;
+        }
+      if (!a)
+        {
+          a = E->a;
+          E->a = NULL;
+        }
+      if (!b)
+        {
+          b = E->b;
+          E->b = NULL;
+        }
+      if (!G)
+        {
+          G = mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z);
+          E->G.x = NULL;
+          E->G.y = NULL;
+          E->G.z = NULL;
+        }
+      if (!n)
+        {
+          n = E->n;
+          E->n = NULL;
+        }
+      if (!h)
+        {
+          h = E->h;
+          E->h = NULL;
+        }
+      _gcry_ecc_curve_free (E);
+      xfree (E);
+    }
+
+
+  errc = _gcry_mpi_ec_p_new (&ctx, model, dialect, flags, p, a, b);
+  if (!errc)
+    {
+      mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
+
+      if (b)
+        {
+          mpi_free (ec->b);
+          ec->b = b;
+          b = NULL;
+        }
+      if (G)
+        {
+          ec->G = G;
+          G = NULL;
+        }
+      if (n)
+        {
+          ec->n = n;
+          n = NULL;
+        }
+      if (h)
+        {
+          ec->h = h;
+          h = NULL;
+        }
+
+      /* Now that we know the curve name we can look for the public key
+         Q.  point_from_keyparam needs to know the curve parameters so
+         that it is able to use the correct decompression.  Parsing
+         the private key D could have been done earlier but it is less
+         surprising if we do it here as well.  */
+      if (keyparam)
+        {
+          errc = point_from_keyparam (&Q, keyparam, "q", ec);
+          if (errc)
+            goto leave;
+          errc = mpi_from_keyparam (&d, keyparam, "d");
+          if (errc)
+            goto leave;
+        }
+
+      if (Q)
+        {
+          ec->Q = Q;
+          Q = NULL;
+        }
+      if (d)
+        {
+          ec->d = d;
+          d = NULL;
+        }
+
+      *r_ctx = ctx;
+      ctx = NULL;
+    }
+
+ leave:
+  _gcry_ctx_release (ctx);
+  mpi_free (p);
+  mpi_free (a);
+  mpi_free (b);
+  _gcry_mpi_point_release (G);
+  mpi_free (n);
+  mpi_free (h);
+  _gcry_mpi_point_release (Q);
+  mpi_free (d);
+  return errc;
+}
+
+
+/* Return the parameters of the curve NAME as an S-expression.  */
+gcry_sexp_t
+_gcry_ecc_get_param_sexp (const char *name)
+{
+  unsigned int nbits;
+  elliptic_curve_t E;
+  mpi_ec_t ctx;
+  gcry_mpi_t g_x, g_y;
+  gcry_mpi_t pkey[7];
+  gcry_sexp_t result;
+  int i;
+
+  memset (&E, 0, sizeof E);
+  if (_gcry_ecc_fill_in_curve (0, name, &E, &nbits))
+    return NULL;
+
+  g_x = mpi_new (0);
+  g_y = mpi_new (0);
+  ctx = _gcry_mpi_ec_p_internal_new (MPI_EC_WEIERSTRASS,
+                                     ECC_DIALECT_STANDARD,
+                                     0,
+                                     E.p, E.a, NULL);
+  if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
+    log_fatal ("ecc get param: Failed to get affine coordinates\n");
+  _gcry_mpi_ec_free (ctx);
+  _gcry_mpi_point_free_parts (&E.G);
+
+  pkey[0] = E.p;
+  pkey[1] = E.a;
+  pkey[2] = E.b;
+  pkey[3] = _gcry_ecc_ec2os (g_x, g_y, E.p);
+  pkey[4] = E.n;
+  pkey[5] = E.h;
+  pkey[6] = NULL;
+
+  mpi_free (g_x);
+  mpi_free (g_y);
+
+  if (sexp_build (&result, NULL,
+                  "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)))",
+                  pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], pkey[5]))
+    result = NULL;
+
+  for (i=0; pkey[i]; i++)
+    _gcry_mpi_release (pkey[i]);
+
+  return result;
+}
+
+
+/* Return an MPI (or opaque MPI) described by NAME and the context EC.
+   If COPY is true a copy is returned, if not a const MPI may be
+   returned.  In any case mpi_free must be used.  */
+gcry_mpi_t
+_gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
+{
+  if (!*name)
+    return NULL;
+
+  if (!strcmp (name, "p") && ec->p)
+    return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p);
+  if (!strcmp (name, "a") && ec->a)
+    return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a);
+  if (!strcmp (name, "b") && ec->b)
+    return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b);
+  if (!strcmp (name, "n") && ec->n)
+    return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n);
+  if (!strcmp (name, "h") && ec->h)
+    return mpi_is_const (ec->h) && !copy? ec->h : mpi_copy (ec->h);
+  if (!strcmp (name, "d") && ec->d)
+    return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d);
+
+  /* Return a requested point coordinate.  */
+  if (!strcmp (name, "g.x") && ec->G && ec->G->x)
+    return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x);
+  if (!strcmp (name, "g.y") && ec->G && ec->G->y)
+    return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y);
+  if (!strcmp (name, "q.x") && ec->Q && ec->Q->x)
+    return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x);
+  if (!strcmp (name, "q.y") && ec->Q && ec->Q->y)
+    return mpi_is_const (ec->Q->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y);
+
+  /* If the base point has been requested, return it in standard
+     encoding.  */
+  if (!strcmp (name, "g") && ec->G)
+    return _gcry_mpi_ec_ec2os (ec->G, ec);
+
+  /* If the public key has been requested, return it by default in
+     standard uncompressed encoding or if requested in other
+     encodings.  */
+  if (*name == 'q' && (!name[1] || name[1] == '@'))
+    {
+      /* If only the private key is given, compute the public key.  */
+      if (!ec->Q)
+        ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL);
+
+      if (!ec->Q)
+        return NULL;
+
+      if (name[1] != '@')
+        return _gcry_mpi_ec_ec2os (ec->Q, ec);
+
+      if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_EDWARDS)
+        {
+          unsigned char *encpk;
+          unsigned int encpklen;
+
+          if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0,
+                                            &encpk, &encpklen))
+            return mpi_set_opaque (NULL, encpk, encpklen*8);
+        }
+    }
+
+  return NULL;
+}
+
+
+/* Return a point described by NAME and the context EC.  */
+gcry_mpi_point_t
+_gcry_ecc_get_point (const char *name, mpi_ec_t ec)
+{
+  if (!strcmp (name, "g") && ec->G)
+    return point_copy (ec->G);
+  if (!strcmp (name, "q"))
+    {
+      /* If only the private key is given, compute the public key.  */
+      if (!ec->Q)
+        ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL);
+
+      if (ec->Q)
+        return point_copy (ec->Q);
+    }
+
+  return NULL;
+}
+
+
+/* Store the MPI NEWVALUE into the context EC under NAME. */
+gpg_err_code_t
+_gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec)
+{
+  gpg_err_code_t rc = 0;
+
+  if (!*name)
+    ;
+  else if (!strcmp (name, "p"))
+    {
+      mpi_free (ec->p);
+      ec->p = mpi_copy (newvalue);
+      _gcry_mpi_ec_get_reset (ec);
+    }
+  else if (!strcmp (name, "a"))
+    {
+      mpi_free (ec->a);
+      ec->a = mpi_copy (newvalue);
+      _gcry_mpi_ec_get_reset (ec);
+    }
+  else if (!strcmp (name, "b"))
+    {
+      mpi_free (ec->b);
+      ec->b = mpi_copy (newvalue);
+    }
+  else if (!strcmp (name, "n"))
+    {
+      mpi_free (ec->n);
+      ec->n = mpi_copy (newvalue);
+    }
+  else if (!strcmp (name, "h"))
+    {
+      mpi_free (ec->h);
+      ec->h = mpi_copy (newvalue);
+    }
+  else if (*name == 'q' && (!name[1] || name[1] == '@'))
+    {
+      if (newvalue)
+        {
+          if (!ec->Q)
+            ec->Q = mpi_point_new (0);
+          if (ec->dialect == ECC_DIALECT_ED25519)
+            rc = _gcry_ecc_eddsa_decodepoint (newvalue, ec, ec->Q, NULL, NULL);
+          else
+            rc = _gcry_ecc_os2ec (ec->Q, newvalue);
+        }
+      if (rc || !newvalue)
+        {
+          _gcry_mpi_point_release (ec->Q);
+          ec->Q = NULL;
+        }
+      /* Note: We assume that Q matches d and thus do not reset d.  */
+    }
+  else if (!strcmp (name, "d"))
+    {
+      mpi_free (ec->d);
+      ec->d = mpi_copy (newvalue);
+      if (ec->d)
+        {
+          /* We need to reset the public key because it may not
+             anymore match.  */
+          _gcry_mpi_point_release (ec->Q);
+          ec->Q = NULL;
+        }
+    }
+  else
+   rc = GPG_ERR_UNKNOWN_NAME;
+
+  return rc;
+}
+
+
+/* Store the point NEWVALUE into the context EC under NAME.  */
+gpg_err_code_t
+_gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec)
+{
+  if (!strcmp (name, "g"))
+    {
+      _gcry_mpi_point_release (ec->G);
+      ec->G = point_copy (newvalue);
+    }
+  else if (!strcmp (name, "q"))
+    {
+      _gcry_mpi_point_release (ec->Q);
+      ec->Q = point_copy (newvalue);
+    }
+  else
+    return GPG_ERR_UNKNOWN_NAME;
+
+  return 0;
+}
diff --git a/SOURCES/hobble-libgcrypt b/SOURCES/hobble-libgcrypt
new file mode 100755
index 0000000..cc53cc1
--- /dev/null
+++ b/SOURCES/hobble-libgcrypt
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Quit out if anything fails.
+set -e -x
+
+# Clean out patent-or-otherwise-encumbered code.
+# EC:    ????????? ??/??/2015
+
+rm -f cipher/ecc-curves.c
+rm -f tests/curves.c
+rm -f tests/t-mpi-point.c
diff --git a/SOURCES/libgcrypt-1.6.1-mpicoder-gccopt.patch b/SOURCES/libgcrypt-1.6.1-mpicoder-gccopt.patch
new file mode 100644
index 0000000..12555d3
--- /dev/null
+++ b/SOURCES/libgcrypt-1.6.1-mpicoder-gccopt.patch
@@ -0,0 +1,104 @@
+diff -up libgcrypt-1.6.1/mpi/mpicoder.c.gccopt libgcrypt-1.6.1/mpi/mpicoder.c
+--- libgcrypt-1.6.1/mpi/mpicoder.c.gccopt	2014-02-28 15:37:53.983139821 +0100
++++ libgcrypt-1.6.1/mpi/mpicoder.c	2014-02-28 15:47:35.312576387 +0100
+@@ -627,16 +627,16 @@ _gcry_mpi_print (enum gcry_mpi_format fo
+           extra = 1;
+ 	}
+ 
+-      if (buffer && n > len)
+-        {
+-          /* The provided buffer is too short. */
+-          xfree (tmp);
+-          return GPG_ERR_TOO_SHORT;
+-	}
+       if (buffer)
+         {
+           unsigned char *s = buffer;
+ 
++          if (n > len)
++            {
++              /* The provided buffer is too short. */
++              xfree (tmp);
++              return GPG_ERR_TOO_SHORT;
++            }
+           if (extra == 1)
+             *s++ = 0;
+           else if (extra)
+@@ -654,13 +654,12 @@ _gcry_mpi_print (enum gcry_mpi_format fo
+       /* Note:  We ignore the sign for this format.  */
+       /* FIXME: for performance reasons we should put this into
+ 	 mpi_aprint because we can then use the buffer directly.  */
+-
+-      if (buffer && n > len)
+-        return GPG_ERR_TOO_SHORT;
+       if (buffer)
+         {
+           unsigned char *tmp;
+ 
++          if (n > len)
++            return GPG_ERR_TOO_SHORT;
+           tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL);
+           if (!tmp)
+             return gpg_err_code_from_syserror ();
+@@ -678,14 +677,14 @@ _gcry_mpi_print (enum gcry_mpi_format fo
+       if (negative)
+         return GPG_ERR_INV_ARG;
+ 
+-      if (buffer && n+2 > len)
+-        return GPG_ERR_TOO_SHORT;
+-
+       if (buffer)
+         {
+           unsigned char *tmp;
+           unsigned char *s = buffer;
+ 
++          if (n+2 > len)
++            return GPG_ERR_TOO_SHORT;
++
+           s[0] = nbits >> 8;
+           s[1] = nbits;
+ 
+@@ -724,16 +723,16 @@ _gcry_mpi_print (enum gcry_mpi_format fo
+           extra=1;
+ 	}
+ 
+-      if (buffer && n+4 > len)
+-        {
+-          xfree(tmp);
+-          return GPG_ERR_TOO_SHORT;
+-	}
+-
+       if (buffer)
+         {
+           unsigned char *s = buffer;
+ 
++          if (n+4 > len)
++            {
++              xfree(tmp);
++              return GPG_ERR_TOO_SHORT;
++            }
++
+           *s++ = n >> 24;
+           *s++ = n >> 16;
+           *s++ = n >> 8;
+@@ -761,15 +760,15 @@ _gcry_mpi_print (enum gcry_mpi_format fo
+       if (!n || (*tmp & 0x80))
+         extra = 2;
+ 
+-      if (buffer && 2*n + extra + negative + 1 > len)
+-        {
+-          xfree(tmp);
+-          return GPG_ERR_TOO_SHORT;
+-	}
+       if (buffer)
+         {
+           unsigned char *s = buffer;
+ 
++          if (2*n + extra + negative + 1 > len)
++            {
++              xfree(tmp);
++              return GPG_ERR_TOO_SHORT;
++	    }
+           if (negative)
+             *s++ = '-';
+           if (extra)
diff --git a/SOURCES/libgcrypt-1.7.3-ecc-test-fix.patch b/SOURCES/libgcrypt-1.7.3-ecc-test-fix.patch
new file mode 100644
index 0000000..8ce7aa9
--- /dev/null
+++ b/SOURCES/libgcrypt-1.7.3-ecc-test-fix.patch
@@ -0,0 +1,122 @@
+diff -up libgcrypt-1.7.3/tests/benchmark.c.eccfix libgcrypt-1.7.3/tests/benchmark.c
+--- libgcrypt-1.7.3/tests/benchmark.c.eccfix	2016-07-14 11:19:17.000000000 +0200
++++ libgcrypt-1.7.3/tests/benchmark.c	2016-11-22 16:21:00.109004197 +0100
+@@ -1412,7 +1412,7 @@ ecc_bench (int iterations, int print_hea
+ {
+ #if USE_ECC
+   gpg_error_t err;
+-  const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519",
++  const char *p_sizes[] = { "224", "256", "384", "521", "Ed25519",
+               "gost256", "gost512" };
+   int testno;
+ 
+diff -up libgcrypt-1.7.3/tests/dsa-rfc6979.c.eccfix libgcrypt-1.7.3/tests/dsa-rfc6979.c
+--- libgcrypt-1.7.3/tests/dsa-rfc6979.c.eccfix	2016-02-18 09:38:03.000000000 +0100
++++ libgcrypt-1.7.3/tests/dsa-rfc6979.c	2016-11-22 16:22:11.804674008 +0100
+@@ -210,16 +210,6 @@ check_dsa_rfc6979 (void)
+       " ))"
+     },
+     {
+-      "ECDSA, 192 bits (prime field)",
+-      "(private-key"
+-      " (ecdsa"
+-      " (curve \"NIST P-192\")"
+-      " (q #04AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56"
+-      "       3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43#)"
+-      " (d #6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4#)"
+-      " ))"
+-    },
+-    {
+       "ECDSA, 224 bits (prime field)",
+       "(private-key"
+       " (ecdsa"
+@@ -443,89 +433,6 @@ check_dsa_rfc6979 (void)
+       "C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1"
+     },
+     {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-1, message = \"sample\"",
+-      "sha1", "sample",
+-      "37D7CA00D2C7B0E5E412AC03BD44BA837FDD5B28CD3B0021",
+-      "98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF",
+-      "57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-224, message = \"sample\"",
+-      "sha224", "sample",
+-      "4381526B3FC1E7128F202E194505592F01D5FF4C5AF015D8",
+-      "A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5",
+-      "E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-256, message = \"sample\"",
+-      "sha256", "sample",
+-      "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496",
+-      "4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55",
+-      "CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-384, message = \"sample\"",
+-      "sha384", "sample",
+-      "4730005C4FCB01834C063A7B6760096DBE284B8252EF4311",
+-      "DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5",
+-      "C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-512, message = \"sample\"",
+-      "sha512", "sample",
+-      "A2AC7AB055E4F20692D49209544C203A7D1F2C0BFBC75DB1",
+-      "4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8",
+-      "3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-1, message = \"test\"",
+-      "sha1", "test",
+-      "D9CF9C3D3297D3260773A1DA7418DB5537AB8DD93DE7FA25",
+-      "0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D",
+-      "EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-224, message = \"test\"",
+-      "sha224", "test",
+-      "F5DC805F76EF851800700CCE82E7B98D8911B7D510059FBE",
+-      "6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34",
+-      "B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-256, message = \"test\"",
+-      "sha256", "test",
+-      "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C",
+-      "3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE",
+-      "5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-384, message = \"test\"",
+-      "sha384", "test",
+-      "5AFEFB5D3393261B828DB6C91FBC68C230727B030C975693",
+-      "B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367",
+-      "7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A"
+-    },
+-    {
+-      "ECDSA, 192 bits (prime field)",
+-      "With SHA-512, message = \"test\"",
+-      "sha512", "test",
+-      "0758753A5254759C7CFBAD2E2D9B0792EEE44136C9480527",
+-      "FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739",
+-      "74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290"
+-    },
+-
+-
+-
+-    {
+       "ECDSA, 224 bits (prime field)",
+       "With SHA-1, message = \"sample\"",
+       "sha1", "sample",
diff --git a/SOURCES/libgcrypt-1.7.3-fips-cavs.patch b/SOURCES/libgcrypt-1.7.3-fips-cavs.patch
new file mode 100644
index 0000000..42d028e
--- /dev/null
+++ b/SOURCES/libgcrypt-1.7.3-fips-cavs.patch
@@ -0,0 +1,1311 @@
+diff -up libgcrypt-1.7.3/tests/cavs_driver.pl.cavs libgcrypt-1.7.3/tests/cavs_driver.pl
+--- libgcrypt-1.7.3/tests/cavs_driver.pl.cavs	2013-03-15 20:25:38.000000000 +0100
++++ libgcrypt-1.7.3/tests/cavs_driver.pl	2016-11-22 17:29:06.067553077 +0100
+@@ -1,9 +1,11 @@
+ #!/usr/bin/env perl
+ #
+-# $Id: cavs_driver.pl 1497 2009-01-22 14:01:29Z smueller $
++# $Id: cavs_driver.pl 2124 2010-12-20 07:56:30Z smueller $
+ #
+ # CAVS test driver (based on the OpenSSL driver)
+ # Written by: Stephan Müller <sm@atsec.com>
++#	      Werner Koch <wk@g10code.com> (libgcrypt interface)
++#	      Tomas Mraz <tmraz@redhat.com> (addition of DSA2)
+ # Copyright (c) atsec information security corporation
+ #
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
+@@ -85,13 +87,16 @@
+ #	T[CBC|CFB??|ECB|OFB]varkey
+ #	T[CBC|CFB??|ECB|OFB]invperm
+ #	T[CBC|CFB??|ECB|OFB]vartext
++# WARNING: TDES in CFB and OFB mode problems see below
+ #
+ # ANSI X9.31 RNG
+ # 	ANSI931_AES128MCT
+ # 	ANSI931_AES128VST
+ #
+-# DSA
++# DSA2
+ # 	PQGGen
++#	PQGVer
++#	KeyPair
+ # 	SigGen
+ # 	SigVer
+ #
+@@ -101,6 +106,36 @@
+ # 	RC4PltBD
+ # 	RC4REGT
+ #
++#
++# TDES MCT for CFB and OFB:
++# -------------------------
++# The inner loop cannot be handled by this script. If you want to have tests
++# for these cipher types, implement your own inner loop and add it to
++# crypto_mct.
++#
++# the value $next_source in crypto_mct is NOT set by the standard implementation
++# of this script. It would need to be set as follows for these two (code take
++# from fipsdrv.c from libgcrypt - the value input at the end will contain the
++# the value for $next_source:
++#
++# ... inner loop ...
++# ...
++# get_current_iv (hd, last_iv, blocklen);
++# ... encrypt / decrypt (input is the data to be en/decrypted and output is the
++#                        result of operation) ...
++# if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB))
++#   memcpy (input, last_iv, blocklen);
++# else if (cipher_mode == GCRY_CIPHER_MODE_OFB)
++#   memcpy (input, last_iv, blocklen);
++# else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB)
++#   {
++#      /* Reconstruct the output vector.  */
++#      int i;
++#      for (i=0; i < blocklen; i++)
++#         input[i] ^= output[i];
++#   }
++# ... inner loop ends ...
++# ==> now, the value of input is to be put into $next_source
+ 
+ use strict;
+ use warnings;
+@@ -226,6 +261,8 @@ my $hmac;
+ # Generate the P, Q, G, Seed, counter, h (value used to generate g) values
+ # for DSA
+ # $1: modulus size
++# $2: q size
++# $3: seed (might be empty string)
+ # return: string with the calculated values in hex format, where each value
+ # 	  is separated from the previous with a \n in the following order:
+ #         P\n
+@@ -236,6 +273,19 @@ my $hmac;
+ #         h
+ my $dsa_pqggen;
+ 
++# Generate the G value from P and Q
++# for DSA
++# $1: modulus size
++# $2: q size
++# $3: P in hex form
++# $4: Q in hex form
++# return: string with the calculated values in hex format, where each value
++#        is separated from the previous with a \n in the following order:
++#         P\n
++#         Q\n
++#         G\n
++my $dsa_ggen;
++
+ #
+ # Generate an DSA public key from the provided parameters:
+ # $1: Name of file to create
+@@ -255,16 +305,30 @@ my $dsa_verify;
+ 
+ # generate a new DSA key with the following properties:
+ #	PEM format
+-# $1 keyfile name
+-# return: file created, hash with keys of P, Q, G in hex format
++# $1: modulus size
++# $2: q size
++# $3 keyfile name
++# return: file created with key, string with values of P, Q, G in hex format
+ my $gen_dsakey;
+ 
++# generate a new DSA private key XY parameters in domain:
++#      PEM format
++# $1: P in hex form
++# $2: Q in hex form
++# $3: G in hex form
++# return: string with values of X, Y in hex format
++my $gen_dsakey_domain;
++
+ # Sign a message with DSA
+ # $1: data to be signed in hex form
+ # $2: Key file in PEM format with the private key
+ # return: hash of digest information in hex format with Y, R, S as keys
+ my $dsa_sign;
+ 
++my $rsa_keygen;
++
++my $rsa_keygen_kat;
++
+ ################################################################
+ ##### OpenSSL interface functions
+ ################################################################
+@@ -404,6 +468,35 @@ sub libgcrypt_rsa_derive($$$$$$$$) {
+ }
+ 
+ 
++sub libgcrypt_rsa_keygen($) {
++	my $n   = shift;
++	my $sexp;
++
++	$n = sprintf ("%u", $n);
++	$sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")))\n";
++
++	return pipe_through_program($sexp, "fipsdrv rsa-keygen");
++}
++
++
++sub libgcrypt_rsa_keygen_kat($$$$) {
++	my $n   = shift;
++	my $e   = shift;
++	my $p   = shift;
++	my $q   = shift;
++	my $sexp;
++
++	$n = sprintf ("%u", $n);
++	$sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")"
++		. "(test-parms"
++		. "(e #$e#)"
++		. "(p #$p#)"
++		. "(q #$q#))))\n";
++
++	return pipe_through_program($sexp, "fipsdrv rsa-keygen-kat");
++}
++
++
+ sub libgcrypt_rsa_sign($$$) {
+ 	my $data = shift;
+ 	my $hashalgo = shift;
+@@ -500,17 +593,32 @@ sub libgcrypt_hmac($$$$) {
+ 	return pipe_through_program($msg, $program);
+ }
+ 
+-sub libgcrypt_dsa_pqggen($) {
++sub libgcrypt_dsa_pqggen($$$) {
++	my $mod = shift;
++	my $qsize = shift;
++	my $seed = shift;
++
++	my $program = "fipsdrv --keysize $mod --qsize $qsize dsa-pqg-gen";
++	return pipe_through_program($seed, $program);
++}
++
++sub libgcrypt_dsa_ggen($$$$) {
+ 	my $mod = shift;
++	my $qsize = shift;
++	my $p = shift;
++	my $q = shift;
++	my $domain = "(domain (p #$p#)(q #$q#))";
+ 
+-	my $program = "fipsdrv --keysize $mod dsa-pqg-gen";
++	my $program = "fipsdrv --keysize $mod --qsize $qsize --key \'$domain\' dsa-g-gen";
+ 	return pipe_through_program("", $program);
+ }
+ 
+-sub libgcrypt_gen_dsakey($) {
++sub libgcrypt_gen_dsakey($$$) {
++	my $mod = shift;
++	my $qsize = shift;
+ 	my $file = shift;
+ 
+-	my $program = "fipsdrv --keysize 1024 --key $file dsa-gen";
++	my $program = "fipsdrv --keysize $mod --qsize $qsize --key $file dsa-gen";
+ 	my $tmp;
+ 	my %ret;
+ 
+@@ -519,10 +627,21 @@ sub libgcrypt_gen_dsakey($) {
+ 	$tmp = pipe_through_program("", $program);
+ 	die "dsa key gen failed: file $file not created" if (! -f $file);
+ 
+-	@ret{'P', 'Q', 'G', 'Seed', 'c', 'H'} = split(/\n/, $tmp);
++	@ret{'P', 'Q', 'G'} = split(/\n/, $tmp);
+ 	return %ret;
+ }
+ 
++sub libgcrypt_gen_dsakey_domain($$$) {
++	my $p = shift;
++	my $q = shift;
++	my $g = shift;
++	my $domain = "(domain (p #$p#)(q #$q#)(g #$g#))";
++
++	my $program = "fipsdrv --key '$domain' dsa-gen-key";
++
++	return pipe_through_program("", $program);
++}
++
+ sub libgcrypt_dsa_genpubkey($$$$$) {
+ 	my $filename = shift;
+ 	my $p = shift;
+@@ -1139,7 +1258,7 @@ sub hmac_kat($$$$) {
+ 	$out .= "Tlen = $tlen\n";
+ 	$out .= "Key = $key\n";
+ 	$out .= "Msg = $msg\n";
+-	$out .= "Mac = " . &$hmac($key, $tlen, $msg, $hashtype{$tlen}) . "\n";
++	$out .= "Mac = " . lc(&$hmac($key, $tlen, $msg, $hashtype{$tlen})) . "\n";
+ 
+ 	return $out;
+ }
+@@ -1205,7 +1324,7 @@ sub crypto_mct($$$$$$$$) {
+                 }
+                 my ($CO, $CI);
+ 		my $cipher_imp = &$state_cipher($cipher, $enc, $bufsize, $key1, $iv);
+-		$cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/);
++		$cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/ && defined($state_cipher_des));
+                 my $pid = open2($CO, $CI, $cipher_imp);
+ 
+                 my $calc_data = $iv; # CT[j]
+@@ -1213,8 +1332,8 @@ sub crypto_mct($$$$$$$$) {
+                 my $old_old_calc_data; # CT[j-2]
+ 		my $next_source;
+ 
+-		# TDES inner loop implements logic within driver
+-		if ($cipher =~ /des/) {
++		# TDES inner loop implements logic within driver of libgcrypt
++		if ($cipher =~ /des/ && $opt{'I'} && $opt{'I'} eq 'libgcrypt' ) {
+ 			# Need to provide a dummy IV in case of ECB mode.
+ 			my $iv_arg = (defined($iv) && $iv ne "")
+ 					? bin2hex($iv)
+@@ -1238,6 +1357,10 @@ sub crypto_mct($$$$$$$$) {
+ 			$line = <$CO>;
+ 		} else {
+ 	                for (my $j = 0; $j < $iloop; ++$j) {
++				if ($cipher =~ /des-ede3-ofb/ ||
++				    (!$enc && $cipher =~ /des-ede3-cfb/)) {
++					die "Implementation lacks support for TDES OFB and TDES CFB in encryption mode - the problem is that we would need to extract the IV of the last round of encryption which would be the input for the next round - see comments in this script for implementation requirements"; 
++				}
+ 				$old_old_calc_data = $old_calc_data;
+                 	        $old_calc_data = $calc_data;
+ 
+@@ -1429,7 +1552,7 @@ sub rsa_sigver($$$$$) {
+ # $7 xq2
+ # $8 Xq
+ # return: string formatted as expected by CAVS
+-sub rsa_keygen($$$$$$$$) {
++sub rsa_keygen_x931($$$$$$$$) {
+ 	my $modulus = shift;
+ 	my $e = shift;
+ 	my $xp1 = shift;
+@@ -1503,21 +1626,23 @@ sub rngx931($$$$) {
+ 	return $out;
+ }
+ 
+-# DSA PQGGen test
++# DSA PQGen test
+ # $1 modulus size
+-# $2 number of rounds to perform the test
++# $2 q size
++# $3 number of rounds to perform the test
+ # return: string formatted as expected by CAVS
+-sub dsa_pqggen_driver($$) {
++sub dsa_pqgen_driver($$$) {
+ 	my $mod = shift;
++	my $qsize = shift;
+ 	my $rounds = shift;
+ 
+ 	my $out = "";
+ 	for(my $i=0; $i<$rounds; $i++) {
+-		my $ret = &$dsa_pqggen($mod);
++		my $ret = &$dsa_pqggen($mod, $qsize, "");
+ 		my ($P, $Q, $G, $Seed, $c, $H) = split(/\n/, $ret);
+-		die "Return value does not contain all expected values of P, Q, G, Seed, c, H for dsa_pqggen"
+-			if (!defined($P) || !defined($Q) || !defined($G) ||
+-			    !defined($Seed) || !defined($c) || !defined($H));
++		die "Return value does not contain all expected values of P, Q, Seed, c for dsa_pqggen"
++			if (!defined($P) || !defined($Q) ||
++			    !defined($Seed) || !defined($c));
+ 
+ 		# now change the counter to decimal as CAVS wants decimal
+ 		# counter value although all other is HEX
+@@ -1525,15 +1650,166 @@ sub dsa_pqggen_driver($$) {
+ 
+ 		$out .= "P = $P\n";
+ 		$out .= "Q = $Q\n";
+-		$out .= "G = $G\n";
+-		$out .= "Seed = $Seed\n";
+-		$out .= "c = $c\n";
+-		$out .= "H = $H\n\n";
++		$out .= "domain_parameter_seed = $Seed\n";
++		$out .= "counter = $c\n\n";
+ 	}
+ 
+ 	return $out;
+ }
+ 
++# DSA GGen test
++# $1 modulus size
++# $2 q size
++# $3 p in hex form
++# $4 q in hex form
++# return: string formatted as expected by CAVS
++sub dsa_ggen_driver($$$$) {
++	my $mod = shift;
++	my $qsize = shift;
++	my $p = shift;
++	my $q = shift;
++
++	my $out = "";
++	my $ret = &$dsa_ggen($mod, $qsize, $p, $q);
++	my ($P, $Q, $G) = split(/\n/, $ret);
++	die "Return value does not contain all expected values of P, Q, G for dsa_ggen"
++		if (!defined($P) || !defined($Q) || !defined($G));
++
++	$out .= "G = $G\n\n";
++
++	return $out;
++}
++
++sub hexcomp($$) {
++	my $a = lc shift;
++	my $b = lc shift;
++
++	if (length $a < length $b) {
++		my $c = $a;
++		$a = $b;
++		$b = $a;
++	}
++
++	while (length $b < length $a) {
++		$b = "00$b";
++	}
++
++	return $a eq $b;
++}
++
++# DSA PQVer test
++# $1 modulus size
++# $2 q size
++# $3 p in hex form
++# $4 q in hex form
++# $5 seed in hex form
++# $6 c decimal counter
++# return: string formatted as expected by CAVS
++sub dsa_pqver_driver($$$$$$) {
++	my $mod = shift;
++	my $qsize = shift;
++	my $p = shift;
++	my $q = shift;
++	my $seed = shift;
++	my $c = shift;
++
++	my $out = "";
++	my $ret = &$dsa_pqggen($mod, $qsize, $seed);
++	my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret);
++	die "Return value does not contain all expected values of P, Q, G, seed, c for dsa_pqggen"
++		if (!defined($P) || !defined($Q) || !defined($G) ||
++		    !defined($seed2) || !defined($c2));
++
++	$c2 = hex($c2);
++
++	$out .= "Seed = $seed\n";
++	$out .= "c = $c\n";
++
++	if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($seed, $seed2) && $c == $c2) {
++		$out .= "Result = P\n\n";
++	}
++	else {
++		$out .= "Result = F\n\n";
++	}
++	return $out;
++}
++
++# DSA PQGVer test
++# $1 modulus size
++# $2 q size
++# $3 p in hex form
++# $4 q in hex form
++# $5 g in hex form
++# $6 seed in hex form
++# $7 c decimal counter
++# $8 h in hex form
++# return: string formatted as expected by CAVS
++sub dsa_pqgver_driver($$$$$$$$) {
++	my $mod = shift;
++	my $qsize = shift;
++	my $p = shift;
++	my $q = shift;
++	my $g = shift;
++	my $seed = shift;
++	my $c = shift;
++	my $h = shift;
++
++	my $out = "";
++	my $ret = &$dsa_pqggen($mod, $qsize, $seed);
++	my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret);
++	die "Return value does not contain all expected values of P, Q, G, seed, c, H for dsa_pqggen"
++		if (!defined($P) || !defined($Q) || !defined($G) ||
++		    !defined($seed2) || !defined($c2) || !defined($h2));
++
++	
++
++	$out .= "Seed = $seed\n";
++	$out .= "c = $c\n";
++	$out .= "H = $h\n";
++
++	$c2 = hex($c2);
++
++	if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($G, $g) && hexcomp($seed, $seed2) && 
++	    $c == $c2 && hex($h) == hex($h2)) {
++		$out .= "Result = P\n\n";
++	}
++	else {
++		$out .= "Result = F\n\n";
++	}
++
++	return $out;
++}
++
++# DSA Keypair test
++# $1 modulus size
++# $2 q size
++# $3 number of rounds to perform the test
++# return: string formatted as expected by CAVS
++sub dsa_keypair_driver($$$) {
++	my $mod = shift;
++	my $qsize = shift;
++	my $rounds = shift;
++
++	my $out = "";
++	my $tmpkeyfile = "dsa_siggen.tmp.$$";
++	my %pqg = &$gen_dsakey($mod, $qsize, $tmpkeyfile);
++	$out .= "P = " . $pqg{'P'} . "\n";
++	$out .= "Q = " . $pqg{'Q'} . "\n";
++	$out .= "G = " . $pqg{'G'} . "\n\n";
++	unlink($tmpkeyfile);
++
++	for(my $i=0; $i<$rounds; $i++) {
++		my $ret = &$gen_dsakey_domain($pqg{'P'}, $pqg{'Q'}, $pqg{'G'});
++		my ($X, $Y) = split(/\n/, $ret);
++		die "Return value does not contain all expected values of X, Y for gen_dsakey_domain"
++			if (!defined($X) || !defined($Y));
++
++		$out .= "X = $X\n";
++		$out .= "Y = $Y\n\n";
++	}
++
++	return $out;
++}
+ 
+ # DSA SigGen test
+ # $1: Message to be signed in hex form
+@@ -1598,6 +1874,53 @@ sub dsa_sigver($$$$$$$$) {
+ 	return $out;
+ }
+ 
++# RSA Keygen RPP test
++# $1 modulus size
++# $2 number of rounds to perform the test
++# return: string formatted as expected by CAVS
++sub rsa_keygen_driver($$) {
++	my $mod = shift;
++	my $rounds = shift;
++
++	my $out = "";
++
++	for(my $i=0; $i<$rounds; $i++) {
++		my $ret = &$rsa_keygen($mod);
++		my ($e, $p, $q, $n, $d) = split(/\n/, $ret);
++		die "Return value does not contain all expected values of e, p, q, n, d for rsa_keygen"
++			if (!defined($e) || !defined($p) || !defined($q) || !defined($n) || !defined($d));
++
++		$out .= "e = $e\n";
++		$out .= "p = $p\n";
++		$out .= "q = $q\n";
++		$out .= "n = $n\n";
++		$out .= "d = $d\n\n";
++	}
++
++	return $out;
++}
++
++# RSA RPP Keygen KAT test
++# $1 modulus size
++# $2 p in hex form
++# $3 q in hex form
++# return: string formatted as expected by CAVS
++sub rsa_keygen_kat_driver($$$) {
++	my $mod = shift;
++	my $p = shift;
++	my $q = shift;
++
++	my $out = "";
++	my $ret = &$rsa_keygen_kat($mod, $p, $q);
++	my ($Result) = split(/\n/, $ret);
++	die "Return value does not contain all expected values of Result for rsa_keygen_kat"
++		if (!defined($Result));
++
++	$out .= "Result = $Result\n\n";
++	return $out;
++}
++
++
+ ##############################################################
+ # Parser of input file and generator of result file
+ #
+@@ -1658,12 +1981,18 @@ sub parse($$) {
+ 	my $klen = "";
+ 	my $tlen = "";
+ 	my $modulus = "";
++	my $qsize = "";
+ 	my $capital_n = 0;
++	my $num = 0;
+ 	my $capital_p = "";
+ 	my $capital_q = "";
+ 	my $capital_g = "";
+ 	my $capital_y = "";
+ 	my $capital_r = "";
++	my $capital_h = "";
++	my $c = "";
++	my $prandom = "";
++	my $qrandom = "";
+ 	my $xp1 = "";
+ 	my $xp2 = "";
+ 	my $Xp = "";
+@@ -1700,7 +2029,7 @@ sub parse($$) {
+ 
+ 		##### Extract cipher
+ 		# XXX there may be more - to be added
+-		if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA)/) {
++		if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyGen - Random Probably Prime|KeyPair|PQGVer)/) {
+ 			if ($tmpline    =~ /CBC/)   { $mode="cbc"; }
+ 			elsif ($tmpline =~ /ECB/)   { $mode="ecb"; }
+ 			elsif ($tmpline =~ /OFB/)   { $mode="ofb"; }
+@@ -1749,7 +2078,23 @@ sub parse($$) {
+ 
+ 			if ($tt == 0) {
+ 			##### Identify the test type
+-				if ($tmpline =~ /KeyGen RSA \(X9\.31\)/) {
++				if ($tmpline =~ /KeyGen - Random Probably Prime Known Answer Test/) {
++					$tt = 19;
++					die "Interface function rsa_keygen_kat for RSA key generation KAT not defined for tested library"
++						if (!defined($rsa_keygen_kat));
++				} elsif ($tmpline =~ /KeyGen - Random Probably Prime Test/) {
++					$tt = 18;
++					die "Interface function rsa_keygen for RSA key generation not defined for tested library"
++						if (!defined($rsa_keygen));
++				} elsif ($tmpline =~ /PQGVer/) {
++					$tt = 16;
++					die "Interface function for DSA PQGVer testing not defined for tested library"
++						if (!defined($dsa_pqggen));
++				} elsif ($tmpline =~ /KeyPair/) {
++					$tt = 14;
++					die "Interface function dsa_keygen for DSA key generation not defined for tested library"
++						if (!defined($gen_dsakey_domain));
++				} elsif ($tmpline =~ /KeyGen RSA \(X9\.31\)/) {
+ 					$tt = 13;
+ 					die "Interface function rsa_derive for RSA key generation not defined for tested library"
+ 						if (!defined($rsa_derive));
+@@ -1760,11 +2105,11 @@ sub parse($$) {
+ 				} elsif ($tmpline =~ /SigGen/ && $opt{'D'}) {
+ 					$tt = 11;
+ 					die "Interface function dsa_sign or gen_dsakey for DSA sign not defined for tested library"
+-						if (!defined($dsa_sign) || !defined($gen_rsakey));
++						if (!defined($dsa_sign) || !defined($gen_dsakey));
+ 				} elsif ($tmpline =~ /PQGGen/) {
+ 					$tt = 10;
+ 					die "Interface function for DSA PQGGen testing not defined for tested library"
+-						if (!defined($dsa_pqggen));
++						if (!defined($dsa_pqggen) || !defined($dsa_ggen));
+ 				} elsif ($tmpline =~ /Hash sizes tested/) {
+ 					$tt = 9;
+ 					die "Interface function hmac for HMAC testing not defined for tested library"
+@@ -1792,7 +2137,7 @@ sub parse($$) {
+ 				} elsif ($tmpline =~ /Monte|MCT|Carlo/) {
+ 					$tt = 2;
+ 					die "Interface function state_cipher for Stateful Cipher operation defined for tested library"
+-						if (!defined($state_cipher) || !defined($state_cipher_des));
++						if (!defined($state_cipher) && !defined($state_cipher_des));
+ 				} elsif ($cipher =~ /^sha/) {
+ 					$tt = 3;
+ 					die "Interface function hash for Hashing not defined for tested library"
+@@ -1875,18 +2220,44 @@ sub parse($$) {
+ 			die "Msg/Seed seen twice - input file crap" if ($pt ne "");
+ 			$pt=$2;
+ 		}
+-		elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests
++		elsif ($line =~ /^\[A.2.1\s.*\]$/) { # found in DSA2 PQGGen request
++			$out .= $line . "\n"; # print it
++			if ($tt == 10) {
++				# now generate G from PQ
++				$tt = 15;
++			}
++		}
++		elsif ($line =~ /^\[A.2.2\s.*\]$/) { # found in DSA2 PQGVer request
++			$out .= $line . "\n"; # print it
++			if ($tt == 16) {
++				# now verify PQG
++				$tt = 17;
++			}
++		}
++		elsif ($line =~ /^\[mod\s*=\s*L=([0-9]*),\s*N=([0-9]*).*\]$/) { # found in DSA2 requests
+ 			$modulus = $1;
++			$qsize = $2;
+ 			$out .= $line . "\n\n"; # print it
++			# clear eventual PQG
++			$capital_p = "";
++			$capital_q = "";
++			$capital_g = "";
+ 			# generate the private key with given bit length now
+ 			# as we have the required key length in bit
+ 			if ($tt == 11) {
+ 				$dsa_keyfile = "dsa_siggen.tmp.$$";
+-				my %pqg = &$gen_dsakey($dsa_keyfile);
++				my %pqg = &$gen_dsakey($modulus, $qsize, $dsa_keyfile);
+ 				$out .= "P = " . $pqg{'P'} . "\n";
+ 				$out .= "Q = " . $pqg{'Q'} . "\n";
+-				$out .= "G = " . $pqg{'G'} . "\n";
+-			} elsif ( $tt == 5 ) {
++				$out .= "G = " . $pqg{'G'} . "\n\n";
++                        }
++                }
++		elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests
++			$modulus = $1;
++			$out .= $line . "\n\n"; # print it
++			# generate the private key with given bit length now
++			# as we have the required key length in bit
++			if ( $tt == 5 ) {
+ 				# XXX maybe a secure temp file name is better here
+ 				# but since it is not run on a security sensitive
+ 				# system, I hope that this is fine
+@@ -1907,6 +2278,9 @@ sub parse($$) {
+ 		}
+ 		elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests
+ 			$e=$1;
++			if ($tt == 19) {
++				$out .= $line . "\n"; # print it
++			}
+ 		}
+ 		elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests
+ 			die "S seen twice - input file crap" if ($signature ne "");
+@@ -1932,11 +2306,16 @@ sub parse($$) {
+ 				if ($tlen ne "");
+ 			$tlen=$1;
+ 		}
+-		elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA PQGGen
++		elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair
+ 			die "N seen twice - check input file"
+ 				if ($capital_n);
+ 			$capital_n = $1;
+ 		}
++		elsif ($line =~ /^Num\s*=\s*(.*)/) { #DSA PQGGen
++			die "Num seen twice - check input file"
++				if ($num);
++			$num = $1;
++		}
+ 		elsif ($line =~ /^P\s*=\s*(.*)/) { #DSA SigVer
+ 			die "P seen twice - check input file"
+ 				if ($capital_p);
+@@ -1965,6 +2344,16 @@ sub parse($$) {
+ 				if ($capital_r);
+ 			$capital_r = $1;
+ 		}
++		elsif ($line =~ /^H\s*=\s*(.*)/) { #DSA PQGVer
++			die "H seen twice - check input file"
++				if ($capital_h);
++			$capital_h = $1;
++		}
++		elsif ($line =~ /^c\s*=\s*(.*)/) { #DSA PQGVer
++			die "c seen twice - check input file"
++				if ($c);
++			$c = $1;
++		}
+ 		elsif ($line =~ /^xp1\s*=\s*(.*)/) { #RSA key gen
+ 			die "xp1 seen twice - check input file"
+ 				if ($xp1);
+@@ -1995,6 +2384,22 @@ sub parse($$) {
+ 				if ($Xq);
+ 			$Xq = $1;
+ 		}
++		elsif ($line =~ /^prandom\s*=\s*(.*)/) { #RSA key gen KAT
++			die "prandom seen twice - check input file"
++				if ($prandom);
++			$prandom = $1;
++			$out .= $line . "\n"; # print it
++		}
++		elsif ($line =~ /^qrandom\s*=\s*(.*)/) { #RSA key gen KAT
++			die "qrandom seen twice - check input file"
++				if ($qrandom);
++			$qrandom = $1;
++			$out .= $line . "\n"; # print it
++		}
++		elsif ($tt == 19 && $line =~ /^ / && $qrandom eq "") { #RSA key gen KAT
++			$qrandom = "00";
++			$out .= $line . "\n"; # print it
++		}
+ 		else {
+ 			$out .= $line . "\n";
+ 		}
+@@ -2074,11 +2479,10 @@ sub parse($$) {
+ 			}
+ 		}
+ 		elsif ($tt == 10) {
+-			if ($modulus ne "" && $capital_n > 0) {
+-				$out .= dsa_pqggen_driver($modulus, $capital_n);
+-				#$mod is not resetted
+-				$capital_n = 0;
+-			}
++			if ($modulus ne "" && $qsize ne "" && $num > 0) {
++				$out .= dsa_pqgen_driver($modulus, $qsize, $num);
++				$num = 0;
++                        }
+ 		}
+ 		elsif ($tt == 11) {
+ 			if ($pt ne "" && $dsa_keyfile ne "") {
+@@ -2124,7 +2528,7 @@ sub parse($$) {
+ 			   $xq1 ne "" &&
+ 			   $xq2 ne "" &&
+ 			   $Xq ne "") {
+-				$out .= rsa_keygen($modulus,
++				$out .= rsa_keygen_x931($modulus,
+ 						   $e,
+ 						   $xp1,
+ 						   $xp2,
+@@ -2141,6 +2545,96 @@ sub parse($$) {
+ 				$Xq = "";
+ 			}
+ 		}
++		elsif ($tt == 14) {
++			if ($modulus ne "" &&
++			    $qsize ne "" &&
++			    $capital_n > 0) {
++				$out .= dsa_keypair_driver($modulus,
++							   $qsize,
++							   $capital_n);
++				$capital_n = 0;
++			}
++		}
++		elsif ($tt == 15) {
++			if ($modulus ne "" &&
++			    $qsize ne "" &&
++			    $capital_p ne "" &&
++			    $capital_q ne "") {
++				$out .= dsa_ggen_driver($modulus,
++							$qsize,
++							$capital_p,
++							$capital_q);
++				$capital_p = "";
++				$capital_q = "";
++				$num--;
++			}
++		}
++		elsif ($tt == 16) {
++			if ($modulus ne "" &&
++			    $qsize ne "" &&
++			    $capital_p ne "" &&
++			    $capital_q ne "" &&
++			    $pt ne "" &&
++			    $c ne "") {
++				$out .= dsa_pqver_driver($modulus,
++							$qsize,
++							$capital_p,
++							$capital_q,
++							$pt,
++							$c);
++				$capital_p = "";
++				$capital_q = "";
++				$pt = "";
++				$c = "";
++			}
++		}
++		elsif ($tt == 17) {
++			if ($modulus ne "" &&
++			    $qsize ne "" &&
++			    $capital_p ne "" &&
++			    $capital_q ne "" &&
++			    $capital_g ne "" &&
++			    $pt ne "" &&
++			    $c ne "" &&
++			    $capital_h ne "") {
++				$out .= dsa_pqgver_driver($modulus,
++							$qsize,
++							$capital_p,
++							$capital_q,
++							$capital_g,
++							$pt,
++							$c,
++							$capital_h);
++				$capital_p = "";
++				$capital_q = "";
++				$capital_g = "";
++				$pt = "";
++				$c = "";
++				$capital_h = "";
++			}
++		}
++		elsif ($tt == 18) {
++			if ($modulus ne "" &&
++			    $capital_n > 0) {
++				$out .= rsa_keygen_driver($modulus,
++						$capital_n);
++				$capital_n = 0;
++			}
++		}
++		elsif ($tt == 19) {
++			if ($modulus ne "" &&
++			    $e ne "" &&
++			    $prandom ne "" &&
++			    $qrandom ne "") {
++				$out .= rsa_keygen_kat_driver($modulus,
++						$e,
++						$prandom,
++						$qrandom);
++				$prandom = "";
++				$qrandom = "";
++				$e = "";
++			}
++		}
+ 		elsif ($tt > 0) {
+ 			die "Test case $tt not defined";
+ 		}
+@@ -2199,10 +2693,14 @@ sub main() {
+ 		$state_rng =	\&libgcrypt_state_rng;
+ 		$hmac =		\&libgcrypt_hmac;
+ 		$dsa_pqggen = 	\&libgcrypt_dsa_pqggen;
++		$dsa_ggen =	\&libgcrypt_dsa_ggen;
+ 		$gen_dsakey =   \&libgcrypt_gen_dsakey;
++		$gen_dsakey_domain =	\&libgcrypt_gen_dsakey_domain;
+ 		$dsa_sign =     \&libgcrypt_dsa_sign;
+ 		$dsa_verify =   \&libgcrypt_dsa_verify;
+ 		$dsa_genpubkey = \&libgcrypt_dsa_genpubkey;
++		$rsa_keygen = \&libgcrypt_rsa_keygen;
++		$rsa_keygen_kat = \&libgcrypt_rsa_keygen_kat;
+         } else {
+                 die "Invalid interface option given";
+         }
+diff -up libgcrypt-1.7.3/tests/cavs_tests.sh.cavs libgcrypt-1.7.3/tests/cavs_tests.sh
+--- libgcrypt-1.7.3/tests/cavs_tests.sh.cavs	2013-03-15 20:25:38.000000000 +0100
++++ libgcrypt-1.7.3/tests/cavs_tests.sh	2016-11-22 17:29:06.067553077 +0100
+@@ -55,7 +55,7 @@ function run_one_test () {
+     [ -d "$respdir" ] || mkdir "$respdir"
+     [ -f "$rspfile" ] &&  rm "$rspfile"
+ 
+-    if echo "$reqfile" | grep '/DSA/req/' >/dev/null 2>/dev/null; then
++    if echo "$reqfile" | grep '/DSA.\?/req/' >/dev/null 2>/dev/null; then
+         dflag="-D"
+     fi
+ 
+diff -up libgcrypt-1.7.3/tests/fipsdrv.c.cavs libgcrypt-1.7.3/tests/fipsdrv.c
+--- libgcrypt-1.7.3/tests/fipsdrv.c.cavs	2016-07-14 11:19:17.000000000 +0200
++++ libgcrypt-1.7.3/tests/fipsdrv.c	2016-11-22 17:33:15.468330859 +0100
+@@ -892,6 +892,9 @@ print_mpi_line (gcry_mpi_t a, int no_lz)
+     die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err));
+ 
+   p = buf;
++  while (*p)
++     *p++ = tolower(*p);
++  p = buf;
+   if (no_lz && p[0] == '0' && p[1] == '0' && p[2])
+     p += 2;
+ 
+@@ -1765,14 +1768,14 @@ run_rsa_verify (const void *data, size_t
+ /* Generate a DSA key of size KEYSIZE and return the complete
+    S-expression.  */
+ static gcry_sexp_t
+-dsa_gen (int keysize)
++dsa_gen (int keysize, int qsize)
+ {
+   gpg_error_t err;
+   gcry_sexp_t keyspec, key;
+ 
+   err = gcry_sexp_build (&keyspec, NULL,
+-                         "(genkey (dsa (nbits %d)(use-fips186-2)))",
+-                         keysize);
++                         "(genkey (dsa (nbits %d)(qbits %d)(use-fips186)))",
++                         keysize, qsize);
+   if (err)
+     die ("gcry_sexp_build failed for DSA key generation: %s\n",
+          gpg_strerror (err));
+@@ -1790,7 +1793,7 @@ dsa_gen (int keysize)
+ /* Generate a DSA key of size KEYSIZE and return the complete
+    S-expression.  */
+ static gcry_sexp_t
+-dsa_gen_with_seed (int keysize, const void *seed, size_t seedlen)
++dsa_gen_with_seed (int keysize, int qsize, const void *seed, size_t seedlen)
+ {
+   gpg_error_t err;
+   gcry_sexp_t keyspec, key;
+@@ -1799,10 +1802,11 @@ dsa_gen_with_seed (int keysize, const vo
+                          "(genkey"
+                          "  (dsa"
+                          "    (nbits %d)"
+-                         "    (use-fips186-2)"
++                         "    (qbits %d)"
++                         "    (use-fips186)"
+                          "    (derive-parms"
+                          "      (seed %b))))",
+-                         keysize, (int)seedlen, seed);
++                         keysize, qsize, (int)seedlen, seed);
+   if (err)
+     die ("gcry_sexp_build failed for DSA key generation: %s\n",
+          gpg_strerror (err));
+@@ -1810,6 +1814,37 @@ dsa_gen_with_seed (int keysize, const vo
+   err = gcry_pk_genkey (&key, keyspec);
+   if (err)
+     die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err));
++  
++  gcry_sexp_release (keyspec);
++
++  return key;
++}
++
++/* Generate a DSA key with specified domain parameters and return the complete
++   S-expression.  */
++static gcry_sexp_t
++dsa_gen_key (const char *domain)
++{
++  gpg_error_t err;
++  gcry_sexp_t keyspec, key, domspec;
++
++  err = gcry_sexp_new (&domspec, domain, strlen(domain), 0);
++  if (err)
++    die ("gcry_sexp_build failed for domain spec: %s\n",
++         gpg_strerror (err));
++
++  err = gcry_sexp_build (&keyspec, NULL,
++                         "(genkey"
++                         "  (dsa"
++                         "    (use-fips186)"
++                         "    %S))",
++                         domspec);
++  if (err)
++    die ("gcry_sexp_build failed for DSA key generation: %s\n",
++         gpg_strerror (err));
++  err = gcry_pk_genkey (&key, keyspec);
++  if (err)
++    die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err));
+ 
+   gcry_sexp_release (keyspec);
+ 
+@@ -1849,7 +1884,7 @@ ecdsa_gen_key (const char *curve)
+    with one parameter per line in hex format using this order: p, q,
+    g, seed, counter, h. */
+ static void
+-print_dsa_domain_parameters (gcry_sexp_t key)
++print_dsa_domain_parameters (gcry_sexp_t key, int print_misc)
+ {
+   gcry_sexp_t l1, l2;
+   gcry_mpi_t mpi;
+@@ -1885,6 +1920,9 @@ print_dsa_domain_parameters (gcry_sexp_t
+     }
+   gcry_sexp_release (l1);
+ 
++  if (!print_misc)
++	return;
++
+   /* Extract the seed values.  */
+   l1 = gcry_sexp_find_token (key, "misc-key-info", 0);
+   if (!l1)
+@@ -1976,38 +2014,106 @@ print_ecdsa_dq (gcry_sexp_t key)
+ }
+ 
+ 
+-/* Generate DSA domain parameters for a modulus size of KEYSIZE.  The
++/* Print just the XY private key parameters.  KEY
++   is the complete key as returned by dsa_gen.  We print to stdout
++   with one parameter per line in hex format using this order: x, y. */
++static void 
++print_dsa_xy (gcry_sexp_t key)
++{
++  gcry_sexp_t l1, l2;
++  gcry_mpi_t mpi;
++  int idx;
++
++  l1 = gcry_sexp_find_token (key, "private-key", 0);
++  if (!l1)
++    die ("private key not found in genkey result\n");
++
++  l2 = gcry_sexp_find_token (l1, "dsa", 0);
++  if (!l2)
++    die ("returned private key not formed as expected\n");
++  gcry_sexp_release (l1);
++  l1 = l2;
++
++  /* Extract the parameters from the S-expression and print them to stdout.  */
++  for (idx=0; "xy"[idx]; idx++) 
++    {
++      l2 = gcry_sexp_find_token (l1, "xy"+idx, 1);
++      if (!l2)
++        die ("no %c parameter in returned public key\n", "xy"[idx]);
++      mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
++      if (!mpi)
++        die ("no value for %c parameter in returned private key\n","xy"[idx]);
++      gcry_sexp_release (l2);
++      if (standalone_mode)
++        printf ("%c = ", "XY"[idx]);
++      print_mpi_line (mpi, 1);
++      gcry_mpi_release (mpi);
++    }
++
++  gcry_sexp_release (l1);
++}
++
++
++/* Generate DSA pq domain parameters for a modulus size of KEYSIZE.  The
+    result is printed to stdout with one parameter per line in hex
+-   format and in this order: p, q, g, seed, counter, h.  If SEED is
++   format and in this order: p, q, seed, counter.  If SEED is
+    not NULL this seed value will be used for the generation.  */
+ static void
+-run_dsa_pqg_gen (int keysize, const void *seed, size_t seedlen)
++run_dsa_pqg_gen (int keysize, int qsize, const void *seed, size_t seedlen)
+ {
+   gcry_sexp_t key;
+ 
+   if (seed)
+-    key = dsa_gen_with_seed (keysize, seed, seedlen);
++    key = dsa_gen_with_seed (keysize, qsize, seed, seedlen);
+   else
+-    key = dsa_gen (keysize);
+-  print_dsa_domain_parameters (key);
++    key = dsa_gen (keysize, qsize);
++  print_dsa_domain_parameters (key, 1);
++  gcry_sexp_release (key);
++}
++
++
++/* Generate DSA domain parameters for a modulus size of KEYSIZE.  The
++   result is printed to stdout with one parameter per line in hex
++   format and in this order: p, q, g, seed, counter, h.  If SEED is
++   not NULL this seed value will be used for the generation.  */
++static void
++run_dsa_g_gen (int keysize, int qsize, const char *domain)
++{
++  gcry_sexp_t key;
++
++  key = dsa_gen_key (domain);
++  print_dsa_domain_parameters (key, 0);
++  gcry_sexp_release (key);
++}
++
++/* Generate a DSA key with specified domain parameters
++   and print the XY values. */
++static void
++run_dsa_gen_key (const char *domain)
++{
++  gcry_sexp_t key;
++
++  key = dsa_gen_key (domain);
++  print_dsa_xy (key);
++
+   gcry_sexp_release (key);
+ }
+ 
+ 
+ /* Generate a DSA key of size of KEYSIZE and write the private key to
+    FILENAME.  Also write the parameters to stdout in the same way as
+-   run_dsa_pqg_gen.  */
++   run_dsa_g_gen.  */
+ static void
+-run_dsa_gen (int keysize, const char *filename)
++run_dsa_gen (int keysize, int qsize, const char *filename)
+ {
+   gcry_sexp_t key, private_key;
+   FILE *fp;
+ 
+-  key = dsa_gen (keysize);
++  key = dsa_gen (keysize, qsize);
+   private_key = gcry_sexp_find_token (key, "private-key", 0);
+   if (!private_key)
+     die ("private key not found in genkey result\n");
+-  print_dsa_domain_parameters (key);
++  print_dsa_domain_parameters (key, 1);
+ 
+   fp = fopen (filename, "wb");
+   if (!fp)
+@@ -2020,6 +2126,53 @@ run_dsa_gen (int keysize, const char *fi
+ }
+ 
+ 
++static int
++dsa_hash_from_key(gcry_sexp_t s_key)
++{
++  gcry_sexp_t l1, l2;
++  gcry_mpi_t q;
++  unsigned int qbits;
++
++  l1 = gcry_sexp_find_token (s_key, "public-key", 0);
++  if (!l1)
++    {
++      l1 = gcry_sexp_find_token (s_key, "private-key", 0);
++      if (!l1)
++        die ("neither private nor public key found in the loaded key\n");
++    }
++
++  l2 = gcry_sexp_find_token (l1, "dsa", 0);
++  if (!l2)
++    die ("public key not formed as expected - no dsa\n");
++  gcry_sexp_release (l1);
++  l1 = l2;
++
++  l2 = gcry_sexp_find_token (l1, "q", 0);
++  if (!l2)
++    die ("public key not formed as expected - no q\n");
++  gcry_sexp_release (l1);
++  l1 = l2;
++
++  q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
++  if (!q)
++    die ("public key not formed as expected - no mpi in q\n");
++  qbits = gcry_mpi_get_nbits(q);
++  gcry_sexp_release(l1);
++  gcry_mpi_release(q);
++  switch(qbits)
++    {
++    case 160:
++	return GCRY_MD_SHA1;
++    case 224:
++	return GCRY_MD_SHA224;
++    case 256:
++        return GCRY_MD_SHA256;
++    default:
++        die("bad number bits (%d) of q in key\n", qbits);
++    }
++  return GCRY_MD_NONE;
++}
++
+ 
+ /* Sign DATA of length DATALEN using the key taken from the S-expression
+    encoded KEYFILE. */
+@@ -2029,11 +2182,16 @@ run_dsa_sign (const void *data, size_t d
+ {
+   gpg_error_t err;
+   gcry_sexp_t s_data, s_key, s_sig, s_tmp, s_tmp2;
+-  char hash[20];
++  char hash[128];
+   gcry_mpi_t tmpmpi;
++  int algo;
++
++  s_key = read_sexp_from_file (keyfile);
++  algo = dsa_hash_from_key(s_key);
+ 
+-  gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen);
+-  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL);
++  gcry_md_hash_buffer (algo, hash, data, datalen);
++  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
++                       gcry_md_get_algo_dlen(algo), NULL);
+   if (!err)
+     {
+       err = gcry_sexp_build (&s_data, NULL,
+@@ -2044,8 +2202,6 @@ run_dsa_sign (const void *data, size_t d
+     die ("gcry_sexp_build failed for DSA data input: %s\n",
+          gpg_strerror (err));
+ 
+-  s_key = read_sexp_from_file (keyfile);
+-
+   err = gcry_pk_sign (&s_sig, s_data, s_key);
+   if (err)
+     {
+@@ -2121,13 +2277,18 @@ run_dsa_verify (const void *data, size_t
+ {
+   gpg_error_t err;
+   gcry_sexp_t s_data, s_key, s_sig;
+-  char hash[20];
++  char hash[128];
+   gcry_mpi_t tmpmpi;
++  int algo;
+ 
+-  gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen);
++  s_key = read_sexp_from_file (keyfile);
++  algo = dsa_hash_from_key(s_key);
++
++  gcry_md_hash_buffer (algo, hash, data, datalen);
+   /* Note that we can't simply use %b with HASH to build the
+      S-expression, because that might yield a negative value.  */
+-  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL);
++  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
++                       gcry_md_get_algo_dlen(algo), NULL);
+   if (!err)
+     {
+       err = gcry_sexp_build (&s_data, NULL,
+@@ -2138,7 +2299,6 @@ run_dsa_verify (const void *data, size_t
+     die ("gcry_sexp_build failed for DSA data input: %s\n",
+          gpg_strerror (err));
+ 
+-  s_key = read_sexp_from_file (keyfile);
+   s_sig = read_sexp_from_file (sigfile);
+ 
+   err = gcry_pk_verify (s_sig, s_data, s_key);
+@@ -2304,7 +2464,7 @@ usage (int show_help)
+      "MODE:\n"
+      "  encrypt, decrypt, digest, random, hmac-sha,\n"
+      "  rsa-{derive,gen,sign,verify},\n"
+-     "  dsa-{pqg-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n"
++     "  dsa-{pq-gen,g-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n"
+      "OPTIONS:\n"
+      "  --verbose        Print additional information\n"
+      "  --binary         Input and output is in binary form\n"
+@@ -2315,6 +2475,7 @@ usage (int show_help)
+      "  --algo NAME      Use algorithm NAME\n"
+      "  --curve NAME     Select ECC curve spec NAME\n"
+      "  --keysize N      Use a keysize of N bits\n"
++     "  --qize N         Use a DSA q parameter size of N bits\n"
+      "  --signature NAME Take signature from file NAME\n"
+      "  --chunk N        Read in chunks of N bytes (implies --binary)\n"
+      "  --pkcs1          Use PKCS#1 encoding\n"
+@@ -2344,6 +2505,7 @@ main (int argc, char **argv)
+   const char *dt_string = NULL;
+   const char *algo_string = NULL;
+   const char *keysize_string = NULL;
++  const char *qsize_string = NULL;
+   const char *signature_string = NULL;
+   FILE *input;
+   void *data;
+@@ -2437,6 +2599,14 @@ main (int argc, char **argv)
+           keysize_string = *argv;
+           argc--; argv++;
+         }
++      else if (!strcmp (*argv, "--qsize"))
++        {
++          argc--; argv++;
++          if (!argc)
++            usage (0);
++          qsize_string = *argv;
++          argc--; argv++;
++        }
+       else if (!strcmp (*argv, "--signature"))
+         {
+           argc--; argv++;
+@@ -2792,23 +2962,49 @@ main (int argc, char **argv)
+     }
+   else if (!strcmp (mode_string, "dsa-pqg-gen"))
+     {
+-      int keysize;
++      int keysize, qsize;
++
++      keysize = keysize_string? atoi (keysize_string) : 0;
++      if (keysize < 1024 || keysize > 3072)
++        die ("invalid keysize specified; needs to be 1024 .. 3072\n");
++      qsize = qsize_string? atoi (qsize_string) : 0;
++      if (qsize < 160 || qsize > 256)
++        die ("invalid qsize specified; needs to be 160 .. 256\n");
++      run_dsa_pqg_gen (keysize, qsize, datalen? data:NULL, datalen);
++    }
++  else if (!strcmp (mode_string, "dsa-g-gen"))
++    {
++      int keysize, qsize;
+ 
+       keysize = keysize_string? atoi (keysize_string) : 0;
+       if (keysize < 1024 || keysize > 3072)
+         die ("invalid keysize specified; needs to be 1024 .. 3072\n");
+-      run_dsa_pqg_gen (keysize, datalen? data:NULL, datalen);
++      qsize = qsize_string? atoi (qsize_string) : 0;
++      if (qsize < 160 || qsize > 256)
++        die ("invalid qsize specified; needs to be 160 .. 256\n");
++      if (!key_string)
++        die ("option --key containing pq domain parameters is required in this mode\n");
++      run_dsa_g_gen (keysize, qsize, key_string);
++    }
++  else if (!strcmp (mode_string, "dsa-gen-key"))
++    {
++      if (!key_string)
++        die ("option --key containing pqg domain parameters is required in this mode\n");
++      run_dsa_gen_key (key_string);
+     }
+   else if (!strcmp (mode_string, "dsa-gen"))
+     {
+-      int keysize;
++      int keysize, qsize;
+ 
+       keysize = keysize_string? atoi (keysize_string) : 0;
+       if (keysize < 1024 || keysize > 3072)
+         die ("invalid keysize specified; needs to be 1024 .. 3072\n");
++      qsize = qsize_string? atoi (qsize_string) : 0;
++      if (qsize < 160 || qsize > 256)
++        die ("invalid qsize specified; needs to be 160 .. 256\n");
+       if (!key_string)
+         die ("option --key is required in this mode\n");
+-      run_dsa_gen (keysize, key_string);
++      run_dsa_gen (keysize, qsize, key_string);
+     }
+   else if (!strcmp (mode_string, "dsa-sign"))
+     {
diff --git a/SOURCES/libgcrypt-1.7.3-fips-reqs.patch b/SOURCES/libgcrypt-1.7.3-fips-reqs.patch
new file mode 100644
index 0000000..ef7f765
--- /dev/null
+++ b/SOURCES/libgcrypt-1.7.3-fips-reqs.patch
@@ -0,0 +1,35 @@
+diff -up libgcrypt-1.7.3/src/visibility.c.fips-reqs libgcrypt-1.7.3/src/visibility.c
+--- libgcrypt-1.7.3/src/visibility.c.fips-reqs	2016-03-23 12:59:34.000000000 +0100
++++ libgcrypt-1.7.3/src/visibility.c	2016-11-22 16:29:36.992042480 +0100
+@@ -1288,6 +1288,8 @@ gcry_kdf_derive (const void *passphrase,
+                  unsigned long iterations,
+                  size_t keysize, void *keybuffer)
+ {
++  if (!fips_is_operational ())
++    return gpg_error (fips_not_operational ());
+   return gpg_error (_gcry_kdf_derive (passphrase, passphraselen, algo, hashalgo,
+                                       salt, saltlen, iterations,
+                                       keysize, keybuffer));
+@@ -1343,6 +1345,13 @@ void
+ gcry_mpi_randomize (gcry_mpi_t w,
+                     unsigned int nbits, enum gcry_random_level level)
+ {
++  if (!fips_is_operational ())
++    {
++      (void)fips_not_operational ();
++      fips_signal_fatal_error ("called in non-operational state");
++      fips_noreturn ();
++    }
++
+   _gcry_mpi_randomize (w, nbits, level);
+ }
+ 
+@@ -1368,6 +1377,8 @@ gcry_prime_generate (gcry_mpi_t *prime,
+                      gcry_random_level_t random_level,
+                      unsigned int flags)
+ {
++  if (!fips_is_operational ())
++    return gpg_error (fips_not_operational ());
+   return gpg_error (_gcry_prime_generate (prime, prime_bits, factor_bits,
+                                           factors, cb_func, cb_arg,
+                                           random_level, flags));
diff --git a/SOURCES/libgcrypt-1.8.3-cmac-selftest.patch b/SOURCES/libgcrypt-1.8.3-cmac-selftest.patch
new file mode 100644
index 0000000..d480092
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.3-cmac-selftest.patch
@@ -0,0 +1,322 @@
+diff -up libgcrypt-1.8.3/cipher/cipher-cmac.c.cmac-selftest libgcrypt-1.8.3/cipher/cipher-cmac.c
+--- libgcrypt-1.8.3/cipher/cipher-cmac.c.cmac-selftest	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.3/cipher/cipher-cmac.c	2019-05-31 17:33:35.594407152 +0200
+@@ -251,3 +251,246 @@ _gcry_cipher_cmac_set_subkeys (gcry_ciph
+ 
+   return GPG_ERR_NO_ERROR;
+ }
++
++/* CMAC selftests.
++ * Copyright (C) 2008 Free Software Foundation, Inc.
++ * Copyright (C) 2019 Red Hat, Inc.
++ */
++
++
++
++/* Check one MAC with MAC ALGO using the regular MAC
++ * API. (DATA,DATALEN) is the data to be MACed, (KEY,KEYLEN) the key
++ * and (EXPECT,EXPECTLEN) the expected result.  If TRUNC is set, the
++ * EXPECTLEN may be less than the digest length.  Returns NULL on
++ * success or a string describing the failure.  */
++static const char *
++check_one (int algo,
++           const void *data, size_t datalen,
++           const void *key, size_t keylen,
++           const void *expect, size_t expectlen)
++{
++  gcry_mac_hd_t hd;
++  unsigned char mac[512]; /* hardcoded to avoid allocation */
++  size_t macoutlen = expectlen;
++
++/*   printf ("MAC algo %d\n", algo); */
++  if (_gcry_mac_get_algo_maclen (algo) != expectlen ||
++      expectlen > sizeof (mac))
++    return "invalid tests data";
++  if (_gcry_mac_open (&hd, algo, 0, NULL))
++    return "gcry_mac_open failed";
++  if (_gcry_mac_setkey (hd, key, keylen))
++    {
++      _gcry_mac_close (hd);
++      return "gcry_md_setkey failed";
++    }
++  if (_gcry_mac_write (hd, data, datalen))
++    {
++      _gcry_mac_close (hd);
++      return "gcry_mac_write failed";
++    }
++  if (_gcry_mac_read (hd, mac, &macoutlen))
++    {
++      _gcry_mac_close (hd);
++      return "gcry_mac_read failed";
++    }
++  _gcry_mac_close (hd);
++  if (macoutlen != expectlen || memcmp (mac, expect, expectlen))
++    {
++/*       int i; */
++
++/*       fputs ("        {", stdout); */
++/*       for (i=0; i < expectlen-1; i++) */
++/*         { */
++/*           if (i && !(i % 8)) */
++/*             fputs ("\n         ", stdout); */
++/*           printf (" 0x%02x,", mac[i]); */
++/*         } */
++/*       printf (" 0x%02x } },\n", mac[i]); */
++
++      return "does not match";
++    }
++  return NULL;
++}
++
++
++static gpg_err_code_t
++selftests_cmac_tdes (int extended, selftest_report_func_t report)
++{
++  const char *what;
++  const char *errtxt;
++
++  what = "Basic TDES";
++  errtxt = check_one (GCRY_MAC_CMAC_3DES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++        "\xae\x2d\x8a\x57", 20,
++        "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
++        "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24,
++        "\x74\x3d\xdb\xe0\xce\x2d\xc2\xed", 8);
++  if (errtxt)
++    goto failed;
++
++  if (extended)
++    {
++      what = "Extended TDES #1";
++      errtxt = check_one (GCRY_MAC_CMAC_3DES,
++        "", 0,
++        "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
++        "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24,
++        "\xb7\xa6\x88\xe1\x22\xff\xaf\x95", 8);
++      if (errtxt)
++        goto failed;
++
++      what = "Extended TDES #2";
++      errtxt = check_one (GCRY_MAC_CMAC_3DES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96", 8,
++        "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
++        "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24,
++        "\x8e\x8f\x29\x31\x36\x28\x37\x97", 8);
++      if (errtxt)
++        goto failed;
++
++      what = "Extended TDES #3";
++      errtxt = check_one (GCRY_MAC_CMAC_3DES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++        "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51", 32,
++        "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58"
++        "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24,
++        "\x33\xe6\xb1\x09\x24\x00\xea\xe5", 8);
++      if (errtxt)
++        goto failed;
++    }
++
++  return 0; /* Succeeded. */
++
++ failed:
++  if (report)
++    report ("cmac", GCRY_MAC_CMAC_3DES, what, errtxt);
++  return GPG_ERR_SELFTEST_FAILED;
++}
++
++
++
++static gpg_err_code_t
++selftests_cmac_aes (int extended, selftest_report_func_t report)
++{
++  const char *what;
++  const char *errtxt;
++
++  what = "Basic AES128";
++  errtxt = check_one (GCRY_MAC_CMAC_AES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++        "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
++        "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40,
++        "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16,
++        "\xdf\xa6\x67\x47\xde\x9a\xe6\x30\x30\xca\x32\x61\x14\x97\xc8\x27", 16);
++  if (errtxt)
++    goto failed;
++
++  what = "Basic AES192";
++  errtxt = check_one (GCRY_MAC_CMAC_AES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++        "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
++        "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40,
++        "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
++        "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", 24,
++        "\x8a\x1d\xe5\xbe\x2e\xb3\x1a\xad\x08\x9a\x82\xe6\xee\x90\x8b\x0e", 16);
++  if (errtxt)
++    goto failed;
++
++  what = "Basic AES256";
++  errtxt = check_one (GCRY_MAC_CMAC_AES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++        "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
++        "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40,
++        "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
++        "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32,
++        "\xaa\xf3\xd8\xf1\xde\x56\x40\xc2\x32\xf5\xb1\x69\xb9\xc9\x11\xe6", 16);
++  if (errtxt)
++    goto failed;
++  if (extended)
++    {
++      what = "Extended AES #1";
++      errtxt = check_one (GCRY_MAC_CMAC_AES,
++        "", 0,
++        "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16,
++        "\xbb\x1d\x69\x29\xe9\x59\x37\x28\x7f\xa3\x7d\x12\x9b\x75\x67\x46", 16);
++      if (errtxt)
++        goto failed;
++
++      what = "Extended AES #2";
++      errtxt = check_one (GCRY_MAC_CMAC_AES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a", 16,
++        "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5"
++        "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", 24,
++        "\x9e\x99\xa7\xbf\x31\xe7\x10\x90\x06\x62\xf6\x5e\x61\x7c\x51\x84", 16);
++      if (errtxt)
++        goto failed;
++
++      what = "Extended AES #3";
++      errtxt = check_one (GCRY_MAC_CMAC_AES,
++        "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++        "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
++        "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
++        "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", 64,
++        "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
++        "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32,
++        "\xe1\x99\x21\x90\x54\x9f\x6e\xd5\x69\x6a\x2c\x05\x6c\x31\x54\x10", 16 );
++      if (errtxt)
++        goto failed;
++    }
++
++  return 0; /* Succeeded. */
++
++ failed:
++  if (report)
++    report ("cmac", GCRY_MAC_CMAC_AES, what, errtxt);
++  return GPG_ERR_SELFTEST_FAILED;
++}
++
++
++/* Run a full self-test for ALGO and return 0 on success.  */
++static gpg_err_code_t
++run_cmac_selftests (int algo, int extended, selftest_report_func_t report)
++{
++  gpg_err_code_t ec;
++
++  switch (algo)
++    {
++    case GCRY_MAC_CMAC_3DES:
++      ec = selftests_cmac_tdes (extended, report);
++      break;
++    case GCRY_MAC_CMAC_AES:
++      ec = selftests_cmac_aes (extended, report);
++      break;
++
++    default:
++      ec = GPG_ERR_MAC_ALGO;
++      break;
++    }
++  return ec;
++}
++
++
++
++
++/* Run the selftests for CMAC with CMAC algorithm ALGO with optional
++   reporting function REPORT.  */
++gpg_error_t
++_gcry_cmac_selftest (int algo, int extended, selftest_report_func_t report)
++{
++  gcry_err_code_t ec = 0;
++
++  if (!_gcry_mac_algo_info( algo, GCRYCTL_TEST_ALGO, NULL, NULL ))
++    {
++      ec = run_cmac_selftests (algo, extended, report);
++    }
++  else
++    {
++      ec = GPG_ERR_MAC_ALGO;
++      if (report)
++        report ("mac", algo, "module", "algorithm not available");
++    }
++  return gpg_error (ec);
++}
+diff -up libgcrypt-1.8.3/src/cipher-proto.h.cmac-selftest libgcrypt-1.8.3/src/cipher-proto.h
+--- libgcrypt-1.8.3/src/cipher-proto.h.cmac-selftest	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.3/src/cipher-proto.h	2019-05-31 17:29:34.574588234 +0200
+@@ -256,6 +256,8 @@ gcry_error_t _gcry_pk_selftest (int algo
+                                 selftest_report_func_t report);
+ gcry_error_t _gcry_hmac_selftest (int algo, int extended,
+                                   selftest_report_func_t report);
++gcry_error_t _gcry_cmac_selftest (int algo, int extended,
++                                  selftest_report_func_t report);
+ 
+ gcry_error_t _gcry_random_selftest (selftest_report_func_t report);
+ 
+diff -up libgcrypt-1.8.3/src/fips.c.cmac-selftest libgcrypt-1.8.3/src/fips.c
+--- libgcrypt-1.8.3/src/fips.c.cmac-selftest	2018-11-01 15:40:36.051865535 +0100
++++ libgcrypt-1.8.3/src/fips.c	2019-05-31 17:31:20.157756640 +0200
+@@ -521,29 +521,32 @@ run_digest_selftests (int extended)
+ 
+ /* Run self-tests for all HMAC algorithms.  Return 0 on success. */
+ static int
+-run_hmac_selftests (int extended)
++run_mac_selftests (int extended)
+ {
+-  static int algos[] =
++  static int algos[][2] =
+     {
+-      GCRY_MD_SHA1,
+-      GCRY_MD_SHA224,
+-      GCRY_MD_SHA256,
+-      GCRY_MD_SHA384,
+-      GCRY_MD_SHA512,
+-      GCRY_MD_SHA3_224,
+-      GCRY_MD_SHA3_256,
+-      GCRY_MD_SHA3_384,
+-      GCRY_MD_SHA3_512,
+-      0
++      { GCRY_MD_SHA1, 0 },
++      { GCRY_MD_SHA224, 0 },
++      { GCRY_MD_SHA256, 0 },
++      { GCRY_MD_SHA384, 0 },
++      { GCRY_MD_SHA512, 0 },
++      { GCRY_MD_SHA3_224, 0 },
++      { GCRY_MD_SHA3_256, 0 },
++      { GCRY_MD_SHA3_384, 0 },
++      { GCRY_MD_SHA3_512, 0 },
++      { GCRY_MAC_CMAC_3DES, 1 },
++      { GCRY_MAC_CMAC_AES, 1 },
++      { 0, 0 }
+     };
+   int idx;
+   gpg_error_t err;
+   int anyerr = 0;
+ 
+-  for (idx=0; algos[idx]; idx++)
++  for (idx=0; algos[idx][0]; idx++)
+     {
+-      err = _gcry_hmac_selftest (algos[idx], extended, reporter);
+-      reporter ("hmac", algos[idx], NULL,
++      err = algos[idx][1] ? _gcry_cmac_selftest (algos[idx][0], extended, reporter) :
++        _gcry_hmac_selftest (algos[idx][0], extended, reporter);
++      reporter (algos[idx][1] ? "cmac" : "hmac", algos[idx][0], NULL,
+                 err? gpg_strerror (err):NULL);
+       if (err)
+         anyerr = 1;
+@@ -747,7 +750,7 @@ _gcry_fips_run_selftests (int extended)
+   if (run_digest_selftests (extended))
+     goto leave;
+ 
+-  if (run_hmac_selftests (extended))
++  if (run_mac_selftests (extended))
+     goto leave;
+ 
+   /* Run random tests before the pubkey tests because the latter
diff --git a/SOURCES/libgcrypt-1.8.3-fips-ctor.patch b/SOURCES/libgcrypt-1.8.3-fips-ctor.patch
new file mode 100644
index 0000000..66abd59
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.3-fips-ctor.patch
@@ -0,0 +1,60 @@
+diff -up libgcrypt-1.8.3/src/global.c.fips-ctor libgcrypt-1.8.3/src/global.c
+--- libgcrypt-1.8.3/src/global.c.fips-ctor	2017-11-23 19:25:58.000000000 +0100
++++ libgcrypt-1.8.3/src/global.c	2020-04-17 16:29:59.258218015 +0200
+@@ -141,6 +141,34 @@ global_init (void)
+ }
+ 
+ 
++#ifndef FIPS_MODULE_PATH
++#define FIPS_MODULE_PATH "/etc/system-fips"
++#endif
++
++void __attribute__ ((constructor)) _gcry_global_constructor (void)
++{
++  int rv;
++
++  rv = access (FIPS_MODULE_PATH, F_OK);
++  if (rv < 0 && errno != ENOENT)
++    rv = 0;
++
++  if (!rv)
++    {
++      int no_secmem_save;
++
++      /* it should be always 0 at this point but let's keep on the safe side */
++      no_secmem_save = no_secure_memory;
++      no_secure_memory = 1;
++      /* force selftests */
++      global_init();
++      _gcry_fips_run_selftests (0);
++      if (!fips_mode())
++         _gcry_random_close_fds ();
++      no_secure_memory = no_secmem_save;
++    }
++}
++
+ /* This function is called by the macro fips_is_operational and makes
+    sure that the minimal initialization has been done.  This is far
+    from a perfect solution and hides problems with an improper
+@@ -671,8 +699,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
+ 
+     case GCRYCTL_FIPS_MODE_P:
+       if (fips_mode ()
+-          && !_gcry_is_fips_mode_inactive ()
+-          && !no_secure_memory)
++          && !_gcry_is_fips_mode_inactive ())
+ 	rc = GPG_ERR_GENERAL; /* Used as TRUE value */
+       break;
+ 
+@@ -749,9 +776,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
+       break;
+ 
+     case GCRYCTL_SET_ENFORCED_FIPS_FLAG:
+-      if (!any_init_done)
++      if (fips_mode ())
+         {
+-          /* Not yet initialized at all.  Set the enforced fips mode flag */
++          /* We are in FIPS mode, we can set the enforced fips mode flag. */
+           _gcry_set_preferred_rng_type (0);
+           _gcry_set_enforced_fips_mode ();
+         }
diff --git a/SOURCES/libgcrypt-1.8.3-fips-enttest.patch b/SOURCES/libgcrypt-1.8.3-fips-enttest.patch
new file mode 100644
index 0000000..b6b09ba
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.3-fips-enttest.patch
@@ -0,0 +1,113 @@
+diff -up libgcrypt-1.8.3/random/random-drbg.c.fips-enttest libgcrypt-1.8.3/random/random-drbg.c
+--- libgcrypt-1.8.3/random/random-drbg.c.fips-enttest	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.3/random/random-drbg.c	2019-06-24 10:04:23.219547141 +0200
+@@ -317,6 +317,7 @@ struct drbg_state_s
+   unsigned char *ctr_null;	/* CTR mode zero buffer */
+   int seeded:1;			/* DRBG fully seeded? */
+   int pr:1;			/* Prediction resistance enabled? */
++  int ent_primed:1;             /* Previous entropy data primed? */
+   /* Taken from libgcrypt ANSI X9.31 DRNG: We need to keep track of the
+    * process which did the initialization so that we can detect a fork.
+    * The volatile modifier is required so that the compiler does not
+@@ -324,6 +325,7 @@ struct drbg_state_s
+   pid_t seed_init_pid;
+   const struct drbg_state_ops_s *d_ops;
+   const struct drbg_core_s *core;
++  unsigned char ent_hash[64];	/* Hash of previous entropy data */
+   struct drbg_test_data_s *test_data;
+ };
+ 
+@@ -610,11 +612,13 @@ drbg_get_entropy (drbg_state_t drbg, uns
+ 		       size_t len)
+ {
+   int rc = 0;
++  unsigned char newhash[64];
+ 
+   /* Perform testing as defined in 11.3.2 */
+   if (drbg->test_data && drbg->test_data->fail_seed_source)
+     return -1;
+ 
++redo:
+   read_cb_buffer = buffer;
+   read_cb_size = len;
+   read_cb_len = 0;
+@@ -634,6 +638,27 @@ drbg_get_entropy (drbg_state_t drbg, uns
+ #else
+   rc = -1;
+ #endif
++
++  /* to avoid storing the actual entropy obtained for indefinite
++     time, we just store the SHA-512 hash of the entropy gathered
++   */
++  _gcry_md_hash_buffer (GCRY_MD_SHA512, newhash, buffer, len);
++
++  if (!drbg->ent_primed)
++    {
++      memcpy (drbg->ent_hash, newhash, sizeof (drbg->ent_hash));
++      drbg->ent_primed = 1;
++      goto redo;
++    }
++
++  if (memcmp (newhash, drbg->ent_hash, sizeof (drbg->ent_hash)) == 0)
++    {
++      fips_signal_error ("Entropy source failed the continuous test");
++      return -1;  /* continuous entropy test failed */
++    }
++
++  memcpy (drbg->ent_hash, newhash, sizeof (drbg->ent_hash));
++
+   return rc;
+ }
+ 
+@@ -1341,26 +1366,38 @@ drbg_seed (drbg_state_t drbg, drbg_strin
+     }
+   else
+     {
++      int nonce = 0;
+       /* Gather entropy equal to the security strength of the DRBG.
+        * With a derivation function, a nonce is required in addition
+        * to the entropy. A nonce must be at least 1/2 of the security
+        * strength of the DRBG in size. Thus, entropy * nonce is 3/2
+        * of the strength. The consideration of a nonce is only
+-       * applicable during initial seeding. */
++       * applicable during initial seeding.
++       * To avoid pulling different length of data from entropy
++       * source, we use 2 * strength for initial seeding. */
+       entropylen = drbg_sec_strength (drbg->core->flags);
+       if (!entropylen)
+ 	return GPG_ERR_GENERAL;
+       if (0 == reseed)
+-	/* make sure we round up strength/2 in
+-	 * case it is not divisible by 2 */
+-	entropylen = ((entropylen + 1) / 2) * 3;
++        {
++	  nonce = 1;
++        }
+       dbg (("DRBG: (re)seeding with %lu bytes of entropy\n", entropylen));
+-      entropy = xcalloc_secure (1, entropylen);
++      entropy = xcalloc_secure (nonce + 1, entropylen);
+       if (!entropy)
+ 	return GPG_ERR_ENOMEM;
+       ret = drbg_get_entropy (drbg, entropy, entropylen);
+       if (ret)
+ 	goto out;
++      if (nonce)
++        {
++          ret = drbg_get_entropy (drbg, entropy + entropylen, entropylen);
++          if (ret)
++	    goto out;
++	  /* make sure we round up strength/2 in
++	   * case it is not divisible by 2 */
++ 	  entropylen = 2 * entropylen;
++        }
+       drbg_string_fill (&data1, entropy, entropylen);
+     }
+ 
+@@ -1597,6 +1634,7 @@ drbg_instantiate (drbg_state_t drbg,
+   drbg->core = &drbg_cores[coreref];
+   drbg->pr = pr;
+   drbg->seeded = 0;
++  drbg->ent_primed = 0;
+   if (drbg->core->flags & DRBG_HMAC)
+     drbg->d_ops = &drbg_hmac_ops;
+   else if (drbg->core->flags & DRBG_HASH_MASK)
diff --git a/SOURCES/libgcrypt-1.8.3-md-fips-enforce.patch b/SOURCES/libgcrypt-1.8.3-md-fips-enforce.patch
new file mode 100644
index 0000000..eed7fa5
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.3-md-fips-enforce.patch
@@ -0,0 +1,18 @@
+diff -up libgcrypt-1.8.3/cipher/md.c.fips-enforce libgcrypt-1.8.3/cipher/md.c
+--- libgcrypt-1.8.3/cipher/md.c.fips-enforce	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.3/cipher/md.c	2020-04-17 15:07:31.364945130 +0200
+@@ -409,13 +409,10 @@ md_enable (gcry_md_hd_t hd, int algorith
+     }
+ 
+ 
+-  if (!err && algorithm == GCRY_MD_MD5 && fips_mode ())
++  if (!err && !spec->flags.fips && fips_mode ())
+     {
+-      _gcry_inactivate_fips_mode ("MD5 used");
+       if (_gcry_enforced_fips_mode () )
+         {
+-          /* We should never get to here because we do not register
+-             MD5 in enforced fips mode. But better throw an error.  */
+           err = GPG_ERR_DIGEST_ALGO;
+         }
+     }
diff --git a/SOURCES/libgcrypt-1.8.4-fips-keygen.patch b/SOURCES/libgcrypt-1.8.4-fips-keygen.patch
new file mode 100644
index 0000000..9d3a647
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.4-fips-keygen.patch
@@ -0,0 +1,65 @@
+diff -up libgcrypt-1.8.4/cipher/dsa.c.fips-keygen libgcrypt-1.8.4/cipher/dsa.c
+--- libgcrypt-1.8.4/cipher/dsa.c.fips-keygen	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.4/cipher/dsa.c	2019-02-12 14:29:25.629513989 +0100
+@@ -457,11 +457,22 @@ generate_fips186 (DSA_secret_key *sk, un
+                                              &prime_q, &prime_p,
+                                              r_counter,
+                                              r_seed, r_seedlen);
+-      else
+-        ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0,
++      else if (!domain->p || !domain->q)
++        ec = _gcry_generate_fips186_3_prime (nbits, qbits,
++                                             initial_seed.seed,
++                                             initial_seed.seedlen,
+                                              &prime_q, &prime_p,
+                                              r_counter,
+                                              r_seed, r_seedlen, NULL);
++      else
++        {
++          /* Domain parameters p and q are given; use them.  */
++          prime_p = mpi_copy (domain->p);
++          prime_q = mpi_copy (domain->q);
++          gcry_assert (mpi_get_nbits (prime_p) == nbits);
++          gcry_assert (mpi_get_nbits (prime_q) == qbits);
++          ec = 0;
++        }
+       sexp_release (initial_seed.sexp);
+       if (ec)
+         goto leave;
+@@ -855,13 +866,12 @@ dsa_generate (const gcry_sexp_t genparms
+       sexp_release (l1);
+       sexp_release (domainsexp);
+ 
+-      /* Check that all domain parameters are available.  */
+-      if (!domain.p || !domain.q || !domain.g)
++      /* Check that p and q domain parameters are available.  */
++      if (!domain.p || !domain.q || (!domain.g && !(flags & PUBKEY_FLAG_USE_FIPS186)))
+         {
+           _gcry_mpi_release (domain.p);
+           _gcry_mpi_release (domain.q);
+           _gcry_mpi_release (domain.g);
+-          sexp_release (deriveparms);
+           return GPG_ERR_MISSING_VALUE;
+         }
+ 
+diff -up libgcrypt-1.8.4/cipher/rsa.c.fips-keygen libgcrypt-1.8.4/cipher/rsa.c
+--- libgcrypt-1.8.4/cipher/rsa.c.fips-keygen	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.4/cipher/rsa.c	2019-02-12 14:29:25.630513971 +0100
+@@ -389,7 +389,7 @@ generate_fips (RSA_secret_key *sk, unsig
+ 
+   if (nbits < 1024 || (nbits & 0x1FF))
+     return GPG_ERR_INV_VALUE;
+-  if (_gcry_enforced_fips_mode() && nbits != 2048 && nbits != 3072)
++  if (fips_mode() && nbits < 2048)
+       return GPG_ERR_INV_VALUE;
+ 
+   /* The random quality depends on the transient_key flag.  */
+@@ -696,7 +696,7 @@ generate_x931 (RSA_secret_key *sk, unsig
+ 
+   *swapped = 0;
+ 
+-  if (e_value == 1)   /* Alias for a secure value. */
++  if (e_value == 1 || e_value == 0)   /* Alias for a secure value. */
+     e_value = 65537;
+ 
+   /* Point 1 of section 4.1:  k = 1024 + 256s with S >= 0  */
diff --git a/SOURCES/libgcrypt-1.8.4-tests-fipsmode.patch b/SOURCES/libgcrypt-1.8.4-tests-fipsmode.patch
new file mode 100644
index 0000000..1442a0b
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.4-tests-fipsmode.patch
@@ -0,0 +1,184 @@
+diff -up libgcrypt-1.8.4/tests/basic.c.tests-fipsmode libgcrypt-1.8.4/tests/basic.c
+--- libgcrypt-1.8.4/tests/basic.c.tests-fipsmode	2018-04-17 17:29:40.000000000 +0200
++++ libgcrypt-1.8.4/tests/basic.c	2019-02-12 13:30:48.935791024 +0100
+@@ -6964,7 +6964,7 @@ check_ciphers (void)
+       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CTR, 0);
+       if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_CCM_BLOCK_LEN)
+         check_one_cipher (algos[i], GCRY_CIPHER_MODE_CCM, 0);
+-      if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_GCM_BLOCK_LEN)
++      if (!in_fips_mode && gcry_cipher_get_algo_blklen (algos[i]) == GCRY_GCM_BLOCK_LEN)
+         check_one_cipher (algos[i], GCRY_CIPHER_MODE_GCM, 0);
+       if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_OCB_BLOCK_LEN)
+         check_one_cipher (algos[i], GCRY_CIPHER_MODE_OCB, 0);
+@@ -7010,11 +7010,17 @@ check_cipher_modes(void)
+   check_cfb_cipher ();
+   check_ofb_cipher ();
+   check_ccm_cipher ();
+-  check_gcm_cipher ();
+-  check_poly1305_cipher ();
+-  check_ocb_cipher ();
++  if (!in_fips_mode)
++    {
++      check_gcm_cipher ();
++      check_poly1305_cipher ();
++      check_ocb_cipher ();
++    }
+   check_xts_cipher ();
+-  check_gost28147_cipher ();
++  if (!in_fips_mode)
++    {
++      check_gost28147_cipher ();
++    }
+   check_stream_cipher ();
+   check_stream_cipher_large_block ();
+ 
+@@ -10001,7 +10007,7 @@ check_mac (void)
+           show_mac_not_available (algos[i].algo);
+           continue;
+         }
+-      if (gcry_mac_test_algo (algos[i].algo) && in_fips_mode)
++      if ((algos[i].algo == GCRY_MAC_GMAC_AES || gcry_mac_test_algo (algos[i].algo)) && in_fips_mode)
+         {
+           if (verbose)
+             fprintf (stderr, "  algorithm %d not available in fips mode\n",
+@@ -11095,8 +11101,6 @@ main (int argc, char **argv)
+       /* If we are in fips mode do some more tests. */
+       gcry_md_hd_t md;
+ 
+-      /* First trigger a self-test.  */
+-      xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+       if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0))
+         fail ("not in operational state after self-test\n");
+ 
+@@ -11121,15 +11125,6 @@ main (int argc, char **argv)
+               gcry_md_close (md);
+               if (gcry_control (GCRYCTL_OPERATIONAL_P, 0))
+                 fail ("expected error state but still in operational state\n");
+-              else
+-                {
+-                  /* Now run a self-test and to get back into
+-                     operational state.  */
+-                  xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+-                  if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0))
+-                    fail ("did not reach operational after error "
+-                          "and self-test\n");
+-                }
+             }
+         }
+ 
+diff -up libgcrypt-1.8.4/tests/benchmark.c.tests-fipsmode libgcrypt-1.8.4/tests/benchmark.c
+--- libgcrypt-1.8.4/tests/benchmark.c.tests-fipsmode	2019-02-12 11:31:44.859603883 +0100
++++ libgcrypt-1.8.4/tests/benchmark.c	2019-02-12 14:10:40.271999352 +0100
+@@ -872,8 +872,10 @@ cipher_bench ( const char *algoname )
+           || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
+         continue;
+ 
+-      if (modes[modeidx].req_blocksize > 0
+-          && blklen != modes[modeidx].req_blocksize)
++      if ((modes[modeidx].req_blocksize > 0
++           && blklen != modes[modeidx].req_blocksize)
++          || (in_fips_mode 
++           && modes[modeidx].mode == GCRY_CIPHER_MODE_GCM))
+         {
+           printf (" %7s %7s", "-", "-" );
+           continue;
+diff -up libgcrypt-1.8.4/tests/bench-slope.c.tests-fipsmode libgcrypt-1.8.4/tests/bench-slope.c
+--- libgcrypt-1.8.4/tests/bench-slope.c.tests-fipsmode	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.4/tests/bench-slope.c	2019-02-12 14:14:33.618763325 +0100
+@@ -1338,7 +1338,7 @@ cipher_bench_one (int algo, struct bench
+     return;
+ 
+   /* GCM has restrictions for block-size */
+-  if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN)
++  if (mode.mode == GCRY_CIPHER_MODE_GCM && (gcry_fips_mode_active () || blklen != GCRY_GCM_BLOCK_LEN))
+     return;
+ 
+   /* XTS has restrictions for block-size */
+diff -up libgcrypt-1.8.4/tests/pubkey.c.tests-fipsmode libgcrypt-1.8.4/tests/pubkey.c
+--- libgcrypt-1.8.4/tests/pubkey.c.tests-fipsmode	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.4/tests/pubkey.c	2019-02-12 13:52:25.658746415 +0100
+@@ -504,15 +504,30 @@ get_dsa_key_with_domain_new (gcry_sexp_t
+   rc = gcry_sexp_new
+     (&key_spec,
+      "(genkey (dsa (transient-key)(domain"
+-     "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921"
+-     "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7"
+-     "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0"
+-     "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)"
+-     "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)"
+-     "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab"
+-     "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad"
+-     "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e"
+-     "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)"
++     " (p #a85378d8fd3f8d72ec7418080da21317e43ec4b62ba8c862"
++     "     3b7e4d04441dd1a0658662596493ca8e9e8fbb7e34aaddb6"
++     "     2e5d67b6d09a6e61b769e7c352aa2b10e20ca0636963b552"
++     "     3e86470decbbeda027e797e7b67635d4d49c30700e74af8a"
++     "     0ff156a801af57a26e7078f1d82f74908ecb6d07e70b3503"
++     "     eed94fa32cf17a7fc3d6cf40dc7b00830e6a2566dc073e34"
++     "     3312517c6aa5152b4bfecd2e551fee346318a153423c996b"
++     "     0d5dcb9102aedd38798616f1f1e0d6c403525b1f9b3d4dc7"
++     "     66de2dfc4a56d7b8ba5963d60f3e16318870ad436952e557"
++     "     65374eab85e8ec17d6b9a4547b9b5f2752f3105be809b23a"
++     "     2c8d7469db02e24d592394a7dba069e9#)"
++     " (q #d277044e50f5a4e3f510a50a0b84fdffbca047ed27602056"
++     "     7441a0a5#)"
++     " (g #13d754e21fd241655da891c522a65a72a89bdc64ec9b54a8"
++     "     21ed4a898b490e0c4fcb72192a4a20f541f3f2925399f0ba"
++     "     ecf929aafbf79dfe4332393b32cd2e2fcf272f32a627434a"
++     "     0df242b75b414df372121e53a553f222f836b000f016485b"
++     "     6bd0898451801dcd8de64cd5365696ffc532d528c506620a"
++     "     942a0305046d8f1876341f1e570bc3974ba6b9a438e97023"
++     "     02a2e6e67bfd06d32bc679962271d7b40cd72f386e64e0d7"
++     "     ef86ca8ca5d14228dc2a4f16e3189886b5990674f4200f3a"
++     "     4cf65a3f0ddba1fa672dff2f5e143d10e4e97ae84f6da095"
++     "     35d5b9df259181a79b63b069e949972b02ba36b3586aab7e"
++     "     45f322f82e4e85ca3ab85591b3c2a966#)"
+      ")))", 0, 1);
+   if (rc)
+     die ("error creating S-expression: %s\n", gcry_strerror (rc));
+@@ -595,7 +610,7 @@ get_dsa_key_fips186_with_seed_new (gcry_
+      "    (use-fips186)"
+      "    (transient-key)"
+      "    (derive-parms"
+-     "      (seed #0cb1990c1fd3626055d7a0096f8fa99807399871#))))",
++     "      (seed #8b4c4d671fff82e8ed932260206d0571e3a1c2cee8cd94cb73fe58f9b67488fa#))))",
+      0, 1);
+   if (rc)
+     die ("error creating S-expression: %s\n", gcry_strerror (rc));
+diff -up libgcrypt-1.8.4/tests/t-cv25519.c.tests-fipsmode libgcrypt-1.8.4/tests/t-cv25519.c
+--- libgcrypt-1.8.4/tests/t-cv25519.c.tests-fipsmode	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.4/tests/t-cv25519.c	2019-02-12 14:02:35.935705390 +0100
+@@ -560,6 +560,9 @@ main (int argc, char **argv)
+     xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+   xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+   xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
++  /* Curve25519 isn't supported in fips mode */
++  if (gcry_fips_mode_active())
++    return 77;
+ 
+   start_timer ();
+   check_cv25519 ();
+diff -up libgcrypt-1.8.4/tests/t-secmem.c.tests-fipsmode libgcrypt-1.8.4/tests/t-secmem.c
+--- libgcrypt-1.8.4/tests/t-secmem.c.tests-fipsmode	2017-11-23 19:19:54.000000000 +0100
++++ libgcrypt-1.8.4/tests/t-secmem.c	2019-02-12 11:51:02.462190538 +0100
+@@ -174,7 +174,8 @@ main (int argc, char **argv)
+     xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+   xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+   xgcry_control (GCRYCTL_INIT_SECMEM, pool_size, 0);
+-  gcry_set_outofcore_handler (outofcore_handler, NULL);
++  if (!gcry_fips_mode_active ())
++    gcry_set_outofcore_handler (outofcore_handler, NULL);
+   xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ 
+   /* Libgcrypt prints a warning when the first overflow is allocated;
+@@ -184,7 +185,8 @@ main (int argc, char **argv)
+ 
+ 
+   test_secmem ();
+-  test_secmem_overflow ();
++  if (!gcry_fips_mode_active ())
++    test_secmem_overflow ();
+   /* FIXME: We need to improve the tests, for example by registering
+    * our own log handler and comparing the output of
+    * PRIV_CTL_DUMP_SECMEM_STATS to expected pattern.  */
diff --git a/SOURCES/libgcrypt-1.8.4-use-poll.patch b/SOURCES/libgcrypt-1.8.4-use-poll.patch
new file mode 100644
index 0000000..b96c6ce
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.4-use-poll.patch
@@ -0,0 +1,77 @@
+diff -up libgcrypt-1.8.4/random/rndlinux.c.use-poll libgcrypt-1.8.4/random/rndlinux.c
+--- libgcrypt-1.8.4/random/rndlinux.c.use-poll	2018-10-26 13:50:20.000000000 +0200
++++ libgcrypt-1.8.4/random/rndlinux.c	2018-11-20 15:51:56.760669058 +0100
+@@ -32,6 +32,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <fcntl.h>
++#include <poll.h>
+ #if defined(__linux__) && defined(HAVE_SYSCALL)
+ # include <sys/syscall.h>
+ #endif
+@@ -241,9 +242,8 @@ _gcry_rndlinux_gather_random (void (*add
+                  return with something we will actually use 100ms. */
+   while (length)
+     {
+-      fd_set rfds;
+-      struct timeval tv;
+       int rc;
++      struct pollfd pfd;
+ 
+       /* If we have a modern Linux kernel, we first try to use the new
+        * getrandom syscall.  That call guarantees that the kernel's
+@@ -300,36 +300,25 @@ _gcry_rndlinux_gather_random (void (*add
+           any_need_entropy = 1;
+         }
+ 
+-      /* If the system has no limit on the number of file descriptors
+-         and we encounter an fd which is larger than the fd_set size,
+-         we don't use the select at all.  The select code is only used
+-         to emit progress messages.  A better solution would be to
+-         fall back to poll() if available.  */
+-#ifdef FD_SETSIZE
+-      if (fd < FD_SETSIZE)
+-#endif
++      pfd.fd = fd;
++      pfd.events = POLLIN;
++
++      _gcry_pre_syscall ();
++      rc = poll(&pfd, 1, delay);
++      _gcry_post_syscall ();
++      if (!rc)
+         {
+-          FD_ZERO(&rfds);
+-          FD_SET(fd, &rfds);
+-          tv.tv_sec = delay;
+-          tv.tv_usec = delay? 0 : 100000;
+-          _gcry_pre_syscall ();
+-          rc = select (fd+1, &rfds, NULL, NULL, &tv);
+-          _gcry_post_syscall ();
+-          if (!rc)
+-            {
+-              any_need_entropy = 1;
+-              delay = 3; /* Use 3 seconds henceforth.  */
+-              continue;
+-            }
+-          else if( rc == -1 )
+-            {
+-              log_error ("select() error: %s\n", strerror(errno));
+-              if (!delay)
+-                delay = 1; /* Use 1 second if we encounter an error before
+-                              we have ever blocked.  */
+-              continue;
+-            }
++          any_need_entropy = 1;
++          delay = 3000; /* Use 3 seconds henceforth.  */
++          continue;
++        }
++        else if( rc == -1 )
++        {
++          log_error ("poll() error: %s\n", strerror(errno));
++          if (!delay)
++            delay = 1000; /* Use 1 second if we encounter an error before
++                          we have ever blocked.  */
++          continue;
+         }
+ 
+       do
diff --git a/SOURCES/libgcrypt-1.8.5-aes-perf.patch b/SOURCES/libgcrypt-1.8.5-aes-perf.patch
new file mode 100644
index 0000000..268ce70
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.5-aes-perf.patch
@@ -0,0 +1,8156 @@
+diff -up libgcrypt-1.8.5/cipher/arcfour.c.aes-perf libgcrypt-1.8.5/cipher/arcfour.c
+--- libgcrypt-1.8.5/cipher/arcfour.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/arcfour.c	2020-04-22 18:29:41.662862382 +0200
+@@ -184,10 +184,12 @@ do_arcfour_setkey (void *context, const
+ }
+ 
+ static gcry_err_code_t
+-arcfour_setkey ( void *context, const byte *key, unsigned int keylen )
++arcfour_setkey ( void *context, const byte *key, unsigned int keylen,
++                 gcry_cipher_hd_t hd )
+ {
+   ARCFOUR_context *ctx = (ARCFOUR_context *) context;
+   gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen );
++  (void)hd;
+   return rc;
+ }
+ 
+@@ -207,11 +209,11 @@ selftest(void)
+   static const byte ciphertext_1[] =
+     { 0xF1, 0x38, 0x29, 0xC9, 0xDE };
+ 
+-  arcfour_setkey( &ctx, key_1, sizeof(key_1));
++  arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL);
+   encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1));
+   if ( memcmp (scratch, ciphertext_1, sizeof (ciphertext_1)))
+     return "Arcfour encryption test 1 failed.";
+-  arcfour_setkey( &ctx, key_1, sizeof(key_1));
++  arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL);
+   encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */
+   if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1)))
+     return "Arcfour decryption test 1 failed.";
+diff -up libgcrypt-1.8.5/cipher/blowfish.c.aes-perf libgcrypt-1.8.5/cipher/blowfish.c
+--- libgcrypt-1.8.5/cipher/blowfish.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/blowfish.c	2020-04-22 18:29:41.663862363 +0200
+@@ -37,6 +37,7 @@
+ #include "g10lib.h"
+ #include "cipher.h"
+ #include "bufhelp.h"
++#include "cipher-internal.h"
+ #include "cipher-selftest.h"
+ 
+ #define BLOWFISH_BLOCKSIZE 8
+@@ -67,7 +68,8 @@ typedef struct {
+     u32 p[BLOWFISH_ROUNDS+2];
+ } BLOWFISH_context;
+ 
+-static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen);
++static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen,
++                                  gcry_cipher_hd_t hd);
+ static unsigned int encrypt_block (void *bc, byte *outbuf, const byte *inbuf);
+ static unsigned int decrypt_block (void *bc, byte *outbuf, const byte *inbuf);
+ 
+@@ -703,7 +705,7 @@ _gcry_blowfish_ctr_enc(void *context, un
+       /* Encrypt the counter. */
+       do_encrypt_block(ctx, tmpbuf, ctr);
+       /* XOR the input with the encrypted counter and store in output.  */
+-      buf_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE);
++      cipher_block_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE);
+       outbuf += BLOWFISH_BLOCKSIZE;
+       inbuf  += BLOWFISH_BLOCKSIZE;
+       /* Increment the counter.  */
+@@ -771,7 +773,7 @@ _gcry_blowfish_cbc_dec(void *context, un
+          the intermediate result to SAVEBUF.  */
+       do_decrypt_block (ctx, savebuf, inbuf);
+ 
+-      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE);
++      cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE);
+       inbuf += BLOWFISH_BLOCKSIZE;
+       outbuf += BLOWFISH_BLOCKSIZE;
+     }
+@@ -828,7 +830,7 @@ _gcry_blowfish_cfb_dec(void *context, un
+   for ( ;nblocks; nblocks-- )
+     {
+       do_encrypt_block(ctx, iv, iv);
+-      buf_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE);
++      cipher_block_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE);
+       outbuf += BLOWFISH_BLOCKSIZE;
+       inbuf  += BLOWFISH_BLOCKSIZE;
+     }
+@@ -897,7 +899,7 @@ selftest(void)
+   const char *r;
+ 
+   bf_setkey( (void *) &c,
+-             (const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26 );
++             (const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26, NULL );
+   encrypt_block( (void *) &c, buffer, plain );
+   if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) )
+     return "Blowfish selftest failed (1).";
+@@ -905,7 +907,7 @@ selftest(void)
+   if( memcmp( buffer, plain, 8 ) )
+     return "Blowfish selftest failed (2).";
+ 
+-  bf_setkey( (void *) &c, key3, 8 );
++  bf_setkey( (void *) &c, key3, 8, NULL );
+   encrypt_block( (void *) &c, buffer, plain3 );
+   if( memcmp( buffer, cipher3, 8 ) )
+     return "Blowfish selftest failed (3).";
+@@ -1095,10 +1097,12 @@ do_bf_setkey (BLOWFISH_context *c, const
+ 
+ 
+ static gcry_err_code_t
+-bf_setkey (void *context, const byte *key, unsigned keylen)
++bf_setkey (void *context, const byte *key, unsigned keylen,
++           gcry_cipher_hd_t hd)
+ {
+   BLOWFISH_context *c = (BLOWFISH_context *) context;
+   gcry_err_code_t rc = do_bf_setkey (c, key, keylen);
++  (void)hd;
+   return rc;
+ }
+ 
+diff -up libgcrypt-1.8.5/cipher/bufhelp.h.aes-perf libgcrypt-1.8.5/cipher/bufhelp.h
+--- libgcrypt-1.8.5/cipher/bufhelp.h.aes-perf	2018-04-17 17:35:28.000000000 +0200
++++ libgcrypt-1.8.5/cipher/bufhelp.h	2020-04-22 18:29:41.663862363 +0200
+@@ -450,7 +450,21 @@ static inline void buf_put_le64(void *_b
+   out->a = le_bswap64(val);
+ }
+ 
+-
+ #endif /*BUFHELP_UNALIGNED_ACCESS*/
+ 
++
++/* Host-endian get/put macros */
++#ifdef WORDS_BIGENDIAN
++# define buf_get_he32 buf_get_be32
++# define buf_put_he32 buf_put_be32
++# define buf_get_he64 buf_get_be64
++# define buf_put_he64 buf_put_be64
++#else
++# define buf_get_he32 buf_get_le32
++# define buf_put_he32 buf_put_le32
++# define buf_get_he64 buf_get_le64
++# define buf_put_he64 buf_put_le64
++#endif
++
++
+ #endif /*GCRYPT_BUFHELP_H*/
+diff -up libgcrypt-1.8.5/cipher/camellia-glue.c.aes-perf libgcrypt-1.8.5/cipher/camellia-glue.c
+--- libgcrypt-1.8.5/cipher/camellia-glue.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/camellia-glue.c	2020-04-22 18:29:41.664862344 +0200
+@@ -204,7 +204,8 @@ extern void _gcry_camellia_aesni_avx2_oc
+ static const char *selftest(void);
+ 
+ static gcry_err_code_t
+-camellia_setkey(void *c, const byte *key, unsigned keylen)
++camellia_setkey(void *c, const byte *key, unsigned keylen,
++                gcry_cipher_hd_t hd)
+ {
+   CAMELLIA_context *ctx=c;
+   static int initialized=0;
+@@ -213,6 +214,8 @@ camellia_setkey(void *c, const byte *key
+   unsigned int hwf = _gcry_get_hw_features ();
+ #endif
+ 
++  (void)hd;
++
+   if(keylen!=16 && keylen!=24 && keylen!=32)
+     return GPG_ERR_INV_KEYLEN;
+ 
+@@ -427,7 +430,7 @@ _gcry_camellia_ctr_enc(void *context, un
+       /* Encrypt the counter. */
+       Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf);
+       /* XOR the input with the encrypted counter and store in output.  */
+-      buf_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE);
++      cipher_block_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE);
+       outbuf += CAMELLIA_BLOCK_SIZE;
+       inbuf  += CAMELLIA_BLOCK_SIZE;
+       /* Increment the counter.  */
+@@ -520,7 +523,8 @@ _gcry_camellia_cbc_dec(void *context, un
+          the intermediate result to SAVEBUF.  */
+       Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, savebuf);
+ 
+-      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAMELLIA_BLOCK_SIZE);
++      cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf,
++                                CAMELLIA_BLOCK_SIZE);
+       inbuf += CAMELLIA_BLOCK_SIZE;
+       outbuf += CAMELLIA_BLOCK_SIZE;
+     }
+@@ -602,7 +606,7 @@ _gcry_camellia_cfb_dec(void *context, un
+   for ( ;nblocks; nblocks-- )
+     {
+       Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv);
+-      buf_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE);
++      cipher_block_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE);
+       outbuf += CAMELLIA_BLOCK_SIZE;
+       inbuf  += CAMELLIA_BLOCK_SIZE;
+     }
+@@ -991,7 +995,7 @@ selftest(void)
+       0x20,0xef,0x7c,0x91,0x9e,0x3a,0x75,0x09
+     };
+ 
+-  camellia_setkey(&ctx,key_128,sizeof(key_128));
++  camellia_setkey(&ctx,key_128,sizeof(key_128),NULL);
+   camellia_encrypt(&ctx,scratch,plaintext);
+   if(memcmp(scratch,ciphertext_128,sizeof(ciphertext_128))!=0)
+     return "CAMELLIA-128 test encryption failed.";
+@@ -999,7 +1003,7 @@ selftest(void)
+   if(memcmp(scratch,plaintext,sizeof(plaintext))!=0)
+     return "CAMELLIA-128 test decryption failed.";
+ 
+-  camellia_setkey(&ctx,key_192,sizeof(key_192));
++  camellia_setkey(&ctx,key_192,sizeof(key_192),NULL);
+   camellia_encrypt(&ctx,scratch,plaintext);
+   if(memcmp(scratch,ciphertext_192,sizeof(ciphertext_192))!=0)
+     return "CAMELLIA-192 test encryption failed.";
+@@ -1007,7 +1011,7 @@ selftest(void)
+   if(memcmp(scratch,plaintext,sizeof(plaintext))!=0)
+     return "CAMELLIA-192 test decryption failed.";
+ 
+-  camellia_setkey(&ctx,key_256,sizeof(key_256));
++  camellia_setkey(&ctx,key_256,sizeof(key_256),NULL);
+   camellia_encrypt(&ctx,scratch,plaintext);
+   if(memcmp(scratch,ciphertext_256,sizeof(ciphertext_256))!=0)
+     return "CAMELLIA-256 test encryption failed.";
+diff -up libgcrypt-1.8.5/cipher/cast5.c.aes-perf libgcrypt-1.8.5/cipher/cast5.c
+--- libgcrypt-1.8.5/cipher/cast5.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cast5.c	2020-04-22 18:29:41.665862325 +0200
+@@ -44,6 +44,7 @@
+ #include "cipher.h"
+ #include "bithelp.h"
+ #include "bufhelp.h"
++#include "cipher-internal.h"
+ #include "cipher-selftest.h"
+ 
+ /* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
+@@ -72,7 +73,8 @@ typedef struct {
+ #endif
+ } CAST5_context;
+ 
+-static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen);
++static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen,
++                                    gcry_cipher_hd_t hd);
+ static unsigned int encrypt_block (void *c, byte *outbuf, const byte *inbuf);
+ static unsigned int decrypt_block (void *c, byte *outbuf, const byte *inbuf);
+ 
+@@ -671,7 +673,7 @@ _gcry_cast5_ctr_enc(void *context, unsig
+       /* Encrypt the counter. */
+       do_encrypt_block(ctx, tmpbuf, ctr);
+       /* XOR the input with the encrypted counter and store in output.  */
+-      buf_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE);
++      cipher_block_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE);
+       outbuf += CAST5_BLOCKSIZE;
+       inbuf  += CAST5_BLOCKSIZE;
+       /* Increment the counter.  */
+@@ -739,7 +741,7 @@ _gcry_cast5_cbc_dec(void *context, unsig
+          the intermediate result to SAVEBUF.  */
+       do_decrypt_block (ctx, savebuf, inbuf);
+ 
+-      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE);
++      cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE);
+       inbuf += CAST5_BLOCKSIZE;
+       outbuf += CAST5_BLOCKSIZE;
+     }
+@@ -795,7 +797,7 @@ _gcry_cast5_cfb_dec(void *context, unsig
+   for ( ;nblocks; nblocks-- )
+     {
+       do_encrypt_block(ctx, iv, iv);
+-      buf_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE);
++      cipher_block_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE);
+       outbuf += CAST5_BLOCKSIZE;
+       inbuf  += CAST5_BLOCKSIZE;
+     }
+@@ -863,7 +865,7 @@ selftest(void)
+     byte buffer[8];
+     const char *r;
+ 
+-    cast_setkey( &c, key, 16 );
++    cast_setkey( &c, key, 16, NULL );
+     encrypt_block( &c, buffer, plain );
+     if( memcmp( buffer, cipher, 8 ) )
+ 	return "1";
+@@ -884,10 +886,10 @@ selftest(void)
+ 			0x80,0xAC,0x05,0xB8,0xE8,0x3D,0x69,0x6E };
+ 
+ 	for(i=0; i < 1000000; i++ ) {
+-	    cast_setkey( &c, b0, 16 );
++	    cast_setkey( &c, b0, 16, NULL );
+ 	    encrypt_block( &c, a0, a0 );
+ 	    encrypt_block( &c, a0+8, a0+8 );
+-	    cast_setkey( &c, a0, 16 );
++	    cast_setkey( &c, a0, 16, NULL );
+ 	    encrypt_block( &c, b0, b0 );
+ 	    encrypt_block( &c, b0+8, b0+8 );
+ 	}
+@@ -1029,10 +1031,12 @@ do_cast_setkey( CAST5_context *c, const
+ }
+ 
+ static gcry_err_code_t
+-cast_setkey (void *context, const byte *key, unsigned keylen )
++cast_setkey (void *context, const byte *key, unsigned keylen,
++             gcry_cipher_hd_t hd )
+ {
+   CAST5_context *c = (CAST5_context *) context;
+   gcry_err_code_t rc = do_cast_setkey (c, key, keylen);
++  (void)hd;
+   return rc;
+ }
+ 
+diff -up libgcrypt-1.8.5/cipher/chacha20.c.aes-perf libgcrypt-1.8.5/cipher/chacha20.c
+--- libgcrypt-1.8.5/cipher/chacha20.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/chacha20.c	2020-04-22 18:29:41.665862325 +0200
+@@ -419,10 +419,12 @@ chacha20_do_setkey (CHACHA20_context_t *
+ 
+ 
+ static gcry_err_code_t
+-chacha20_setkey (void *context, const byte * key, unsigned int keylen)
++chacha20_setkey (void *context, const byte *key, unsigned int keylen,
++                 gcry_cipher_hd_t hd)
+ {
+   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
+   gcry_err_code_t rc = chacha20_do_setkey (ctx, key, keylen);
++  (void)hd;
+   _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *));
+   return rc;
+ }
+@@ -569,7 +571,7 @@ selftest (void)
+   /* 16-byte alignment required for amd64 implementation. */
+   ctx = (CHACHA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15);
+ 
+-  chacha20_setkey (ctx, key_1, sizeof key_1);
++  chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
+   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
+   scratch[sizeof (scratch) - 1] = 0;
+   chacha20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1);
+@@ -577,7 +579,7 @@ selftest (void)
+     return "ChaCha20 encryption test 1 failed.";
+   if (scratch[sizeof (scratch) - 1])
+     return "ChaCha20 wrote too much.";
+-  chacha20_setkey (ctx, key_1, sizeof (key_1));
++  chacha20_setkey (ctx, key_1, sizeof (key_1), NULL);
+   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
+   chacha20_encrypt_stream (ctx, scratch, scratch, sizeof plaintext_1);
+   if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
+@@ -585,12 +587,12 @@ selftest (void)
+ 
+   for (i = 0; i < sizeof buf; i++)
+     buf[i] = i;
+-  chacha20_setkey (ctx, key_1, sizeof key_1);
++  chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
+   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
+   /*encrypt */
+   chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
+   /*decrypt */
+-  chacha20_setkey (ctx, key_1, sizeof key_1);
++  chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
+   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
+   chacha20_encrypt_stream (ctx, buf, buf, 1);
+   chacha20_encrypt_stream (ctx, buf + 1, buf + 1, (sizeof buf) - 1 - 1);
+@@ -600,13 +602,13 @@ selftest (void)
+     if (buf[i] != (byte) i)
+       return "ChaCha20 encryption test 2 failed.";
+ 
+-  chacha20_setkey (ctx, key_1, sizeof key_1);
++  chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
+   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
+   /* encrypt */
+   for (i = 0; i < sizeof buf; i++)
+     chacha20_encrypt_stream (ctx, &buf[i], &buf[i], 1);
+   /* decrypt */
+-  chacha20_setkey (ctx, key_1, sizeof key_1);
++  chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
+   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
+   chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
+   for (i = 0; i < sizeof buf; i++)
+diff -up libgcrypt-1.8.5/cipher/cipher-aeswrap.c.aes-perf libgcrypt-1.8.5/cipher/cipher-aeswrap.c
+--- libgcrypt-1.8.5/cipher/cipher-aeswrap.c.aes-perf	2018-04-17 17:49:00.000000000 +0200
++++ libgcrypt-1.8.5/cipher/cipher-aeswrap.c	2020-04-22 18:29:41.665862325 +0200
+@@ -99,7 +99,7 @@ _gcry_cipher_aeswrap_encrypt (gcry_ciphe
+ 		break;
+ 	    }
+           /* A := MSB_64(B) ^ t */
+-	  buf_xor(a, b, t, 8);
++	  cipher_block_xor(a, b, t, 8);
+           /* R[i] := LSB_64(B) */
+           memcpy (r+i*8, b+8, 8);
+         }
+@@ -170,7 +170,7 @@ _gcry_cipher_aeswrap_decrypt (gcry_ciphe
+       for (i = n; i >= 1; i--)
+         {
+           /* B := AES_k^1( (A ^ t)| R[i] ) */
+-	  buf_xor(b, a, t, 8);
++	  cipher_block_xor(b, a, t, 8);
+           memcpy (b+8, r+(i-1)*8, 8);
+           nburn = c->spec->decrypt (&c->context.c, b, b);
+           burn = nburn > burn ? nburn : burn;
+diff -up libgcrypt-1.8.5/cipher/cipher.c.aes-perf libgcrypt-1.8.5/cipher/cipher.c
+--- libgcrypt-1.8.5/cipher/cipher.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher.c	2020-04-22 18:29:41.666862306 +0200
+@@ -92,6 +92,8 @@ static gcry_cipher_spec_t *cipher_list[]
+ 
+ 
+ 
++static void _gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode);
++
+ 
+ static int
+ map_algo (int algo)
+@@ -532,6 +534,7 @@ _gcry_cipher_open_internal (gcry_cipher_
+               h->bulk.ctr_enc = _gcry_aes_ctr_enc;
+               h->bulk.ocb_crypt = _gcry_aes_ocb_crypt;
+               h->bulk.ocb_auth  = _gcry_aes_ocb_auth;
++              h->bulk.xts_crypt = _gcry_aes_xts_crypt;
+               break;
+ #endif /*USE_AES*/
+ #ifdef USE_BLOWFISH
+@@ -592,6 +595,9 @@ _gcry_cipher_open_internal (gcry_cipher_
+               break;
+             }
+ 
++          /* Setup mode routines. */
++          _gcry_cipher_setup_mode_ops(h, mode);
++
+           /* Setup defaults depending on the mode.  */
+           switch (mode)
+             {
+@@ -609,8 +615,7 @@ _gcry_cipher_open_internal (gcry_cipher_
+             default:
+               break;
+             }
+-
+-	}
++        }
+     }
+ 
+   /* Done.  */
+@@ -675,7 +680,7 @@ cipher_setkey (gcry_cipher_hd_t c, byte
+ 	}
+     }
+ 
+-  rc = c->spec->setkey (&c->context.c, key, keylen);
++  rc = c->spec->setkey (&c->context.c, key, keylen, c);
+   if (!rc)
+     {
+       /* Duplicate initial context.  */
+@@ -701,7 +706,7 @@ cipher_setkey (gcry_cipher_hd_t c, byte
+ 	case GCRY_CIPHER_MODE_XTS:
+ 	  /* Setup tweak cipher with second part of XTS key. */
+ 	  rc = c->spec->setkey (c->u_mode.xts.tweak_context, key + keylen,
+-				keylen);
++				keylen, c);
+ 	  if (!rc)
+ 	    {
+ 	      /* Duplicate initial tweak context.  */
+@@ -872,85 +877,78 @@ do_ecb_decrypt (gcry_cipher_hd_t c,
+ }
+ 
+ 
+-/****************
+- * Encrypt INBUF to OUTBUF with the mode selected at open.
+- * inbuf and outbuf may overlap or be the same.
+- * Depending on the mode some constraints apply to INBUFLEN.
+- */
+ static gcry_err_code_t
+-cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
+-		const byte *inbuf, size_t inbuflen)
++do_stream_encrypt (gcry_cipher_hd_t c,
++                unsigned char *outbuf, size_t outbuflen,
++                const unsigned char *inbuf, size_t inbuflen)
++{
++  (void)outbuflen;
++  c->spec->stencrypt (&c->context.c, outbuf, (void *)inbuf, inbuflen);
++  return 0;
++}
++
++static gcry_err_code_t
++do_stream_decrypt (gcry_cipher_hd_t c,
++                unsigned char *outbuf, size_t outbuflen,
++                const unsigned char *inbuf, size_t inbuflen)
++{
++  (void)outbuflen;
++  c->spec->stdecrypt (&c->context.c, outbuf, (void *)inbuf, inbuflen);
++  return 0;
++}
++
++
++static gcry_err_code_t
++do_encrypt_none_unknown (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
++                         const byte *inbuf, size_t inbuflen)
+ {
+   gcry_err_code_t rc;
+ 
+-  if (c->mode != GCRY_CIPHER_MODE_NONE && !c->marks.key)
+-    {
+-      log_error ("cipher_encrypt: key not set\n");
+-      return GPG_ERR_MISSING_KEY;
+-    }
++  (void)outbuflen;
+ 
+   switch (c->mode)
+     {
+-    case GCRY_CIPHER_MODE_ECB:
+-      rc = do_ecb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CBC:
+-      rc = _gcry_cipher_cbc_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CFB:
+-      rc = _gcry_cipher_cfb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
++    case GCRY_CIPHER_MODE_CMAC:
++      rc = GPG_ERR_INV_CIPHER_MODE;
+       break;
+ 
+-    case GCRY_CIPHER_MODE_CFB8:
+-      rc = _gcry_cipher_cfb8_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
++    case GCRY_CIPHER_MODE_NONE:
++      if (fips_mode () || !_gcry_get_debug_flag (0))
++        {
++          fips_signal_error ("cipher mode NONE used");
++          rc = GPG_ERR_INV_CIPHER_MODE;
++        }
++      else
++        {
++          if (inbuf != outbuf)
++            memmove (outbuf, inbuf, inbuflen);
++          rc = 0;
++        }
+       break;
+ 
+-    case GCRY_CIPHER_MODE_OFB:
+-      rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
++    default:
++      log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode );
++      rc = GPG_ERR_INV_CIPHER_MODE;
+       break;
++    }
+ 
+-    case GCRY_CIPHER_MODE_CTR:
+-      rc = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
++  return rc;
++}
+ 
+-    case GCRY_CIPHER_MODE_AESWRAP:
+-      rc = _gcry_cipher_aeswrap_encrypt (c, outbuf, outbuflen,
+-                                         inbuf, inbuflen);
+-      break;
++static gcry_err_code_t
++do_decrypt_none_unknown (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
++                         const byte *inbuf, size_t inbuflen)
++{
++  gcry_err_code_t rc;
+ 
+-    case GCRY_CIPHER_MODE_CCM:
+-      rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
++  (void)outbuflen;
+ 
++  switch (c->mode)
++    {
+     case GCRY_CIPHER_MODE_CMAC:
+       rc = GPG_ERR_INV_CIPHER_MODE;
+       break;
+ 
+-    case GCRY_CIPHER_MODE_GCM:
+-      rc = _gcry_cipher_gcm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_POLY1305:
+-      rc = _gcry_cipher_poly1305_encrypt (c, outbuf, outbuflen,
+-					  inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_OCB:
+-      rc = _gcry_cipher_ocb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_XTS:
+-      rc = _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 1);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_STREAM:
+-      c->spec->stencrypt (&c->context.c,
+-                          outbuf, (byte*)/*arggg*/inbuf, inbuflen);
+-      rc = 0;
+-      break;
+-
+     case GCRY_CIPHER_MODE_NONE:
+       if (fips_mode () || !_gcry_get_debug_flag (0))
+         {
+@@ -966,7 +964,7 @@ cipher_encrypt (gcry_cipher_hd_t c, byte
+       break;
+ 
+     default:
+-      log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode );
++      log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode );
+       rc = GPG_ERR_INV_CIPHER_MODE;
+       break;
+     }
+@@ -991,7 +989,13 @@ _gcry_cipher_encrypt (gcry_cipher_hd_t h
+       inlen = outsize;
+     }
+ 
+-  rc = cipher_encrypt (h, out, outsize, in, inlen);
++  if (h->mode != GCRY_CIPHER_MODE_NONE && !h->marks.key)
++    {
++      log_error ("cipher_decrypt: key not set\n");
++      return GPG_ERR_MISSING_KEY;
++    }
++
++  rc = h->mode_ops.encrypt (h, out, outsize, in, inlen);
+ 
+   /* Failsafe: Make sure that the plaintext will never make it into
+      OUT if the encryption returned an error.  */
+@@ -1002,110 +1006,10 @@ _gcry_cipher_encrypt (gcry_cipher_hd_t h
+ }
+ 
+ 
+-
+ /****************
+- * Decrypt INBUF to OUTBUF with the mode selected at open.
+- * inbuf and outbuf may overlap or be the same.
+- * Depending on the mode some some constraints apply to INBUFLEN.
++ * Decrypt IN and write it to OUT.  If IN is NULL, in-place encryption has
++ * been requested.
+  */
+-static gcry_err_code_t
+-cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen,
+-                const byte *inbuf, size_t inbuflen)
+-{
+-  gcry_err_code_t rc;
+-
+-  if (c->mode != GCRY_CIPHER_MODE_NONE && !c->marks.key)
+-    {
+-      log_error ("cipher_decrypt: key not set\n");
+-      return GPG_ERR_MISSING_KEY;
+-    }
+-
+-  switch (c->mode)
+-    {
+-    case GCRY_CIPHER_MODE_ECB:
+-      rc = do_ecb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CBC:
+-      rc = _gcry_cipher_cbc_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CFB:
+-      rc = _gcry_cipher_cfb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CFB8:
+-      rc = _gcry_cipher_cfb8_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_OFB:
+-      rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CTR:
+-      rc = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_AESWRAP:
+-      rc = _gcry_cipher_aeswrap_decrypt (c, outbuf, outbuflen,
+-                                         inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CCM:
+-      rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CMAC:
+-      rc = GPG_ERR_INV_CIPHER_MODE;
+-      break;
+-
+-    case GCRY_CIPHER_MODE_GCM:
+-      rc = _gcry_cipher_gcm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_POLY1305:
+-      rc = _gcry_cipher_poly1305_decrypt (c, outbuf, outbuflen,
+-					  inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_OCB:
+-      rc = _gcry_cipher_ocb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_XTS:
+-      rc = _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 0);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_STREAM:
+-      c->spec->stdecrypt (&c->context.c,
+-                          outbuf, (byte*)/*arggg*/inbuf, inbuflen);
+-      rc = 0;
+-      break;
+-
+-    case GCRY_CIPHER_MODE_NONE:
+-      if (fips_mode () || !_gcry_get_debug_flag (0))
+-        {
+-          fips_signal_error ("cipher mode NONE used");
+-          rc = GPG_ERR_INV_CIPHER_MODE;
+-        }
+-      else
+-        {
+-          if (inbuf != outbuf)
+-            memmove (outbuf, inbuf, inbuflen);
+-          rc = 0;
+-        }
+-      break;
+-
+-    default:
+-      log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode );
+-      rc = GPG_ERR_INV_CIPHER_MODE;
+-      break;
+-    }
+-
+-  return rc;
+-}
+-
+-
+ gcry_err_code_t
+ _gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize,
+                       const void *in, size_t inlen)
+@@ -1116,9 +1020,14 @@ _gcry_cipher_decrypt (gcry_cipher_hd_t h
+       inlen = outsize;
+     }
+ 
+-  return cipher_decrypt (h, out, outsize, in, inlen);
+-}
++  if (h->mode != GCRY_CIPHER_MODE_NONE && !h->marks.key)
++    {
++      log_error ("cipher_decrypt: key not set\n");
++      return GPG_ERR_MISSING_KEY;
++    }
+ 
++  return h->mode_ops.decrypt (h, out, outsize, in, inlen);
++}
+ 
+ 
+ /****************
+@@ -1149,33 +1058,10 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd
+ gcry_err_code_t
+ _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen)
+ {
+-  gcry_err_code_t rc = 0;
+-
+-  switch (hd->mode)
+-    {
+-      case GCRY_CIPHER_MODE_CCM:
+-        rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen);
+-        break;
+-
+-      case GCRY_CIPHER_MODE_GCM:
+-        rc =  _gcry_cipher_gcm_setiv (hd, iv, ivlen);
+-        break;
+-
+-      case GCRY_CIPHER_MODE_POLY1305:
+-        rc =  _gcry_cipher_poly1305_setiv (hd, iv, ivlen);
+-        break;
+-
+-      case GCRY_CIPHER_MODE_OCB:
+-        rc = _gcry_cipher_ocb_set_nonce (hd, iv, ivlen);
+-        break;
+-
+-      default:
+-        rc = cipher_setiv (hd, iv, ivlen);
+-        break;
+-    }
+-  return rc;
++  return hd->mode_ops.setiv (hd, iv, ivlen);
+ }
+ 
++
+ /* Set counter for CTR mode.  (CTR,CTRLEN) must denote a buffer of
+    block size length, or (NULL,0) to set the CTR to the all-zero
+    block. */
+@@ -1209,38 +1095,40 @@ _gcry_cipher_getctr (gcry_cipher_hd_t hd
+   return 0;
+ }
+ 
++
+ gcry_err_code_t
+ _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
+                            size_t abuflen)
+ {
+   gcry_err_code_t rc;
+ 
+-  switch (hd->mode)
++  if (hd->mode_ops.authenticate)
+     {
+-    case GCRY_CIPHER_MODE_CCM:
+-      rc = _gcry_cipher_ccm_authenticate (hd, abuf, abuflen);
+-      break;
+-
+-    case GCRY_CIPHER_MODE_CMAC:
+-      rc = _gcry_cipher_cmac_authenticate (hd, abuf, abuflen);
+-      break;
++      rc = hd->mode_ops.authenticate (hd, abuf, abuflen);
++    }
++  else
++    {
++      log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode);
++      rc = GPG_ERR_INV_CIPHER_MODE;
++    }
+ 
+-    case GCRY_CIPHER_MODE_GCM:
+-      rc = _gcry_cipher_gcm_authenticate (hd, abuf, abuflen);
+-      break;
++  return rc;
++}
+ 
+-    case GCRY_CIPHER_MODE_POLY1305:
+-      rc = _gcry_cipher_poly1305_authenticate (hd, abuf, abuflen);
+-      break;
+ 
+-    case GCRY_CIPHER_MODE_OCB:
+-      rc = _gcry_cipher_ocb_authenticate (hd, abuf, abuflen);
+-      break;
++gcry_err_code_t
++_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen)
++{
++  gcry_err_code_t rc;
+ 
+-    default:
+-      log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode);
++  if (hd->mode_ops.get_tag)
++    {
++      rc = hd->mode_ops.get_tag (hd, outtag, taglen);
++    }
++  else
++    {
++      log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode);
+       rc = GPG_ERR_INV_CIPHER_MODE;
+-      break;
+     }
+ 
+   return rc;
+@@ -1248,76 +1136,166 @@ _gcry_cipher_authenticate (gcry_cipher_h
+ 
+ 
+ gcry_err_code_t
+-_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen)
++_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen)
+ {
+   gcry_err_code_t rc;
+ 
+-  switch (hd->mode)
++  if (hd->mode_ops.check_tag)
+     {
+-    case GCRY_CIPHER_MODE_CCM:
+-      rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen);
++      rc = hd->mode_ops.check_tag (hd, intag, taglen);
++    }
++  else
++    {
++      log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode);
++      rc = GPG_ERR_INV_CIPHER_MODE;
++    }
++
++  return rc;
++}
++
++
++
++static void
++_gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode)
++{
++  /* Setup encryption and decryption routines. */
++  switch (mode)
++    {
++    case GCRY_CIPHER_MODE_STREAM:
++      c->mode_ops.encrypt = do_stream_encrypt;
++      c->mode_ops.decrypt = do_stream_decrypt;
+       break;
+ 
+-    case GCRY_CIPHER_MODE_CMAC:
+-      rc = _gcry_cipher_cmac_get_tag (hd, outtag, taglen);
++    case GCRY_CIPHER_MODE_ECB:
++      c->mode_ops.encrypt = do_ecb_encrypt;
++      c->mode_ops.decrypt = do_ecb_decrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_CBC:
++      c->mode_ops.encrypt = _gcry_cipher_cbc_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_cbc_decrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_CFB:
++      c->mode_ops.encrypt = _gcry_cipher_cfb_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_cfb_decrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_CFB8:
++      c->mode_ops.encrypt = _gcry_cipher_cfb8_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_cfb8_decrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_OFB:
++      c->mode_ops.encrypt = _gcry_cipher_ofb_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_ofb_encrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_CTR:
++      c->mode_ops.encrypt = _gcry_cipher_ctr_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_ctr_encrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_AESWRAP:
++      c->mode_ops.encrypt = _gcry_cipher_aeswrap_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_aeswrap_decrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_CCM:
++      c->mode_ops.encrypt = _gcry_cipher_ccm_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_ccm_decrypt;
+       break;
+ 
+     case GCRY_CIPHER_MODE_GCM:
+-      rc = _gcry_cipher_gcm_get_tag (hd, outtag, taglen);
++      c->mode_ops.encrypt = _gcry_cipher_gcm_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_gcm_decrypt;
+       break;
+ 
+     case GCRY_CIPHER_MODE_POLY1305:
+-      rc = _gcry_cipher_poly1305_get_tag (hd, outtag, taglen);
++      c->mode_ops.encrypt = _gcry_cipher_poly1305_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_poly1305_decrypt;
+       break;
+ 
+     case GCRY_CIPHER_MODE_OCB:
+-      rc = _gcry_cipher_ocb_get_tag (hd, outtag, taglen);
++      c->mode_ops.encrypt = _gcry_cipher_ocb_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_ocb_decrypt;
++      break;
++
++    case GCRY_CIPHER_MODE_XTS:
++      c->mode_ops.encrypt = _gcry_cipher_xts_encrypt;
++      c->mode_ops.decrypt = _gcry_cipher_xts_decrypt;
+       break;
+ 
+     default:
+-      log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode);
+-      rc = GPG_ERR_INV_CIPHER_MODE;
++      c->mode_ops.encrypt = do_encrypt_none_unknown;
++      c->mode_ops.decrypt = do_decrypt_none_unknown;
+       break;
+     }
+ 
+-  return rc;
+-}
++  /* Setup IV setting routine. */
++  switch (mode)
++    {
++    case GCRY_CIPHER_MODE_CCM:
++      c->mode_ops.setiv = _gcry_cipher_ccm_set_nonce;
++      break;
++
++    case GCRY_CIPHER_MODE_GCM:
++      c->mode_ops.setiv =  _gcry_cipher_gcm_setiv;
++      break;
+ 
++    case GCRY_CIPHER_MODE_POLY1305:
++      c->mode_ops.setiv = _gcry_cipher_poly1305_setiv;
++      break;
+ 
+-gcry_err_code_t
+-_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen)
+-{
+-  gcry_err_code_t rc;
++    case GCRY_CIPHER_MODE_OCB:
++      c->mode_ops.setiv = _gcry_cipher_ocb_set_nonce;
++      break;
+ 
+-  switch (hd->mode)
++    default:
++      c->mode_ops.setiv = cipher_setiv;
++      break;
++    }
++
++
++  /* Setup authentication routines for AEAD modes. */
++  switch (mode)
+     {
+     case GCRY_CIPHER_MODE_CCM:
+-      rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen);
++      c->mode_ops.authenticate = _gcry_cipher_ccm_authenticate;
++      c->mode_ops.get_tag      = _gcry_cipher_ccm_get_tag;
++      c->mode_ops.check_tag    = _gcry_cipher_ccm_check_tag;
+       break;
+ 
+     case GCRY_CIPHER_MODE_CMAC:
+-      rc = _gcry_cipher_cmac_check_tag (hd, intag, taglen);
++      c->mode_ops.authenticate = _gcry_cipher_cmac_authenticate;
++      c->mode_ops.get_tag      = _gcry_cipher_cmac_get_tag;
++      c->mode_ops.check_tag    = _gcry_cipher_cmac_check_tag;
+       break;
+ 
+     case GCRY_CIPHER_MODE_GCM:
+-      rc = _gcry_cipher_gcm_check_tag (hd, intag, taglen);
++      c->mode_ops.authenticate = _gcry_cipher_gcm_authenticate;
++      c->mode_ops.get_tag      = _gcry_cipher_gcm_get_tag;
++      c->mode_ops.check_tag    = _gcry_cipher_gcm_check_tag;
+       break;
+ 
+     case GCRY_CIPHER_MODE_POLY1305:
+-      rc = _gcry_cipher_poly1305_check_tag (hd, intag, taglen);
++      c->mode_ops.authenticate = _gcry_cipher_poly1305_authenticate;
++      c->mode_ops.get_tag      = _gcry_cipher_poly1305_get_tag;
++      c->mode_ops.check_tag    = _gcry_cipher_poly1305_check_tag;
+       break;
+ 
+     case GCRY_CIPHER_MODE_OCB:
+-      rc = _gcry_cipher_ocb_check_tag (hd, intag, taglen);
++      c->mode_ops.authenticate = _gcry_cipher_ocb_authenticate;
++      c->mode_ops.get_tag      = _gcry_cipher_ocb_get_tag;
++      c->mode_ops.check_tag    = _gcry_cipher_ocb_check_tag;
+       break;
+ 
+     default:
+-      log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode);
+-      rc = GPG_ERR_INV_CIPHER_MODE;
++      c->mode_ops.authenticate = NULL;
++      c->mode_ops.get_tag      = NULL;
++      c->mode_ops.check_tag    = NULL;
+       break;
+     }
+-
+-  return rc;
+ }
+ 
+ 
+diff -up libgcrypt-1.8.5/cipher/cipher-cbc.c.aes-perf libgcrypt-1.8.5/cipher/cipher-cbc.c
+--- libgcrypt-1.8.5/cipher/cipher-cbc.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-cbc.c	2020-04-22 18:29:41.666862306 +0200
+@@ -79,7 +79,7 @@ _gcry_cipher_cbc_encrypt (gcry_cipher_hd
+ 
+       for (n=0; n < nblocks; n++ )
+         {
+-          buf_xor (outbuf, inbuf, ivp, blocksize);
++          cipher_block_xor (outbuf, inbuf, ivp, blocksize);
+           nburn = enc_fn ( &c->context.c, outbuf, outbuf );
+           burn = nburn > burn ? nburn : burn;
+           ivp = outbuf;
+@@ -116,7 +116,7 @@ _gcry_cipher_cbc_encrypt (gcry_cipher_hd
+ 
+       nburn = enc_fn (&c->context.c, outbuf, outbuf);
+       burn = nburn > burn ? nburn : burn;
+-      buf_cpy (c->u_iv.iv, outbuf, blocksize);
++      cipher_block_cpy (c->u_iv.iv, outbuf, blocksize);
+     }
+ 
+   if (burn > 0)
+@@ -158,7 +158,7 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd
+       nblocks--;
+       if ((inbuflen % blocksize) == 0)
+ 	nblocks--;
+-      buf_cpy (c->lastiv, c->u_iv.iv, blocksize);
++      cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize);
+     }
+ 
+   if (c->bulk.cbc_dec)
+@@ -176,7 +176,8 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd
+              storage here because it is not used otherwise.  */
+           nburn = dec_fn ( &c->context.c, c->lastiv, inbuf );
+           burn = nburn > burn ? nburn : burn;
+-          buf_xor_n_copy_2(outbuf, c->lastiv, c->u_iv.iv, inbuf, blocksize);
++          cipher_block_xor_n_copy_2 (outbuf, c->lastiv, c->u_iv.iv, inbuf,
++                                     blocksize);
+           inbuf  += blocksize;
+           outbuf += blocksize;
+         }
+@@ -191,7 +192,7 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd
+       else
+         restbytes = inbuflen % blocksize;
+ 
+-      buf_cpy (c->lastiv, c->u_iv.iv, blocksize );         /* Save Cn-2. */
++      cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */
+       buf_cpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */
+ 
+       nburn = dec_fn ( &c->context.c, outbuf, inbuf );
+@@ -203,7 +204,7 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd
+         c->u_iv.iv[i] = outbuf[i];
+       nburn = dec_fn (&c->context.c, outbuf, c->u_iv.iv);
+       burn = nburn > burn ? nburn : burn;
+-      buf_xor(outbuf, outbuf, c->lastiv, blocksize);
++      cipher_block_xor(outbuf, outbuf, c->lastiv, blocksize);
+       /* c->lastiv is now really lastlastiv, does this matter? */
+     }
+ 
+diff -up libgcrypt-1.8.5/cipher/cipher-ccm.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ccm.c
+--- libgcrypt-1.8.5/cipher/cipher-ccm.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-ccm.c	2020-04-22 18:29:41.666862306 +0200
+@@ -67,7 +67,8 @@ do_cbc_mac (gcry_cipher_hd_t c, const un
+       if (unused > 0)
+         {
+           /* Process one block from macbuf.  */
+-          buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize);
++          cipher_block_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf,
++                           blocksize);
+           set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
+ 
+           unused = 0;
+@@ -86,7 +87,7 @@ do_cbc_mac (gcry_cipher_hd_t c, const un
+         {
+           while (inlen >= blocksize)
+             {
+-              buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
++              cipher_block_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
+ 
+               set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
+ 
+@@ -272,7 +273,7 @@ _gcry_cipher_ccm_tag (gcry_cipher_hd_t c
+       burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding.  */
+ 
+       /* Add S_0 */
+-      buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16);
++      cipher_block_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16);
+ 
+       wipememory (c->u_ctr.ctr, 16);
+       wipememory (c->u_mode.ccm.s0, 16);
+diff -up libgcrypt-1.8.5/cipher/cipher-cfb.c.aes-perf libgcrypt-1.8.5/cipher/cipher-cfb.c
+--- libgcrypt-1.8.5/cipher/cipher-cfb.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-cfb.c	2020-04-22 18:29:41.667862287 +0200
+@@ -91,7 +91,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd
+           nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+           burn = nburn > burn ? nburn : burn;
+           /* XOR the input with the IV and store input into IV.  */
+-          buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
++          cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
+           outbuf += blocksize;
+           inbuf += blocksize;
+           inbuflen -= blocksize;
+@@ -101,11 +101,11 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd
+   if ( inbuflen >= blocksize )
+     {
+       /* Save the current IV and then encrypt the IV. */
+-      buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
++      cipher_block_cpy( c->lastiv, c->u_iv.iv, blocksize );
+       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+       burn = nburn > burn ? nburn : burn;
+       /* XOR the input with the IV and store input into IV */
+-      buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
++      cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
+       outbuf += blocksize;
+       inbuf += blocksize;
+       inbuflen -= blocksize;
+@@ -113,7 +113,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd
+   if ( inbuflen )
+     {
+       /* Save the current IV and then encrypt the IV. */
+-      buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
++      cipher_block_cpy( c->lastiv, c->u_iv.iv, blocksize );
+       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+       burn = nburn > burn ? nburn : burn;
+       c->unused = blocksize;
+@@ -193,7 +193,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd
+           nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+           burn = nburn > burn ? nburn : burn;
+           /* XOR the input with the IV and store input into IV. */
+-          buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
++          cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
+           outbuf += blocksize;
+           inbuf += blocksize;
+           inbuflen -= blocksize;
+@@ -203,11 +203,11 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd
+   if (inbuflen >= blocksize )
+     {
+       /* Save the current IV and then encrypt the IV. */
+-      buf_cpy ( c->lastiv, c->u_iv.iv, blocksize);
++      cipher_block_cpy ( c->lastiv, c->u_iv.iv, blocksize);
+       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+       burn = nburn > burn ? nburn : burn;
+       /* XOR the input with the IV and store input into IV */
+-      buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
++      cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
+       outbuf += blocksize;
+       inbuf += blocksize;
+       inbuflen -= blocksize;
+@@ -216,7 +216,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd
+   if (inbuflen)
+     {
+       /* Save the current IV and then encrypt the IV. */
+-      buf_cpy ( c->lastiv, c->u_iv.iv, blocksize );
++      cipher_block_cpy ( c->lastiv, c->u_iv.iv, blocksize );
+       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+       burn = nburn > burn ? nburn : burn;
+       c->unused = blocksize;
+diff -up libgcrypt-1.8.5/cipher/cipher-cmac.c.aes-perf libgcrypt-1.8.5/cipher/cipher-cmac.c
+--- libgcrypt-1.8.5/cipher/cipher-cmac.c.aes-perf	2020-04-22 18:29:41.643862745 +0200
++++ libgcrypt-1.8.5/cipher/cipher-cmac.c	2020-04-22 18:29:41.667862287 +0200
+@@ -63,7 +63,7 @@ cmac_write (gcry_cipher_hd_t c, const by
+       for (; inlen && c->unused < blocksize; inlen--)
+         c->lastiv[c->unused++] = *inbuf++;
+ 
+-      buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
++      cipher_block_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
+       set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
+ 
+       c->unused = 0;
+@@ -83,7 +83,7 @@ cmac_write (gcry_cipher_hd_t c, const by
+   else
+     while (inlen > blocksize)
+       {
+-        buf_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
++        cipher_block_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
+         set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv));
+         inlen -= blocksize;
+         inbuf += blocksize;
+@@ -174,9 +174,9 @@ cmac_final (gcry_cipher_hd_t c)
+         c->lastiv[count++] = 0;
+     }
+ 
+-  buf_xor (c->lastiv, c->lastiv, subkey, blocksize);
++  cipher_block_xor (c->lastiv, c->lastiv, subkey, blocksize);
+ 
+-  buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
++  cipher_block_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize);
+   burn = c->spec->encrypt (&c->context.c, c->u_iv.iv, c->u_iv.iv);
+   if (burn)
+     _gcry_burn_stack (burn + 4 * sizeof (void *));
+diff -up libgcrypt-1.8.5/cipher/cipher-ctr.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ctr.c
+--- libgcrypt-1.8.5/cipher/cipher-ctr.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-ctr.c	2020-04-22 18:29:41.667862287 +0200
+@@ -81,24 +81,34 @@ _gcry_cipher_ctr_encrypt (gcry_cipher_hd
+     {
+       unsigned char tmp[MAX_BLOCKSIZE];
+ 
+-      do {
+-        nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr);
+-        burn = nburn > burn ? nburn : burn;
+-
+-        for (i = blocksize; i > 0; i--)
+-          {
+-            c->u_ctr.ctr[i-1]++;
+-            if (c->u_ctr.ctr[i-1] != 0)
+-              break;
+-          }
+-
+-        n = blocksize < inbuflen ? blocksize : inbuflen;
+-        buf_xor(outbuf, inbuf, tmp, n);
+-
+-        inbuflen -= n;
+-        outbuf += n;
+-        inbuf += n;
+-      } while (inbuflen);
++      do
++        {
++          nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr);
++          burn = nburn > burn ? nburn : burn;
++
++          for (i = blocksize; i > 0; i--)
++            {
++              c->u_ctr.ctr[i-1]++;
++              if (c->u_ctr.ctr[i-1] != 0)
++                break;
++            }
++
++          if (inbuflen < blocksize)
++            break;
++          n = blocksize;
++          cipher_block_xor(outbuf, inbuf, tmp, blocksize);
++
++          inbuflen -= n;
++          outbuf += n;
++          inbuf += n;
++        }
++      while (inbuflen);
++
++      if (inbuflen)
++        {
++          n = inbuflen;
++          buf_xor(outbuf, inbuf, tmp, inbuflen);
++        }
+ 
+       /* Save the unused bytes of the counter.  */
+       c->unused = blocksize - n;
+diff -up libgcrypt-1.8.5/cipher/cipher-gcm.c.aes-perf libgcrypt-1.8.5/cipher/cipher-gcm.c
+--- libgcrypt-1.8.5/cipher/cipher-gcm.c.aes-perf	2018-04-17 17:27:25.000000000 +0200
++++ libgcrypt-1.8.5/cipher/cipher-gcm.c	2020-04-22 18:29:41.667862287 +0200
+@@ -150,7 +150,7 @@ do_ghash (unsigned char *result, const u
+   u32 A;
+   int i;
+ 
+-  buf_xor (V, result, buf, 16);
++  cipher_block_xor (V, result, buf, 16);
+   V[0] = be_bswap64 (V[0]);
+   V[1] = be_bswap64 (V[1]);
+ 
+@@ -259,7 +259,7 @@ do_ghash (unsigned char *result, const u
+   u32 T[3];
+   int i;
+ 
+-  buf_xor (V, result, buf, 16); /* V is big-endian */
++  cipher_block_xor (V, result, buf, 16); /* V is big-endian */
+ 
+   /* First round can be manually tweaked based on fact that 'tmp' is zero. */
+   i = 15;
+@@ -342,7 +342,7 @@ do_ghash (unsigned char *hsub, unsigned
+ #else
+   unsigned long T[4];
+ 
+-  buf_xor (V, result, buf, 16);
++  cipher_block_xor (V, result, buf, 16);
+   for (i = 0; i < 4; i++)
+     {
+       V[i] = (V[i] & 0x00ff00ff) << 8 | (V[i] & 0xff00ff00) >> 8;
+@@ -358,7 +358,7 @@ do_ghash (unsigned char *hsub, unsigned
+       for (j = 0x80; j; j >>= 1)
+         {
+           if (hsub[i] & j)
+-            buf_xor (p, p, V, 16);
++            cipher_block_xor (p, p, V, 16);
+           if (bshift (V))
+             V[0] ^= 0xe1000000;
+         }
+@@ -598,7 +598,7 @@ gcm_ctr_encrypt (gcry_cipher_hd_t c, byt
+                 }
+ 
+               fix_ctr = 1;
+-              buf_cpy(ctr_copy, c->u_ctr.ctr, GCRY_GCM_BLOCK_LEN);
++              cipher_block_cpy(ctr_copy, c->u_ctr.ctr, GCRY_GCM_BLOCK_LEN);
+             }
+         }
+ 
+@@ -928,8 +928,8 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c
+       /* Add bitlengths to tag. */
+       do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, (byte*)bitlengths,
+                    GCRY_GCM_BLOCK_LEN, 1);
+-      buf_xor (c->u_mode.gcm.u_tag.tag, c->u_mode.gcm.tagiv,
+-               c->u_mode.gcm.u_tag.tag, GCRY_GCM_BLOCK_LEN);
++      cipher_block_xor (c->u_mode.gcm.u_tag.tag, c->u_mode.gcm.tagiv,
++                        c->u_mode.gcm.u_tag.tag, GCRY_GCM_BLOCK_LEN);
+       c->marks.tag = 1;
+ 
+       wipememory (bitlengths, sizeof (bitlengths));
+diff -up libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c.aes-perf libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c
+--- libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c	2020-04-22 18:29:41.668862268 +0200
+@@ -248,7 +248,8 @@ static inline void gfmul_pclmul_aggr4(vo
+ void
+ _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c)
+ {
+-  u64 tmp[2];
++  static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
++    { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
+ #if defined(__x86_64__) && defined(__WIN64__)
+   char win64tmp[3 * 16];
+ 
+@@ -262,15 +263,19 @@ _gcry_ghash_setup_intel_pclmul (gcry_cip
+ #endif
+ 
+   /* Swap endianness of hsub. */
+-  tmp[0] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 8);
+-  tmp[1] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 0);
+-  buf_cpy (c->u_mode.gcm.u_ghash_key.key, tmp, GCRY_GCM_BLOCK_LEN);
++  asm volatile ("movdqu (%[key]), %%xmm0\n\t"
++                "pshufb %[be_mask], %%xmm0\n\t"
++                "movdqu %%xmm0, (%[key])\n\t"
++                :
++                : [key] "r" (c->u_mode.gcm.u_ghash_key.key),
++                  [be_mask] "m" (*be_mask)
++                : "memory");
+ 
+ #ifdef __x86_64__
+-  asm volatile ("movdqu %[h_1], %%xmm0\n\t"
+-                "movdqa %%xmm0, %%xmm1\n\t"
++  asm volatile ("movdqa %%xmm0, %%xmm1\n\t"
++                :
+                 :
+-                : [h_1] "m" (*tmp));
++                : "memory");
+ 
+   gfmul_pclmul (); /* H•H => H² */
+ 
+@@ -324,8 +329,6 @@ _gcry_ghash_setup_intel_pclmul (gcry_cip
+                 ::: "cc" );
+ #endif
+ #endif
+-
+-  wipememory (tmp, sizeof(tmp));
+ }
+ 
+ 
+diff -up libgcrypt-1.8.5/cipher/cipher-internal.h.aes-perf libgcrypt-1.8.5/cipher/cipher-internal.h
+--- libgcrypt-1.8.5/cipher/cipher-internal.h.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-internal.h	2020-04-22 18:29:41.668862268 +0200
+@@ -121,6 +121,25 @@ struct gcry_cipher_handle
+      interface does not easily allow to retrieve this value. */
+   int algo;
+ 
++  /* A structure with function pointers for mode operations. */
++  struct {
++    gcry_err_code_t (*encrypt)(gcry_cipher_hd_t c,
++                               unsigned char *outbuf, size_t outbuflen,
++                               const unsigned char *inbuf, size_t inbuflen);
++    gcry_err_code_t (*decrypt)(gcry_cipher_hd_t c,
++                               unsigned char *outbuf, size_t outbuflen,
++                               const unsigned char *inbuf, size_t inbuflen);
++    gcry_err_code_t (*setiv)(gcry_cipher_hd_t c, const unsigned char *iv,
++                             size_t ivlen);
++
++    gcry_err_code_t (*authenticate)(gcry_cipher_hd_t c,
++                                    const unsigned char *abuf, size_t abuflen);
++    gcry_err_code_t (*get_tag)(gcry_cipher_hd_t c, unsigned char *outtag,
++                               size_t taglen);
++    gcry_err_code_t (*check_tag)(gcry_cipher_hd_t c, const unsigned char *intag,
++                                 size_t taglen);
++  } mode_ops;
++
+   /* A structure with function pointers for bulk operations.  Due to
+      limitations of the module system (we don't want to change the
+      API) we need to keep these function pointers here.  The cipher
+@@ -146,7 +165,7 @@ struct gcry_cipher_handle
+ 			const void *inbuf_arg, size_t nblocks, int encrypt);
+     size_t (*ocb_auth)(gcry_cipher_hd_t c, const void *abuf_arg,
+ 		       size_t nblocks);
+-    void (*xts_crypt)(gcry_cipher_hd_t c, unsigned char *tweak,
++    void (*xts_crypt)(void *context, unsigned char *tweak,
+ 		      void *outbuf_arg, const void *inbuf_arg,
+ 		      size_t nblocks, int encrypt);
+   } bulk;
+@@ -479,9 +498,12 @@ gcry_err_code_t _gcry_cipher_ocb_check_t
+ 
+ 
+ /*-- cipher-xts.c --*/
+-gcry_err_code_t _gcry_cipher_xts_crypt
++gcry_err_code_t _gcry_cipher_xts_encrypt
+ /*           */ (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen,
+-		 const unsigned char *inbuf, size_t inbuflen, int encrypt);
++		 const unsigned char *inbuf, size_t inbuflen);
++gcry_err_code_t _gcry_cipher_xts_decrypt
++/*           */ (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen,
++		 const unsigned char *inbuf, size_t inbuflen);
+ 
+ 
+ /* Return the L-value for block N.  Note: 'cipher_ocb.c' ensures that N
+@@ -506,4 +528,145 @@ ocb_get_l (gcry_cipher_hd_t c, u64 n)
+   return c->u_mode.ocb.L[ntz];
+ }
+ 
++/* Optimized function for cipher block copying */
++static inline void
++cipher_block_cpy(void *_dst, const void *_src, size_t blocksize)
++{
++  byte *dst = _dst;
++  const byte *src = _src;
++  u64 s[2];
++
++  if (blocksize == 8)
++    {
++      buf_put_he64(dst + 0, buf_get_he64(src + 0));
++    }
++  else /* blocksize == 16 */
++    {
++      s[0] = buf_get_he64(src + 0);
++      s[1] = buf_get_he64(src + 8);
++      buf_put_he64(dst + 0, s[0]);
++      buf_put_he64(dst + 8, s[1]);
++    }
++}
++
++
++/* Optimized function for cipher block xoring */
++static inline void
++cipher_block_xor(void *_dst, const void *_src1, const void *_src2,
++                 size_t blocksize)
++{
++  byte *dst = _dst;
++  const byte *src1 = _src1;
++  const byte *src2 = _src2;
++  u64 s1[2];
++  u64 s2[2];
++
++  if (blocksize == 8)
++    {
++      buf_put_he64(dst + 0, buf_get_he64(src1 + 0) ^ buf_get_he64(src2 + 0));
++    }
++  else /* blocksize == 16 */
++    {
++      s1[0] = buf_get_he64(src1 + 0);
++      s1[1] = buf_get_he64(src1 + 8);
++      s2[0] = buf_get_he64(src2 + 0);
++      s2[1] = buf_get_he64(src2 + 8);
++      buf_put_he64(dst + 0, s1[0] ^ s2[0]);
++      buf_put_he64(dst + 8, s1[1] ^ s2[1]);
++    }
++}
++
++
++/* Optimized function for in-place cipher block xoring */
++static inline void
++cipher_block_xor_1(void *_dst, const void *_src, size_t blocksize)
++{
++  cipher_block_xor (_dst, _dst, _src, blocksize);
++}
++
++
++/* Optimized function for cipher block xoring with two destination cipher
++   blocks.  Used mainly by CFB mode encryption.  */
++static inline void
++cipher_block_xor_2dst(void *_dst1, void *_dst2, const void *_src,
++                      size_t blocksize)
++{
++  byte *dst1 = _dst1;
++  byte *dst2 = _dst2;
++  const byte *src = _src;
++  u64 d2[2];
++  u64 s[2];
++
++  if (blocksize == 8)
++    {
++      d2[0] = buf_get_he64(dst2 + 0) ^ buf_get_he64(src + 0);
++      buf_put_he64(dst2 + 0, d2[0]);
++      buf_put_he64(dst1 + 0, d2[0]);
++    }
++  else /* blocksize == 16 */
++    {
++      s[0] = buf_get_he64(src + 0);
++      s[1] = buf_get_he64(src + 8);
++      d2[0] = buf_get_he64(dst2 + 0);
++      d2[1] = buf_get_he64(dst2 + 8);
++      d2[0] = d2[0] ^ s[0];
++      d2[1] = d2[1] ^ s[1];
++      buf_put_he64(dst2 + 0, d2[0]);
++      buf_put_he64(dst2 + 8, d2[1]);
++      buf_put_he64(dst1 + 0, d2[0]);
++      buf_put_he64(dst1 + 8, d2[1]);
++    }
++}
++
++
++/* Optimized function for combined cipher block xoring and copying.
++   Used by mainly CBC mode decryption.  */
++static inline void
++cipher_block_xor_n_copy_2(void *_dst_xor, const void *_src_xor,
++                          void *_srcdst_cpy, const void *_src_cpy,
++                          size_t blocksize)
++{
++  byte *dst_xor = _dst_xor;
++  byte *srcdst_cpy = _srcdst_cpy;
++  const byte *src_xor = _src_xor;
++  const byte *src_cpy = _src_cpy;
++  u64 sc[2];
++  u64 sx[2];
++  u64 sdc[2];
++
++  if (blocksize == 8)
++    {
++      sc[0] = buf_get_he64(src_cpy + 0);
++      buf_put_he64(dst_xor + 0,
++                   buf_get_he64(srcdst_cpy + 0) ^ buf_get_he64(src_xor + 0));
++      buf_put_he64(srcdst_cpy + 0, sc[0]);
++    }
++  else /* blocksize == 16 */
++    {
++      sc[0] = buf_get_he64(src_cpy + 0);
++      sc[1] = buf_get_he64(src_cpy + 8);
++      sx[0] = buf_get_he64(src_xor + 0);
++      sx[1] = buf_get_he64(src_xor + 8);
++      sdc[0] = buf_get_he64(srcdst_cpy + 0);
++      sdc[1] = buf_get_he64(srcdst_cpy + 8);
++      sx[0] ^= sdc[0];
++      sx[1] ^= sdc[1];
++      buf_put_he64(dst_xor + 0, sx[0]);
++      buf_put_he64(dst_xor + 8, sx[1]);
++      buf_put_he64(srcdst_cpy + 0, sc[0]);
++      buf_put_he64(srcdst_cpy + 8, sc[1]);
++    }
++}
++
++
++/* Optimized function for combined cipher block xoring and copying.
++   Used by mainly CFB mode decryption.  */
++static inline void
++cipher_block_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src,
++                        size_t blocksize)
++{
++  cipher_block_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, blocksize);
++}
++
++
+ #endif /*G10_CIPHER_INTERNAL_H*/
+diff -up libgcrypt-1.8.5/cipher/cipher-ocb.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ocb.c
+--- libgcrypt-1.8.5/cipher/cipher-ocb.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-ocb.c	2020-04-22 18:29:41.668862268 +0200
+@@ -82,7 +82,7 @@ static void
+ double_block_cpy (unsigned char *d, const unsigned char *s)
+ {
+   if (d != s)
+-    buf_cpy (d, s, OCB_BLOCK_LEN);
++    cipher_block_cpy (d, s, OCB_BLOCK_LEN);
+   double_block (d);
+ }
+ 
+@@ -181,8 +181,8 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_
+   nburn = c->spec->encrypt (&c->context.c, ktop, ktop);
+   burn = nburn > burn ? nburn : burn;
+   /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */
+-  buf_cpy (stretch, ktop, OCB_BLOCK_LEN);
+-  buf_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8);
++  cipher_block_cpy (stretch, ktop, OCB_BLOCK_LEN);
++  cipher_block_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8);
+   /* Offset_0 = Stretch[1+bottom..128+bottom]
+      (We use the IV field to store the offset) */
+   bit_copy (c->u_iv.iv, stretch, bottom, OCB_BLOCK_LEN);
+@@ -267,18 +267,18 @@ _gcry_cipher_ocb_authenticate (gcry_ciph
+             }
+           else
+             {
+-              buf_cpy (l_tmp, ocb_get_l (c, c->u_mode.ocb.aad_nblocks),
+-                       OCB_BLOCK_LEN);
++              cipher_block_cpy (l_tmp, ocb_get_l (c, c->u_mode.ocb.aad_nblocks),
++                                OCB_BLOCK_LEN);
+             }
+ 
+           /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-          buf_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN);
+           /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
+-          buf_xor (l_tmp, c->u_mode.ocb.aad_offset,
+-                   c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN);
++          cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset,
++                            c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN);
+           nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp);
+           burn = nburn > burn ? nburn : burn;
+-          buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
+ 
+           c->u_mode.ocb.aad_nleftover = 0;
+         }
+@@ -309,12 +309,13 @@ _gcry_cipher_ocb_authenticate (gcry_ciph
+           ocb_get_L_big(c, c->u_mode.ocb.aad_nblocks, l_tmp);
+ 
+           /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-          buf_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN);
+           /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
+-          buf_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, OCB_BLOCK_LEN);
++          cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf,
++                            OCB_BLOCK_LEN);
+           nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp);
+           burn = nburn > burn ? nburn : burn;
+-          buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
+ 
+           abuf += OCB_BLOCK_LEN;
+           abuflen -= OCB_BLOCK_LEN;
+@@ -349,14 +350,15 @@ _gcry_cipher_ocb_authenticate (gcry_ciph
+           gcry_assert(c->u_mode.ocb.aad_nblocks & table_size_mask);
+ 
+           /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-          buf_xor_1 (c->u_mode.ocb.aad_offset,
+-                     ocb_get_l (c, c->u_mode.ocb.aad_nblocks),
+-                     OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_offset,
++                              ocb_get_l (c, c->u_mode.ocb.aad_nblocks),
++                              OCB_BLOCK_LEN);
+           /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
+-          buf_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, OCB_BLOCK_LEN);
++          cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf,
++                            OCB_BLOCK_LEN);
+           nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp);
+           burn = nburn > burn ? nburn : burn;
+-          buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
+ 
+           abuf += OCB_BLOCK_LEN;
+           abuflen -= OCB_BLOCK_LEN;
+@@ -397,18 +399,18 @@ ocb_aad_finalize (gcry_cipher_hd_t c)
+   if (c->u_mode.ocb.aad_nleftover)
+     {
+       /* Offset_* = Offset_m xor L_*  */
+-      buf_xor_1 (c->u_mode.ocb.aad_offset,
+-                 c->u_mode.ocb.L_star, OCB_BLOCK_LEN);
++      cipher_block_xor_1 (c->u_mode.ocb.aad_offset,
++                          c->u_mode.ocb.L_star, OCB_BLOCK_LEN);
+       /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_*  */
+       buf_cpy (l_tmp, c->u_mode.ocb.aad_leftover, c->u_mode.ocb.aad_nleftover);
+       memset (l_tmp + c->u_mode.ocb.aad_nleftover, 0,
+               OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover);
+       l_tmp[c->u_mode.ocb.aad_nleftover] = 0x80;
+-      buf_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN);
++      cipher_block_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN);
+       /* Sum = Sum_m xor ENCIPHER(K, CipherInput)  */
+       nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp);
+       burn = nburn > burn ? nburn : burn;
+-      buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
++      cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN);
+ 
+       c->u_mode.ocb.aad_nleftover = 0;
+     }
+@@ -431,7 +433,7 @@ ocb_checksum (unsigned char *chksum, con
+   while (nblks > 0)
+     {
+       /* Checksum_i = Checksum_{i-1} xor P_i  */
+-      buf_xor_1(chksum, plainbuf, OCB_BLOCK_LEN);
++      cipher_block_xor_1(chksum, plainbuf, OCB_BLOCK_LEN);
+ 
+       plainbuf += OCB_BLOCK_LEN;
+       nblks--;
+@@ -491,12 +493,12 @@ ocb_crypt (gcry_cipher_hd_t c, int encry
+             }
+ 
+           /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-          buf_xor_1 (c->u_iv.iv, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_iv.iv, l_tmp, OCB_BLOCK_LEN);
+           /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
+-          buf_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN);
++          cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN);
+           nburn = crypt_fn (&c->context.c, outbuf, outbuf);
+           burn = nburn > burn ? nburn : burn;
+-          buf_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN);
+ 
+           if (!encrypt)
+             {
+@@ -551,14 +553,14 @@ ocb_crypt (gcry_cipher_hd_t c, int encry
+               gcry_assert(c->u_mode.ocb.data_nblocks & table_size_mask);
+ 
+               /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-              buf_xor_1 (c->u_iv.iv,
+-                         ocb_get_l (c, c->u_mode.ocb.data_nblocks),
+-                         OCB_BLOCK_LEN);
++              cipher_block_xor_1 (c->u_iv.iv,
++                                  ocb_get_l (c, c->u_mode.ocb.data_nblocks),
++                                  OCB_BLOCK_LEN);
+               /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
+-              buf_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN);
++              cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN);
+               nburn = crypt_fn (&c->context.c, outbuf, outbuf);
+               burn = nburn > burn ? nburn : burn;
+-              buf_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN);
++              cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN);
+ 
+               inbuf += OCB_BLOCK_LEN;
+               inbuflen -= OCB_BLOCK_LEN;
+@@ -584,7 +586,7 @@ ocb_crypt (gcry_cipher_hd_t c, int encry
+       unsigned char pad[OCB_BLOCK_LEN];
+ 
+       /* Offset_* = Offset_m xor L_*  */
+-      buf_xor_1 (c->u_iv.iv, c->u_mode.ocb.L_star, OCB_BLOCK_LEN);
++      cipher_block_xor_1 (c->u_iv.iv, c->u_mode.ocb.L_star, OCB_BLOCK_LEN);
+       /* Pad = ENCIPHER(K, Offset_*) */
+       nburn = c->spec->encrypt (&c->context.c, pad, c->u_iv.iv);
+       burn = nburn > burn ? nburn : burn;
+@@ -596,7 +598,7 @@ ocb_crypt (gcry_cipher_hd_t c, int encry
+           buf_cpy (l_tmp, inbuf, inbuflen);
+           memset (l_tmp + inbuflen, 0, OCB_BLOCK_LEN - inbuflen);
+           l_tmp[inbuflen] = 0x80;
+-          buf_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN);
+           /* C_* = P_* xor Pad[1..bitlen(P_*)] */
+           buf_xor (outbuf, inbuf, pad, inbuflen);
+         }
+@@ -604,13 +606,13 @@ ocb_crypt (gcry_cipher_hd_t c, int encry
+         {
+           /* P_* = C_* xor Pad[1..bitlen(C_*)] */
+           /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
+-          buf_cpy (l_tmp, pad, OCB_BLOCK_LEN);
++          cipher_block_cpy (l_tmp, pad, OCB_BLOCK_LEN);
+           buf_cpy (l_tmp, inbuf, inbuflen);
+-          buf_xor_1 (l_tmp, pad, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (l_tmp, pad, OCB_BLOCK_LEN);
+           l_tmp[inbuflen] = 0x80;
+           buf_cpy (outbuf, l_tmp, inbuflen);
+ 
+-          buf_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN);
++          cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN);
+         }
+     }
+ 
+@@ -618,8 +620,10 @@ ocb_crypt (gcry_cipher_hd_t c, int encry
+   if (c->marks.finalize)
+     {
+       /* Tag = ENCIPHER(K, Checksum xor Offset xor L_$) xor HASH(K,A) */
+-      buf_xor (c->u_mode.ocb.tag, c->u_ctr.ctr, c->u_iv.iv, OCB_BLOCK_LEN);
+-      buf_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.L_dollar, OCB_BLOCK_LEN);
++      cipher_block_xor (c->u_mode.ocb.tag, c->u_ctr.ctr, c->u_iv.iv,
++                        OCB_BLOCK_LEN);
++      cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.L_dollar,
++                          OCB_BLOCK_LEN);
+       nburn = c->spec->encrypt (&c->context.c,
+                                 c->u_mode.ocb.tag, c->u_mode.ocb.tag);
+       burn = nburn > burn ? nburn : burn;
+@@ -672,7 +676,8 @@ compute_tag_if_needed (gcry_cipher_hd_t
+   if (!c->marks.tag)
+     {
+       ocb_aad_finalize (c);
+-      buf_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum, OCB_BLOCK_LEN);
++      cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum,
++                          OCB_BLOCK_LEN);
+       c->marks.tag = 1;
+     }
+ }
+diff -up libgcrypt-1.8.5/cipher/cipher-ofb.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ofb.c
+--- libgcrypt-1.8.5/cipher/cipher-ofb.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-ofb.c	2020-04-22 18:29:41.668862268 +0200
+@@ -76,7 +76,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd
+       /* Encrypt the IV (and save the current one). */
+       nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+       burn = nburn > burn ? nburn : burn;
+-      buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize);
++      cipher_block_xor(outbuf, c->u_iv.iv, inbuf, blocksize);
+       outbuf += blocksize;
+       inbuf += blocksize;
+       inbuflen -= blocksize;
+diff -up libgcrypt-1.8.5/cipher/cipher-selftest.c.aes-perf libgcrypt-1.8.5/cipher/cipher-selftest.c
+--- libgcrypt-1.8.5/cipher/cipher-selftest.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-selftest.c	2020-04-22 18:29:41.669862248 +0200
+@@ -105,7 +105,7 @@ _gcry_selftest_helper_cbc (const char *c
+   ciphertext = plaintext2 + nblocks * blocksize;
+ 
+   /* Initialize ctx */
+-  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
++  if (setkey_func (ctx, key, sizeof(key), NULL) != GPG_ERR_NO_ERROR)
+    {
+      xfree(mem);
+      return "setkey failed";
+@@ -228,7 +228,7 @@ _gcry_selftest_helper_cfb (const char *c
+   ciphertext = plaintext2 + nblocks * blocksize;
+ 
+   /* Initialize ctx */
+-  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
++  if (setkey_func (ctx, key, sizeof(key), NULL) != GPG_ERR_NO_ERROR)
+    {
+      xfree(mem);
+      return "setkey failed";
+@@ -351,7 +351,7 @@ _gcry_selftest_helper_ctr (const char *c
+   ciphertext2 = ciphertext + nblocks * blocksize;
+ 
+   /* Initialize ctx */
+-  if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR)
++  if (setkey_func (ctx, key, sizeof(key), NULL) != GPG_ERR_NO_ERROR)
+    {
+      xfree(mem);
+      return "setkey failed";
+diff -up libgcrypt-1.8.5/cipher/cipher-xts.c.aes-perf libgcrypt-1.8.5/cipher/cipher-xts.c
+--- libgcrypt-1.8.5/cipher/cipher-xts.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/cipher-xts.c	2020-04-22 18:29:41.669862248 +0200
+@@ -93,7 +93,8 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t
+   /* Use a bulk method if available.  */
+   if (nblocks && c->bulk.xts_crypt)
+     {
+-      c->bulk.xts_crypt (c, c->u_ctr.ctr, outbuf, inbuf, nblocks, encrypt);
++      c->bulk.xts_crypt (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks,
++			 encrypt);
+       inbuf  += nblocks * GCRY_XTS_BLOCK_LEN;
+       outbuf += nblocks * GCRY_XTS_BLOCK_LEN;
+       inbuflen -= nblocks * GCRY_XTS_BLOCK_LEN;
+@@ -106,10 +107,10 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t
+   while (nblocks)
+     {
+       /* Xor-Encrypt/Decrypt-Xor block. */
+-      buf_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
++      cipher_block_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
+       nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1);
+       burn = nburn > burn ? nburn : burn;
+-      buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
++      cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
+ 
+       outbuf += GCRY_XTS_BLOCK_LEN;
+       inbuf += GCRY_XTS_BLOCK_LEN;
+@@ -132,10 +133,10 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t
+ 	  xts_gfmul_byA (tmp.x1, c->u_ctr.ctr);
+ 
+ 	  /* Decrypt last block first. */
+-	  buf_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN);
++	  cipher_block_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN);
+ 	  nburn = crypt_fn (&c->context.c, outbuf, outbuf);
+ 	  burn = nburn > burn ? nburn : burn;
+-	  buf_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN);
++	  cipher_block_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN);
+ 
+ 	  inbuflen -= GCRY_XTS_BLOCK_LEN;
+ 	  inbuf += GCRY_XTS_BLOCK_LEN;
+@@ -146,15 +147,15 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t
+       outbuf -= GCRY_XTS_BLOCK_LEN;
+ 
+       /* Steal ciphertext from previous block. */
+-      buf_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN);
++      cipher_block_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN);
+       buf_cpy (tmp.x64, inbuf, inbuflen);
+       buf_cpy (outbuf + GCRY_XTS_BLOCK_LEN, outbuf, inbuflen);
+ 
+       /* Decrypt/Encrypt last block. */
+-      buf_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
++      cipher_block_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
+       nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1);
+       burn = nburn > burn ? nburn : burn;
+-      buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
++      cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN);
+     }
+ 
+   /* Auto-increment data-unit sequence number */
+@@ -168,3 +169,21 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t
+ 
+   return 0;
+ }
++
++
++gcry_err_code_t
++_gcry_cipher_xts_encrypt (gcry_cipher_hd_t c,
++                          unsigned char *outbuf, size_t outbuflen,
++                          const unsigned char *inbuf, size_t inbuflen)
++{
++  return _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 1);
++}
++
++
++gcry_err_code_t
++_gcry_cipher_xts_decrypt (gcry_cipher_hd_t c,
++                          unsigned char *outbuf, size_t outbuflen,
++                          const unsigned char *inbuf, size_t inbuflen)
++{
++  return _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 0);
++}
+diff -up libgcrypt-1.8.5/cipher/des.c.aes-perf libgcrypt-1.8.5/cipher/des.c
+--- libgcrypt-1.8.5/cipher/des.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/des.c	2020-04-22 18:29:41.669862248 +0200
+@@ -119,6 +119,7 @@
+ #include "g10lib.h"
+ #include "cipher.h"
+ #include "bufhelp.h"
++#include "cipher-internal.h"
+ #include "cipher-selftest.h"
+ 
+ 
+@@ -197,7 +198,8 @@ static unsigned int do_tripledes_encrypt
+ static unsigned int do_tripledes_decrypt(void *context, byte *outbuf,
+ 					 const byte *inbuf );
+ static gcry_err_code_t do_tripledes_setkey(void *context, const byte *key,
+-                                           unsigned keylen);
++                                           unsigned keylen,
++                                           gcry_cipher_hd_t hd);
+ 
+ static int initialized;
+ 
+@@ -940,7 +942,7 @@ _gcry_3des_ctr_enc(void *context, unsign
+       /* Encrypt the counter. */
+       tripledes_ecb_encrypt (ctx, ctr, tmpbuf);
+       /* XOR the input with the encrypted counter and store in output.  */
+-      buf_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE);
++      cipher_block_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE);
+       outbuf += DES_BLOCKSIZE;
+       inbuf  += DES_BLOCKSIZE;
+       /* Increment the counter.  */
+@@ -996,7 +998,7 @@ _gcry_3des_cbc_dec(void *context, unsign
+          the intermediate result to SAVEBUF.  */
+       tripledes_ecb_decrypt (ctx, inbuf, savebuf);
+ 
+-      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE);
++      cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE);
+       inbuf += DES_BLOCKSIZE;
+       outbuf += DES_BLOCKSIZE;
+     }
+@@ -1041,7 +1043,7 @@ _gcry_3des_cfb_dec(void *context, unsign
+   for ( ;nblocks; nblocks-- )
+     {
+       tripledes_ecb_encrypt (ctx, iv, iv);
+-      buf_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE);
++      cipher_block_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE);
+       outbuf += DES_BLOCKSIZE;
+       inbuf  += DES_BLOCKSIZE;
+     }
+@@ -1086,7 +1088,8 @@ is_weak_key ( const byte *key )
+ 
+ /* Alternative setkey for selftests; need larger key than default. */
+ static gcry_err_code_t
+-bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen)
++bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen,
++                      gcry_cipher_hd_t hd)
+ {
+   static const unsigned char key[24] ATTR_ALIGNED_16 = {
+       0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,
+@@ -1094,10 +1097,11 @@ bulk_selftest_setkey (void *context, con
+       0x18,0x2A,0x39,0x47,0x5E,0x6F,0x75,0x82
+     };
+ 
++  (void)hd;
+   (void)__key;
+   (void)__keylen;
+ 
+-  return do_tripledes_setkey(context, key, sizeof(key));
++  return do_tripledes_setkey(context, key, sizeof(key), NULL);
+ }
+ 
+ 
+@@ -1349,10 +1353,13 @@ selftest (void)
+ 
+ 
+ static gcry_err_code_t
+-do_tripledes_setkey ( void *context, const byte *key, unsigned keylen )
++do_tripledes_setkey ( void *context, const byte *key, unsigned keylen,
++                      gcry_cipher_hd_t hd )
+ {
+   struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context;
+ 
++  (void)hd;
++
+   if( keylen != 24 )
+     return GPG_ERR_INV_KEYLEN;
+ 
+@@ -1413,10 +1420,13 @@ do_tripledes_decrypt( void *context, byt
+ }
+ 
+ static gcry_err_code_t
+-do_des_setkey (void *context, const byte *key, unsigned keylen)
++do_des_setkey (void *context, const byte *key, unsigned keylen,
++               gcry_cipher_hd_t hd)
+ {
+   struct _des_ctx *ctx = (struct _des_ctx *) context;
+ 
++  (void)hd;
++
+   if (keylen != 8)
+     return GPG_ERR_INV_KEYLEN;
+ 
+diff -up libgcrypt-1.8.5/cipher/gost28147.c.aes-perf libgcrypt-1.8.5/cipher/gost28147.c
+--- libgcrypt-1.8.5/cipher/gost28147.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/gost28147.c	2020-04-22 18:29:41.669862248 +0200
+@@ -39,11 +39,14 @@
+ #include "gost-sb.h"
+ 
+ static gcry_err_code_t
+-gost_setkey (void *c, const byte *key, unsigned keylen)
++gost_setkey (void *c, const byte *key, unsigned keylen,
++             gcry_cipher_hd_t hd)
+ {
+   int i;
+   GOST28147_context *ctx = c;
+ 
++  (void)hd;
++
+   if (keylen != 256 / 8)
+     return GPG_ERR_INV_KEYLEN;
+ 
+diff -up libgcrypt-1.8.5/cipher/idea.c.aes-perf libgcrypt-1.8.5/cipher/idea.c
+--- libgcrypt-1.8.5/cipher/idea.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/idea.c	2020-04-22 18:29:41.670862229 +0200
+@@ -258,10 +258,12 @@ do_setkey( IDEA_context *c, const byte *
+ }
+ 
+ static gcry_err_code_t
+-idea_setkey (void *context, const byte *key, unsigned int keylen)
++idea_setkey (void *context, const byte *key, unsigned int keylen,
++             gcry_cipher_hd_t hd)
+ {
+     IDEA_context *ctx = context;
+     int rc = do_setkey (ctx, key, keylen);
++    (void)hd;
+     _gcry_burn_stack (23+6*sizeof(void*));
+     return rc;
+ }
+diff -up libgcrypt-1.8.5/cipher/Makefile.am.aes-perf libgcrypt-1.8.5/cipher/Makefile.am
+--- libgcrypt-1.8.5/cipher/Makefile.am.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/Makefile.am	2020-04-22 18:29:41.670862229 +0200
+@@ -83,7 +83,8 @@ rijndael.c rijndael-internal.h rijndael-
+   rijndael-padlock.c rijndael-amd64.S rijndael-arm.S \
+   rijndael-ssse3-amd64.c rijndael-ssse3-amd64-asm.S \
+   rijndael-armv8-ce.c rijndael-armv8-aarch32-ce.S rijndael-armv8-aarch64-ce.S \
+-  rijndael-aarch64.S \
++  rijndael-aarch64.S rijndael-ppc.c rijndael-ppc9le.c \
++  rijndael-ppc-common.h rijndael-ppc-functions.h \
+ rmd160.c \
+ rsa.c \
+ salsa20.c salsa20-amd64.S salsa20-armv7-neon.S \
+@@ -128,3 +129,23 @@ tiger.o: $(srcdir)/tiger.c
+ 
+ tiger.lo: $(srcdir)/tiger.c
+ 	`echo $(LTCOMPILE) -c $(srcdir)/tiger.c | $(o_flag_munging) `
++
++if ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS
++ppc_vcrypto_cflags = -maltivec -mvsx -mcrypto
++else
++ppc_vcrypto_cflags =
++endif
++
++rijndael-ppc.o: $(srcdir)/rijndael-ppc.c Makefile
++	`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< `
++
++rijndael-ppc.lo: $(srcdir)/rijndael-ppc.c Makefile
++	`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< `
++
++rijndael-ppc9le.o: $(srcdir)/rijndael-ppc9le.c Makefile
++	`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< `
++
++rijndael-ppc9le.lo: $(srcdir)/rijndael-ppc9le.c Makefile
++	`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< `
++
++
+diff -up libgcrypt-1.8.5/cipher/rfc2268.c.aes-perf libgcrypt-1.8.5/cipher/rfc2268.c
+--- libgcrypt-1.8.5/cipher/rfc2268.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rfc2268.c	2020-04-22 18:29:41.670862229 +0200
+@@ -262,8 +262,10 @@ setkey_core (void *context, const unsign
+ }
+ 
+ static gpg_err_code_t
+-do_setkey (void *context, const unsigned char *key, unsigned int keylen)
++do_setkey (void *context, const unsigned char *key, unsigned int keylen,
++           gcry_cipher_hd_t hd)
+ {
++  (void)hd;
+   return setkey_core (context, key, keylen, 1);
+ }
+ 
+diff -up libgcrypt-1.8.5/cipher/rijndael-aesni.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-aesni.c
+--- libgcrypt-1.8.5/cipher/rijndael-aesni.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rijndael-aesni.c	2020-04-28 11:22:26.025519954 +0200
+@@ -327,8 +327,8 @@ _gcry_aes_aesni_do_setkey (RIJNDAEL_cont
+ 
+ 
+ /* Make a decryption key from an encryption key. */
+-void
+-_gcry_aes_aesni_prepare_decryption (RIJNDAEL_context *ctx)
++static inline void
++do_aesni_prepare_decryption (RIJNDAEL_context *ctx)
+ {
+   /* The AES-NI decrypt instructions use the Equivalent Inverse
+      Cipher, thus we can't use the the standard decrypt key
+@@ -338,8 +338,6 @@ _gcry_aes_aesni_prepare_decryption (RIJN
+   int rr;
+   int r;
+ 
+-  aesni_prepare();
+-
+ #define DO_AESNI_AESIMC() \
+   asm volatile ("movdqa %[ekey], %%xmm1\n\t" \
+                 /*"aesimc %%xmm1, %%xmm1\n\t"*/ \
+@@ -375,7 +373,13 @@ _gcry_aes_aesni_prepare_decryption (RIJN
+   dkey[r] = ekey[0];
+ 
+ #undef DO_AESNI_AESIMC
++}
+ 
++void
++_gcry_aes_aesni_prepare_decryption (RIJNDAEL_context *ctx)
++{
++  aesni_prepare();
++  do_aesni_prepare_decryption (ctx);
+   aesni_cleanup();
+ }
+ 
+@@ -1023,8 +1027,8 @@ _gcry_aes_aesni_encrypt (const RIJNDAEL_
+ 
+ 
+ void
+-_gcry_aes_aesni_cfb_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                         const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_aesni_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
+                          size_t nblocks)
+ {
+   aesni_prepare ();
+@@ -1059,8 +1063,8 @@ _gcry_aes_aesni_cfb_enc (RIJNDAEL_contex
+ 
+ 
+ void
+-_gcry_aes_aesni_cbc_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                         const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_aesni_cbc_enc (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
+                          size_t nblocks, int cbc_mac)
+ {
+   aesni_prepare_2_6_variable;
+@@ -1105,8 +1109,8 @@ _gcry_aes_aesni_cbc_enc (RIJNDAEL_contex
+ 
+ 
+ void
+-_gcry_aes_aesni_ctr_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                         const unsigned char *inbuf, unsigned char *ctr,
++_gcry_aes_aesni_ctr_enc (RIJNDAEL_context *ctx, unsigned char *ctr,
++                         unsigned char *outbuf, const unsigned char *inbuf,
+                          size_t nblocks)
+ {
+   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
+@@ -1160,8 +1164,8 @@ _gcry_aes_aesni_decrypt (const RIJNDAEL_
+ 
+ 
+ void
+-_gcry_aes_aesni_cfb_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                         const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_aesni_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
+                          size_t nblocks)
+ {
+   aesni_prepare_2_6_variable;
+@@ -1245,15 +1249,21 @@ _gcry_aes_aesni_cfb_dec (RIJNDAEL_contex
+ 
+ 
+ void
+-_gcry_aes_aesni_cbc_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-			 const unsigned char *inbuf, unsigned char *iv,
+-			 size_t nblocks)
++_gcry_aes_aesni_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
++                         size_t nblocks)
+ {
+   aesni_prepare_2_6_variable;
+ 
+   aesni_prepare ();
+   aesni_prepare_2_6();
+ 
++  if ( !ctx->decryption_prepared )
++    {
++      do_aesni_prepare_decryption ( ctx );
++      ctx->decryption_prepared = 1;
++    }
++
+   asm volatile
+     ("movdqu %[iv], %%xmm5\n\t"	/* use xmm5 as fast IV storage */
+      : /* No output */
+@@ -1514,6 +1524,12 @@ aesni_ocb_dec (gcry_cipher_hd_t c, void
+   aesni_prepare ();
+   aesni_prepare_2_6 ();
+ 
++  if ( !ctx->decryption_prepared )
++    {
++      do_aesni_prepare_decryption ( ctx );
++      ctx->decryption_prepared = 1;
++    }
++
+   /* Preload Offset and Checksum */
+   asm volatile ("movdqu %[iv], %%xmm5\n\t"
+                 "movdqu %[ctr], %%xmm6\n\t"
+@@ -1665,7 +1681,7 @@ aesni_ocb_dec (gcry_cipher_hd_t c, void
+ }
+ 
+ 
+-void
++size_t
+ _gcry_aes_aesni_ocb_crypt(gcry_cipher_hd_t c, void *outbuf_arg,
+                           const void *inbuf_arg, size_t nblocks, int encrypt)
+ {
+@@ -1673,10 +1689,12 @@ _gcry_aes_aesni_ocb_crypt(gcry_cipher_hd
+     aesni_ocb_enc(c, outbuf_arg, inbuf_arg, nblocks);
+   else
+     aesni_ocb_dec(c, outbuf_arg, inbuf_arg, nblocks);
++
++  return 0;
+ }
+ 
+ 
+-void
++size_t
+ _gcry_aes_aesni_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
+                           size_t nblocks)
+ {
+@@ -1810,7 +1828,306 @@ _gcry_aes_aesni_ocb_auth (gcry_cipher_hd
+ 
+   aesni_cleanup ();
+   aesni_cleanup_2_6 ();
++
++  return 0;
+ }
+ 
+ 
++static const u64 xts_gfmul_const[16] __attribute__ ((aligned (16))) =
++  { 0x87, 0x01 };
++
++
++static void
++_gcry_aes_aesni_xts_enc (RIJNDAEL_context *ctx, unsigned char *tweak,
++			 unsigned char *outbuf, const unsigned char *inbuf,
++			 size_t nblocks)
++{
++  aesni_prepare_2_6_variable;
++
++  aesni_prepare ();
++  aesni_prepare_2_6 ();
++
++  /* Preload Tweak */
++  asm volatile ("movdqu %[tweak], %%xmm5\n\t"
++		"movdqa %[gfmul], %%xmm6\n\t"
++		:
++		: [tweak] "m" (*tweak),
++		  [gfmul] "m" (*xts_gfmul_const)
++		: "memory" );
++
++  for ( ;nblocks >= 4; nblocks -= 4 )
++    {
++      asm volatile ("pshufd $0x13,     %%xmm5,  %%xmm4\n\t"
++		    "movdqu %[inbuf0], %%xmm1\n\t"
++		    "pxor   %%xmm5,    %%xmm1\n\t"
++		    "movdqu %%xmm5,    %[outbuf0]\n\t"
++
++		    "movdqa %%xmm4,    %%xmm0\n\t"
++		    "paddd  %%xmm4,    %%xmm4\n\t"
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf0] "=m" (*(outbuf + 0 * 16))
++		    : [inbuf0] "m" (*(inbuf + 0 * 16))
++		    : "memory" );
++
++      asm volatile ("movdqu %[inbuf1], %%xmm2\n\t"
++		    "pxor   %%xmm5,    %%xmm2\n\t"
++		    "movdqu %%xmm5,    %[outbuf1]\n\t"
++
++		    "movdqa %%xmm4,    %%xmm0\n\t"
++		    "paddd  %%xmm4,    %%xmm4\n\t"
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf1] "=m" (*(outbuf + 1 * 16))
++		    : [inbuf1] "m" (*(inbuf + 1 * 16))
++		    : "memory" );
++
++      asm volatile ("movdqu %[inbuf2], %%xmm3\n\t"
++		    "pxor   %%xmm5,    %%xmm3\n\t"
++		    "movdqu %%xmm5,    %[outbuf2]\n\t"
++
++		    "movdqa %%xmm4,    %%xmm0\n\t"
++		    "paddd  %%xmm4,    %%xmm4\n\t"
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf2] "=m" (*(outbuf + 2 * 16))
++		    : [inbuf2] "m" (*(inbuf + 2 * 16))
++		    : "memory" );
++
++      asm volatile ("movdqa %%xmm4,    %%xmm0\n\t"
++		    "movdqu %[inbuf3], %%xmm4\n\t"
++		    "pxor   %%xmm5,    %%xmm4\n\t"
++		    "movdqu %%xmm5,    %[outbuf3]\n\t"
++
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf3] "=m" (*(outbuf + 3 * 16))
++		    : [inbuf3] "m" (*(inbuf + 3 * 16))
++		    : "memory" );
++
++      do_aesni_enc_vec4 (ctx);
++
++      asm volatile ("movdqu %[outbuf0], %%xmm0\n\t"
++                    "pxor   %%xmm0,     %%xmm1\n\t"
++		    "movdqu %[outbuf1], %%xmm0\n\t"
++		    "movdqu %%xmm1,     %[outbuf0]\n\t"
++		    "movdqu %[outbuf2], %%xmm1\n\t"
++                    "pxor   %%xmm0,     %%xmm2\n\t"
++		    "movdqu %[outbuf3], %%xmm0\n\t"
++                    "pxor   %%xmm1,     %%xmm3\n\t"
++                    "pxor   %%xmm0,     %%xmm4\n\t"
++		    "movdqu %%xmm2,     %[outbuf1]\n\t"
++		    "movdqu %%xmm3,     %[outbuf2]\n\t"
++		    "movdqu %%xmm4,     %[outbuf3]\n\t"
++		    : [outbuf0] "+m" (*(outbuf + 0 * 16)),
++		      [outbuf1] "+m" (*(outbuf + 1 * 16)),
++		      [outbuf2] "+m" (*(outbuf + 2 * 16)),
++		      [outbuf3] "+m" (*(outbuf + 3 * 16))
++		    :
++		    : "memory" );
++
++      outbuf += BLOCKSIZE * 4;
++      inbuf += BLOCKSIZE * 4;
++    }
++
++  for ( ;nblocks; nblocks-- )
++    {
++      asm volatile ("movdqu %[inbuf],  %%xmm0\n\t"
++		    "pxor   %%xmm5,    %%xmm0\n\t"
++		    "movdqa %%xmm5,    %%xmm4\n\t"
++
++		    "pshufd $0x13,     %%xmm5,  %%xmm1\n\t"
++		    "psrad  $31,       %%xmm1\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm1\n\t"
++		    "pxor   %%xmm1,    %%xmm5\n\t"
++		    :
++		    : [inbuf] "m" (*inbuf)
++		    : "memory" );
++
++      do_aesni_enc (ctx);
++
++      asm volatile ("pxor   %%xmm4,    %%xmm0\n\t"
++		    "movdqu %%xmm0,    %[outbuf]\n\t"
++		    : [outbuf] "=m" (*outbuf)
++		    :
++		    : "memory" );
++
++      outbuf += BLOCKSIZE;
++      inbuf += BLOCKSIZE;
++    }
++
++  asm volatile ("movdqu %%xmm5, %[tweak]\n\t"
++		: [tweak] "=m" (*tweak)
++		:
++		: "memory" );
++
++  aesni_cleanup ();
++  aesni_cleanup_2_6 ();
++}
++
++
++static void
++_gcry_aes_aesni_xts_dec (RIJNDAEL_context *ctx, unsigned char *tweak,
++			 unsigned char *outbuf, const unsigned char *inbuf,
++			 size_t nblocks)
++{
++  aesni_prepare_2_6_variable;
++
++  aesni_prepare ();
++  aesni_prepare_2_6 ();
++
++  if ( !ctx->decryption_prepared )
++    {
++      do_aesni_prepare_decryption ( ctx );
++      ctx->decryption_prepared = 1;
++    }
++
++  /* Preload Tweak */
++  asm volatile ("movdqu %[tweak], %%xmm5\n\t"
++		"movdqa %[gfmul], %%xmm6\n\t"
++		:
++		: [tweak] "m" (*tweak),
++		  [gfmul] "m" (*xts_gfmul_const)
++		: "memory" );
++
++  for ( ;nblocks >= 4; nblocks -= 4 )
++    {
++      asm volatile ("pshufd $0x13,     %%xmm5,  %%xmm4\n\t"
++		    "movdqu %[inbuf0], %%xmm1\n\t"
++		    "pxor   %%xmm5,    %%xmm1\n\t"
++		    "movdqu %%xmm5,    %[outbuf0]\n\t"
++
++		    "movdqa %%xmm4,    %%xmm0\n\t"
++		    "paddd  %%xmm4,    %%xmm4\n\t"
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf0] "=m" (*(outbuf + 0 * 16))
++		    : [inbuf0] "m" (*(inbuf + 0 * 16))
++		    : "memory" );
++
++      asm volatile ("movdqu %[inbuf1], %%xmm2\n\t"
++		    "pxor   %%xmm5,    %%xmm2\n\t"
++		    "movdqu %%xmm5,    %[outbuf1]\n\t"
++
++		    "movdqa %%xmm4,    %%xmm0\n\t"
++		    "paddd  %%xmm4,    %%xmm4\n\t"
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf1] "=m" (*(outbuf + 1 * 16))
++		    : [inbuf1] "m" (*(inbuf + 1 * 16))
++		    : "memory" );
++
++      asm volatile ("movdqu %[inbuf2], %%xmm3\n\t"
++		    "pxor   %%xmm5,    %%xmm3\n\t"
++		    "movdqu %%xmm5,    %[outbuf2]\n\t"
++
++		    "movdqa %%xmm4,    %%xmm0\n\t"
++		    "paddd  %%xmm4,    %%xmm4\n\t"
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf2] "=m" (*(outbuf + 2 * 16))
++		    : [inbuf2] "m" (*(inbuf + 2 * 16))
++		    : "memory" );
++
++      asm volatile ("movdqa %%xmm4,    %%xmm0\n\t"
++		    "movdqu %[inbuf3], %%xmm4\n\t"
++		    "pxor   %%xmm5,    %%xmm4\n\t"
++		    "movdqu %%xmm5,    %[outbuf3]\n\t"
++
++		    "psrad  $31,       %%xmm0\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm0\n\t"
++		    "pxor   %%xmm0,    %%xmm5\n\t"
++		    : [outbuf3] "=m" (*(outbuf + 3 * 16))
++		    : [inbuf3] "m" (*(inbuf + 3 * 16))
++		    : "memory" );
++
++      do_aesni_dec_vec4 (ctx);
++
++      asm volatile ("movdqu %[outbuf0], %%xmm0\n\t"
++                    "pxor   %%xmm0,     %%xmm1\n\t"
++		    "movdqu %[outbuf1], %%xmm0\n\t"
++		    "movdqu %%xmm1,     %[outbuf0]\n\t"
++		    "movdqu %[outbuf2], %%xmm1\n\t"
++                    "pxor   %%xmm0,     %%xmm2\n\t"
++		    "movdqu %[outbuf3], %%xmm0\n\t"
++                    "pxor   %%xmm1,     %%xmm3\n\t"
++                    "pxor   %%xmm0,     %%xmm4\n\t"
++		    "movdqu %%xmm2,     %[outbuf1]\n\t"
++		    "movdqu %%xmm3,     %[outbuf2]\n\t"
++		    "movdqu %%xmm4,     %[outbuf3]\n\t"
++		    : [outbuf0] "+m" (*(outbuf + 0 * 16)),
++		      [outbuf1] "+m" (*(outbuf + 1 * 16)),
++		      [outbuf2] "+m" (*(outbuf + 2 * 16)),
++		      [outbuf3] "+m" (*(outbuf + 3 * 16))
++		    :
++		    : "memory" );
++
++      outbuf += BLOCKSIZE * 4;
++      inbuf += BLOCKSIZE * 4;
++    }
++
++  for ( ;nblocks; nblocks-- )
++    {
++      asm volatile ("movdqu %[inbuf],  %%xmm0\n\t"
++		    "pxor   %%xmm5,    %%xmm0\n\t"
++		    "movdqa %%xmm5,    %%xmm4\n\t"
++
++		    "pshufd $0x13,     %%xmm5,  %%xmm1\n\t"
++		    "psrad  $31,       %%xmm1\n\t"
++		    "paddq  %%xmm5,    %%xmm5\n\t"
++		    "pand   %%xmm6,    %%xmm1\n\t"
++		    "pxor   %%xmm1,    %%xmm5\n\t"
++		    :
++		    : [inbuf] "m" (*inbuf)
++		    : "memory" );
++
++      do_aesni_dec (ctx);
++
++      asm volatile ("pxor   %%xmm4,    %%xmm0\n\t"
++		    "movdqu %%xmm0,    %[outbuf]\n\t"
++		    : [outbuf] "=m" (*outbuf)
++		    :
++		    : "memory" );
++
++      outbuf += BLOCKSIZE;
++      inbuf += BLOCKSIZE;
++    }
++
++  asm volatile ("movdqu %%xmm5, %[tweak]\n\t"
++                : [tweak] "=m" (*tweak)
++                :
++                : "memory" );
++
++  aesni_cleanup ();
++  aesni_cleanup_2_6 ();
++}
++
++
++void
++_gcry_aes_aesni_xts_crypt (RIJNDAEL_context *ctx, unsigned char *tweak,
++			   unsigned char *outbuf, const unsigned char *inbuf,
++			   size_t nblocks, int encrypt)
++{
++  if (encrypt)
++    _gcry_aes_aesni_xts_enc(ctx, tweak, outbuf, inbuf, nblocks);
++  else
++    _gcry_aes_aesni_xts_dec(ctx, tweak, outbuf, inbuf, nblocks);
++}
++
+ #endif /* USE_AESNI */
+diff -up libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S.aes-perf libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S
+--- libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S	2020-04-22 18:29:41.673862172 +0200
+@@ -1517,6 +1517,317 @@ _gcry_aes_ocb_auth_armv8_ce:
+ .size _gcry_aes_ocb_auth_armv8_ce,.-_gcry_aes_ocb_auth_armv8_ce;
+ 
+ 
++
++/*
++ * void _gcry_aes_xts_enc_armv8_ce (const void *keysched,
++ *                                  unsigned char *outbuf,
++ *                                  const unsigned char *inbuf,
++ *                                  unsigned char *iv, unsigned int nrounds);
++ */
++
++.align 3
++.globl _gcry_aes_xts_enc_armv8_ce
++.type  _gcry_aes_xts_enc_armv8_ce,%function;
++_gcry_aes_xts_enc_armv8_ce:
++  /* input:
++   *    r0: keysched
++   *    r1: outbuf
++   *    r2: inbuf
++   *    r3: iv
++   *    %st+0: nblocks => r4
++   *    %st+4: nrounds => r5
++   */
++
++  vpush {q4-q7}
++  push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
++  ldr r4, [sp, #(104+0)]
++  ldr r5, [sp, #(104+4)]
++  cmp r4, #0
++  beq .Lxts_enc_skip
++
++  cmp r5, #12
++
++  vld1.8 {q0}, [r3] /* load tweak */
++  mov r7, #0x87;
++
++  aes_preload_keys(r0, r6);
++
++  beq .Lxts_enc_entry_192
++  bhi .Lxts_enc_entry_256
++
++#define CTR_XTS(bits, ...) \
++  .Lxts_enc_entry_##bits: \
++    cmp r4, #4; \
++    blo .Lxts_enc_loop_##bits; \
++    \
++  .Lxts_enc_loop4_##bits: \
++    sub r4, r4, #4; \
++    veor q9, q9, q9; \
++    \
++    vld1.8 {q1-q2}, [r2]!; /* load plaintext */ \
++    veor q1, q1, q0; \
++    cmp r4, #4; \
++    vmov.u32 d18[0], r7; \
++    vst1.8 {q0}, [r1]!; /* store tweak0 to temp */ \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    vld1.8 {q3-q4}, [r2]!; /* load plaintext */ \
++    veor q2, q2, q0; \
++    vst1.8 {q0}, [r1]!; /* store tweak1 to temp */ \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    veor q3, q3, q0; \
++    vst1.8 {q0}, [r1]!; /* store tweak2 to temp */ \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    veor q4, q4, q0; \
++    vst1.8 {q0}, [r1]; /* store tweak3 to temp */ \
++    sub r1, r1, #48; \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \
++    \
++    vld1.8 {q8-q9}, [r1]!; /* load tweak from temp */ \
++    veor q1, q1, q8; \
++    veor q2, q2, q9; \
++    vld1.8 {q8-q9}, [r1]; /* load tweak from temp */ \
++    sub r1, r1, #32; \
++    veor q3, q3, q8; \
++    veor q4, q4, q9; \
++    vst1.8 {q1-q2}, [r1]!; /* store plaintext */ \
++    vst1.8 {q3-q4}, [r1]!; /* store plaintext */ \
++    \
++    bhs .Lxts_enc_loop4_##bits; \
++    cmp r4, #0; \
++    beq .Lxts_enc_done; \
++    \
++  .Lxts_enc_loop_##bits: \
++    \
++    vld1.8 {q1}, [r2]!; /* load ciphertext */ \
++    \
++    veor q9, q9, q9; \
++    veor q1, q1, q0; \
++    vmov.u32 d18[0], r7; \
++    vmov q2, q0; \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    subs r4, r4, #1; \
++    \
++    do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__); \
++    \
++    veor q1, q1, q2; \
++    vst1.8 {q1}, [r1]!; /* store plaintext */ \
++    \
++    bne .Lxts_enc_loop_##bits; \
++    b .Lxts_enc_done;
++
++  CTR_XTS(128re, r0, r6)
++  CTR_XTS(192, r0, r6)
++  CTR_XTS(256, r0, r6)
++
++#undef CTR_XTS
++
++.Lxts_enc_done:
++  vst1.8 {q0}, [r3] /* store tweak */
++
++  CLEAR_REG(q0)
++  CLEAR_REG(q1)
++  CLEAR_REG(q2)
++  CLEAR_REG(q3)
++  CLEAR_REG(q8)
++  CLEAR_REG(q9)
++  CLEAR_REG(q10)
++  CLEAR_REG(q11)
++  CLEAR_REG(q12)
++  CLEAR_REG(q13)
++  CLEAR_REG(q14)
++
++.Lxts_enc_skip:
++  pop {r4-r12,lr}
++  vpop {q4-q7}
++  bx lr
++.size _gcry_aes_xts_enc_armv8_ce,.-_gcry_aes_xts_enc_armv8_ce;
++
++
++/*
++ * void _gcry_aes_xts_dec_armv8_ce (const void *keysched,
++ *                                  unsigned char *outbuf,
++ *                                  const unsigned char *inbuf,
++ *                                  unsigned char *iv, unsigned int nrounds);
++ */
++
++.align 3
++.globl _gcry_aes_xts_dec_armv8_ce
++.type  _gcry_aes_xts_dec_armv8_ce,%function;
++_gcry_aes_xts_dec_armv8_ce:
++  /* input:
++   *    r0: keysched
++   *    r1: outbuf
++   *    r2: inbuf
++   *    r3: iv
++   *    %st+0: nblocks => r4
++   *    %st+4: nrounds => r5
++   */
++
++  vpush {q4-q7}
++  push {r4-r12,lr} /* 4*16 + 4*10 = 104b */
++  ldr r4, [sp, #(104+0)]
++  ldr r5, [sp, #(104+4)]
++  cmp r4, #0
++  beq .Lxts_dec_skip
++
++  cmp r5, #12
++
++  vld1.8 {q0}, [r3] /* load tweak */
++  mov r7, #0x87;
++
++  aes_preload_keys(r0, r6);
++
++  beq .Lxts_dec_entry_192
++  bhi .Lxts_dec_entry_256
++
++#define CTR_XTS(bits, ...) \
++  .Lxts_dec_entry_##bits: \
++    cmp r4, #4; \
++    blo .Lxts_dec_loop_##bits; \
++    \
++  .Lxts_dec_loop4_##bits: \
++    sub r4, r4, #4; \
++    veor q9, q9, q9; \
++    \
++    vld1.8 {q1-q2}, [r2]!; /* load plaintext */ \
++    veor q1, q1, q0; \
++    cmp r4, #4; \
++    vmov.u32 d18[0], r7; \
++    vst1.8 {q0}, [r1]!; /* store tweak0 to temp */ \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    vld1.8 {q3-q4}, [r2]!; /* load plaintext */ \
++    veor q2, q2, q0; \
++    vst1.8 {q0}, [r1]!; /* store tweak1 to temp */ \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    veor q3, q3, q0; \
++    vst1.8 {q0}, [r1]!; /* store tweak2 to temp */ \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    veor q4, q4, q0; \
++    vst1.8 {q0}, [r1]; /* store tweak3 to temp */ \
++    sub r1, r1, #48; \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    \
++    do_aes_4_##bits(d, imc, q1, q2, q3, q4, ##__VA_ARGS__); \
++    \
++    vld1.8 {q8-q9}, [r1]!; /* load tweak from temp */ \
++    veor q1, q1, q8; \
++    veor q2, q2, q9; \
++    vld1.8 {q8-q9}, [r1]; /* load tweak from temp */ \
++    sub r1, r1, #32; \
++    veor q3, q3, q8; \
++    veor q4, q4, q9; \
++    vst1.8 {q1-q2}, [r1]!; /* store plaintext */ \
++    vst1.8 {q3-q4}, [r1]!; /* store plaintext */ \
++    \
++    bhs .Lxts_dec_loop4_##bits; \
++    cmp r4, #0; \
++    beq .Lxts_dec_done; \
++    \
++  .Lxts_dec_loop_##bits: \
++    \
++    vld1.8 {q1}, [r2]!; /* load ciphertext */ \
++    \
++    veor q9, q9, q9; \
++    veor q1, q1, q0; \
++    vmov.u32 d18[0], r7; \
++    vmov q2, q0; \
++    \
++    vshr.s64 d16, d1, #63; \
++    vshr.u64 d17, d0, #63; \
++    vadd.u64 q0, q0, q0; \
++    vand d16, d16, d18; \
++    veor q0, q0, q8; \
++    subs r4, r4, #1; \
++    \
++    do_aes_one##bits(d, imc, q1, q1, ##__VA_ARGS__); \
++    \
++    veor q1, q1, q2; \
++    vst1.8 {q1}, [r1]!; /* store plaintext */ \
++    \
++    bne .Lxts_dec_loop_##bits; \
++    b .Lxts_dec_done;
++
++  CTR_XTS(128re, r0, r6)
++  CTR_XTS(192, r0, r6)
++  CTR_XTS(256, r0, r6)
++
++#undef CTR_XTS
++
++.Lxts_dec_done:
++  vst1.8 {q0}, [r3] /* store tweak */
++
++  CLEAR_REG(q0)
++  CLEAR_REG(q1)
++  CLEAR_REG(q2)
++  CLEAR_REG(q3)
++  CLEAR_REG(q8)
++  CLEAR_REG(q9)
++  CLEAR_REG(q10)
++  CLEAR_REG(q11)
++  CLEAR_REG(q12)
++  CLEAR_REG(q13)
++  CLEAR_REG(q14)
++
++.Lxts_dec_skip:
++  pop {r4-r12,lr}
++  vpop {q4-q7}
++  bx lr
++.size _gcry_aes_xts_dec_armv8_ce,.-_gcry_aes_xts_dec_armv8_ce;
++
++
+ /*
+  * u32 _gcry_aes_sbox4_armv8_ce(u32 in4b);
+  */
+diff -up libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S.aes-perf libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S
+--- libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S	2020-04-22 18:29:41.674862153 +0200
+@@ -1157,8 +1157,8 @@ _gcry_aes_ocb_auth_armv8_ce:
+    *    w6: nrounds => w7
+    *    w7: blkn => w12
+    */
+-  mov x12, x7
+-  mov x7, x6
++  mov w12, w7
++  mov w7, w6
+   mov x6, x5
+   mov x5, x4
+   mov x4, x3
+@@ -1277,6 +1277,284 @@ _gcry_aes_ocb_auth_armv8_ce:
+ 
+ 
+ /*
++ * void _gcry_aes_xts_enc_armv8_ce (const void *keysched,
++ *                                  unsigned char *outbuf,
++ *                                  const unsigned char *inbuf,
++ *                                  unsigned char *tweak,
++ *                                  size_t nblocks,
++ *                                  unsigned int nrounds);
++ */
++
++.align 3
++.globl _gcry_aes_xts_enc_armv8_ce
++.type  _gcry_aes_xts_enc_armv8_ce,%function;
++_gcry_aes_xts_enc_armv8_ce:
++  /* input:
++   *    r0: keysched
++   *    r1: outbuf
++   *    r2: inbuf
++   *    r3: tweak
++   *    x4: nblocks
++   *    w5: nrounds
++   */
++
++  cbz x4, .Lxts_enc_skip
++
++  /* load tweak */
++  ld1 {v0.16b}, [x3]
++
++  /* load gfmul mask */
++  mov x6, #0x87
++  mov x7, #0x01
++  mov v16.D[0], x6
++  mov v16.D[1], x7
++
++  aes_preload_keys(x0, w5);
++
++  b.eq .Lxts_enc_entry_192
++  b.hi .Lxts_enc_entry_256
++
++#define XTS_ENC(bits) \
++  .Lxts_enc_entry_##bits: \
++    cmp x4, #4; \
++    b.lo .Lxts_enc_loop_##bits; \
++    \
++  .Lxts_enc_loop4_##bits: \
++    \
++    ext v4.16b, v0.16b, v0.16b, #8; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v5.2d, v0.2d, v0.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v5.16b, v5.16b, v2.16b; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v6.2d, v5.2d, v5.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v6.16b, v6.16b, v2.16b; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v7.2d, v6.2d, v6.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v7.16b, v7.16b, v2.16b; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v3.2d, v7.2d, v7.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v3.16b, v3.16b, v2.16b; \
++    ld1 {v1.16b-v2.16b}, [x2], #32; /* load plaintext */ \
++    st1 {v3.16b}, [x3]; \
++    sub x4, x4, #4; \
++    eor v1.16b, v1.16b, v0.16b; \
++    \
++    ld1 {v3.16b-v4.16b}, [x2], #32; /* load plaintext */ \
++    cmp x4, #4; \
++    eor v2.16b, v2.16b, v5.16b; \
++    eor v3.16b, v3.16b, v6.16b; \
++    eor v4.16b, v4.16b, v7.16b; \
++    \
++    do_aes_4_##bits(e, mc, v1, v2, v3, v4); \
++    \
++    eor v1.16b, v1.16b, v0.16b; \
++    ld1 {v0.16b}, [x3]; \
++    eor v2.16b, v2.16b, v5.16b; \
++    eor v3.16b, v3.16b, v6.16b; \
++    eor v4.16b, v4.16b, v7.16b; \
++    st1 {v1.16b-v4.16b}, [x1], #64; /* store plaintext */ \
++    \
++    b.hs .Lxts_enc_loop4_##bits; \
++    CLEAR_REG(v3); \
++    CLEAR_REG(v4); \
++    CLEAR_REG(v5); \
++    CLEAR_REG(v6); \
++    CLEAR_REG(v7); \
++    cbz x4, .Lxts_enc_done; \
++    \
++  .Lxts_enc_loop_##bits: \
++    \
++    ld1 {v1.16b}, [x2], #16; /* load plaintext */ \
++    ext v3.16b, v0.16b, v0.16b, #8; \
++    mov v2.16b, v0.16b; \
++    sshr v3.2d, v3.2d, #63; \
++    add v0.2d, v0.2d, v0.2d; \
++    and v3.16b, v3.16b, v16.16b; \
++    eor v1.16b, v1.16b, v2.16b; \
++    eor v0.16b, v0.16b, v3.16b; \
++    sub x4, x4, #1; \
++    \
++    do_aes_one##bits(e, mc, v1, v1); \
++    \
++    eor v1.16b, v1.16b, v2.16b; \
++    st1 {v1.16b}, [x1], #16; /* store ciphertext */ \
++    \
++    cbnz x4, .Lxts_enc_loop_##bits; \
++    b .Lxts_enc_done;
++
++  XTS_ENC(128)
++  XTS_ENC(192)
++  XTS_ENC(256)
++
++#undef XTS_ENC
++
++.Lxts_enc_done:
++  aes_clear_keys(w5)
++
++  st1 {v0.16b}, [x3] /* store tweak */
++
++  CLEAR_REG(v0)
++  CLEAR_REG(v1)
++  CLEAR_REG(v2)
++
++.Lxts_enc_skip:
++  ret
++
++.size _gcry_aes_xts_enc_armv8_ce,.-_gcry_aes_xts_enc_armv8_ce;
++
++
++/*
++ * void _gcry_aes_xts_dec_armv8_ce (const void *keysched,
++ *                                  unsigned char *outbuf,
++ *                                  const unsigned char *inbuf,
++ *                                  unsigned char *tweak,
++ *                                  size_t nblocks,
++ *                                  unsigned int nrounds);
++ */
++
++.align 3
++.globl _gcry_aes_xts_dec_armv8_ce
++.type  _gcry_aes_xts_dec_armv8_ce,%function;
++_gcry_aes_xts_dec_armv8_ce:
++  /* input:
++   *    r0: keysched
++   *    r1: outbuf
++   *    r2: inbuf
++   *    r3: tweak
++   *    x4: nblocks
++   *    w5: nrounds
++   */
++
++  cbz x4, .Lxts_dec_skip
++
++  /* load tweak */
++  ld1 {v0.16b}, [x3]
++
++  /* load gfmul mask */
++  mov x6, #0x87
++  mov x7, #0x01
++  mov v16.D[0], x6
++  mov v16.D[1], x7
++
++  aes_preload_keys(x0, w5);
++
++  b.eq .Lxts_dec_entry_192
++  b.hi .Lxts_dec_entry_256
++
++#define XTS_DEC(bits) \
++  .Lxts_dec_entry_##bits: \
++    cmp x4, #4; \
++    b.lo .Lxts_dec_loop_##bits; \
++    \
++  .Lxts_dec_loop4_##bits: \
++    \
++    ext v4.16b, v0.16b, v0.16b, #8; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v5.2d, v0.2d, v0.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v5.16b, v5.16b, v2.16b; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v6.2d, v5.2d, v5.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v6.16b, v6.16b, v2.16b; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v7.2d, v6.2d, v6.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v7.16b, v7.16b, v2.16b; \
++    \
++    sshr v2.2d, v4.2d, #63; \
++    add v3.2d, v7.2d, v7.2d; \
++    and v2.16b, v2.16b, v16.16b; \
++    add v4.2d, v4.2d, v4.2d; \
++    eor v3.16b, v3.16b, v2.16b; \
++    ld1 {v1.16b-v2.16b}, [x2], #32; /* load plaintext */ \
++    st1 {v3.16b}, [x3]; \
++    sub x4, x4, #4; \
++    eor v1.16b, v1.16b, v0.16b; \
++    \
++    ld1 {v3.16b-v4.16b}, [x2], #32; /* load plaintext */ \
++    cmp x4, #4; \
++    eor v2.16b, v2.16b, v5.16b; \
++    eor v3.16b, v3.16b, v6.16b; \
++    eor v4.16b, v4.16b, v7.16b; \
++    \
++    do_aes_4_##bits(d, imc, v1, v2, v3, v4); \
++    \
++    eor v1.16b, v1.16b, v0.16b; \
++    ld1 {v0.16b}, [x3]; \
++    eor v2.16b, v2.16b, v5.16b; \
++    eor v3.16b, v3.16b, v6.16b; \
++    eor v4.16b, v4.16b, v7.16b; \
++    st1 {v1.16b-v4.16b}, [x1], #64; /* store plaintext */ \
++    \
++    b.hs .Lxts_dec_loop4_##bits; \
++    CLEAR_REG(v3); \
++    CLEAR_REG(v4); \
++    CLEAR_REG(v5); \
++    CLEAR_REG(v6); \
++    CLEAR_REG(v7); \
++    cbz x4, .Lxts_dec_done; \
++    \
++  .Lxts_dec_loop_##bits: \
++    \
++    ld1 {v1.16b}, [x2], #16; /* load plaintext */ \
++    ext v3.16b, v0.16b, v0.16b, #8; \
++    mov v2.16b, v0.16b; \
++    sshr v3.2d, v3.2d, #63; \
++    add v0.2d, v0.2d, v0.2d; \
++    and v3.16b, v3.16b, v16.16b; \
++    eor v1.16b, v1.16b, v2.16b; \
++    eor v0.16b, v0.16b, v3.16b; \
++    sub x4, x4, #1; \
++    \
++    do_aes_one##bits(d, imc, v1, v1); \
++    \
++    eor v1.16b, v1.16b, v2.16b; \
++    st1 {v1.16b}, [x1], #16; /* store ciphertext */ \
++    \
++    cbnz x4, .Lxts_dec_loop_##bits; \
++    b .Lxts_dec_done;
++
++  XTS_DEC(128)
++  XTS_DEC(192)
++  XTS_DEC(256)
++
++#undef XTS_DEC
++
++.Lxts_dec_done:
++  aes_clear_keys(w5)
++
++  st1 {v0.16b}, [x3] /* store tweak */
++
++  CLEAR_REG(v0)
++  CLEAR_REG(v1)
++  CLEAR_REG(v2)
++
++.Lxts_dec_skip:
++  ret
++
++.size _gcry_aes_xts_dec_armv8_ce,.-_gcry_aes_xts_dec_armv8_ce;
++
++
++/*
+  * u32 _gcry_aes_sbox4_armv8_ce(u32 in4b);
+  */
+ .align 3
+diff -up libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c
+--- libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c	2020-04-22 18:29:41.675862134 +0200
+@@ -101,6 +101,16 @@ extern void _gcry_aes_ocb_auth_armv8_ce
+                                          size_t nblocks,
+                                          unsigned int nrounds,
+                                          unsigned int blkn);
++extern void _gcry_aes_xts_enc_armv8_ce (const void *keysched,
++                                        unsigned char *outbuf,
++                                        const unsigned char *inbuf,
++                                        unsigned char *tweak,
++                                        size_t nblocks, unsigned int nrounds);
++extern void _gcry_aes_xts_dec_armv8_ce (const void *keysched,
++                                        unsigned char *outbuf,
++                                        const unsigned char *inbuf,
++                                        unsigned char *tweak,
++                                        size_t nblocks, unsigned int nrounds);
+ 
+ typedef void (*ocb_crypt_fn_t) (const void *keysched, unsigned char *outbuf,
+                                 const unsigned char *inbuf,
+@@ -108,6 +118,11 @@ typedef void (*ocb_crypt_fn_t) (const vo
+                                 unsigned char *L_table, size_t nblocks,
+                                 unsigned int nrounds, unsigned int blkn);
+ 
++typedef void (*xts_crypt_fn_t) (const void *keysched, unsigned char *outbuf,
++                                const unsigned char *inbuf,
++                                unsigned char *tweak, size_t nblocks,
++                                unsigned int nrounds);
++
+ void
+ _gcry_aes_armv8_ce_setkey (RIJNDAEL_context *ctx, const byte *key)
+ {
+@@ -269,8 +284,8 @@ _gcry_aes_armv8_ce_decrypt (const RIJNDA
+ }
+ 
+ void
+-_gcry_aes_armv8_ce_cbc_enc (const RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                            const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_armv8_ce_cbc_enc (const RIJNDAEL_context *ctx, unsigned char *iv,
++                            unsigned char *outbuf, const unsigned char *inbuf,
+                             size_t nblocks, int cbc_mac)
+ {
+   const void *keysched = ctx->keyschenc32;
+@@ -281,19 +296,25 @@ _gcry_aes_armv8_ce_cbc_enc (const RIJNDA
+ }
+ 
+ void
+-_gcry_aes_armv8_ce_cbc_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                            const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_armv8_ce_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv,
++                            unsigned char *outbuf, const unsigned char *inbuf,
+                             size_t nblocks)
+ {
+   const void *keysched = ctx->keyschdec32;
+   unsigned int nrounds = ctx->rounds;
+ 
++  if ( !ctx->decryption_prepared )
++    {
++      _gcry_aes_armv8_ce_prepare_decryption ( ctx );
++      ctx->decryption_prepared = 1;
++    }
++
+   _gcry_aes_cbc_dec_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds);
+ }
+ 
+ void
+-_gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                            const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv,
++                            unsigned char *outbuf, const unsigned char *inbuf,
+                             size_t nblocks)
+ {
+   const void *keysched = ctx->keyschenc32;
+@@ -303,8 +324,8 @@ _gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_con
+ }
+ 
+ void
+-_gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                            const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv,
++                            unsigned char *outbuf, const unsigned char *inbuf,
+                             size_t nblocks)
+ {
+   const void *keysched = ctx->keyschenc32;
+@@ -314,8 +335,8 @@ _gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_con
+ }
+ 
+ void
+-_gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                            const unsigned char *inbuf, unsigned char *iv,
++_gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_context *ctx, unsigned char *iv,
++                            unsigned char *outbuf, const unsigned char *inbuf,
+                             size_t nblocks)
+ {
+   const void *keysched = ctx->keyschenc32;
+@@ -324,7 +345,7 @@ _gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_con
+   _gcry_aes_ctr_enc_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds);
+ }
+ 
+-void
++size_t
+ _gcry_aes_armv8_ce_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
+                               const void *inbuf_arg, size_t nblocks,
+                               int encrypt)
+@@ -338,13 +359,21 @@ _gcry_aes_armv8_ce_ocb_crypt (gcry_ciphe
+   unsigned int nrounds = ctx->rounds;
+   u64 blkn = c->u_mode.ocb.data_nblocks;
+ 
++  if ( !encrypt && !ctx->decryption_prepared )
++    {
++      _gcry_aes_armv8_ce_prepare_decryption ( ctx );
++      ctx->decryption_prepared = 1;
++    }
++
+   c->u_mode.ocb.data_nblocks = blkn + nblocks;
+ 
+   crypt_fn(keysched, outbuf, inbuf, c->u_iv.iv, c->u_ctr.ctr,
+            c->u_mode.ocb.L[0], nblocks, nrounds, (unsigned int)blkn);
++
++  return 0;
+ }
+ 
+-void
++size_t
+ _gcry_aes_armv8_ce_ocb_auth (gcry_cipher_hd_t c, void *abuf_arg,
+                              size_t nblocks)
+ {
+@@ -359,6 +388,27 @@ _gcry_aes_armv8_ce_ocb_auth (gcry_cipher
+   _gcry_aes_ocb_auth_armv8_ce(keysched, abuf, c->u_mode.ocb.aad_offset,
+ 			      c->u_mode.ocb.aad_sum, c->u_mode.ocb.L[0],
+ 			      nblocks, nrounds, (unsigned int)blkn);
++
++  return 0;
++}
++
++void
++_gcry_aes_armv8_ce_xts_crypt (RIJNDAEL_context *ctx, unsigned char *tweak,
++			      unsigned char *outbuf, const unsigned char *inbuf,
++			      size_t nblocks, int encrypt)
++{
++  const void *keysched = encrypt ? ctx->keyschenc32 : ctx->keyschdec32;
++  xts_crypt_fn_t crypt_fn = encrypt ? _gcry_aes_xts_enc_armv8_ce
++                                    : _gcry_aes_xts_dec_armv8_ce;
++  unsigned int nrounds = ctx->rounds;
++
++  if ( !encrypt && !ctx->decryption_prepared )
++    {
++      _gcry_aes_armv8_ce_prepare_decryption ( ctx );
++      ctx->decryption_prepared = 1;
++    }
++
++  crypt_fn(keysched, outbuf, inbuf, tweak, nblocks, nrounds);
+ }
+ 
+ #endif /* USE_ARM_CE */
+diff -up libgcrypt-1.8.5/cipher/rijndael.c.aes-perf libgcrypt-1.8.5/cipher/rijndael.c
+--- libgcrypt-1.8.5/cipher/rijndael.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rijndael.c	2020-04-22 18:29:41.676862114 +0200
+@@ -77,32 +77,29 @@ extern unsigned int _gcry_aes_aesni_encr
+ extern unsigned int _gcry_aes_aesni_decrypt (const RIJNDAEL_context *ctx,
+                                              unsigned char *dst,
+                                              const unsigned char *src);
+-extern void _gcry_aes_aesni_cfb_enc (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_aesni_cbc_enc (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks,
+-                                     int cbc_mac);
+-extern void _gcry_aes_aesni_ctr_enc (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *ctr, size_t nblocks);
+-extern void _gcry_aes_aesni_cfb_dec (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_aesni_cbc_dec (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_aesni_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
+-                                       const void *inbuf_arg, size_t nblocks,
+-                                       int encrypt);
+-extern void _gcry_aes_aesni_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
+-                                      size_t nblocks);
++extern void _gcry_aes_aesni_cfb_enc (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern void _gcry_aes_aesni_cbc_enc (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks, int cbc_mac);
++extern void _gcry_aes_aesni_ctr_enc (void *context, unsigned char *ctr,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern void _gcry_aes_aesni_cfb_dec (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern void _gcry_aes_aesni_cbc_dec (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern size_t _gcry_aes_aesni_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
++                                         const void *inbuf_arg, size_t nblocks,
++                                         int encrypt);
++extern size_t _gcry_aes_aesni_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
++                                        size_t nblocks);
++extern void _gcry_aes_aesni_xts_crypt (void *context, unsigned char *tweak,
++                                       void *outbuf_arg, const void *inbuf_arg,
++                                       size_t nblocks, int encrypt);
+ #endif
+ 
+ #ifdef USE_SSSE3
+@@ -116,32 +113,27 @@ extern unsigned int _gcry_aes_ssse3_encr
+ extern unsigned int _gcry_aes_ssse3_decrypt (const RIJNDAEL_context *ctx,
+                                              unsigned char *dst,
+                                              const unsigned char *src);
+-extern void _gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks,
++extern void _gcry_aes_ssse3_cfb_enc (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern void _gcry_aes_ssse3_cbc_enc (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks,
+                                      int cbc_mac);
+-extern void _gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *ctr, size_t nblocks);
+-extern void _gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx,
+-                                     unsigned char *outbuf,
+-                                     const unsigned char *inbuf,
+-                                     unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_ssse3_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
+-                                       const void *inbuf_arg, size_t nblocks,
+-                                       int encrypt);
+-extern void _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
+-                                      size_t nblocks);
++extern void _gcry_aes_ssse3_ctr_enc (void *context, unsigned char *ctr,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern void _gcry_aes_ssse3_cfb_dec (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern void _gcry_aes_ssse3_cbc_dec (void *context, unsigned char *iv,
++                                     void *outbuf_arg, const void *inbuf_arg,
++                                     size_t nblocks);
++extern size_t _gcry_aes_ssse3_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
++                                         const void *inbuf_arg, size_t nblocks,
++                                         int encrypt);
++extern size_t _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
++                                        size_t nblocks);
+ #endif
+ 
+ #ifdef USE_PADLOCK
+@@ -180,34 +172,110 @@ extern unsigned int _gcry_aes_armv8_ce_d
+                                                unsigned char *dst,
+                                                const unsigned char *src);
+ 
+-extern void _gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_context *ctx,
+-                                        unsigned char *outbuf,
+-                                        const unsigned char *inbuf,
+-                                        unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_armv8_ce_cbc_enc (RIJNDAEL_context *ctx,
+-                                        unsigned char *outbuf,
+-                                        const unsigned char *inbuf,
+-                                        unsigned char *iv, size_t nblocks,
++extern void _gcry_aes_armv8_ce_cfb_enc (void *context, unsigned char *iv,
++                                        void *outbuf_arg, const void *inbuf_arg,
++                                        size_t nblocks);
++extern void _gcry_aes_armv8_ce_cbc_enc (void *context, unsigned char *iv,
++                                        void *outbuf_arg, const void *inbuf_arg,
++                                        size_t nblocks,
+                                         int cbc_mac);
+-extern void _gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_context *ctx,
+-                                        unsigned char *outbuf,
+-                                        const unsigned char *inbuf,
+-                                        unsigned char *ctr, size_t nblocks);
+-extern void _gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_context *ctx,
+-                                        unsigned char *outbuf,
+-                                        const unsigned char *inbuf,
+-                                        unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_armv8_ce_cbc_dec (RIJNDAEL_context *ctx,
+-                                        unsigned char *outbuf,
+-                                        const unsigned char *inbuf,
+-                                        unsigned char *iv, size_t nblocks);
+-extern void _gcry_aes_armv8_ce_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
+-                                          const void *inbuf_arg, size_t nblocks,
+-                                          int encrypt);
+-extern void _gcry_aes_armv8_ce_ocb_auth (gcry_cipher_hd_t c,
+-                                         const void *abuf_arg, size_t nblocks);
++extern void _gcry_aes_armv8_ce_ctr_enc (void *context, unsigned char *ctr,
++                                        void *outbuf_arg, const void *inbuf_arg,
++                                        size_t nblocks);
++extern void _gcry_aes_armv8_ce_cfb_dec (void *context, unsigned char *iv,
++                                        void *outbuf_arg, const void *inbuf_arg,
++                                        size_t nblocks);
++extern void _gcry_aes_armv8_ce_cbc_dec (void *context, unsigned char *iv,
++                                        void *outbuf_arg, const void *inbuf_arg,
++                                        size_t nblocks);
++extern size_t _gcry_aes_armv8_ce_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
++                                            const void *inbuf_arg, size_t nblocks,
++                                            int encrypt);
++extern size_t _gcry_aes_armv8_ce_ocb_auth (gcry_cipher_hd_t c,
++                                           const void *abuf_arg, size_t nblocks);
++extern void _gcry_aes_armv8_ce_xts_crypt (void *context, unsigned char *tweak,
++                                          void *outbuf_arg,
++                                          const void *inbuf_arg,
++                                          size_t nblocks, int encrypt);
+ #endif /*USE_ARM_ASM*/
+ 
++#ifdef USE_PPC_CRYPTO
++/* PowerPC Crypto implementations of AES */
++extern void _gcry_aes_ppc8_setkey(RIJNDAEL_context *ctx, const byte *key);
++extern void _gcry_aes_ppc8_prepare_decryption(RIJNDAEL_context *ctx);
++
++extern unsigned int _gcry_aes_ppc8_encrypt(const RIJNDAEL_context *ctx,
++					   unsigned char *dst,
++					   const unsigned char *src);
++extern unsigned int _gcry_aes_ppc8_decrypt(const RIJNDAEL_context *ctx,
++					   unsigned char *dst,
++					   const unsigned char *src);
++
++extern void _gcry_aes_ppc8_cfb_enc (void *context, unsigned char *iv,
++				    void *outbuf_arg, const void *inbuf_arg,
++				    size_t nblocks);
++extern void _gcry_aes_ppc8_cbc_enc (void *context, unsigned char *iv,
++				    void *outbuf_arg, const void *inbuf_arg,
++				    size_t nblocks, int cbc_mac);
++extern void _gcry_aes_ppc8_ctr_enc (void *context, unsigned char *ctr,
++				    void *outbuf_arg, const void *inbuf_arg,
++				    size_t nblocks);
++extern void _gcry_aes_ppc8_cfb_dec (void *context, unsigned char *iv,
++				    void *outbuf_arg, const void *inbuf_arg,
++				    size_t nblocks);
++extern void _gcry_aes_ppc8_cbc_dec (void *context, unsigned char *iv,
++				    void *outbuf_arg, const void *inbuf_arg,
++				    size_t nblocks);
++
++extern size_t _gcry_aes_ppc8_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
++					const void *inbuf_arg, size_t nblocks,
++					int encrypt);
++extern size_t _gcry_aes_ppc8_ocb_auth (gcry_cipher_hd_t c,
++				       const void *abuf_arg, size_t nblocks);
++
++extern void _gcry_aes_ppc8_xts_crypt (void *context, unsigned char *tweak,
++				      void *outbuf_arg,
++				      const void *inbuf_arg,
++				      size_t nblocks, int encrypt);
++#endif /*USE_PPC_CRYPTO*/
++
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++/* Power9 little-endian crypto implementations of AES */
++extern unsigned int _gcry_aes_ppc9le_encrypt(const RIJNDAEL_context *ctx,
++					    unsigned char *dst,
++					    const unsigned char *src);
++extern unsigned int _gcry_aes_ppc9le_decrypt(const RIJNDAEL_context *ctx,
++					    unsigned char *dst,
++					    const unsigned char *src);
++
++extern void _gcry_aes_ppc9le_cfb_enc (void *context, unsigned char *iv,
++				      void *outbuf_arg, const void *inbuf_arg,
++				      size_t nblocks);
++extern void _gcry_aes_ppc9le_cbc_enc (void *context, unsigned char *iv,
++				      void *outbuf_arg, const void *inbuf_arg,
++				      size_t nblocks, int cbc_mac);
++extern void _gcry_aes_ppc9le_ctr_enc (void *context, unsigned char *ctr,
++				      void *outbuf_arg, const void *inbuf_arg,
++				      size_t nblocks);
++extern void _gcry_aes_ppc9le_cfb_dec (void *context, unsigned char *iv,
++				      void *outbuf_arg, const void *inbuf_arg,
++				      size_t nblocks);
++extern void _gcry_aes_ppc9le_cbc_dec (void *context, unsigned char *iv,
++				      void *outbuf_arg, const void *inbuf_arg,
++				      size_t nblocks);
++
++extern size_t _gcry_aes_ppc9le_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg,
++					  const void *inbuf_arg, size_t nblocks,
++					  int encrypt);
++extern size_t _gcry_aes_ppc9le_ocb_auth (gcry_cipher_hd_t c,
++					const void *abuf_arg, size_t nblocks);
++
++extern void _gcry_aes_ppc9le_xts_crypt (void *context, unsigned char *tweak,
++					void *outbuf_arg,
++					const void *inbuf_arg,
++					size_t nblocks, int encrypt);
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++
+ static unsigned int do_encrypt (const RIJNDAEL_context *ctx, unsigned char *bx,
+                                 const unsigned char *ax);
+ static unsigned int do_decrypt (const RIJNDAEL_context *ctx, unsigned char *bx,
+@@ -260,7 +328,8 @@ static void prefetch_dec(void)
+ 
+ /* Perform the key setup.  */
+ static gcry_err_code_t
+-do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen)
++do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen,
++           gcry_cipher_hd_t hd)
+ {
+   static int initialized = 0;
+   static const char *selftest_failed = 0;
+@@ -268,7 +337,7 @@ do_setkey (RIJNDAEL_context *ctx, const
+   int i,j, r, t, rconpointer = 0;
+   int KC;
+ #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \
+-    || defined(USE_ARM_CE)
++    || defined(USE_ARM_CE) || defined(USE_PPC_CRYPTO)
+   unsigned int hwfeatures;
+ #endif
+ 
+@@ -310,7 +379,7 @@ do_setkey (RIJNDAEL_context *ctx, const
+   ctx->rounds = rounds;
+ 
+ #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \
+-    || defined(USE_ARM_CE)
++    || defined(USE_ARM_CE) || defined(USE_PPC_CRYPTO)
+   hwfeatures = _gcry_get_hw_features ();
+ #endif
+ 
+@@ -327,6 +396,12 @@ do_setkey (RIJNDAEL_context *ctx, const
+ #ifdef USE_ARM_CE
+   ctx->use_arm_ce = 0;
+ #endif
++#ifdef USE_PPC_CRYPTO
++  ctx->use_ppc_crypto = 0;
++#endif
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  ctx->use_ppc9le_crypto = 0;
++#endif
+ 
+   if (0)
+     {
+@@ -340,6 +415,17 @@ do_setkey (RIJNDAEL_context *ctx, const
+       ctx->prefetch_enc_fn = NULL;
+       ctx->prefetch_dec_fn = NULL;
+       ctx->use_aesni = 1;
++      if (hd)
++        {
++          hd->bulk.cfb_enc = _gcry_aes_aesni_cfb_enc;
++          hd->bulk.cfb_dec = _gcry_aes_aesni_cfb_dec;
++          hd->bulk.cbc_enc = _gcry_aes_aesni_cbc_enc;
++          hd->bulk.cbc_dec = _gcry_aes_aesni_cbc_dec;
++          hd->bulk.ctr_enc = _gcry_aes_aesni_ctr_enc;
++          hd->bulk.ocb_crypt = _gcry_aes_aesni_ocb_crypt;
++          hd->bulk.ocb_auth = _gcry_aes_aesni_ocb_auth;
++          hd->bulk.xts_crypt = _gcry_aes_aesni_xts_crypt;
++        }
+     }
+ #endif
+ #ifdef USE_PADLOCK
+@@ -361,6 +447,16 @@ do_setkey (RIJNDAEL_context *ctx, const
+       ctx->prefetch_enc_fn = NULL;
+       ctx->prefetch_dec_fn = NULL;
+       ctx->use_ssse3 = 1;
++      if (hd)
++        {
++          hd->bulk.cfb_enc = _gcry_aes_ssse3_cfb_enc;
++          hd->bulk.cfb_dec = _gcry_aes_ssse3_cfb_dec;
++          hd->bulk.cbc_enc = _gcry_aes_ssse3_cbc_enc;
++          hd->bulk.cbc_dec = _gcry_aes_ssse3_cbc_dec;
++          hd->bulk.ctr_enc = _gcry_aes_ssse3_ctr_enc;
++          hd->bulk.ocb_crypt = _gcry_aes_ssse3_ocb_crypt;
++          hd->bulk.ocb_auth = _gcry_aes_ssse3_ocb_auth;
++        }
+     }
+ #endif
+ #ifdef USE_ARM_CE
+@@ -371,6 +467,60 @@ do_setkey (RIJNDAEL_context *ctx, const
+       ctx->prefetch_enc_fn = NULL;
+       ctx->prefetch_dec_fn = NULL;
+       ctx->use_arm_ce = 1;
++      if (hd)
++        {
++          hd->bulk.cfb_enc = _gcry_aes_armv8_ce_cfb_enc;
++          hd->bulk.cfb_dec = _gcry_aes_armv8_ce_cfb_dec;
++          hd->bulk.cbc_enc = _gcry_aes_armv8_ce_cbc_enc;
++          hd->bulk.cbc_dec = _gcry_aes_armv8_ce_cbc_dec;
++          hd->bulk.ctr_enc = _gcry_aes_armv8_ce_ctr_enc;
++          hd->bulk.ocb_crypt = _gcry_aes_armv8_ce_ocb_crypt;
++          hd->bulk.ocb_auth = _gcry_aes_armv8_ce_ocb_auth;
++          hd->bulk.xts_crypt = _gcry_aes_armv8_ce_xts_crypt;
++        }
++    }
++#endif
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if ((hwfeatures & HWF_PPC_VCRYPTO) && (hwfeatures & HWF_PPC_ARCH_3_00))
++    {
++      ctx->encrypt_fn = _gcry_aes_ppc9le_encrypt;
++      ctx->decrypt_fn = _gcry_aes_ppc9le_decrypt;
++      ctx->prefetch_enc_fn = NULL;
++      ctx->prefetch_dec_fn = NULL;
++      ctx->use_ppc_crypto = 1; /* same key-setup as USE_PPC_CRYPTO */
++      ctx->use_ppc9le_crypto = 1;
++      if (hd)
++        {
++          hd->bulk.cfb_enc = _gcry_aes_ppc9le_cfb_enc;
++          hd->bulk.cfb_dec = _gcry_aes_ppc9le_cfb_dec;
++          hd->bulk.cbc_enc = _gcry_aes_ppc9le_cbc_enc;
++          hd->bulk.cbc_dec = _gcry_aes_ppc9le_cbc_dec;
++          hd->bulk.ctr_enc = _gcry_aes_ppc9le_ctr_enc;
++          hd->bulk.ocb_crypt = _gcry_aes_ppc9le_ocb_crypt;
++          hd->bulk.ocb_auth = _gcry_aes_ppc9le_ocb_auth;
++          hd->bulk.xts_crypt = _gcry_aes_ppc9le_xts_crypt;
++        }
++    }
++#endif
++#ifdef USE_PPC_CRYPTO
++  else if (hwfeatures & HWF_PPC_VCRYPTO)
++    {
++      ctx->encrypt_fn = _gcry_aes_ppc8_encrypt;
++      ctx->decrypt_fn = _gcry_aes_ppc8_decrypt;
++      ctx->prefetch_enc_fn = NULL;
++      ctx->prefetch_dec_fn = NULL;
++      ctx->use_ppc_crypto = 1;
++      if (hd)
++        {
++          hd->bulk.cfb_enc = _gcry_aes_ppc8_cfb_enc;
++          hd->bulk.cfb_dec = _gcry_aes_ppc8_cfb_dec;
++          hd->bulk.cbc_enc = _gcry_aes_ppc8_cbc_enc;
++          hd->bulk.cbc_dec = _gcry_aes_ppc8_cbc_dec;
++          hd->bulk.ctr_enc = _gcry_aes_ppc8_ctr_enc;
++          hd->bulk.ocb_crypt = _gcry_aes_ppc8_ocb_crypt;
++          hd->bulk.ocb_auth = _gcry_aes_ppc8_ocb_auth;
++          hd->bulk.xts_crypt = _gcry_aes_ppc8_xts_crypt;
++        }
+     }
+ #endif
+   else
+@@ -399,6 +549,10 @@ do_setkey (RIJNDAEL_context *ctx, const
+   else if (ctx->use_arm_ce)
+     _gcry_aes_armv8_ce_setkey (ctx, key);
+ #endif
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    _gcry_aes_ppc8_setkey (ctx, key);
++#endif
+   else
+     {
+       const byte *sbox = ((const byte *)encT) + 1;
+@@ -503,10 +657,11 @@ do_setkey (RIJNDAEL_context *ctx, const
+ 
+ 
+ static gcry_err_code_t
+-rijndael_setkey (void *context, const byte *key, const unsigned keylen)
++rijndael_setkey (void *context, const byte *key, const unsigned keylen,
++                 gcry_cipher_hd_t hd)
+ {
+   RIJNDAEL_context *ctx = context;
+-  return do_setkey (ctx, key, keylen);
++  return do_setkey (ctx, key, keylen, hd);
+ }
+ 
+ 
+@@ -535,7 +690,19 @@ prepare_decryption( RIJNDAEL_context *ct
+     {
+       _gcry_aes_armv8_ce_prepare_decryption (ctx);
+     }
+-#endif /*USE_SSSE3*/
++#endif /*USE_ARM_CE*/
++#ifdef USE_ARM_CE
++  else if (ctx->use_arm_ce)
++    {
++      _gcry_aes_armv8_ce_prepare_decryption (ctx);
++    }
++#endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      _gcry_aes_ppc8_prepare_decryption (ctx);
++    }
++#endif
+ #ifdef USE_PADLOCK
+   else if (ctx->use_padlock)
+     {
+@@ -790,42 +957,56 @@ _gcry_aes_cfb_enc (void *context, unsign
+   const unsigned char *inbuf = inbuf_arg;
+   unsigned int burn_depth = 0;
+ 
+-  if (ctx->prefetch_enc_fn)
+-    ctx->prefetch_enc_fn();
+-
+   if (0)
+     ;
+ #ifdef USE_AESNI
+   else if (ctx->use_aesni)
+     {
+-      _gcry_aes_aesni_cfb_enc (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_aesni_cfb_enc (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_AESNI*/
+ #ifdef USE_SSSE3
+   else if (ctx->use_ssse3)
+     {
+-      _gcry_aes_ssse3_cfb_enc (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_ssse3_cfb_enc (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_SSSE3*/
+ #ifdef USE_ARM_CE
+   else if (ctx->use_arm_ce)
+     {
+-      _gcry_aes_armv8_ce_cfb_enc (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_armv8_ce_cfb_enc (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      _gcry_aes_ppc9le_cfb_enc (ctx, iv, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      _gcry_aes_ppc8_cfb_enc (ctx, iv, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO*/
+   else
+     {
+       rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn;
+ 
++      if (ctx->prefetch_enc_fn)
++        ctx->prefetch_enc_fn();
++
+       for ( ;nblocks; nblocks-- )
+         {
+           /* Encrypt the IV. */
+           burn_depth = encrypt_fn (ctx, iv, iv);
+           /* XOR the input with the IV and store input into IV.  */
+-          buf_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE);
++          cipher_block_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE);
+           outbuf += BLOCKSIZE;
+           inbuf  += BLOCKSIZE;
+         }
+@@ -851,41 +1032,55 @@ _gcry_aes_cbc_enc (void *context, unsign
+   unsigned char *last_iv;
+   unsigned int burn_depth = 0;
+ 
+-  if (ctx->prefetch_enc_fn)
+-    ctx->prefetch_enc_fn();
+-
+   if (0)
+     ;
+ #ifdef USE_AESNI
+   else if (ctx->use_aesni)
+     {
+-      _gcry_aes_aesni_cbc_enc (ctx, outbuf, inbuf, iv, nblocks, cbc_mac);
+-      burn_depth = 0;
++      _gcry_aes_aesni_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac);
++      return;
+     }
+ #endif /*USE_AESNI*/
+ #ifdef USE_SSSE3
+   else if (ctx->use_ssse3)
+     {
+-      _gcry_aes_ssse3_cbc_enc (ctx, outbuf, inbuf, iv, nblocks, cbc_mac);
+-      burn_depth = 0;
++      _gcry_aes_ssse3_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac);
++      return;
+     }
+ #endif /*USE_SSSE3*/
+ #ifdef USE_ARM_CE
+   else if (ctx->use_arm_ce)
+     {
+-      _gcry_aes_armv8_ce_cbc_enc (ctx, outbuf, inbuf, iv, nblocks, cbc_mac);
+-      burn_depth = 0;
++      _gcry_aes_armv8_ce_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac);
++      return;
+     }
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      _gcry_aes_ppc9le_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      _gcry_aes_ppc8_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO*/
+   else
+     {
+       rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn;
+ 
++      if (ctx->prefetch_enc_fn)
++        ctx->prefetch_enc_fn();
++
+       last_iv = iv;
+ 
+       for ( ;nblocks; nblocks-- )
+         {
+-          buf_xor(outbuf, inbuf, last_iv, BLOCKSIZE);
++          cipher_block_xor(outbuf, inbuf, last_iv, BLOCKSIZE);
+ 
+           burn_depth = encrypt_fn (ctx, outbuf, outbuf);
+ 
+@@ -896,7 +1091,7 @@ _gcry_aes_cbc_enc (void *context, unsign
+         }
+ 
+       if (last_iv != iv)
+-        buf_cpy (iv, last_iv, BLOCKSIZE);
++        cipher_block_cpy (iv, last_iv, BLOCKSIZE);
+     }
+ 
+   if (burn_depth)
+@@ -920,43 +1115,57 @@ _gcry_aes_ctr_enc (void *context, unsign
+   unsigned int burn_depth = 0;
+   int i;
+ 
+-  if (ctx->prefetch_enc_fn)
+-    ctx->prefetch_enc_fn();
+-
+   if (0)
+     ;
+ #ifdef USE_AESNI
+   else if (ctx->use_aesni)
+     {
+-      _gcry_aes_aesni_ctr_enc (ctx, outbuf, inbuf, ctr, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_aesni_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_AESNI*/
+ #ifdef USE_SSSE3
+   else if (ctx->use_ssse3)
+     {
+-      _gcry_aes_ssse3_ctr_enc (ctx, outbuf, inbuf, ctr, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_ssse3_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_SSSE3*/
+ #ifdef USE_ARM_CE
+   else if (ctx->use_arm_ce)
+     {
+-      _gcry_aes_armv8_ce_ctr_enc (ctx, outbuf, inbuf, ctr, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_armv8_ce_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      _gcry_aes_ppc9le_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      _gcry_aes_ppc8_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO*/
+   else
+     {
+       union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } tmp;
+       rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn;
+ 
++      if (ctx->prefetch_enc_fn)
++        ctx->prefetch_enc_fn();
++
+       for ( ;nblocks; nblocks-- )
+         {
+           /* Encrypt the counter. */
+           burn_depth = encrypt_fn (ctx, tmp.x1, ctr);
+           /* XOR the input with the encrypted counter and store in output.  */
+-          buf_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE);
++          cipher_block_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE);
+           outbuf += BLOCKSIZE;
+           inbuf  += BLOCKSIZE;
+           /* Increment the counter.  */
+@@ -1187,40 +1396,54 @@ _gcry_aes_cfb_dec (void *context, unsign
+   const unsigned char *inbuf = inbuf_arg;
+   unsigned int burn_depth = 0;
+ 
+-  if (ctx->prefetch_enc_fn)
+-    ctx->prefetch_enc_fn();
+-
+   if (0)
+     ;
+ #ifdef USE_AESNI
+   else if (ctx->use_aesni)
+     {
+-      _gcry_aes_aesni_cfb_dec (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_aesni_cfb_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_AESNI*/
+ #ifdef USE_SSSE3
+   else if (ctx->use_ssse3)
+     {
+-      _gcry_aes_ssse3_cfb_dec (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_ssse3_cfb_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_SSSE3*/
+ #ifdef USE_ARM_CE
+   else if (ctx->use_arm_ce)
+     {
+-      _gcry_aes_armv8_ce_cfb_dec (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_armv8_ce_cfb_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      _gcry_aes_ppc9le_cfb_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      _gcry_aes_ppc8_cfb_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO*/
+   else
+     {
+       rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn;
+ 
++      if (ctx->prefetch_enc_fn)
++        ctx->prefetch_enc_fn();
++
+       for ( ;nblocks; nblocks-- )
+         {
+           burn_depth = encrypt_fn (ctx, iv, iv);
+-          buf_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE);
++          cipher_block_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE);
+           outbuf += BLOCKSIZE;
+           inbuf  += BLOCKSIZE;
+         }
+@@ -1245,39 +1468,53 @@ _gcry_aes_cbc_dec (void *context, unsign
+   const unsigned char *inbuf = inbuf_arg;
+   unsigned int burn_depth = 0;
+ 
+-  check_decryption_preparation (ctx);
+-
+-  if (ctx->prefetch_dec_fn)
+-    ctx->prefetch_dec_fn();
+-
+   if (0)
+     ;
+ #ifdef USE_AESNI
+   else if (ctx->use_aesni)
+     {
+-      _gcry_aes_aesni_cbc_dec (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_aesni_cbc_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_AESNI*/
+ #ifdef USE_SSSE3
+   else if (ctx->use_ssse3)
+     {
+-      _gcry_aes_ssse3_cbc_dec (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_ssse3_cbc_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_SSSE3*/
+ #ifdef USE_ARM_CE
+   else if (ctx->use_arm_ce)
+     {
+-      _gcry_aes_armv8_ce_cbc_dec (ctx, outbuf, inbuf, iv, nblocks);
+-      burn_depth = 0;
++      _gcry_aes_armv8_ce_cbc_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
+     }
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      _gcry_aes_ppc9le_cbc_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      _gcry_aes_ppc8_cbc_dec (ctx, iv, outbuf, inbuf, nblocks);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO*/
+   else
+     {
+       unsigned char savebuf[BLOCKSIZE] ATTR_ALIGNED_16;
+       rijndael_cryptfn_t decrypt_fn = ctx->decrypt_fn;
+ 
++      check_decryption_preparation (ctx);
++
++      if (ctx->prefetch_dec_fn)
++        ctx->prefetch_dec_fn();
++
+       for ( ;nblocks; nblocks-- )
+         {
+           /* INBUF is needed later and it may be identical to OUTBUF, so store
+@@ -1285,7 +1522,7 @@ _gcry_aes_cbc_dec (void *context, unsign
+ 
+           burn_depth = decrypt_fn (ctx, savebuf, inbuf);
+ 
+-          buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOCKSIZE);
++          cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOCKSIZE);
+           inbuf += BLOCKSIZE;
+           outbuf += BLOCKSIZE;
+         }
+@@ -1309,62 +1546,61 @@ _gcry_aes_ocb_crypt (gcry_cipher_hd_t c,
+   const unsigned char *inbuf = inbuf_arg;
+   unsigned int burn_depth = 0;
+ 
+-  if (encrypt)
+-    {
+-      if (ctx->prefetch_enc_fn)
+-        ctx->prefetch_enc_fn();
+-    }
+-  else
+-    {
+-      check_decryption_preparation (ctx);
+-
+-      if (ctx->prefetch_dec_fn)
+-        ctx->prefetch_dec_fn();
+-    }
+-
+   if (0)
+     ;
+ #ifdef USE_AESNI
+   else if (ctx->use_aesni)
+     {
+-      _gcry_aes_aesni_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
+-      burn_depth = 0;
++      return _gcry_aes_aesni_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
+     }
+ #endif /*USE_AESNI*/
+ #ifdef USE_SSSE3
+   else if (ctx->use_ssse3)
+     {
+-      _gcry_aes_ssse3_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
+-      burn_depth = 0;
++      return _gcry_aes_ssse3_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
+     }
+ #endif /*USE_SSSE3*/
+ #ifdef USE_ARM_CE
+   else if (ctx->use_arm_ce)
+     {
+-      _gcry_aes_armv8_ce_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
+-      burn_depth = 0;
++      return _gcry_aes_armv8_ce_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
+     }
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      return _gcry_aes_ppc9le_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      return _gcry_aes_ppc8_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt);
++    }
++#endif /*USE_PPC_CRYPTO*/
+   else if (encrypt)
+     {
+       union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } l_tmp;
+       rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn;
+ 
++      if (ctx->prefetch_enc_fn)
++        ctx->prefetch_enc_fn();
++
+       for ( ;nblocks; nblocks-- )
+         {
+           u64 i = ++c->u_mode.ocb.data_nblocks;
+           const unsigned char *l = ocb_get_l(c, i);
+ 
+           /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-          buf_xor_1 (c->u_iv.iv, l, BLOCKSIZE);
+-          buf_cpy (l_tmp.x1, inbuf, BLOCKSIZE);
++          cipher_block_xor_1 (c->u_iv.iv, l, BLOCKSIZE);
++          cipher_block_cpy (l_tmp.x1, inbuf, BLOCKSIZE);
+           /* Checksum_i = Checksum_{i-1} xor P_i  */
+-          buf_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE);
++          cipher_block_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE);
+           /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
+-          buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
++          cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
+           burn_depth = encrypt_fn (ctx, l_tmp.x1, l_tmp.x1);
+-          buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
+-          buf_cpy (outbuf, l_tmp.x1, BLOCKSIZE);
++          cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
++          cipher_block_cpy (outbuf, l_tmp.x1, BLOCKSIZE);
+ 
+           inbuf += BLOCKSIZE;
+           outbuf += BLOCKSIZE;
+@@ -1375,21 +1611,26 @@ _gcry_aes_ocb_crypt (gcry_cipher_hd_t c,
+       union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } l_tmp;
+       rijndael_cryptfn_t decrypt_fn = ctx->decrypt_fn;
+ 
++      check_decryption_preparation (ctx);
++
++      if (ctx->prefetch_dec_fn)
++        ctx->prefetch_dec_fn();
++
+       for ( ;nblocks; nblocks-- )
+         {
+           u64 i = ++c->u_mode.ocb.data_nblocks;
+           const unsigned char *l = ocb_get_l(c, i);
+ 
+           /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-          buf_xor_1 (c->u_iv.iv, l, BLOCKSIZE);
+-          buf_cpy (l_tmp.x1, inbuf, BLOCKSIZE);
++          cipher_block_xor_1 (c->u_iv.iv, l, BLOCKSIZE);
++          cipher_block_cpy (l_tmp.x1, inbuf, BLOCKSIZE);
+           /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
+-          buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
++          cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
+           burn_depth = decrypt_fn (ctx, l_tmp.x1, l_tmp.x1);
+-          buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
++          cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE);
+           /* Checksum_i = Checksum_{i-1} xor P_i  */
+-          buf_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE);
+-          buf_cpy (outbuf, l_tmp.x1, BLOCKSIZE);
++          cipher_block_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE);
++          cipher_block_cpy (outbuf, l_tmp.x1, BLOCKSIZE);
+ 
+           inbuf += BLOCKSIZE;
+           outbuf += BLOCKSIZE;
+@@ -1411,48 +1652,58 @@ _gcry_aes_ocb_auth (gcry_cipher_hd_t c,
+   const unsigned char *abuf = abuf_arg;
+   unsigned int burn_depth = 0;
+ 
+-  if (ctx->prefetch_enc_fn)
+-    ctx->prefetch_enc_fn();
+-
+   if (0)
+     ;
+ #ifdef USE_AESNI
+   else if (ctx->use_aesni)
+     {
+-      _gcry_aes_aesni_ocb_auth (c, abuf, nblocks);
+-      burn_depth = 0;
++      return _gcry_aes_aesni_ocb_auth (c, abuf, nblocks);
+     }
+ #endif /*USE_AESNI*/
+ #ifdef USE_SSSE3
+   else if (ctx->use_ssse3)
+     {
+-      _gcry_aes_ssse3_ocb_auth (c, abuf, nblocks);
+-      burn_depth = 0;
++      return _gcry_aes_ssse3_ocb_auth (c, abuf, nblocks);
+     }
+ #endif /*USE_SSSE3*/
+ #ifdef USE_ARM_CE
+   else if (ctx->use_arm_ce)
+     {
+-      _gcry_aes_armv8_ce_ocb_auth (c, abuf, nblocks);
+-      burn_depth = 0;
++      return _gcry_aes_armv8_ce_ocb_auth (c, abuf, nblocks);
+     }
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      return _gcry_aes_ppc9le_ocb_auth (c, abuf, nblocks);
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      return _gcry_aes_ppc8_ocb_auth (c, abuf, nblocks);
++    }
++#endif /*USE_PPC_CRYPTO*/
+   else
+     {
+       union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } l_tmp;
+       rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn;
+ 
++      if (ctx->prefetch_enc_fn)
++        ctx->prefetch_enc_fn();
++
+       for ( ;nblocks; nblocks-- )
+         {
+           u64 i = ++c->u_mode.ocb.aad_nblocks;
+           const unsigned char *l = ocb_get_l(c, i);
+ 
+           /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+-          buf_xor_1 (c->u_mode.ocb.aad_offset, l, BLOCKSIZE);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l, BLOCKSIZE);
+           /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
+-          buf_xor (l_tmp.x1, c->u_mode.ocb.aad_offset, abuf, BLOCKSIZE);
++          cipher_block_xor (l_tmp.x1, c->u_mode.ocb.aad_offset, abuf,
++                            BLOCKSIZE);
+           burn_depth = encrypt_fn (ctx, l_tmp.x1, l_tmp.x1);
+-          buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp.x1, BLOCKSIZE);
++          cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp.x1, BLOCKSIZE);
+ 
+           abuf += BLOCKSIZE;
+         }
+@@ -1467,6 +1718,106 @@ _gcry_aes_ocb_auth (gcry_cipher_hd_t c,
+ }
+ 
+ 
++/* Bulk encryption/decryption of complete blocks in XTS mode. */
++void
++_gcry_aes_xts_crypt (void *context, unsigned char *tweak,
++		     void *outbuf_arg, const void *inbuf_arg,
++		     size_t nblocks, int encrypt)
++{
++  RIJNDAEL_context *ctx = context;
++  unsigned char *outbuf = outbuf_arg;
++  const unsigned char *inbuf = inbuf_arg;
++  unsigned int burn_depth = 0;
++  rijndael_cryptfn_t crypt_fn;
++  u64 tweak_lo, tweak_hi, tweak_next_lo, tweak_next_hi, tmp_lo, tmp_hi, carry;
++
++  if (0)
++    ;
++#ifdef USE_AESNI
++  else if (ctx->use_aesni)
++    {
++      _gcry_aes_aesni_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt);
++      return;
++    }
++#endif /*USE_AESNI*/
++#ifdef USE_ARM_CE
++  else if (ctx->use_arm_ce)
++    {
++      _gcry_aes_armv8_ce_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt);
++      return;
++    }
++#endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  else if (ctx->use_ppc9le_crypto)
++    {
++      _gcry_aes_ppc9le_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/
++#ifdef USE_PPC_CRYPTO
++  else if (ctx->use_ppc_crypto)
++    {
++      _gcry_aes_ppc8_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt);
++      return;
++    }
++#endif /*USE_PPC_CRYPTO*/
++  else
++    {
++      if (encrypt)
++        {
++          if (ctx->prefetch_enc_fn)
++            ctx->prefetch_enc_fn();
++
++          crypt_fn = ctx->encrypt_fn;
++        }
++      else
++        {
++          check_decryption_preparation (ctx);
++
++          if (ctx->prefetch_dec_fn)
++            ctx->prefetch_dec_fn();
++
++          crypt_fn = ctx->decrypt_fn;
++        }
++
++      tweak_next_lo = buf_get_le64 (tweak + 0);
++      tweak_next_hi = buf_get_le64 (tweak + 8);
++
++      while (nblocks)
++	{
++	  tweak_lo = tweak_next_lo;
++	  tweak_hi = tweak_next_hi;
++
++	  /* Xor-Encrypt/Decrypt-Xor block. */
++	  tmp_lo = buf_get_le64 (inbuf + 0) ^ tweak_lo;
++	  tmp_hi = buf_get_le64 (inbuf + 8) ^ tweak_hi;
++
++	  buf_put_le64 (outbuf + 0, tmp_lo);
++	  buf_put_le64 (outbuf + 8, tmp_hi);
++
++	  /* Generate next tweak. */
++	  carry = -(tweak_next_hi >> 63) & 0x87;
++	  tweak_next_hi = (tweak_next_hi << 1) + (tweak_next_lo >> 63);
++	  tweak_next_lo = (tweak_next_lo << 1) ^ carry;
++
++	  burn_depth = crypt_fn (ctx, outbuf, outbuf);
++
++	  buf_put_le64 (outbuf + 0, buf_get_le64 (outbuf + 0) ^ tweak_lo);
++	  buf_put_le64 (outbuf + 8, buf_get_le64 (outbuf + 8) ^ tweak_hi);
++
++	  outbuf += GCRY_XTS_BLOCK_LEN;
++	  inbuf += GCRY_XTS_BLOCK_LEN;
++	  nblocks--;
++	}
++
++      buf_put_le64 (tweak + 0, tweak_next_lo);
++      buf_put_le64 (tweak + 8, tweak_next_hi);
++    }
++
++  if (burn_depth)
++    _gcry_burn_stack (burn_depth + 5 * sizeof(void *));
++}
++
+ 
+ /* Run the self-tests for AES 128.  Returns NULL on success. */
+ static const char*
+@@ -1522,7 +1873,7 @@ selftest_basic_128 (void)
+   if (!ctx)
+     return "failed to allocate memory";
+ 
+-  rijndael_setkey (ctx, key_128, sizeof (key_128));
++  rijndael_setkey (ctx, key_128, sizeof (key_128), NULL);
+   rijndael_encrypt (ctx, scratch, plaintext_128);
+   if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128)))
+     {
+@@ -1565,7 +1916,7 @@ selftest_basic_192 (void)
+   ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem);
+   if (!ctx)
+     return "failed to allocate memory";
+-  rijndael_setkey (ctx, key_192, sizeof(key_192));
++  rijndael_setkey (ctx, key_192, sizeof(key_192), NULL);
+   rijndael_encrypt (ctx, scratch, plaintext_192);
+   if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192)))
+     {
+@@ -1610,7 +1961,7 @@ selftest_basic_256 (void)
+   ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem);
+   if (!ctx)
+     return "failed to allocate memory";
+-  rijndael_setkey (ctx, key_256, sizeof(key_256));
++  rijndael_setkey (ctx, key_256, sizeof(key_256), NULL);
+   rijndael_encrypt (ctx, scratch, plaintext_256);
+   if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
+     {
+diff -up libgcrypt-1.8.5/cipher/rijndael-internal.h.aes-perf libgcrypt-1.8.5/cipher/rijndael-internal.h
+--- libgcrypt-1.8.5/cipher/rijndael-internal.h.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rijndael-internal.h	2020-04-22 18:29:41.676862114 +0200
+@@ -73,7 +73,7 @@
+ #   define USE_PADLOCK 1
+ #  endif
+ # endif
+-#endif /*ENABLE_PADLOCK_SUPPORT*/
++#endif /* ENABLE_PADLOCK_SUPPORT */
+ 
+ /* USE_AESNI inidicates whether to compile with Intel AES-NI code.  We
+    need the vector-size attribute which seems to be available since
+@@ -102,6 +102,23 @@
+ # endif
+ #endif /* ENABLE_ARM_CRYPTO_SUPPORT */
+ 
++/* USE_PPC_CRYPTO indicates whether to enable PowerPC vector crypto
++ * accelerated code.  USE_PPC_CRYPTO_WITH_PPC9LE indicates whether to
++ * enable POWER9 optimized variant.  */
++#undef USE_PPC_CRYPTO
++#undef USE_PPC_CRYPTO_WITH_PPC9LE
++#ifdef ENABLE_PPC_CRYPTO_SUPPORT
++# if defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \
++     defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC)
++#  if __GNUC__ >= 4
++#   define USE_PPC_CRYPTO 1
++#   if !defined(WORDS_BIGENDIAN) && defined(HAVE_GCC_INLINE_ASM_PPC_ARCH_3_00)
++#    define USE_PPC_CRYPTO_WITH_PPC9LE 1
++#   endif
++#  endif
++# endif
++#endif /* ENABLE_PPC_CRYPTO_SUPPORT */
++
+ struct RIJNDAEL_context_s;
+ 
+ typedef unsigned int (*rijndael_cryptfn_t)(const struct RIJNDAEL_context_s *ctx,
+@@ -150,6 +167,12 @@ typedef struct RIJNDAEL_context_s
+ #ifdef USE_ARM_CE
+   unsigned int use_arm_ce:1;          /* ARMv8 CE shall be used.  */
+ #endif /*USE_ARM_CE*/
++#ifdef USE_PPC_CRYPTO
++  unsigned int use_ppc_crypto:1;      /* PowerPC crypto shall be used.  */
++#endif /*USE_PPC_CRYPTO*/
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++  unsigned int use_ppc9le_crypto:1;   /* POWER9 LE crypto shall be used.  */
++#endif
+   rijndael_cryptfn_t encrypt_fn;
+   rijndael_cryptfn_t decrypt_fn;
+   rijndael_prefetchfn_t prefetch_enc_fn;
+diff -up libgcrypt-1.8.5/cipher/rijndael-ppc9le.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc9le.c
+--- libgcrypt-1.8.5/cipher/rijndael-ppc9le.c.aes-perf	2020-04-22 18:29:41.677862096 +0200
++++ libgcrypt-1.8.5/cipher/rijndael-ppc9le.c	2020-04-22 18:29:41.677862096 +0200
+@@ -0,0 +1,102 @@
++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation
++ * Copyright (C) 2019 Shawn Landden <shawn@git.icu>
++ * Copyright (C) 2019-2020 Jussi Kivilinna <jussi.kivilinna@iki.fi>
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project,
++ * and Cryptogams by Andy Polyakov, and if made part of a release of either
++ * or both projects, is thereafter dual-licensed under the license said project
++ * is released under.
++ */
++
++#include <config.h>
++
++#include "rijndael-internal.h"
++#include "cipher-internal.h"
++#include "bufhelp.h"
++
++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE
++
++#include "rijndael-ppc-common.h"
++
++
++static ASM_FUNC_ATTR_INLINE block
++asm_load_be_const(void)
++{
++  static const block vec_dummy = { 0 };
++  return vec_dummy;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_be_swap(block vec, block be_bswap_const)
++{
++  (void)be_bswap_const;
++  return vec;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_load_be_noswap(unsigned long offset, const void *ptr)
++{
++  block vec;
++#if __GNUC__ >= 4
++  if (__builtin_constant_p (offset) && offset == 0)
++    __asm__ volatile ("lxvb16x %x0,0,%1\n\t"
++		      : "=wa" (vec)
++		      : "r" ((uintptr_t)ptr)
++		      : "memory");
++  else
++#endif
++    __asm__ volatile ("lxvb16x %x0,%1,%2\n\t"
++		      : "=wa" (vec)
++		      : "r" (offset), "r" ((uintptr_t)ptr)
++		      : "memory", "r0");
++  return vec;
++}
++
++static ASM_FUNC_ATTR_INLINE void
++asm_store_be_noswap(block vec, unsigned long offset, void *ptr)
++{
++#if __GNUC__ >= 4
++  if (__builtin_constant_p (offset) && offset == 0)
++    __asm__ volatile ("stxvb16x %x0,0,%1\n\t"
++		      :
++		      : "wa" (vec), "r" ((uintptr_t)ptr)
++		      : "memory");
++  else
++#endif
++    __asm__ volatile ("stxvb16x %x0,%1,%2\n\t"
++		      :
++		      : "wa" (vec), "r" (offset), "r" ((uintptr_t)ptr)
++		      : "memory", "r0");
++}
++
++
++#define GCRY_AES_PPC9LE 1
++#define ENCRYPT_BLOCK_FUNC	_gcry_aes_ppc9le_encrypt
++#define DECRYPT_BLOCK_FUNC	_gcry_aes_ppc9le_decrypt
++#define CFB_ENC_FUNC		_gcry_aes_ppc9le_cfb_enc
++#define CFB_DEC_FUNC		_gcry_aes_ppc9le_cfb_dec
++#define CBC_ENC_FUNC		_gcry_aes_ppc9le_cbc_enc
++#define CBC_DEC_FUNC		_gcry_aes_ppc9le_cbc_dec
++#define CTR_ENC_FUNC		_gcry_aes_ppc9le_ctr_enc
++#define OCB_CRYPT_FUNC		_gcry_aes_ppc9le_ocb_crypt
++#define OCB_AUTH_FUNC		_gcry_aes_ppc9le_ocb_auth
++#define XTS_CRYPT_FUNC		_gcry_aes_ppc9le_xts_crypt
++
++#include <rijndael-ppc-functions.h>
++
++#endif /* USE_PPC_CRYPTO */
+diff -up libgcrypt-1.8.5/cipher/rijndael-ppc.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc.c
+--- libgcrypt-1.8.5/cipher/rijndael-ppc.c.aes-perf	2020-04-22 18:29:41.677862096 +0200
++++ libgcrypt-1.8.5/cipher/rijndael-ppc.c	2020-04-22 18:29:41.677862096 +0200
+@@ -0,0 +1,259 @@
++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation
++ * Copyright (C) 2019 Shawn Landden <shawn@git.icu>
++ * Copyright (C) 2019-2020 Jussi Kivilinna <jussi.kivilinna@iki.fi>
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project,
++ * and Cryptogams by Andy Polyakov, and if made part of a release of either
++ * or both projects, is thereafter dual-licensed under the license said project
++ * is released under.
++ */
++
++#include <config.h>
++
++#include "rijndael-internal.h"
++#include "cipher-internal.h"
++#include "bufhelp.h"
++
++#ifdef USE_PPC_CRYPTO
++
++#include "rijndael-ppc-common.h"
++
++
++#ifdef WORDS_BIGENDIAN
++static const block vec_bswap32_const =
++  { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 };
++#else
++static const block vec_bswap32_const_neg =
++  { ~3, ~2, ~1, ~0, ~7, ~6, ~5, ~4, ~11, ~10, ~9, ~8, ~15, ~14, ~13, ~12 };
++#endif
++
++
++static ASM_FUNC_ATTR_INLINE block
++asm_load_be_const(void)
++{
++#ifndef WORDS_BIGENDIAN
++  return ALIGNED_LOAD (&vec_bswap32_const_neg, 0);
++#else
++  static const block vec_dummy = { 0 };
++  return vec_dummy;
++#endif
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_be_swap(block vec, block be_bswap_const)
++{
++  (void)be_bswap_const;
++#ifndef WORDS_BIGENDIAN
++  return asm_vperm1 (vec, be_bswap_const);
++#else
++  return vec;
++#endif
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_load_be_noswap(unsigned long offset, const void *ptr)
++{
++  block vec;
++#if __GNUC__ >= 4
++  if (__builtin_constant_p (offset) && offset == 0)
++    __asm__ volatile ("lxvw4x %x0,0,%1\n\t"
++		      : "=wa" (vec)
++		      : "r" ((uintptr_t)ptr)
++		      : "memory");
++  else
++#endif
++    __asm__ volatile ("lxvw4x %x0,%1,%2\n\t"
++		      : "=wa" (vec)
++		      : "r" (offset), "r" ((uintptr_t)ptr)
++		      : "memory", "r0");
++  /* NOTE: vec needs to be be-swapped using 'asm_be_swap' by caller */
++  return vec;
++}
++
++static ASM_FUNC_ATTR_INLINE void
++asm_store_be_noswap(block vec, unsigned long offset, void *ptr)
++{
++  /* NOTE: vec be-swapped using 'asm_be_swap' by caller */
++#if __GNUC__ >= 4
++  if (__builtin_constant_p (offset) && offset == 0)
++    __asm__ volatile ("stxvw4x %x0,0,%1\n\t"
++		      :
++		      : "wa" (vec), "r" ((uintptr_t)ptr)
++		      : "memory");
++  else
++#endif
++    __asm__ volatile ("stxvw4x %x0,%1,%2\n\t"
++		      :
++		      : "wa" (vec), "r" (offset), "r" ((uintptr_t)ptr)
++		      : "memory", "r0");
++}
++
++
++static ASM_FUNC_ATTR_INLINE u32
++_gcry_aes_sbox4_ppc8(u32 fourbytes)
++{
++  union
++    {
++      PROPERLY_ALIGNED_TYPE dummy;
++      block data_vec;
++      u32 data32[4];
++    } u;
++
++  u.data32[0] = fourbytes;
++  u.data_vec = vec_sbox_be(u.data_vec);
++  return u.data32[0];
++}
++
++void
++_gcry_aes_ppc8_setkey (RIJNDAEL_context *ctx, const byte *key)
++{
++  const block bige_const = asm_load_be_const();
++  union
++    {
++      PROPERLY_ALIGNED_TYPE dummy;
++      byte data[MAXKC][4];
++      u32 data32[MAXKC];
++    } tkk[2];
++  unsigned int rounds = ctx->rounds;
++  int KC = rounds - 6;
++  unsigned int keylen = KC * 4;
++  u128_t *ekey = (u128_t *)(void *)ctx->keyschenc;
++  unsigned int i, r, t;
++  byte rcon = 1;
++  int j;
++#define k      tkk[0].data
++#define k_u32  tkk[0].data32
++#define tk     tkk[1].data
++#define tk_u32 tkk[1].data32
++#define W      (ctx->keyschenc)
++#define W_u32  (ctx->keyschenc32)
++
++  for (i = 0; i < keylen; i++)
++    {
++      k[i >> 2][i & 3] = key[i];
++    }
++
++  for (j = KC-1; j >= 0; j--)
++    {
++      tk_u32[j] = k_u32[j];
++    }
++  r = 0;
++  t = 0;
++  /* Copy values into round key array.  */
++  for (j = 0; (j < KC) && (r < rounds + 1); )
++    {
++      for (; (j < KC) && (t < 4); j++, t++)
++        {
++          W_u32[r][t] = le_bswap32(tk_u32[j]);
++        }
++      if (t == 4)
++        {
++          r++;
++          t = 0;
++        }
++    }
++  while (r < rounds + 1)
++    {
++      tk_u32[0] ^=
++	le_bswap32(
++	  _gcry_aes_sbox4_ppc8(rol(le_bswap32(tk_u32[KC - 1]), 24)) ^ rcon);
++
++      if (KC != 8)
++        {
++          for (j = 1; j < KC; j++)
++            {
++              tk_u32[j] ^= tk_u32[j-1];
++            }
++        }
++      else
++        {
++          for (j = 1; j < KC/2; j++)
++            {
++              tk_u32[j] ^= tk_u32[j-1];
++            }
++
++          tk_u32[KC/2] ^=
++	    le_bswap32(_gcry_aes_sbox4_ppc8(le_bswap32(tk_u32[KC/2 - 1])));
++
++          for (j = KC/2 + 1; j < KC; j++)
++            {
++              tk_u32[j] ^= tk_u32[j-1];
++            }
++        }
++
++      /* Copy values into round key array.  */
++      for (j = 0; (j < KC) && (r < rounds + 1); )
++        {
++          for (; (j < KC) && (t < 4); j++, t++)
++            {
++              W_u32[r][t] = le_bswap32(tk_u32[j]);
++            }
++          if (t == 4)
++            {
++              r++;
++              t = 0;
++            }
++        }
++
++      rcon = (rcon << 1) ^ (-(rcon >> 7) & 0x1b);
++    }
++
++  /* Store in big-endian order. */
++  for (r = 0; r <= rounds; r++)
++    {
++#ifndef WORDS_BIGENDIAN
++      VEC_STORE_BE(ekey, r, ALIGNED_LOAD (ekey, r), bige_const);
++#else
++      block rvec = ALIGNED_LOAD (ekey, r);
++      ALIGNED_STORE (ekey, r,
++                     vec_perm(rvec, rvec, vec_bswap32_const));
++      (void)bige_const;
++#endif
++    }
++
++#undef W
++#undef tk
++#undef k
++#undef W_u32
++#undef tk_u32
++#undef k_u32
++  wipememory(&tkk, sizeof(tkk));
++}
++
++void
++_gcry_aes_ppc8_prepare_decryption (RIJNDAEL_context *ctx)
++{
++  internal_aes_ppc_prepare_decryption (ctx);
++}
++
++
++#define GCRY_AES_PPC8 1
++#define ENCRYPT_BLOCK_FUNC	_gcry_aes_ppc8_encrypt
++#define DECRYPT_BLOCK_FUNC	_gcry_aes_ppc8_decrypt
++#define CFB_ENC_FUNC		_gcry_aes_ppc8_cfb_enc
++#define CFB_DEC_FUNC		_gcry_aes_ppc8_cfb_dec
++#define CBC_ENC_FUNC		_gcry_aes_ppc8_cbc_enc
++#define CBC_DEC_FUNC		_gcry_aes_ppc8_cbc_dec
++#define CTR_ENC_FUNC		_gcry_aes_ppc8_ctr_enc
++#define OCB_CRYPT_FUNC		_gcry_aes_ppc8_ocb_crypt
++#define OCB_AUTH_FUNC		_gcry_aes_ppc8_ocb_auth
++#define XTS_CRYPT_FUNC		_gcry_aes_ppc8_xts_crypt
++
++#include <rijndael-ppc-functions.h>
++
++#endif /* USE_PPC_CRYPTO */
+diff -up libgcrypt-1.8.5/cipher/rijndael-ppc-common.h.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc-common.h
+--- libgcrypt-1.8.5/cipher/rijndael-ppc-common.h.aes-perf	2020-04-22 18:29:41.678862076 +0200
++++ libgcrypt-1.8.5/cipher/rijndael-ppc-common.h	2020-04-22 18:29:41.678862076 +0200
+@@ -0,0 +1,342 @@
++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation
++ * Copyright (C) 2019 Shawn Landden <shawn@git.icu>
++ * Copyright (C) 2019-2020 Jussi Kivilinna <jussi.kivilinna@iki.fi>
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project,
++ * and Cryptogams by Andy Polyakov, and if made part of a release of either
++ * or both projects, is thereafter dual-licensed under the license said project
++ * is released under.
++ */
++
++#ifndef G10_RIJNDAEL_PPC_COMMON_H
++#define G10_RIJNDAEL_PPC_COMMON_H
++
++#include <altivec.h>
++
++
++typedef vector unsigned char block;
++
++typedef union
++{
++  u32 data32[4];
++} __attribute__((packed, aligned(1), may_alias)) u128_t;
++
++
++#define ALWAYS_INLINE inline __attribute__((always_inline))
++#define NO_INLINE __attribute__((noinline))
++#define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function))
++
++#define ASM_FUNC_ATTR          NO_INSTRUMENT_FUNCTION
++#define ASM_FUNC_ATTR_INLINE   ASM_FUNC_ATTR ALWAYS_INLINE
++#define ASM_FUNC_ATTR_NOINLINE ASM_FUNC_ATTR NO_INLINE
++
++
++#define ALIGNED_LOAD(in_ptr, offs) \
++  (asm_aligned_ld ((offs) * 16, (const void *)(in_ptr)))
++
++#define ALIGNED_STORE(out_ptr, offs, vec) \
++  (asm_aligned_st ((vec), (offs) * 16, (void *)(out_ptr)))
++
++#define VEC_BE_SWAP(vec, bige_const) (asm_be_swap ((vec), (bige_const)))
++
++#define VEC_LOAD_BE(in_ptr, offs, bige_const) \
++  (asm_be_swap (asm_load_be_noswap ((offs) * 16, (const void *)(in_ptr)), \
++		bige_const))
++
++#define VEC_LOAD_BE_NOSWAP(in_ptr, offs) \
++  (asm_load_be_noswap ((offs) * 16, (const unsigned char *)(in_ptr)))
++
++#define VEC_STORE_BE(out_ptr, offs, vec, bige_const) \
++  (asm_store_be_noswap (asm_be_swap ((vec), (bige_const)), (offs) * 16, \
++		        (void *)(out_ptr)))
++
++#define VEC_STORE_BE_NOSWAP(out_ptr, offs, vec) \
++  (asm_store_be_noswap ((vec), (offs) * 16, (void *)(out_ptr)))
++
++
++#define ROUND_KEY_VARIABLES \
++  block rkey0, rkeylast
++
++#define PRELOAD_ROUND_KEYS(nrounds) \
++  do { \
++    rkey0 = ALIGNED_LOAD (rk, 0); \
++    rkeylast = ALIGNED_LOAD (rk, nrounds); \
++  } while (0)
++
++#define AES_ENCRYPT(blk, nrounds) \
++  do { \
++    blk ^= rkey0; \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 1)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 2)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 3)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 4)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 5)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 6)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 7)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 8)); \
++    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 9)); \
++    if (nrounds >= 12) \
++      { \
++	blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 10)); \
++	blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 11)); \
++	if (rounds > 12) \
++	  { \
++	    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 12)); \
++	    blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 13)); \
++	  } \
++      } \
++    blk = asm_cipherlast_be (blk, rkeylast); \
++  } while (0)
++
++#define AES_DECRYPT(blk, nrounds) \
++  do { \
++    blk ^= rkey0; \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 1)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 2)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 3)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 4)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 5)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 6)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 7)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 8)); \
++    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 9)); \
++    if (nrounds >= 12) \
++      { \
++	blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 10)); \
++	blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 11)); \
++	if (rounds > 12) \
++	  { \
++	    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 12)); \
++	    blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 13)); \
++	  } \
++      } \
++    blk = asm_ncipherlast_be (blk, rkeylast); \
++  } while (0)
++
++
++#define ROUND_KEY_VARIABLES_ALL \
++  block rkey0, rkey1, rkey2, rkey3, rkey4, rkey5, rkey6, rkey7, rkey8, \
++        rkey9, rkey10, rkey11, rkey12, rkey13, rkeylast
++
++#define PRELOAD_ROUND_KEYS_ALL(nrounds) \
++  do { \
++    rkey0 = ALIGNED_LOAD (rk, 0); \
++    rkey1 = ALIGNED_LOAD (rk, 1); \
++    rkey2 = ALIGNED_LOAD (rk, 2); \
++    rkey3 = ALIGNED_LOAD (rk, 3); \
++    rkey4 = ALIGNED_LOAD (rk, 4); \
++    rkey5 = ALIGNED_LOAD (rk, 5); \
++    rkey6 = ALIGNED_LOAD (rk, 6); \
++    rkey7 = ALIGNED_LOAD (rk, 7); \
++    rkey8 = ALIGNED_LOAD (rk, 8); \
++    rkey9 = ALIGNED_LOAD (rk, 9); \
++    if (nrounds >= 12) \
++      { \
++	rkey10 = ALIGNED_LOAD (rk, 10); \
++	rkey11 = ALIGNED_LOAD (rk, 11); \
++	if (rounds > 12) \
++	  { \
++	    rkey12 = ALIGNED_LOAD (rk, 12); \
++	    rkey13 = ALIGNED_LOAD (rk, 13); \
++	  } \
++      } \
++    rkeylast = ALIGNED_LOAD (rk, nrounds); \
++  } while (0)
++
++#define AES_ENCRYPT_ALL(blk, nrounds) \
++  do { \
++    blk ^= rkey0; \
++    blk = asm_cipher_be (blk, rkey1); \
++    blk = asm_cipher_be (blk, rkey2); \
++    blk = asm_cipher_be (blk, rkey3); \
++    blk = asm_cipher_be (blk, rkey4); \
++    blk = asm_cipher_be (blk, rkey5); \
++    blk = asm_cipher_be (blk, rkey6); \
++    blk = asm_cipher_be (blk, rkey7); \
++    blk = asm_cipher_be (blk, rkey8); \
++    blk = asm_cipher_be (blk, rkey9); \
++    if (nrounds >= 12) \
++      { \
++	blk = asm_cipher_be (blk, rkey10); \
++	blk = asm_cipher_be (blk, rkey11); \
++	if (rounds > 12) \
++	  { \
++	    blk = asm_cipher_be (blk, rkey12); \
++	    blk = asm_cipher_be (blk, rkey13); \
++	  } \
++      } \
++    blk = asm_cipherlast_be (blk, rkeylast); \
++  } while (0)
++
++
++static ASM_FUNC_ATTR_INLINE block
++asm_aligned_ld(unsigned long offset, const void *ptr)
++{
++  block vec;
++#if __GNUC__ >= 4
++  if (__builtin_constant_p (offset) && offset == 0)
++    __asm__ volatile ("lvx %0,0,%1\n\t"
++		      : "=v" (vec)
++		      : "r" ((uintptr_t)ptr)
++		      : "memory");
++  else
++#endif
++    __asm__ volatile ("lvx %0,%1,%2\n\t"
++		      : "=v" (vec)
++		      : "r" (offset), "r" ((uintptr_t)ptr)
++		      : "memory", "r0");
++  return vec;
++}
++
++static ASM_FUNC_ATTR_INLINE void
++asm_aligned_st(block vec, unsigned long offset, void *ptr)
++{
++#if __GNUC__ >= 4
++  if (__builtin_constant_p (offset) && offset == 0)
++    __asm__ volatile ("stvx %0,0,%1\n\t"
++		      :
++		      : "v" (vec), "r" ((uintptr_t)ptr)
++		      : "memory");
++  else
++#endif
++    __asm__ volatile ("stvx %0,%1,%2\n\t"
++		      :
++		      : "v" (vec), "r" (offset), "r" ((uintptr_t)ptr)
++		      : "memory", "r0");
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_vperm1(block vec, block mask)
++{
++  block o;
++  __asm__ volatile ("vperm %0,%1,%1,%2\n\t"
++		    : "=v" (o)
++		    : "v" (vec), "v" (mask));
++  return o;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_add_uint128(block a, block b)
++{
++  block res;
++  __asm__ volatile ("vadduqm %0,%1,%2\n\t"
++		    : "=v" (res)
++		    : "v" (a), "v" (b));
++  return res;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_add_uint64(block a, block b)
++{
++  block res;
++  __asm__ volatile ("vaddudm %0,%1,%2\n\t"
++		    : "=v" (res)
++		    : "v" (a), "v" (b));
++  return res;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_sra_int64(block a, block b)
++{
++  block res;
++  __asm__ volatile ("vsrad %0,%1,%2\n\t"
++		    : "=v" (res)
++		    : "v" (a), "v" (b));
++  return res;
++}
++
++static block
++asm_swap_uint64_halfs(block a)
++{
++  block res;
++  __asm__ volatile ("xxswapd %x0, %x1"
++		    : "=wa" (res)
++		    : "wa" (a));
++  return res;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_xor(block a, block b)
++{
++  block res;
++  __asm__ volatile ("vxor %0,%1,%2\n\t"
++		    : "=v" (res)
++		    : "v" (a), "v" (b));
++  return res;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_cipher_be(block b, block rk)
++{
++  block o;
++  __asm__ volatile ("vcipher %0, %1, %2\n\t"
++		    : "=v" (o)
++		    : "v" (b), "v" (rk));
++  return o;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_cipherlast_be(block b, block rk)
++{
++  block o;
++  __asm__ volatile ("vcipherlast %0, %1, %2\n\t"
++		    : "=v" (o)
++		    : "v" (b), "v" (rk));
++  return o;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_ncipher_be(block b, block rk)
++{
++  block o;
++  __asm__ volatile ("vncipher %0, %1, %2\n\t"
++		    : "=v" (o)
++		    : "v" (b), "v" (rk));
++  return o;
++}
++
++static ASM_FUNC_ATTR_INLINE block
++asm_ncipherlast_be(block b, block rk)
++{
++  block o;
++  __asm__ volatile ("vncipherlast %0, %1, %2\n\t"
++		    : "=v" (o)
++		    : "v" (b), "v" (rk));
++  return o;
++}
++
++
++/* Make a decryption key from an encryption key. */
++static ASM_FUNC_ATTR_INLINE void
++internal_aes_ppc_prepare_decryption (RIJNDAEL_context *ctx)
++{
++  u128_t *ekey = (u128_t *)(void *)ctx->keyschenc;
++  u128_t *dkey = (u128_t *)(void *)ctx->keyschdec;
++  int rounds = ctx->rounds;
++  int rr;
++  int r;
++
++  r = 0;
++  rr = rounds;
++  for (r = 0, rr = rounds; r <= rounds; r++, rr--)
++    {
++      ALIGNED_STORE (dkey, r, ALIGNED_LOAD (ekey, rr));
++    }
++}
++
++#endif /* G10_RIJNDAEL_PPC_COMMON_H */
+diff -up libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h
+--- libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h.aes-perf	2020-04-22 18:29:41.679862057 +0200
++++ libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h	2020-04-22 18:29:41.679862057 +0200
+@@ -0,0 +1,2020 @@
++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation
++ * Copyright (C) 2019 Shawn Landden <shawn@git.icu>
++ * Copyright (C) 2019-2020 Jussi Kivilinna <jussi.kivilinna@iki.fi>
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project,
++ * and Cryptogams by Andy Polyakov, and if made part of a release of either
++ * or both projects, is thereafter dual-licensed under the license said project
++ * is released under.
++ */
++
++unsigned int ENCRYPT_BLOCK_FUNC (const RIJNDAEL_context *ctx,
++				 unsigned char *out,
++				 const unsigned char *in)
++{
++  const block bige_const = asm_load_be_const();
++  const u128_t *rk = (u128_t *)&ctx->keyschenc;
++  int rounds = ctx->rounds;
++  ROUND_KEY_VARIABLES;
++  block b;
++
++  b = VEC_LOAD_BE (in, 0, bige_const);
++
++  PRELOAD_ROUND_KEYS (rounds);
++
++  AES_ENCRYPT (b, rounds);
++  VEC_STORE_BE (out, 0, b, bige_const);
++
++  return 0; /* does not use stack */
++}
++
++
++unsigned int DECRYPT_BLOCK_FUNC (const RIJNDAEL_context *ctx,
++				 unsigned char *out,
++				 const unsigned char *in)
++{
++  const block bige_const = asm_load_be_const();
++  const u128_t *rk = (u128_t *)&ctx->keyschdec;
++  int rounds = ctx->rounds;
++  ROUND_KEY_VARIABLES;
++  block b;
++
++  b = VEC_LOAD_BE (in, 0, bige_const);
++
++  PRELOAD_ROUND_KEYS (rounds);
++
++  AES_DECRYPT (b, rounds);
++  VEC_STORE_BE (out, 0, b, bige_const);
++
++  return 0; /* does not use stack */
++}
++
++
++void CFB_ENC_FUNC (void *context, unsigned char *iv_arg,
++		   void *outbuf_arg, const void *inbuf_arg,
++		   size_t nblocks)
++{
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = context;
++  const u128_t *rk = (u128_t *)&ctx->keyschenc;
++  const u128_t *in = (const u128_t *)inbuf_arg;
++  u128_t *out = (u128_t *)outbuf_arg;
++  int rounds = ctx->rounds;
++  ROUND_KEY_VARIABLES_ALL;
++  block rkeylast_orig;
++  block iv;
++
++  iv = VEC_LOAD_BE (iv_arg, 0, bige_const);
++
++  PRELOAD_ROUND_KEYS_ALL (rounds);
++  rkeylast_orig = rkeylast;
++
++  for (; nblocks >= 2; nblocks -= 2)
++    {
++      block in2, iv1;
++
++      rkeylast = rkeylast_orig ^ VEC_LOAD_BE (in, 0, bige_const);
++      in2 = VEC_LOAD_BE (in + 1, 0, bige_const);
++      in += 2;
++
++      AES_ENCRYPT_ALL (iv, rounds);
++
++      iv1 = iv;
++      rkeylast = rkeylast_orig ^ in2;
++
++      AES_ENCRYPT_ALL (iv, rounds);
++
++      VEC_STORE_BE (out++, 0, iv1, bige_const);
++      VEC_STORE_BE (out++, 0, iv, bige_const);
++    }
++
++  for (; nblocks; nblocks--)
++    {
++      rkeylast = rkeylast_orig ^ VEC_LOAD_BE (in++, 0, bige_const);
++
++      AES_ENCRYPT_ALL (iv, rounds);
++
++      VEC_STORE_BE (out++, 0, iv, bige_const);
++    }
++
++  VEC_STORE_BE (iv_arg, 0, iv, bige_const);
++}
++
++void CFB_DEC_FUNC (void *context, unsigned char *iv_arg,
++		   void *outbuf_arg, const void *inbuf_arg,
++		   size_t nblocks)
++{
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = context;
++  const u128_t *rk = (u128_t *)&ctx->keyschenc;
++  const u128_t *in = (const u128_t *)inbuf_arg;
++  u128_t *out = (u128_t *)outbuf_arg;
++  int rounds = ctx->rounds;
++  ROUND_KEY_VARIABLES;
++  block rkeylast_orig;
++  block iv, b, bin;
++  block in0, in1, in2, in3, in4, in5, in6, in7;
++  block b0, b1, b2, b3, b4, b5, b6, b7;
++  block rkey;
++
++  iv = VEC_LOAD_BE (iv_arg, 0, bige_const);
++
++  PRELOAD_ROUND_KEYS (rounds);
++  rkeylast_orig = rkeylast;
++
++  for (; nblocks >= 8; nblocks -= 8)
++    {
++      in0 = iv;
++      in1 = VEC_LOAD_BE_NOSWAP (in, 0);
++      in2 = VEC_LOAD_BE_NOSWAP (in, 1);
++      in3 = VEC_LOAD_BE_NOSWAP (in, 2);
++      in4 = VEC_LOAD_BE_NOSWAP (in, 3);
++      in1 = VEC_BE_SWAP (in1, bige_const);
++      in2 = VEC_BE_SWAP (in2, bige_const);
++      in5 = VEC_LOAD_BE_NOSWAP (in, 4);
++      in6 = VEC_LOAD_BE_NOSWAP (in, 5);
++      in3 = VEC_BE_SWAP (in3, bige_const);
++      in4 = VEC_BE_SWAP (in4, bige_const);
++      in7 = VEC_LOAD_BE_NOSWAP (in, 6);
++      iv = VEC_LOAD_BE_NOSWAP (in, 7);
++      in += 8;
++      in5 = VEC_BE_SWAP (in5, bige_const);
++      in6 = VEC_BE_SWAP (in6, bige_const);
++      b0 = asm_xor (rkey0, in0);
++      b1 = asm_xor (rkey0, in1);
++      in7 = VEC_BE_SWAP (in7, bige_const);
++      iv = VEC_BE_SWAP (iv, bige_const);
++      b2 = asm_xor (rkey0, in2);
++      b3 = asm_xor (rkey0, in3);
++      b4 = asm_xor (rkey0, in4);
++      b5 = asm_xor (rkey0, in5);
++      b6 = asm_xor (rkey0, in6);
++      b7 = asm_xor (rkey0, in7);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey); \
++	      b4 = asm_cipher_be (b4, rkey); \
++	      b5 = asm_cipher_be (b5, rkey); \
++	      b6 = asm_cipher_be (b6, rkey); \
++	      b7 = asm_cipher_be (b7, rkey);
++
++      DO_ROUND(1);
++      DO_ROUND(2);
++      DO_ROUND(3);
++      DO_ROUND(4);
++      DO_ROUND(5);
++      DO_ROUND(6);
++      DO_ROUND(7);
++      DO_ROUND(8);
++      DO_ROUND(9);
++      if (rounds >= 12)
++	{
++	  DO_ROUND(10);
++	  DO_ROUND(11);
++	  if (rounds > 12)
++	    {
++	      DO_ROUND(12);
++	      DO_ROUND(13);
++	    }
++	}
++
++#undef DO_ROUND
++
++      in1 = asm_xor (rkeylast, in1);
++      in2 = asm_xor (rkeylast, in2);
++      in3 = asm_xor (rkeylast, in3);
++      in4 = asm_xor (rkeylast, in4);
++      b0 = asm_cipherlast_be (b0, in1);
++      b1 = asm_cipherlast_be (b1, in2);
++      in5 = asm_xor (rkeylast, in5);
++      in6 = asm_xor (rkeylast, in6);
++      b2 = asm_cipherlast_be (b2, in3);
++      b3 = asm_cipherlast_be (b3, in4);
++      in7 = asm_xor (rkeylast, in7);
++      in0 = asm_xor (rkeylast, iv);
++      b0 = VEC_BE_SWAP (b0, bige_const);
++      b1 = VEC_BE_SWAP (b1, bige_const);
++      b4 = asm_cipherlast_be (b4, in5);
++      b5 = asm_cipherlast_be (b5, in6);
++      b2 = VEC_BE_SWAP (b2, bige_const);
++      b3 = VEC_BE_SWAP (b3, bige_const);
++      b6 = asm_cipherlast_be (b6, in7);
++      b7 = asm_cipherlast_be (b7, in0);
++      b4 = VEC_BE_SWAP (b4, bige_const);
++      b5 = VEC_BE_SWAP (b5, bige_const);
++      b6 = VEC_BE_SWAP (b6, bige_const);
++      b7 = VEC_BE_SWAP (b7, bige_const);
++      VEC_STORE_BE_NOSWAP (out, 0, b0);
++      VEC_STORE_BE_NOSWAP (out, 1, b1);
++      VEC_STORE_BE_NOSWAP (out, 2, b2);
++      VEC_STORE_BE_NOSWAP (out, 3, b3);
++      VEC_STORE_BE_NOSWAP (out, 4, b4);
++      VEC_STORE_BE_NOSWAP (out, 5, b5);
++      VEC_STORE_BE_NOSWAP (out, 6, b6);
++      VEC_STORE_BE_NOSWAP (out, 7, b7);
++      out += 8;
++    }
++
++  if (nblocks >= 4)
++    {
++      in0 = iv;
++      in1 = VEC_LOAD_BE (in, 0, bige_const);
++      in2 = VEC_LOAD_BE (in, 1, bige_const);
++      in3 = VEC_LOAD_BE (in, 2, bige_const);
++      iv = VEC_LOAD_BE (in, 3, bige_const);
++
++      b0 = asm_xor (rkey0, in0);
++      b1 = asm_xor (rkey0, in1);
++      b2 = asm_xor (rkey0, in2);
++      b3 = asm_xor (rkey0, in3);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey);
++
++      DO_ROUND(1);
++      DO_ROUND(2);
++      DO_ROUND(3);
++      DO_ROUND(4);
++      DO_ROUND(5);
++      DO_ROUND(6);
++      DO_ROUND(7);
++      DO_ROUND(8);
++      DO_ROUND(9);
++      if (rounds >= 12)
++	{
++	  DO_ROUND(10);
++	  DO_ROUND(11);
++	  if (rounds > 12)
++	    {
++	      DO_ROUND(12);
++	      DO_ROUND(13);
++	    }
++	}
++
++#undef DO_ROUND
++
++      in1 = asm_xor (rkeylast, in1);
++      in2 = asm_xor (rkeylast, in2);
++      in3 = asm_xor (rkeylast, in3);
++      in0 = asm_xor (rkeylast, iv);
++      b0 = asm_cipherlast_be (b0, in1);
++      b1 = asm_cipherlast_be (b1, in2);
++      b2 = asm_cipherlast_be (b2, in3);
++      b3 = asm_cipherlast_be (b3, in0);
++      VEC_STORE_BE (out, 0, b0, bige_const);
++      VEC_STORE_BE (out, 1, b1, bige_const);
++      VEC_STORE_BE (out, 2, b2, bige_const);
++      VEC_STORE_BE (out, 3, b3, bige_const);
++
++      in += 4;
++      out += 4;
++      nblocks -= 4;
++    }
++
++  for (; nblocks; nblocks--)
++    {
++      bin = VEC_LOAD_BE (in, 0, bige_const);
++      rkeylast = rkeylast_orig ^ bin;
++      b = iv;
++      iv = bin;
++
++      AES_ENCRYPT (b, rounds);
++
++      VEC_STORE_BE (out, 0, b, bige_const);
++
++      out++;
++      in++;
++    }
++
++  VEC_STORE_BE (iv_arg, 0, iv, bige_const);
++}
++
++
++void CBC_ENC_FUNC (void *context, unsigned char *iv_arg,
++		   void *outbuf_arg, const void *inbuf_arg,
++		   size_t nblocks, int cbc_mac)
++{
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = context;
++  const u128_t *rk = (u128_t *)&ctx->keyschenc;
++  const u128_t *in = (const u128_t *)inbuf_arg;
++  byte *out = (byte *)outbuf_arg;
++  int rounds = ctx->rounds;
++  ROUND_KEY_VARIABLES_ALL;
++  block lastiv, b;
++  unsigned int outadd = -(!cbc_mac) & 16;
++
++  lastiv = VEC_LOAD_BE (iv_arg, 0, bige_const);
++
++  PRELOAD_ROUND_KEYS_ALL (rounds);
++
++  for (; nblocks >= 2; nblocks -= 2)
++    {
++      block in2, lastiv1;
++
++      b = lastiv ^ VEC_LOAD_BE (in, 0, bige_const);
++      in2 = VEC_LOAD_BE (in + 1, 0, bige_const);
++      in += 2;
++
++      AES_ENCRYPT_ALL (b, rounds);
++
++      lastiv1 = b;
++      b = lastiv1 ^ in2;
++
++      AES_ENCRYPT_ALL (b, rounds);
++
++      lastiv = b;
++      VEC_STORE_BE ((u128_t *)out, 0, lastiv1, bige_const);
++      out += outadd;
++      VEC_STORE_BE ((u128_t *)out, 0, lastiv, bige_const);
++      out += outadd;
++    }
++
++  for (; nblocks; nblocks--)
++    {
++      b = lastiv ^ VEC_LOAD_BE (in++, 0, bige_const);
++
++      AES_ENCRYPT_ALL (b, rounds);
++
++      lastiv = b;
++      VEC_STORE_BE ((u128_t *)out, 0, b, bige_const);
++      out += outadd;
++    }
++
++  VEC_STORE_BE (iv_arg, 0, lastiv, bige_const);
++}
++
++void CBC_DEC_FUNC (void *context, unsigned char *iv_arg,
++		   void *outbuf_arg, const void *inbuf_arg,
++		   size_t nblocks)
++{
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = context;
++  const u128_t *rk = (u128_t *)&ctx->keyschdec;
++  const u128_t *in = (const u128_t *)inbuf_arg;
++  u128_t *out = (u128_t *)outbuf_arg;
++  int rounds = ctx->rounds;
++  ROUND_KEY_VARIABLES;
++  block rkeylast_orig;
++  block in0, in1, in2, in3, in4, in5, in6, in7;
++  block b0, b1, b2, b3, b4, b5, b6, b7;
++  block rkey;
++  block iv, b;
++
++  if (!ctx->decryption_prepared)
++    {
++      internal_aes_ppc_prepare_decryption (ctx);
++      ctx->decryption_prepared = 1;
++    }
++
++  iv = VEC_LOAD_BE (iv_arg, 0, bige_const);
++
++  PRELOAD_ROUND_KEYS (rounds);
++  rkeylast_orig = rkeylast;
++
++  for (; nblocks >= 8; nblocks -= 8)
++    {
++      in0 = VEC_LOAD_BE_NOSWAP (in, 0);
++      in1 = VEC_LOAD_BE_NOSWAP (in, 1);
++      in2 = VEC_LOAD_BE_NOSWAP (in, 2);
++      in3 = VEC_LOAD_BE_NOSWAP (in, 3);
++      in0 = VEC_BE_SWAP (in0, bige_const);
++      in1 = VEC_BE_SWAP (in1, bige_const);
++      in4 = VEC_LOAD_BE_NOSWAP (in, 4);
++      in5 = VEC_LOAD_BE_NOSWAP (in, 5);
++      in2 = VEC_BE_SWAP (in2, bige_const);
++      in3 = VEC_BE_SWAP (in3, bige_const);
++      in6 = VEC_LOAD_BE_NOSWAP (in, 6);
++      in7 = VEC_LOAD_BE_NOSWAP (in, 7);
++      in += 8;
++      b0 = asm_xor (rkey0, in0);
++      b1 = asm_xor (rkey0, in1);
++      in4 = VEC_BE_SWAP (in4, bige_const);
++      in5 = VEC_BE_SWAP (in5, bige_const);
++      b2 = asm_xor (rkey0, in2);
++      b3 = asm_xor (rkey0, in3);
++      in6 = VEC_BE_SWAP (in6, bige_const);
++      in7 = VEC_BE_SWAP (in7, bige_const);
++      b4 = asm_xor (rkey0, in4);
++      b5 = asm_xor (rkey0, in5);
++      b6 = asm_xor (rkey0, in6);
++      b7 = asm_xor (rkey0, in7);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_ncipher_be (b0, rkey); \
++	      b1 = asm_ncipher_be (b1, rkey); \
++	      b2 = asm_ncipher_be (b2, rkey); \
++	      b3 = asm_ncipher_be (b3, rkey); \
++	      b4 = asm_ncipher_be (b4, rkey); \
++	      b5 = asm_ncipher_be (b5, rkey); \
++	      b6 = asm_ncipher_be (b6, rkey); \
++	      b7 = asm_ncipher_be (b7, rkey);
++
++      DO_ROUND(1);
++      DO_ROUND(2);
++      DO_ROUND(3);
++      DO_ROUND(4);
++      DO_ROUND(5);
++      DO_ROUND(6);
++      DO_ROUND(7);
++      DO_ROUND(8);
++      DO_ROUND(9);
++      if (rounds >= 12)
++	{
++	  DO_ROUND(10);
++	  DO_ROUND(11);
++	  if (rounds > 12)
++	    {
++	      DO_ROUND(12);
++	      DO_ROUND(13);
++	    }
++	}
++
++#undef DO_ROUND
++
++      iv = asm_xor (rkeylast, iv);
++      in0 = asm_xor (rkeylast, in0);
++      in1 = asm_xor (rkeylast, in1);
++      in2 = asm_xor (rkeylast, in2);
++      b0 = asm_ncipherlast_be (b0, iv);
++      iv = in7;
++      b1 = asm_ncipherlast_be (b1, in0);
++      in3 = asm_xor (rkeylast, in3);
++      in4 = asm_xor (rkeylast, in4);
++      b2 = asm_ncipherlast_be (b2, in1);
++      b3 = asm_ncipherlast_be (b3, in2);
++      in5 = asm_xor (rkeylast, in5);
++      in6 = asm_xor (rkeylast, in6);
++      b0 = VEC_BE_SWAP (b0, bige_const);
++      b1 = VEC_BE_SWAP (b1, bige_const);
++      b4 = asm_ncipherlast_be (b4, in3);
++      b5 = asm_ncipherlast_be (b5, in4);
++      b2 = VEC_BE_SWAP (b2, bige_const);
++      b3 = VEC_BE_SWAP (b3, bige_const);
++      b6 = asm_ncipherlast_be (b6, in5);
++      b7 = asm_ncipherlast_be (b7, in6);
++      b4 = VEC_BE_SWAP (b4, bige_const);
++      b5 = VEC_BE_SWAP (b5, bige_const);
++      b6 = VEC_BE_SWAP (b6, bige_const);
++      b7 = VEC_BE_SWAP (b7, bige_const);
++      VEC_STORE_BE_NOSWAP (out, 0, b0);
++      VEC_STORE_BE_NOSWAP (out, 1, b1);
++      VEC_STORE_BE_NOSWAP (out, 2, b2);
++      VEC_STORE_BE_NOSWAP (out, 3, b3);
++      VEC_STORE_BE_NOSWAP (out, 4, b4);
++      VEC_STORE_BE_NOSWAP (out, 5, b5);
++      VEC_STORE_BE_NOSWAP (out, 6, b6);
++      VEC_STORE_BE_NOSWAP (out, 7, b7);
++      out += 8;
++    }
++
++  if (nblocks >= 4)
++    {
++      in0 = VEC_LOAD_BE (in, 0, bige_const);
++      in1 = VEC_LOAD_BE (in, 1, bige_const);
++      in2 = VEC_LOAD_BE (in, 2, bige_const);
++      in3 = VEC_LOAD_BE (in, 3, bige_const);
++
++      b0 = asm_xor (rkey0, in0);
++      b1 = asm_xor (rkey0, in1);
++      b2 = asm_xor (rkey0, in2);
++      b3 = asm_xor (rkey0, in3);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_ncipher_be (b0, rkey); \
++	      b1 = asm_ncipher_be (b1, rkey); \
++	      b2 = asm_ncipher_be (b2, rkey); \
++	      b3 = asm_ncipher_be (b3, rkey);
++
++      DO_ROUND(1);
++      DO_ROUND(2);
++      DO_ROUND(3);
++      DO_ROUND(4);
++      DO_ROUND(5);
++      DO_ROUND(6);
++      DO_ROUND(7);
++      DO_ROUND(8);
++      DO_ROUND(9);
++      if (rounds >= 12)
++	{
++	  DO_ROUND(10);
++	  DO_ROUND(11);
++	  if (rounds > 12)
++	    {
++	      DO_ROUND(12);
++	      DO_ROUND(13);
++	    }
++	}
++
++#undef DO_ROUND
++
++      iv = asm_xor (rkeylast, iv);
++      in0 = asm_xor (rkeylast, in0);
++      in1 = asm_xor (rkeylast, in1);
++      in2 = asm_xor (rkeylast, in2);
++
++      b0 = asm_ncipherlast_be (b0, iv);
++      iv = in3;
++      b1 = asm_ncipherlast_be (b1, in0);
++      b2 = asm_ncipherlast_be (b2, in1);
++      b3 = asm_ncipherlast_be (b3, in2);
++
++      VEC_STORE_BE (out, 0, b0, bige_const);
++      VEC_STORE_BE (out, 1, b1, bige_const);
++      VEC_STORE_BE (out, 2, b2, bige_const);
++      VEC_STORE_BE (out, 3, b3, bige_const);
++
++      in += 4;
++      out += 4;
++      nblocks -= 4;
++    }
++
++  for (; nblocks; nblocks--)
++    {
++      rkeylast = rkeylast_orig ^ iv;
++
++      iv = VEC_LOAD_BE (in, 0, bige_const);
++      b = iv;
++      AES_DECRYPT (b, rounds);
++
++      VEC_STORE_BE (out, 0, b, bige_const);
++
++      in++;
++      out++;
++    }
++
++  VEC_STORE_BE (iv_arg, 0, iv, bige_const);
++}
++
++
++void CTR_ENC_FUNC (void *context, unsigned char *ctr_arg,
++		   void *outbuf_arg, const void *inbuf_arg,
++		   size_t nblocks)
++{
++  static const unsigned char vec_one_const[16] =
++    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = context;
++  const u128_t *rk = (u128_t *)&ctx->keyschenc;
++  const u128_t *in = (const u128_t *)inbuf_arg;
++  u128_t *out = (u128_t *)outbuf_arg;
++  int rounds = ctx->rounds;
++  ROUND_KEY_VARIABLES;
++  block rkeylast_orig;
++  block ctr, b, one;
++
++  ctr = VEC_LOAD_BE (ctr_arg, 0, bige_const);
++  one = VEC_LOAD_BE (&vec_one_const, 0, bige_const);
++
++  PRELOAD_ROUND_KEYS (rounds);
++  rkeylast_orig = rkeylast;
++
++  if (nblocks >= 4)
++    {
++      block in0, in1, in2, in3, in4, in5, in6, in7;
++      block b0, b1, b2, b3, b4, b5, b6, b7;
++      block two, three, four;
++      block rkey;
++
++      two   = asm_add_uint128 (one, one);
++      three = asm_add_uint128 (two, one);
++      four  = asm_add_uint128 (two, two);
++
++      for (; nblocks >= 8; nblocks -= 8)
++	{
++	  b1 = asm_add_uint128 (ctr, one);
++	  b2 = asm_add_uint128 (ctr, two);
++	  b3 = asm_add_uint128 (ctr, three);
++	  b4 = asm_add_uint128 (ctr, four);
++	  b5 = asm_add_uint128 (b1, four);
++	  b6 = asm_add_uint128 (b2, four);
++	  b7 = asm_add_uint128 (b3, four);
++	  b0 = asm_xor (rkey0, ctr);
++	  rkey = ALIGNED_LOAD (rk, 1);
++	  ctr = asm_add_uint128 (b4, four);
++	  b1 = asm_xor (rkey0, b1);
++	  b2 = asm_xor (rkey0, b2);
++	  b3 = asm_xor (rkey0, b3);
++	  b0 = asm_cipher_be (b0, rkey);
++	  b1 = asm_cipher_be (b1, rkey);
++	  b2 = asm_cipher_be (b2, rkey);
++	  b3 = asm_cipher_be (b3, rkey);
++	  b4 = asm_xor (rkey0, b4);
++	  b5 = asm_xor (rkey0, b5);
++	  b6 = asm_xor (rkey0, b6);
++	  b7 = asm_xor (rkey0, b7);
++	  b4 = asm_cipher_be (b4, rkey);
++	  b5 = asm_cipher_be (b5, rkey);
++	  b6 = asm_cipher_be (b6, rkey);
++	  b7 = asm_cipher_be (b7, rkey);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey); \
++	      b4 = asm_cipher_be (b4, rkey); \
++	      b5 = asm_cipher_be (b5, rkey); \
++	      b6 = asm_cipher_be (b6, rkey); \
++	      b7 = asm_cipher_be (b7, rkey);
++
++	  in0 = VEC_LOAD_BE_NOSWAP (in, 0);
++	  DO_ROUND(2);
++	  in1 = VEC_LOAD_BE_NOSWAP (in, 1);
++	  DO_ROUND(3);
++	  in2 = VEC_LOAD_BE_NOSWAP (in, 2);
++	  DO_ROUND(4);
++	  in3 = VEC_LOAD_BE_NOSWAP (in, 3);
++	  DO_ROUND(5);
++	  in4 = VEC_LOAD_BE_NOSWAP (in, 4);
++	  DO_ROUND(6);
++	  in5 = VEC_LOAD_BE_NOSWAP (in, 5);
++	  DO_ROUND(7);
++	  in6 = VEC_LOAD_BE_NOSWAP (in, 6);
++	  DO_ROUND(8);
++	  in7 = VEC_LOAD_BE_NOSWAP (in, 7);
++	  in += 8;
++	  DO_ROUND(9);
++
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  in0 = VEC_BE_SWAP (in0, bige_const);
++	  in1 = VEC_BE_SWAP (in1, bige_const);
++	  in2 = VEC_BE_SWAP (in2, bige_const);
++	  in3 = VEC_BE_SWAP (in3, bige_const);
++	  in4 = VEC_BE_SWAP (in4, bige_const);
++	  in5 = VEC_BE_SWAP (in5, bige_const);
++	  in6 = VEC_BE_SWAP (in6, bige_const);
++	  in7 = VEC_BE_SWAP (in7, bige_const);
++
++	  in0 = asm_xor (rkeylast, in0);
++	  in1 = asm_xor (rkeylast, in1);
++	  in2 = asm_xor (rkeylast, in2);
++	  in3 = asm_xor (rkeylast, in3);
++	  b0 = asm_cipherlast_be (b0, in0);
++	  b1 = asm_cipherlast_be (b1, in1);
++	  in4 = asm_xor (rkeylast, in4);
++	  in5 = asm_xor (rkeylast, in5);
++	  b2 = asm_cipherlast_be (b2, in2);
++	  b3 = asm_cipherlast_be (b3, in3);
++	  in6 = asm_xor (rkeylast, in6);
++	  in7 = asm_xor (rkeylast, in7);
++	  b4 = asm_cipherlast_be (b4, in4);
++	  b5 = asm_cipherlast_be (b5, in5);
++	  b6 = asm_cipherlast_be (b6, in6);
++	  b7 = asm_cipherlast_be (b7, in7);
++
++	  b0 = VEC_BE_SWAP (b0, bige_const);
++	  b1 = VEC_BE_SWAP (b1, bige_const);
++	  b2 = VEC_BE_SWAP (b2, bige_const);
++	  b3 = VEC_BE_SWAP (b3, bige_const);
++	  b4 = VEC_BE_SWAP (b4, bige_const);
++	  b5 = VEC_BE_SWAP (b5, bige_const);
++	  b6 = VEC_BE_SWAP (b6, bige_const);
++	  b7 = VEC_BE_SWAP (b7, bige_const);
++	  VEC_STORE_BE_NOSWAP (out, 0, b0);
++	  VEC_STORE_BE_NOSWAP (out, 1, b1);
++	  VEC_STORE_BE_NOSWAP (out, 2, b2);
++	  VEC_STORE_BE_NOSWAP (out, 3, b3);
++	  VEC_STORE_BE_NOSWAP (out, 4, b4);
++	  VEC_STORE_BE_NOSWAP (out, 5, b5);
++	  VEC_STORE_BE_NOSWAP (out, 6, b6);
++	  VEC_STORE_BE_NOSWAP (out, 7, b7);
++	  out += 8;
++	}
++
++      if (nblocks >= 4)
++	{
++	  b1 = asm_add_uint128 (ctr, one);
++	  b2 = asm_add_uint128 (ctr, two);
++	  b3 = asm_add_uint128 (ctr, three);
++	  b0 = asm_xor (rkey0, ctr);
++	  ctr = asm_add_uint128 (ctr, four);
++	  b1 = asm_xor (rkey0, b1);
++	  b2 = asm_xor (rkey0, b2);
++	  b3 = asm_xor (rkey0, b3);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++	  DO_ROUND(8);
++
++	  in0 = VEC_LOAD_BE (in, 0, bige_const);
++	  in1 = VEC_LOAD_BE (in, 1, bige_const);
++	  in2 = VEC_LOAD_BE (in, 2, bige_const);
++	  in3 = VEC_LOAD_BE (in, 3, bige_const);
++
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  in0 = asm_xor (rkeylast, in0);
++	  in1 = asm_xor (rkeylast, in1);
++	  in2 = asm_xor (rkeylast, in2);
++	  in3 = asm_xor (rkeylast, in3);
++
++	  b0 = asm_cipherlast_be (b0, in0);
++	  b1 = asm_cipherlast_be (b1, in1);
++	  b2 = asm_cipherlast_be (b2, in2);
++	  b3 = asm_cipherlast_be (b3, in3);
++
++	  VEC_STORE_BE (out, 0, b0, bige_const);
++	  VEC_STORE_BE (out, 1, b1, bige_const);
++	  VEC_STORE_BE (out, 2, b2, bige_const);
++	  VEC_STORE_BE (out, 3, b3, bige_const);
++
++	  in += 4;
++	  out += 4;
++	  nblocks -= 4;
++	}
++    }
++
++  for (; nblocks; nblocks--)
++    {
++      b = ctr;
++      ctr = asm_add_uint128 (ctr, one);
++      rkeylast = rkeylast_orig ^ VEC_LOAD_BE (in, 0, bige_const);
++
++      AES_ENCRYPT (b, rounds);
++
++      VEC_STORE_BE (out, 0, b, bige_const);
++
++      out++;
++      in++;
++    }
++
++  VEC_STORE_BE (ctr_arg, 0, ctr, bige_const);
++}
++
++
++size_t OCB_CRYPT_FUNC (gcry_cipher_hd_t c, void *outbuf_arg,
++		       const void *inbuf_arg, size_t nblocks,
++		       int encrypt)
++{
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = (void *)&c->context.c;
++  const u128_t *in = (const u128_t *)inbuf_arg;
++  u128_t *out = (u128_t *)outbuf_arg;
++  int rounds = ctx->rounds;
++  u64 data_nblocks = c->u_mode.ocb.data_nblocks;
++  block l0, l1, l2, l;
++  block b0, b1, b2, b3, b4, b5, b6, b7, b;
++  block iv0, iv1, iv2, iv3, iv4, iv5, iv6, iv7;
++  block rkey, rkeylf;
++  block ctr, iv;
++  ROUND_KEY_VARIABLES;
++
++  iv = VEC_LOAD_BE (c->u_iv.iv, 0, bige_const);
++  ctr = VEC_LOAD_BE (c->u_ctr.ctr, 0, bige_const);
++
++  l0 = VEC_LOAD_BE (c->u_mode.ocb.L[0], 0, bige_const);
++  l1 = VEC_LOAD_BE (c->u_mode.ocb.L[1], 0, bige_const);
++  l2 = VEC_LOAD_BE (c->u_mode.ocb.L[2], 0, bige_const);
++
++  if (encrypt)
++    {
++      const u128_t *rk = (u128_t *)&ctx->keyschenc;
++
++      PRELOAD_ROUND_KEYS (rounds);
++
++      for (; nblocks >= 8 && data_nblocks % 8; nblocks--)
++	{
++	  l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const);
++	  b = VEC_LOAD_BE (in, 0, bige_const);
++
++	  /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++	  iv ^= l;
++	  /* Checksum_i = Checksum_{i-1} xor P_i  */
++	  ctr ^= b;
++	  /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
++	  b ^= iv;
++	  AES_ENCRYPT (b, rounds);
++	  b ^= iv;
++
++	  VEC_STORE_BE (out, 0, b, bige_const);
++
++	  in += 1;
++	  out += 1;
++	}
++
++      for (; nblocks >= 8; nblocks -= 8)
++	{
++	  b0 = VEC_LOAD_BE_NOSWAP (in, 0);
++	  b1 = VEC_LOAD_BE_NOSWAP (in, 1);
++	  b2 = VEC_LOAD_BE_NOSWAP (in, 2);
++	  b3 = VEC_LOAD_BE_NOSWAP (in, 3);
++	  b4 = VEC_LOAD_BE_NOSWAP (in, 4);
++	  b5 = VEC_LOAD_BE_NOSWAP (in, 5);
++	  b6 = VEC_LOAD_BE_NOSWAP (in, 6);
++	  b7 = VEC_LOAD_BE_NOSWAP (in, 7);
++	  in += 8;
++	  l = VEC_LOAD_BE_NOSWAP (ocb_get_l (c, data_nblocks += 8), 0);
++	  b0 = VEC_BE_SWAP(b0, bige_const);
++	  b1 = VEC_BE_SWAP(b1, bige_const);
++	  b2 = VEC_BE_SWAP(b2, bige_const);
++	  b3 = VEC_BE_SWAP(b3, bige_const);
++	  b4 = VEC_BE_SWAP(b4, bige_const);
++	  b5 = VEC_BE_SWAP(b5, bige_const);
++	  b6 = VEC_BE_SWAP(b6, bige_const);
++	  b7 = VEC_BE_SWAP(b7, bige_const);
++	  l = VEC_BE_SWAP(l, bige_const);
++
++	  ctr ^= b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7;
++
++	  iv ^= rkey0;
++
++	  iv0 = iv ^ l0;
++	  iv1 = iv ^ l0 ^ l1;
++	  iv2 = iv ^ l1;
++	  iv3 = iv ^ l1 ^ l2;
++	  iv4 = iv ^ l1 ^ l2 ^ l0;
++	  iv5 = iv ^ l2 ^ l0;
++	  iv6 = iv ^ l2;
++	  iv7 = iv ^ l2 ^ l;
++
++	  b0 ^= iv0;
++	  b1 ^= iv1;
++	  b2 ^= iv2;
++	  b3 ^= iv3;
++	  b4 ^= iv4;
++	  b5 ^= iv5;
++	  b6 ^= iv6;
++	  b7 ^= iv7;
++	  iv = iv7 ^ rkey0;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey); \
++	      b4 = asm_cipher_be (b4, rkey); \
++	      b5 = asm_cipher_be (b5, rkey); \
++	      b6 = asm_cipher_be (b6, rkey); \
++	      b7 = asm_cipher_be (b7, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++
++	  rkeylf = asm_xor (rkeylast, rkey0);
++
++	  DO_ROUND(8);
++
++	  iv0 = asm_xor (rkeylf, iv0);
++	  iv1 = asm_xor (rkeylf, iv1);
++	  iv2 = asm_xor (rkeylf, iv2);
++	  iv3 = asm_xor (rkeylf, iv3);
++	  iv4 = asm_xor (rkeylf, iv4);
++	  iv5 = asm_xor (rkeylf, iv5);
++	  iv6 = asm_xor (rkeylf, iv6);
++	  iv7 = asm_xor (rkeylf, iv7);
++
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  b0 = asm_cipherlast_be (b0, iv0);
++	  b1 = asm_cipherlast_be (b1, iv1);
++	  b2 = asm_cipherlast_be (b2, iv2);
++	  b3 = asm_cipherlast_be (b3, iv3);
++	  b4 = asm_cipherlast_be (b4, iv4);
++	  b5 = asm_cipherlast_be (b5, iv5);
++	  b6 = asm_cipherlast_be (b6, iv6);
++	  b7 = asm_cipherlast_be (b7, iv7);
++
++	  b0 = VEC_BE_SWAP (b0, bige_const);
++	  b1 = VEC_BE_SWAP (b1, bige_const);
++	  b2 = VEC_BE_SWAP (b2, bige_const);
++	  b3 = VEC_BE_SWAP (b3, bige_const);
++	  b4 = VEC_BE_SWAP (b4, bige_const);
++	  b5 = VEC_BE_SWAP (b5, bige_const);
++	  b6 = VEC_BE_SWAP (b6, bige_const);
++	  b7 = VEC_BE_SWAP (b7, bige_const);
++	  VEC_STORE_BE_NOSWAP (out, 0, b0);
++	  VEC_STORE_BE_NOSWAP (out, 1, b1);
++	  VEC_STORE_BE_NOSWAP (out, 2, b2);
++	  VEC_STORE_BE_NOSWAP (out, 3, b3);
++	  VEC_STORE_BE_NOSWAP (out, 4, b4);
++	  VEC_STORE_BE_NOSWAP (out, 5, b5);
++	  VEC_STORE_BE_NOSWAP (out, 6, b6);
++	  VEC_STORE_BE_NOSWAP (out, 7, b7);
++	  out += 8;
++	}
++
++      if (nblocks >= 4 && (data_nblocks % 4) == 0)
++	{
++	  b0 = VEC_LOAD_BE (in, 0, bige_const);
++	  b1 = VEC_LOAD_BE (in, 1, bige_const);
++	  b2 = VEC_LOAD_BE (in, 2, bige_const);
++	  b3 = VEC_LOAD_BE (in, 3, bige_const);
++
++	  l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 4), 0, bige_const);
++
++	  ctr ^= b0 ^ b1 ^ b2 ^ b3;
++
++	  iv ^= rkey0;
++
++	  iv0 = iv ^ l0;
++	  iv1 = iv ^ l0 ^ l1;
++	  iv2 = iv ^ l1;
++	  iv3 = iv ^ l1 ^ l;
++
++	  b0 ^= iv0;
++	  b1 ^= iv1;
++	  b2 ^= iv2;
++	  b3 ^= iv3;
++	  iv = iv3 ^ rkey0;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++	  DO_ROUND(8);
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  rkey = rkeylast ^ rkey0;
++	  b0 = asm_cipherlast_be (b0, rkey ^ iv0);
++	  b1 = asm_cipherlast_be (b1, rkey ^ iv1);
++	  b2 = asm_cipherlast_be (b2, rkey ^ iv2);
++	  b3 = asm_cipherlast_be (b3, rkey ^ iv3);
++
++	  VEC_STORE_BE (out, 0, b0, bige_const);
++	  VEC_STORE_BE (out, 1, b1, bige_const);
++	  VEC_STORE_BE (out, 2, b2, bige_const);
++	  VEC_STORE_BE (out, 3, b3, bige_const);
++
++	  in += 4;
++	  out += 4;
++	  nblocks -= 4;
++	}
++
++      for (; nblocks; nblocks--)
++	{
++	  l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const);
++	  b = VEC_LOAD_BE (in, 0, bige_const);
++
++	  /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++	  iv ^= l;
++	  /* Checksum_i = Checksum_{i-1} xor P_i  */
++	  ctr ^= b;
++	  /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)  */
++	  b ^= iv;
++	  AES_ENCRYPT (b, rounds);
++	  b ^= iv;
++
++	  VEC_STORE_BE (out, 0, b, bige_const);
++
++	  in += 1;
++	  out += 1;
++	}
++    }
++  else
++    {
++      const u128_t *rk = (u128_t *)&ctx->keyschdec;
++
++      if (!ctx->decryption_prepared)
++	{
++	  internal_aes_ppc_prepare_decryption (ctx);
++	  ctx->decryption_prepared = 1;
++	}
++
++      PRELOAD_ROUND_KEYS (rounds);
++
++      for (; nblocks >= 8 && data_nblocks % 8; nblocks--)
++	{
++	  l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const);
++	  b = VEC_LOAD_BE (in, 0, bige_const);
++
++	  /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++	  iv ^= l;
++	  /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */
++	  b ^= iv;
++	  AES_DECRYPT (b, rounds);
++	  b ^= iv;
++	  /* Checksum_i = Checksum_{i-1} xor P_i  */
++	  ctr ^= b;
++
++	  VEC_STORE_BE (out, 0, b, bige_const);
++
++	  in += 1;
++	  out += 1;
++	}
++
++      for (; nblocks >= 8; nblocks -= 8)
++	{
++	  b0 = VEC_LOAD_BE_NOSWAP (in, 0);
++	  b1 = VEC_LOAD_BE_NOSWAP (in, 1);
++	  b2 = VEC_LOAD_BE_NOSWAP (in, 2);
++	  b3 = VEC_LOAD_BE_NOSWAP (in, 3);
++	  b4 = VEC_LOAD_BE_NOSWAP (in, 4);
++	  b5 = VEC_LOAD_BE_NOSWAP (in, 5);
++	  b6 = VEC_LOAD_BE_NOSWAP (in, 6);
++	  b7 = VEC_LOAD_BE_NOSWAP (in, 7);
++	  in += 8;
++	  l = VEC_LOAD_BE_NOSWAP (ocb_get_l (c, data_nblocks += 8), 0);
++	  b0 = VEC_BE_SWAP(b0, bige_const);
++	  b1 = VEC_BE_SWAP(b1, bige_const);
++	  b2 = VEC_BE_SWAP(b2, bige_const);
++	  b3 = VEC_BE_SWAP(b3, bige_const);
++	  b4 = VEC_BE_SWAP(b4, bige_const);
++	  b5 = VEC_BE_SWAP(b5, bige_const);
++	  b6 = VEC_BE_SWAP(b6, bige_const);
++	  b7 = VEC_BE_SWAP(b7, bige_const);
++	  l = VEC_BE_SWAP(l, bige_const);
++
++	  iv ^= rkey0;
++
++	  iv0 = iv ^ l0;
++	  iv1 = iv ^ l0 ^ l1;
++	  iv2 = iv ^ l1;
++	  iv3 = iv ^ l1 ^ l2;
++	  iv4 = iv ^ l1 ^ l2 ^ l0;
++	  iv5 = iv ^ l2 ^ l0;
++	  iv6 = iv ^ l2;
++	  iv7 = iv ^ l2 ^ l;
++
++	  b0 ^= iv0;
++	  b1 ^= iv1;
++	  b2 ^= iv2;
++	  b3 ^= iv3;
++	  b4 ^= iv4;
++	  b5 ^= iv5;
++	  b6 ^= iv6;
++	  b7 ^= iv7;
++	  iv = iv7 ^ rkey0;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_ncipher_be (b0, rkey); \
++	      b1 = asm_ncipher_be (b1, rkey); \
++	      b2 = asm_ncipher_be (b2, rkey); \
++	      b3 = asm_ncipher_be (b3, rkey); \
++	      b4 = asm_ncipher_be (b4, rkey); \
++	      b5 = asm_ncipher_be (b5, rkey); \
++	      b6 = asm_ncipher_be (b6, rkey); \
++	      b7 = asm_ncipher_be (b7, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++
++	  rkeylf = asm_xor (rkeylast, rkey0);
++
++	  DO_ROUND(8);
++
++	  iv0 = asm_xor (rkeylf, iv0);
++	  iv1 = asm_xor (rkeylf, iv1);
++	  iv2 = asm_xor (rkeylf, iv2);
++	  iv3 = asm_xor (rkeylf, iv3);
++	  iv4 = asm_xor (rkeylf, iv4);
++	  iv5 = asm_xor (rkeylf, iv5);
++	  iv6 = asm_xor (rkeylf, iv6);
++	  iv7 = asm_xor (rkeylf, iv7);
++
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  b0 = asm_ncipherlast_be (b0, iv0);
++	  b1 = asm_ncipherlast_be (b1, iv1);
++	  b2 = asm_ncipherlast_be (b2, iv2);
++	  b3 = asm_ncipherlast_be (b3, iv3);
++	  b4 = asm_ncipherlast_be (b4, iv4);
++	  b5 = asm_ncipherlast_be (b5, iv5);
++	  b6 = asm_ncipherlast_be (b6, iv6);
++	  b7 = asm_ncipherlast_be (b7, iv7);
++
++	  ctr ^= b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7;
++
++	  b0 = VEC_BE_SWAP (b0, bige_const);
++	  b1 = VEC_BE_SWAP (b1, bige_const);
++	  b2 = VEC_BE_SWAP (b2, bige_const);
++	  b3 = VEC_BE_SWAP (b3, bige_const);
++	  b4 = VEC_BE_SWAP (b4, bige_const);
++	  b5 = VEC_BE_SWAP (b5, bige_const);
++	  b6 = VEC_BE_SWAP (b6, bige_const);
++	  b7 = VEC_BE_SWAP (b7, bige_const);
++	  VEC_STORE_BE_NOSWAP (out, 0, b0);
++	  VEC_STORE_BE_NOSWAP (out, 1, b1);
++	  VEC_STORE_BE_NOSWAP (out, 2, b2);
++	  VEC_STORE_BE_NOSWAP (out, 3, b3);
++	  VEC_STORE_BE_NOSWAP (out, 4, b4);
++	  VEC_STORE_BE_NOSWAP (out, 5, b5);
++	  VEC_STORE_BE_NOSWAP (out, 6, b6);
++	  VEC_STORE_BE_NOSWAP (out, 7, b7);
++	  out += 8;
++	}
++
++      if (nblocks >= 4 && (data_nblocks % 4) == 0)
++	{
++	  b0 = VEC_LOAD_BE (in, 0, bige_const);
++	  b1 = VEC_LOAD_BE (in, 1, bige_const);
++	  b2 = VEC_LOAD_BE (in, 2, bige_const);
++	  b3 = VEC_LOAD_BE (in, 3, bige_const);
++
++	  l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 4), 0, bige_const);
++
++	  iv ^= rkey0;
++
++	  iv0 = iv ^ l0;
++	  iv1 = iv ^ l0 ^ l1;
++	  iv2 = iv ^ l1;
++	  iv3 = iv ^ l1 ^ l;
++
++	  b0 ^= iv0;
++	  b1 ^= iv1;
++	  b2 ^= iv2;
++	  b3 ^= iv3;
++	  iv = iv3 ^ rkey0;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_ncipher_be (b0, rkey); \
++	      b1 = asm_ncipher_be (b1, rkey); \
++	      b2 = asm_ncipher_be (b2, rkey); \
++	      b3 = asm_ncipher_be (b3, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++	  DO_ROUND(8);
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  rkey = rkeylast ^ rkey0;
++	  b0 = asm_ncipherlast_be (b0, rkey ^ iv0);
++	  b1 = asm_ncipherlast_be (b1, rkey ^ iv1);
++	  b2 = asm_ncipherlast_be (b2, rkey ^ iv2);
++	  b3 = asm_ncipherlast_be (b3, rkey ^ iv3);
++
++	  VEC_STORE_BE (out, 0, b0, bige_const);
++	  VEC_STORE_BE (out, 1, b1, bige_const);
++	  VEC_STORE_BE (out, 2, b2, bige_const);
++	  VEC_STORE_BE (out, 3, b3, bige_const);
++
++	  ctr ^= b0 ^ b1 ^ b2 ^ b3;
++
++	  in += 4;
++	  out += 4;
++	  nblocks -= 4;
++	}
++
++      for (; nblocks; nblocks--)
++	{
++	  l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const);
++	  b = VEC_LOAD_BE (in, 0, bige_const);
++
++	  /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++	  iv ^= l;
++	  /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)  */
++	  b ^= iv;
++	  AES_DECRYPT (b, rounds);
++	  b ^= iv;
++	  /* Checksum_i = Checksum_{i-1} xor P_i  */
++	  ctr ^= b;
++
++	  VEC_STORE_BE (out, 0, b, bige_const);
++
++	  in += 1;
++	  out += 1;
++	}
++    }
++
++  VEC_STORE_BE (c->u_iv.iv, 0, iv, bige_const);
++  VEC_STORE_BE (c->u_ctr.ctr, 0, ctr, bige_const);
++  c->u_mode.ocb.data_nblocks = data_nblocks;
++
++  return 0;
++}
++
++size_t OCB_AUTH_FUNC (gcry_cipher_hd_t c, void *abuf_arg, size_t nblocks)
++{
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = (void *)&c->context.c;
++  const u128_t *rk = (u128_t *)&ctx->keyschenc;
++  const u128_t *abuf = (const u128_t *)abuf_arg;
++  int rounds = ctx->rounds;
++  u64 data_nblocks = c->u_mode.ocb.aad_nblocks;
++  block l0, l1, l2, l;
++  block b0, b1, b2, b3, b4, b5, b6, b7, b;
++  block iv0, iv1, iv2, iv3, iv4, iv5, iv6, iv7;
++  block rkey, frkey;
++  block ctr, iv;
++  ROUND_KEY_VARIABLES;
++
++  iv = VEC_LOAD_BE (c->u_mode.ocb.aad_offset, 0, bige_const);
++  ctr = VEC_LOAD_BE (c->u_mode.ocb.aad_sum, 0, bige_const);
++
++  l0 = VEC_LOAD_BE (c->u_mode.ocb.L[0], 0, bige_const);
++  l1 = VEC_LOAD_BE (c->u_mode.ocb.L[1], 0, bige_const);
++  l2 = VEC_LOAD_BE (c->u_mode.ocb.L[2], 0, bige_const);
++
++  PRELOAD_ROUND_KEYS (rounds);
++
++  for (; nblocks >= 8 && data_nblocks % 8; nblocks--)
++    {
++      l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const);
++      b = VEC_LOAD_BE (abuf, 0, bige_const);
++
++      /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++      iv ^= l;
++      /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
++      b ^= iv;
++      AES_ENCRYPT (b, rounds);
++      ctr ^= b;
++
++      abuf += 1;
++    }
++
++  for (; nblocks >= 8; nblocks -= 8)
++    {
++      b0 = VEC_LOAD_BE (abuf, 0, bige_const);
++      b1 = VEC_LOAD_BE (abuf, 1, bige_const);
++      b2 = VEC_LOAD_BE (abuf, 2, bige_const);
++      b3 = VEC_LOAD_BE (abuf, 3, bige_const);
++      b4 = VEC_LOAD_BE (abuf, 4, bige_const);
++      b5 = VEC_LOAD_BE (abuf, 5, bige_const);
++      b6 = VEC_LOAD_BE (abuf, 6, bige_const);
++      b7 = VEC_LOAD_BE (abuf, 7, bige_const);
++
++      l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 8), 0, bige_const);
++
++      frkey = rkey0;
++      iv ^= frkey;
++
++      iv0 = iv ^ l0;
++      iv1 = iv ^ l0 ^ l1;
++      iv2 = iv ^ l1;
++      iv3 = iv ^ l1 ^ l2;
++      iv4 = iv ^ l1 ^ l2 ^ l0;
++      iv5 = iv ^ l2 ^ l0;
++      iv6 = iv ^ l2;
++      iv7 = iv ^ l2 ^ l;
++
++      b0 ^= iv0;
++      b1 ^= iv1;
++      b2 ^= iv2;
++      b3 ^= iv3;
++      b4 ^= iv4;
++      b5 ^= iv5;
++      b6 ^= iv6;
++      b7 ^= iv7;
++      iv = iv7 ^ frkey;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey); \
++	      b4 = asm_cipher_be (b4, rkey); \
++	      b5 = asm_cipher_be (b5, rkey); \
++	      b6 = asm_cipher_be (b6, rkey); \
++	      b7 = asm_cipher_be (b7, rkey);
++
++      DO_ROUND(1);
++      DO_ROUND(2);
++      DO_ROUND(3);
++      DO_ROUND(4);
++      DO_ROUND(5);
++      DO_ROUND(6);
++      DO_ROUND(7);
++      DO_ROUND(8);
++      DO_ROUND(9);
++      if (rounds >= 12)
++	{
++	  DO_ROUND(10);
++	  DO_ROUND(11);
++	  if (rounds > 12)
++	    {
++	      DO_ROUND(12);
++	      DO_ROUND(13);
++	    }
++	}
++
++#undef DO_ROUND
++
++      rkey = rkeylast;
++      b0 = asm_cipherlast_be (b0, rkey);
++      b1 = asm_cipherlast_be (b1, rkey);
++      b2 = asm_cipherlast_be (b2, rkey);
++      b3 = asm_cipherlast_be (b3, rkey);
++      b4 = asm_cipherlast_be (b4, rkey);
++      b5 = asm_cipherlast_be (b5, rkey);
++      b6 = asm_cipherlast_be (b6, rkey);
++      b7 = asm_cipherlast_be (b7, rkey);
++
++      ctr ^= b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7;
++
++      abuf += 8;
++    }
++
++  if (nblocks >= 4 && (data_nblocks % 4) == 0)
++    {
++      b0 = VEC_LOAD_BE (abuf, 0, bige_const);
++      b1 = VEC_LOAD_BE (abuf, 1, bige_const);
++      b2 = VEC_LOAD_BE (abuf, 2, bige_const);
++      b3 = VEC_LOAD_BE (abuf, 3, bige_const);
++
++      l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 4), 0, bige_const);
++
++      frkey = rkey0;
++      iv ^= frkey;
++
++      iv0 = iv ^ l0;
++      iv1 = iv ^ l0 ^ l1;
++      iv2 = iv ^ l1;
++      iv3 = iv ^ l1 ^ l;
++
++      b0 ^= iv0;
++      b1 ^= iv1;
++      b2 ^= iv2;
++      b3 ^= iv3;
++      iv = iv3 ^ frkey;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey);
++
++      DO_ROUND(1);
++      DO_ROUND(2);
++      DO_ROUND(3);
++      DO_ROUND(4);
++      DO_ROUND(5);
++      DO_ROUND(6);
++      DO_ROUND(7);
++      DO_ROUND(8);
++      DO_ROUND(9);
++      if (rounds >= 12)
++	{
++	  DO_ROUND(10);
++	  DO_ROUND(11);
++	  if (rounds > 12)
++	    {
++	      DO_ROUND(12);
++	      DO_ROUND(13);
++	    }
++	}
++
++#undef DO_ROUND
++
++      rkey = rkeylast;
++      b0 = asm_cipherlast_be (b0, rkey);
++      b1 = asm_cipherlast_be (b1, rkey);
++      b2 = asm_cipherlast_be (b2, rkey);
++      b3 = asm_cipherlast_be (b3, rkey);
++
++      ctr ^= b0 ^ b1 ^ b2 ^ b3;
++
++      abuf += 4;
++      nblocks -= 4;
++    }
++
++  for (; nblocks; nblocks--)
++    {
++      l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const);
++      b = VEC_LOAD_BE (abuf, 0, bige_const);
++
++      /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
++      iv ^= l;
++      /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i)  */
++      b ^= iv;
++      AES_ENCRYPT (b, rounds);
++      ctr ^= b;
++
++      abuf += 1;
++    }
++
++  VEC_STORE_BE (c->u_mode.ocb.aad_offset, 0, iv, bige_const);
++  VEC_STORE_BE (c->u_mode.ocb.aad_sum, 0, ctr, bige_const);
++  c->u_mode.ocb.aad_nblocks = data_nblocks;
++
++  return 0;
++}
++
++
++void XTS_CRYPT_FUNC (void *context, unsigned char *tweak_arg,
++		     void *outbuf_arg, const void *inbuf_arg,
++		     size_t nblocks, int encrypt)
++{
++#ifdef WORDS_BIGENDIAN
++  static const block vec_bswap128_const =
++    { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
++#else
++  static const block vec_bswap128_const =
++    { ~15, ~14, ~13, ~12, ~11, ~10, ~9, ~8, ~7, ~6, ~5, ~4, ~3, ~2, ~1, ~0 };
++#endif
++  static const unsigned char vec_tweak_const[16] =
++    { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x87 };
++  static const vector unsigned long long vec_shift63_const =
++    { 63, 63 };
++  const block bige_const = asm_load_be_const();
++  RIJNDAEL_context *ctx = context;
++  const u128_t *in = (const u128_t *)inbuf_arg;
++  u128_t *out = (u128_t *)outbuf_arg;
++  int rounds = ctx->rounds;
++  block tweak;
++  block b0, b1, b2, b3, b4, b5, b6, b7, b, rkey, rkeylf;
++  block tweak0, tweak1, tweak2, tweak3, tweak4, tweak5, tweak6, tweak7;
++  block tweak_const, bswap128_const, shift63_const;
++  ROUND_KEY_VARIABLES;
++
++  tweak_const = VEC_LOAD_BE (&vec_tweak_const, 0, bige_const);
++  bswap128_const = ALIGNED_LOAD (&vec_bswap128_const, 0);
++  shift63_const = ALIGNED_LOAD (&vec_shift63_const, 0);
++
++  tweak = VEC_LOAD_BE (tweak_arg, 0, bige_const);
++  tweak = asm_vperm1 (tweak, bswap128_const);
++
++#define GEN_TWEAK(tout, tin) /* Generate next tweak. */ \
++    do { \
++      block tmp1, tmp2; \
++      tmp1 = asm_swap_uint64_halfs(tin); \
++      tmp2 = asm_add_uint64(tin, tin); \
++      tmp1 = asm_sra_int64(tmp1, shift63_const) & tweak_const; \
++      tout = asm_xor(tmp1, tmp2); \
++    } while (0)
++
++  if (encrypt)
++    {
++      const u128_t *rk = (u128_t *)&ctx->keyschenc;
++
++      PRELOAD_ROUND_KEYS (rounds);
++
++      for (; nblocks >= 8; nblocks -= 8)
++	{
++	  b0 = VEC_LOAD_BE_NOSWAP (in, 0);
++	  b1 = VEC_LOAD_BE_NOSWAP (in, 1);
++	  b2 = VEC_LOAD_BE_NOSWAP (in, 2);
++	  b3 = VEC_LOAD_BE_NOSWAP (in, 3);
++	  tweak0 = tweak;
++	  GEN_TWEAK (tweak1, tweak0);
++	  tweak0 = asm_vperm1 (tweak0, bswap128_const);
++	  b4 = VEC_LOAD_BE_NOSWAP (in, 4);
++	  b5 = VEC_LOAD_BE_NOSWAP (in, 5);
++	  GEN_TWEAK (tweak2, tweak1);
++	  tweak1 = asm_vperm1 (tweak1, bswap128_const);
++	  b6 = VEC_LOAD_BE_NOSWAP (in, 6);
++	  b7 = VEC_LOAD_BE_NOSWAP (in, 7);
++	  in += 8;
++
++	  b0 = VEC_BE_SWAP(b0, bige_const);
++	  b1 = VEC_BE_SWAP(b1, bige_const);
++	  GEN_TWEAK (tweak3, tweak2);
++	  tweak2 = asm_vperm1 (tweak2, bswap128_const);
++	  GEN_TWEAK (tweak4, tweak3);
++	  tweak3 = asm_vperm1 (tweak3, bswap128_const);
++	  b2 = VEC_BE_SWAP(b2, bige_const);
++	  b3 = VEC_BE_SWAP(b3, bige_const);
++	  GEN_TWEAK (tweak5, tweak4);
++	  tweak4 = asm_vperm1 (tweak4, bswap128_const);
++	  GEN_TWEAK (tweak6, tweak5);
++	  tweak5 = asm_vperm1 (tweak5, bswap128_const);
++	  b4 = VEC_BE_SWAP(b4, bige_const);
++	  b5 = VEC_BE_SWAP(b5, bige_const);
++	  GEN_TWEAK (tweak7, tweak6);
++	  tweak6 = asm_vperm1 (tweak6, bswap128_const);
++	  GEN_TWEAK (tweak, tweak7);
++	  tweak7 = asm_vperm1 (tweak7, bswap128_const);
++	  b6 = VEC_BE_SWAP(b6, bige_const);
++	  b7 = VEC_BE_SWAP(b7, bige_const);
++
++	  tweak0 = asm_xor (tweak0, rkey0);
++	  tweak1 = asm_xor (tweak1, rkey0);
++	  tweak2 = asm_xor (tweak2, rkey0);
++	  tweak3 = asm_xor (tweak3, rkey0);
++	  tweak4 = asm_xor (tweak4, rkey0);
++	  tweak5 = asm_xor (tweak5, rkey0);
++	  tweak6 = asm_xor (tweak6, rkey0);
++	  tweak7 = asm_xor (tweak7, rkey0);
++
++	  b0 = asm_xor (b0, tweak0);
++	  b1 = asm_xor (b1, tweak1);
++	  b2 = asm_xor (b2, tweak2);
++	  b3 = asm_xor (b3, tweak3);
++	  b4 = asm_xor (b4, tweak4);
++	  b5 = asm_xor (b5, tweak5);
++	  b6 = asm_xor (b6, tweak6);
++	  b7 = asm_xor (b7, tweak7);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey); \
++	      b4 = asm_cipher_be (b4, rkey); \
++	      b5 = asm_cipher_be (b5, rkey); \
++	      b6 = asm_cipher_be (b6, rkey); \
++	      b7 = asm_cipher_be (b7, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++
++	  rkeylf = asm_xor (rkeylast, rkey0);
++
++	  DO_ROUND(8);
++
++	  tweak0 = asm_xor (tweak0, rkeylf);
++	  tweak1 = asm_xor (tweak1, rkeylf);
++	  tweak2 = asm_xor (tweak2, rkeylf);
++	  tweak3 = asm_xor (tweak3, rkeylf);
++	  tweak4 = asm_xor (tweak4, rkeylf);
++	  tweak5 = asm_xor (tweak5, rkeylf);
++	  tweak6 = asm_xor (tweak6, rkeylf);
++	  tweak7 = asm_xor (tweak7, rkeylf);
++
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  b0 = asm_cipherlast_be (b0, tweak0);
++	  b1 = asm_cipherlast_be (b1, tweak1);
++	  b2 = asm_cipherlast_be (b2, tweak2);
++	  b3 = asm_cipherlast_be (b3, tweak3);
++	  b0 = VEC_BE_SWAP (b0, bige_const);
++	  b1 = VEC_BE_SWAP (b1, bige_const);
++	  b4 = asm_cipherlast_be (b4, tweak4);
++	  b5 = asm_cipherlast_be (b5, tweak5);
++	  b2 = VEC_BE_SWAP (b2, bige_const);
++	  b3 = VEC_BE_SWAP (b3, bige_const);
++	  b6 = asm_cipherlast_be (b6, tweak6);
++	  b7 = asm_cipherlast_be (b7, tweak7);
++	  VEC_STORE_BE_NOSWAP (out, 0, b0);
++	  VEC_STORE_BE_NOSWAP (out, 1, b1);
++	  b4 = VEC_BE_SWAP (b4, bige_const);
++	  b5 = VEC_BE_SWAP (b5, bige_const);
++	  VEC_STORE_BE_NOSWAP (out, 2, b2);
++	  VEC_STORE_BE_NOSWAP (out, 3, b3);
++	  b6 = VEC_BE_SWAP (b6, bige_const);
++	  b7 = VEC_BE_SWAP (b7, bige_const);
++	  VEC_STORE_BE_NOSWAP (out, 4, b4);
++	  VEC_STORE_BE_NOSWAP (out, 5, b5);
++	  VEC_STORE_BE_NOSWAP (out, 6, b6);
++	  VEC_STORE_BE_NOSWAP (out, 7, b7);
++	  out += 8;
++	}
++
++      if (nblocks >= 4)
++	{
++	  tweak0 = tweak;
++	  GEN_TWEAK (tweak1, tweak0);
++	  GEN_TWEAK (tweak2, tweak1);
++	  GEN_TWEAK (tweak3, tweak2);
++	  GEN_TWEAK (tweak, tweak3);
++
++	  b0 = VEC_LOAD_BE (in, 0, bige_const);
++	  b1 = VEC_LOAD_BE (in, 1, bige_const);
++	  b2 = VEC_LOAD_BE (in, 2, bige_const);
++	  b3 = VEC_LOAD_BE (in, 3, bige_const);
++
++	  tweak0 = asm_vperm1 (tweak0, bswap128_const);
++	  tweak1 = asm_vperm1 (tweak1, bswap128_const);
++	  tweak2 = asm_vperm1 (tweak2, bswap128_const);
++	  tweak3 = asm_vperm1 (tweak3, bswap128_const);
++
++	  b0 ^= tweak0 ^ rkey0;
++	  b1 ^= tweak1 ^ rkey0;
++	  b2 ^= tweak2 ^ rkey0;
++	  b3 ^= tweak3 ^ rkey0;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_cipher_be (b0, rkey); \
++	      b1 = asm_cipher_be (b1, rkey); \
++	      b2 = asm_cipher_be (b2, rkey); \
++	      b3 = asm_cipher_be (b3, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++	  DO_ROUND(8);
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  rkey = rkeylast;
++	  b0 = asm_cipherlast_be (b0, rkey ^ tweak0);
++	  b1 = asm_cipherlast_be (b1, rkey ^ tweak1);
++	  b2 = asm_cipherlast_be (b2, rkey ^ tweak2);
++	  b3 = asm_cipherlast_be (b3, rkey ^ tweak3);
++
++	  VEC_STORE_BE (out, 0, b0, bige_const);
++	  VEC_STORE_BE (out, 1, b1, bige_const);
++	  VEC_STORE_BE (out, 2, b2, bige_const);
++	  VEC_STORE_BE (out, 3, b3, bige_const);
++
++	  in += 4;
++	  out += 4;
++	  nblocks -= 4;
++	}
++
++      for (; nblocks; nblocks--)
++	{
++	  tweak0 = asm_vperm1 (tweak, bswap128_const);
++
++	  /* Xor-Encrypt/Decrypt-Xor block. */
++	  b = VEC_LOAD_BE (in, 0, bige_const) ^ tweak0;
++
++	  /* Generate next tweak. */
++	  GEN_TWEAK (tweak, tweak);
++
++	  AES_ENCRYPT (b, rounds);
++
++	  b ^= tweak0;
++	  VEC_STORE_BE (out, 0, b, bige_const);
++
++	  in++;
++	  out++;
++	}
++    }
++  else
++    {
++      const u128_t *rk = (u128_t *)&ctx->keyschdec;
++
++      if (!ctx->decryption_prepared)
++	{
++	  internal_aes_ppc_prepare_decryption (ctx);
++	  ctx->decryption_prepared = 1;
++	}
++
++      PRELOAD_ROUND_KEYS (rounds);
++
++      for (; nblocks >= 8; nblocks -= 8)
++	{
++	  b0 = VEC_LOAD_BE_NOSWAP (in, 0);
++	  b1 = VEC_LOAD_BE_NOSWAP (in, 1);
++	  b2 = VEC_LOAD_BE_NOSWAP (in, 2);
++	  b3 = VEC_LOAD_BE_NOSWAP (in, 3);
++	  tweak0 = tweak;
++	  GEN_TWEAK (tweak1, tweak0);
++	  tweak0 = asm_vperm1 (tweak0, bswap128_const);
++	  b4 = VEC_LOAD_BE_NOSWAP (in, 4);
++	  b5 = VEC_LOAD_BE_NOSWAP (in, 5);
++	  GEN_TWEAK (tweak2, tweak1);
++	  tweak1 = asm_vperm1 (tweak1, bswap128_const);
++	  b6 = VEC_LOAD_BE_NOSWAP (in, 6);
++	  b7 = VEC_LOAD_BE_NOSWAP (in, 7);
++	  in += 8;
++
++	  b0 = VEC_BE_SWAP(b0, bige_const);
++	  b1 = VEC_BE_SWAP(b1, bige_const);
++	  GEN_TWEAK (tweak3, tweak2);
++	  tweak2 = asm_vperm1 (tweak2, bswap128_const);
++	  GEN_TWEAK (tweak4, tweak3);
++	  tweak3 = asm_vperm1 (tweak3, bswap128_const);
++	  b2 = VEC_BE_SWAP(b2, bige_const);
++	  b3 = VEC_BE_SWAP(b3, bige_const);
++	  GEN_TWEAK (tweak5, tweak4);
++	  tweak4 = asm_vperm1 (tweak4, bswap128_const);
++	  GEN_TWEAK (tweak6, tweak5);
++	  tweak5 = asm_vperm1 (tweak5, bswap128_const);
++	  b4 = VEC_BE_SWAP(b4, bige_const);
++	  b5 = VEC_BE_SWAP(b5, bige_const);
++	  GEN_TWEAK (tweak7, tweak6);
++	  tweak6 = asm_vperm1 (tweak6, bswap128_const);
++	  GEN_TWEAK (tweak, tweak7);
++	  tweak7 = asm_vperm1 (tweak7, bswap128_const);
++	  b6 = VEC_BE_SWAP(b6, bige_const);
++	  b7 = VEC_BE_SWAP(b7, bige_const);
++
++	  tweak0 = asm_xor (tweak0, rkey0);
++	  tweak1 = asm_xor (tweak1, rkey0);
++	  tweak2 = asm_xor (tweak2, rkey0);
++	  tweak3 = asm_xor (tweak3, rkey0);
++	  tweak4 = asm_xor (tweak4, rkey0);
++	  tweak5 = asm_xor (tweak5, rkey0);
++	  tweak6 = asm_xor (tweak6, rkey0);
++	  tweak7 = asm_xor (tweak7, rkey0);
++
++	  b0 = asm_xor (b0, tweak0);
++	  b1 = asm_xor (b1, tweak1);
++	  b2 = asm_xor (b2, tweak2);
++	  b3 = asm_xor (b3, tweak3);
++	  b4 = asm_xor (b4, tweak4);
++	  b5 = asm_xor (b5, tweak5);
++	  b6 = asm_xor (b6, tweak6);
++	  b7 = asm_xor (b7, tweak7);
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_ncipher_be (b0, rkey); \
++	      b1 = asm_ncipher_be (b1, rkey); \
++	      b2 = asm_ncipher_be (b2, rkey); \
++	      b3 = asm_ncipher_be (b3, rkey); \
++	      b4 = asm_ncipher_be (b4, rkey); \
++	      b5 = asm_ncipher_be (b5, rkey); \
++	      b6 = asm_ncipher_be (b6, rkey); \
++	      b7 = asm_ncipher_be (b7, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++
++	  rkeylf = asm_xor (rkeylast, rkey0);
++
++	  DO_ROUND(8);
++
++	  tweak0 = asm_xor (tweak0, rkeylf);
++	  tweak1 = asm_xor (tweak1, rkeylf);
++	  tweak2 = asm_xor (tweak2, rkeylf);
++	  tweak3 = asm_xor (tweak3, rkeylf);
++	  tweak4 = asm_xor (tweak4, rkeylf);
++	  tweak5 = asm_xor (tweak5, rkeylf);
++	  tweak6 = asm_xor (tweak6, rkeylf);
++	  tweak7 = asm_xor (tweak7, rkeylf);
++
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  b0 = asm_ncipherlast_be (b0, tweak0);
++	  b1 = asm_ncipherlast_be (b1, tweak1);
++	  b2 = asm_ncipherlast_be (b2, tweak2);
++	  b3 = asm_ncipherlast_be (b3, tweak3);
++	  b0 = VEC_BE_SWAP (b0, bige_const);
++	  b1 = VEC_BE_SWAP (b1, bige_const);
++	  b4 = asm_ncipherlast_be (b4, tweak4);
++	  b5 = asm_ncipherlast_be (b5, tweak5);
++	  b2 = VEC_BE_SWAP (b2, bige_const);
++	  b3 = VEC_BE_SWAP (b3, bige_const);
++	  b6 = asm_ncipherlast_be (b6, tweak6);
++	  b7 = asm_ncipherlast_be (b7, tweak7);
++	  VEC_STORE_BE_NOSWAP (out, 0, b0);
++	  VEC_STORE_BE_NOSWAP (out, 1, b1);
++	  b4 = VEC_BE_SWAP (b4, bige_const);
++	  b5 = VEC_BE_SWAP (b5, bige_const);
++	  VEC_STORE_BE_NOSWAP (out, 2, b2);
++	  VEC_STORE_BE_NOSWAP (out, 3, b3);
++	  b6 = VEC_BE_SWAP (b6, bige_const);
++	  b7 = VEC_BE_SWAP (b7, bige_const);
++	  VEC_STORE_BE_NOSWAP (out, 4, b4);
++	  VEC_STORE_BE_NOSWAP (out, 5, b5);
++	  VEC_STORE_BE_NOSWAP (out, 6, b6);
++	  VEC_STORE_BE_NOSWAP (out, 7, b7);
++	  out += 8;
++	}
++
++      if (nblocks >= 4)
++	{
++	  tweak0 = tweak;
++	  GEN_TWEAK (tweak1, tweak0);
++	  GEN_TWEAK (tweak2, tweak1);
++	  GEN_TWEAK (tweak3, tweak2);
++	  GEN_TWEAK (tweak, tweak3);
++
++	  b0 = VEC_LOAD_BE (in, 0, bige_const);
++	  b1 = VEC_LOAD_BE (in, 1, bige_const);
++	  b2 = VEC_LOAD_BE (in, 2, bige_const);
++	  b3 = VEC_LOAD_BE (in, 3, bige_const);
++
++	  tweak0 = asm_vperm1 (tweak0, bswap128_const);
++	  tweak1 = asm_vperm1 (tweak1, bswap128_const);
++	  tweak2 = asm_vperm1 (tweak2, bswap128_const);
++	  tweak3 = asm_vperm1 (tweak3, bswap128_const);
++
++	  b0 ^= tweak0 ^ rkey0;
++	  b1 ^= tweak1 ^ rkey0;
++	  b2 ^= tweak2 ^ rkey0;
++	  b3 ^= tweak3 ^ rkey0;
++
++#define DO_ROUND(r) \
++	      rkey = ALIGNED_LOAD (rk, r); \
++	      b0 = asm_ncipher_be (b0, rkey); \
++	      b1 = asm_ncipher_be (b1, rkey); \
++	      b2 = asm_ncipher_be (b2, rkey); \
++	      b3 = asm_ncipher_be (b3, rkey);
++
++	  DO_ROUND(1);
++	  DO_ROUND(2);
++	  DO_ROUND(3);
++	  DO_ROUND(4);
++	  DO_ROUND(5);
++	  DO_ROUND(6);
++	  DO_ROUND(7);
++	  DO_ROUND(8);
++	  DO_ROUND(9);
++	  if (rounds >= 12)
++	    {
++	      DO_ROUND(10);
++	      DO_ROUND(11);
++	      if (rounds > 12)
++		{
++		  DO_ROUND(12);
++		  DO_ROUND(13);
++		}
++	    }
++
++#undef DO_ROUND
++
++	  rkey = rkeylast;
++	  b0 = asm_ncipherlast_be (b0, rkey ^ tweak0);
++	  b1 = asm_ncipherlast_be (b1, rkey ^ tweak1);
++	  b2 = asm_ncipherlast_be (b2, rkey ^ tweak2);
++	  b3 = asm_ncipherlast_be (b3, rkey ^ tweak3);
++
++	  VEC_STORE_BE (out, 0, b0, bige_const);
++	  VEC_STORE_BE (out, 1, b1, bige_const);
++	  VEC_STORE_BE (out, 2, b2, bige_const);
++	  VEC_STORE_BE (out, 3, b3, bige_const);
++
++	  in += 4;
++	  out += 4;
++	  nblocks -= 4;
++	}
++
++      for (; nblocks; nblocks--)
++	{
++	  tweak0 = asm_vperm1 (tweak, bswap128_const);
++
++	  /* Xor-Encrypt/Decrypt-Xor block. */
++	  b = VEC_LOAD_BE (in, 0, bige_const) ^ tweak0;
++
++	  /* Generate next tweak. */
++	  GEN_TWEAK (tweak, tweak);
++
++	  AES_DECRYPT (b, rounds);
++
++	  b ^= tweak0;
++	  VEC_STORE_BE (out, 0, b, bige_const);
++
++	  in++;
++	  out++;
++	}
++    }
++
++  tweak = asm_vperm1 (tweak, bswap128_const);
++  VEC_STORE_BE (tweak_arg, 0, tweak, bige_const);
++
++#undef GEN_TWEAK
++}
+diff -up libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c
+--- libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c	2020-04-22 18:29:41.679862057 +0200
+@@ -208,11 +208,11 @@ _gcry_aes_ssse3_do_setkey (RIJNDAEL_cont
+ 
+ 
+ /* Make a decryption key from an encryption key. */
+-void
+-_gcry_aes_ssse3_prepare_decryption (RIJNDAEL_context *ctx)
++static inline void
++do_ssse3_prepare_decryption (RIJNDAEL_context *ctx,
++                             byte ssse3_state[SSSE3_STATE_SIZE])
+ {
+   unsigned int keybits = (ctx->rounds - 10) * 32 + 128;
+-  byte ssse3_state[SSSE3_STATE_SIZE];
+ 
+   vpaes_ssse3_prepare();
+ 
+@@ -237,6 +237,14 @@ _gcry_aes_ssse3_prepare_decryption (RIJN
+   vpaes_ssse3_cleanup();
+ }
+ 
++void
++_gcry_aes_ssse3_prepare_decryption (RIJNDAEL_context *ctx)
++{
++  byte ssse3_state[SSSE3_STATE_SIZE];
++
++  do_ssse3_prepare_decryption(ctx, ssse3_state);
++}
++
+ 
+ /* Encrypt one block using the Intel SSSE3 instructions.  Block is input
+ * and output through SSE register xmm0. */
+@@ -295,9 +303,9 @@ _gcry_aes_ssse3_encrypt (const RIJNDAEL_
+ 
+ 
+ void
+-_gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                        const unsigned char *inbuf, unsigned char *iv,
+-                        size_t nblocks)
++_gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
++                         size_t nblocks)
+ {
+   unsigned int nrounds = ctx->rounds;
+   byte ssse3_state[SSSE3_STATE_SIZE];
+@@ -334,9 +342,9 @@ _gcry_aes_ssse3_cfb_enc (RIJNDAEL_contex
+ 
+ 
+ void
+-_gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                        const unsigned char *inbuf, unsigned char *iv,
+-                        size_t nblocks, int cbc_mac)
++_gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
++                         size_t nblocks, int cbc_mac)
+ {
+   unsigned int nrounds = ctx->rounds;
+   byte ssse3_state[SSSE3_STATE_SIZE];
+@@ -379,9 +387,9 @@ _gcry_aes_ssse3_cbc_enc (RIJNDAEL_contex
+ 
+ 
+ void
+-_gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                        const unsigned char *inbuf, unsigned char *ctr,
+-                        size_t nblocks)
++_gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx, unsigned char *ctr,
++                         unsigned char *outbuf, const unsigned char *inbuf,
++                         size_t nblocks)
+ {
+   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
+     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
+@@ -447,7 +455,7 @@ _gcry_aes_ssse3_ctr_enc (RIJNDAEL_contex
+ 
+ unsigned int
+ _gcry_aes_ssse3_decrypt (const RIJNDAEL_context *ctx, unsigned char *dst,
+-                        const unsigned char *src)
++                         const unsigned char *src)
+ {
+   unsigned int nrounds = ctx->rounds;
+   byte ssse3_state[SSSE3_STATE_SIZE];
+@@ -468,9 +476,9 @@ _gcry_aes_ssse3_decrypt (const RIJNDAEL_
+ 
+ 
+ void
+-_gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                        const unsigned char *inbuf, unsigned char *iv,
+-                        size_t nblocks)
++_gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
++                         size_t nblocks)
+ {
+   unsigned int nrounds = ctx->rounds;
+   byte ssse3_state[SSSE3_STATE_SIZE];
+@@ -508,13 +516,19 @@ _gcry_aes_ssse3_cfb_dec (RIJNDAEL_contex
+ 
+ 
+ void
+-_gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx, unsigned char *outbuf,
+-                        const unsigned char *inbuf, unsigned char *iv,
+-                        size_t nblocks)
++_gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv,
++                         unsigned char *outbuf, const unsigned char *inbuf,
++                         size_t nblocks)
+ {
+   unsigned int nrounds = ctx->rounds;
+   byte ssse3_state[SSSE3_STATE_SIZE];
+ 
++  if ( !ctx->decryption_prepared )
++    {
++      do_ssse3_prepare_decryption ( ctx, ssse3_state );
++      ctx->decryption_prepared = 1;
++    }
++
+   vpaes_ssse3_prepare_dec ();
+ 
+   asm volatile ("movdqu %[iv], %%xmm7\n\t"	/* use xmm7 as fast IV storage */
+@@ -626,6 +640,12 @@ ssse3_ocb_dec (gcry_cipher_hd_t c, void
+   unsigned int nrounds = ctx->rounds;
+   byte ssse3_state[SSSE3_STATE_SIZE];
+ 
++  if ( !ctx->decryption_prepared )
++    {
++      do_ssse3_prepare_decryption ( ctx, ssse3_state );
++      ctx->decryption_prepared = 1;
++    }
++
+   vpaes_ssse3_prepare_dec ();
+ 
+   /* Preload Offset and Checksum */
+@@ -679,7 +699,7 @@ ssse3_ocb_dec (gcry_cipher_hd_t c, void
+ }
+ 
+ 
+-void
++size_t
+ _gcry_aes_ssse3_ocb_crypt(gcry_cipher_hd_t c, void *outbuf_arg,
+                           const void *inbuf_arg, size_t nblocks, int encrypt)
+ {
+@@ -687,10 +707,12 @@ _gcry_aes_ssse3_ocb_crypt(gcry_cipher_hd
+     ssse3_ocb_enc(c, outbuf_arg, inbuf_arg, nblocks);
+   else
+     ssse3_ocb_dec(c, outbuf_arg, inbuf_arg, nblocks);
++
++  return 0;
+ }
+ 
+ 
+-void
++size_t
+ _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
+                           size_t nblocks)
+ {
+@@ -746,6 +768,8 @@ _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd
+                 : "memory" );
+ 
+   vpaes_ssse3_cleanup ();
++
++  return 0;
+ }
+ 
+ #endif /* USE_SSSE3 */
+diff -up libgcrypt-1.8.5/cipher/salsa20.c.aes-perf libgcrypt-1.8.5/cipher/salsa20.c
+--- libgcrypt-1.8.5/cipher/salsa20.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/salsa20.c	2020-04-22 18:29:41.679862057 +0200
+@@ -366,10 +366,12 @@ salsa20_do_setkey (SALSA20_context_t *ct
+ 
+ 
+ static gcry_err_code_t
+-salsa20_setkey (void *context, const byte *key, unsigned int keylen)
++salsa20_setkey (void *context, const byte *key, unsigned int keylen,
++                gcry_cipher_hd_t hd)
+ {
+   SALSA20_context_t *ctx = (SALSA20_context_t *)context;
+   gcry_err_code_t rc = salsa20_do_setkey (ctx, key, keylen);
++  (void)hd;
+   _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *));
+   return rc;
+ }
+@@ -522,7 +524,7 @@ selftest (void)
+   /* 16-byte alignment required for amd64 implementation. */
+   ctx = (SALSA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15);
+ 
+-  salsa20_setkey (ctx, key_1, sizeof key_1);
++  salsa20_setkey (ctx, key_1, sizeof key_1, NULL);
+   salsa20_setiv  (ctx, nonce_1, sizeof nonce_1);
+   scratch[8] = 0;
+   salsa20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1);
+@@ -530,7 +532,7 @@ selftest (void)
+     return "Salsa20 encryption test 1 failed.";
+   if (scratch[8])
+     return "Salsa20 wrote too much.";
+-  salsa20_setkey( ctx, key_1, sizeof(key_1));
++  salsa20_setkey( ctx, key_1, sizeof(key_1), NULL);
+   salsa20_setiv  (ctx, nonce_1, sizeof nonce_1);
+   salsa20_encrypt_stream (ctx, scratch, scratch, sizeof plaintext_1);
+   if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
+@@ -538,12 +540,12 @@ selftest (void)
+ 
+   for (i = 0; i < sizeof buf; i++)
+     buf[i] = i;
+-  salsa20_setkey (ctx, key_1, sizeof key_1);
++  salsa20_setkey (ctx, key_1, sizeof key_1, NULL);
+   salsa20_setiv (ctx, nonce_1, sizeof nonce_1);
+   /*encrypt*/
+   salsa20_encrypt_stream (ctx, buf, buf, sizeof buf);
+   /*decrypt*/
+-  salsa20_setkey (ctx, key_1, sizeof key_1);
++  salsa20_setkey (ctx, key_1, sizeof key_1, NULL);
+   salsa20_setiv (ctx, nonce_1, sizeof nonce_1);
+   salsa20_encrypt_stream (ctx, buf, buf, 1);
+   salsa20_encrypt_stream (ctx, buf+1, buf+1, (sizeof buf)-1-1);
+diff -up libgcrypt-1.8.5/cipher/seed.c.aes-perf libgcrypt-1.8.5/cipher/seed.c
+--- libgcrypt-1.8.5/cipher/seed.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/seed.c	2020-04-22 18:29:41.680862038 +0200
+@@ -309,11 +309,12 @@ do_setkey (SEED_context *ctx, const byte
+ }
+ 
+ static gcry_err_code_t
+-seed_setkey (void *context, const byte *key, const unsigned keylen)
++seed_setkey (void *context, const byte *key, const unsigned keylen,
++             gcry_cipher_hd_t hd)
+ {
+   SEED_context *ctx = context;
+-
+   int rc = do_setkey (ctx, key, keylen);
++  (void)hd;
+   _gcry_burn_stack (4*6 + sizeof(void*)*2 + sizeof(int)*2);
+   return rc;
+ }
+@@ -446,7 +447,7 @@ selftest (void)
+     0x22, 0x6B, 0xC3, 0x14, 0x2C, 0xD4, 0x0D, 0x4A,
+   };
+ 
+-  seed_setkey (&ctx, key, sizeof(key));
++  seed_setkey (&ctx, key, sizeof(key), NULL);
+   seed_encrypt (&ctx, scratch, plaintext);
+   if (memcmp (scratch, ciphertext, sizeof (ciphertext)))
+     return "SEED test encryption failed.";
+diff -up libgcrypt-1.8.5/cipher/serpent.c.aes-perf libgcrypt-1.8.5/cipher/serpent.c
+--- libgcrypt-1.8.5/cipher/serpent.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/serpent.c	2020-04-22 18:29:41.680862038 +0200
+@@ -748,13 +748,16 @@ serpent_setkey_internal (serpent_context
+ /* Initialize CTX with the key KEY of KEY_LENGTH bytes.  */
+ static gcry_err_code_t
+ serpent_setkey (void *ctx,
+-		const byte *key, unsigned int key_length)
++		const byte *key, unsigned int key_length,
++                gcry_cipher_hd_t hd)
+ {
+   serpent_context_t *context = ctx;
+   static const char *serpent_test_ret;
+   static int serpent_init_done;
+   gcry_err_code_t ret = GPG_ERR_NO_ERROR;
+ 
++  (void)hd;
++
+   if (! serpent_init_done)
+     {
+       /* Execute a self-test the first time, Serpent is used.  */
+@@ -999,7 +1002,7 @@ _gcry_serpent_ctr_enc(void *context, uns
+       /* Encrypt the counter. */
+       serpent_encrypt_internal(ctx, ctr, tmpbuf);
+       /* XOR the input with the encrypted counter and store in output.  */
+-      buf_xor(outbuf, tmpbuf, inbuf, sizeof(serpent_block_t));
++      cipher_block_xor(outbuf, tmpbuf, inbuf, sizeof(serpent_block_t));
+       outbuf += sizeof(serpent_block_t);
+       inbuf  += sizeof(serpent_block_t);
+       /* Increment the counter.  */
+@@ -1114,7 +1117,8 @@ _gcry_serpent_cbc_dec(void *context, uns
+          the intermediate result to SAVEBUF.  */
+       serpent_decrypt_internal (ctx, inbuf, savebuf);
+ 
+-      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, sizeof(serpent_block_t));
++      cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf,
++                                sizeof(serpent_block_t));
+       inbuf += sizeof(serpent_block_t);
+       outbuf += sizeof(serpent_block_t);
+     }
+@@ -1218,7 +1222,7 @@ _gcry_serpent_cfb_dec(void *context, uns
+   for ( ;nblocks; nblocks-- )
+     {
+       serpent_encrypt_internal(ctx, iv, iv);
+-      buf_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t));
++      cipher_block_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t));
+       outbuf += sizeof(serpent_block_t);
+       inbuf  += sizeof(serpent_block_t);
+     }
+diff -up libgcrypt-1.8.5/cipher/twofish.c.aes-perf libgcrypt-1.8.5/cipher/twofish.c
+--- libgcrypt-1.8.5/cipher/twofish.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/twofish.c	2020-04-22 18:29:41.680862038 +0200
+@@ -734,12 +734,15 @@ do_twofish_setkey (TWOFISH_context *ctx,
+ }
+ 
+ static gcry_err_code_t
+-twofish_setkey (void *context, const byte *key, unsigned int keylen)
++twofish_setkey (void *context, const byte *key, unsigned int keylen,
++                gcry_cipher_hd_t hd)
+ {
+   TWOFISH_context *ctx = context;
+   unsigned int hwfeatures = _gcry_get_hw_features ();
+   int rc;
+ 
++  (void)hd;
++
+   rc = do_twofish_setkey (ctx, key, keylen);
+ 
+ #ifdef USE_AVX2
+@@ -1245,7 +1248,7 @@ _gcry_twofish_ctr_enc(void *context, uns
+         burn_stack_depth = burn;
+ 
+       /* XOR the input with the encrypted counter and store in output.  */
+-      buf_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE);
++      cipher_block_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE);
+       outbuf += TWOFISH_BLOCKSIZE;
+       inbuf  += TWOFISH_BLOCKSIZE;
+       /* Increment the counter.  */
+@@ -1327,7 +1330,7 @@ _gcry_twofish_cbc_dec(void *context, uns
+       if (burn > burn_stack_depth)
+         burn_stack_depth = burn;
+ 
+-      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, TWOFISH_BLOCKSIZE);
++      cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, TWOFISH_BLOCKSIZE);
+       inbuf += TWOFISH_BLOCKSIZE;
+       outbuf += TWOFISH_BLOCKSIZE;
+     }
+@@ -1399,7 +1402,7 @@ _gcry_twofish_cfb_dec(void *context, uns
+       if (burn > burn_stack_depth)
+         burn_stack_depth = burn;
+ 
+-      buf_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE);
++      cipher_block_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE);
+       outbuf += TWOFISH_BLOCKSIZE;
+       inbuf += TWOFISH_BLOCKSIZE;
+     }
+@@ -1710,7 +1713,7 @@ selftest (void)
+     0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA
+   };
+ 
+-  twofish_setkey (&ctx, key, sizeof(key));
++  twofish_setkey (&ctx, key, sizeof(key), NULL);
+   twofish_encrypt (&ctx, scratch, plaintext);
+   if (memcmp (scratch, ciphertext, sizeof (ciphertext)))
+     return "Twofish-128 test encryption failed.";
+@@ -1718,7 +1721,7 @@ selftest (void)
+   if (memcmp (scratch, plaintext, sizeof (plaintext)))
+     return "Twofish-128 test decryption failed.";
+ 
+-  twofish_setkey (&ctx, key_256, sizeof(key_256));
++  twofish_setkey (&ctx, key_256, sizeof(key_256), NULL);
+   twofish_encrypt (&ctx, scratch, plaintext_256);
+   if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
+     return "Twofish-256 test encryption failed.";
+@@ -1800,13 +1803,13 @@ main()
+   /* Encryption test. */
+   for (i = 0; i < 125; i++)
+     {
+-      twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]));
++      twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]), NULL);
+       for (j = 0; j < 1000; j++)
+         twofish_encrypt (&ctx, buffer[2], buffer[2]);
+-      twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]));
++      twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]), NULL);
+       for (j = 0; j < 1000; j++)
+         twofish_encrypt (&ctx, buffer[3], buffer[3]);
+-      twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2);
++      twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2, NULL);
+       for (j = 0; j < 1000; j++) {
+         twofish_encrypt (&ctx, buffer[0], buffer[0]);
+         twofish_encrypt (&ctx, buffer[1], buffer[1]);
+@@ -1818,15 +1821,15 @@ main()
+   /* Decryption test. */
+   for (i = 0; i < 125; i++)
+     {
+-      twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2);
++      twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2, NULL);
+       for (j = 0; j < 1000; j++) {
+         twofish_decrypt (&ctx, buffer[0], buffer[0]);
+         twofish_decrypt (&ctx, buffer[1], buffer[1]);
+       }
+-      twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]));
++      twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]), NULL);
+       for (j = 0; j < 1000; j++)
+         twofish_decrypt (&ctx, buffer[3], buffer[3]);
+-      twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]));
++      twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]), NULL);
+       for (j = 0; j < 1000; j++)
+         twofish_decrypt (&ctx, buffer[2], buffer[2]);
+     }
+diff -up libgcrypt-1.8.5/configure.ac.aes-perf libgcrypt-1.8.5/configure.ac
+--- libgcrypt-1.8.5/configure.ac.aes-perf	2020-04-22 18:29:41.655862516 +0200
++++ libgcrypt-1.8.5/configure.ac	2020-04-22 18:29:41.681862019 +0200
+@@ -649,6 +649,14 @@ AC_ARG_ENABLE(arm-crypto-support,
+ 	      armcryptosupport=$enableval,armcryptosupport=yes)
+ AC_MSG_RESULT($armcryptosupport)
+ 
++# Implementation of the --disable-ppc-crypto-support switch.
++AC_MSG_CHECKING([whether PPC crypto support is requested])
++AC_ARG_ENABLE(ppc-crypto-support,
++              AC_HELP_STRING([--disable-ppc-crypto-support],
++                 [Disable support for the PPC crypto instructions introduced in POWER 8 (PowerISA 2.07)]),
++              ppccryptosupport=$enableval,ppccryptosupport=yes)
++AC_MSG_RESULT($ppccryptosupport)
++
+ # Implementation of the --disable-O-flag-munging switch.
+ AC_MSG_CHECKING([whether a -O flag munging is requested])
+ AC_ARG_ENABLE([O-flag-munging],
+@@ -1196,6 +1204,9 @@ if test "$mpi_cpu_arch" != "arm" ; then
+    fi
+ fi
+ 
++if test "$mpi_cpu_arch" != "ppc"; then
++   ppccryptosupport="n/a"
++fi
+ 
+ #############################################
+ ####                                     ####
+@@ -1722,6 +1733,113 @@ if test "$gcry_cv_gcc_inline_asm_aarch64
+ fi
+ 
+ 
++#
++# Check whether PowerPC AltiVec/VSX intrinsics
++#
++AC_CACHE_CHECK([whether compiler supports PowerPC AltiVec/VSX intrinsics],
++      [gcry_cv_cc_ppc_altivec],
++      [if test "$mpi_cpu_arch" != "ppc" ; then
++	gcry_cv_cc_ppc_altivec="n/a"
++      else
++	gcry_cv_cc_ppc_altivec=no
++	AC_COMPILE_IFELSE([AC_LANG_SOURCE(
++	[[#include <altivec.h>
++	  typedef vector unsigned char block;
++	  block fn(block in)
++	  {
++	    block t = vec_perm (in, in, vec_vsx_ld (0, (unsigned char*)0));
++	    return vec_cipher_be (t, in);
++	  }
++	  ]])],
++	[gcry_cv_cc_ppc_altivec=yes])
++      fi])
++if test "$gcry_cv_cc_ppc_altivec" = "yes" ; then
++    AC_DEFINE(HAVE_COMPATIBLE_CC_PPC_ALTIVEC,1,
++	    [Defined if underlying compiler supports PowerPC AltiVec/VSX/crypto intrinsics])
++fi
++
++_gcc_cflags_save=$CFLAGS
++CFLAGS="$CFLAGS -maltivec -mvsx -mcrypto"
++
++if test "$gcry_cv_cc_ppc_altivec" = "no" &&
++    test "$mpi_cpu_arch" = "ppc" ; then
++  AC_CACHE_CHECK([whether compiler supports PowerPC AltiVec/VSX/crypto intrinsics with extra GCC flags],
++    [gcry_cv_cc_ppc_altivec_cflags],
++    [gcry_cv_cc_ppc_altivec_cflags=no
++    AC_COMPILE_IFELSE([AC_LANG_SOURCE(
++      [[#include <altivec.h>
++	typedef vector unsigned char block;
++	block fn(block in)
++	{
++	  block t = vec_perm (in, in, vec_vsx_ld (0, (unsigned char*)0));
++	  return vec_cipher_be (t, in);
++	}]])],
++      [gcry_cv_cc_ppc_altivec_cflags=yes])])
++  if test "$gcry_cv_cc_ppc_altivec_cflags" = "yes" ; then
++    AC_DEFINE(HAVE_COMPATIBLE_CC_PPC_ALTIVEC,1,
++	      [Defined if underlying compiler supports PowerPC AltiVec/VSX/crypto intrinsics])
++    AC_DEFINE(HAVE_COMPATIBLE_CC_PPC_ALTIVEC_WITH_CFLAGS,1,
++	      [Defined if underlying compiler supports PowerPC AltiVec/VSX/crypto intrinsics with extra GCC flags])
++  fi
++fi
++
++AM_CONDITIONAL(ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS,
++	       test "$gcry_cv_cc_ppc_altivec_cflags" = "yes")
++
++# Restore flags.
++CFLAGS=$_gcc_cflags_save;
++
++
++#
++# Check whether GCC inline assembler supports PowerPC AltiVec/VSX/crypto instructions
++#
++AC_CACHE_CHECK([whether GCC inline assembler supports PowerPC AltiVec/VSX/crypto instructions],
++       [gcry_cv_gcc_inline_asm_ppc_altivec],
++       [if test "$mpi_cpu_arch" != "ppc" ; then
++          gcry_cv_gcc_inline_asm_ppc_altivec="n/a"
++        else
++          gcry_cv_gcc_inline_asm_ppc_altivec=no
++          AC_COMPILE_IFELSE([AC_LANG_SOURCE(
++          [[__asm__(".globl testfn;\n"
++		    "testfn:\n"
++		    "stvx %v31,%r12,%r0;\n"
++		    "lvx  %v20,%r12,%r0;\n"
++		    "vcipher %v0, %v1, %v22;\n"
++		    "lxvw4x %vs32, %r0, %r1;\n"
++		    "vadduwm %v0, %v1, %v22;\n"
++		  );
++            ]])],
++          [gcry_cv_gcc_inline_asm_ppc_altivec=yes])
++        fi])
++if test "$gcry_cv_gcc_inline_asm_ppc_altivec" = "yes" ; then
++   AC_DEFINE(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC,1,
++     [Defined if inline assembler supports PowerPC AltiVec/VSX/crypto instructions])
++fi
++
++
++#
++# Check whether GCC inline assembler supports PowerISA 3.00 instructions
++#
++AC_CACHE_CHECK([whether GCC inline assembler supports PowerISA 3.00 instructions],
++       [gcry_cv_gcc_inline_asm_ppc_arch_3_00],
++       [if test "$mpi_cpu_arch" != "ppc" ; then
++          gcry_cv_gcc_inline_asm_ppc_arch_3_00="n/a"
++        else
++          gcry_cv_gcc_inline_asm_ppc_arch_3_00=no
++          AC_COMPILE_IFELSE([AC_LANG_SOURCE(
++          [[__asm__(".globl testfn;\n"
++		    "testfn:\n"
++		    "stxvb16x %r1,%v12,%v30;\n"
++		  );
++            ]])],
++          [gcry_cv_gcc_inline_asm_ppc_arch_3_00=yes])
++        fi])
++if test "$gcry_cv_gcc_inline_asm_ppc_arch_3_00" = "yes" ; then
++   AC_DEFINE(HAVE_GCC_INLINE_ASM_PPC_ARCH_3_00,1,
++     [Defined if inline assembler supports PowerISA 3.00 instructions])
++fi
++
++
+ #######################################
+ #### Checks for library functions. ####
+ #######################################
+@@ -1999,6 +2117,10 @@ if test x"$armcryptosupport" = xyes ; th
+   AC_DEFINE(ENABLE_ARM_CRYPTO_SUPPORT,1,
+             [Enable support for ARMv8 Crypto Extension instructions.])
+ fi
++if test x"$ppccryptosupport" = xyes ; then
++  AC_DEFINE(ENABLE_PPC_CRYPTO_SUPPORT,1,
++            [Enable support for POWER 8 (PowerISA 2.07) crypto extension.])
++fi
+ if test x"$jentsupport" = xyes ; then
+   AC_DEFINE(ENABLE_JENT_SUPPORT, 1,
+             [Enable support for the jitter entropy collector.])
+@@ -2106,6 +2228,21 @@ if test "$found" = "1" ; then
+          GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-armv8-ce.lo"
+          GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-armv8-aarch64-ce.lo"
+       ;;
++      powerpc64le-*-*)
++         # Build with the crypto extension implementation
++         GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc.lo"
++         GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc9le.lo"
++      ;;
++      powerpc64-*-*)
++         # Big-Endian.
++         # Build with the crypto extension implementation
++         GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc.lo"
++      ;;
++      powerpc-*-*)
++         # Big-Endian.
++         # Build with the crypto extension implementation
++         GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc.lo"
++      ;;
+    esac
+ 
+    case "$mpi_cpu_arch" in
+@@ -2555,6 +2692,7 @@ case "$mpi_cpu_arch" in
+         ;;
+      ppc)
+         AC_DEFINE(HAVE_CPU_ARCH_PPC, 1,   [Defined for PPC platforms])
++        GCRYPT_HWF_MODULES="hwf-ppc.lo"
+         ;;
+      arm)
+         AC_DEFINE(HAVE_CPU_ARCH_ARM, 1,   [Defined for ARM platforms])
+@@ -2653,6 +2791,7 @@ GCRY_MSG_SHOW([Try using Intel AVX:
+ GCRY_MSG_SHOW([Try using Intel AVX2:     ],[$avx2support])
+ GCRY_MSG_SHOW([Try using ARM NEON:       ],[$neonsupport])
+ GCRY_MSG_SHOW([Try using ARMv8 crypto:   ],[$armcryptosupport])
++GCRY_MSG_SHOW([Try using PPC crypto:     ],[$ppccryptosupport])
+ GCRY_MSG_SHOW([],[])
+ 
+ if test "x${gpg_config_script_warn}" != x; then
+diff -up libgcrypt-1.8.5/src/cipher.h.aes-perf libgcrypt-1.8.5/src/cipher.h
+--- libgcrypt-1.8.5/src/cipher.h.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/src/cipher.h	2020-04-22 18:29:41.681862019 +0200
+@@ -158,6 +158,9 @@ size_t _gcry_aes_ocb_crypt (gcry_cipher_
+ 			    const void *inbuf_arg, size_t nblocks, int encrypt);
+ size_t _gcry_aes_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg,
+ 			   size_t nblocks);
++void _gcry_aes_xts_crypt (void *context, unsigned char *tweak,
++			  void *outbuf_arg, const void *inbuf_arg,
++			  size_t nblocks, int encrypt);
+ 
+ /*-- blowfish.c --*/
+ void _gcry_blowfish_cfb_dec (void *context, unsigned char *iv,
+diff -up libgcrypt-1.8.5/src/cipher-proto.h.aes-perf libgcrypt-1.8.5/src/cipher-proto.h
+--- libgcrypt-1.8.5/src/cipher-proto.h.aes-perf	2020-04-22 18:29:41.643862745 +0200
++++ libgcrypt-1.8.5/src/cipher-proto.h	2020-04-22 18:29:41.681862019 +0200
+@@ -132,7 +132,8 @@ typedef struct gcry_pk_spec
+ /* Type for the cipher_setkey function.  */
+ typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c,
+ 						 const unsigned char *key,
+-						 unsigned keylen);
++						 unsigned keylen,
++						 gcry_cipher_hd_t hd);
+ 
+ /* Type for the cipher_encrypt function.  */
+ typedef unsigned int (*gcry_cipher_encrypt_t) (void *c,
+diff -up libgcrypt-1.8.5/src/g10lib.h.aes-perf libgcrypt-1.8.5/src/g10lib.h
+--- libgcrypt-1.8.5/src/g10lib.h.aes-perf	2020-04-22 18:29:41.660862420 +0200
++++ libgcrypt-1.8.5/src/g10lib.h	2020-04-22 18:50:46.990661309 +0200
+@@ -233,7 +233,9 @@ char **_gcry_strtokenize (const char *st
+ 
+ #define HWF_INTEL_RDTSC         (1 << 20)
+ 
+-
++#define HWF_PPC_VCRYPTO         (1 << 22)
++#define HWF_PPC_ARCH_3_00       (1 << 23)
++#define HWF_PPC_ARCH_2_07       (1 << 24)
+ 
+ gpg_err_code_t _gcry_disable_hw_feature (const char *name);
+ void _gcry_detect_hw_features (void);
+diff -up libgcrypt-1.8.5/src/hwf-common.h.aes-perf libgcrypt-1.8.5/src/hwf-common.h
+--- libgcrypt-1.8.5/src/hwf-common.h.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/src/hwf-common.h	2020-04-22 18:29:41.682862000 +0200
+@@ -22,6 +22,6 @@
+ 
+ unsigned int _gcry_hwf_detect_x86 (void);
+ unsigned int _gcry_hwf_detect_arm (void);
+-
++unsigned int _gcry_hwf_detect_ppc (void);
+ 
+ #endif /*HWF_COMMON_H*/
+diff -up libgcrypt-1.8.5/src/hwfeatures.c.aes-perf libgcrypt-1.8.5/src/hwfeatures.c
+--- libgcrypt-1.8.5/src/hwfeatures.c.aes-perf	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/src/hwfeatures.c	2020-04-22 18:51:48.326487879 +0200
+@@ -42,6 +42,7 @@ static struct
+   const char *desc;
+ } hwflist[] =
+   {
++#if defined(HAVE_CPU_ARCH_X86)
+     { HWF_PADLOCK_RNG,         "padlock-rng" },
+     { HWF_PADLOCK_AES,         "padlock-aes" },
+     { HWF_PADLOCK_SHA,         "padlock-sha" },
+@@ -58,11 +59,17 @@ static struct
+     { HWF_INTEL_AVX2,          "intel-avx2" },
+     { HWF_INTEL_FAST_VPGATHER, "intel-fast-vpgather" },
+     { HWF_INTEL_RDTSC,         "intel-rdtsc" },
++#elif defined(HAVE_CPU_ARCH_ARM)
+     { HWF_ARM_NEON,            "arm-neon" },
+     { HWF_ARM_AES,             "arm-aes" },
+     { HWF_ARM_SHA1,            "arm-sha1" },
+     { HWF_ARM_SHA2,            "arm-sha2" },
+-    { HWF_ARM_PMULL,           "arm-pmull" }
++    { HWF_ARM_PMULL,           "arm-pmull" },
++#elif defined(HAVE_CPU_ARCH_PPC)
++    { HWF_PPC_VCRYPTO,         "ppc-vcrypto" },
++    { HWF_PPC_ARCH_3_00,       "ppc-arch_3_00" },
++    { HWF_PPC_ARCH_2_07,       "ppc-arch_2_07" },
++#endif
+   };
+ 
+ /* A bit vector with the hardware features which shall not be used.
+@@ -207,12 +214,14 @@ _gcry_detect_hw_features (void)
+   {
+     hw_features = _gcry_hwf_detect_x86 ();
+   }
+-#endif /* HAVE_CPU_ARCH_X86 */
+-#if defined (HAVE_CPU_ARCH_ARM)
++#elif defined (HAVE_CPU_ARCH_ARM)
+   {
+     hw_features = _gcry_hwf_detect_arm ();
+   }
+-#endif /* HAVE_CPU_ARCH_ARM */
+-
++#elif defined (HAVE_CPU_ARCH_PPC)
++  {
++    hw_features = _gcry_hwf_detect_ppc ();
++  }
++#endif
+   hw_features &= ~disabled_hw_features;
+ }
+diff -up libgcrypt-1.8.5/src/hwf-ppc.c.aes-perf libgcrypt-1.8.5/src/hwf-ppc.c
+--- libgcrypt-1.8.5/src/hwf-ppc.c.aes-perf	2020-04-22 18:29:41.682862000 +0200
++++ libgcrypt-1.8.5/src/hwf-ppc.c	2020-04-22 18:50:21.396150974 +0200
+@@ -0,0 +1,243 @@
++/* hwf-ppc.c - Detect hardware features - PPC part
++ * Copyright (C) 2013,2019 Jussi Kivilinna <jussi.kivilinna@iki.fi>
++ * Copyright (C) 2019 Shawn Landden <shawn@git.icu>
++ *
++ * 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, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <config.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <stdarg.h>
++#include <unistd.h>
++#include <errno.h>
++#if defined(HAVE_SYS_AUXV_H) && (defined(HAVE_GETAUXVAL) || \
++    defined(HAVE_ELF_AUX_INFO))
++#include <sys/auxv.h>
++#endif
++
++#include "g10lib.h"
++#include "hwf-common.h"
++
++#if !defined (__powerpc__) && !defined (__powerpc64__)
++# error Module build for wrong CPU.
++#endif
++
++
++#if defined(HAVE_SYS_AUXV_H) && defined(HAVE_ELF_AUX_INFO) && \
++    !defined(HAVE_GETAUXVAL) && defined(AT_HWCAP)
++#define HAVE_GETAUXVAL
++static unsigned long getauxval(unsigned long type)
++{
++  unsigned long auxval = 0;
++  int err;
++
++  /* FreeBSD provides 'elf_aux_info' function that does the same as
++   * 'getauxval' on Linux. */
++
++  err = elf_aux_info (type, &auxval, sizeof(auxval));
++  if (err)
++    {
++      errno = err;
++      auxval = 0;
++    }
++
++  return auxval;
++}
++#endif
++
++
++#undef HAS_SYS_AT_HWCAP
++#if defined(__linux__) || \
++    (defined(HAVE_SYS_AUXV_H) && defined(HAVE_GETAUXVAL))
++#define HAS_SYS_AT_HWCAP 1
++
++struct feature_map_s
++  {
++    unsigned int hwcap_flag;
++    unsigned int hwcap2_flag;
++    unsigned int hwf_flag;
++  };
++
++#if defined(__powerpc__) || defined(__powerpc64__)
++
++/* Note: These macros have same values on Linux and FreeBSD. */
++#ifndef AT_HWCAP
++# define AT_HWCAP      16
++#endif
++#ifndef AT_HWCAP2
++# define AT_HWCAP2     26
++#endif
++
++#ifndef PPC_FEATURE2_ARCH_2_07
++# define PPC_FEATURE2_ARCH_2_07     0x80000000
++#endif
++#ifndef PPC_FEATURE2_VEC_CRYPTO
++# define PPC_FEATURE2_VEC_CRYPTO    0x02000000
++#endif
++#ifndef PPC_FEATURE2_ARCH_3_00
++# define PPC_FEATURE2_ARCH_3_00     0x00800000
++#endif
++
++static const struct feature_map_s ppc_features[] =
++  {
++    { 0, PPC_FEATURE2_ARCH_2_07, HWF_PPC_ARCH_2_07 },
++#ifdef ENABLE_PPC_CRYPTO_SUPPORT
++    { 0, PPC_FEATURE2_VEC_CRYPTO, HWF_PPC_VCRYPTO },
++#endif
++    { 0, PPC_FEATURE2_ARCH_3_00, HWF_PPC_ARCH_3_00 },
++  };
++#endif
++
++static int
++get_hwcap(unsigned int *hwcap, unsigned int *hwcap2)
++{
++  struct { unsigned long a_type; unsigned long a_val; } auxv;
++  FILE *f;
++  int err = -1;
++  static int hwcap_initialized = 0;
++  static unsigned int stored_hwcap = 0;
++  static unsigned int stored_hwcap2 = 0;
++
++  if (hwcap_initialized)
++    {
++      *hwcap = stored_hwcap;
++      *hwcap2 = stored_hwcap2;
++      return 0;
++    }
++
++#if 0 // TODO: configure.ac detection for __builtin_cpu_supports
++      // TODO: move to 'detect_ppc_builtin_cpu_supports'
++#if defined(__GLIBC__) && defined(__GNUC__) && __GNUC__ >= 6
++  /* __builtin_cpu_supports returns 0 if glibc support doesn't exist, so
++   * we can only trust positive results. */
++#ifdef ENABLE_PPC_CRYPTO_SUPPORT
++  if (__builtin_cpu_supports("vcrypto")) /* TODO: Configure.ac */
++    {
++      stored_hwcap2 |= PPC_FEATURE2_VEC_CRYPTO;
++      hwcap_initialized = 1;
++    }
++#endif
++
++  if (__builtin_cpu_supports("arch_3_00")) /* TODO: Configure.ac */
++    {
++      stored_hwcap2 |= PPC_FEATURE2_ARCH_3_00;
++      hwcap_initialized = 1;
++    }
++#endif
++#endif
++
++#if defined(HAVE_SYS_AUXV_H) && defined(HAVE_GETAUXVAL)
++  errno = 0;
++  auxv.a_val = getauxval (AT_HWCAP);
++  if (errno == 0)
++    {
++      stored_hwcap |= auxv.a_val;
++      hwcap_initialized = 1;
++    }
++
++  if (AT_HWCAP2 >= 0)
++    {
++      errno = 0;
++      auxv.a_val = getauxval (AT_HWCAP2);
++      if (errno == 0)
++	{
++	  stored_hwcap2 |= auxv.a_val;
++	  hwcap_initialized = 1;
++	}
++    }
++
++  if (hwcap_initialized && (stored_hwcap || stored_hwcap2))
++    {
++      *hwcap = stored_hwcap;
++      *hwcap2 = stored_hwcap2;
++      return 0;
++    }
++#endif
++
++  f = fopen("/proc/self/auxv", "r");
++  if (!f)
++    {
++      *hwcap = stored_hwcap;
++      *hwcap2 = stored_hwcap2;
++      return -1;
++    }
++
++  while (fread(&auxv, sizeof(auxv), 1, f) > 0)
++    {
++      if (auxv.a_type == AT_HWCAP)
++        {
++          stored_hwcap |= auxv.a_val;
++          hwcap_initialized = 1;
++        }
++
++      if (auxv.a_type == AT_HWCAP2)
++        {
++          stored_hwcap2 |= auxv.a_val;
++          hwcap_initialized = 1;
++        }
++    }
++
++  if (hwcap_initialized)
++      err = 0;
++
++  fclose(f);
++
++  *hwcap = stored_hwcap;
++  *hwcap2 = stored_hwcap2;
++  return err;
++}
++
++static unsigned int
++detect_ppc_at_hwcap(void)
++{
++  unsigned int hwcap;
++  unsigned int hwcap2;
++  unsigned int features = 0;
++  unsigned int i;
++
++  if (get_hwcap(&hwcap, &hwcap2) < 0)
++      return features;
++
++  for (i = 0; i < DIM(ppc_features); i++)
++    {
++      if (hwcap & ppc_features[i].hwcap_flag)
++        features |= ppc_features[i].hwf_flag;
++
++      if (hwcap2 & ppc_features[i].hwcap2_flag)
++        features |= ppc_features[i].hwf_flag;
++    }
++
++  return features;
++}
++
++#endif
++
++unsigned int
++_gcry_hwf_detect_ppc (void)
++{
++  unsigned int ret = 0;
++  unsigned int broken_hwfs = 0;
++
++#if defined (HAS_SYS_AT_HWCAP)
++  ret |= detect_ppc_at_hwcap ();
++#endif
++
++  ret &= ~broken_hwfs;
++
++  return ret;
++}
+diff -up libgcrypt-1.8.5/src/Makefile.am.aes-perf libgcrypt-1.8.5/src/Makefile.am
+--- libgcrypt-1.8.5/src/Makefile.am.aes-perf	2018-11-14 14:16:40.000000000 +0100
++++ libgcrypt-1.8.5/src/Makefile.am	2020-04-22 18:29:41.683861981 +0200
+@@ -66,7 +66,7 @@ libgcrypt_la_SOURCES = \
+ 	hmac256.c hmac256.h context.c context.h \
+ 	ec-context.h
+ 
+-EXTRA_libgcrypt_la_SOURCES = hwf-x86.c hwf-arm.c
++EXTRA_libgcrypt_la_SOURCES = hwf-x86.c hwf-arm.c hwf-ppc.c
+ gcrypt_hwf_modules = @GCRYPT_HWF_MODULES@
+ 
+ 
diff --git a/SOURCES/libgcrypt-1.8.5-build.patch b/SOURCES/libgcrypt-1.8.5-build.patch
new file mode 100644
index 0000000..3e71238
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.5-build.patch
@@ -0,0 +1,14 @@
+diff -up libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S.build libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S
+--- libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S.build	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S	2020-01-30 17:26:12.026404286 +0100
+@@ -87,9 +87,8 @@ _gcry_poly1305_armv7_neon_init_ext:
+ .Lpoly1305_init_ext_neon_local:
+ 	stmfd sp!, {r4-r11, lr}
+ 	sub sp, sp, #32
+-	mov r14, r2
++	mov r14, #-1
+ 	and r2, r2, r2
+-	moveq r14, #-1
+ 	UNALIGNED_LDMIA4(r1, r2, r3, r4, r5)
+ 	GET_DATA_POINTER(r7,.Lpoly1305_init_constants_neon,r8)
+ 	mov r6, r2
diff --git a/SOURCES/libgcrypt-1.8.5-fips-module.patch b/SOURCES/libgcrypt-1.8.5-fips-module.patch
new file mode 100644
index 0000000..60b9ce2
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.5-fips-module.patch
@@ -0,0 +1,139 @@
+diff -up libgcrypt-1.8.5/src/fips.c.fips-module libgcrypt-1.8.5/src/fips.c
+--- libgcrypt-1.8.5/src/fips.c.fips-module	2020-04-20 19:07:45.924919645 +0200
++++ libgcrypt-1.8.5/src/fips.c	2020-04-20 19:10:33.690722470 +0200
+@@ -35,10 +35,6 @@
+ #include "hmac256.h"
+ 
+ 
+-/* The name of the file used to force libgcrypt into fips mode. */
+-#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled"
+-
+-
+ /* The states of the finite state machine used in fips mode.  */
+ enum module_states
+   {
+@@ -122,54 +118,6 @@ _gcry_initialize_fips_mode (int force)
+       goto leave;
+     }
+ 
+-  /* For testing the system it is useful to override the system
+-     provided detection of the FIPS mode and force FIPS mode using a
+-     file.  The filename is hardwired so that there won't be any
+-     confusion on whether /etc/gcrypt/ or /usr/local/etc/gcrypt/ is
+-     actually used.  The file itself may be empty.  */
+-  if ( !access (FIPS_FORCE_FILE, F_OK) )
+-    {
+-      gcry_assert (!no_fips_mode_required);
+-      goto leave;
+-    }
+-
+-  /* Checking based on /proc file properties.  */
+-  {
+-    static const char procfname[] = "/proc/sys/crypto/fips_enabled";
+-    FILE *fp;
+-    int saved_errno;
+-
+-    fp = fopen (procfname, "r");
+-    if (fp)
+-      {
+-        char line[256];
+-
+-        if (fgets (line, sizeof line, fp) && atoi (line))
+-          {
+-            /* System is in fips mode.  */
+-            fclose (fp);
+-            gcry_assert (!no_fips_mode_required);
+-            goto leave;
+-          }
+-        fclose (fp);
+-      }
+-    else if ((saved_errno = errno) != ENOENT
+-             && saved_errno != EACCES
+-             && !access ("/proc/version", F_OK) )
+-      {
+-        /* Problem reading the fips file despite that we have the proc
+-           file system.  We better stop right away. */
+-        log_info ("FATAL: error reading `%s' in libgcrypt: %s\n",
+-                  procfname, strerror (saved_errno));
+-#ifdef HAVE_SYSLOG
+-        syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
+-                "reading `%s' failed: %s - abort",
+-                procfname, strerror (saved_errno));
+-#endif /*HAVE_SYSLOG*/
+-        abort ();
+-      }
+-  }
+-
+   /* Fips not not requested, set flag.  */
+   no_fips_mode_required = 1;
+ 
+diff -up libgcrypt-1.8.5/src/g10lib.h.fips-module libgcrypt-1.8.5/src/g10lib.h
+--- libgcrypt-1.8.5/src/g10lib.h.fips-module	2020-04-20 19:07:45.918919759 +0200
++++ libgcrypt-1.8.5/src/g10lib.h	2020-04-20 19:11:05.003125740 +0200
+@@ -422,6 +422,9 @@ gpg_err_code_t _gcry_sexp_vextract_param
+ 
+ /*-- fips.c --*/
+ 
++/* The name of the file used to force libgcrypt into fips mode. */
++#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled"
++
+ void _gcry_initialize_fips_mode (int force);
+ 
+ int _gcry_fips_mode (void);
+diff -up libgcrypt-1.8.5/src/global.c.fips-module libgcrypt-1.8.5/src/global.c
+--- libgcrypt-1.8.5/src/global.c.fips-module	2020-04-20 19:07:45.919919741 +0200
++++ libgcrypt-1.8.5/src/global.c	2020-04-20 19:07:45.950919149 +0200
+@@ -160,6 +160,53 @@ void __attribute__ ((constructor)) _gcry
+   rv = access (FIPS_MODULE_PATH, F_OK);
+   if (rv < 0 && errno != ENOENT)
+     rv = 0;
++ 
++  /* For testing the system it is useful to override the system
++     provided detection of the FIPS mode and force FIPS mode using a
++     file.  The filename is hardwired so that there won't be any
++     confusion on whether /etc/gcrypt/ or /usr/local/etc/gcrypt/ is
++     actually used.  The file itself may be empty.  */
++  if ( !access (FIPS_FORCE_FILE, F_OK) )
++    {
++      rv = 0;
++      force_fips_mode = 1;
++    }
++
++  /* Checking based on /proc file properties.  */
++  {
++    static const char procfname[] = "/proc/sys/crypto/fips_enabled";
++    FILE *fp;
++    int saved_errno;
++
++    fp = fopen (procfname, "r");
++    if (fp)
++      {
++        char line[256];
++
++        if (fgets (line, sizeof line, fp) && atoi (line))
++          {
++            /* System is in fips mode.  */
++            rv = 0;
++            force_fips_mode = 1;
++          }
++        fclose (fp);
++      }
++    else if ((saved_errno = errno) != ENOENT
++             && saved_errno != EACCES
++             && !access ("/proc/version", F_OK) )
++      {
++        /* Problem reading the fips file despite that we have the proc
++           file system.  We better stop right away. */
++        log_info ("FATAL: error reading `%s' in libgcrypt: %s\n",
++                  procfname, strerror (saved_errno));
++#ifdef HAVE_SYSLOG
++        syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
++                "reading `%s' failed: %s - abort",
++                procfname, strerror (saved_errno));
++#endif /*HAVE_SYSLOG*/
++        abort ();
++      }
++  }
+ 
+   if (!rv)
+     {
diff --git a/SOURCES/libgcrypt-1.8.5-getrandom.patch b/SOURCES/libgcrypt-1.8.5-getrandom.patch
new file mode 100644
index 0000000..ff2ef3b
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.5-getrandom.patch
@@ -0,0 +1,285 @@
+diff -up libgcrypt-1.8.5/random/rand-internal.h.getrandom libgcrypt-1.8.5/random/rand-internal.h
+--- libgcrypt-1.8.5/random/rand-internal.h.getrandom	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/random/rand-internal.h	2020-04-20 14:55:34.875949624 +0200
+@@ -47,6 +47,7 @@ void _gcry_random_progress (const char *
+ 
+ /*-- random-csprng.c --*/
+ void _gcry_rngcsprng_initialize (int full);
++void _gcry_rngcsprng_deinit (void);
+ void _gcry_rngcsprng_close_fds (void);
+ void _gcry_rngcsprng_dump_stats (void);
+ void _gcry_rngcsprng_secure_alloc (void);
+@@ -68,6 +69,7 @@ void _gcry_rngcsprng_fast_poll (void);
+ 
+ /*-- random-drbg.c --*/
+ void _gcry_rngdrbg_inititialize (int full);
++void _gcry_rngdrbg_deinit (void);
+ void _gcry_rngdrbg_close_fds (void);
+ void _gcry_rngdrbg_dump_stats (void);
+ int  _gcry_rngdrbg_is_faked (void);
+diff -up libgcrypt-1.8.5/random/random.c.getrandom libgcrypt-1.8.5/random/random.c
+--- libgcrypt-1.8.5/random/random.c.getrandom	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/random/random.c	2020-04-20 14:55:34.876949605 +0200
+@@ -110,8 +110,8 @@ _gcry_random_read_conf (void)
+   unsigned int result = 0;
+ 
+   fp = fopen (fname, "r");
+-  if (!fp)
+-    return result;
++  if (!fp) /* We make only_urandom the default. */
++    return RANDOM_CONF_ONLY_URANDOM;
+ 
+   for (;;)
+     {
+@@ -228,6 +228,22 @@ _gcry_random_initialize (int full)
+ }
+ 
+ 
++/* Deinitialize this random subsystem. */
++void
++_gcry_random_deinit (void)
++{
++  if (fips_mode ())
++    _gcry_rngdrbg_deinit ();
++  else if (rng_types.standard)
++    _gcry_rngcsprng_deinit ();
++  else if (rng_types.fips)
++    _gcry_rngdrbg_deinit ();
++  else
++    _gcry_rngcsprng_deinit ();
++  /* not needed for system */
++}
++
++
+ /* If possible close file descriptors used by the RNG. */
+ void
+ _gcry_random_close_fds (void)
+diff -up libgcrypt-1.8.5/random/random-csprng.c.getrandom libgcrypt-1.8.5/random/random-csprng.c
+--- libgcrypt-1.8.5/random/random-csprng.c.getrandom	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/random/random-csprng.c	2020-04-20 15:04:27.182877975 +0200
+@@ -55,6 +55,10 @@
+ #ifdef __MINGW32__
+ #include <process.h>
+ #endif
++#if defined(__linux__) && defined(HAVE_SYSCALL)
++# include <sys/syscall.h>
++# include <linux/random.h>
++#endif
+ #include "g10lib.h"
+ #include "random.h"
+ #include "rand-internal.h"
+@@ -343,6 +347,21 @@ _gcry_rngcsprng_initialize (int full)
+ }
+ 
+ 
++void
++_gcry_rngcsprng_deinit (void)
++{
++  lock_pool();
++  pool_writepos = 0;
++  pool_readpos = 0;
++  pool_filled = 0;
++  pool_filled_counter = 0;
++  did_initial_extra_seeding = 0;
++  pool_balance = 0;
++  just_mixed = 0;
++  unlock_pool();
++}
++
++
+ /* Try to close the FDs of the random gather module.  This is
+    currently only implemented for rndlinux. */
+ void
+@@ -1116,6 +1135,22 @@ getfnc_gather_random (void))(void (*)(co
+              enum random_origins, size_t, int);
+ 
+ #if USE_RNDLINUX
++#if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom)
++  long ret;
++  char buffer[1];
++
++  _gcry_pre_syscall ();
++  ret = syscall (__NR_getrandom,
++                 (void*)buffer, (size_t)1, (unsigned int)GRND_NONBLOCK);
++  _gcry_post_syscall ();
++  if (ret != -1 || errno != ENOSYS)
++    {
++      fnc = _gcry_rndlinux_gather_random;
++      return fnc;
++    }
++  else
++          /* The syscall is not supported - fallback to /dev/urandom. */
++#endif
+   if ( !access (NAME_OF_DEV_RANDOM, R_OK)
+        && !access (NAME_OF_DEV_URANDOM, R_OK))
+     {
+diff -up libgcrypt-1.8.5/random/random-drbg.c.getrandom libgcrypt-1.8.5/random/random-drbg.c
+--- libgcrypt-1.8.5/random/random-drbg.c.getrandom	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/random/random-drbg.c	2020-04-20 15:02:37.782947902 +0200
+@@ -1811,6 +1811,22 @@ _gcry_rngdrbg_inititialize (int full)
+ }
+ 
+ /*
++ * Deinitialize the DRBG invoked by the libgcrypt API
++ * It will be automatically re-initialized on next call
++ */
++void
++_gcry_rngdrbg_deinit (void)
++{
++  drbg_lock ();
++  if (drbg_state)
++    {
++      drbg_uninstantiate (drbg_state);
++      drbg_state = NULL;
++    }
++  drbg_unlock ();
++}
++
++/*
+  * Backend handler function for GCRYCTL_DRBG_REINIT
+  *
+  * Select a different DRBG type and initialize it.
+diff -up libgcrypt-1.8.5/random/random.h.getrandom libgcrypt-1.8.5/random/random.h
+--- libgcrypt-1.8.5/random/random.h.getrandom	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/random/random.h	2020-04-20 14:55:34.877949586 +0200
+@@ -29,6 +29,7 @@ void _gcry_register_random_progress (voi
+ 
+ void _gcry_set_preferred_rng_type (int type);
+ void _gcry_random_initialize (int full);
++void _gcry_random_deinit (void);
+ void _gcry_random_close_fds (void);
+ int  _gcry_get_rng_type (int ignore_fips_mode);
+ void _gcry_random_dump_stats(void);
+diff -up libgcrypt-1.8.5/random/rndlinux.c.getrandom libgcrypt-1.8.5/random/rndlinux.c
+--- libgcrypt-1.8.5/random/rndlinux.c.getrandom	2020-04-20 15:01:50.159848963 +0200
++++ libgcrypt-1.8.5/random/rndlinux.c	2020-04-20 16:14:21.901610921 +0200
+@@ -35,6 +35,7 @@
+ #include <poll.h>
+ #if defined(__linux__) && defined(HAVE_SYSCALL)
+ # include <sys/syscall.h>
++# include <linux/random.h>
+ #endif
+ 
+ #include "types.h"
+@@ -147,12 +148,12 @@ _gcry_rndlinux_gather_random (void (*add
+   if (!add)
+     {
+       /* Special mode to close the descriptors.  */
+-      if (fd_random != -1)
++      if (fd_random >= 0)
+         {
+           close (fd_random);
+           fd_random = -1;
+         }
+-      if (fd_urandom != -1)
++      if (fd_urandom >= 0)
+         {
+           close (fd_urandom);
+           fd_urandom = -1;
+@@ -166,12 +167,12 @@ _gcry_rndlinux_gather_random (void (*add
+   apid = getpid ();
+   if (my_pid != apid)
+     {
+-      if (fd_random != -1)
++      if (fd_random >= 0)
+         {
+           close (fd_random);
+           fd_random = -1;
+         }
+-      if (fd_urandom != -1)
++      if (fd_urandom >= 0)
+         {
+           close (fd_urandom);
+           fd_urandom = -1;
+@@ -216,7 +217,23 @@ _gcry_rndlinux_gather_random (void (*add
+      that we always require the device to be existent but want a more
+      graceful behaviour if the rarely needed close operation has been
+      used and the device needs to be re-opened later. */
+-  if (level >= GCRY_VERY_STRONG_RANDOM && !only_urandom)
++#if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom)
++   if (fd_urandom != -2 && !_gcry_in_constructor ())
++     {
++       long ret;
++
++       _gcry_pre_syscall ();
++       ret = syscall (__NR_getrandom,
++                      (void*)buffer, (size_t)1, (unsigned int)GRND_NONBLOCK);
++       _gcry_post_syscall ();
++       if (ret > -1 || errno == EAGAIN || errno == EINTR)
++         {
++           fd_urandom = -2;
++           fd_random = -2;
++         }
++     }
++#endif
++  if (level >= GCRY_VERY_STRONG_RANDOM && !only_urandom && !_gcry_in_constructor ())
+     {
+       if (fd_random == -1)
+         {
+@@ -255,6 +272,7 @@ _gcry_rndlinux_gather_random (void (*add
+        * syscall and not a new device and thus we are not able to use
+        * select(2) to have a timeout. */
+ #if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom)
++      if (fd == -2)
+         {
+           long ret;
+           size_t nbytes;
+@@ -270,9 +288,7 @@ _gcry_rndlinux_gather_random (void (*add
+               _gcry_post_syscall ();
+             }
+           while (ret == -1 && errno == EINTR);
+-          if (ret == -1 && errno == ENOSYS)
+-            ; /* The syscall is not supported - fallback to pulling from fd.  */
+-          else
++          if (1)
+             { /* The syscall is supported.  Some sanity checks.  */
+               if (ret == -1)
+                 log_fatal ("unexpected error from getrandom: %s\n",
+diff -up libgcrypt-1.8.5/src/g10lib.h.getrandom libgcrypt-1.8.5/src/g10lib.h
+--- libgcrypt-1.8.5/src/g10lib.h.getrandom	2020-04-20 15:08:16.528538580 +0200
++++ libgcrypt-1.8.5/src/g10lib.h	2020-04-20 15:08:28.641309399 +0200
+@@ -464,6 +464,6 @@ gpg_err_code_t _gcry_fips_run_selftests
+ void _gcry_fips_noreturn (void);
+ #define fips_noreturn()  (_gcry_fips_noreturn ())
+ 
+-
++int _gcry_in_constructor (void);
+ 
+ #endif /* G10LIB_H */
+diff -up libgcrypt-1.8.5/src/global.c.getrandom libgcrypt-1.8.5/src/global.c
+--- libgcrypt-1.8.5/src/global.c.getrandom	2020-04-20 15:06:21.891707597 +0200
++++ libgcrypt-1.8.5/src/global.c	2020-04-20 15:07:29.018437509 +0200
+@@ -145,10 +145,18 @@ global_init (void)
+ #define FIPS_MODULE_PATH "/etc/system-fips"
+ #endif
+ 
++static int in_constructor = 0;
++
++int _gcry_in_constructor(void)
++{
++  return in_constructor;
++}
++
+ void __attribute__ ((constructor)) _gcry_global_constructor (void)
+ {
+   int rv;
+ 
++  in_constructor = 1;
+   rv = access (FIPS_MODULE_PATH, F_OK);
+   if (rv < 0 && errno != ENOENT)
+     rv = 0;
+@@ -163,10 +171,12 @@ void __attribute__ ((constructor)) _gcry
+       /* force selftests */
+       global_init();
+       _gcry_fips_run_selftests (0);
+-      if (!fips_mode())
+-         _gcry_random_close_fds ();
++      _gcry_random_close_fds ();
++      _gcry_random_deinit ();
+       no_secure_memory = no_secmem_save;
+     }
++
++  in_constructor = 0;
+ }
+ 
+ /* This function is called by the macro fips_is_operational and makes
diff --git a/SOURCES/libgcrypt-1.8.5-intel-cet.patch b/SOURCES/libgcrypt-1.8.5-intel-cet.patch
new file mode 100644
index 0000000..f58084e
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.5-intel-cet.patch
@@ -0,0 +1,348 @@
+diff -up libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S
+--- libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S	2020-01-23 15:36:44.148972045 +0100
+@@ -18,8 +18,9 @@
+  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#ifdef __x86_64
+ #include <config.h>
++
++#ifdef __x86_64
+ #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
+      defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \
+     defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT)
+diff -up libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S.intel-cet libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S
+--- libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S	2020-01-23 15:36:44.145972088 +0100
+@@ -18,8 +18,9 @@
+  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#ifdef __x86_64
+ #include <config.h>
++
++#ifdef __x86_64
+ #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
+      defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \
+     defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT)
+diff -up libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S
+--- libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S	2020-01-23 15:36:16.780250066 +0100
+@@ -48,6 +48,9 @@
+ .globl _gcry_chacha20_amd64_avx2_blocks
+ ELF(.type  _gcry_chacha20_amd64_avx2_blocks,@function;)
+ _gcry_chacha20_amd64_avx2_blocks:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lchacha_blocks_avx2_local:
+ 	vzeroupper
+ 	pushq %rbx
+diff -up libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S
+--- libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S	2020-01-23 15:36:16.783250095 +0100
+@@ -41,6 +41,9 @@
+ .globl _gcry_chacha20_amd64_sse2_blocks
+ ELF(.type  _gcry_chacha20_amd64_sse2_blocks,@function;)
+ _gcry_chacha20_amd64_sse2_blocks:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lchacha_blocks_sse2_local:
+ 	pushq %rbx
+ 	pushq %rbp
+diff -up libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S
+--- libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S	2020-01-23 15:36:16.784250105 +0100
+@@ -43,6 +43,9 @@
+ .globl _gcry_poly1305_amd64_avx2_init_ext
+ ELF(.type  _gcry_poly1305_amd64_avx2_init_ext,@function;)
+ _gcry_poly1305_amd64_avx2_init_ext:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lpoly1305_init_ext_avx2_local:
+ 	xor %edx, %edx
+ 	vzeroupper
+@@ -406,6 +409,9 @@ ELF(.size _gcry_poly1305_amd64_avx2_init
+ .globl _gcry_poly1305_amd64_avx2_blocks
+ ELF(.type  _gcry_poly1305_amd64_avx2_blocks,@function;)
+ _gcry_poly1305_amd64_avx2_blocks:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lpoly1305_blocks_avx2_local:
+ 	vzeroupper
+ 	pushq %rbp
+@@ -732,6 +738,9 @@ ELF(.size _gcry_poly1305_amd64_avx2_bloc
+ .globl _gcry_poly1305_amd64_avx2_finish_ext
+ ELF(.type  _gcry_poly1305_amd64_avx2_finish_ext,@function;)
+ _gcry_poly1305_amd64_avx2_finish_ext:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lpoly1305_finish_ext_avx2_local:
+ 	vzeroupper
+ 	pushq %rbp
+diff -up libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S
+--- libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S	2020-01-23 15:36:16.787250134 +0100
+@@ -42,6 +42,9 @@
+ .globl _gcry_poly1305_amd64_sse2_init_ext
+ ELF(.type  _gcry_poly1305_amd64_sse2_init_ext,@function;)
+ _gcry_poly1305_amd64_sse2_init_ext:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lpoly1305_init_ext_x86_local:
+ 	xor %edx, %edx
+ 	pushq %r12
+@@ -288,6 +291,9 @@ ELF(.size _gcry_poly1305_amd64_sse2_init
+ .globl _gcry_poly1305_amd64_sse2_finish_ext
+ ELF(.type  _gcry_poly1305_amd64_sse2_finish_ext,@function;)
+ _gcry_poly1305_amd64_sse2_finish_ext:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lpoly1305_finish_ext_x86_local:
+ 	pushq %rbp
+ 	movq %rsp, %rbp
+@@ -439,6 +445,9 @@ ELF(.size _gcry_poly1305_amd64_sse2_fini
+ .globl _gcry_poly1305_amd64_sse2_blocks
+ ELF(.type  _gcry_poly1305_amd64_sse2_blocks,@function;)
+ _gcry_poly1305_amd64_sse2_blocks:
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ .Lpoly1305_blocks_x86_local:
+ 	pushq %rbp
+ 	movq %rsp, %rbp
+diff -up libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S
+--- libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S	2020-01-23 15:36:44.151972003 +0100
+@@ -18,8 +18,9 @@
+  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#ifdef __x86_64
+ #include <config.h>
++
++#ifdef __x86_64
+ #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
+     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && defined(USE_SERPENT) && \
+     defined(ENABLE_AVX2_SUPPORT)
+diff -up libgcrypt-1.8.5/configure.ac.intel-cet libgcrypt-1.8.5/configure.ac
+--- libgcrypt-1.8.5/configure.ac.intel-cet	2019-08-29 15:00:08.000000000 +0200
++++ libgcrypt-1.8.5/configure.ac	2020-01-23 15:35:28.147774463 +0100
+@@ -95,6 +95,12 @@ AH_TOP([
+ AH_BOTTOM([
+ #define _GCRYPT_IN_LIBGCRYPT 1
+ 
++/* Add .note.gnu.property section for Intel CET in assembler sources
++   when CET is enabled.  */
++#if defined(__ASSEMBLER__) && defined(__CET__)
++# include <cet.h>
++#endif
++
+ /* If the configure check for endianness has been disabled, get it from
+    OS macros.  This is intended for making fat binary builds on OS X.  */
+ #ifdef DISABLED_ENDIAN_CHECK
+diff -up libgcrypt-1.8.5/mpi/config.links.intel-cet libgcrypt-1.8.5/mpi/config.links
+--- libgcrypt-1.8.5/mpi/config.links.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/mpi/config.links	2020-01-23 15:35:46.398952954 +0100
+@@ -382,6 +382,16 @@ if test x"$mpi_cpu_arch" = x ; then
+     mpi_cpu_arch="unknown"
+ fi
+ 
++# Add .note.gnu.property section for Intel CET in assembler sources
++# when CET is enabled.  */
++if test x"$mpi_cpu_arch" = xx86 ; then
++    cat <<EOF >> ./mpi/asm-syntax.h
++
++#if defined(__ASSEMBLER__) && defined(__CET__)
++# include <cet.h>
++#endif
++EOF
++fi
+ 
+ # Make sysdep.h
+ echo '/* created by config.links - do not edit */' >./mpi/sysdep.h
+diff -up libgcrypt-1.8.5/mpi/i386/mpih-add1.S.intel-cet libgcrypt-1.8.5/mpi/i386/mpih-add1.S
+--- libgcrypt-1.8.5/mpi/i386/mpih-add1.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/mpi/i386/mpih-add1.S	2020-01-23 15:37:40.470175379 +0100
+@@ -52,6 +52,10 @@ C_SYMBOL_NAME(_gcry_mpih_add_n:)
+ 	movl 20(%esp),%edx		/* s2_ptr */
+ 	movl 24(%esp),%ecx		/* size */
+ 
++#if defined __CET__ && (__CET__ & 1) != 0
++	pushl	%ebx
++#endif
++
+ 	movl	%ecx,%eax
+ 	shrl	$3,%ecx 		/* compute count for unrolled loop */
+ 	negl	%eax
+@@ -63,6 +67,9 @@ C_SYMBOL_NAME(_gcry_mpih_add_n:)
+ 	subl	%eax,%esi		/* ... by a constant when we ... */
+ 	subl	%eax,%edx		/* ... enter the loop */
+ 	shrl	$2,%eax 		/* restore previous value */
++#if defined __CET__ && (__CET__ & 1) != 0
++	leal	-4(,%eax,4),%ebx	/* Count for 4-byte endbr32 */
++#endif
+ #ifdef PIC
+ /* Calculate start address in loop for PIC.  Due to limitations in some
+    assemblers, Loop-L0-3 cannot be put into the leal */
+@@ -75,29 +82,53 @@ L0:	leal	(%eax,%eax,8),%eax
+ /* Calculate start address in loop for non-PIC.  */
+ 	leal	(Loop - 3)(%eax,%eax,8),%eax
+ #endif
++#if defined __CET__ && (__CET__ & 1) != 0
++	addl	%ebx,%eax		/* Adjust for endbr32 */
++#endif
+ 	jmp	*%eax			/* jump into loop */
+ 	ALIGN (3)
+ Loop:	movl	(%esi),%eax
+ 	adcl	(%edx),%eax
+ 	movl	%eax,(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	4(%esi),%eax
+ 	adcl	4(%edx),%eax
+ 	movl	%eax,4(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	8(%esi),%eax
+ 	adcl	8(%edx),%eax
+ 	movl	%eax,8(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	12(%esi),%eax
+ 	adcl	12(%edx),%eax
+ 	movl	%eax,12(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	16(%esi),%eax
+ 	adcl	16(%edx),%eax
+ 	movl	%eax,16(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	20(%esi),%eax
+ 	adcl	20(%edx),%eax
+ 	movl	%eax,20(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	24(%esi),%eax
+ 	adcl	24(%edx),%eax
+ 	movl	%eax,24(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	28(%esi),%eax
+ 	adcl	28(%edx),%eax
+ 	movl	%eax,28(%edi)
+@@ -110,6 +141,10 @@ Loop:	movl	(%esi),%eax
+ 	sbbl	%eax,%eax
+ 	negl	%eax
+ 
++#if defined __CET__ && (__CET__ & 1) != 0
++	popl	%ebx
++#endif
++
+ 	popl %esi
+ 	popl %edi
+ 	ret
+diff -up libgcrypt-1.8.5/mpi/i386/mpih-sub1.S.intel-cet libgcrypt-1.8.5/mpi/i386/mpih-sub1.S
+--- libgcrypt-1.8.5/mpi/i386/mpih-sub1.S.intel-cet	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/mpi/i386/mpih-sub1.S	2020-01-23 15:37:40.472175351 +0100
+@@ -53,6 +53,10 @@ C_SYMBOL_NAME(_gcry_mpih_sub_n:)
+ 	movl 20(%esp),%edx		/* s2_ptr */
+ 	movl 24(%esp),%ecx		/* size */
+ 
++#if defined __CET__ && (__CET__ & 1) != 0
++	pushl	%ebx
++#endif
++
+ 	movl	%ecx,%eax
+ 	shrl	$3,%ecx 		/* compute count for unrolled loop */
+ 	negl	%eax
+@@ -64,6 +68,9 @@ C_SYMBOL_NAME(_gcry_mpih_sub_n:)
+ 	subl	%eax,%esi		/* ... by a constant when we ... */
+ 	subl	%eax,%edx		/* ... enter the loop */
+ 	shrl	$2,%eax 		/* restore previous value */
++#if defined __CET__ && (__CET__ & 1) != 0
++	leal	-4(,%eax,4),%ebx	/* Count for 4-byte endbr32 */
++#endif
+ #ifdef PIC
+ /* Calculate start address in loop for PIC.  Due to limitations in some
+    assemblers, Loop-L0-3 cannot be put into the leal */
+@@ -76,29 +83,53 @@ L0:	leal	(%eax,%eax,8),%eax
+ /* Calculate start address in loop for non-PIC.  */
+ 	leal	(Loop - 3)(%eax,%eax,8),%eax
+ #endif
++#if defined __CET__ && (__CET__ & 1) != 0
++	addl	%ebx,%eax		/* Adjust for endbr32 */
++#endif
+ 	jmp	*%eax			/* jump into loop */
+ 	ALIGN (3)
+ Loop:	movl	(%esi),%eax
+ 	sbbl	(%edx),%eax
+ 	movl	%eax,(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	4(%esi),%eax
+ 	sbbl	4(%edx),%eax
+ 	movl	%eax,4(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	8(%esi),%eax
+ 	sbbl	8(%edx),%eax
+ 	movl	%eax,8(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	12(%esi),%eax
+ 	sbbl	12(%edx),%eax
+ 	movl	%eax,12(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	16(%esi),%eax
+ 	sbbl	16(%edx),%eax
+ 	movl	%eax,16(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	20(%esi),%eax
+ 	sbbl	20(%edx),%eax
+ 	movl	%eax,20(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	24(%esi),%eax
+ 	sbbl	24(%edx),%eax
+ 	movl	%eax,24(%edi)
++#ifdef _CET_ENDBR
++	_CET_ENDBR
++#endif
+ 	movl	28(%esi),%eax
+ 	sbbl	28(%edx),%eax
+ 	movl	%eax,28(%edi)
+@@ -111,6 +142,10 @@ Loop:	movl	(%esi),%eax
+ 	sbbl	%eax,%eax
+ 	negl	%eax
+ 
++#if defined __CET__ && (__CET__ & 1) != 0
++	popl	%ebx
++#endif
++
+ 	popl %esi
+ 	popl %edi
+ 	ret
diff --git a/SOURCES/libgcrypt-1.8.5-use-fipscheck.patch b/SOURCES/libgcrypt-1.8.5-use-fipscheck.patch
new file mode 100644
index 0000000..298ec4c
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.5-use-fipscheck.patch
@@ -0,0 +1,89 @@
+diff -up libgcrypt-1.8.5/src/fips.c.use-fipscheck libgcrypt-1.8.5/src/fips.c
+--- libgcrypt-1.8.5/src/fips.c.use-fipscheck	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/src/fips.c	2020-04-23 10:18:36.235764741 +0200
+@@ -581,23 +581,50 @@ run_random_selftests (void)
+   return !!err;
+ }
+ 
++#ifdef ENABLE_HMAC_BINARY_CHECK
++static int
++get_library_path(const char *libname, const char *symbolname, char *path, size_t pathlen)
++{
++    Dl_info info;
++    void *dl, *sym;
++    int rv = -1;
++
++        dl = dlopen(libname, RTLD_LAZY);
++        if (dl == NULL) {
++            return -1;
++        }       
++
++    sym = dlsym(dl, symbolname);
++
++    if (sym != NULL && dladdr(sym, &info)) {
++	strncpy(path, info.dli_fname, pathlen-1);
++	path[pathlen-1] = '\0';
++	rv = 0;
++    }
++
++    dlclose(dl);	
++    
++    return rv;
++}
++#endif
++
+ /* Run an integrity check on the binary.  Returns 0 on success.  */
+ static int
+ check_binary_integrity (void)
+ {
+ #ifdef ENABLE_HMAC_BINARY_CHECK
+   gpg_error_t err;
+-  Dl_info info;
++  char libpath[4096];
+   unsigned char digest[32];
+   int dlen;
+   char *fname = NULL;
+-  const char key[] = "What am I, a doctor or a moonshuttle conductor?";
+-
+-  if (!dladdr ("gcry_check_version", &info))
++  const char key[] = "orboDeJITITejsirpADONivirpUkvarP";
++  
++  if (get_library_path ("libgcrypt.so.20", "gcry_check_version", libpath, sizeof(libpath)))
+     err = gpg_error_from_syserror ();
+   else
+     {
+-      dlen = _gcry_hmac256_file (digest, sizeof digest, info.dli_fname,
++      dlen = _gcry_hmac256_file (digest, sizeof digest, libpath,
+                                  key, strlen (key));
+       if (dlen < 0)
+         err = gpg_error_from_syserror ();
+@@ -605,7 +632,7 @@ check_binary_integrity (void)
+         err = gpg_error (GPG_ERR_INTERNAL);
+       else
+         {
+-          fname = xtrymalloc (strlen (info.dli_fname) + 1 + 5 + 1 );
++          fname = xtrymalloc (strlen (libpath) + 1 + 5 + 1 );
+           if (!fname)
+             err = gpg_error_from_syserror ();
+           else
+@@ -614,7 +641,7 @@ check_binary_integrity (void)
+               char *p;
+ 
+               /* Prefix the basename with a dot.  */
+-              strcpy (fname, info.dli_fname);
++              strcpy (fname, libpath);
+               p = strrchr (fname, '/');
+               if (p)
+                 p++;
+diff -up libgcrypt-1.8.5/src/Makefile.am.use-fipscheck libgcrypt-1.8.5/src/Makefile.am
+--- libgcrypt-1.8.5/src/Makefile.am.use-fipscheck	2020-04-23 10:18:36.237764702 +0200
++++ libgcrypt-1.8.5/src/Makefile.am	2020-04-23 10:19:03.186247455 +0200
+@@ -125,7 +125,7 @@ libgcrypt_la_LIBADD = $(gcrypt_res) \
+ 	../cipher/libcipher.la \
+ 	../random/librandom.la \
+ 	../mpi/libmpi.la \
+-	../compat/libcompat.la  $(GPG_ERROR_LIBS)
++	../compat/libcompat.la  $(GPG_ERROR_LIBS) -ldl
+ 
+ 
+ dumpsexp_SOURCES = dumpsexp.c
diff --git a/SOURCES/random.conf b/SOURCES/random.conf
new file mode 100644
index 0000000..6041bcd
--- /dev/null
+++ b/SOURCES/random.conf
@@ -0,0 +1,4 @@
+# use only /dev/urandom - see https://www.2uo.de/myths-about-urandom/
+only-urandom
+# Keep jitter entropy generator enabled (should do no harm)
+#disable-jent
diff --git a/SOURCES/t-mpi-point.c b/SOURCES/t-mpi-point.c
new file mode 100644
index 0000000..b12a8ba
--- /dev/null
+++ b/SOURCES/t-mpi-point.c
@@ -0,0 +1,1225 @@
+/* t-mpi-point.c  - Tests for mpi point functions
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#define PGM "t-mpi-point"
+#include "t-common.h"
+
+static struct
+{
+  const char *desc;           /* Description of the curve.  */
+  const char *p;              /* Order of the prime field.  */
+  const char *a, *b;          /* The coefficients. */
+  const char *n;              /* The order of the base point.  */
+  const char *g_x, *g_y;      /* Base point.  */
+  const char *h;              /* Cofactor.  */
+} test_curve[] =
+  {
+    {
+      "NIST P-224",
+      "0xffffffffffffffffffffffffffffffff000000000000000000000001",
+      "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe",
+      "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+      "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" ,
+
+      "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+      "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
+      "0x01"
+    },
+    {
+      "NIST P-256",
+      "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff",
+      "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc",
+      "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+      "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
+
+      "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+      "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
+      "0x01"
+    },
+    {
+      "NIST P-384",
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000ffffffff",
+      "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
+      "ffffffff0000000000000000fffffffc",
+      "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a"
+      "c656398d8a2ed19d2a85c8edd3ec2aef",
+      "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf"
+      "581a0db248b0a77aecec196accc52973",
+
+      "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38"
+      "5502f25dbf55296c3a545e3872760ab7",
+      "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0"
+      "0a60b1ce1d7e819d7a431d7c90ea0e5f",
+      "0x01"
+    },
+    {
+      "NIST P-521",
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+      "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc",
+      "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10"
+      "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
+      "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+
+      "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d"
+      "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+      "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6"
+      "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650",
+      "0x01"
+    },
+    {
+      "Ed25519",
+      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+      "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC",
+      "0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3",
+      "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
+      "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A",
+      "0x6666666666666666666666666666666666666666666666666666666666666658",
+      "0x08"
+    },
+    { NULL, NULL, NULL, NULL, NULL, NULL }
+  };
+
+/* A sample public key for NIST P-256.  */
+static const char sample_p256_q[] =
+  "04"
+  "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E"
+  "E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E";
+static const char sample_p256_q_x[] =
+  "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E";
+static const char sample_p256_q_y[] =
+  "00E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E";
+
+
+/* A sample public key for Ed25519.  */
+static const char sample_ed25519_q[] =
+  "04"
+  "55d0e09a2b9d34292297e08d60d0f620c513d47253187c24b12786bd777645ce"
+  "1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7";
+static const char sample_ed25519_q_x[] =
+  "55d0e09a2b9d34292297e08d60d0f620c513d47253187c24b12786bd777645ce";
+static const char sample_ed25519_q_y[] =
+  "1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7";
+static const char sample_ed25519_q_eddsa[] =
+  "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
+static const char sample_ed25519_d[] =
+  "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60";
+
+
+static void
+print_mpi_2 (const char *text, const char *text2, gcry_mpi_t a)
+{
+  gcry_error_t err;
+  char *buf;
+  void *bufaddr = &buf;
+
+  err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
+  if (err)
+    fprintf (stderr, "%s%s: [error printing number: %s]\n",
+             text, text2? text2:"", gpg_strerror (err));
+  else
+    {
+      fprintf (stderr, "%s%s: %s\n", text, text2? text2:"", buf);
+      gcry_free (buf);
+    }
+}
+
+
+static void
+print_mpi (const char *text, gcry_mpi_t a)
+{
+  print_mpi_2 (text, NULL, a);
+}
+
+
+static void
+print_point (const char *text, gcry_mpi_point_t a)
+{
+  gcry_mpi_t x, y, z;
+
+  x = gcry_mpi_new (0);
+  y = gcry_mpi_new (0);
+  z = gcry_mpi_new (0);
+  gcry_mpi_point_get (x, y, z, a);
+  print_mpi_2 (text, ".x", x);
+  print_mpi_2 (text, ".y", y);
+  print_mpi_2 (text, ".z", z);
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  gcry_mpi_release (z);
+}
+
+
+static void
+print_sexp (const char *prefix, gcry_sexp_t a)
+{
+  char *buf;
+  size_t size;
+
+  if (prefix)
+    fputs (prefix, stderr);
+  size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+  buf = gcry_xmalloc (size);
+
+  gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+  fprintf (stderr, "%.*s", (int)size, buf);
+  gcry_free (buf);
+}
+
+
+static gcry_mpi_t
+hex2mpi (const char *string)
+{
+  gpg_error_t err;
+  gcry_mpi_t val;
+
+  err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+  if (err)
+    die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err));
+  return val;
+}
+
+
+/* Convert STRING consisting of hex characters into its binary
+   representation and return it as an allocated buffer. The valid
+   length of the buffer is returned at R_LENGTH.  The string is
+   delimited by end of string.  The function returns NULL on
+   error.  */
+static void *
+hex2buffer (const char *string, size_t *r_length)
+{
+  const char *s;
+  unsigned char *buffer;
+  size_t length;
+
+  buffer = xmalloc (strlen(string)/2+1);
+  length = 0;
+  for (s=string; *s; s +=2 )
+    {
+      if (!hexdigitp (s) || !hexdigitp (s+1))
+        return NULL;           /* Invalid hex digits. */
+      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = length;
+  return buffer;
+}
+
+
+static gcry_mpi_t
+hex2mpiopa (const char *string)
+{
+  char *buffer;
+  size_t buflen;
+  gcry_mpi_t val;
+
+  buffer = hex2buffer (string, &buflen);
+  if (!buffer)
+    die ("hex2mpiopa '%s' failed: parser error\n", string);
+  val = gcry_mpi_set_opaque (NULL, buffer, buflen*8);
+  if (!buffer)
+    die ("hex2mpiopa '%s' failed: set_opaque error\n", string);
+  return val;
+}
+
+
+/* Compare A to B, where B is given as a hex string.  */
+static int
+cmp_mpihex (gcry_mpi_t a, const char *b)
+{
+  gcry_mpi_t bval;
+  int res;
+
+  if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    bval = hex2mpiopa (b);
+  else
+    bval = hex2mpi (b);
+  res = gcry_mpi_cmp (a, bval);
+  gcry_mpi_release (bval);
+  return res;
+}
+
+
+/* Wrapper to emulate the libgcrypt internal EC context allocation
+   function.  */
+static gpg_error_t
+ec_p_new (gcry_ctx_t *r_ctx, gcry_mpi_t p, gcry_mpi_t a)
+{
+  gpg_error_t err;
+  gcry_sexp_t sexp;
+
+  if (p && a)
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m)(a %m))", p, a);
+  else if (p)
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m))", p);
+  else if (a)
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa (a %m))", a);
+  else
+    err = gcry_sexp_build (&sexp, NULL, "(ecdsa)");
+  if (err)
+    return err;
+  err = gcry_mpi_ec_new (r_ctx, sexp, NULL);
+  gcry_sexp_release (sexp);
+  return err;
+}
+
+
+
+static void
+set_get_point (void)
+{
+  gcry_mpi_point_t point, point2;
+  gcry_mpi_t x, y, z;
+
+  wherestr = "set_get_point";
+  info ("checking point setting functions\n");
+
+  point = gcry_mpi_point_new (0);
+  x = gcry_mpi_set_ui (NULL, 17);
+  y = gcry_mpi_set_ui (NULL, 42);
+  z = gcry_mpi_set_ui (NULL, 11371);
+  gcry_mpi_point_get (x, y, z, point);
+  if (gcry_mpi_cmp_ui (x, 0)
+      || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0))
+    fail ("new point not initialized to (0,0,0)\n");
+  gcry_mpi_point_snatch_get (x, y, z, point);
+  point = NULL;
+  if (gcry_mpi_cmp_ui (x, 0)
+      || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0))
+    fail ("snatch_get failed\n");
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  gcry_mpi_release (z);
+
+  point = gcry_mpi_point_new (0);
+  x = gcry_mpi_set_ui (NULL, 17);
+  y = gcry_mpi_set_ui (NULL, 42);
+  z = gcry_mpi_set_ui (NULL, 11371);
+  gcry_mpi_point_set (point, x, y, z);
+  gcry_mpi_set_ui (x, 23);
+  gcry_mpi_set_ui (y, 24);
+  gcry_mpi_set_ui (z, 25);
+  gcry_mpi_point_get (x, y, z, point);
+  if (gcry_mpi_cmp_ui (x, 17)
+      || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
+    fail ("point_set/point_get failed\n");
+  gcry_mpi_point_snatch_set (point, x, y, z);
+  x = gcry_mpi_new (0);
+  y = gcry_mpi_new (0);
+  z = gcry_mpi_new (0);
+  gcry_mpi_point_get (x, y, z, point);
+  if (gcry_mpi_cmp_ui (x, 17)
+      || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
+    fail ("point_snatch_set/point_get failed\n");
+
+  point2 = gcry_mpi_point_copy (point);
+
+  gcry_mpi_point_get (x, y, z, point2);
+  if (gcry_mpi_cmp_ui (x, 17)
+      || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
+    fail ("point_copy failed (1)\n");
+
+  gcry_mpi_point_release (point);
+
+  gcry_mpi_point_get (x, y, z, point2);
+  if (gcry_mpi_cmp_ui (x, 17)
+      || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371))
+    fail ("point_copy failed (2)\n");
+
+  gcry_mpi_point_release (point2);
+
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  gcry_mpi_release (z);
+}
+
+
+static void
+context_alloc (void)
+{
+  gpg_error_t err;
+  gcry_ctx_t ctx;
+  gcry_mpi_t p, a;
+
+  wherestr = "context_alloc";
+  info ("checking context functions\n");
+
+  p = gcry_mpi_set_ui (NULL, 1);
+  a = gcry_mpi_set_ui (NULL, 1);
+  err = ec_p_new (&ctx, p, a);
+  if (err)
+    die ("ec_p_new returned an error: %s\n", gpg_strerror (err));
+  gcry_mpi_release (p);
+  gcry_mpi_release (a);
+  gcry_ctx_release (ctx);
+
+  p = NULL;
+  a = gcry_mpi_set_ui (NULL, 0);
+
+  err = ec_p_new (&ctx, p, a);
+  if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
+    fail ("ec_p_new: bad parameter detection failed (1)\n");
+
+  gcry_mpi_release (a);
+  a = NULL;
+  err = ec_p_new (&ctx, p, a);
+  if (!err || gpg_err_code (err) != GPG_ERR_EINVAL)
+    fail ("ec_p_new: bad parameter detection failed (2)\n");
+
+}
+
+
+static int
+get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc,
+                 gcry_ctx_t ctx)
+{
+  gcry_mpi_t mpi;
+
+  mpi = gcry_mpi_ec_get_mpi (name, ctx, 1);
+  if (!mpi)
+    {
+      fail ("error getting parameter '%s' of curve '%s'\n", name, desc);
+      return 1;
+    }
+  if (debug)
+    print_mpi (name, mpi);
+  if (cmp_mpihex (mpi, mpistring))
+    {
+      fail ("parameter '%s' of curve '%s' does not match\n", name, desc);
+      gcry_mpi_release (mpi);
+      return 1;
+    }
+  gcry_mpi_release (mpi);
+  return 0;
+}
+
+
+static int
+get_and_cmp_point (const char *name,
+                   const char *mpi_x_string, const char *mpi_y_string,
+                   const char *desc, gcry_ctx_t ctx)
+{
+  gcry_mpi_point_t point;
+  gcry_mpi_t x, y, z;
+  int result = 0;
+
+  point = gcry_mpi_ec_get_point (name, ctx, 1);
+  if (!point)
+    {
+      fail ("error getting point parameter '%s' of curve '%s'\n", name, desc);
+      return 1;
+    }
+  if (debug)
+    print_point (name, point);
+
+  x = gcry_mpi_new (0);
+  y = gcry_mpi_new (0);
+  z = gcry_mpi_new (0);
+  gcry_mpi_point_snatch_get (x, y, z, point);
+  if (cmp_mpihex (x, mpi_x_string))
+    {
+      fail ("x coordinate of '%s' of curve '%s' does not match\n", name, desc);
+      result = 1;
+    }
+  if (cmp_mpihex (y, mpi_y_string))
+    {
+      fail ("y coordinate of '%s' of curve '%s' does not match\n", name, desc);
+      result = 1;
+    }
+  if (cmp_mpihex (z, "01"))
+    {
+      fail ("z coordinate of '%s' of curve '%s' is not 1\n", name, desc);
+      result = 1;
+    }
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  gcry_mpi_release (z);
+  return result;
+}
+
+
+static void
+context_param (void)
+{
+  gpg_error_t err;
+  int idx;
+  gcry_ctx_t ctx = NULL;
+  gcry_mpi_t q, d;
+  gcry_sexp_t keyparam;
+
+  wherestr = "context_param";
+
+  info ("checking standard curves\n");
+  for (idx=0; test_curve[idx].desc; idx++)
+    {
+      /* P-192 and Ed25519 are not supported in fips mode */
+      if (gcry_fips_mode_active())
+        {
+          if (!strcmp(test_curve[idx].desc, "NIST P-192")
+              || !strcmp(test_curve[idx].desc, "Ed25519"))
+            {
+	      info ("skipping %s in fips mode\n", test_curve[idx].desc );
+              continue;
+            }
+        }
+
+      gcry_ctx_release (ctx);
+      err = gcry_mpi_ec_new (&ctx, NULL, test_curve[idx].desc);
+      if (err)
+        {
+          fail ("can't create context for curve '%s': %s\n",
+                test_curve[idx].desc, gpg_strerror (err));
+          continue;
+        }
+      if (get_and_cmp_mpi ("p", test_curve[idx].p, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_mpi ("a", test_curve[idx].a, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_mpi ("b", test_curve[idx].b, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_mpi ("g.x",test_curve[idx].g_x, test_curve[idx].desc,ctx))
+        continue;
+      if (get_and_cmp_mpi ("g.y",test_curve[idx].g_y, test_curve[idx].desc,ctx))
+        continue;
+      if (get_and_cmp_mpi ("n", test_curve[idx].n, test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_point ("g", test_curve[idx].g_x, test_curve[idx].g_y,
+                             test_curve[idx].desc, ctx))
+        continue;
+      if (get_and_cmp_mpi ("h", test_curve[idx].h, test_curve[idx].desc, ctx))
+        continue;
+
+    }
+
+  info ("checking sample public key (nistp256)\n");
+  q = hex2mpi (sample_p256_q);
+  err = gcry_sexp_build (&keyparam, NULL,
+                        "(public-key(ecc(curve %s)(q %m)))",
+                        "NIST P-256", q);
+  if (err)
+    die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
+  gcry_mpi_release (q);
+
+  /* We can't call gcry_pk_testkey because it is only implemented for
+     private keys.  */
+  /* err = gcry_pk_testkey (keyparam); */
+  /* if (err) */
+  /*   fail ("gcry_pk_testkey failed for sample public key: %s\n", */
+  /*         gpg_strerror (err)); */
+
+  gcry_ctx_release (ctx);
+  err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
+  if (err)
+    fail ("gcry_mpi_ec_new failed for sample public key (nistp256): %s\n",
+          gpg_strerror (err));
+  else
+    {
+      gcry_sexp_t sexp;
+
+      get_and_cmp_mpi ("q", sample_p256_q, "nistp256", ctx);
+      get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "nistp256",
+                         ctx);
+
+      /* Delete Q.  */
+      err = gcry_mpi_ec_set_mpi ("q", NULL, ctx);
+      if (err)
+        fail ("clearing Q for nistp256 failed: %s\n", gpg_strerror (err));
+      if (gcry_mpi_ec_get_mpi ("q", ctx, 0))
+        fail ("clearing Q for nistp256 did not work\n");
+
+      /* Set Q again.  */
+      q = hex2mpi (sample_p256_q);
+      err = gcry_mpi_ec_set_mpi ("q", q, ctx);
+      if (err)
+        fail ("setting Q for nistp256 failed: %s\n", gpg_strerror (err));
+      get_and_cmp_mpi ("q", sample_p256_q, "nistp256(2)", ctx);
+      gcry_mpi_release (q);
+
+      /* Get as s-expression.  */
+      err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
+      if (err)
+        fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
+      else if (debug)
+        print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
+      gcry_sexp_release (sexp);
+
+      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx);
+      if (err)
+        fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n",
+              gpg_strerror (err));
+      else if (debug)
+        print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
+      gcry_sexp_release (sexp);
+
+      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx);
+      if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
+        fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n",
+              gpg_strerror (err));
+      gcry_sexp_release (sexp);
+    }
+
+  /* Skipping Ed25519 if in FIPS mode (it isn't supported) */
+  if (gcry_fips_mode_active())
+    goto cleanup;
+
+  info ("checking sample public key (Ed25519)\n");
+  q = hex2mpi (sample_ed25519_q);
+  gcry_sexp_release (keyparam);
+  err = gcry_sexp_build (&keyparam, NULL,
+                        "(public-key(ecc(curve %s)(flags eddsa)(q %m)))",
+                        "Ed25519", q);
+  if (err)
+    die ("gcry_sexp_build failed: %s\n", gpg_strerror (err));
+  gcry_mpi_release (q);
+
+  /* We can't call gcry_pk_testkey because it is only implemented for
+     private keys.  */
+  /* err = gcry_pk_testkey (keyparam); */
+  /* if (err) */
+  /*   fail ("gcry_pk_testkey failed for sample public key: %s\n", */
+  /*         gpg_strerror (err)); */
+
+  gcry_ctx_release (ctx);
+  err = gcry_mpi_ec_new (&ctx, keyparam, NULL);
+  if (err)
+    fail ("gcry_mpi_ec_new failed for sample public key: %s\n",
+          gpg_strerror (err));
+  else
+    {
+      gcry_sexp_t sexp;
+
+      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519", ctx);
+      get_and_cmp_point ("q", sample_ed25519_q_x, sample_ed25519_q_y,
+                         "Ed25519", ctx);
+      get_and_cmp_mpi ("q@eddsa", sample_ed25519_q_eddsa, "Ed25519", ctx);
+
+      /* Set d to see whether Q is correctly re-computed.  */
+      d = hex2mpi (sample_ed25519_d);
+      err = gcry_mpi_ec_set_mpi ("d", d, ctx);
+      if (err)
+        fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err));
+      gcry_mpi_release (d);
+      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(recompute Q)", ctx);
+
+      /* Delete Q by setting d and then clearing d.  The clearing is
+         required so that we can check whether Q has been cleared and
+         because further tests only expect a public key.  */
+      d = hex2mpi (sample_ed25519_d);
+      err = gcry_mpi_ec_set_mpi ("d", d, ctx);
+      if (err)
+        fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err));
+      gcry_mpi_release (d);
+      err = gcry_mpi_ec_set_mpi ("d", NULL, ctx);
+      if (err)
+        fail ("setting d for Ed25519 failed(2): %s\n", gpg_strerror (err));
+      if (gcry_mpi_ec_get_mpi ("q", ctx, 0))
+        fail ("setting d for Ed25519 did not reset Q\n");
+
+      /* Set Q again.  We need to use an opaque MPI here because
+         sample_ed25519_q is in uncompressed format which can only be
+         auto-detected if passed opaque.  */
+      q = hex2mpiopa (sample_ed25519_q);
+      err = gcry_mpi_ec_set_mpi ("q", q, ctx);
+      if (err)
+        fail ("setting Q for Ed25519 failed: %s\n", gpg_strerror (err));
+      gcry_mpi_release (q);
+      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(2)", ctx);
+
+      /* Get as s-expression.  */
+      err = gcry_pubkey_get_sexp (&sexp, 0, ctx);
+      if (err)
+        fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err));
+      else if (debug)
+        print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp);
+      gcry_sexp_release (sexp);
+
+      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx);
+      if (err)
+        fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n",
+              gpg_strerror (err));
+      else if (debug)
+        print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp);
+      gcry_sexp_release (sexp);
+
+      err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx);
+      if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
+        fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n",
+              gpg_strerror (err));
+      gcry_sexp_release (sexp);
+
+    }
+
+ cleanup:
+  gcry_ctx_release (ctx);
+  gcry_sexp_release (keyparam);
+}
+
+
+
+
+/* Create a new point from (X,Y,Z) given as hex strings.  */
+gcry_mpi_point_t
+make_point (const char *x, const char *y, const char *z)
+{
+  gcry_mpi_point_t point;
+
+  point = gcry_mpi_point_new (0);
+  gcry_mpi_point_snatch_set (point, hex2mpi (x), hex2mpi (y), hex2mpi (z));
+
+  return point;
+}
+
+
+/* This tests checks that the low-level EC API yields the same result
+   as using the high level API.  The values have been taken from a
+   test run using the high level API.  */
+static void
+basic_ec_math (void)
+{
+  gpg_error_t err;
+  gcry_ctx_t ctx;
+  gcry_mpi_t P, A;
+  gcry_mpi_point_t G, Q;
+  gcry_mpi_t d;
+  gcry_mpi_t x, y, z;
+
+  wherestr = "basic_ec_math";
+  info ("checking basic math functions for EC\n");
+
+  P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff");
+  A = hex2mpi ("0xfffffffffffffffffffffffffffffffefffffffffffffffc");
+  G = make_point ("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
+                  "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+                  "1");
+  d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D");
+  Q = gcry_mpi_point_new (0);
+
+  err = ec_p_new (&ctx, P, A);
+  if (err)
+    die ("ec_p_new failed: %s\n", gpg_strerror (err));
+
+  x = gcry_mpi_new (0);
+  y = gcry_mpi_new (0);
+  z = gcry_mpi_new (0);
+
+  {
+    /* A quick check that multiply by zero works.  */
+    gcry_mpi_t tmp;
+
+    tmp = gcry_mpi_new (0);
+    gcry_mpi_ec_mul (Q, tmp, G, ctx);
+    gcry_mpi_release (tmp);
+    gcry_mpi_point_get (x, y, z, Q);
+    if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 0)
+        || gcry_mpi_cmp_ui (z, 0))
+      fail ("multiply a point by zero failed\n");
+  }
+
+  gcry_mpi_ec_mul (Q, d, G, ctx);
+  gcry_mpi_point_get (x, y, z, Q);
+  if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66")
+      || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8")
+      || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F"))
+    fail ("computed public key does not match\n");
+  if (debug)
+    {
+      print_mpi ("Q.x", x);
+      print_mpi ("Q.y", y);
+      print_mpi ("Q.z", z);
+    }
+
+  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
+    fail ("failed to get affine coordinates\n");
+  if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE")
+      || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966"))
+    fail ("computed affine coordinates of public key do not match\n");
+  if (debug)
+    {
+      print_mpi ("q.x", x);
+      print_mpi ("q.y", y);
+    }
+
+  gcry_mpi_release (z);
+  gcry_mpi_release (y);
+  gcry_mpi_release (x);
+  gcry_mpi_point_release (Q);
+  gcry_mpi_release (d);
+  gcry_mpi_point_release (G);
+  gcry_mpi_release (A);
+  gcry_mpi_release (P);
+  gcry_ctx_release (ctx);
+}
+
+
+/* This is the same as basic_ec_math but uses more advanced
+   features.  */
+static void
+basic_ec_math_simplified (void)
+{
+}
+
+
+/* Check the math used with Twisted Edwards curves.  */
+static void
+twistededwards_math (void)
+{
+  gpg_error_t err;
+  gcry_ctx_t ctx;
+  gcry_mpi_point_t G, Q;
+  gcry_mpi_t k;
+  gcry_mpi_t w, a, x, y, z, p, n, b, I;
+
+  wherestr = "twistededwards_math";
+  info ("checking basic Twisted Edwards math\n");
+
+  err = gcry_mpi_ec_new (&ctx, NULL, "Ed25519");
+  if (err)
+    die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err));
+
+  k = hex2mpi
+    ("2D3501E723239632802454EE5DDC406EFB0BDF18486A5BDE9C0390A9C2984004"
+     "F47252B628C953625B8DEB5DBCB8DA97AA43A1892D11FA83596F42E0D89CB1B6");
+  G = gcry_mpi_ec_get_point ("g", ctx, 1);
+  if (!G)
+    die ("gcry_mpi_ec_get_point(G) failed\n");
+  Q = gcry_mpi_point_new (0);
+
+
+  w = gcry_mpi_new (0);
+  a = gcry_mpi_new (0);
+  x = gcry_mpi_new (0);
+  y = gcry_mpi_new (0);
+  z = gcry_mpi_new (0);
+  I = gcry_mpi_new (0);
+  p = gcry_mpi_ec_get_mpi ("p", ctx, 1);
+  n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
+  b = gcry_mpi_ec_get_mpi ("b", ctx, 1);
+
+  /* Check: 2^{p-1} mod p == 1 */
+  gcry_mpi_sub_ui (a, p, 1);
+  gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, p);
+  if (gcry_mpi_cmp_ui (w, 1))
+    fail ("failed assertion: 2^{p-1} mod p == 1\n");
+
+  /* Check: p % 4 == 1 */
+  gcry_mpi_mod (w, p, GCRYMPI_CONST_FOUR);
+  if (gcry_mpi_cmp_ui (w, 1))
+    fail ("failed assertion: p %% 4 == 1\n");
+
+  /* Check: 2^{n-1} mod n == 1 */
+  gcry_mpi_sub_ui (a, n, 1);
+  gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, n);
+  if (gcry_mpi_cmp_ui (w, 1))
+    fail ("failed assertion: 2^{n-1} mod n == 1\n");
+
+  /* Check: b^{(p-1)/2} mod p == p-1 */
+  gcry_mpi_sub_ui (a, p, 1);
+  gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_TWO, -1);
+  gcry_mpi_powm (w, b, x, p);
+  gcry_mpi_abs (w);
+  if (gcry_mpi_cmp (w, a))
+    fail ("failed assertion: b^{(p-1)/2} mod p == p-1\n");
+
+  /* I := 2^{(p-1)/4} mod p */
+  gcry_mpi_sub_ui (a, p, 1);
+  gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_FOUR, -1);
+  gcry_mpi_powm (I, GCRYMPI_CONST_TWO, x, p);
+
+  /* Check: I^2 mod p == p-1 */
+  gcry_mpi_powm (w, I, GCRYMPI_CONST_TWO, p);
+  if (gcry_mpi_cmp (w, a))
+    fail ("failed assertion: I^2 mod p == p-1\n");
+
+  /* Check: G is on the curve */
+  if (!gcry_mpi_ec_curve_point (G, ctx))
+    fail ("failed assertion: G is on the curve\n");
+
+  /* Check: nG == (0,1) */
+  gcry_mpi_ec_mul (Q, n, G, ctx);
+  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
+    fail ("failed to get affine coordinates\n");
+  if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 1))
+    fail ("failed assertion: nG == (0,1)\n");
+
+  /* Now two arbitrary point operations taken from the ed25519.py
+     sample data.  */
+  gcry_mpi_release (a);
+  a = hex2mpi
+    ("4f71d012df3c371af3ea4dc38385ca5bb7272f90cb1b008b3ed601c76de1d496"
+     "e30cbf625f0a756a678d8f256d5325595cccc83466f36db18f0178eb9925edd3");
+  gcry_mpi_ec_mul (Q, a, G, ctx);
+  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
+    fail ("failed to get affine coordinates\n");
+  if (cmp_mpihex (x, ("157f7361c577aad36f67ed33e38dc7be"
+                      "00014fecc2165ca5cee9eee19fe4d2c1"))
+      || cmp_mpihex (y, ("5a69dbeb232276b38f3f5016547bb2a2"
+                         "4025645f0b820e72b8cad4f0a909a092")))
+    {
+      fail ("sample point multiply failed:\n");
+      print_mpi ("r", a);
+      print_mpi ("Rx", x);
+      print_mpi ("Ry", y);
+    }
+
+  gcry_mpi_release (a);
+  a = hex2mpi
+    ("2d3501e723239632802454ee5ddc406efb0bdf18486a5bde9c0390a9c2984004"
+     "f47252b628c953625b8deb5dbcb8da97aa43a1892d11fa83596f42e0d89cb1b6");
+  gcry_mpi_ec_mul (Q, a, G, ctx);
+  if (gcry_mpi_ec_get_affine (x, y, Q, ctx))
+    fail ("failed to get affine coordinates\n");
+  if (cmp_mpihex (x, ("6218e309d40065fcc338b3127f468371"
+                      "82324bd01ce6f3cf81ab44e62959c82a"))
+      || cmp_mpihex (y, ("5501492265e073d874d9e5b81e7f8784"
+                         "8a826e80cce2869072ac60c3004356e5")))
+    {
+      fail ("sample point multiply failed:\n");
+      print_mpi ("r", a);
+      print_mpi ("Rx", x);
+      print_mpi ("Ry", y);
+    }
+
+
+  gcry_mpi_release (I);
+  gcry_mpi_release (b);
+  gcry_mpi_release (n);
+  gcry_mpi_release (p);
+  gcry_mpi_release (w);
+  gcry_mpi_release (a);
+  gcry_mpi_release (x);
+  gcry_mpi_release (y);
+  gcry_mpi_release (z);
+  gcry_mpi_point_release (Q);
+  gcry_mpi_point_release (G);
+  gcry_mpi_release (k);
+  gcry_ctx_release (ctx);
+}
+
+
+/* Check the point on curve function.  */
+static void
+point_on_curve (void)
+{
+  static struct {
+    const char *curve;
+    int oncurve;      /* Point below is on the curve.  */
+    const char *qx;
+    const char *qy;
+  } t[] = {
+    {
+      "NIST P-256", 0,
+      "015B4F6775D68D4D2E2192C6B8027FC5A3D49957E453CB251155AA3FF5D3EC9974",
+      "4BC4C87B57A25E1056831208AB5B8F091142F891E9FF19F1E090B030DF1087B3"
+    }, {
+      "NIST P-256", 0,
+      "D22C316E7EBE7B293BD66808E000806F0754398A5D72A4F9BBC21C26EAC0A651",
+      "3C8DB80CC3CDE5E530D040536E6A58AAB41C33FA70B30896943513FF3690132D"
+    }, {
+      "NIST P-256", 0,
+      "0130F7E7BC52854CA493A0DE87DC4AB3B4343758F2B634F15B10D70DBC0A5A5291",
+      "86F9CA73C25CE86D54CB21C181AECBB52A5971334FF5040F76CAE9845ED46023"
+    }, {
+      "NIST P-256", 1,
+      "14957B602C7849F28858C7407696F014BC091D6D68C449560B7A38147D6E6A9B",
+      "A8E09EFEECFE00C797A0848F38B61992D30C61FAB13021E88C8BD3545B3A6C63"
+    }, {
+      "NIST P-256", 0,
+      "923DE4957241DD97780841C76294DB0D4F5DC04C3045081174764D2D32AD2D53",
+      "01B4B1A2027C02F0F520A3B01E4CE3C668BF481346A74499C5D1044A53E210B600"
+    }, {
+      "NIST P-256", 1,
+      "9021DFAB8B4DAEAADA634AAA26D6E5FFDF8C0476FF5CA31606C870A1B933FB36",
+      "9AFC65EEB24E46C7B75712EF29A981CB09FAC56E2B81D3ED024748CCAB1CB77E"
+    }, {
+      "NIST P-256", 0,
+      "011529F0B26DE5E0EB2DA4BFB6C149C802CB52EE479DD666553286928A4005E990",
+      "0EBC63DB2104884456DC0AA81A3F4E99D93B7AE2CD4B1489655EA9BE6289CF9E"
+    }, {
+      "NIST P-256", 1,
+      "216EC5DE8CA989199D31F0DFCD381DCC9270A0785365EC3E34CA347C070A87BE",
+      "87A88897BA763509ECC1DBE28D9D37F6F4E70E3B99B1CD3C0B934D4190968A6D"
+    }, {
+      "NIST P-256", 1,
+      "7ABAA44ACBC6016FDB52A6F45F6178E65CBFC35F9920D99149CA9999612CE945",
+      "88F7684BDCDA31EAFB6CAD859F8AB29B5D921D7DB2B34DF7E40CE36235F45B63"
+    }, {
+      "NIST P-256", 0,
+      "E765B4272D211DD0064189B55421FB76BB3A7756364A6CB1627FAED848157A84",
+      "C13171CFFB243E06B203F0996BBDD16F52292AD11F2DA81106E9C2FD87F4FA0F"
+    }, {
+      "NIST P-256", 0,
+      "EE4999DFC3A1871EE7A592BE26A09BEC9D9B561613EE9EFB6ED42F17985C9CDC",
+      "8399E967338A7A618336AF70DA67D9CAC1C19267809652F5C5183C8B129E0902"
+    }, {
+      "NIST P-256", 0,
+      "F755D0CF2642A2C7FBACCC8E9E442B8B047A99C6E052B2FA5AB0544B36B4D51C",
+      "AA080F17657B6565D9A4D94BD260B54D92FEE8DC4A78C4FC9C19209933AF39B0"
+    } , {
+      "NIST P-384", 0,
+      "CBFC7DBEBF15BEAD682549757F9BBA0E3F67669DF13FCE0EBE8024B725B38B00"
+      "83EC46A8F2FF3203C5C7F8C7E722A5EF",
+      "0548FE281BEAB18FD1AB86F59B0CA524479A4A81373C83B78AFFD801FAC75922"
+      "96470753DCF46173C9AA4A8A4C2FBE51"
+    }, {
+      "NIST P-384", 0,
+      "1DC8E054A883DB81EAEDE6C487B26816C927B8196780525A6CA8F675D2557752"
+      "02CE06CCBE705EA8A38AA2894D4BEEE6",
+      "010191050E867AFAA96A199FE9C591CF8B853D81486786DA889124881FB39D2F"
+      "8E0875F4C4BB1E3D0F8535C7A52306FB82"
+    }, {
+      "NIST P-384", 1,
+      "2539FC368CE1D5E464B6C0FBB12D557B712327DB086975255AD7D17F7E7E4F23"
+      "D719ED4116E2CC907AEB92CF22331A60",
+      "8843FDBA742CB64323E49CEBE8DD74908CFC9C3AA0015662DFBB7219E92CF32E"
+      "9FC63F61EF19DE9B3CEA98D163ABF254"
+    }, {
+      "NIST P-384", 0,
+      "0B786DACF400D43575394349EDD9F9CD145FC7EF737A3C5F69B253BE7639DB24"
+      "EC2F0CA62FF1F90B6515DE356EC2A404",
+      "225D6B2939CC7F7133F43353946A682C68DAC6BB75EE9CF6BD9A1609FA915692"
+      "72F4D3A87E88529754E109BB9B61B03B"
+    }, {
+      "NIST P-384", 0,
+      "76C660C9F58CF2051F9F8B06049694AB6FE418009DE6F0A0833BC690CEC06CC2"
+      "9A440AD51C94CF5BC28817C8C6E2D302",
+      "012974E5D9E55304ED294AB6C7A3C65B663E67ABC5E6F6C0F6498B519F2F6CA1"
+      "8306976291F3ADC0B5ABA42DED376EA9A5"
+    }, {
+      "NIST P-384", 0,
+      "23D758B1EDB8E12E9E707C53C131A19D9464B20EE05C99766F5ABDF9F906AD03"
+      "B958BF28B022E54E320672C4BAD4EEC0",
+      "01E9E72870C88F4C82A5AB3CC8A3398E8F006BF3EC05FFBB1EFF8AEE88020FEA"
+      "9E558E9F58ED1D324C9DCBCB4E8F2A5970"
+    }, {
+      "NIST P-384", 0,
+      "D062B96D5A10F715ACF361F99262ABF0F7693A8BB60ECB1DF459CF95750E4293"
+      "18BCB9FC60499D009F949298F3F9F47B",
+      "9089C6328E4B39A73D7EE6FAE1A77E48CE354B83BBCE432082C32C8FD6784B86"
+      "CFE9C552E2E720F5DA5806503D3784CD"
+    }, {
+      "NIST P-384", 0,
+      "2A951D4D6EB35C43D94866280D37365B82441BC84D62CBFF3365CAB1FD0A3E20"
+      "823CA8F84D2BBF4EA687885437DE7839",
+      "01CC7D762AFE613F7B5568BC516568A421159C40599E8D52DE10E8F9488931E1"
+      "69F3656C322DE45C4A70DC6DB9A661E599"
+    }, {
+      "NIST P-384", 1,
+      "A4BAEE6CDAF3AEB69032B3FBA811707C54F5753670DA5173D891547E8CBAEEF3"
+      "89B92C9A55573A596123415FBFA26991",
+      "3241EA716583C11C71BB30AF6C5E3A6637956F17ADBBE641BAB52E8539F9FC7B"
+      "F3B04F46DBFFE08151E0F0950CC70081"
+    }, {
+      "NIST P-384", 0,
+      "5C0E18B0DE3261BCBCFC7B702C2D75CF481336BFBADF420BADC616235C1966AB"
+      "4C0F876575DDEC1BDB3F3F04061C9AE4",
+      "E90C78550D1C922F1D8161D8C9C0576E29BD09CA665376FA887D13FA8DF48352"
+      "D7BBEEFB803F6CC8FC7895E47F348D33"
+    }, {
+      "NIST P-384", 1,
+      "2015864CD50F0A1A50E6401F44191665C19E4AD4B4903EA9EB464E95D1070E36"
+      "F1D8325E45734D5A0FDD103F4DF6F83E",
+      "5FB3E9A5C59DD5C5262A8176CB7032A00AE33AED08485884A3E5D68D9EEB990B"
+      "F26E8D87EC175577E782AD51A6A12C02"
+    }, {
+      "NIST P-384", 1,
+      "56EBF5310EEF5A5D8D001F570A18625383ECD4882B3FC738A69874E7C9D8F89C"
+      "187BECA23369DFD6C15CC0DA0629958F",
+      "C1230B349FB662CB762563DB8F9FCB32D5CCA16120681C474D67D279CCA6F6DB"
+      "73DE6AA96140B5C457B7486E06D318CE"
+    }, {
+      "NIST P-521", 0,
+      "01E4D82EE5CD6DA37080252295EFA273BBBA6952012D0120EAF131E73F1E5024"
+      "36E3324624471040030E1C345D65490ECEE9B64E03B15B6C7EB69A39C618BAFEED70",
+      "03EE3A3C88A6933B7B16016BE4CC4E3BF5EA0625CB3DB2604CDCBBD02CABBC90"
+      "8904D9DB42998F6C5101D4D4318ACFC9643C9CD641F636D1810ED86F1840EA74F3C0"
+    }, {
+      "NIST P-521", 0,
+      "01F3DFCB5433387B6B2E3F74177F4F3D7300F05E1AD49DE112630E27B1C8A437"
+      "1E742CB020E0039B5477FC897D17332034F9660B3066764EFF5FB440EB8856E782E3",
+      "02D337616C9D202DC5E290C486F5855CBD6A8470AE62CA96245834CF49257D8D"
+      "96D4041B15007650DEE668C00DDBF749054256C571F60980AC74D0DBCA7FB96C2F48"
+    }, {
+      "NIST P-521", 1,
+      "822A846606DC9E96452CAC373567A8B57D9ACA15B177F75DD7EF10C635F52CE4"
+      "EF6ABEEDB90D3F48F50A0C9015A95C955A25C45DE8413DE3BF899B6B1E62CF7CB8",
+      "0102771B5F3EC8C36838CEC04DCBC28AD1E38C37DAB0EA89B5EE92D21F7A35CE"
+      "ABC8B155EDC70154D6DFA2E77EC1D8C4A3406A6BD0ECF8F1EE2AC33A02464CB70C97"
+    }, {
+      "NIST P-521", 0,
+      "F733D48467912D1FFE46CF442F27FDD218D190E7B8A829D822DA3B6BAF9B987E"
+      "5B4BCCE34499248F59EEAF74F63ED15FF73F243C6FC3FD5E5842F6A3BA34C2022D",
+      "0281AAAD1B7EEBABEB6EC67932CB7E95717AFA3B4CF7A2DB151CD537C419C3A5"
+      "156ED9160758190B47696CDC15E81BBAD12975283907A571604DB23F702AEA4B38FF"
+    }, {
+      "NIST P-521", 0,
+      "03B1B274175AAEB5907152E5114CCAEADA28A7ADD4A2B1831C3D8302E8596489"
+      "E2C98B9B8D0CAE98C03BB11E28CE66D4736449758AF58BAFE40EF5A5FA22C9A43117",
+      "94C5951F81D544E959EDFC5DC1D5F42FE427871D4FB91A43A0B4A6BEA6B35B9E"
+      "BC5FB444C70BE4FD47B4ED16704F8C86EF019FC47C7FF2271F8B0DDEA9E2D3BCDD"
+    }, {
+      "NIST P-521", 1,
+      "F2248C318055DE37CD706D4FCAF7E7D96737A4A7B6B8067A66DCD58B6B8DFC55"
+      "90ECE67F6AA67F9C51B57E7B023075F2F42909BF47361CB6881C10F55FB7215B56",
+      "0162F735CE6A2ADA54CAF96A12D6888C02DE0A74638CF34CE39DABBACA4D651B"
+      "7E6ED1A65B551B36BAE7BE474BB6E6905ED0E33C7BA2021885027C7C6E40C5613004"
+    }, {
+      "NIST P-521", 0,
+      "9F08E97FEADCF0A391CA1EA4D97B5FE62D3B164593E12027EB967BD6E1FA841A"
+      "9831158DF164BCAD0BF3ADA96127745E25F349BDDD52EEA1654892B35960C9C023",
+      "AE2A25F5440F258AFACA6925C4C9F7AEAD3CB67153C4FACB31AC33F58B43A78C"
+      "B14F682FF726CEE2A6B6F6B481AEEB29A9B3150F02D1CFB764672BA8294C477291"
+    }, {
+      "NIST P-521", 0,
+      "01047B52014748C904980716953206A93F0D01B34CA94A997407FA93FE304F86"
+      "17BB6E402B2BB8B434C2671ECE953ABE7BADB75713CD9DF950943A33A9A19ACCDABE",
+      "7433533F098037DEA616337986887D01C5CC8DEC3DC1FDB9CDF7287EF27CC125"
+      "54FCF3A5E212DF9DAD9F8A3A7173B23FC6E15930704F3AEE1B074BDDB0ED6823E4"
+    }, {
+      "NIST P-521", 0,
+      "01C2A9EBF51592FE6589F618EAADA1697D9B2EC7CE5D48C9E80FC597642B23F1"
+      "F0EBE953449762BD3F094F57791D9850AFE98BBDA9872BE399B7BDD617860076BB03",
+      "0B822E27692F63DB8E12C59BB3CCA172B9BBF613CAE5F9D1474186E45E8B26FF"
+      "962084E1C6BE74821EDBB60941A3B75516F603719563433383812BFEA89EC14B89"
+    }, {
+      "NIST P-521", 0,
+      "99390F342C3F0D46E80C5B65C61E8AA8ACA0B6D4E1352404586364A05D8398E9"
+      "2BC71A644E8663F0A9B87D0B3ACAEE32F2AB9B321317AD23059D045EBAB91C5D93",
+      "82FCF93AE4467EB57766F2B150E736636727E7282500CD482DA70D153D195F2B"
+      "DF9B96D689A0DC1BB9137B41557A33F202F1B71840544CBEFF03072E77E4BB6F0B"
+    }, {
+      "NIST P-521", 1,
+      "018E48E80594FF5496D8CC7DF8A19D6AA18805A4EF4490038AED6A1E9AA18056"
+      "D0244A97DCF6D132C6804E3F4F369922119544B4C057D783C848FB798B48730A382C",
+      "01AF510B4F5E1C40BC9C110216D35E7C6D7A2BEE52914FC98258676288449901"
+      "F27A07EE91DF2D5D79259712906C3E18A990CBF35BCAC41A952820CE2BA8D0220080"
+    }, {
+      "NIST P-521", 1,
+      "ADCEF3539B4BC831DC0AFD173137A4426152058AFBAE06A17FCB89F4DB6E48B5"
+      "335CB88F8E4DB475A1E390E5656072F06605BFB84CBF9795B7992ECA04A8E10CA1",
+      "01BCB985AFD6404B9EDA49B6190AAA346BF7D5909CA440C0F7E505C62FAC8635"
+      "31D3EB7B2AC4DD4F4404E4B12E9D6D3C596179587F3724B1EFFF684CFDB4B21826B9"
+    }
+  };
+  gpg_error_t err;
+  int tidx;
+  const char *lastcurve = NULL;
+  gcry_ctx_t ctx = NULL;
+  gcry_mpi_t qx = NULL;
+  gcry_mpi_t qy = NULL;
+  gcry_mpi_point_t Q;
+  int oncurve;
+
+  wherestr = "point_on_curve";
+  for (tidx=0; tidx < DIM (t); tidx++)
+    {
+      if (!t[tidx].curve)
+        {
+          if (!lastcurve || !ctx)
+            die ("invalid test vectors at idx %d\n", tidx);
+        }
+      else if (!ctx || !lastcurve || strcmp (t[tidx].curve, lastcurve))
+        {
+          lastcurve = t[tidx].curve;
+          gcry_ctx_release (ctx);
+          err = gcry_mpi_ec_new (&ctx, NULL, lastcurve);
+          if (err)
+            die ("error creating context for curve %s at idx %d: %s\n",
+                 lastcurve, tidx, gpg_strerror (err));
+
+          info ("checking points on curve %s\n", lastcurve);
+        }
+
+      gcry_mpi_release (qx);
+      gcry_mpi_release (qy);
+      qx = hex2mpi (t[tidx].qx);
+      qy = hex2mpi (t[tidx].qy);
+
+      Q = gcry_mpi_point_set (NULL, qx, qy, GCRYMPI_CONST_ONE);
+      if (!Q)
+        die ("gcry_mpi_point_set(Q) failed at idx %d\n", tidx);
+
+      oncurve = gcry_mpi_ec_curve_point (Q, ctx);
+
+      if (t[tidx].oncurve && !oncurve)
+        {
+          fail ("point expected on curve but not identified as such (i=%d):\n",
+                tidx);
+          print_point ("  Q", Q);
+        }
+      else if (!t[tidx].oncurve && oncurve)
+        {
+          fail ("point not expected on curve but identified as such (i=%d):\n",
+                tidx);
+          print_point ("  Q", Q);
+        }
+      gcry_mpi_point_release (Q);
+    }
+
+  gcry_mpi_release (qx);
+  gcry_mpi_release (qy);
+  gcry_ctx_release (ctx);
+}
+
+
+int
+main (int argc, char **argv)
+{
+
+  if (argc > 1 && !strcmp (argv[1], "--verbose"))
+    verbose = 1;
+  else if (argc > 1 && !strcmp (argv[1], "--debug"))
+    verbose = debug = 1;
+
+  if (!gcry_check_version (GCRYPT_VERSION))
+    die ("version mismatch\n");
+
+  xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+  if (debug)
+    xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+  xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+  set_get_point ();
+  context_alloc ();
+  context_param ();
+  basic_ec_math ();
+  point_on_curve ();
+
+  /* The tests are for P-192 and ed25519 which are not supported in
+     FIPS mode.  */
+  if (!gcry_fips_mode_active())
+    {
+      basic_ec_math_simplified ();
+      twistededwards_math ();
+    }
+
+  info ("All tests completed. Errors: %d\n", error_count);
+  return error_count ? 1 : 0;
+}
diff --git a/SOURCES/wk@g10code.com b/SOURCES/wk@g10code.com
new file mode 100644
index 0000000..5e193e3
--- /dev/null
+++ b/SOURCES/wk@g10code.com
@@ -0,0 +1,2007 @@
+Login: wk                              Name: Werner Koch                             
+No project.
+No plan.
+Public key:
+  pub   1024D/5B0358A2 1999-03-15 [expires: 2011-07-11]
+  uid                  Werner Koch <wk@gnupg.org>
+  uid                  Werner Koch <wk@g10code.com>
+  uid                  Werner Koch
+  uid                  Werner Koch <werner@fsfe.org>
+  sub   1024D/010A57ED 2004-03-21 [expires: 2007-12-31]
+  sub   2048R/C3680A6E 2006-01-01 [expires: 2007-12-31]
+  
+  pub   1024R/1CE0C630 2006-01-01 [expires: 2008-12-31]
+  uid                  Werner Koch (dist sig) <dd9jn@gnu.org>
+  
+  pub   1024R/37D92FFB 2003-11-17 [expires: 2009-12-31]
+  uid                  g10 Code (code signing key 1) <code@g10code.com>
+  
+  pub   1024D/57548DCD 1998-07-07 [expired: 2005-12-31]
+  uid                  Werner Koch (gnupg sig) <dd9jn@gnu.org>
+  
+
+5B0358A2 is my main key.
+1CE0C630 is used to sign software distributions.
+37D92FFB is used to sign certain source files.
+57548DCD was used to sign GNU crypto software;
+         it has been superseded by 1CE0C630.
+
+Please note that I use a subkey for signing messages; some old OpenPGP
+implementations may not be able to check such a signature. The primary
+key is stored at a more or less secure place and only used on a spare
+laptop which is not connected to any network. If you find a key
+certified by this one, you can be sure that I personally met this
+person and checked the name part of the user ID against an official
+looking passport or another suitable photo id.  My signature does not
+say anything about the email address (I merely check that the address
+looks plausible).
+
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.7 (GNU/Linux)
+
+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
+Ooh6BBMRAgA6BQJEXmVkMxpodHRwOi8vd3d3LnNjLWRlbHBoaW4tZXNjaHdlaWxl
+ci5kZS9wZ3AvaW5kZXguaHRtbAAKCRC0deIHurWCKcwdAJ4hvG79xMFKtYL0GGP8
+WuvvxnMnzQCfZUjHFhMNMGgrCPthD6oeNaw2FxCIRgQTEQIABgUCRFz9JwAKCRCK
+o2Kv6XIyzVjaAJ9MSW3iP1fUZqr7xdbj/PLkHLzJeACfZNe6IgDrJk9E3a/8IKZi
+E4iYtqWIRgQTEQIABgUCRFz9LwAKCRCn31hycNRMI+EXAKDRHf6ZRUGa6T7Uosgx
+huo5I3sK6gCfRxthF9FN1SXK11O+tjRS1mwN0JaIYwQTEQIAGwUCNxrPkAUJDMl8
+gAMLCgMDFQMCAxYCAQIXgAASCRBd4kmWWwNYogdlR1BHAAEBXcIAnjv7ON5AiwzC
+LBwm9h9ywufXJQuVAJ9RMq6lpPqnDly6UCKz+kGt0EplyIhmBBMRAgAeAwsKAwMV
+AwIDFgIBAheAAhkBBQJAXdnoBQkTa4v/ABIHZUdQRwABAQkQXeJJllsDWKLs0gCg
+y5RdOqhFvwUFYWj+dHb4LGt7xi0AoKduFxGMuM/loPShQnjvk/VVFesAiF4EExEC
+AB4DCwoDAxUDAgMWAgECF4ACGQEFAkBd2egFCRNri/8ACgkQXeJJllsDCRDs0gCg
+y5RdOqhFvwUFYWj+dHb4LGt7xi0AoKduFxGMuM/loPShQnjvk/VVFesAiQEVAwUQ
+O0HCUNImKUTOasbBAQFLZwgAkgMC/ximskOjL/CxghgdkSWkDFdpEr3XYhzUdLes
+WgN4AM28mGZZKA9la7dXXRrKYkxhX8mpL4C3Q9LnrafP+Zn1c8mTuNIxX86j7iZA
+IksoZ4D2csN8NSMYT9pKK6jZP1IOckCFBBI0W/yMGUGulDitWj4TwIArf2xQkV73
+////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////4hGBBMRAgAGBQJDRBuk
+AAoJEOrUtZD2iZvAafoAoKReCbMFRrpwzb2tS7M6iHDbN9E+AJoDy8nLf8A4f/EV
+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
+wZyP4MwTIOb4NIhGBBARAgAGBQJEKFdaAAoJEBH0xB6z+64zBhUAoJ6kWu5gDqHB
+Z8Wan0YynEZi6tKyAJsHBacxx6UNYPENlVXlb0xl+kssa4h6BBMRAgA6BQJEXmVA
+MxpodHRwOi8vd3d3LnNjLWRlbHBoaW4tZXNjaHdlaWxlci5kZS9wZ3AvaW5kZXgu
+aHRtbAAKCRCUj9ag4Q9QLulZAJ992LLlu7wU5sJddqnffDzPoKh69QCgoX8QzBEi
+SZjLKSrALwLCTYI/akSIegQTEQIAOgUCRF5lZDMaaHR0cDovL3d3dy5zYy1kZWxw
+aGluLWVzY2h3ZWlsZXIuZGUvcGdwL2luZGV4Lmh0bWwACgkQtHXiB7q1gikU0QCf
+ZM81Hr4p7ZPwxMZW+TVcRdaSIjoAoMq7mN4xSLtRsB/lGlFLhc1O4soLiEYEExEC
+AAYFAkRc/SoACgkQiqNir+lyMs3HBACfb7fa3KzNGB9Oma3KDWeC42feCzAAoIfF
+w3OXxtigxx8+AowiXGsZmqI+iEYEExECAAYFAkRc/TEACgkQp99YcnDUTCOrZQCg
+gV7PoPMl1d+gvPTiuUAZm8UG/dYAn3PlOcTP4vxayC7OGSkoDA8Dut+KiEYEExEC
+AAYFAkNEG6QACgkQ6tS1kPaJm8DI0ACfRfci8SHm+sQpjzKqr0zxfJT5yF0AnA37
+mn7nQyY28SJ2sddCo/f1JhvAiEYEEBECAAYFAkQFglgACgkQb11ZaBzVLeiG9wCf
+aX6+h8bpMOraCn/sH1yQb6aI34EAoLzx4H6lGdyqnQTYiLXSrBTrto/niEYEEBEC
+AAYFAkQGCjQACgkQmsnSLGNcY0vZ4wCgvBjcB5ABcNYRMEFSWsClxhaRAqUAmwUv
+MA9NWdLk0pcUndbE3w70B5hUiEwEEhECAAwFAkQGKycFgwZSqcEACgkQ3+ZXkjKV
+xc2qMwCfdew+RX+7ultYmO0Y8gRoLJzjBfgAn1UkZILe3+NKZBJTd1ZowJQiljHI
+iEwEEhECAAwFAkQGK2cFgwZSqYEACgkQoOUVvzmICVQuFwCgqbjde48qPvUqLEip
+he/zFq6pqgAAn1dXi6z+1s+bHavwCQK/q+3K5gdHiJwEEwECAAYFAkQNdesACgkQ
+/dJ0ek5GOmrWRgQAoFF9IdTs5vX5OIDKIHW+d4aJfPg6w91SKkfpElDxNqZuk3rA
+HvekwMSeCapKjyUajgKA4hHLy51cupdJPrz01uHO8ySxVaHt7f0qKXEcMXiEFP64
+aEi+Mhx6TvPAE79tJdvgSOnUWqtckaEJ1oY4+J8kEvXP40WcnGynIPDVB6eJAhwE
+EAECAAYFAkQPSJcACgkQGioH6hxXudkA+xAAruFS7PuoOVGB2fS3Er4O/NaT7H9h
+0TVpGKI8JiE35+CCEbxESuIV62M23fqipD/Xli3XHBoycx+DtazmYSCjCp6yoKWN
+XC/sm+oTOKFT0y2tQyPJ0cu4hwWYYMPbL1QIgtlIeB1TKEd3vzCt2rf/Xlod/udV
+7KFQ6V5ZJFkrDnpwEmlL5RmfE2rW1EL7oEc4VfbbgyERiJP8jxoqntTkMFR6LLdb
+NXhdnUse2BsVwtNgpcStrDb+1ucVj2BpsDNjTx+mPBUG3KgirCazO1kuu6qTMW/P
+0jhds5TU5DlVrCaBHiCUotcKtVCigruNqosNRc2aCKXWnaJUpnmSaHBCN7wWey2K
+BqPXPjC3LOR0olqdFuLtXdzMj4lDdrWfFss60ABcxUl8LafWYTDTiVTXQLJlv8kH
+XY2bwNDyy++Ybu1wBw5ODtUBtdrL6vnIMm2EzrxFMi/jIP+lBVEcdSS3E/pO859k
+UQ54mY3/JTKTpOMWcqLJ1ujNn5U7lRHBBCJzRfIfQL/xXxFVkq314AgguOmylOsY
++KlVngmeTD0XOAgWg1vwDEw3vXRpwiB66QCOLYoAcZzhpvWlmrTdCVWXQlciSbP0
+1jG2BNN3fWa/l5ok4s60uFhcLnhpUepzuq0gHzSgg2H3pWlvVaO4KQr+3N+o+abd
+ngPGs5CQufTiYTeJAiIEEAECAAwFAkQFDZkFgwZTx08ACgkQbjbvGsyNqzB0zw//
+YgstKNU1LGBbXgrwhJM8Qg/Y0JCa29yMMDr7iWnEP3nRft+cNgU6F58Qq/n9+3i6
+SgpXFBtPW1UrJnZHVl4ykDDx2dQf8QwjAPcDAWs/yz6XbRihpSD3FBuclgnMCbrr
+ZpDAnEAFuK/Z5Zj8ymsdqf2Mjgth9ch0qbu8Q/SKAUhYZPw/07s5g9ie4CrNu3XN
+IjlCW5myPStcP8swqIcCJRbB5VvY7q2dGT6tFD3KbpLEn0Ur7vX27dLgF7hx4F6e
+g+ZIta/vvHKFCV7UIA4qe36K9brv4LwOxs+ftFRxJYLW+UnNbB9x9ublOk6V+cmc
+ChlGvdxFd0pXskvHT6+XBawnmrOvBy7zDiZdMBodHL0SfoswDRNf2/fkdmKhURDc
+9PLtfPzuloUmxaN06IIA//kFXZzFFS1Yjq6tWQo6dJKPRvsYlQPTz9t2nWF1dOfs
+0iGhW7lR0NU05auSqzgaJUQytIZIr5QoKHx0Zn2nPh2890/xgJ2HamiaQQ0aT7tz
+w+ox+/XgG2dYuKDKW8ki2WAehXYVGNEtDK6YJmfdbkbUww+Q478g+TfnKQ6w8VS2
+w1jqpg3656jzWZg6wUiCvhpnyE0dZD8J8KQwkEnFNc4TcdN5BEmWxnz6JTr3gdUA
+6DmDi821xLkQDndOvd0lbAlKoDxascWP0aTBciVlAvCJAiIEEAECAAwFAkQFESIF
+gwZTw8YACgkQHRqO3OFAoFSLYw/9GFOeol/eGOQotl7lOcffMlaTUdI/PIvFvoAR
+/8shR+za0dWqKzIRARn5Q9pjmNcuIHWlueupA+32mEqP7a4IhZF815k26kPJ7BWC
+ZXjEF6tU/clTvgOsqBk+E6VazL96p8WzvFWvO9jqNNgX+ACEq6GA5z0sO2XrNdnI
+YE3t2MsWebYbsV6jdyaIbjatO/eZ62kbYn9pDRkL5UULyYYDJUB24xbZK0xoFcem
+GGs+rzm9Z5Av9+F25bhZ84S11KXcR9GPoe4uW7tMEI25y9FKr/+PDRUhGP7KnlvA
+/x7hfUnlPbmhZlM4Ewhu0GP3fwzVXzh7ExdfebWFQhDluz8Kio3UvZI99sSqB8F4
+ICmexnTXWsyKTYsU1b24l6RCzss8NUjJGZPo7bM3Z6cFsdPtJ82j00CLuhgB50BM
+I+df96iKhTeEn3pN/whqLrrIIBDxw0DeebRxKdZnXAjKHKwGOIqKepEexr6y7bi8
+Xos/swevSNEIdx+EtU6gWDI5GyT0sNePAtf1mr4O5zGr95XrZ3Kf84BrpUTHCkiz
+neg/kirnnW3Zn7lv7i5TwJlK0jH85es3kWYbyy5qbQzmrMvOqtw8IcQM5Iny0I6v
+TCDh2hzmGUEpPHJQf79LKb2HFg3PJAy/qyWOiGk4C9meqmpJFSy5UJhd4yAK7uuG
+iMz5etmIRgQQEQIABgUCREihKQAKCRAFi1rNRBxfgangAJ9+uYWIpLFlxzA0ecaQ
+xVXJkHDj6ACePdI2VJIxflo2IzVDZR8E1tavH4GIRgQQEQIABgUCREjJ/QAKCRCn
+L/ZsQr1kXR7pAJwIKv2Qqa+/+462dqU61HjyYD6cIwCfaVG6OEZVKvyxF39Y7dCq
+okIgk5OIRgQQEQIABgUCRFsJZQAKCRB/3j6P8z4/xjliAJ0Y9b5gJ7AMKwamZxfo
+7vUpytH4bwCfRVVxusRKkqgQ44Yi+pEZulMkfpCIRgQQEQIABgUCRGCHygAKCRD9
+AQSw4jPImMrLAJ9gxkxh4oIcJM5XEYvKaYxO1r8RbACgybXZPUKIjB0D6VGea8TH
+LJOV3kaIRgQTEQIABgUCRE/tdQAKCRA/0h0qmjpVWLDwAKCcTi0jyFD2d/MI1NZd
+GYBQiJAvsgCeNHNSZjWWHuvz68YF1ZyaZzLvzZOITAQQEQIADAUCRF3UigWDBfsA
+XgAKCRBbqJPk7D6Y30TkAKDHS7wBh5G6EPPMC16vNJwOIgfrNQCfdLK+e71M+mz4
+sgzVEh625NcGtZCITAQQEQIADAUCRF8XTgWDBfm9mgAKCRC8EAnaDpclP5j9AKDB
+VPkHkPJOeLTvpTFU49JloRL/ZwCfYMniDkE2yjqPyeAe6WLat+nZfJiITAQSEQIA
+DAUCRF22QgWDBfsepgAKCRAyNS1FZ/eCZBq6AJ95fp74I7lRx8zt3B+WjWK19bWd
+5ACggupHyHoQEEm00m+7UgEGmuFMHHmI3AQQAQIABgUCRFC2ogAKCRDR2VIECemh
+1f+tBgC0TjA2eTBH5WfFG7N0+XvHVj4SZnRJfj5k9WM7NyVXAuBRHqRDClz4o+7t
+DI7XnpJa6Uf7kI9iabJ7gMxEcXjHstKz1LhycgpmEnCqvVHWZrYfudKqzVfMt0t6
+QEjDtDR8ccYUoNYRhNBFovSHQazsEIISIk+I0nm/l6TOREI80+qBSsktW0Pvd6lg
+BkjHScDk52hXeLd8BQfpfIDxdqAFyW0wC/2lF0jYYC7/FZXpsAFyTTZXeMCZ+vSy
+z3iLTyKJARwEEAECAAYFAkRbcFcACgkQZ02H1ZEZDvnadQgAyHXaBb3PpaZUlvA7
+wb1nAua+LO7qXSR5jLsLl71iWSzfdViqtGVjlXSrsCB74QvSxcRHtpTFqDN80VdV
+oGwNfLPOVUWOEu/Meh1EfugpD0rahwae0FCc0Tu/RnAQbibN+I5SdNKxIPKutCH4
+XdouoD7gSDN4wNAXrHatSxaDTHRpu3+3FNOLYy5NgAPzJcchT6/mQ/YmwIlEped2
+AdEfuio2E/SFpR1y+p3xfqvZEZ9iiX5QKr65fmazBksDYhqR+sGwtjqQwifMqUUI
+tnzUTHQH8IQU5aoI97DCMOu1mlrA4NhNXqBNRC4+CWm3XGgQc6kBnL/qF6syeUMk
+z8gDlYicBBMBAgAGBQJElY7IAAoJENwG3M95JPpzalYD/jp8FsIDlMIoNhHr7+sN
+qbexeYupQDeNNqZUSvVFl2OsIY9clsWAioWHoQtBTZQ3z45nVV6RRVK15+tWdXSe
+EoTQskfdS79woeq7LgLTOB6yLjjhNgG2YyMwBw6eqC97/FpNqED101n538J75XZ3
+9v8fMErAz2GEMrT8lLgj5UEuiEYEEBECAAYFAkS9UTAACgkQxKXVjqqse7yTbwCf
+Vdx7ZbTonurIXC27+BRl8eA4HXIAnih67tYrdols1F3hxc5WGDNuGt9ziEYEEBEC
+AAYFAkS9Os0ACgkQOOnzljbgEa/DZQCfXp8cAjuDumQJJHqJsF6xDzMxeYUAoIoc
++HbWTvWAyUAJhezqfSTxvvfkiEYEEBECAAYFAkTCe3AACgkQQggFxokHT625SgCf
+anHG7BMHpCjPGl0K1A2jvk+UsT8An1blZqLZfsQFqOwp8aM3lYfXgQDtiEYEEBEC
+AAYFAkSNRGcACgkQp6+YGoOsM0oNzwCgxLPbVnWls9geqVyjZxFalLvWJDsAmQFf
+76bS7JiyhQ5adD8iXhW0CKdziEYEEBECAAYFAkVXpxYACgkQ9LSwzHl+v6v0+ACf
+TH2UJ1s11ygX4MGuVJZ1lXEJ9LAAn0gk/Fga/IEJ2x4IhchMw8xV8RvdiIEEExEC
+AEEFAkVbWTI6Gmh0dHA6Ly93d3cuZmFicml6aW90YXJpenpvLm9yZy9kb2N1bWVu
+dGkvZ3BnLXNpZ24tcG9saWN5LwAKCRAyNXpF8ejm5IczAJ0S/kd6+n9RtlhMuXc8
+ij9XsTV8nACg3/CDXfU3mo3eFY8C6taTFUkT842IRgQQEQIABgUCRex7sAAKCRDP
+6Ei//GeFord7AJ9OTDnZn4UoOMI8SMhMSQG2RwZS1QCeMo4+3rhFWl197wQUISSa
+UbEymqCIRgQQEQIABgUCRe3kPQAKCRB3vlkTd0nZ2UACAJ4++JE629pGiJZvvjgY
+t5Rt2qYciQCffDOE5ldc8/vfkY/j3g9qjb3+f9GIRgQQEQIABgUCRcPBPQAKCRCO
+qodEOSmdMQ3xAJ9aoLpFPtuw3WO6xJP4q1bzOIDp6QCfVHhJYiDBcTQbnIeDeIhW
+Q0QsznOIRgQQEQIABgUCRcPBSAAKCRD6RGIhxCQl7ZtEAJ991bKoauaANbLu5AHJ
+DeDZqbDzrgCgoF0R9fuJfcOIToZfn8/TgIjCcX+IRgQQEQIABgUCRcPBUQAKCRDU
+BjIcB09ehLwDAKDHaRXarOBs+dy2YZLP+ps6J5GRaQCfcBs4PbRdyfPExOmzrJjK
+am6x7EaIRgQQEQIABgUCRcPBWAAKCRAtCXF4Sgiq3wDDAJ4vdHpx5jfxVjZK2b36
+e76o5ciwVACdGIdCTvt4T64gkukks+Iz/L8brPSIRgQQEQIABgUCRer2xgAKCRBO
+OFL0w3wdCTQOAKCp9dc7VBEMwSfoUzVVOutO/C8AVACdEHrn6/W3F05u56dkRMS7
+9AByuSmIRgQTEQIABgUCRVg8TQAKCRBU9GFq67wvJiEaAJ9rLGAkAvMeccqYFBVm
+rP0aMvUOwACeM7QuCLlRy1Vj1aITHzFceHp5JjqIRgQQEQIABgUCRe3bCAAKCRDR
+lQx2FhPo1SIpAJ9Tx3e0bx91LgKzod0R0uhRAMGHCgCfdJ/t6r5hBZIAWM3AFWaG
+BGVJIPGIRgQQEQIABgUCRe34FQAKCRDemKiKLdsArEpKAJ95NIcqjpLxNwWersWD
+IUy0m67bRACeOkaaI/i+HL4XTtQUPp3P89TSbN6IYwQTEQIAIwIbAwIeAQIXgAUL
+BwoDAgMVAgMDFgIBBQJGtcWRBQkXLil/AAoJEF3iSZZbA1iiYL0AoI5OdGEa6zru
+BXaT7wrZLDK1gOpVAJ9xoQkq7wQF3SzHcXTbgZf9E3CdmrkBogRAXdpPEQQA/1KB
+8hsg8voFDWeqhuWxNiiLBY8vjy4Fk+OQN/LxexVHlX1pFCWCALjHj8wPcinkBSBF
+4js9weenibe9xUtc+X7/uLuEDB3ziIrOA3wjxVbQR69+Vw2budtYSemNobElYVuF
+IsjUOaqdp+hTydmAanZCgT5+WAYN3nn0LdKIdFMAoNuqBLcQOFNvB9L5sCFbleLz
+/YI/A/0e5565b0z9zK3xS+WIuyPZ5gwQjLsJ5Is7Xdd+eoKNyccr5vn38AN3312k
+xqreAqPsCPVEixFXapYMmkM1dXE/sLL4XPF6VCzK09A5XwfwCQH5GCZLJ/GU1FSQ
+LexBTqNH0jCY8PiIHl+n9KpSmf77vtMACteqx8duaWfBy5TUQAP+LsISHEsFhLU3
+vuHDEvwNYKqOmL7U8ob7p1zQFAUhTe5SFvMsZ+oShtQOG96qC2Wy+gRn+VHxGAy/
++46NcSCIBNDJMRruzcza+NeWkuNePOSWZrcuqZxqbd0R//k5HTbJmJ/qE9T/Hx/9
+VCV7SQo0p04JXX52WjxokfZQhlFEi+2ITwQYEQIADwUCQF3aTwIbAgUJBxtWAAAK
+CRBd4kmWWwNYoiKoAJ9/4y+YEsZIEDQ2R0r1kHd9NLMJ1wCgusn1Bh7b68W7ZZgZ
+k0LnEnLZ1vWITwQYEQIADwUCQF3aUAIbAgUJBxtWAAAKCRBd4kmWWwNYosNxAJ90
+WHb91jqnxLPqdLm1/HlqQ6qY8ACfdj8+liZn5sh+gVweXOM/GYj3e5KIlwQYEQIA
+DwIbAgUJBxtWAAUCRHWsHQBSRyAEGRECAAYFAkR1rBMACgkQYHhOlAEKV+3ZEwCf
+VeIv9sL2EHJkicIlNoJ3xZLyRgIAoJ+kBbAsjGR/AB4P9Ej7anTSdB+8CRBd4kmW
+WwNYorHtAKC5zj8eISzrgTLmnpiKHLrtfwTRiwCdFcwV1dU/vDDy6V2WM+IPVODK
+6um5AQsEQF3bKQEIANEoVLSVnD/YxrBL3s/edXK3YUX1dZvyyLtP0mCX41EX3e6p
+Q4gLXmze7lJU9zB0iGgbTjBgodMsqHIECMWnhrN8uaIgEMOnfsNjdIC0lPpOyBQt
+H7IWRdtG+4g5Tk3/RbHOsroknCUVUTJo9fvOZZUowKP5IyPYWuaW25VLRoJ/SKje
+f3ttQC+5Td2CNMWgepbjTXuyZ9sThUzCctiLf/VJL2zTKwozo/HnIQzehCI5b/2l
+LjzBIV+zeVeLw3UGKSA91TkUUD7kEZJSHHIV/6Wp2PBwHIELstPd0KsV5ZA4vRR5
+WHrAbjw7rePyO57uZ9Ob7nn25ecP8nrk+IdxlOcABimITwQYEQIADwUCQF3bKQIb
+DAUJA1jvAAAKCRBd4kmWWwNYohLWAKCgnbPg6cDR1W3tkz894CwpcDQoVQCfcBXf
+K5kpfhYfDk+d/mwuYXktSSW5AQsEQ7gWIgEIANFah4LB/iVUglBqEzvK0VG88yuR
+JlDLTvb8jr/hA8qxocj4eegHw+NOYGnIEMsrxjo5/djWE1vvvF76baD7xar8FQoe
+9SLUX7HOzOmeLG0yv5A6LLpTuQIkDp8a+rSqbOtcZy/mteka9bDJl/KZMtbhfZYq
+A0vxuE4PLS4n1lH9+GMTuecgeAhuhKcEBQ8cKwj0EW6axtTwUqwokI4GrOIcTIMd
+uLHu4/oHJiyUfa1TD1Z1BTxjOjaZaiOCFemMTtRPS0BvhA1N3C6suCIQgfm6awzj
+d6WvX/ad3ToqKBBf41HgyrK1H7bwm0QQq9QvAlmmYTGzgH44HjHyX7otzT8ABimI
+TwQYEQIADwUCQ7gWIgIbDAUJA8EVgAAKCRBd4kmWWwNYol3LAJ43JG07X/IjKI2S
+i1hF87nLfG4ehwCcDIDiNrFrvTaxGziI9H9ZYmQyASqYjgQ/uRN7AQQA4PCjWWzi
+/vMxKJcYm5eECcScwD2KanQ0jznjMTrfuwkJVmKiqZro42kF54x8pQMFpcEBOrKK
+KVlcp9JEsSjjyN0qE21MEYIweAYxJQXOGlEGZHimDK3C7stXtNMRJ7EFnpLUWUbg
+eIwNDLnV8Locjpi20cFm21GdUgud4VefnOMAIPpvtYO0MGcxMCBDb2RlIChjb2Rl
+IHNpZ25pbmcga2V5IDEpIDxjb2RlQGcxMGNvZGUuY29tPoi2BBMBAgAgBQI/uRN7
+AhsDBQkLg9oAAgsCAxUCAwMWAgECHgECF4AACgkQMQCenzfZL/vXIgP+MVhiaKzD
+y7LeeVXZwwHwfwc3yI/q67mcrbbCwWomgQKb+J2HSS0MLoio6mKiLLeR6Fy/QsRL
+S347V5jcWnhqlohCYOipmVVSRHrLcOrAuuUEjtjBBuPdH7NgN3cHFSo+Nc4cbcry
+opcwxNUCLr2GDqbvBI7k7dn1B7ob+V3UokGISwQTEQIADAUCP7owmwWDC4K84AAK
+CRBot6uJV1SNzdO3AJjZiVSOGYmMzWVc+XfFKy2+Mvh7AJkBpHifVlq5ybuLa65Y
+gIzwp/+8BZiOBEO3+scBBADQmRl6K1zJAyqTbEZ3/mYahzj5g3BCjw5KZXAi9jxQ
+Aje0GiuEXqFr2eJqplTi92V1OdcxTSPWg9yQCE6BE9o69oRmFhRMXQX/XmmIAXl2
+RlDp2yZdVSQ81gxlOmRzacD4gAIGI6bKAYGQsW5e8dFbWLpI3PbyJEf9RlxguL/a
+IQAggVZQmbQmV2VybmVyIEtvY2ggKGRpc3Qgc2lnKSA8ZGQ5am5AZ251Lm9yZz6I
+vAQTAQIAJgUCQ7f6yAIbAwUJBaOagAYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJ
+EFO2INAc4MYweaMEAIdDDtJLkO4TOgCo/GCuG0RmqRwZniJ4mnq/WOr8F4BK3w1H
+IuwVEE8V6BRU4Chx8wc9/W83krckIE5uaZRmjhCXCWsiK9Ow2ngbXAv3TKFVCbMM
+myjBbT+31M9OT0Sowob8a1s4Xv2J+gQJjxfumMUKNlvfK86tEx0ucCiY15h8iEYE
+EBECAAYFAkO4EUMACgkQXeJJllsDWKKR5gCfdiiNjGdj9/mMariU4cnuSmaPQIkA
+nj+zW9f9Z2M0K2r+gldEC2Ew2yTl
+=I1gH
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/SPECS/libgcrypt.spec b/SPECS/libgcrypt.spec
new file mode 100644
index 0000000..3ea8c12
--- /dev/null
+++ b/SPECS/libgcrypt.spec
@@ -0,0 +1,602 @@
+Name: libgcrypt
+Version: 1.8.5
+Release: 3%{?dist}
+URL: http://www.gnupg.org/
+Source0: libgcrypt-%{version}-hobbled.tar.xz
+# The original libgcrypt sources now contain potentially patented ECC
+# cipher support. We have to remove it in the tarball we ship with
+# the hobble-libgcrypt script. 
+# (We replace it with RH approved ECC in Source4-5)
+#Source0: ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-{version}.tar.bz2
+#Source1: ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-{version}.tar.bz2.sig
+Source2: wk@g10code.com
+Source3: hobble-libgcrypt
+# Approved ECC support
+Source4: ecc-curves.c
+Source5: curves.c
+Source6: t-mpi-point.c
+Source7: random.conf
+# make FIPS hmac compatible with fipscheck - non upstreamable
+# update on soname bump
+Patch2: libgcrypt-1.8.5-use-fipscheck.patch
+# modify FIPS RSA and DSA keygen to comply with requirements
+Patch5: libgcrypt-1.8.4-fips-keygen.patch
+# fix the tests to work correctly in the FIPS mode
+Patch6: libgcrypt-1.8.4-tests-fipsmode.patch
+# update the CAVS tests
+Patch7: libgcrypt-1.7.3-fips-cavs.patch
+# use poll instead of select when gathering randomness
+Patch11: libgcrypt-1.8.4-use-poll.patch
+# slight optimalization of mpicoder.c to silence Valgrind (#968288)
+Patch13: libgcrypt-1.6.1-mpicoder-gccopt.patch
+# fix tests to work with approved ECC
+Patch14: libgcrypt-1.7.3-ecc-test-fix.patch
+# Run the FIPS mode initialization in the shared library constructor
+Patch18: libgcrypt-1.8.3-fips-ctor.patch
+# Block some operations if in FIPS non-operational state
+Patch22: libgcrypt-1.7.3-fips-reqs.patch
+# Do not try to open /dev/urandom if getrandom() works
+Patch24: libgcrypt-1.8.5-getrandom.patch
+# CMAC selftest for FIPS POST
+Patch25: libgcrypt-1.8.3-cmac-selftest.patch
+# Continuous FIPS entropy test
+Patch26: libgcrypt-1.8.3-fips-enttest.patch
+# Disable non-approved FIPS hashes in the enforced FIPS mode
+Patch27: libgcrypt-1.8.3-md-fips-enforce.patch
+# Intel CET support, in upstream master
+Patch28: libgcrypt-1.8.5-intel-cet.patch
+# Fix build on ARMv7
+Patch29: libgcrypt-1.8.5-build.patch
+# FIPS module is redefined a little bit (implicit by kernel FIPS mode)
+Patch30: libgcrypt-1.8.5-fips-module.patch
+# Backported AES performance improvements
+Patch31: libgcrypt-1.8.5-aes-perf.patch
+
+%define gcrylibdir %{_libdir}
+
+# Technically LGPLv2.1+, but Fedora's table doesn't draw a distinction.
+# Documentation and some utilities are GPLv2+ licensed. These files
+# are in the devel subpackage.
+License: LGPLv2+
+Summary: A general-purpose cryptography library
+BuildRequires: gcc
+BuildRequires: gawk, libgpg-error-devel >= 1.11, pkgconfig
+BuildRequires: fipscheck
+# This is needed only when patching the .texi doc.
+BuildRequires: texinfo
+BuildRequires: autoconf, automake, libtool
+
+%package devel
+Summary: Development files for the %{name} package
+License: LGPLv2+ and GPLv2+
+Requires(pre): /sbin/install-info
+Requires(post): /sbin/install-info
+Requires: libgpg-error-devel
+Requires: %{name} = %{version}-%{release}
+
+%description
+Libgcrypt is a general purpose crypto library based on the code used
+in GNU Privacy Guard.  This is a development version.
+
+%description devel
+Libgcrypt is a general purpose crypto library based on the code used
+in GNU Privacy Guard.  This package contains files needed to develop
+applications using libgcrypt.
+
+%prep
+%setup -q
+%{SOURCE3}
+%patch2 -p1 -b .use-fipscheck
+%patch5 -p1 -b .fips-keygen
+%patch6 -p1 -b .tests-fipsmode
+%patch7 -p1 -b .cavs
+%patch11 -p1 -b .use-poll
+%patch13 -p1 -b .gccopt
+%patch14 -p1 -b .eccfix
+%patch18 -p1 -b .fips-ctor
+%patch22 -p1 -b .fips-reqs
+%patch24 -p1 -b .getrandom
+%patch25 -p1 -b .cmac-selftest
+%patch26 -p1 -b .fips-enttest
+%patch27 -p1 -b .fips-enforce
+%patch28 -p1 -b .intel-cet
+%patch29 -p1 -b .build
+%patch30 -p1 -b .fips-module
+%patch31 -p1 -b .aes-perf
+
+cp %{SOURCE4} cipher/
+cp %{SOURCE5} %{SOURCE6} tests/
+
+%build
+autoreconf -f
+%configure --disable-static \
+%ifarch sparc64
+     --disable-asm \
+%endif
+     --enable-noexecstack \
+     --enable-hmac-binary-check \
+     --enable-pubkey-ciphers='dsa elgamal rsa ecc' \
+     --disable-O-flag-munging
+sed -i -e '/^sys_lib_dlsearch_path_spec/s,/lib /usr/lib,/usr/lib /lib64 /usr/lib64 /lib,g' libtool
+make %{?_smp_mflags}
+
+%check
+fipshmac src/.libs/libgcrypt.so.??
+make check
+
+# Add generation of HMAC checksums of the final stripped binaries 
+%define __spec_install_post \
+    %{?__debug_package:%{__debug_install_post}} \
+    %{__arch_install_post} \
+    %{__os_install_post} \
+    fipshmac $RPM_BUILD_ROOT%{gcrylibdir}/*.so.?? \
+%{nil}
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT
+
+# Change /usr/lib64 back to /usr/lib.  This saves us from having to patch the
+# script to "know" that -L/usr/lib64 should be suppressed, and also removes
+# a file conflict between 32- and 64-bit versions of this package.
+# Also replace my_host with none.
+sed -i -e 's,^libdir="/usr/lib.*"$,libdir="/usr/lib",g' $RPM_BUILD_ROOT/%{_bindir}/libgcrypt-config
+sed -i -e 's,^my_host=".*"$,my_host="none",g' $RPM_BUILD_ROOT/%{_bindir}/libgcrypt-config
+
+rm -f ${RPM_BUILD_ROOT}/%{_infodir}/dir ${RPM_BUILD_ROOT}/%{_libdir}/*.la
+/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_libdir}
+
+%if "%{gcrylibdir}" != "%{_libdir}"
+# Relocate the shared libraries to %{gcrylibdir}.
+mkdir -p $RPM_BUILD_ROOT%{gcrylibdir}
+for shlib in $RPM_BUILD_ROOT%{_libdir}/*.so* ; do
+	if test -L "$shlib" ; then
+		rm "$shlib"
+	else
+		mv "$shlib" $RPM_BUILD_ROOT%{gcrylibdir}/
+	fi
+done
+
+# Add soname symlink.
+/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_lib}/
+%endif
+
+# Overwrite development symlinks.
+pushd $RPM_BUILD_ROOT/%{gcrylibdir}
+for shlib in lib*.so.?? ; do
+	target=$RPM_BUILD_ROOT/%{_libdir}/`echo "$shlib" | sed -e 's,\.so.*,,g'`.so
+%if "%{gcrylibdir}" != "%{_libdir}"
+	shlib=%{gcrylibdir}/$shlib
+%endif
+	ln -sf $shlib $target
+done
+popd
+
+# Create /etc/gcrypt (hardwired, not dependent on the configure invocation) so
+# that _someone_ owns it.
+mkdir -p -m 755 $RPM_BUILD_ROOT/etc/gcrypt
+install -m644 %{SOURCE7} $RPM_BUILD_ROOT/etc/gcrypt/random.conf
+
+# Drop the pkgconfig as it would require an updated libgpg-error
+rm $RPM_BUILD_ROOT/%{_libdir}/pkgconfig/libgcrypt.pc
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%post devel
+[ -f %{_infodir}/gcrypt.info.gz ] && \
+    /sbin/install-info %{_infodir}/gcrypt.info.gz %{_infodir}/dir
+exit 0
+
+%preun devel
+if [ $1 = 0 -a -f %{_infodir}/gcrypt.info.gz ]; then
+    /sbin/install-info --delete %{_infodir}/gcrypt.info.gz %{_infodir}/dir
+fi
+exit 0
+
+%files
+%dir /etc/gcrypt
+%config(noreplace) /etc/gcrypt/random.conf
+%{gcrylibdir}/libgcrypt.so.*
+%{gcrylibdir}/.libgcrypt.so.*.hmac
+%{!?_licensedir:%global license %%doc}
+%license COPYING.LIB
+%doc AUTHORS NEWS THANKS
+
+%files devel
+%{_bindir}/%{name}-config
+%{_bindir}/dumpsexp
+%{_bindir}/hmac256
+%{_bindir}/mpicalc
+%{_includedir}/*
+%{_libdir}/*.so
+%{_datadir}/aclocal/*
+%{_mandir}/man1/*
+
+%{_infodir}/gcrypt.info*
+%{!?_licensedir:%global license %%doc}
+%license COPYING
+
+%changelog
+* Tue Apr 28 2020 Tomáš Mráz <tmraz@redhat.com> 1.8.5-3
+- new upstream version 1.8.5
+- AES performance improvements backported from master branch
+- FIPS module is implicit with kernel FIPS flag
+- always run the FIPS selftests if FIPS module is installed
+
+* Mon Jun 24 2019 Tomáš Mráz <tmraz@redhat.com> 1.8.3-4
+- improve the continuous FIPS entropy test
+
+* Mon Jun  3 2019 Tomáš Mráz <tmraz@redhat.com> 1.8.3-3
+- add CMAC selftest for FIPS POST
+- add continuous FIPS entropy test
+- disable non-approved FIPS hashes in the enforced FIPS mode
+
+* Thu Jul 12 2018 Tomáš Mráz <tmraz@redhat.com> 1.8.3-2
+- make only_urandom a default in non-presence of configuration file
+- run the full FIPS selftests only when the library is called from
+  application
+
+* Thu Jun 14 2018 Tomáš Mráz <tmraz@redhat.com> 1.8.3-1
+- new upstream version 1.8.3
+
+* Tue Feb  6 2018 Tomáš Mráz <tmraz@redhat.com> 1.8.2-2
+- fix behavior when getrandom syscall is not present (#1542453)
+
+* Thu Dec 21 2017 Tomáš Mráz <tmraz@redhat.com> 1.8.2-1
+- new upstream version 1.8.2
+
+* Tue Dec  5 2017 Tomáš Mráz <tmraz@redhat.com> 1.8.1-3
+- do not try to access() /dev/urandom either if getrandom() works
+
+* Mon Dec  4 2017 Tomáš Mráz <tmraz@redhat.com> 1.8.1-2
+- do not try to open /dev/urandom if getrandom() works (#1380866)
+
+* Tue Sep  5 2017 Tomáš Mráz <tmraz@redhat.com> 1.8.1-1
+- new upstream version 1.8.1
+
+* Wed Aug 16 2017 Tomáš Mráz <tmraz@redhat.com> 1.8.0-1
+- new upstream version 1.8.0
+
+* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.7.8-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
+
+* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.7.8-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Thu Jun 29 2017 Tomáš Mráz <tmraz@redhat.com> 1.7.8-1
+- new upstream version 1.7.8
+
+* Fri Jun  2 2017 Tomáš Mráz <tmraz@redhat.com> 1.7.7-1
+- new upstream version 1.7.7
+- GOST is now enabled
+
+* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.7.6-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Mon Jan 30 2017 Tomáš Mráz <tmraz@redhat.com> 1.7.6-1
+- new upstream version 1.7.6
+
+* Fri Dec 16 2016 Tomáš Mráz <tmraz@redhat.com> 1.7.5-1
+- new upstream version 1.7.5
+
+* Wed Nov 23 2016 Tomáš Mráz <tmraz@redhat.com> 1.7.3-1
+- new upstream version 1.7.3
+
+* Wed Aug 17 2016 Tomáš Mráz <tmraz@redhat.com> 1.6.6-1
+- new upstream version with important security fix (CVE-2016-6316)
+
+* Thu Jul 21 2016 Tomáš Mráz <tmraz@redhat.com> 1.6.5-1
+- new upstream version fixing low impact issue CVE-2015-7511
+
+* Thu Feb 04 2016 Fedora Release Engineering <releng@fedoraproject.org> - 1.6.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Wed Sep  9 2015 Tomáš Mráz <tmraz@redhat.com> 1.6.4-1
+- new upstream version
+
+* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.6.3-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Fri Apr  3 2015 Tomáš Mráz <tmraz@redhat.com> 1.6.3-4
+- deinitialize the RNG after the selftest is run
+
+* Tue Mar 24 2015 Tomáš Mráz <tmraz@redhat.com> 1.6.3-3
+- touch only urandom in the selftest and when /dev/random is
+  unavailable for example by SELinux confinement
+- fix the RSA selftest key (p q swap) (#1204517)
+
+* Fri Mar 13 2015 Tomáš Mráz <tmraz@redhat.com> 1.6.3-2
+- do not use strict aliasing for bufhelp functions (#1201219)
+
+* Fri Mar  6 2015 Tomáš Mráz <tmraz@redhat.com> 1.6.3-1
+- new upstream version
+
+* Wed Feb 25 2015 Tomáš Mráz <tmraz@redhat.com> 1.6.2-4
+- do not initialize secure memory during the selftest (#1195850)
+
+* Sat Feb 21 2015 Till Maas <opensource@till.name> - 1.6.2-3
+- Rebuilt for Fedora 23 Change
+  https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code
+
+* Wed Jan 14 2015 Tomáš Mráz <tmraz@redhat.com> 1.6.2-2
+- fix buildability of programs using gcrypt.h with -ansi (#1182200)
+
+* Mon Dec  8 2014 Tomáš Mráz <tmraz@redhat.com> 1.6.2-1
+- new upstream version
+
+* Sun Aug 17 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.6.1-7
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Thu Jul 17 2014 Tom Callaway <spot@fedoraproject.org> - 1.6.1-6
+- fix license handling
+
+* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.6.1-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Tue May 20 2014 Kyle McMartin <kyle@fedoraproject.org> 1.6.1-4
+- Re-enable below algos, apply patch from upstream list to make
+  that code -fPIC friendly. (rhbz#1069792)
+
+* Mon May 19 2014 Kyle McMartin <kyle@fedoraproject.org> 1.6.1-3
+- Disable rijndael, cast5, camellia ARM assembly, as it's non-PIC as
+  presently written, which results in .text relocations in the shared
+  library. (rhbz#1069792)
+
+* Thu Apr 24 2014 Tomáš Mráz <tmraz@redhat.com> 1.6.1-2
+- drop the temporary compat shared library version
+- fix the soname version in -use-fipscheck.patch
+
+* Fri Feb 28 2014 Tomáš Mráz <tmraz@redhat.com> 1.6.1-1
+- new upstream version breaking ABI compatibility
+- this release temporarily includes old compatibility .so
+
+* Tue Jan 21 2014 Tomáš Mráz <tmraz@redhat.com> 1.5.3-3
+- add back the nistp521r1 EC curve
+- fix a bug in the Whirlpool hash implementation
+- speed up the PBKDF2 computation
+
+* Sun Oct 20 2013 Tom Callaway <spot@fedoraproject.org> - 1.5.3-2
+- add cleared ECC support
+
+* Fri Jul 26 2013 Tomáš Mráz <tmraz@redhat.com> 1.5.3-1
+- new upstream version fixing cache side-channel attack on RSA private keys
+
+* Thu Jun 20 2013 Tomáš Mráz <tmraz@redhat.com> 1.5.2-3
+- silence false error detected by valgrind (#968288)
+
+* Thu Apr 25 2013 Tomáš Mráz <tmraz@redhat.com> 1.5.2-2
+- silence strict aliasing warning in Rijndael
+- apply UsrMove
+- spec file cleanups
+
+* Fri Apr 19 2013 Tomáš Mráz <tmraz@redhat.com> 1.5.2-1
+- new upstream version
+
+* Wed Mar 20 2013 Tomas Mraz <tmraz@redhat.com> 1.5.1-1
+- new upstream version
+
+* Tue Mar  5 2013 Tomas Mraz <tmraz@redhat.com> 1.5.0-11
+- use poll() instead of select() when gathering randomness (#913773)
+
+* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.5.0-10
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Thu Jan  3 2013 Tomas Mraz <tmraz@redhat.com> 1.5.0-9
+- allow empty passphrase in PBKDF2 needed for cryptsetup (=891266)
+
+* Mon Dec  3 2012 Tomas Mraz <tmraz@redhat.com> 1.5.0-8
+- fix multilib conflict in libgcrypt-config
+- fix minor memory leaks and other bugs found by Coverity scan
+
+* Thu Jul 19 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.5.0-6
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Thu Apr  5 2012 Tomas Mraz <tmraz@redhat.com> 1.5.0-5
+- Correctly rebuild the info documentation
+
+* Wed Apr  4 2012 Tomas Mraz <tmraz@redhat.com> 1.5.0-4
+- Add GCRYCTL_SET_ENFORCED_FIPS_FLAG command
+
+* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.5.0-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Mon Aug 15 2011 Kalev Lember <kalevlember@gmail.com> 1.5.0-2
+- Rebuilt for rpm bug #728707
+
+* Thu Jul 21 2011 Tomas Mraz <tmraz@redhat.com> 1.5.0-1
+- new upstream version
+
+* Mon Jun 20 2011 Tomas Mraz <tmraz@redhat.com> 1.4.6-4
+- Always xor seed from /dev/urandom over /etc/gcrypt/rngseed
+
+* Mon May 30 2011 Tomas Mraz <tmraz@redhat.com> 1.4.6-3
+- Make the FIPS-186-3 DSA implementation CAVS testable
+- add configurable source of RNG seed /etc/gcrypt/rngseed
+  in the FIPS mode (#700388)
+
+* Fri Feb 11 2011 Tomas Mraz <tmraz@redhat.com> 1.4.6-1
+- new upstream version with minor changes
+
+* Mon Feb 07 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.4.5-7
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Fri Feb  4 2011 Tomas Mraz <tmraz@redhat.com> 1.4.5-6
+- fix a bug in the fips-186-3 dsa parameter generation code
+
+* Tue Feb  1 2011 Tomas Mraz <tmraz@redhat.com> 1.4.5-5
+- use /dev/urandom for seeding in the FIPS mode
+- make the tests to pass in the FIPS mode also fixing
+  the FIPS-186-3 DSA keygen
+
+* Sun Feb 14 2010 Rex Dieter <rdieter@fedoraproject.org> 1.4.5-4
+- FTBFS libgcrypt-1.4.5-3.fc13: ImplicitDSOLinking (#564973)
+
+* Wed Feb  3 2010 Tomas Mraz <tmraz@redhat.com> 1.4.5-3
+- drop the S390 build workaround as it is no longer needed
+- additional spec file cleanups for merge review (#226008)
+
+* Mon Dec 21 2009 Tomas Mraz <tmraz@redhat.com> 1.4.5-1
+- workaround for build on S390 (#548825)
+- spec file cleanups
+- upgrade to new minor upstream release
+
+* Tue Aug 11 2009 Tomas Mraz <tmraz@redhat.com> 1.4.4-8
+- fix warning when installed with --excludedocs (#515961)
+
+* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.4.4-7
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Thu Jun 18 2009 Tomas Mraz <tmraz@redhat.com> 1.4.4-6
+- and now really apply the padlock patch
+
+* Wed Jun 17 2009 Tomas Mraz <tmraz@redhat.com> 1.4.4-5
+- fix VIA padlock RNG inline assembly call (#505724)
+
+* Thu Mar  5 2009 Tomas Mraz <tmraz@redhat.com> 1.4.4-4
+- with the integrity verification check the library needs to link to libdl
+  (#488702)
+
+* Tue Mar  3 2009 Tomas Mraz <tmraz@redhat.com> 1.4.4-3
+- add hmac FIPS integrity verification check
+
+* Wed Feb 25 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.4.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
+
+* Fri Jan 30 2009 Tomas Mraz <tmraz@redhat.com> 1.4.4-1
+- update to 1.4.4
+- do not abort when the fips mode kernel flag is inaccessible
+  due to permissions (#470219)
+- hobble the library to drop the ECC support
+
+* Mon Oct 20 2008 Dennis Gilmore <dennis@ausil.us> 1.4.3-2
+- disable asm on sparc64
+
+* Thu Sep 18 2008 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-1
+- update to 1.4.3
+- own /etc/gcrypt
+
+* Mon Sep 15 2008 Nalin Dahyabhai <nalin@redhat.com>
+- invoke make with %%{?_smp_mflags} to build faster on multi-processor
+  systems (Steve Grubb)
+
+* Mon Sep  8 2008 Nalin Dahyabhai <nalin@redhat.com> 1.4.2-1
+- update to 1.4.2
+
+* Tue Apr 29 2008 Nalin Dahyabhai <nalin@redhat.com> 1.4.1-1
+- update to 1.4.1
+- bump libgpgerror-devel requirement to 1.4, matching the requirement enforced
+  by the configure script
+
+* Thu Apr  3 2008 Joe Orton <jorton@redhat.com> 1.4.0-3
+- add patch from upstream to fix severe performance regression
+  in entropy gathering
+
+* Tue Feb 19 2008 Fedora Release Engineering <rel-eng@fedoraproject.org> - 1.4.0-2
+- Autorebuild for GCC 4.3
+
+* Mon Dec 10 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.4.0-1
+- update to 1.4.0
+
+* Tue Oct 16 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.2.4-6
+- use ldconfig to build the soname symlink for packaging along with the
+  shared library (#334731)
+
+* Wed Aug 22 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.2.4-5
+- add missing gawk buildrequirement
+- switch from explicitly specifying the /dev/random RNG to just verifying
+  that the non-LGPL ones were disabled by the configure script
+
+* Thu Aug 16 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.2.4-4
+- clarify license
+- force use of the linux /dev/random RNG, to avoid accidentally falling back
+  to others which would affect the license of the resulting library
+
+* Mon Jul 30 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.2.4-3
+- disable static libraries (part of #249815)
+
+* Fri Jul 27 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.2.4-2
+- move libgcrypt shared library to /%%{_lib} (#249815)
+
+* Tue Feb  6 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.2.4-1
+- update to 1.2.4
+
+* Mon Jan 22 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.2.3-2
+- make use of install-info more failsafe (Ville Skyttä, #223705)
+
+* Fri Sep  1 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.2.3-1
+- update to 1.2.3
+
+* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 1.2.2-3.1
+- rebuild
+
+* Mon Jun 05 2006 Jesse Keating <jkeating@redhat.com> 1.2.2-3
+- Added missing buildreq pkgconfig
+
+* Tue May 16 2006 Nalin Dahyabhai <nalin@redhat.com> 1.2.2-2
+- remove file conflicts in libgcrypt-config by making the 64-bit version
+  think the libraries are in /usr/lib (which is wrong, but which it also
+  prunes from the suggest --libs output, so no harm done, hopefully)
+
+* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 1.2.2-1.2.1
+- bump again for double-long bug on ppc(64)
+
+* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 1.2.2-1.2
+- rebuilt for new gcc4.1 snapshot and glibc changes
+
+* Fri Dec 09 2005 Jesse Keating <jkeating@redhat.com>
+- rebuilt
+
+* Wed Oct  5 2005 Nalin Dahyabhai <nalin@redhat.com> 1.2.2-1
+- update to 1.2.2
+
+* Wed Mar 16 2005 Nalin Dahyabhai <nalin@redhat.com> 1.2.1-1
+- update to 1.2.1
+
+* Fri Jul 30 2004 Florian La Roche <Florian.LaRoche@redhat.de>
+- another try to package the symlink
+
+* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Sun May  2 2004 Bill Nottingham <notting@redhat.com> - 1.2.0-1
+- update to official 1.2.0
+
+* Fri Apr 16 2004 Bill Nottingham <notting@redhat.com> - 1.1.94-1
+- update to 1.1.94
+
+* Tue Mar 02 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Sat Feb 21 2004 Florian La Roche <Florian.LaRoche@redhat.de>
+- add symlinks to shared libs at compile time
+
+* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Thu Mar 20 2003 Jeff Johnson <jbj@redhat.com> 1.1.12-1
+- upgrade to 1.1.12 (beta).
+
+* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Sun May 26 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Tue May 21 2002 Jeff Johnson <jbj@redhat.com>
+- update to 1.1.7
+- change license to LGPL.
+- include splint annotations patch.
+- install info pages.
+
+* Tue Apr  2 2002 Nalin Dahyabhai <nalin@redhat.com> 1.1.6-1
+- update to 1.1.6
+
+* Thu Jan 10 2002 Nalin Dahyabhai <nalin@redhat.com> 1.1.5-1
+- fix the Source tag so that it's a real URL
+
+* Thu Dec 20 2001 Nalin Dahyabhai <nalin@redhat.com>
+- initial package