diff --git a/.gitignore b/.gitignore
index 38ce260..7298222 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/libgcrypt-1.8.3-hobbled.tar.xz
+SOURCES/libgcrypt-1.8.5-hobbled.tar.xz
diff --git a/.libgcrypt.metadata b/.libgcrypt.metadata
index c94d94b..04ef129 100644
--- a/.libgcrypt.metadata
+++ b/.libgcrypt.metadata
@@ -1 +1 @@
-e89427b41b148a28583825079d45a7a64234fdbf SOURCES/libgcrypt-1.8.3-hobbled.tar.xz
+1edcc623a15ed87ff832e021b4cb77fd94eb66c9 SOURCES/libgcrypt-1.8.5-hobbled.tar.xz
diff --git a/SOURCES/ecc-curves.c b/SOURCES/ecc-curves.c
index 1720778..7378bae 100644
--- a/SOURCES/ecc-curves.c
+++ b/SOURCES/ecc-curves.c
@@ -1057,7 +1057,7 @@ _gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy)
   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->G->y) && !copy? ec->Q->y : mpi_copy (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.  */
diff --git a/SOURCES/libgcrypt-1.6.2-use-fipscheck.patch b/SOURCES/libgcrypt-1.6.2-use-fipscheck.patch
deleted file mode 100644
index 26af6bf..0000000
--- a/SOURCES/libgcrypt-1.6.2-use-fipscheck.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-diff -up libgcrypt-1.6.2/src/fips.c.use-fipscheck libgcrypt-1.6.2/src/fips.c
---- libgcrypt-1.6.2/src/fips.c.use-fipscheck	2014-08-21 14:50:39.000000000 +0200
-+++ libgcrypt-1.6.2/src/fips.c	2014-09-26 11:42:20.999588282 +0200
-@@ -578,23 +578,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 ();
-@@ -602,7 +629,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
-@@ -611,7 +638,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.6.2/src/Makefile.in.use-fipscheck libgcrypt-1.6.2/src/Makefile.in
---- libgcrypt-1.6.2/src/Makefile.in.use-fipscheck	2014-08-21 15:14:08.000000000 +0200
-+++ libgcrypt-1.6.2/src/Makefile.in	2014-09-26 11:41:13.271059281 +0200
-@@ -449,7 +449,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
- dumpsexp_CFLAGS = $(arch_gpg_error_cflags)
diff --git a/SOURCES/libgcrypt-1.8.0-tests.patch b/SOURCES/libgcrypt-1.8.0-tests.patch
deleted file mode 100644
index f3dfe96..0000000
--- a/SOURCES/libgcrypt-1.8.0-tests.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-diff -up libgcrypt-1.8.0/cipher/dsa.c.tests libgcrypt-1.8.0/cipher/dsa.c
---- libgcrypt-1.8.0/cipher/dsa.c.tests	2016-04-07 17:30:08.000000000 +0200
-+++ libgcrypt-1.8.0/cipher/dsa.c	2017-08-15 15:10:39.551600227 +0200
-@@ -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.0/cipher/rsa.c.tests libgcrypt-1.8.0/cipher/rsa.c
---- libgcrypt-1.8.0/cipher/rsa.c.tests	2017-07-06 10:21:36.000000000 +0200
-+++ libgcrypt-1.8.0/cipher/rsa.c	2017-08-15 15:10:39.551600227 +0200
-@@ -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 -up libgcrypt-1.8.0/tests/keygen.c.tests libgcrypt-1.8.0/tests/keygen.c
---- libgcrypt-1.8.0/tests/keygen.c.tests	2017-08-15 15:10:39.551600227 +0200
-+++ libgcrypt-1.8.0/tests/keygen.c	2017-08-15 15:16:05.433176171 +0200
-@@ -200,11 +200,11 @@ check_rsa_keys (void)
- 
- 
-   if (verbose)
--    info ("creating 512 bit RSA key with e=257\n");
-+    info ("creating 1024 bit RSA key with e=257\n");
-   rc = gcry_sexp_new (&keyparm,
-                       "(genkey\n"
-                       " (rsa\n"
--                      "  (nbits 3:512)\n"
-+                      "  (nbits 4:1024)\n"
-                       "  (rsa-use-e 3:257)\n"
-                       " ))", 0, 1);
-   if (rc)
-@@ -225,11 +225,11 @@ check_rsa_keys (void)
-   gcry_sexp_release (key);
- 
-   if (verbose)
--    info ("creating 512 bit RSA key with default e\n");
-+    info ("creating 1024 bit RSA key with default e\n");
-   rc = gcry_sexp_new (&keyparm,
-                       "(genkey\n"
-                       " (rsa\n"
--                      "  (nbits 3:512)\n"
-+                      "  (nbits 4:1024)\n"
-                       "  (rsa-use-e 1:0)\n"
-                       " ))", 0, 1);
-   if (rc)
-@@ -309,12 +309,12 @@ check_dsa_keys (void)
-     }
- 
-   if (verbose)
--    info ("creating 1536 bit DSA key\n");
-+    info ("creating 2048 bit DSA key\n");
-   rc = gcry_sexp_new (&keyparm,
-                       "(genkey\n"
-                       " (dsa\n"
--                      "  (nbits 4:1536)\n"
--                      "  (qbits 3:224)\n"
-+                      "  (nbits 4:2048)\n"
-+                      "  (qbits 3:256)\n"
-                       " ))", 0, 1);
-   if (rc)
-     die ("error creating S-expression: %s\n", gpg_strerror (rc));
-diff -up libgcrypt-1.8.0/tests/pubkey.c.tests libgcrypt-1.8.0/tests/pubkey.c
---- libgcrypt-1.8.0/tests/pubkey.c.tests	2017-01-18 15:24:25.000000000 +0100
-+++ libgcrypt-1.8.0/tests/pubkey.c	2017-08-15 15:10:39.552600207 +0200
-@@ -595,7 +595,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 --git a/SOURCES/libgcrypt-1.8.0-use-poll.patch b/SOURCES/libgcrypt-1.8.0-use-poll.patch
deleted file mode 100644
index 07df8dd..0000000
--- a/SOURCES/libgcrypt-1.8.0-use-poll.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-diff -up libgcrypt-1.8.0/random/rndlinux.c.use-poll libgcrypt-1.8.0/random/rndlinux.c
---- libgcrypt-1.8.0/random/rndlinux.c.use-poll	2017-06-24 13:34:29.000000000 +0200
-+++ libgcrypt-1.8.0/random/rndlinux.c	2017-08-15 15:37:37.604629377 +0200
-@@ -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
-@@ -216,9 +217,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 and we want to read from the
-        * the non-blocking /dev/urandom, we first try to use the new
-@@ -276,36 +276,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.3-fips-ctor.patch b/SOURCES/libgcrypt-1.8.3-fips-ctor.patch
index e04201f..66abd59 100644
--- a/SOURCES/libgcrypt-1.8.3-fips-ctor.patch
+++ b/SOURCES/libgcrypt-1.8.3-fips-ctor.patch
@@ -1,196 +1,7 @@
-diff -up libgcrypt-1.8.3/cipher/md.c.fips-ctor libgcrypt-1.8.3/cipher/md.c
---- libgcrypt-1.8.3/cipher/md.c.fips-ctor	2017-11-23 19:16:58.000000000 +0100
-+++ libgcrypt-1.8.3/cipher/md.c	2018-07-12 13:24:54.088403006 +0200
-@@ -411,11 +411,8 @@ md_enable (gcry_md_hd_t hd, int algorith
- 
-   if (!err && algorithm == GCRY_MD_MD5 && 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 -up libgcrypt-1.8.3/src/fips.c.fips-ctor libgcrypt-1.8.3/src/fips.c
---- libgcrypt-1.8.3/src/fips.c.fips-ctor	2018-07-12 13:24:54.075402698 +0200
-+++ libgcrypt-1.8.3/src/fips.c	2018-07-12 13:24:54.088403006 +0200
-@@ -91,6 +91,31 @@ static void fips_new_state (enum module_
- 
- 
- 
-+/* Initialize the FSM lock - this function may only
-+   be called once and is intended to be run from the library
-+   constructor  */
-+void
-+_gcry_initialize_fsm_lock (void)
-+{
-+  gpg_error_t err;
-+  /* Intitialize the lock to protect the FSM.  */
-+  err = gpgrt_lock_init (&fsm_lock);
-+  if (err)
-+    {
-+      /* If that fails we can't do anything but abort the
-+         process. We need to use log_info so that the FSM won't
-+         get involved.  */
-+      log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n",
-+                gpg_strerror (err));
-+#ifdef HAVE_SYSLOG
-+      syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
-+              "creating FSM lock failed: %s - abort",
-+              gpg_strerror (err));
-+#endif /*HAVE_SYSLOG*/
-+      abort ();
-+    }
-+}
-+
- /* Check whether the OS is in FIPS mode and record that in a module
-    local variable.  If FORCE is passed as true, fips mode will be
-    enabled anyway. Note: This function is not thread-safe and should
-@@ -100,7 +125,6 @@ void
- _gcry_initialize_fips_mode (int force)
- {
-   static int done;
--  gpg_error_t err;
- 
-   /* Make sure we are not accidentally called twice.  */
-   if (done)
-@@ -179,24 +203,6 @@ _gcry_initialize_fips_mode (int force)
-       /* Yes, we are in FIPS mode.  */
-       FILE *fp;
- 
--      /* Intitialize the lock to protect the FSM.  */
--      err = gpgrt_lock_init (&fsm_lock);
--      if (err)
--        {
--          /* If that fails we can't do anything but abort the
--             process. We need to use log_info so that the FSM won't
--             get involved.  */
--          log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n",
--                    gpg_strerror (err));
--#ifdef HAVE_SYSLOG
--          syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
--                  "creating FSM lock failed: %s - abort",
--                  gpg_strerror (err));
--#endif /*HAVE_SYSLOG*/
--          abort ();
--        }
--
--
-       /* If the FIPS force files exists, is readable and has a number
-          != 0 on its first line, we enable the enforced fips mode.  */
-       fp = fopen (FIPS_FORCE_FILE, "r");
-@@ -359,16 +365,20 @@ _gcry_fips_is_operational (void)
- {
-   int result;
- 
--  if (!fips_mode ())
-+  lock_fsm ();
-+  if (current_state == STATE_POWERON && !fips_mode ())
-+    /* If we are at this point in POWERON state it means the FIPS
-+       module installation was not completed. (/etc/system-fips
-+      is not present.) */
-     result = 1;
-   else
-     {
--      lock_fsm ();
--      if (current_state == STATE_INIT)
-+      if (current_state == STATE_INIT || current_state == STATE_SELFTEST)
-         {
--          /* If we are still in the INIT state, we need to run the
--             selftests so that the FSM can eventually get into
--             operational state.  Given that we would need a 2-phase
-+          /* If we are still in the INIT (or SELFTEST) state,
-+             we need to run (or finish) the selftests so
-+             that the FSM can eventually get into operational
-+             state. Given that we would need a 2-phase
-              initialization of libgcrypt, but that has traditionally
-              not been enforced, we use this on demand self-test
-              checking.  Note that Proper applications would do the
-@@ -384,9 +394,11 @@ _gcry_fips_is_operational (void)
-           lock_fsm ();
-         }
- 
--      result = (current_state == STATE_OPERATIONAL);
--      unlock_fsm ();
-+      result = (current_state == STATE_OPERATIONAL) || !fips_mode ();
-+      /* We always run the selftests but ignore the result
-+         in non-FIPS mode. */
-     }
-+  unlock_fsm ();
-   return result;
- }
- 
-@@ -709,9 +721,25 @@ _gcry_fips_run_selftests (int extended)
- {
-   enum module_states result = STATE_ERROR;
-   gcry_err_code_t ec = GPG_ERR_SELFTEST_FAILED;
-+  int in_poweron;
- 
--  if (fips_mode ())
--    fips_new_state (STATE_SELFTEST);
-+  lock_fsm ();
-+  in_poweron = (current_state == STATE_POWERON);
-+  unlock_fsm ();
-+
-+  fips_new_state (STATE_SELFTEST);
-+
-+  /* We first check the integrity of the binary.
-+     If run from the constructor we are in POWERON state,
-+     we return and finish the remaining selftests before
-+     real use of the library. It will be in the POWERON
-+     state meanwhile.  */
-+  if (in_poweron)
-+    if (check_binary_integrity ())
-+      goto leave;
-+
-+  if (in_poweron)
-+    return 0;
- 
-   if (run_cipher_selftests (extended))
-     goto leave;
-@@ -730,18 +758,12 @@ _gcry_fips_run_selftests (int extended)
-   if (run_pubkey_selftests (extended))
-     goto leave;
- 
--  /* Now check the integrity of the binary.  We do this this after
--     having checked the HMAC code.  */
--  if (check_binary_integrity ())
--    goto leave;
--
-   /* All selftests passed.  */
-   result = STATE_OPERATIONAL;
-   ec = 0;
- 
-  leave:
--  if (fips_mode ())
--    fips_new_state (result);
-+  fips_new_state (result);
- 
-   return ec;
- }
-@@ -797,6 +819,7 @@ fips_new_state (enum module_states new_s
-     {
-     case STATE_POWERON:
-       if (new_state == STATE_INIT
-+          || new_state == STATE_SELFTEST
-           || new_state == STATE_ERROR
-           || new_state == STATE_FATALERROR)
-         ok = 1;
-@@ -811,6 +834,8 @@ fips_new_state (enum module_states new_s
- 
-     case STATE_SELFTEST:
-       if (new_state == STATE_OPERATIONAL
-+          || new_state == STATE_INIT
-+          || new_state == STATE_SELFTEST
-           || new_state == STATE_ERROR
-           || new_state == STATE_FATALERROR)
-         ok = 1;
 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	2018-07-17 19:15:43.933827112 +0200
-@@ -141,6 +141,29 @@ global_init (void)
++++ libgcrypt-1.8.3/src/global.c	2020-04-17 16:29:59.258218015 +0200
+@@ -141,6 +141,34 @@ global_init (void)
  }
  
  
@@ -202,25 +13,30 @@ diff -up libgcrypt-1.8.3/src/global.c.fips-ctor libgcrypt-1.8.3/src/global.c
 +{
 +  int rv;
 +
-+  /* We always need the FSM lock to be functional. */
-+  _gcry_initialize_fsm_lock ();
-+
 +  rv = access (FIPS_MODULE_PATH, F_OK);
 +  if (rv < 0 && errno != ENOENT)
 +    rv = 0;
 +
 +  if (!rv)
 +    {
-+      /* We run the integrity check at this point. The remaining
-+         selftests are run before use of the library by application. */
++      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 +694,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
+@@ -671,8 +699,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
  
      case GCRYCTL_FIPS_MODE_P:
        if (fips_mode ()
@@ -230,7 +46,7 @@ diff -up libgcrypt-1.8.3/src/global.c.fips-ctor libgcrypt-1.8.3/src/global.c
  	rc = GPG_ERR_GENERAL; /* Used as TRUE value */
        break;
  
-@@ -749,9 +771,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
+@@ -749,9 +776,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
        break;
  
      case GCRYCTL_SET_ENFORCED_FIPS_FLAG:
@@ -242,15 +58,3 @@ diff -up libgcrypt-1.8.3/src/global.c.fips-ctor libgcrypt-1.8.3/src/global.c
            _gcry_set_preferred_rng_type (0);
            _gcry_set_enforced_fips_mode ();
          }
-diff -up libgcrypt-1.8.3/src/g10lib.h.fips-ctor libgcrypt-1.8.3/src/g10lib.h
---- libgcrypt-1.8.3/src/g10lib.h.fips-ctor	2017-11-23 19:16:58.000000000 +0100
-+++ libgcrypt-1.8.3/src/g10lib.h	2018-07-12 13:24:54.089403030 +0200
-@@ -422,6 +422,8 @@ gpg_err_code_t _gcry_sexp_vextract_param
- 
- /*-- fips.c --*/
- 
-+void _gcry_initialize_fsm_lock (void);
-+
- void _gcry_initialize_fips_mode (int force);
- 
- int _gcry_fips_mode (void);
diff --git a/SOURCES/libgcrypt-1.8.3-getrandom.patch b/SOURCES/libgcrypt-1.8.3-getrandom.patch
deleted file mode 100644
index 7428dfb..0000000
--- a/SOURCES/libgcrypt-1.8.3-getrandom.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-diff -up libgcrypt-1.8.3/random/random.c.getrandom libgcrypt-1.8.3/random/random.c
---- libgcrypt-1.8.3/random/random.c.getrandom	2017-11-23 19:16:58.000000000 +0100
-+++ libgcrypt-1.8.3/random/random.c	2018-07-10 15:38:34.303855808 +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 (;;)
-     {
-diff -up libgcrypt-1.8.3/random/random-csprng.c.getrandom libgcrypt-1.8.3/random/random-csprng.c
---- libgcrypt-1.8.3/random/random-csprng.c.getrandom	2017-11-23 19:16:58.000000000 +0100
-+++ libgcrypt-1.8.3/random/random-csprng.c	2018-06-14 16:31:04.731179208 +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"
-@@ -1116,6 +1120,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.3/random/rndlinux.c.getrandom libgcrypt-1.8.3/random/rndlinux.c
---- libgcrypt-1.8.3/random/rndlinux.c.getrandom	2018-06-14 16:31:04.722178971 +0200
-+++ libgcrypt-1.8.3/random/rndlinux.c	2018-07-10 15:55:03.301075155 +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"
-@@ -204,6 +205,18 @@ _gcry_rndlinux_gather_random (void (*add
-     {
-       if (fd_urandom == -1)
-         {
-+#if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom)
-+          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;
-+	  else
-+            /* The syscall is not supported - fallback to /dev/urandom. */
-+#endif
-           fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2));
-           ever_opened |= 2;
-         }
-@@ -230,7 +243,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 == fd_urandom)
-+      if (fd == -2)
-         {
-           long ret;
-           size_t nbytes;
-@@ -246,9 +259,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 /dev/urandom.  */
--          else
-+          if (1)
-             { /* The syscall is supported.  Some sanity checks.  */
-               if (ret == -1)
-                 log_fatal ("unexpected error from getrandom: %s\n",
diff --git a/SOURCES/libgcrypt-1.8.3-md-fips-enforce.patch b/SOURCES/libgcrypt-1.8.3-md-fips-enforce.patch
index d040bfb..eed7fa5 100644
--- a/SOURCES/libgcrypt-1.8.3-md-fips-enforce.patch
+++ b/SOURCES/libgcrypt-1.8.3-md-fips-enforce.patch
@@ -1,12 +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	2018-11-01 15:40:36.051865535 +0100
-+++ libgcrypt-1.8.3/cipher/md.c	2019-06-03 11:50:21.435401753 +0200
-@@ -409,7 +409,7 @@ md_enable (gcry_md_hd_t hd, int algorith
+--- 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-kdf-selftest.patch b/SOURCES/libgcrypt-1.8.5-kdf-selftest.patch
new file mode 100644
index 0000000..f622283
--- /dev/null
+++ b/SOURCES/libgcrypt-1.8.5-kdf-selftest.patch
@@ -0,0 +1,158 @@
+diff -up libgcrypt-1.8.5/cipher/kdf.c.kdf-selftest libgcrypt-1.8.5/cipher/kdf.c
+--- libgcrypt-1.8.5/cipher/kdf.c.kdf-selftest	2017-11-23 19:16:58.000000000 +0100
++++ libgcrypt-1.8.5/cipher/kdf.c	2020-06-15 18:14:26.494995669 +0200
+@@ -305,3 +305,99 @@ _gcry_kdf_derive (const void *passphrase
+  leave:
+   return ec;
+ }
++
++
++/* PBKDF2 selftests.
++ * Copyright (C) 2008 Free Software Foundation, Inc.
++ * Copyright (C) 2019, 2020 Red Hat, Inc.
++ */
++
++/* Check one PBKDF2 call with HASH ALGO using the regular KDF
++ * API. (passphrase,passphraselen) is the password to be derived,
++ * (salt,saltlen) the salt for the key derivation,
++ * iterations is the number of the kdf iterations,
++ * and (expect,expectlen) the expected result. Returns NULL on
++ * success or a string describing the failure.  */
++
++static const char *
++check_one (int algo,
++           const void *passphrase, size_t passphraselen,
++           const void *salt, size_t saltlen,
++           unsigned long iterations,
++           const void *expect, size_t expectlen)
++{
++  unsigned char key[512]; /* hardcoded to avoid allocation */
++  size_t keysize = expectlen;
++
++  if (keysize > sizeof(key))
++    return "invalid tests data";
++
++  if (_gcry_kdf_derive (passphrase, passphraselen, GCRY_KDF_PBKDF2,
++                        algo, salt, saltlen, iterations,
++                         keysize, key))
++    return "gcry_kdf_derive failed";
++
++  if (memcmp (key, expect, expectlen))
++    return "does not match";
++
++  return NULL;
++}
++
++static gpg_err_code_t
++run_pbkdf2_selftest (int extended, selftest_report_func_t report)
++{
++  const char *what;
++  const char *errtxt;
++
++  what = "Basic PBKDF2 SHA256";
++  errtxt = check_one (GCRY_MD_SHA256,
++        "password", 8,
++        "salt", 4,
++        2,
++        "\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9\x28\xf0\x6d\xd0"
++        "\x2a\x30\x3f\x8e\xf3\xc2\x51\xdf\xd6\xe2\xd8\x5a\x95\x47\x4c\x43", 32);
++  if (errtxt)
++    goto failed;
++
++  if (extended)
++    {
++      what = "Extended PBKDF2 SHA256";
++      errtxt = check_one (GCRY_MD_SHA256,
++        "passwordPASSWORDpassword", 24,
++        "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
++        4096,
++        "\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11\x6e\x84\xcf"
++        "\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c\x4e\x2a\x1f\xb8\xdd\x53\xe1"
++        "\xc6\x35\x51\x8c\x7d\xac\x47\xe9", 40);
++      if (errtxt)
++        goto failed;
++    }
++
++  return 0; /* Succeeded. */
++
++ failed:
++  if (report)
++    report ("kdf", GCRY_KDF_PBKDF2, what, errtxt);
++  return GPG_ERR_SELFTEST_FAILED;
++}
++
++
++/* Run the selftests for KDF with KDF algorithm ALGO with optional
++   reporting function REPORT.  */
++gpg_error_t
++_gcry_kdf_selftest (int algo, int extended, selftest_report_func_t report)
++{
++  gcry_err_code_t ec = 0;
++
++  if (algo == GCRY_KDF_PBKDF2)
++    {
++      ec = run_pbkdf2_selftest (extended, report);
++    }
++  else
++    {
++      ec = GPG_ERR_UNSUPPORTED_ALGORITHM;
++      if (report)
++        report ("kdf", algo, "module", "algorithm not available");
++    }
++  return gpg_error (ec);
++}
+diff -up libgcrypt-1.8.5/src/cipher-proto.h.kdf-selftest libgcrypt-1.8.5/src/cipher-proto.h
+--- libgcrypt-1.8.5/src/cipher-proto.h.kdf-selftest	2020-06-15 18:03:25.785353036 +0200
++++ libgcrypt-1.8.5/src/cipher-proto.h	2020-06-15 18:03:25.788353061 +0200
+@@ -259,6 +259,8 @@ gcry_error_t _gcry_hmac_selftest (int al
+                                   selftest_report_func_t report);
+ gcry_error_t _gcry_cmac_selftest (int algo, int extended,
+                                   selftest_report_func_t report);
++gcry_error_t _gcry_kdf_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.5/src/fips.c.kdf-selftest libgcrypt-1.8.5/src/fips.c
+--- libgcrypt-1.8.5/src/fips.c.kdf-selftest	2020-06-15 18:03:25.777352968 +0200
++++ libgcrypt-1.8.5/src/fips.c	2020-06-15 18:08:40.651028096 +0200
+@@ -490,6 +490,29 @@ run_mac_selftests (int extended)
+   return anyerr;
+ }
+ 
++/* Run self-tests for all KDF algorithms.  Return 0 on success. */
++static int
++run_kdf_selftests (int extended)
++{
++  static int algos[] =
++    {
++      GCRY_KDF_PBKDF2,
++      0
++    };
++  int idx;
++  gpg_error_t err;
++  int anyerr = 0;
++
++  for (idx=0; algos[idx]; idx++)
++    {
++      err = _gcry_kdf_selftest (algos[idx], extended, reporter);
++      reporter ("kdf", algos[idx], NULL, err? gpg_strerror (err):NULL);
++      if (err)
++        anyerr = 1;
++    }
++  return anyerr;
++}
++
+ 
+ /* Run self-tests for all required public key algorithms.  Return 0 on
+    success. */
+@@ -673,6 +696,9 @@ _gcry_fips_run_selftests (int extended)
+   if (run_mac_selftests (extended))
+     goto leave;
+ 
++  if (run_kdf_selftests (extended))
++    goto leave;
++
+   /* Run random tests before the pubkey tests because the latter
+      require random.  */
+   if (run_random_selftests ())
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/SPECS/libgcrypt.spec b/SPECS/libgcrypt.spec
index 7eaf176..f41c9c9 100644
--- a/SPECS/libgcrypt.spec
+++ b/SPECS/libgcrypt.spec
@@ -1,5 +1,5 @@
 Name: libgcrypt
-Version: 1.8.3
+Version: 1.8.5
 Release: 4%{?dist}
 URL: http://www.gnupg.org/
 Source0: libgcrypt-%{version}-hobbled.tar.xz
@@ -18,13 +18,15 @@ Source6: t-mpi-point.c
 Source7: random.conf
 # make FIPS hmac compatible with fipscheck - non upstreamable
 # update on soname bump
-Patch2: libgcrypt-1.6.2-use-fipscheck.patch
-# fix tests in the FIPS mode, allow CAVS testing of DSA keygen
-Patch5: libgcrypt-1.8.0-tests.patch
+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.0-use-poll.patch
+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
@@ -34,13 +36,23 @@ 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.3-getrandom.patch
+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
+# FIPS selftest for PBKDF2
+Patch32: libgcrypt-1.8.5-kdf-selftest.patch
 
 %define gcrylibdir %{_libdir}
 
@@ -54,12 +66,11 @@ BuildRequires: gawk, libgpg-error-devel >= 1.11, pkgconfig
 BuildRequires: fipscheck
 # This is needed only when patching the .texi doc.
 BuildRequires: texinfo
-Group: System Environment/Libraries
+BuildRequires: autoconf, automake, libtool
 
 %package devel
 Summary: Development files for the %{name} package
 License: LGPLv2+ and GPLv2+
-Group: Development/Libraries
 Requires(pre): /sbin/install-info
 Requires(post): /sbin/install-info
 Requires: libgpg-error-devel
@@ -78,7 +89,8 @@ applications using libgcrypt.
 %setup -q
 %{SOURCE3}
 %patch2 -p1 -b .use-fipscheck
-%patch5 -p1 -b .tests
+%patch5 -p1 -b .fips-keygen
+%patch6 -p1 -b .tests-fipsmode
 %patch7 -p1 -b .cavs
 %patch11 -p1 -b .use-poll
 %patch13 -p1 -b .gccopt
@@ -89,11 +101,17 @@ applications using libgcrypt.
 %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
+%patch32 -p1 -b .kdf-selftest
 
 cp %{SOURCE4} cipher/
 cp %{SOURCE5} %{SOURCE6} tests/
 
 %build
+autoreconf -f
 %configure --disable-static \
 %ifarch sparc64
      --disable-asm \
@@ -161,6 +179,9 @@ popd
 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
@@ -200,6 +221,15 @@ exit 0
 %license COPYING
 
 %changelog
+* Mon Jun 15 2020 Tomáš Mráz <tmraz@redhat.com> 1.8.5-4
+- add PBKDF2 selftest for FIPS POST
+
+* 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