Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Linus Torvalds [Thu, 2 May 2013 21:53:12 +0000 (14:53 -0700)]
Pull crypto update from Herbert Xu:

 - XTS mode optimisation for twofish/cast6/camellia/aes on x86

 - AVX2/x86_64 implementation for blowfish/twofish/serpent/camellia

 - SSSE3/AVX/AVX2 optimisations for sha256/sha512

 - Added driver for SAHARA2 crypto accelerator

 - Fix for GMAC when used in non-IPsec secnarios

 - Added generic CMAC implementation (including IPsec glue)

 - IP update for crypto/atmel

 - Support for more than one device in hwrng/timeriomem

 - Added Broadcom BCM2835 RNG driver

 - Misc fixes

* git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (59 commits)
  crypto: caam - fix job ring cleanup code
  crypto: camellia - add AVX2/AES-NI/x86_64 assembler implementation of camellia cipher
  crypto: serpent - add AVX2/x86_64 assembler implementation of serpent cipher
  crypto: twofish - add AVX2/x86_64 assembler implementation of twofish cipher
  crypto: blowfish - add AVX2/x86_64 implementation of blowfish cipher
  crypto: tcrypt - add async cipher speed tests for blowfish
  crypto: testmgr - extend camellia test-vectors for camellia-aesni/avx2
  crypto: aesni_intel - fix Kconfig problem with CRYPTO_GLUE_HELPER_X86
  crypto: aesni_intel - add more optimized XTS mode for x86-64
  crypto: x86/camellia-aesni-avx - add more optimized XTS code
  crypto: cast6-avx: use new optimized XTS code
  crypto: x86/twofish-avx - use optimized XTS code
  crypto: x86 - add more optimized XTS-mode for serpent-avx
  xfrm: add rfc4494 AES-CMAC-96 support
  crypto: add CMAC support to CryptoAPI
  crypto: testmgr - add empty test vectors for null ciphers
  crypto: testmgr - add AES GMAC test vectors
  crypto: gcm - fix rfc4543 to handle async crypto correctly
  crypto: gcm - make GMAC work when dst and src are different
  hwrng: timeriomem - added devicetree hooks
  ...

88 files changed:
Documentation/devicetree/bindings/crypto/fsl-imx-sahara.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwrng/timeriomem_rng.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rng/brcm,bcm2835.txt [new file with mode: 0644]
Documentation/hw_random.txt
arch/arm/mach-at91/at91sam9g45_devices.c
arch/x86/crypto/Makefile
arch/x86/crypto/aesni-intel_asm.S
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/blowfish-avx2-asm_64.S [new file with mode: 0644]
arch/x86/crypto/blowfish_avx2_glue.c [new file with mode: 0644]
arch/x86/crypto/blowfish_glue.c
arch/x86/crypto/camellia-aesni-avx-asm_64.S
arch/x86/crypto/camellia-aesni-avx2-asm_64.S [new file with mode: 0644]
arch/x86/crypto/camellia_aesni_avx2_glue.c [new file with mode: 0644]
arch/x86/crypto/camellia_aesni_avx_glue.c
arch/x86/crypto/cast6-avx-x86_64-asm_64.S
arch/x86/crypto/cast6_avx_glue.c
arch/x86/crypto/crc32-pclmul_asm.S
arch/x86/crypto/crc32c-pcl-intel-asm_64.S
arch/x86/crypto/glue_helper-asm-avx.S
arch/x86/crypto/glue_helper-asm-avx2.S [new file with mode: 0644]
arch/x86/crypto/glue_helper.c
arch/x86/crypto/serpent-avx-x86_64-asm_64.S
arch/x86/crypto/serpent-avx2-asm_64.S [new file with mode: 0644]
arch/x86/crypto/serpent_avx2_glue.c [new file with mode: 0644]
arch/x86/crypto/serpent_avx_glue.c
arch/x86/crypto/sha256-avx-asm.S [new file with mode: 0644]
arch/x86/crypto/sha256-avx2-asm.S [new file with mode: 0644]
arch/x86/crypto/sha256-ssse3-asm.S [new file with mode: 0644]
arch/x86/crypto/sha256_ssse3_glue.c [new file with mode: 0644]
arch/x86/crypto/sha512-avx-asm.S [new file with mode: 0644]
arch/x86/crypto/sha512-avx2-asm.S [new file with mode: 0644]
arch/x86/crypto/sha512-ssse3-asm.S [new file with mode: 0644]
arch/x86/crypto/sha512_ssse3_glue.c [new file with mode: 0644]
arch/x86/crypto/twofish-avx-x86_64-asm_64.S
arch/x86/crypto/twofish-avx2-asm_64.S [new file with mode: 0644]
arch/x86/crypto/twofish_avx2_glue.c [new file with mode: 0644]
arch/x86/crypto/twofish_avx_glue.c
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/crypto/blowfish.h [new file with mode: 0644]
arch/x86/include/asm/crypto/camellia.h
arch/x86/include/asm/crypto/glue_helper.h
arch/x86/include/asm/crypto/serpent-avx.h
arch/x86/include/asm/crypto/twofish.h
crypto/Kconfig
crypto/Makefile
crypto/cmac.c [new file with mode: 0644]
crypto/crypto_user.c
crypto/gcm.c
crypto/sha256_generic.c
crypto/sha512_generic.c
crypto/tcrypt.c
crypto/testmgr.c
crypto/testmgr.h
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/bcm2835-rng.c [new file with mode: 0644]
drivers/char/hw_random/exynos-rng.c
drivers/char/hw_random/mxc-rnga.c
drivers/char/hw_random/timeriomem-rng.c
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/atmel-aes.c
drivers/crypto/atmel-sha-regs.h
drivers/crypto/atmel-sha.c
drivers/crypto/atmel-tdes-regs.h
drivers/crypto/atmel-tdes.c
drivers/crypto/bfin_crc.c
drivers/crypto/caam/Kconfig
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/ctrl.c
drivers/crypto/caam/error.c
drivers/crypto/caam/intern.h
drivers/crypto/caam/jr.c
drivers/crypto/caam/key_gen.c
drivers/crypto/caam/key_gen.h
drivers/crypto/caam/regs.h
drivers/crypto/omap-aes.c
drivers/crypto/omap-sham.c
drivers/crypto/picoxcell_crypto.c
drivers/crypto/sahara.c [new file with mode: 0644]
drivers/crypto/ux500/hash/hash_core.c
include/crypto/sha.h
include/linux/platform_data/atmel-aes.h [deleted file]
include/linux/platform_data/crypto-atmel.h [new file with mode: 0644]
include/linux/timeriomem-rng.h
net/xfrm/xfrm_algo.c

diff --git a/Documentation/devicetree/bindings/crypto/fsl-imx-sahara.txt b/Documentation/devicetree/bindings/crypto/fsl-imx-sahara.txt
new file mode 100644 (file)
index 0000000..5c65ecc
--- /dev/null
@@ -0,0 +1,15 @@
+Freescale SAHARA Cryptographic Accelerator included in some i.MX chips.
+Currently only i.MX27 is supported.
+
+Required properties:
+- compatible : Should be "fsl,<soc>-sahara"
+- reg : Should contain SAHARA registers location and length
+- interrupts : Should contain SAHARA interrupt number
+
+Example:
+
+sah@10025000 {
+       compatible = "fsl,imx27-sahara";
+       reg = < 0x10025000 0x800>;
+       interrupts = <75>;
+};
diff --git a/Documentation/devicetree/bindings/hwrng/timeriomem_rng.txt b/Documentation/devicetree/bindings/hwrng/timeriomem_rng.txt
new file mode 100644 (file)
index 0000000..6616d15
--- /dev/null
@@ -0,0 +1,18 @@
+HWRNG support for the timeriomem_rng driver
+
+Required properties:
+- compatible : "timeriomem_rng"
+- reg : base address to sample from
+- period : wait time in microseconds to use between samples
+
+N.B. currently 'reg' must be four bytes wide and aligned
+
+Example:
+
+hwrng@44 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "timeriomem_rng";
+       reg = <0x44 0x04>;
+       period = <1000000>;
+};
diff --git a/Documentation/devicetree/bindings/rng/brcm,bcm2835.txt b/Documentation/devicetree/bindings/rng/brcm,bcm2835.txt
new file mode 100644 (file)
index 0000000..07ccdaa
--- /dev/null
@@ -0,0 +1,13 @@
+BCM2835 Random number generator
+
+Required properties:
+
+- compatible : should be "brcm,bcm2835-rng"
+- reg : Specifies base physical address and size of the registers.
+
+Example:
+
+rng {
+        compatible = "brcm,bcm2835-rng";
+        reg = <0x7e104000 0x10>;
+};
index 690f525..026e237 100644 (file)
@@ -63,7 +63,7 @@ Intel RNG Driver notes:
 
        * FIXME: support poll(2)
 
-       NOTE: request_mem_region was removed, for two reasons:
+       NOTE: request_mem_region was removed, for three reasons:
        1) Only one RNG is supported by this driver, 2) The location
        used by the RNG is a fixed location in MMIO-addressable memory,
        3) users with properly working BIOS e820 handling will always
index 827c9f2..f0bf682 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 #include <linux/atmel-mci.h>
-#include <linux/platform_data/atmel-aes.h>
+#include <linux/platform_data/crypto-atmel.h>
 
 #include <linux/platform_data/at91_adc.h>
 
@@ -1900,7 +1900,8 @@ static void __init at91_add_device_tdes(void) {}
  * -------------------------------------------------------------------- */
 
 #if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
-static struct aes_platform_data aes_data;
+static struct crypto_platform_data aes_data;
+static struct crypto_dma_data alt_atslave;
 static u64 aes_dmamask = DMA_BIT_MASK(32);
 
 static struct resource aes_resources[] = {
@@ -1931,23 +1932,20 @@ static struct platform_device at91sam9g45_aes_device = {
 static void __init at91_add_device_aes(void)
 {
        struct at_dma_slave     *atslave;
-       struct aes_dma_data     *alt_atslave;
-
-       alt_atslave = kzalloc(sizeof(struct aes_dma_data), GFP_KERNEL);
 
        /* DMA TX slave channel configuration */
-       atslave = &alt_atslave->txdata;
+       atslave = &alt_atslave.txdata;
        atslave->dma_dev = &at_hdmac_device.dev;
        atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE  | ATC_SRC_H2SEL_HW |
                                                ATC_SRC_PER(AT_DMA_ID_AES_RX);
 
        /* DMA RX slave channel configuration */
-       atslave = &alt_atslave->rxdata;
+       atslave = &alt_atslave.rxdata;
        atslave->dma_dev = &at_hdmac_device.dev;
        atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE  | ATC_DST_H2SEL_HW |
                                                ATC_DST_PER(AT_DMA_ID_AES_TX);
 
-       aes_data.dma_slave = alt_atslave;
+       aes_data.dma_slave = &alt_atslave;
        platform_device_register(&at91sam9g45_aes_device);
 }
 #else
index 63947a8..a3a0ed8 100644 (file)
@@ -2,6 +2,10 @@
 # Arch-specific CryptoAPI modules.
 #
 
+avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no)
+avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
+                                       $(comma)4)$(comma)%ymm2,yes,no)
+
 obj-$(CONFIG_CRYPTO_ABLK_HELPER_X86) += ablk_helper.o
 obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o
 
@@ -12,22 +16,37 @@ obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o
 
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o
-obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64) += camellia-aesni-avx-x86_64.o
-obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o
-obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o
 obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
-obj-$(CONFIG_CRYPTO_TWOFISH_AVX_X86_64) += twofish-avx-x86_64.o
 obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
 obj-$(CONFIG_CRYPTO_SERPENT_SSE2_X86_64) += serpent-sse2-x86_64.o
-obj-$(CONFIG_CRYPTO_SERPENT_AVX_X86_64) += serpent-avx-x86_64.o
 obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
 obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
 
 obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
 obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
 obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
+obj-$(CONFIG_CRYPTO_SHA256_SSSE3) += sha256-ssse3.o
+obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
+
+# These modules require assembler to support AVX.
+ifeq ($(avx_supported),yes)
+       obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64) += \
+                                               camellia-aesni-avx-x86_64.o
+       obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o
+       obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o
+       obj-$(CONFIG_CRYPTO_TWOFISH_AVX_X86_64) += twofish-avx-x86_64.o
+       obj-$(CONFIG_CRYPTO_SERPENT_AVX_X86_64) += serpent-avx-x86_64.o
+endif
+
+# These modules require assembler to support AVX2.
+ifeq ($(avx2_supported),yes)
+       obj-$(CONFIG_CRYPTO_BLOWFISH_AVX2_X86_64) += blowfish-avx2.o
+       obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64) += camellia-aesni-avx2.o
+       obj-$(CONFIG_CRYPTO_SERPENT_AVX2_X86_64) += serpent-avx2.o
+       obj-$(CONFIG_CRYPTO_TWOFISH_AVX2_X86_64) += twofish-avx2.o
+endif
 
 aes-i586-y := aes-i586-asm_32.o aes_glue.o
 twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
@@ -36,21 +55,35 @@ serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o
 
 aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
 camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o
-camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o \
-                              camellia_aesni_avx_glue.o
-cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o
-cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_glue.o
 blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
 twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
 twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
-twofish-avx-x86_64-y := twofish-avx-x86_64-asm_64.o twofish_avx_glue.o
 salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
 serpent-sse2-x86_64-y := serpent-sse2-x86_64-asm_64.o serpent_sse2_glue.o
-serpent-avx-x86_64-y := serpent-avx-x86_64-asm_64.o serpent_avx_glue.o
+
+ifeq ($(avx_supported),yes)
+       camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o \
+                                       camellia_aesni_avx_glue.o
+       cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o
+       cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_glue.o
+       twofish-avx-x86_64-y := twofish-avx-x86_64-asm_64.o \
+                               twofish_avx_glue.o
+       serpent-avx-x86_64-y := serpent-avx-x86_64-asm_64.o \
+                               serpent_avx_glue.o
+endif
+
+ifeq ($(avx2_supported),yes)
+       blowfish-avx2-y := blowfish-avx2-asm_64.o blowfish_avx2_glue.o
+       camellia-aesni-avx2-y := camellia-aesni-avx2-asm_64.o camellia_aesni_avx2_glue.o
+       serpent-avx2-y := serpent-avx2-asm_64.o serpent_avx2_glue.o
+       twofish-avx2-y := twofish-avx2-asm_64.o twofish_avx2_glue.o
+endif
 
 aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o
 ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
 sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o
 crc32c-intel-y := crc32c-intel_glue.o
-crc32c-intel-$(CONFIG_CRYPTO_CRC32C_X86_64) += crc32c-pcl-intel-asm_64.o
+crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o
 crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o
+sha256-ssse3-y := sha256-ssse3-asm.o sha256-avx-asm.o sha256-avx2-asm.o sha256_ssse3_glue.o
+sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
index 04b7977..62fe22c 100644 (file)
 
 #ifdef __x86_64__
 .data
+.align 16
+.Lgf128mul_x_ble_mask:
+       .octa 0x00000000000000010000000000000087
+
 POLY:   .octa 0xC2000000000000000000000000000001
 TWOONE: .octa 0x00000001000000000000000000000001
 
@@ -105,6 +109,8 @@ enc:        .octa 0x2
 #define CTR    %xmm11
 #define INC    %xmm12
 
+#define GF128MUL_MASK %xmm10
+
 #ifdef __x86_64__
 #define AREG   %rax
 #define KEYP   %rdi
@@ -2636,4 +2642,115 @@ ENTRY(aesni_ctr_enc)
 .Lctr_enc_just_ret:
        ret
 ENDPROC(aesni_ctr_enc)
+
+/*
+ * _aesni_gf128mul_x_ble:              internal ABI
+ *     Multiply in GF(2^128) for XTS IVs
+ * input:
+ *     IV:     current IV
+ *     GF128MUL_MASK == mask with 0x87 and 0x01
+ * output:
+ *     IV:     next IV
+ * changed:
+ *     CTR:    == temporary value
+ */
+#define _aesni_gf128mul_x_ble() \
+       pshufd $0x13, IV, CTR; \
+       paddq IV, IV; \
+       psrad $31, CTR; \
+       pand GF128MUL_MASK, CTR; \
+       pxor CTR, IV;
+
+/*
+ * void aesni_xts_crypt8(struct crypto_aes_ctx *ctx, const u8 *dst, u8 *src,
+ *                      bool enc, u8 *iv)
+ */
+ENTRY(aesni_xts_crypt8)
+       cmpb $0, %cl
+       movl $0, %ecx
+       movl $240, %r10d
+       leaq _aesni_enc4, %r11
+       leaq _aesni_dec4, %rax
+       cmovel %r10d, %ecx
+       cmoveq %rax, %r11
+
+       movdqa .Lgf128mul_x_ble_mask, GF128MUL_MASK
+       movups (IVP), IV
+
+       mov 480(KEYP), KLEN
+       addq %rcx, KEYP
+
+       movdqa IV, STATE1
+       pxor 0x00(INP), STATE1
+       movdqu IV, 0x00(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movdqa IV, STATE2
+       pxor 0x10(INP), STATE2
+       movdqu IV, 0x10(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movdqa IV, STATE3
+       pxor 0x20(INP), STATE3
+       movdqu IV, 0x20(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movdqa IV, STATE4
+       pxor 0x30(INP), STATE4
+       movdqu IV, 0x30(OUTP)
+
+       call *%r11
+
+       pxor 0x00(OUTP), STATE1
+       movdqu STATE1, 0x00(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movdqa IV, STATE1
+       pxor 0x40(INP), STATE1
+       movdqu IV, 0x40(OUTP)
+
+       pxor 0x10(OUTP), STATE2
+       movdqu STATE2, 0x10(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movdqa IV, STATE2
+       pxor 0x50(INP), STATE2
+       movdqu IV, 0x50(OUTP)
+
+       pxor 0x20(OUTP), STATE3
+       movdqu STATE3, 0x20(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movdqa IV, STATE3
+       pxor 0x60(INP), STATE3
+       movdqu IV, 0x60(OUTP)
+
+       pxor 0x30(OUTP), STATE4
+       movdqu STATE4, 0x30(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movdqa IV, STATE4
+       pxor 0x70(INP), STATE4
+       movdqu IV, 0x70(OUTP)
+
+       _aesni_gf128mul_x_ble()
+       movups IV, (IVP)
+
+       call *%r11
+
+       pxor 0x40(OUTP), STATE1
+       movdqu STATE1, 0x40(OUTP)
+
+       pxor 0x50(OUTP), STATE2
+       movdqu STATE2, 0x50(OUTP)
+
+       pxor 0x60(OUTP), STATE3
+       movdqu STATE3, 0x60(OUTP)
+
+       pxor 0x70(OUTP), STATE4
+       movdqu STATE4, 0x70(OUTP)
+
+       ret
+ENDPROC(aesni_xts_crypt8)
+
 #endif
index a0795da..f80e668 100644 (file)
@@ -39,6 +39,9 @@
 #include <crypto/internal/aead.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#ifdef CONFIG_X86_64
+#include <asm/crypto/glue_helper.h>
+#endif
 
 #if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE)
 #define HAS_PCBC
@@ -102,6 +105,9 @@ void crypto_fpu_exit(void);
 asmlinkage void aesni_ctr_enc(struct crypto_aes_ctx *ctx, u8 *out,
                              const u8 *in, unsigned int len, u8 *iv);
 
+asmlinkage void aesni_xts_crypt8(struct crypto_aes_ctx *ctx, u8 *out,
+                                const u8 *in, bool enc, u8 *iv);
+
 /* asmlinkage void aesni_gcm_enc()
  * void *ctx,  AES Key schedule. Starts on a 16 byte boundary.
  * u8 *out, Ciphertext output. Encrypt in-place is allowed.
@@ -510,6 +516,78 @@ static void aesni_xts_tweak(void *ctx, u8 *out, const u8 *in)
        aesni_enc(ctx, out, in);
 }
 
+#ifdef CONFIG_X86_64
+
+static void aesni_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv, GLUE_FUNC_CAST(aesni_enc));
+}
+
+static void aesni_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv, GLUE_FUNC_CAST(aesni_dec));
+}
+
+static void aesni_xts_enc8(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       aesni_xts_crypt8(ctx, (u8 *)dst, (const u8 *)src, true, (u8 *)iv);
+}
+
+static void aesni_xts_dec8(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       aesni_xts_crypt8(ctx, (u8 *)dst, (const u8 *)src, false, (u8 *)iv);
+}
+
+static const struct common_glue_ctx aesni_enc_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = 1,
+
+       .funcs = { {
+               .num_blocks = 8,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_enc8) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_enc) }
+       } }
+};
+
+static const struct common_glue_ctx aesni_dec_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = 1,
+
+       .funcs = { {
+               .num_blocks = 8,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_dec8) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(aesni_xts_dec) }
+       } }
+};
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct aesni_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+
+       return glue_xts_crypt_128bit(&aesni_enc_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(aesni_xts_tweak),
+                                    aes_ctx(ctx->raw_tweak_ctx),
+                                    aes_ctx(ctx->raw_crypt_ctx));
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct aesni_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+
+       return glue_xts_crypt_128bit(&aesni_dec_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(aesni_xts_tweak),
+                                    aes_ctx(ctx->raw_tweak_ctx),
+                                    aes_ctx(ctx->raw_crypt_ctx));
+}
+
+#else
+
 static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
@@ -560,6 +638,8 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return ret;
 }
 
+#endif
+
 #ifdef CONFIG_X86_64
 static int rfc4106_init(struct crypto_tfm *tfm)
 {
diff --git a/arch/x86/crypto/blowfish-avx2-asm_64.S b/arch/x86/crypto/blowfish-avx2-asm_64.S
new file mode 100644 (file)
index 0000000..784452e
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * x86_64/AVX2 assembler optimized version of Blowfish
+ *
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/linkage.h>
+
+.file "blowfish-avx2-asm_64.S"
+
+.data
+.align 32
+
+.Lprefetch_mask:
+.long 0*64
+.long 1*64
+.long 2*64
+.long 3*64
+.long 4*64
+.long 5*64
+.long 6*64
+.long 7*64
+
+.Lbswap32_mask:
+.long 0x00010203
+.long 0x04050607
+.long 0x08090a0b
+.long 0x0c0d0e0f
+
+.Lbswap128_mask:
+       .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+.Lbswap_iv_mask:
+       .byte 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0
+
+.text
+/* structure of crypto context */
+#define p      0
+#define s0     ((16 + 2) * 4)
+#define s1     ((16 + 2 + (1 * 256)) * 4)
+#define s2     ((16 + 2 + (2 * 256)) * 4)
+#define s3     ((16 + 2 + (3 * 256)) * 4)
+
+/* register macros */
+#define CTX    %rdi
+#define RIO     %rdx
+
+#define RS0    %rax
+#define RS1    %r8
+#define RS2    %r9
+#define RS3    %r10
+
+#define RLOOP  %r11
+#define RLOOPd %r11d
+
+#define RXr0   %ymm8
+#define RXr1   %ymm9
+#define RXr2   %ymm10
+#define RXr3   %ymm11
+#define RXl0   %ymm12
+#define RXl1   %ymm13
+#define RXl2   %ymm14
+#define RXl3   %ymm15
+
+/* temp regs */
+#define RT0    %ymm0
+#define RT0x   %xmm0
+#define RT1    %ymm1
+#define RT1x   %xmm1
+#define RIDX0  %ymm2
+#define RIDX1  %ymm3
+#define RIDX1x %xmm3
+#define RIDX2  %ymm4
+#define RIDX3  %ymm5
+
+/* vpgatherdd mask and '-1' */
+#define RNOT   %ymm6
+
+/* byte mask, (-1 >> 24) */
+#define RBYTE  %ymm7
+
+/***********************************************************************
+ * 32-way AVX2 blowfish
+ ***********************************************************************/
+#define F(xl, xr) \
+       vpsrld $24, xl, RIDX0; \
+       vpsrld $16, xl, RIDX1; \
+       vpsrld $8, xl, RIDX2; \
+       vpand RBYTE, RIDX1, RIDX1; \
+       vpand RBYTE, RIDX2, RIDX2; \
+       vpand RBYTE, xl, RIDX3; \
+       \
+       vpgatherdd RNOT, (RS0, RIDX0, 4), RT0; \
+       vpcmpeqd RNOT, RNOT, RNOT; \
+       vpcmpeqd RIDX0, RIDX0, RIDX0; \
+       \
+       vpgatherdd RNOT, (RS1, RIDX1, 4), RT1; \
+       vpcmpeqd RIDX1, RIDX1, RIDX1; \
+       vpaddd RT0, RT1, RT0; \
+       \
+       vpgatherdd RIDX0, (RS2, RIDX2, 4), RT1; \
+       vpxor RT0, RT1, RT0; \
+       \
+       vpgatherdd RIDX1, (RS3, RIDX3, 4), RT1; \
+       vpcmpeqd RNOT, RNOT, RNOT; \
+       vpaddd RT0, RT1, RT0; \
+       \
+       vpxor RT0, xr, xr;
+
+#define add_roundkey(xl, nmem) \
+       vpbroadcastd nmem, RT0; \
+       vpxor RT0, xl ## 0, xl ## 0; \
+       vpxor RT0, xl ## 1, xl ## 1; \
+       vpxor RT0, xl ## 2, xl ## 2; \
+       vpxor RT0, xl ## 3, xl ## 3;
+
+#define round_enc() \
+       add_roundkey(RXr, p(CTX,RLOOP,4)); \
+       F(RXl0, RXr0); \
+       F(RXl1, RXr1); \
+       F(RXl2, RXr2); \
+       F(RXl3, RXr3); \
+       \
+       add_roundkey(RXl, p+4(CTX,RLOOP,4)); \
+       F(RXr0, RXl0); \
+       F(RXr1, RXl1); \
+       F(RXr2, RXl2); \
+       F(RXr3, RXl3);
+
+#define round_dec() \
+       add_roundkey(RXr, p+4*2(CTX,RLOOP,4)); \
+       F(RXl0, RXr0); \
+       F(RXl1, RXr1); \
+       F(RXl2, RXr2); \
+       F(RXl3, RXr3); \
+       \
+       add_roundkey(RXl, p+4(CTX,RLOOP,4)); \
+       F(RXr0, RXl0); \
+       F(RXr1, RXl1); \
+       F(RXr2, RXl2); \
+       F(RXr3, RXl3);
+
+#define init_round_constants() \
+       vpcmpeqd RNOT, RNOT, RNOT; \
+       leaq s0(CTX), RS0; \
+       leaq s1(CTX), RS1; \
+       leaq s2(CTX), RS2; \
+       leaq s3(CTX), RS3; \
+       vpsrld $24, RNOT, RBYTE;
+
+#define transpose_2x2(x0, x1, t0) \
+       vpunpckldq x0, x1, t0; \
+       vpunpckhdq x0, x1, x1; \
+       \
+       vpunpcklqdq t0, x1, x0; \
+       vpunpckhqdq t0, x1, x1;
+
+#define read_block(xl, xr) \
+       vbroadcasti128 .Lbswap32_mask, RT1; \
+       \
+       vpshufb RT1, xl ## 0, xl ## 0; \
+       vpshufb RT1, xr ## 0, xr ## 0; \
+       vpshufb RT1, xl ## 1, xl ## 1; \
+       vpshufb RT1, xr ## 1, xr ## 1; \
+       vpshufb RT1, xl ## 2, xl ## 2; \
+       vpshufb RT1, xr ## 2, xr ## 2; \
+       vpshufb RT1, xl ## 3, xl ## 3; \
+       vpshufb RT1, xr ## 3, xr ## 3; \
+       \
+       transpose_2x2(xl ## 0, xr ## 0, RT0); \
+       transpose_2x2(xl ## 1, xr ## 1, RT0); \
+       transpose_2x2(xl ## 2, xr ## 2, RT0); \
+       transpose_2x2(xl ## 3, xr ## 3, RT0);
+
+#define write_block(xl, xr) \
+       vbroadcasti128 .Lbswap32_mask, RT1; \
+       \
+       transpose_2x2(xl ## 0, xr ## 0, RT0); \
+       transpose_2x2(xl ## 1, xr ## 1, RT0); \
+       transpose_2x2(xl ## 2, xr ## 2, RT0); \
+       transpose_2x2(xl ## 3, xr ## 3, RT0); \
+       \
+       vpshufb RT1, xl ## 0, xl ## 0; \
+       vpshufb RT1, xr ## 0, xr ## 0; \
+       vpshufb RT1, xl ## 1, xl ## 1; \
+       vpshufb RT1, xr ## 1, xr ## 1; \
+       vpshufb RT1, xl ## 2, xl ## 2; \
+       vpshufb RT1, xr ## 2, xr ## 2; \
+       vpshufb RT1, xl ## 3, xl ## 3; \
+       vpshufb RT1, xr ## 3, xr ## 3;
+
+.align 8
+__blowfish_enc_blk32:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      RXl0..4, RXr0..4: plaintext
+        * output:
+        *      RXl0..4, RXr0..4: ciphertext (RXl <=> RXr swapped)
+        */
+       init_round_constants();
+
+       read_block(RXl, RXr);
+
+       movl $1, RLOOPd;
+       add_roundkey(RXl, p+4*(0)(CTX));
+
+.align 4
+.L__enc_loop:
+       round_enc();
+
+       leal 2(RLOOPd), RLOOPd;
+       cmpl $17, RLOOPd;
+       jne .L__enc_loop;
+
+       add_roundkey(RXr, p+4*(17)(CTX));
+
+       write_block(RXl, RXr);
+
+       ret;
+ENDPROC(__blowfish_enc_blk32)
+
+.align 8
+__blowfish_dec_blk32:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      RXl0..4, RXr0..4: ciphertext
+        * output:
+        *      RXl0..4, RXr0..4: plaintext (RXl <=> RXr swapped)
+        */
+       init_round_constants();
+
+       read_block(RXl, RXr);
+
+       movl $14, RLOOPd;
+       add_roundkey(RXl, p+4*(17)(CTX));
+
+.align 4
+.L__dec_loop:
+       round_dec();
+
+       addl $-2, RLOOPd;
+       jns .L__dec_loop;
+
+       add_roundkey(RXr, p+4*(0)(CTX));
+
+       write_block(RXl, RXr);
+
+       ret;
+ENDPROC(__blowfish_dec_blk32)
+
+ENTRY(blowfish_ecb_enc_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       vzeroupper;
+
+       vmovdqu 0*32(%rdx), RXl0;
+       vmovdqu 1*32(%rdx), RXr0;
+       vmovdqu 2*32(%rdx), RXl1;
+       vmovdqu 3*32(%rdx), RXr1;
+       vmovdqu 4*32(%rdx), RXl2;
+       vmovdqu 5*32(%rdx), RXr2;
+       vmovdqu 6*32(%rdx), RXl3;
+       vmovdqu 7*32(%rdx), RXr3;
+
+       call __blowfish_enc_blk32;
+
+       vmovdqu RXr0, 0*32(%rsi);
+       vmovdqu RXl0, 1*32(%rsi);
+       vmovdqu RXr1, 2*32(%rsi);
+       vmovdqu RXl1, 3*32(%rsi);
+       vmovdqu RXr2, 4*32(%rsi);
+       vmovdqu RXl2, 5*32(%rsi);
+       vmovdqu RXr3, 6*32(%rsi);
+       vmovdqu RXl3, 7*32(%rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(blowfish_ecb_enc_32way)
+
+ENTRY(blowfish_ecb_dec_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       vzeroupper;
+
+       vmovdqu 0*32(%rdx), RXl0;
+       vmovdqu 1*32(%rdx), RXr0;
+       vmovdqu 2*32(%rdx), RXl1;
+       vmovdqu 3*32(%rdx), RXr1;
+       vmovdqu 4*32(%rdx), RXl2;
+       vmovdqu 5*32(%rdx), RXr2;
+       vmovdqu 6*32(%rdx), RXl3;
+       vmovdqu 7*32(%rdx), RXr3;
+
+       call __blowfish_dec_blk32;
+
+       vmovdqu RXr0, 0*32(%rsi);
+       vmovdqu RXl0, 1*32(%rsi);
+       vmovdqu RXr1, 2*32(%rsi);
+       vmovdqu RXl1, 3*32(%rsi);
+       vmovdqu RXr2, 4*32(%rsi);
+       vmovdqu RXl2, 5*32(%rsi);
+       vmovdqu RXr3, 6*32(%rsi);
+       vmovdqu RXl3, 7*32(%rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(blowfish_ecb_dec_32way)
+
+ENTRY(blowfish_cbc_dec_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       vzeroupper;
+
+       vmovdqu 0*32(%rdx), RXl0;
+       vmovdqu 1*32(%rdx), RXr0;
+       vmovdqu 2*32(%rdx), RXl1;
+       vmovdqu 3*32(%rdx), RXr1;
+       vmovdqu 4*32(%rdx), RXl2;
+       vmovdqu 5*32(%rdx), RXr2;
+       vmovdqu 6*32(%rdx), RXl3;
+       vmovdqu 7*32(%rdx), RXr3;
+
+       call __blowfish_dec_blk32;
+
+       /* xor with src */
+       vmovq (%rdx), RT0x;
+       vpshufd $0x4f, RT0x, RT0x;
+       vinserti128 $1, 8(%rdx), RT0, RT0;
+       vpxor RT0, RXr0, RXr0;
+       vpxor 0*32+24(%rdx), RXl0, RXl0;
+       vpxor 1*32+24(%rdx), RXr1, RXr1;
+       vpxor 2*32+24(%rdx), RXl1, RXl1;
+       vpxor 3*32+24(%rdx), RXr2, RXr2;
+       vpxor 4*32+24(%rdx), RXl2, RXl2;
+       vpxor 5*32+24(%rdx), RXr3, RXr3;
+       vpxor 6*32+24(%rdx), RXl3, RXl3;
+
+       vmovdqu RXr0, (0*32)(%rsi);
+       vmovdqu RXl0, (1*32)(%rsi);
+       vmovdqu RXr1, (2*32)(%rsi);
+       vmovdqu RXl1, (3*32)(%rsi);
+       vmovdqu RXr2, (4*32)(%rsi);
+       vmovdqu RXl2, (5*32)(%rsi);
+       vmovdqu RXr3, (6*32)(%rsi);
+       vmovdqu RXl3, (7*32)(%rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(blowfish_cbc_dec_32way)
+
+ENTRY(blowfish_ctr_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: iv (big endian, 64bit)
+        */
+
+       vzeroupper;
+
+       vpcmpeqd RT0, RT0, RT0;
+       vpsrldq $8, RT0, RT0; /* a: -1, b: 0, c: -1, d: 0 */
+
+       vpcmpeqd RT1x, RT1x, RT1x;
+       vpaddq RT1x, RT1x, RT1x; /* a: -2, b: -2 */
+       vpxor RIDX0, RIDX0, RIDX0;
+       vinserti128 $1, RT1x, RIDX0, RIDX0; /* a: 0, b: 0, c: -2, d: -2 */
+
+       vpaddq RIDX0, RT0, RT0; /* a: -1, b: 0, c: -3, d: -2 */
+
+       vpcmpeqd RT1, RT1, RT1;
+       vpaddq RT1, RT1, RT1; /* a: -2, b: -2, c: -2, d: -2 */
+       vpaddq RT1, RT1, RIDX2; /* a: -4, b: -4, c: -4, d: -4 */
+
+       vbroadcasti128 .Lbswap_iv_mask, RIDX0;
+       vbroadcasti128 .Lbswap128_mask, RIDX1;
+
+       /* load IV and byteswap */
+       vmovq (%rcx), RT1x;
+       vinserti128 $1, RT1x, RT1, RT1; /* a: BE, b: 0, c: BE, d: 0 */
+       vpshufb RIDX0, RT1, RT1; /* a: LE, b: LE, c: LE, d: LE */
+
+       /* construct IVs */
+       vpsubq RT0, RT1, RT1;           /* a: le1, b: le0, c: le3, d: le2 */
+       vpshufb RIDX1, RT1, RXl0;       /* a: be0, b: be1, c: be2, d: be3 */
+       vpsubq RIDX2, RT1, RT1;         /* le5, le4, le7, le6 */
+       vpshufb RIDX1, RT1, RXr0;       /* be4, be5, be6, be7 */
+       vpsubq RIDX2, RT1, RT1;
+       vpshufb RIDX1, RT1, RXl1;
+       vpsubq RIDX2, RT1, RT1;
+       vpshufb RIDX1, RT1, RXr1;
+       vpsubq RIDX2, RT1, RT1;
+       vpshufb RIDX1, RT1, RXl2;
+       vpsubq RIDX2, RT1, RT1;
+       vpshufb RIDX1, RT1, RXr2;
+       vpsubq RIDX2, RT1, RT1;
+       vpshufb RIDX1, RT1, RXl3;
+       vpsubq RIDX2, RT1, RT1;
+       vpshufb RIDX1, RT1, RXr3;
+
+       /* store last IV */
+       vpsubq RIDX2, RT1, RT1; /* a: le33, b: le32, ... */
+       vpshufb RIDX1x, RT1x, RT1x; /* a: be32, ... */
+       vmovq RT1x, (%rcx);
+
+       call __blowfish_enc_blk32;
+
+       /* dst = src ^ iv */
+       vpxor 0*32(%rdx), RXr0, RXr0;
+       vpxor 1*32(%rdx), RXl0, RXl0;
+       vpxor 2*32(%rdx), RXr1, RXr1;
+       vpxor 3*32(%rdx), RXl1, RXl1;
+       vpxor 4*32(%rdx), RXr2, RXr2;
+       vpxor 5*32(%rdx), RXl2, RXl2;
+       vpxor 6*32(%rdx), RXr3, RXr3;
+       vpxor 7*32(%rdx), RXl3, RXl3;
+       vmovdqu RXr0, (0*32)(%rsi);
+       vmovdqu RXl0, (1*32)(%rsi);
+       vmovdqu RXr1, (2*32)(%rsi);
+       vmovdqu RXl1, (3*32)(%rsi);
+       vmovdqu RXr2, (4*32)(%rsi);
+       vmovdqu RXl2, (5*32)(%rsi);
+       vmovdqu RXr3, (6*32)(%rsi);
+       vmovdqu RXl3, (7*32)(%rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(blowfish_ctr_32way)
diff --git a/arch/x86/crypto/blowfish_avx2_glue.c b/arch/x86/crypto/blowfish_avx2_glue.c
new file mode 100644 (file)
index 0000000..4417e9a
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * Glue Code for x86_64/AVX2 assembler optimized version of Blowfish
+ *
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
+ *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ * CTR part based on code (crypto/ctr.c) by:
+ *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/blowfish.h>
+#include <crypto/cryptd.h>
+#include <crypto/ctr.h>
+#include <asm/i387.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/crypto/blowfish.h>
+#include <asm/crypto/ablk_helper.h>
+#include <crypto/scatterwalk.h>
+
+#define BF_AVX2_PARALLEL_BLOCKS 32
+
+/* 32-way AVX2 parallel cipher functions */
+asmlinkage void blowfish_ecb_enc_32way(struct bf_ctx *ctx, u8 *dst,
+                                      const u8 *src);
+asmlinkage void blowfish_ecb_dec_32way(struct bf_ctx *ctx, u8 *dst,
+                                      const u8 *src);
+asmlinkage void blowfish_cbc_dec_32way(struct bf_ctx *ctx, u8 *dst,
+                                      const u8 *src);
+asmlinkage void blowfish_ctr_32way(struct bf_ctx *ctx, u8 *dst, const u8 *src,
+                                  __be64 *iv);
+
+static inline bool bf_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+       if (fpu_enabled)
+               return true;
+
+       /* FPU is only used when chunk to be processed is large enough, so
+        * do not enable FPU until it is necessary.
+        */
+       if (nbytes < BF_BLOCK_SIZE * BF_AVX2_PARALLEL_BLOCKS)
+               return false;
+
+       kernel_fpu_begin();
+       return true;
+}
+
+static inline void bf_fpu_end(bool fpu_enabled)
+{
+       if (fpu_enabled)
+               kernel_fpu_end();
+}
+
+static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+                    bool enc)
+{
+       bool fpu_enabled = false;
+       struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = BF_BLOCK_SIZE;
+       unsigned int nbytes;
+       int err;
+
+       err = blkcipher_walk_virt(desc, walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk->nbytes)) {
+               u8 *wsrc = walk->src.virt.addr;
+               u8 *wdst = walk->dst.virt.addr;
+
+               fpu_enabled = bf_fpu_begin(fpu_enabled, nbytes);
+
+               /* Process multi-block AVX2 batch */
+               if (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS) {
+                       do {
+                               if (enc)
+                                       blowfish_ecb_enc_32way(ctx, wdst, wsrc);
+                               else
+                                       blowfish_ecb_dec_32way(ctx, wdst, wsrc);
+
+                               wsrc += bsize * BF_AVX2_PARALLEL_BLOCKS;
+                               wdst += bsize * BF_AVX2_PARALLEL_BLOCKS;
+                               nbytes -= bsize * BF_AVX2_PARALLEL_BLOCKS;
+                       } while (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS);
+
+                       if (nbytes < bsize)
+                               goto done;
+               }
+
+               /* Process multi-block batch */
+               if (nbytes >= bsize * BF_PARALLEL_BLOCKS) {
+                       do {
+                               if (enc)
+                                       blowfish_enc_blk_4way(ctx, wdst, wsrc);
+                               else
+                                       blowfish_dec_blk_4way(ctx, wdst, wsrc);
+
+                               wsrc += bsize * BF_PARALLEL_BLOCKS;
+                               wdst += bsize * BF_PARALLEL_BLOCKS;
+                               nbytes -= bsize * BF_PARALLEL_BLOCKS;
+                       } while (nbytes >= bsize * BF_PARALLEL_BLOCKS);
+
+                       if (nbytes < bsize)
+                               goto done;
+               }
+
+               /* Handle leftovers */
+               do {
+                       if (enc)
+                               blowfish_enc_blk(ctx, wdst, wsrc);
+                       else
+                               blowfish_dec_blk(ctx, wdst, wsrc);
+
+                       wsrc += bsize;
+                       wdst += bsize;
+                       nbytes -= bsize;
+               } while (nbytes >= bsize);
+
+done:
+               err = blkcipher_walk_done(desc, walk, nbytes);
+       }
+
+       bf_fpu_end(fpu_enabled);
+       return err;
+}
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, true);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, false);
+}
+
+static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       unsigned int bsize = BF_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u64 *src = (u64 *)walk->src.virt.addr;
+       u64 *dst = (u64 *)walk->dst.virt.addr;
+       u64 *iv = (u64 *)walk->iv;
+
+       do {
+               *dst = *src ^ *iv;
+               blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
+               iv = dst;
+
+               src += 1;
+               dst += 1;
+               nbytes -= bsize;
+       } while (nbytes >= bsize);
+
+       *(u64 *)walk->iv = *iv;
+       return nbytes;
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       while ((nbytes = walk.nbytes)) {
+               nbytes = __cbc_encrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       return err;
+}
+
+static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = BF_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u64 *src = (u64 *)walk->src.virt.addr;
+       u64 *dst = (u64 *)walk->dst.virt.addr;
+       u64 last_iv;
+       int i;
+
+       /* Start of the last block. */
+       src += nbytes / bsize - 1;
+       dst += nbytes / bsize - 1;
+
+       last_iv = *src;
+
+       /* Process multi-block AVX2 batch */
+       if (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS) {
+               do {
+                       nbytes -= bsize * (BF_AVX2_PARALLEL_BLOCKS - 1);
+                       src -= BF_AVX2_PARALLEL_BLOCKS - 1;
+                       dst -= BF_AVX2_PARALLEL_BLOCKS - 1;
+
+                       blowfish_cbc_dec_32way(ctx, (u8 *)dst, (u8 *)src);
+
+                       nbytes -= bsize;
+                       if (nbytes < bsize)
+                               goto done;
+
+                       *dst ^= *(src - 1);
+                       src -= 1;
+                       dst -= 1;
+               } while (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Process multi-block batch */
+       if (nbytes >= bsize * BF_PARALLEL_BLOCKS) {
+               u64 ivs[BF_PARALLEL_BLOCKS - 1];
+
+               do {
+                       nbytes -= bsize * (BF_PARALLEL_BLOCKS - 1);
+                       src -= BF_PARALLEL_BLOCKS - 1;
+                       dst -= BF_PARALLEL_BLOCKS - 1;
+
+                       for (i = 0; i < BF_PARALLEL_BLOCKS - 1; i++)
+                               ivs[i] = src[i];
+
+                       blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src);
+
+                       for (i = 0; i < BF_PARALLEL_BLOCKS - 1; i++)
+                               dst[i + 1] ^= ivs[i];
+
+                       nbytes -= bsize;
+                       if (nbytes < bsize)
+                               goto done;
+
+                       *dst ^= *(src - 1);
+                       src -= 1;
+                       dst -= 1;
+               } while (nbytes >= bsize * BF_PARALLEL_BLOCKS);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       for (;;) {
+               blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src);
+
+               nbytes -= bsize;
+               if (nbytes < bsize)
+                       break;
+
+               *dst ^= *(src - 1);
+               src -= 1;
+               dst -= 1;
+       }
+
+done:
+       *dst ^= *(u64 *)walk->iv;
+       *(u64 *)walk->iv = last_iv;
+
+       return nbytes;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       bool fpu_enabled = false;
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk.nbytes)) {
+               fpu_enabled = bf_fpu_begin(fpu_enabled, nbytes);
+               nbytes = __cbc_decrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       bf_fpu_end(fpu_enabled);
+       return err;
+}
+
+static void ctr_crypt_final(struct blkcipher_desc *desc,
+                           struct blkcipher_walk *walk)
+{
+       struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       u8 *ctrblk = walk->iv;
+       u8 keystream[BF_BLOCK_SIZE];
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+
+       blowfish_enc_blk(ctx, keystream, ctrblk);
+       crypto_xor(keystream, src, nbytes);
+       memcpy(dst, keystream, nbytes);
+
+       crypto_inc(ctrblk, BF_BLOCK_SIZE);
+}
+
+static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
+                               struct blkcipher_walk *walk)
+{
+       struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       unsigned int bsize = BF_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u64 *src = (u64 *)walk->src.virt.addr;
+       u64 *dst = (u64 *)walk->dst.virt.addr;
+       int i;
+
+       /* Process multi-block AVX2 batch */
+       if (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS) {
+               do {
+                       blowfish_ctr_32way(ctx, (u8 *)dst, (u8 *)src,
+                                          (__be64 *)walk->iv);
+
+                       src += BF_AVX2_PARALLEL_BLOCKS;
+                       dst += BF_AVX2_PARALLEL_BLOCKS;
+                       nbytes -= bsize * BF_AVX2_PARALLEL_BLOCKS;
+               } while (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Process four block batch */
+       if (nbytes >= bsize * BF_PARALLEL_BLOCKS) {
+               __be64 ctrblocks[BF_PARALLEL_BLOCKS];
+               u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
+
+               do {
+                       /* create ctrblks for parallel encrypt */
+                       for (i = 0; i < BF_PARALLEL_BLOCKS; i++) {
+                               if (dst != src)
+                                       dst[i] = src[i];
+
+                               ctrblocks[i] = cpu_to_be64(ctrblk++);
+                       }
+
+                       blowfish_enc_blk_xor_4way(ctx, (u8 *)dst,
+                                                 (u8 *)ctrblocks);
+
+                       src += BF_PARALLEL_BLOCKS;
+                       dst += BF_PARALLEL_BLOCKS;
+                       nbytes -= bsize * BF_PARALLEL_BLOCKS;
+               } while (nbytes >= bsize * BF_PARALLEL_BLOCKS);
+
+               *(__be64 *)walk->iv = cpu_to_be64(ctrblk);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       do {
+               u64 ctrblk;
+
+               if (dst != src)
+                       *dst = *src;
+
+               ctrblk = *(u64 *)walk->iv;
+               be64_add_cpu((__be64 *)walk->iv, 1);
+
+               blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)&ctrblk);
+
+               src += 1;
+               dst += 1;
+       } while ((nbytes -= bsize) >= bsize);
+
+done:
+       return nbytes;
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes)
+{
+       bool fpu_enabled = false;
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, BF_BLOCK_SIZE);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) {
+               fpu_enabled = bf_fpu_begin(fpu_enabled, nbytes);
+               nbytes = __ctr_crypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       bf_fpu_end(fpu_enabled);
+
+       if (walk.nbytes) {
+               ctr_crypt_final(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
+static struct crypto_alg bf_algs[6] = { {
+       .cra_name               = "__ecb-blowfish-avx2",
+       .cra_driver_name        = "__driver-ecb-blowfish-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = BF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct bf_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .setkey         = blowfish_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__cbc-blowfish-avx2",
+       .cra_driver_name        = "__driver-cbc-blowfish-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = BF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct bf_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .setkey         = blowfish_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__ctr-blowfish-avx2",
+       .cra_driver_name        = "__driver-ctr-blowfish-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct bf_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .ivsize         = BF_BLOCK_SIZE,
+                       .setkey         = blowfish_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "ecb(blowfish)",
+       .cra_driver_name        = "ecb-blowfish-avx2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = BF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(blowfish)",
+       .cra_driver_name        = "cbc-blowfish-avx2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = BF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .ivsize         = BF_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = __ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ctr(blowfish)",
+       .cra_driver_name        = "ctr-blowfish-avx2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = BF_MIN_KEY_SIZE,
+                       .max_keysize    = BF_MAX_KEY_SIZE,
+                       .ivsize         = BF_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_encrypt,
+                       .geniv          = "chainiv",
+               },
+       },
+} };
+
+
+static int __init init(void)
+{
+       u64 xcr0;
+
+       if (!cpu_has_avx2 || !cpu_has_osxsave) {
+               pr_info("AVX2 instructions are not detected.\n");
+               return -ENODEV;
+       }
+
+       xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+       if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+               pr_info("AVX detected but unusable.\n");
+               return -ENODEV;
+       }
+
+       return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs));
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs));
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Blowfish Cipher Algorithm, AVX2 optimized");
+MODULE_ALIAS("blowfish");
+MODULE_ALIAS("blowfish-asm");
index 50ec333..3548d76 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Glue Code for assembler optimized version of Blowfish
  *
- * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2011-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
  *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <crypto/algapi.h>
+#include <asm/crypto/blowfish.h>
 
 /* regular block cipher functions */
 asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src,
                                   bool xor);
+EXPORT_SYMBOL_GPL(__blowfish_enc_blk);
+
 asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src);
+EXPORT_SYMBOL_GPL(blowfish_dec_blk);
 
 /* 4-way parallel cipher functions */
 asmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
                                        const u8 *src, bool xor);
+EXPORT_SYMBOL_GPL(__blowfish_enc_blk_4way);
+
 asmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst,
                                      const u8 *src);
-
-static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src)
-{
-       __blowfish_enc_blk(ctx, dst, src, false);
-}
-
-static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst,
-                                       const u8 *src)
-{
-       __blowfish_enc_blk(ctx, dst, src, true);
-}
-
-static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
-                                        const u8 *src)
-{
-       __blowfish_enc_blk_4way(ctx, dst, src, false);
-}
-
-static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst,
-                                     const u8 *src)
-{
-       __blowfish_enc_blk_4way(ctx, dst, src, true);
-}
+EXPORT_SYMBOL_GPL(blowfish_dec_blk_4way);
 
 static void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
 {
index cfc1634..ce71f92 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * x86_64/AVX/AES-NI assembler implementation of Camellia
  *
- * Copyright © 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -589,6 +589,10 @@ ENDPROC(roundsm16_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
 .Lbswap128_mask:
        .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
 
+/* For XTS mode IV generation */
+.Lxts_gf128mul_and_shl1_mask:
+       .byte 0x87, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
+
 /*
  * pre-SubByte transform
  *
@@ -1090,3 +1094,177 @@ ENTRY(camellia_ctr_16way)
 
        ret;
 ENDPROC(camellia_ctr_16way)
+
+#define gf128mul_x_ble(iv, mask, tmp) \
+       vpsrad $31, iv, tmp; \
+       vpaddq iv, iv, iv; \
+       vpshufd $0x13, tmp, tmp; \
+       vpand mask, tmp, tmp; \
+       vpxor tmp, iv, iv;
+
+.align 8
+camellia_xts_crypt_16way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (16 blocks)
+        *      %rdx: src (16 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        *      %r8: index for input whitening key
+        *      %r9: pointer to  __camellia_enc_blk16 or __camellia_dec_blk16
+        */
+
+       subq $(16 * 16), %rsp;
+       movq %rsp, %rax;
+
+       vmovdqa .Lxts_gf128mul_and_shl1_mask, %xmm14;
+
+       /* load IV */
+       vmovdqu (%rcx), %xmm0;
+       vpxor 0 * 16(%rdx), %xmm0, %xmm15;
+       vmovdqu %xmm15, 15 * 16(%rax);
+       vmovdqu %xmm0, 0 * 16(%rsi);
+
+       /* construct IVs */
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 1 * 16(%rdx), %xmm0, %xmm15;
+       vmovdqu %xmm15, 14 * 16(%rax);
+       vmovdqu %xmm0, 1 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 2 * 16(%rdx), %xmm0, %xmm13;
+       vmovdqu %xmm0, 2 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 3 * 16(%rdx), %xmm0, %xmm12;
+       vmovdqu %xmm0, 3 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 4 * 16(%rdx), %xmm0, %xmm11;
+       vmovdqu %xmm0, 4 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 5 * 16(%rdx), %xmm0, %xmm10;
+       vmovdqu %xmm0, 5 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 6 * 16(%rdx), %xmm0, %xmm9;
+       vmovdqu %xmm0, 6 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 7 * 16(%rdx), %xmm0, %xmm8;
+       vmovdqu %xmm0, 7 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 8 * 16(%rdx), %xmm0, %xmm7;
+       vmovdqu %xmm0, 8 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 9 * 16(%rdx), %xmm0, %xmm6;
+       vmovdqu %xmm0, 9 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 10 * 16(%rdx), %xmm0, %xmm5;
+       vmovdqu %xmm0, 10 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 11 * 16(%rdx), %xmm0, %xmm4;
+       vmovdqu %xmm0, 11 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 12 * 16(%rdx), %xmm0, %xmm3;
+       vmovdqu %xmm0, 12 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 13 * 16(%rdx), %xmm0, %xmm2;
+       vmovdqu %xmm0, 13 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 14 * 16(%rdx), %xmm0, %xmm1;
+       vmovdqu %xmm0, 14 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vpxor 15 * 16(%rdx), %xmm0, %xmm15;
+       vmovdqu %xmm15, 0 * 16(%rax);
+       vmovdqu %xmm0, 15 * 16(%rsi);
+
+       gf128mul_x_ble(%xmm0, %xmm14, %xmm15);
+       vmovdqu %xmm0, (%rcx);
+
+       /* inpack16_pre: */
+       vmovq (key_table)(CTX, %r8, 8), %xmm15;
+       vpshufb .Lpack_bswap, %xmm15, %xmm15;
+       vpxor 0 * 16(%rax), %xmm15, %xmm0;
+       vpxor %xmm1, %xmm15, %xmm1;
+       vpxor %xmm2, %xmm15, %xmm2;
+       vpxor %xmm3, %xmm15, %xmm3;
+       vpxor %xmm4, %xmm15, %xmm4;
+       vpxor %xmm5, %xmm15, %xmm5;
+       vpxor %xmm6, %xmm15, %xmm6;
+       vpxor %xmm7, %xmm15, %xmm7;
+       vpxor %xmm8, %xmm15, %xmm8;
+       vpxor %xmm9, %xmm15, %xmm9;
+       vpxor %xmm10, %xmm15, %xmm10;
+       vpxor %xmm11, %xmm15, %xmm11;
+       vpxor %xmm12, %xmm15, %xmm12;
+       vpxor %xmm13, %xmm15, %xmm13;
+       vpxor 14 * 16(%rax), %xmm15, %xmm14;
+       vpxor 15 * 16(%rax), %xmm15, %xmm15;
+
+       call *%r9;
+
+       addq $(16 * 16), %rsp;
+
+       vpxor 0 * 16(%rsi), %xmm7, %xmm7;
+       vpxor 1 * 16(%rsi), %xmm6, %xmm6;
+       vpxor 2 * 16(%rsi), %xmm5, %xmm5;
+       vpxor 3 * 16(%rsi), %xmm4, %xmm4;
+       vpxor 4 * 16(%rsi), %xmm3, %xmm3;
+       vpxor 5 * 16(%rsi), %xmm2, %xmm2;
+       vpxor 6 * 16(%rsi), %xmm1, %xmm1;
+       vpxor 7 * 16(%rsi), %xmm0, %xmm0;
+       vpxor 8 * 16(%rsi), %xmm15, %xmm15;
+       vpxor 9 * 16(%rsi), %xmm14, %xmm14;
+       vpxor 10 * 16(%rsi), %xmm13, %xmm13;
+       vpxor 11 * 16(%rsi), %xmm12, %xmm12;
+       vpxor 12 * 16(%rsi), %xmm11, %xmm11;
+       vpxor 13 * 16(%rsi), %xmm10, %xmm10;
+       vpxor 14 * 16(%rsi), %xmm9, %xmm9;
+       vpxor 15 * 16(%rsi), %xmm8, %xmm8;
+       write_output(%xmm7, %xmm6, %xmm5, %xmm4, %xmm3, %xmm2, %xmm1, %xmm0,
+                    %xmm15, %xmm14, %xmm13, %xmm12, %xmm11, %xmm10, %xmm9,
+                    %xmm8, %rsi);
+
+       ret;
+ENDPROC(camellia_xts_crypt_16way)
+
+ENTRY(camellia_xts_enc_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (16 blocks)
+        *      %rdx: src (16 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+       xorl %r8d, %r8d; /* input whitening key, 0 for enc */
+
+       leaq __camellia_enc_blk16, %r9;
+
+       jmp camellia_xts_crypt_16way;
+ENDPROC(camellia_xts_enc_16way)
+
+ENTRY(camellia_xts_dec_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (16 blocks)
+        *      %rdx: src (16 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       cmpl $16, key_length(CTX);
+       movl $32, %r8d;
+       movl $24, %eax;
+       cmovel %eax, %r8d;  /* input whitening key, last for dec */
+
+       leaq __camellia_dec_blk16, %r9;
+
+       jmp camellia_xts_crypt_16way;
+ENDPROC(camellia_xts_dec_16way)
diff --git a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S
new file mode 100644 (file)
index 0000000..91a1878
--- /dev/null
@@ -0,0 +1,1368 @@
+/*
+ * x86_64/AVX2/AES-NI assembler implementation of Camellia
+ *
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/linkage.h>
+
+#define CAMELLIA_TABLE_BYTE_LEN 272
+
+/* struct camellia_ctx: */
+#define key_table 0
+#define key_length CAMELLIA_TABLE_BYTE_LEN
+
+/* register macros */
+#define CTX %rdi
+#define RIO %r8
+
+/**********************************************************************
+  helper macros
+ **********************************************************************/
+#define filter_8bit(x, lo_t, hi_t, mask4bit, tmp0) \
+       vpand x, mask4bit, tmp0; \
+       vpandn x, mask4bit, x; \
+       vpsrld $4, x, x; \
+       \
+       vpshufb tmp0, lo_t, tmp0; \
+       vpshufb x, hi_t, x; \
+       vpxor tmp0, x, x;
+
+#define ymm0_x xmm0
+#define ymm1_x xmm1
+#define ymm2_x xmm2
+#define ymm3_x xmm3
+#define ymm4_x xmm4
+#define ymm5_x xmm5
+#define ymm6_x xmm6
+#define ymm7_x xmm7
+#define ymm8_x xmm8
+#define ymm9_x xmm9
+#define ymm10_x xmm10
+#define ymm11_x xmm11
+#define ymm12_x xmm12
+#define ymm13_x xmm13
+#define ymm14_x xmm14
+#define ymm15_x xmm15
+
+/*
+ * AES-NI instructions do not support ymmX registers, so we need splitting and
+ * merging.
+ */
+#define vaesenclast256(zero, yreg, tmp) \
+       vextracti128 $1, yreg, tmp##_x; \
+       vaesenclast zero##_x, yreg##_x, yreg##_x; \
+       vaesenclast zero##_x, tmp##_x, tmp##_x; \
+       vinserti128 $1, tmp##_x, yreg, yreg;
+
+/**********************************************************************
+  32-way camellia
+ **********************************************************************/
+
+/*
+ * IN:
+ *   x0..x7: byte-sliced AB state
+ *   mem_cd: register pointer storing CD state
+ *   key: index for key material
+ * OUT:
+ *   x0..x7: new byte-sliced CD state
+ */
+#define roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, t0, t1, t2, t3, t4, t5, t6, \
+                 t7, mem_cd, key) \
+       /* \
+        * S-function with AES subbytes \
+        */ \
+       vbroadcasti128 .Linv_shift_row, t4; \
+       vpbroadcastb .L0f0f0f0f, t7; \
+       vbroadcasti128 .Lpre_tf_lo_s1, t0; \
+       vbroadcasti128 .Lpre_tf_hi_s1, t1; \
+       \
+       /* AES inverse shift rows */ \
+       vpshufb t4, x0, x0; \
+       vpshufb t4, x7, x7; \
+       vpshufb t4, x1, x1; \
+       vpshufb t4, x4, x4; \
+       vpshufb t4, x2, x2; \
+       vpshufb t4, x5, x5; \
+       vpshufb t4, x3, x3; \
+       vpshufb t4, x6, x6; \
+       \
+       /* prefilter sboxes 1, 2 and 3 */ \
+       vbroadcasti128 .Lpre_tf_lo_s4, t2; \
+       vbroadcasti128 .Lpre_tf_hi_s4, t3; \
+       filter_8bit(x0, t0, t1, t7, t6); \
+       filter_8bit(x7, t0, t1, t7, t6); \
+       filter_8bit(x1, t0, t1, t7, t6); \
+       filter_8bit(x4, t0, t1, t7, t6); \
+       filter_8bit(x2, t0, t1, t7, t6); \
+       filter_8bit(x5, t0, t1, t7, t6); \
+       \
+       /* prefilter sbox 4 */ \
+       vpxor t4##_x, t4##_x, t4##_x; \
+       filter_8bit(x3, t2, t3, t7, t6); \
+       filter_8bit(x6, t2, t3, t7, t6); \
+       \
+       /* AES subbytes + AES shift rows */ \
+       vbroadcasti128 .Lpost_tf_lo_s1, t0; \
+       vbroadcasti128 .Lpost_tf_hi_s1, t1; \
+       vaesenclast256(t4, x0, t5); \
+       vaesenclast256(t4, x7, t5); \
+       vaesenclast256(t4, x1, t5); \
+       vaesenclast256(t4, x4, t5); \
+       vaesenclast256(t4, x2, t5); \
+       vaesenclast256(t4, x5, t5); \
+       vaesenclast256(t4, x3, t5); \
+       vaesenclast256(t4, x6, t5); \
+       \
+       /* postfilter sboxes 1 and 4 */ \
+       vbroadcasti128 .Lpost_tf_lo_s3, t2; \
+       vbroadcasti128 .Lpost_tf_hi_s3, t3; \
+       filter_8bit(x0, t0, t1, t7, t6); \
+       filter_8bit(x7, t0, t1, t7, t6); \
+       filter_8bit(x3, t0, t1, t7, t6); \
+       filter_8bit(x6, t0, t1, t7, t6); \
+       \
+       /* postfilter sbox 3 */ \
+       vbroadcasti128 .Lpost_tf_lo_s2, t4; \
+       vbroadcasti128 .Lpost_tf_hi_s2, t5; \
+       filter_8bit(x2, t2, t3, t7, t6); \
+       filter_8bit(x5, t2, t3, t7, t6); \
+       \
+       vpbroadcastq key, t0; /* higher 64-bit duplicate ignored */ \
+       \
+       /* postfilter sbox 2 */ \
+       filter_8bit(x1, t4, t5, t7, t2); \
+       filter_8bit(x4, t4, t5, t7, t2); \
+       \
+       vpsrldq $1, t0, t1; \
+       vpsrldq $2, t0, t2; \
+       vpsrldq $3, t0, t3; \
+       vpsrldq $4, t0, t4; \
+       vpsrldq $5, t0, t5; \
+       vpsrldq $6, t0, t6; \
+       vpsrldq $7, t0, t7; \
+       vpbroadcastb t0##_x, t0; \
+       vpbroadcastb t1##_x, t1; \
+       vpbroadcastb t2##_x, t2; \
+       vpbroadcastb t3##_x, t3; \
+       vpbroadcastb t4##_x, t4; \
+       vpbroadcastb t6##_x, t6; \
+       vpbroadcastb t5##_x, t5; \
+       vpbroadcastb t7##_x, t7; \
+       \
+       /* P-function */ \
+       vpxor x5, x0, x0; \
+       vpxor x6, x1, x1; \
+       vpxor x7, x2, x2; \
+       vpxor x4, x3, x3; \
+       \
+       vpxor x2, x4, x4; \
+       vpxor x3, x5, x5; \
+       vpxor x0, x6, x6; \
+       vpxor x1, x7, x7; \
+       \
+       vpxor x7, x0, x0; \
+       vpxor x4, x1, x1; \
+       vpxor x5, x2, x2; \
+       vpxor x6, x3, x3; \
+       \
+       vpxor x3, x4, x4; \
+       vpxor x0, x5, x5; \
+       vpxor x1, x6, x6; \
+       vpxor x2, x7, x7; /* note: high and low parts swapped */ \
+       \
+       /* Add key material and result to CD (x becomes new CD) */ \
+       \
+       vpxor t7, x0, x0; \
+       vpxor 4 * 32(mem_cd), x0, x0; \
+       \
+       vpxor t6, x1, x1; \
+       vpxor 5 * 32(mem_cd), x1, x1; \
+       \
+       vpxor t5, x2, x2; \
+       vpxor 6 * 32(mem_cd), x2, x2; \
+       \
+       vpxor t4, x3, x3; \
+       vpxor 7 * 32(mem_cd), x3, x3; \
+       \
+       vpxor t3, x4, x4; \
+       vpxor 0 * 32(mem_cd), x4, x4; \
+       \
+       vpxor t2, x5, x5; \
+       vpxor 1 * 32(mem_cd), x5, x5; \
+       \
+       vpxor t1, x6, x6; \
+       vpxor 2 * 32(mem_cd), x6, x6; \
+       \
+       vpxor t0, x7, x7; \
+       vpxor 3 * 32(mem_cd), x7, x7;
+
+/*
+ * Size optimization... with inlined roundsm16 binary would be over 5 times
+ * larger and would only marginally faster.
+ */
+.align 8
+roundsm32_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd:
+       roundsm32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                 %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14, %ymm15,
+                 %rcx, (%r9));
+       ret;
+ENDPROC(roundsm32_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd)
+
+.align 8
+roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab:
+       roundsm32(%ymm4, %ymm5, %ymm6, %ymm7, %ymm0, %ymm1, %ymm2, %ymm3,
+                 %ymm12, %ymm13, %ymm14, %ymm15, %ymm8, %ymm9, %ymm10, %ymm11,
+                 %rax, (%r9));
+       ret;
+ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
+
+/*
+ * IN/OUT:
+ *  x0..x7: byte-sliced AB state preloaded
+ *  mem_ab: byte-sliced AB state in memory
+ *  mem_cb: byte-sliced CD state in memory
+ */
+#define two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, i, dir, store_ab) \
+       leaq (key_table + (i) * 8)(CTX), %r9; \
+       call roundsm32_x0_x1_x2_x3_x4_x5_x6_x7_y0_y1_y2_y3_y4_y5_y6_y7_cd; \
+       \
+       vmovdqu x0, 4 * 32(mem_cd); \
+       vmovdqu x1, 5 * 32(mem_cd); \
+       vmovdqu x2, 6 * 32(mem_cd); \
+       vmovdqu x3, 7 * 32(mem_cd); \
+       vmovdqu x4, 0 * 32(mem_cd); \
+       vmovdqu x5, 1 * 32(mem_cd); \
+       vmovdqu x6, 2 * 32(mem_cd); \
+       vmovdqu x7, 3 * 32(mem_cd); \
+       \
+       leaq (key_table + ((i) + (dir)) * 8)(CTX), %r9; \
+       call roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab; \
+       \
+       store_ab(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab);
+
+#define dummy_store(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab) /* do nothing */
+
+#define store_ab_state(x0, x1, x2, x3, x4, x5, x6, x7, mem_ab) \
+       /* Store new AB state */ \
+       vmovdqu x4, 4 * 32(mem_ab); \
+       vmovdqu x5, 5 * 32(mem_ab); \
+       vmovdqu x6, 6 * 32(mem_ab); \
+       vmovdqu x7, 7 * 32(mem_ab); \
+       vmovdqu x0, 0 * 32(mem_ab); \
+       vmovdqu x1, 1 * 32(mem_ab); \
+       vmovdqu x2, 2 * 32(mem_ab); \
+       vmovdqu x3, 3 * 32(mem_ab);
+
+#define enc_rounds32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, i) \
+       two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, (i) + 2, 1, store_ab_state); \
+       two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, (i) + 4, 1, store_ab_state); \
+       two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, (i) + 6, 1, dummy_store);
+
+#define dec_rounds32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, i) \
+       two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, (i) + 7, -1, store_ab_state); \
+       two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, (i) + 5, -1, store_ab_state); \
+       two_roundsm32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd, (i) + 3, -1, dummy_store);
+
+/*
+ * IN:
+ *  v0..3: byte-sliced 32-bit integers
+ * OUT:
+ *  v0..3: (IN <<< 1)
+ */
+#define rol32_1_32(v0, v1, v2, v3, t0, t1, t2, zero) \
+       vpcmpgtb v0, zero, t0; \
+       vpaddb v0, v0, v0; \
+       vpabsb t0, t0; \
+       \
+       vpcmpgtb v1, zero, t1; \
+       vpaddb v1, v1, v1; \
+       vpabsb t1, t1; \
+       \
+       vpcmpgtb v2, zero, t2; \
+       vpaddb v2, v2, v2; \
+       vpabsb t2, t2; \
+       \
+       vpor t0, v1, v1; \
+       \
+       vpcmpgtb v3, zero, t0; \
+       vpaddb v3, v3, v3; \
+       vpabsb t0, t0; \
+       \
+       vpor t1, v2, v2; \
+       vpor t2, v3, v3; \
+       vpor t0, v0, v0;
+
+/*
+ * IN:
+ *   r: byte-sliced AB state in memory
+ *   l: byte-sliced CD state in memory
+ * OUT:
+ *   x0..x7: new byte-sliced CD state
+ */
+#define fls32(l, l0, l1, l2, l3, l4, l5, l6, l7, r, t0, t1, t2, t3, tt0, \
+             tt1, tt2, tt3, kll, klr, krl, krr) \
+       /* \
+        * t0 = kll; \
+        * t0 &= ll; \
+        * lr ^= rol32(t0, 1); \
+        */ \
+       vpbroadcastd kll, t0; /* only lowest 32-bit used */ \
+       vpxor tt0, tt0, tt0; \
+       vpbroadcastb t0##_x, t3; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t2; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t1; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t0; \
+       \
+       vpand l0, t0, t0; \
+       vpand l1, t1, t1; \
+       vpand l2, t2, t2; \
+       vpand l3, t3, t3; \
+       \
+       rol32_1_32(t3, t2, t1, t0, tt1, tt2, tt3, tt0); \
+       \
+       vpxor l4, t0, l4; \
+       vmovdqu l4, 4 * 32(l); \
+       vpxor l5, t1, l5; \
+       vmovdqu l5, 5 * 32(l); \
+       vpxor l6, t2, l6; \
+       vmovdqu l6, 6 * 32(l); \
+       vpxor l7, t3, l7; \
+       vmovdqu l7, 7 * 32(l); \
+       \
+       /* \
+        * t2 = krr; \
+        * t2 |= rr; \
+        * rl ^= t2; \
+        */ \
+       \
+       vpbroadcastd krr, t0; /* only lowest 32-bit used */ \
+       vpbroadcastb t0##_x, t3; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t2; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t1; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t0; \
+       \
+       vpor 4 * 32(r), t0, t0; \
+       vpor 5 * 32(r), t1, t1; \
+       vpor 6 * 32(r), t2, t2; \
+       vpor 7 * 32(r), t3, t3; \
+       \
+       vpxor 0 * 32(r), t0, t0; \
+       vpxor 1 * 32(r), t1, t1; \
+       vpxor 2 * 32(r), t2, t2; \
+       vpxor 3 * 32(r), t3, t3; \
+       vmovdqu t0, 0 * 32(r); \
+       vmovdqu t1, 1 * 32(r); \
+       vmovdqu t2, 2 * 32(r); \
+       vmovdqu t3, 3 * 32(r); \
+       \
+       /* \
+        * t2 = krl; \
+        * t2 &= rl; \
+        * rr ^= rol32(t2, 1); \
+        */ \
+       vpbroadcastd krl, t0; /* only lowest 32-bit used */ \
+       vpbroadcastb t0##_x, t3; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t2; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t1; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t0; \
+       \
+       vpand 0 * 32(r), t0, t0; \
+       vpand 1 * 32(r), t1, t1; \
+       vpand 2 * 32(r), t2, t2; \
+       vpand 3 * 32(r), t3, t3; \
+       \
+       rol32_1_32(t3, t2, t1, t0, tt1, tt2, tt3, tt0); \
+       \
+       vpxor 4 * 32(r), t0, t0; \
+       vpxor 5 * 32(r), t1, t1; \
+       vpxor 6 * 32(r), t2, t2; \
+       vpxor 7 * 32(r), t3, t3; \
+       vmovdqu t0, 4 * 32(r); \
+       vmovdqu t1, 5 * 32(r); \
+       vmovdqu t2, 6 * 32(r); \
+       vmovdqu t3, 7 * 32(r); \
+       \
+       /* \
+        * t0 = klr; \
+        * t0 |= lr; \
+        * ll ^= t0; \
+        */ \
+       \
+       vpbroadcastd klr, t0; /* only lowest 32-bit used */ \
+       vpbroadcastb t0##_x, t3; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t2; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t1; \
+       vpsrldq $1, t0, t0; \
+       vpbroadcastb t0##_x, t0; \
+       \
+       vpor l4, t0, t0; \
+       vpor l5, t1, t1; \
+       vpor l6, t2, t2; \
+       vpor l7, t3, t3; \
+       \
+       vpxor l0, t0, l0; \
+       vmovdqu l0, 0 * 32(l); \
+       vpxor l1, t1, l1; \
+       vmovdqu l1, 1 * 32(l); \
+       vpxor l2, t2, l2; \
+       vmovdqu l2, 2 * 32(l); \
+       vpxor l3, t3, l3; \
+       vmovdqu l3, 3 * 32(l);
+
+#define transpose_4x4(x0, x1, x2, x3, t1, t2) \
+       vpunpckhdq x1, x0, t2; \
+       vpunpckldq x1, x0, x0; \
+       \
+       vpunpckldq x3, x2, t1; \
+       vpunpckhdq x3, x2, x2; \
+       \
+       vpunpckhqdq t1, x0, x1; \
+       vpunpcklqdq t1, x0, x0; \
+       \
+       vpunpckhqdq x2, t2, x3; \
+       vpunpcklqdq x2, t2, x2;
+
+#define byteslice_16x16b_fast(a0, b0, c0, d0, a1, b1, c1, d1, a2, b2, c2, d2, \
+                             a3, b3, c3, d3, st0, st1) \
+       vmovdqu d2, st0; \
+       vmovdqu d3, st1; \
+       transpose_4x4(a0, a1, a2, a3, d2, d3); \
+       transpose_4x4(b0, b1, b2, b3, d2, d3); \
+       vmovdqu st0, d2; \
+       vmovdqu st1, d3; \
+       \
+       vmovdqu a0, st0; \
+       vmovdqu a1, st1; \
+       transpose_4x4(c0, c1, c2, c3, a0, a1); \
+       transpose_4x4(d0, d1, d2, d3, a0, a1); \
+       \
+       vbroadcasti128 .Lshufb_16x16b, a0; \
+       vmovdqu st1, a1; \
+       vpshufb a0, a2, a2; \
+       vpshufb a0, a3, a3; \
+       vpshufb a0, b0, b0; \
+       vpshufb a0, b1, b1; \
+       vpshufb a0, b2, b2; \
+       vpshufb a0, b3, b3; \
+       vpshufb a0, a1, a1; \
+       vpshufb a0, c0, c0; \
+       vpshufb a0, c1, c1; \
+       vpshufb a0, c2, c2; \
+       vpshufb a0, c3, c3; \
+       vpshufb a0, d0, d0; \
+       vpshufb a0, d1, d1; \
+       vpshufb a0, d2, d2; \
+       vpshufb a0, d3, d3; \
+       vmovdqu d3, st1; \
+       vmovdqu st0, d3; \
+       vpshufb a0, d3, a0; \
+       vmovdqu d2, st0; \
+       \
+       transpose_4x4(a0, b0, c0, d0, d2, d3); \
+       transpose_4x4(a1, b1, c1, d1, d2, d3); \
+       vmovdqu st0, d2; \
+       vmovdqu st1, d3; \
+       \
+       vmovdqu b0, st0; \
+       vmovdqu b1, st1; \
+       transpose_4x4(a2, b2, c2, d2, b0, b1); \
+       transpose_4x4(a3, b3, c3, d3, b0, b1); \
+       vmovdqu st0, b0; \
+       vmovdqu st1, b1; \
+       /* does not adjust output bytes inside vectors */
+
+/* load blocks to registers and apply pre-whitening */
+#define inpack32_pre(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                    y6, y7, rio, key) \
+       vpbroadcastq key, x0; \
+       vpshufb .Lpack_bswap, x0, x0; \
+       \
+       vpxor 0 * 32(rio), x0, y7; \
+       vpxor 1 * 32(rio), x0, y6; \
+       vpxor 2 * 32(rio), x0, y5; \
+       vpxor 3 * 32(rio), x0, y4; \
+       vpxor 4 * 32(rio), x0, y3; \
+       vpxor 5 * 32(rio), x0, y2; \
+       vpxor 6 * 32(rio), x0, y1; \
+       vpxor 7 * 32(rio), x0, y0; \
+       vpxor 8 * 32(rio), x0, x7; \
+       vpxor 9 * 32(rio), x0, x6; \
+       vpxor 10 * 32(rio), x0, x5; \
+       vpxor 11 * 32(rio), x0, x4; \
+       vpxor 12 * 32(rio), x0, x3; \
+       vpxor 13 * 32(rio), x0, x2; \
+       vpxor 14 * 32(rio), x0, x1; \
+       vpxor 15 * 32(rio), x0, x0;
+
+/* byteslice pre-whitened blocks and store to temporary memory */
+#define inpack32_post(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                     y6, y7, mem_ab, mem_cd) \
+       byteslice_16x16b_fast(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, \
+                             y4, y5, y6, y7, (mem_ab), (mem_cd)); \
+       \
+       vmovdqu x0, 0 * 32(mem_ab); \
+       vmovdqu x1, 1 * 32(mem_ab); \
+       vmovdqu x2, 2 * 32(mem_ab); \
+       vmovdqu x3, 3 * 32(mem_ab); \
+       vmovdqu x4, 4 * 32(mem_ab); \
+       vmovdqu x5, 5 * 32(mem_ab); \
+       vmovdqu x6, 6 * 32(mem_ab); \
+       vmovdqu x7, 7 * 32(mem_ab); \
+       vmovdqu y0, 0 * 32(mem_cd); \
+       vmovdqu y1, 1 * 32(mem_cd); \
+       vmovdqu y2, 2 * 32(mem_cd); \
+       vmovdqu y3, 3 * 32(mem_cd); \
+       vmovdqu y4, 4 * 32(mem_cd); \
+       vmovdqu y5, 5 * 32(mem_cd); \
+       vmovdqu y6, 6 * 32(mem_cd); \
+       vmovdqu y7, 7 * 32(mem_cd);
+
+/* de-byteslice, apply post-whitening and store blocks */
+#define outunpack32(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, \
+                   y5, y6, y7, key, stack_tmp0, stack_tmp1) \
+       byteslice_16x16b_fast(y0, y4, x0, x4, y1, y5, x1, x5, y2, y6, x2, x6, \
+                             y3, y7, x3, x7, stack_tmp0, stack_tmp1); \
+       \
+       vmovdqu x0, stack_tmp0; \
+       \
+       vpbroadcastq key, x0; \
+       vpshufb .Lpack_bswap, x0, x0; \
+       \
+       vpxor x0, y7, y7; \
+       vpxor x0, y6, y6; \
+       vpxor x0, y5, y5; \
+       vpxor x0, y4, y4; \
+       vpxor x0, y3, y3; \
+       vpxor x0, y2, y2; \
+       vpxor x0, y1, y1; \
+       vpxor x0, y0, y0; \
+       vpxor x0, x7, x7; \
+       vpxor x0, x6, x6; \
+       vpxor x0, x5, x5; \
+       vpxor x0, x4, x4; \
+       vpxor x0, x3, x3; \
+       vpxor x0, x2, x2; \
+       vpxor x0, x1, x1; \
+       vpxor stack_tmp0, x0, x0;
+
+#define write_output(x0, x1, x2, x3, x4, x5, x6, x7, y0, y1, y2, y3, y4, y5, \
+                    y6, y7, rio) \
+       vmovdqu x0, 0 * 32(rio); \
+       vmovdqu x1, 1 * 32(rio); \
+       vmovdqu x2, 2 * 32(rio); \
+       vmovdqu x3, 3 * 32(rio); \
+       vmovdqu x4, 4 * 32(rio); \
+       vmovdqu x5, 5 * 32(rio); \
+       vmovdqu x6, 6 * 32(rio); \
+       vmovdqu x7, 7 * 32(rio); \
+       vmovdqu y0, 8 * 32(rio); \
+       vmovdqu y1, 9 * 32(rio); \
+       vmovdqu y2, 10 * 32(rio); \
+       vmovdqu y3, 11 * 32(rio); \
+       vmovdqu y4, 12 * 32(rio); \
+       vmovdqu y5, 13 * 32(rio); \
+       vmovdqu y6, 14 * 32(rio); \
+       vmovdqu y7, 15 * 32(rio);
+
+.data
+.align 32
+
+#define SHUFB_BYTES(idx) \
+       0 + (idx), 4 + (idx), 8 + (idx), 12 + (idx)
+
+.Lshufb_16x16b:
+       .byte SHUFB_BYTES(0), SHUFB_BYTES(1), SHUFB_BYTES(2), SHUFB_BYTES(3)
+       .byte SHUFB_BYTES(0), SHUFB_BYTES(1), SHUFB_BYTES(2), SHUFB_BYTES(3)
+
+.Lpack_bswap:
+       .long 0x00010203, 0x04050607, 0x80808080, 0x80808080
+       .long 0x00010203, 0x04050607, 0x80808080, 0x80808080
+
+/* For CTR-mode IV byteswap */
+.Lbswap128_mask:
+       .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+/* For XTS mode */
+.Lxts_gf128mul_and_shl1_mask_0:
+       .byte 0x87, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
+.Lxts_gf128mul_and_shl1_mask_1:
+       .byte 0x0e, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0
+
+/*
+ * pre-SubByte transform
+ *
+ * pre-lookup for sbox1, sbox2, sbox3:
+ *   swap_bitendianness(
+ *       isom_map_camellia_to_aes(
+ *           camellia_f(
+ *               swap_bitendianess(in)
+ *           )
+ *       )
+ *   )
+ *
+ * (note: '⊕ 0xc5' inside camellia_f())
+ */
+.Lpre_tf_lo_s1:
+       .byte 0x45, 0xe8, 0x40, 0xed, 0x2e, 0x83, 0x2b, 0x86
+       .byte 0x4b, 0xe6, 0x4e, 0xe3, 0x20, 0x8d, 0x25, 0x88
+.Lpre_tf_hi_s1:
+       .byte 0x00, 0x51, 0xf1, 0xa0, 0x8a, 0xdb, 0x7b, 0x2a
+       .byte 0x09, 0x58, 0xf8, 0xa9, 0x83, 0xd2, 0x72, 0x23
+
+/*
+ * pre-SubByte transform
+ *
+ * pre-lookup for sbox4:
+ *   swap_bitendianness(
+ *       isom_map_camellia_to_aes(
+ *           camellia_f(
+ *               swap_bitendianess(in <<< 1)
+ *           )
+ *       )
+ *   )
+ *
+ * (note: '⊕ 0xc5' inside camellia_f())
+ */
+.Lpre_tf_lo_s4:
+       .byte 0x45, 0x40, 0x2e, 0x2b, 0x4b, 0x4e, 0x20, 0x25
+       .byte 0x14, 0x11, 0x7f, 0x7a, 0x1a, 0x1f, 0x71, 0x74
+.Lpre_tf_hi_s4:
+       .byte 0x00, 0xf1, 0x8a, 0x7b, 0x09, 0xf8, 0x83, 0x72
+       .byte 0xad, 0x5c, 0x27, 0xd6, 0xa4, 0x55, 0x2e, 0xdf
+
+/*
+ * post-SubByte transform
+ *
+ * post-lookup for sbox1, sbox4:
+ *  swap_bitendianness(
+ *      camellia_h(
+ *          isom_map_aes_to_camellia(
+ *              swap_bitendianness(
+ *                  aes_inverse_affine_transform(in)
+ *              )
+ *          )
+ *      )
+ *  )
+ *
+ * (note: '⊕ 0x6e' inside camellia_h())
+ */
+.Lpost_tf_lo_s1:
+       .byte 0x3c, 0xcc, 0xcf, 0x3f, 0x32, 0xc2, 0xc1, 0x31
+       .byte 0xdc, 0x2c, 0x2f, 0xdf, 0xd2, 0x22, 0x21, 0xd1
+.Lpost_tf_hi_s1:
+       .byte 0x00, 0xf9, 0x86, 0x7f, 0xd7, 0x2e, 0x51, 0xa8
+       .byte 0xa4, 0x5d, 0x22, 0xdb, 0x73, 0x8a, 0xf5, 0x0c
+
+/*
+ * post-SubByte transform
+ *
+ * post-lookup for sbox2:
+ *  swap_bitendianness(
+ *      camellia_h(
+ *          isom_map_aes_to_camellia(
+ *              swap_bitendianness(
+ *                  aes_inverse_affine_transform(in)
+ *              )
+ *          )
+ *      )
+ *  ) <<< 1
+ *
+ * (note: '⊕ 0x6e' inside camellia_h())
+ */
+.Lpost_tf_lo_s2:
+       .byte 0x78, 0x99, 0x9f, 0x7e, 0x64, 0x85, 0x83, 0x62
+       .byte 0xb9, 0x58, 0x5e, 0xbf, 0xa5, 0x44, 0x42, 0xa3
+.Lpost_tf_hi_s2:
+       .byte 0x00, 0xf3, 0x0d, 0xfe, 0xaf, 0x5c, 0xa2, 0x51
+       .byte 0x49, 0xba, 0x44, 0xb7, 0xe6, 0x15, 0xeb, 0x18
+
+/*
+ * post-SubByte transform
+ *
+ * post-lookup for sbox3:
+ *  swap_bitendianness(
+ *      camellia_h(
+ *          isom_map_aes_to_camellia(
+ *              swap_bitendianness(
+ *                  aes_inverse_affine_transform(in)
+ *              )
+ *          )
+ *      )
+ *  ) >>> 1
+ *
+ * (note: '⊕ 0x6e' inside camellia_h())
+ */
+.Lpost_tf_lo_s3:
+       .byte 0x1e, 0x66, 0xe7, 0x9f, 0x19, 0x61, 0xe0, 0x98
+       .byte 0x6e, 0x16, 0x97, 0xef, 0x69, 0x11, 0x90, 0xe8
+.Lpost_tf_hi_s3:
+       .byte 0x00, 0xfc, 0x43, 0xbf, 0xeb, 0x17, 0xa8, 0x54
+       .byte 0x52, 0xae, 0x11, 0xed, 0xb9, 0x45, 0xfa, 0x06
+
+/* For isolating SubBytes from AESENCLAST, inverse shift row */
+.Linv_shift_row:
+       .byte 0x00, 0x0d, 0x0a, 0x07, 0x04, 0x01, 0x0e, 0x0b
+       .byte 0x08, 0x05, 0x02, 0x0f, 0x0c, 0x09, 0x06, 0x03
+
+.align 4
+/* 4-bit mask */
+.L0f0f0f0f:
+       .long 0x0f0f0f0f
+
+.text
+
+.align 8
+__camellia_enc_blk32:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rax: temporary storage, 512 bytes
+        *      %ymm0..%ymm15: 32 plaintext blocks
+        * output:
+        *      %ymm0..%ymm15: 32 encrypted blocks, order swapped:
+        *       7, 8, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8
+        */
+
+       leaq 8 * 32(%rax), %rcx;
+
+       inpack32_post(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                     %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                     %ymm15, %rax, %rcx);
+
+       enc_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 0);
+
+       fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+             %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+             %ymm15,
+             ((key_table + (8) * 8) + 0)(CTX),
+             ((key_table + (8) * 8) + 4)(CTX),
+             ((key_table + (8) * 8) + 8)(CTX),
+             ((key_table + (8) * 8) + 12)(CTX));
+
+       enc_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 8);
+
+       fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+             %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+             %ymm15,
+             ((key_table + (16) * 8) + 0)(CTX),
+             ((key_table + (16) * 8) + 4)(CTX),
+             ((key_table + (16) * 8) + 8)(CTX),
+             ((key_table + (16) * 8) + 12)(CTX));
+
+       enc_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 16);
+
+       movl $24, %r8d;
+       cmpl $16, key_length(CTX);
+       jne .Lenc_max32;
+
+.Lenc_done:
+       /* load CD for output */
+       vmovdqu 0 * 32(%rcx), %ymm8;
+       vmovdqu 1 * 32(%rcx), %ymm9;
+       vmovdqu 2 * 32(%rcx), %ymm10;
+       vmovdqu 3 * 32(%rcx), %ymm11;
+       vmovdqu 4 * 32(%rcx), %ymm12;
+       vmovdqu 5 * 32(%rcx), %ymm13;
+       vmovdqu 6 * 32(%rcx), %ymm14;
+       vmovdqu 7 * 32(%rcx), %ymm15;
+
+       outunpack32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                   %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                   %ymm15, (key_table)(CTX, %r8, 8), (%rax), 1 * 32(%rax));
+
+       ret;
+
+.align 8
+.Lenc_max32:
+       movl $32, %r8d;
+
+       fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+             %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+             %ymm15,
+             ((key_table + (24) * 8) + 0)(CTX),
+             ((key_table + (24) * 8) + 4)(CTX),
+             ((key_table + (24) * 8) + 8)(CTX),
+             ((key_table + (24) * 8) + 12)(CTX));
+
+       enc_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 24);
+
+       jmp .Lenc_done;
+ENDPROC(__camellia_enc_blk32)
+
+.align 8
+__camellia_dec_blk32:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rax: temporary storage, 512 bytes
+        *      %r8d: 24 for 16 byte key, 32 for larger
+        *      %ymm0..%ymm15: 16 encrypted blocks
+        * output:
+        *      %ymm0..%ymm15: 16 plaintext blocks, order swapped:
+        *       7, 8, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8
+        */
+
+       leaq 8 * 32(%rax), %rcx;
+
+       inpack32_post(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                     %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                     %ymm15, %rax, %rcx);
+
+       cmpl $32, %r8d;
+       je .Ldec_max32;
+
+.Ldec_max24:
+       dec_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 16);
+
+       fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+             %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+             %ymm15,
+             ((key_table + (16) * 8) + 8)(CTX),
+             ((key_table + (16) * 8) + 12)(CTX),
+             ((key_table + (16) * 8) + 0)(CTX),
+             ((key_table + (16) * 8) + 4)(CTX));
+
+       dec_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 8);
+
+       fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+             %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+             %ymm15,
+             ((key_table + (8) * 8) + 8)(CTX),
+             ((key_table + (8) * 8) + 12)(CTX),
+             ((key_table + (8) * 8) + 0)(CTX),
+             ((key_table + (8) * 8) + 4)(CTX));
+
+       dec_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 0);
+
+       /* load CD for output */
+       vmovdqu 0 * 32(%rcx), %ymm8;
+       vmovdqu 1 * 32(%rcx), %ymm9;
+       vmovdqu 2 * 32(%rcx), %ymm10;
+       vmovdqu 3 * 32(%rcx), %ymm11;
+       vmovdqu 4 * 32(%rcx), %ymm12;
+       vmovdqu 5 * 32(%rcx), %ymm13;
+       vmovdqu 6 * 32(%rcx), %ymm14;
+       vmovdqu 7 * 32(%rcx), %ymm15;
+
+       outunpack32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                   %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                   %ymm15, (key_table)(CTX), (%rax), 1 * 32(%rax));
+
+       ret;
+
+.align 8
+.Ldec_max32:
+       dec_rounds32(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rax, %rcx, 24);
+
+       fls32(%rax, %ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+             %rcx, %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+             %ymm15,
+             ((key_table + (24) * 8) + 8)(CTX),
+             ((key_table + (24) * 8) + 12)(CTX),
+             ((key_table + (24) * 8) + 0)(CTX),
+             ((key_table + (24) * 8) + 4)(CTX));
+
+       jmp .Ldec_max24;
+ENDPROC(__camellia_dec_blk32)
+
+ENTRY(camellia_ecb_enc_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (32 blocks)
+        *      %rdx: src (32 blocks)
+        */
+
+       vzeroupper;
+
+       inpack32_pre(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rdx, (key_table)(CTX));
+
+       /* now dst can be used as temporary buffer (even in src == dst case) */
+       movq    %rsi, %rax;
+
+       call __camellia_enc_blk32;
+
+       write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0,
+                    %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9,
+                    %ymm8, %rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(camellia_ecb_enc_32way)
+
+ENTRY(camellia_ecb_dec_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (32 blocks)
+        *      %rdx: src (32 blocks)
+        */
+
+       vzeroupper;
+
+       cmpl $16, key_length(CTX);
+       movl $32, %r8d;
+       movl $24, %eax;
+       cmovel %eax, %r8d; /* max */
+
+       inpack32_pre(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rdx, (key_table)(CTX, %r8, 8));
+
+       /* now dst can be used as temporary buffer (even in src == dst case) */
+       movq    %rsi, %rax;
+
+       call __camellia_dec_blk32;
+
+       write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0,
+                    %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9,
+                    %ymm8, %rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(camellia_ecb_dec_32way)
+
+ENTRY(camellia_cbc_dec_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (32 blocks)
+        *      %rdx: src (32 blocks)
+        */
+
+       vzeroupper;
+
+       cmpl $16, key_length(CTX);
+       movl $32, %r8d;
+       movl $24, %eax;
+       cmovel %eax, %r8d; /* max */
+
+       inpack32_pre(%ymm0, %ymm1, %ymm2, %ymm3, %ymm4, %ymm5, %ymm6, %ymm7,
+                    %ymm8, %ymm9, %ymm10, %ymm11, %ymm12, %ymm13, %ymm14,
+                    %ymm15, %rdx, (key_table)(CTX, %r8, 8));
+
+       movq %rsp, %r10;
+       cmpq %rsi, %rdx;
+       je .Lcbc_dec_use_stack;
+
+       /* dst can be used as temporary storage, src is not overwritten. */
+       movq %rsi, %rax;
+       jmp .Lcbc_dec_continue;
+
+.Lcbc_dec_use_stack:
+       /*
+        * dst still in-use (because dst == src), so use stack for temporary
+        * storage.
+        */
+       subq $(16 * 32), %rsp;
+       movq %rsp, %rax;
+
+.Lcbc_dec_continue:
+       call __camellia_dec_blk32;
+
+       vmovdqu %ymm7, (%rax);
+       vpxor %ymm7, %ymm7, %ymm7;
+       vinserti128 $1, (%rdx), %ymm7, %ymm7;
+       vpxor (%rax), %ymm7, %ymm7;
+       movq %r10, %rsp;
+       vpxor (0 * 32 + 16)(%rdx), %ymm6, %ymm6;
+       vpxor (1 * 32 + 16)(%rdx), %ymm5, %ymm5;
+       vpxor (2 * 32 + 16)(%rdx), %ymm4, %ymm4;
+       vpxor (3 * 32 + 16)(%rdx), %ymm3, %ymm3;
+       vpxor (4 * 32 + 16)(%rdx), %ymm2, %ymm2;
+       vpxor (5 * 32 + 16)(%rdx), %ymm1, %ymm1;
+       vpxor (6 * 32 + 16)(%rdx), %ymm0, %ymm0;
+       vpxor (7 * 32 + 16)(%rdx), %ymm15, %ymm15;
+       vpxor (8 * 32 + 16)(%rdx), %ymm14, %ymm14;
+       vpxor (9 * 32 + 16)(%rdx), %ymm13, %ymm13;
+       vpxor (10 * 32 + 16)(%rdx), %ymm12, %ymm12;
+       vpxor (11 * 32 + 16)(%rdx), %ymm11, %ymm11;
+       vpxor (12 * 32 + 16)(%rdx), %ymm10, %ymm10;
+       vpxor (13 * 32 + 16)(%rdx), %ymm9, %ymm9;
+       vpxor (14 * 32 + 16)(%rdx), %ymm8, %ymm8;
+       write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0,
+                    %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9,
+                    %ymm8, %rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(camellia_cbc_dec_32way)
+
+#define inc_le128(x, minus_one, tmp) \
+       vpcmpeqq minus_one, x, tmp; \
+       vpsubq minus_one, x, x; \
+       vpslldq $8, tmp, tmp; \
+       vpsubq tmp, x, x;
+
+#define add2_le128(x, minus_one, minus_two, tmp1, tmp2) \
+       vpcmpeqq minus_one, x, tmp1; \
+       vpcmpeqq minus_two, x, tmp2; \
+       vpsubq minus_two, x, x; \
+       vpor tmp2, tmp1, tmp1; \
+       vpslldq $8, tmp1, tmp1; \
+       vpsubq tmp1, x, x;
+
+ENTRY(camellia_ctr_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (32 blocks)
+        *      %rdx: src (32 blocks)
+        *      %rcx: iv (little endian, 128bit)
+        */
+
+       vzeroupper;
+
+       movq %rsp, %r10;
+       cmpq %rsi, %rdx;
+       je .Lctr_use_stack;
+
+       /* dst can be used as temporary storage, src is not overwritten. */
+       movq %rsi, %rax;
+       jmp .Lctr_continue;
+
+.Lctr_use_stack:
+       subq $(16 * 32), %rsp;
+       movq %rsp, %rax;
+
+.Lctr_continue:
+       vpcmpeqd %ymm15, %ymm15, %ymm15;
+       vpsrldq $8, %ymm15, %ymm15; /* ab: -1:0 ; cd: -1:0 */
+       vpaddq %ymm15, %ymm15, %ymm12; /* ab: -2:0 ; cd: -2:0 */
+
+       /* load IV and byteswap */
+       vmovdqu (%rcx), %xmm0;
+       vmovdqa %xmm0, %xmm1;
+       inc_le128(%xmm0, %xmm15, %xmm14);
+       vbroadcasti128 .Lbswap128_mask, %ymm14;
+       vinserti128 $1, %xmm0, %ymm1, %ymm0;
+       vpshufb %ymm14, %ymm0, %ymm13;
+       vmovdqu %ymm13, 15 * 32(%rax);
+
+       /* construct IVs */
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13); /* ab:le2 ; cd:le3 */
+       vpshufb %ymm14, %ymm0, %ymm13;
+       vmovdqu %ymm13, 14 * 32(%rax);
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm13;
+       vmovdqu %ymm13, 13 * 32(%rax);
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm13;
+       vmovdqu %ymm13, 12 * 32(%rax);
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm13;
+       vmovdqu %ymm13, 11 * 32(%rax);
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm10;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm9;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm8;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm7;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm6;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm5;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm4;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm3;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm2;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vpshufb %ymm14, %ymm0, %ymm1;
+       add2_le128(%ymm0, %ymm15, %ymm12, %ymm11, %ymm13);
+       vextracti128 $1, %ymm0, %xmm13;
+       vpshufb %ymm14, %ymm0, %ymm0;
+       inc_le128(%xmm13, %xmm15, %xmm14);
+       vmovdqu %xmm13, (%rcx);
+
+       /* inpack32_pre: */
+       vpbroadcastq (key_table)(CTX), %ymm15;
+       vpshufb .Lpack_bswap, %ymm15, %ymm15;
+       vpxor %ymm0, %ymm15, %ymm0;
+       vpxor %ymm1, %ymm15, %ymm1;
+       vpxor %ymm2, %ymm15, %ymm2;
+       vpxor %ymm3, %ymm15, %ymm3;
+       vpxor %ymm4, %ymm15, %ymm4;
+       vpxor %ymm5, %ymm15, %ymm5;
+       vpxor %ymm6, %ymm15, %ymm6;
+       vpxor %ymm7, %ymm15, %ymm7;
+       vpxor %ymm8, %ymm15, %ymm8;
+       vpxor %ymm9, %ymm15, %ymm9;
+       vpxor %ymm10, %ymm15, %ymm10;
+       vpxor 11 * 32(%rax), %ymm15, %ymm11;
+       vpxor 12 * 32(%rax), %ymm15, %ymm12;
+       vpxor 13 * 32(%rax), %ymm15, %ymm13;
+       vpxor 14 * 32(%rax), %ymm15, %ymm14;
+       vpxor 15 * 32(%rax), %ymm15, %ymm15;
+
+       call __camellia_enc_blk32;
+
+       movq %r10, %rsp;
+
+       vpxor 0 * 32(%rdx), %ymm7, %ymm7;
+       vpxor 1 * 32(%rdx), %ymm6, %ymm6;
+       vpxor 2 * 32(%rdx), %ymm5, %ymm5;
+       vpxor 3 * 32(%rdx), %ymm4, %ymm4;
+       vpxor 4 * 32(%rdx), %ymm3, %ymm3;
+       vpxor 5 * 32(%rdx), %ymm2, %ymm2;
+       vpxor 6 * 32(%rdx), %ymm1, %ymm1;
+       vpxor 7 * 32(%rdx), %ymm0, %ymm0;
+       vpxor 8 * 32(%rdx), %ymm15, %ymm15;
+       vpxor 9 * 32(%rdx), %ymm14, %ymm14;
+       vpxor 10 * 32(%rdx), %ymm13, %ymm13;
+       vpxor 11 * 32(%rdx), %ymm12, %ymm12;
+       vpxor 12 * 32(%rdx), %ymm11, %ymm11;
+       vpxor 13 * 32(%rdx), %ymm10, %ymm10;
+       vpxor 14 * 32(%rdx), %ymm9, %ymm9;
+       vpxor 15 * 32(%rdx), %ymm8, %ymm8;
+       write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0,
+                    %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9,
+                    %ymm8, %rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(camellia_ctr_32way)
+
+#define gf128mul_x_ble(iv, mask, tmp) \
+       vpsrad $31, iv, tmp; \
+       vpaddq iv, iv, iv; \
+       vpshufd $0x13, tmp, tmp; \
+       vpand mask, tmp, tmp; \
+       vpxor tmp, iv, iv;
+
+#define gf128mul_x2_ble(iv, mask1, mask2, tmp0, tmp1) \
+       vpsrad $31, iv, tmp0; \
+       vpaddq iv, iv, tmp1; \
+       vpsllq $2, iv, iv; \
+       vpshufd $0x13, tmp0, tmp0; \
+       vpsrad $31, tmp1, tmp1; \
+       vpand mask2, tmp0, tmp0; \
+       vpshufd $0x13, tmp1, tmp1; \
+       vpxor tmp0, iv, iv; \
+       vpand mask1, tmp1, tmp1; \
+       vpxor tmp1, iv, iv;
+
+.align 8
+camellia_xts_crypt_32way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (32 blocks)
+        *      %rdx: src (32 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        *      %r8: index for input whitening key
+        *      %r9: pointer to  __camellia_enc_blk32 or __camellia_dec_blk32
+        */
+
+       vzeroupper;
+
+       subq $(16 * 32), %rsp;
+       movq %rsp, %rax;
+
+       vbroadcasti128 .Lxts_gf128mul_and_shl1_mask_0, %ymm12;
+
+       /* load IV and construct second IV */
+       vmovdqu (%rcx), %xmm0;
+       vmovdqa %xmm0, %xmm15;
+       gf128mul_x_ble(%xmm0, %xmm12, %xmm13);
+       vbroadcasti128 .Lxts_gf128mul_and_shl1_mask_1, %ymm13;
+       vinserti128 $1, %xmm0, %ymm15, %ymm0;
+       vpxor 0 * 32(%rdx), %ymm0, %ymm15;
+       vmovdqu %ymm15, 15 * 32(%rax);
+       vmovdqu %ymm0, 0 * 32(%rsi);
+
+       /* construct IVs */
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 1 * 32(%rdx), %ymm0, %ymm15;
+       vmovdqu %ymm15, 14 * 32(%rax);
+       vmovdqu %ymm0, 1 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 2 * 32(%rdx), %ymm0, %ymm15;
+       vmovdqu %ymm15, 13 * 32(%rax);
+       vmovdqu %ymm0, 2 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 3 * 32(%rdx), %ymm0, %ymm15;
+       vmovdqu %ymm15, 12 * 32(%rax);
+       vmovdqu %ymm0, 3 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 4 * 32(%rdx), %ymm0, %ymm11;
+       vmovdqu %ymm0, 4 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 5 * 32(%rdx), %ymm0, %ymm10;
+       vmovdqu %ymm0, 5 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 6 * 32(%rdx), %ymm0, %ymm9;
+       vmovdqu %ymm0, 6 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 7 * 32(%rdx), %ymm0, %ymm8;
+       vmovdqu %ymm0, 7 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 8 * 32(%rdx), %ymm0, %ymm7;
+       vmovdqu %ymm0, 8 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 9 * 32(%rdx), %ymm0, %ymm6;
+       vmovdqu %ymm0, 9 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 10 * 32(%rdx), %ymm0, %ymm5;
+       vmovdqu %ymm0, 10 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 11 * 32(%rdx), %ymm0, %ymm4;
+       vmovdqu %ymm0, 11 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 12 * 32(%rdx), %ymm0, %ymm3;
+       vmovdqu %ymm0, 12 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 13 * 32(%rdx), %ymm0, %ymm2;
+       vmovdqu %ymm0, 13 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 14 * 32(%rdx), %ymm0, %ymm1;
+       vmovdqu %ymm0, 14 * 32(%rsi);
+
+       gf128mul_x2_ble(%ymm0, %ymm12, %ymm13, %ymm14, %ymm15);
+       vpxor 15 * 32(%rdx), %ymm0, %ymm15;
+       vmovdqu %ymm15, 0 * 32(%rax);
+       vmovdqu %ymm0, 15 * 32(%rsi);
+
+       vextracti128 $1, %ymm0, %xmm0;
+       gf128mul_x_ble(%xmm0, %xmm12, %xmm15);
+       vmovdqu %xmm0, (%rcx);
+
+       /* inpack32_pre: */
+       vpbroadcastq (key_table)(CTX, %r8, 8), %ymm15;
+       vpshufb .Lpack_bswap, %ymm15, %ymm15;
+       vpxor 0 * 32(%rax), %ymm15, %ymm0;
+       vpxor %ymm1, %ymm15, %ymm1;
+       vpxor %ymm2, %ymm15, %ymm2;
+       vpxor %ymm3, %ymm15, %ymm3;
+       vpxor %ymm4, %ymm15, %ymm4;
+       vpxor %ymm5, %ymm15, %ymm5;
+       vpxor %ymm6, %ymm15, %ymm6;
+       vpxor %ymm7, %ymm15, %ymm7;
+       vpxor %ymm8, %ymm15, %ymm8;
+       vpxor %ymm9, %ymm15, %ymm9;
+       vpxor %ymm10, %ymm15, %ymm10;
+       vpxor %ymm11, %ymm15, %ymm11;
+       vpxor 12 * 32(%rax), %ymm15, %ymm12;
+       vpxor 13 * 32(%rax), %ymm15, %ymm13;
+       vpxor 14 * 32(%rax), %ymm15, %ymm14;
+       vpxor 15 * 32(%rax), %ymm15, %ymm15;
+
+       call *%r9;
+
+       addq $(16 * 32), %rsp;
+
+       vpxor 0 * 32(%rsi), %ymm7, %ymm7;
+       vpxor 1 * 32(%rsi), %ymm6, %ymm6;
+       vpxor 2 * 32(%rsi), %ymm5, %ymm5;
+       vpxor 3 * 32(%rsi), %ymm4, %ymm4;
+       vpxor 4 * 32(%rsi), %ymm3, %ymm3;
+       vpxor 5 * 32(%rsi), %ymm2, %ymm2;
+       vpxor 6 * 32(%rsi), %ymm1, %ymm1;
+       vpxor 7 * 32(%rsi), %ymm0, %ymm0;
+       vpxor 8 * 32(%rsi), %ymm15, %ymm15;
+       vpxor 9 * 32(%rsi), %ymm14, %ymm14;
+       vpxor 10 * 32(%rsi), %ymm13, %ymm13;
+       vpxor 11 * 32(%rsi), %ymm12, %ymm12;
+       vpxor 12 * 32(%rsi), %ymm11, %ymm11;
+       vpxor 13 * 32(%rsi), %ymm10, %ymm10;
+       vpxor 14 * 32(%rsi), %ymm9, %ymm9;
+       vpxor 15 * 32(%rsi), %ymm8, %ymm8;
+       write_output(%ymm7, %ymm6, %ymm5, %ymm4, %ymm3, %ymm2, %ymm1, %ymm0,
+                    %ymm15, %ymm14, %ymm13, %ymm12, %ymm11, %ymm10, %ymm9,
+                    %ymm8, %rsi);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(camellia_xts_crypt_32way)
+
+ENTRY(camellia_xts_enc_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (32 blocks)
+        *      %rdx: src (32 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       xorl %r8d, %r8d; /* input whitening key, 0 for enc */
+
+       leaq __camellia_enc_blk32, %r9;
+
+       jmp camellia_xts_crypt_32way;
+ENDPROC(camellia_xts_enc_32way)
+
+ENTRY(camellia_xts_dec_32way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (32 blocks)
+        *      %rdx: src (32 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       cmpl $16, key_length(CTX);
+       movl $32, %r8d;
+       movl $24, %eax;
+       cmovel %eax, %r8d;  /* input whitening key, last for dec */
+
+       leaq __camellia_dec_blk32, %r9;
+
+       jmp camellia_xts_crypt_32way;
+ENDPROC(camellia_xts_dec_32way)
diff --git a/arch/x86/crypto/camellia_aesni_avx2_glue.c b/arch/x86/crypto/camellia_aesni_avx2_glue.c
new file mode 100644 (file)
index 0000000..414fe5d
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Glue Code for x86_64/AVX2/AES-NI assembler optimized version of Camellia
+ *
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/crypto/camellia.h>
+#include <asm/crypto/ablk_helper.h>
+#include <asm/crypto/glue_helper.h>
+
+#define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
+#define CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS 32
+
+/* 32-way AVX2/AES-NI parallel cipher functions */
+asmlinkage void camellia_ecb_enc_32way(struct camellia_ctx *ctx, u8 *dst,
+                                      const u8 *src);
+asmlinkage void camellia_ecb_dec_32way(struct camellia_ctx *ctx, u8 *dst,
+                                      const u8 *src);
+
+asmlinkage void camellia_cbc_dec_32way(struct camellia_ctx *ctx, u8 *dst,
+                                      const u8 *src);
+asmlinkage void camellia_ctr_32way(struct camellia_ctx *ctx, u8 *dst,
+                                  const u8 *src, le128 *iv);
+
+asmlinkage void camellia_xts_enc_32way(struct camellia_ctx *ctx, u8 *dst,
+                                      const u8 *src, le128 *iv);
+asmlinkage void camellia_xts_dec_32way(struct camellia_ctx *ctx, u8 *dst,
+                                      const u8 *src, le128 *iv);
+
+static const struct common_glue_ctx camellia_enc = {
+       .num_funcs = 4,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_enc_32way) }
+       }, {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_enc_16way) }
+       }, {
+               .num_blocks = 2,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk_2way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_enc_blk) }
+       } }
+};
+
+static const struct common_glue_ctx camellia_ctr = {
+       .num_funcs = 4,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_ctr_32way) }
+       }, {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_ctr_16way) }
+       }, {
+               .num_blocks = 2,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr_2way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(camellia_crypt_ctr) }
+       } }
+};
+
+static const struct common_glue_ctx camellia_enc_xts = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc_32way) }
+       }, {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc_16way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc) }
+       } }
+};
+
+static const struct common_glue_ctx camellia_dec = {
+       .num_funcs = 4,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_dec_32way) }
+       }, {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_ecb_dec_16way) }
+       }, {
+               .num_blocks = 2,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk_2way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(camellia_dec_blk) }
+       } }
+};
+
+static const struct common_glue_ctx camellia_dec_cbc = {
+       .num_funcs = 4,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_cbc_dec_32way) }
+       }, {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_cbc_dec_16way) }
+       }, {
+               .num_blocks = 2,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_decrypt_cbc_2way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(camellia_dec_blk) }
+       } }
+};
+
+static const struct common_glue_ctx camellia_dec_xts = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec_32way) }
+       }, {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec_16way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec) }
+       } }
+};
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ecb_crypt_128bit(&camellia_enc, desc, dst, src, nbytes);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ecb_crypt_128bit(&camellia_dec, desc, dst, src, nbytes);
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(camellia_enc_blk), desc,
+                                      dst, src, nbytes);
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_cbc_decrypt_128bit(&camellia_dec_cbc, desc, dst, src,
+                                      nbytes);
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ctr_crypt_128bit(&camellia_ctr, desc, dst, src, nbytes);
+}
+
+static inline bool camellia_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+       return glue_fpu_begin(CAMELLIA_BLOCK_SIZE,
+                             CAMELLIA_AESNI_PARALLEL_BLOCKS, NULL, fpu_enabled,
+                             nbytes);
+}
+
+static inline void camellia_fpu_end(bool fpu_enabled)
+{
+       glue_fpu_end(fpu_enabled);
+}
+
+static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+                          unsigned int key_len)
+{
+       return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len,
+                                &tfm->crt_flags);
+}
+
+struct crypt_priv {
+       struct camellia_ctx *ctx;
+       bool fpu_enabled;
+};
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = camellia_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes >= CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS * bsize) {
+               camellia_ecb_enc_32way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
+               nbytes -= bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
+       }
+
+       if (nbytes >= CAMELLIA_AESNI_PARALLEL_BLOCKS * bsize) {
+               camellia_ecb_enc_16way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
+               nbytes -= bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
+       }
+
+       while (nbytes >= CAMELLIA_PARALLEL_BLOCKS * bsize) {
+               camellia_enc_blk_2way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * CAMELLIA_PARALLEL_BLOCKS;
+               nbytes -= bsize * CAMELLIA_PARALLEL_BLOCKS;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               camellia_enc_blk(ctx->ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = CAMELLIA_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = camellia_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes >= CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS * bsize) {
+               camellia_ecb_dec_32way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
+               nbytes -= bsize * CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS;
+       }
+
+       if (nbytes >= CAMELLIA_AESNI_PARALLEL_BLOCKS * bsize) {
+               camellia_ecb_dec_16way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
+               nbytes -= bsize * CAMELLIA_AESNI_PARALLEL_BLOCKS;
+       }
+
+       while (nbytes >= CAMELLIA_PARALLEL_BLOCKS * bsize) {
+               camellia_dec_blk_2way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * CAMELLIA_PARALLEL_BLOCKS;
+               nbytes -= bsize * CAMELLIA_PARALLEL_BLOCKS;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               camellia_dec_blk(ctx->ctx, srcdst, srcdst);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->camellia_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       camellia_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[CAMELLIA_AESNI_AVX2_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->camellia_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       camellia_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+
+       return glue_xts_crypt_128bit(&camellia_enc_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(camellia_enc_blk),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+
+       return glue_xts_crypt_128bit(&camellia_dec_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(camellia_enc_blk),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
+}
+
+static struct crypto_alg cmll_algs[10] = { {
+       .cra_name               = "__ecb-camellia-aesni-avx2",
+       .cra_driver_name        = "__driver-ecb-camellia-aesni-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .setkey         = camellia_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__cbc-camellia-aesni-avx2",
+       .cra_driver_name        = "__driver-cbc-camellia-aesni-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .setkey         = camellia_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__ctr-camellia-aesni-avx2",
+       .cra_driver_name        = "__driver-ctr-camellia-aesni-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct camellia_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = camellia_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "__lrw-camellia-aesni-avx2",
+       .cra_driver_name        = "__driver-lrw-camellia-aesni-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_exit               = lrw_camellia_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE +
+                                         CAMELLIA_BLOCK_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE +
+                                         CAMELLIA_BLOCK_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = lrw_camellia_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__xts-camellia-aesni-avx2",
+       .cra_driver_name        = "__driver-xts-camellia-aesni-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct camellia_xts_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE * 2,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE * 2,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = xts_camellia_setkey,
+                       .encrypt        = xts_encrypt,
+                       .decrypt        = xts_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ecb(camellia)",
+       .cra_driver_name        = "ecb-camellia-aesni-avx2",
+       .cra_priority           = 500,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(camellia)",
+       .cra_driver_name        = "cbc-camellia-aesni-avx2",
+       .cra_priority           = 500,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = __ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ctr(camellia)",
+       .cra_driver_name        = "ctr-camellia-aesni-avx2",
+       .cra_priority           = 500,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_encrypt,
+                       .geniv          = "chainiv",
+               },
+       },
+}, {
+       .cra_name               = "lrw(camellia)",
+       .cra_driver_name        = "lrw-camellia-aesni-avx2",
+       .cra_priority           = 500,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE +
+                                         CAMELLIA_BLOCK_SIZE,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE +
+                                         CAMELLIA_BLOCK_SIZE,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "xts(camellia)",
+       .cra_driver_name        = "xts-camellia-aesni-avx2",
+       .cra_priority           = 500,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAMELLIA_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAMELLIA_MIN_KEY_SIZE * 2,
+                       .max_keysize    = CAMELLIA_MAX_KEY_SIZE * 2,
+                       .ivsize         = CAMELLIA_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+} };
+
+static int __init camellia_aesni_init(void)
+{
+       u64 xcr0;
+
+       if (!cpu_has_avx2 || !cpu_has_avx || !cpu_has_aes || !cpu_has_osxsave) {
+               pr_info("AVX2 or AES-NI instructions are not detected.\n");
+               return -ENODEV;
+       }
+
+       xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+       if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+               pr_info("AVX2 detected but unusable.\n");
+               return -ENODEV;
+       }
+
+       return crypto_register_algs(cmll_algs, ARRAY_SIZE(cmll_algs));
+}
+
+static void __exit camellia_aesni_fini(void)
+{
+       crypto_unregister_algs(cmll_algs, ARRAY_SIZE(cmll_algs));
+}
+
+module_init(camellia_aesni_init);
+module_exit(camellia_aesni_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Camellia Cipher Algorithm, AES-NI/AVX2 optimized");
+MODULE_ALIAS("camellia");
+MODULE_ALIAS("camellia-asm");
index 96cbb60..37fd0c0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Glue Code for x86_64/AVX/AES-NI assembler optimized version of Camellia
  *
- * Copyright © 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #define CAMELLIA_AESNI_PARALLEL_BLOCKS 16
 
-/* 16-way AES-NI parallel cipher functions */
+/* 16-way parallel cipher functions (avx/aes-ni) */
 asmlinkage void camellia_ecb_enc_16way(struct camellia_ctx *ctx, u8 *dst,
                                       const u8 *src);
+EXPORT_SYMBOL_GPL(camellia_ecb_enc_16way);
+
 asmlinkage void camellia_ecb_dec_16way(struct camellia_ctx *ctx, u8 *dst,
                                       const u8 *src);
+EXPORT_SYMBOL_GPL(camellia_ecb_dec_16way);
 
 asmlinkage void camellia_cbc_dec_16way(struct camellia_ctx *ctx, u8 *dst,
                                       const u8 *src);
+EXPORT_SYMBOL_GPL(camellia_cbc_dec_16way);
+
 asmlinkage void camellia_ctr_16way(struct camellia_ctx *ctx, u8 *dst,
                                   const u8 *src, le128 *iv);
+EXPORT_SYMBOL_GPL(camellia_ctr_16way);
+
+asmlinkage void camellia_xts_enc_16way(struct camellia_ctx *ctx, u8 *dst,
+                                      const u8 *src, le128 *iv);
+EXPORT_SYMBOL_GPL(camellia_xts_enc_16way);
+
+asmlinkage void camellia_xts_dec_16way(struct camellia_ctx *ctx, u8 *dst,
+                                      const u8 *src, le128 *iv);
+EXPORT_SYMBOL_GPL(camellia_xts_dec_16way);
+
+void camellia_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv,
+                                 GLUE_FUNC_CAST(camellia_enc_blk));
+}
+EXPORT_SYMBOL_GPL(camellia_xts_enc);
+
+void camellia_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv,
+                                 GLUE_FUNC_CAST(camellia_dec_blk));
+}
+EXPORT_SYMBOL_GPL(camellia_xts_dec);
 
 static const struct common_glue_ctx camellia_enc = {
        .num_funcs = 3,
@@ -69,6 +97,19 @@ static const struct common_glue_ctx camellia_ctr = {
        } }
 };
 
+static const struct common_glue_ctx camellia_enc_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc_16way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_enc) }
+       } }
+};
+
 static const struct common_glue_ctx camellia_dec = {
        .num_funcs = 3,
        .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
@@ -101,6 +142,19 @@ static const struct common_glue_ctx camellia_dec_cbc = {
        } }
 };
 
+static const struct common_glue_ctx camellia_dec_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAMELLIA_AESNI_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec_16way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(camellia_xts_dec) }
+       } }
+};
+
 static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
@@ -261,54 +315,20 @@ static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
        struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-       be128 buf[CAMELLIA_AESNI_PARALLEL_BLOCKS];
-       struct crypt_priv crypt_ctx = {
-               .ctx = &ctx->crypt_ctx,
-               .fpu_enabled = false,
-       };
-       struct xts_crypt_req req = {
-               .tbuf = buf,
-               .tbuflen = sizeof(buf),
 
-               .tweak_ctx = &ctx->tweak_ctx,
-               .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk),
-               .crypt_ctx = &crypt_ctx,
-               .crypt_fn = encrypt_callback,
-       };
-       int ret;
-
-       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-       ret = xts_crypt(desc, dst, src, nbytes, &req);
-       camellia_fpu_end(crypt_ctx.fpu_enabled);
-
-       return ret;
+       return glue_xts_crypt_128bit(&camellia_enc_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(camellia_enc_blk),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
 }
 
 static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
        struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-       be128 buf[CAMELLIA_AESNI_PARALLEL_BLOCKS];
-       struct crypt_priv crypt_ctx = {
-               .ctx = &ctx->crypt_ctx,
-               .fpu_enabled = false,
-       };
-       struct xts_crypt_req req = {
-               .tbuf = buf,
-               .tbuflen = sizeof(buf),
-
-               .tweak_ctx = &ctx->tweak_ctx,
-               .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk),
-               .crypt_ctx = &crypt_ctx,
-               .crypt_fn = decrypt_callback,
-       };
-       int ret;
 
-       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-       ret = xts_crypt(desc, dst, src, nbytes, &req);
-       camellia_fpu_end(crypt_ctx.fpu_enabled);
-
-       return ret;
+       return glue_xts_crypt_128bit(&camellia_dec_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(camellia_enc_blk),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
 }
 
 static struct crypto_alg cmll_algs[10] = { {
index f93b610..e3531f8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2012 Johannes Goetzfried
  *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
  *
- * Copyright © 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 .data
 
 .align 16
+.Lxts_gf128mul_and_shl1_mask:
+       .byte 0x87, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
 .Lbswap_mask:
        .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
 .Lbswap128_mask:
@@ -424,3 +426,47 @@ ENTRY(cast6_ctr_8way)
 
        ret;
 ENDPROC(cast6_ctr_8way)
+
+ENTRY(cast6_xts_enc_8way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       movq %rsi, %r11;
+
+       /* regs <= src, dst <= IVs, regs <= regs xor IVs */
+       load_xts_8way(%rcx, %rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2,
+                     RX, RKR, RKM, .Lxts_gf128mul_and_shl1_mask);
+
+       call __cast6_enc_blk8;
+
+       /* dst <= regs xor IVs(in dst) */
+       store_xts_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       ret;
+ENDPROC(cast6_xts_enc_8way)
+
+ENTRY(cast6_xts_dec_8way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       movq %rsi, %r11;
+
+       /* regs <= src, dst <= IVs, regs <= regs xor IVs */
+       load_xts_8way(%rcx, %rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2,
+                     RX, RKR, RKM, .Lxts_gf128mul_and_shl1_mask);
+
+       call __cast6_dec_blk8;
+
+       /* dst <= regs xor IVs(in dst) */
+       store_xts_8way(%r11, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       ret;
+ENDPROC(cast6_xts_dec_8way)
index 92f7ca2..8d0dfb8 100644 (file)
@@ -4,6 +4,8 @@
  * Copyright (C) 2012 Johannes Goetzfried
  *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
  *
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -50,6 +52,23 @@ asmlinkage void cast6_cbc_dec_8way(struct cast6_ctx *ctx, u8 *dst,
 asmlinkage void cast6_ctr_8way(struct cast6_ctx *ctx, u8 *dst, const u8 *src,
                               le128 *iv);
 
+asmlinkage void cast6_xts_enc_8way(struct cast6_ctx *ctx, u8 *dst,
+                                  const u8 *src, le128 *iv);
+asmlinkage void cast6_xts_dec_8way(struct cast6_ctx *ctx, u8 *dst,
+                                  const u8 *src, le128 *iv);
+
+static void cast6_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv,
+                                 GLUE_FUNC_CAST(__cast6_encrypt));
+}
+
+static void cast6_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv,
+                                 GLUE_FUNC_CAST(__cast6_decrypt));
+}
+
 static void cast6_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
 {
        be128 ctrblk;
@@ -87,6 +106,19 @@ static const struct common_glue_ctx cast6_ctr = {
        } }
 };
 
+static const struct common_glue_ctx cast6_enc_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAST6_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_enc_8way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_enc) }
+       } }
+};
+
 static const struct common_glue_ctx cast6_dec = {
        .num_funcs = 2,
        .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
@@ -113,6 +145,19 @@ static const struct common_glue_ctx cast6_dec_cbc = {
        } }
 };
 
+static const struct common_glue_ctx cast6_dec_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAST6_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_dec_8way) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(cast6_xts_dec) }
+       } }
+};
+
 static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
@@ -307,54 +352,20 @@ static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
        struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-       be128 buf[CAST6_PARALLEL_BLOCKS];
-       struct crypt_priv crypt_ctx = {
-               .ctx = &ctx->crypt_ctx,
-               .fpu_enabled = false,
-       };
-       struct xts_crypt_req req = {
-               .tbuf = buf,
-               .tbuflen = sizeof(buf),
 
-               .tweak_ctx = &ctx->tweak_ctx,
-               .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt),
-               .crypt_ctx = &crypt_ctx,
-               .crypt_fn = encrypt_callback,
-       };
-       int ret;
-
-       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-       ret = xts_crypt(desc, dst, src, nbytes, &req);
-       cast6_fpu_end(crypt_ctx.fpu_enabled);
-
-       return ret;
+       return glue_xts_crypt_128bit(&cast6_enc_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(__cast6_encrypt),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
 }
 
 static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
        struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-       be128 buf[CAST6_PARALLEL_BLOCKS];
-       struct crypt_priv crypt_ctx = {
-               .ctx = &ctx->crypt_ctx,
-               .fpu_enabled = false,
-       };
-       struct xts_crypt_req req = {
-               .tbuf = buf,
-               .tbuflen = sizeof(buf),
-
-               .tweak_ctx = &ctx->tweak_ctx,
-               .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt),
-               .crypt_ctx = &crypt_ctx,
-               .crypt_fn = decrypt_callback,
-       };
-       int ret;
 
-       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-       ret = xts_crypt(desc, dst, src, nbytes, &req);
-       cast6_fpu_end(crypt_ctx.fpu_enabled);
-
-       return ret;
+       return glue_xts_crypt_128bit(&cast6_dec_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(__cast6_encrypt),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
 }
 
 static struct crypto_alg cast6_algs[10] = { {
index c833501..94c27df 100644 (file)
  *      uint crc32_pclmul_le_16(unsigned char const *buffer,
  *                          size_t len, uint crc32)
  */
-.globl crc32_pclmul_le_16
-.align 4, 0x90
-crc32_pclmul_le_16:/* buffer and buffer size are 16 bytes aligned */
+
+ENTRY(crc32_pclmul_le_16) /* buffer and buffer size are 16 bytes aligned */
        movdqa  (BUF), %xmm1
        movdqa  0x10(BUF), %xmm2
        movdqa  0x20(BUF), %xmm3
@@ -244,3 +243,4 @@ fold_64:
        pextrd  $0x01, %xmm1, %eax
 
        ret
+ENDPROC(crc32_pclmul_le_16)
index cf1a7ec..dbc4339 100644 (file)
@@ -1,9 +1,10 @@
 /*
  * Implement fast CRC32C with PCLMULQDQ instructions. (x86_64)
  *
- * The white paper on CRC32C calculations with PCLMULQDQ instruction can be
+ * The white papers on CRC32C calculations with PCLMULQDQ instruction can be
  * downloaded from:
- * http://download.intel.com/design/intarch/papers/323405.pdf
+ * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/crc-iscsi-polynomial-crc32-instruction-paper.pdf
+ * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-paper.pdf
  *
  * Copyright (C) 2012 Intel Corporation.
  *
@@ -42,6 +43,7 @@
  * SOFTWARE.
  */
 
+#include <asm/inst.h>
 #include <linux/linkage.h>
 
 ## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction
@@ -225,10 +227,10 @@ LABEL crc_ %i
        movdqa  (bufp), %xmm0                   # 2 consts: K1:K2
 
        movq    crc_init, %xmm1                 # CRC for block 1
-       pclmulqdq $0x00,%xmm0,%xmm1             # Multiply by K2
+       PCLMULQDQ 0x00,%xmm0,%xmm1              # Multiply by K2
 
        movq    crc1, %xmm2                     # CRC for block 2
-       pclmulqdq $0x10, %xmm0, %xmm2           # Multiply by K1
+       PCLMULQDQ 0x10, %xmm0, %xmm2            # Multiply by K1
 
        pxor    %xmm2,%xmm1
        movq    %xmm1, %rax
index f7b6ea2..02ee230 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Shared glue code for 128bit block ciphers, AVX assembler macros
  *
- * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
        vpxor (6*16)(src), x6, x6; \
        vpxor (7*16)(src), x7, x7; \
        store_8way(dst, x0, x1, x2, x3, x4, x5, x6, x7);
+
+#define gf128mul_x_ble(iv, mask, tmp) \
+       vpsrad $31, iv, tmp; \
+       vpaddq iv, iv, iv; \
+       vpshufd $0x13, tmp, tmp; \
+       vpand mask, tmp, tmp; \
+       vpxor tmp, iv, iv;
+
+#define load_xts_8way(iv, src, dst, x0, x1, x2, x3, x4, x5, x6, x7, tiv, t0, \
+                     t1, xts_gf128mul_and_shl1_mask) \
+       vmovdqa xts_gf128mul_and_shl1_mask, t0; \
+       \
+       /* load IV */ \
+       vmovdqu (iv), tiv; \
+       vpxor (0*16)(src), tiv, x0; \
+       vmovdqu tiv, (0*16)(dst); \
+       \
+       /* construct and store IVs, also xor with source */ \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vpxor (1*16)(src), tiv, x1; \
+       vmovdqu tiv, (1*16)(dst); \
+       \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vpxor (2*16)(src), tiv, x2; \
+       vmovdqu tiv, (2*16)(dst); \
+       \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vpxor (3*16)(src), tiv, x3; \
+       vmovdqu tiv, (3*16)(dst); \
+       \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vpxor (4*16)(src), tiv, x4; \
+       vmovdqu tiv, (4*16)(dst); \
+       \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vpxor (5*16)(src), tiv, x5; \
+       vmovdqu tiv, (5*16)(dst); \
+       \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vpxor (6*16)(src), tiv, x6; \
+       vmovdqu tiv, (6*16)(dst); \
+       \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vpxor (7*16)(src), tiv, x7; \
+       vmovdqu tiv, (7*16)(dst); \
+       \
+       gf128mul_x_ble(tiv, t0, t1); \
+       vmovdqu tiv, (iv);
+
+#define store_xts_8way(dst, x0, x1, x2, x3, x4, x5, x6, x7) \
+       vpxor (0*16)(dst), x0, x0; \
+       vpxor (1*16)(dst), x1, x1; \
+       vpxor (2*16)(dst), x2, x2; \
+       vpxor (3*16)(dst), x3, x3; \
+       vpxor (4*16)(dst), x4, x4; \
+       vpxor (5*16)(dst), x5, x5; \
+       vpxor (6*16)(dst), x6, x6; \
+       vpxor (7*16)(dst), x7, x7; \
+       store_8way(dst, x0, x1, x2, x3, x4, x5, x6, x7);
diff --git a/arch/x86/crypto/glue_helper-asm-avx2.S b/arch/x86/crypto/glue_helper-asm-avx2.S
new file mode 100644 (file)
index 0000000..a53ac11
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Shared glue code for 128bit block ciphers, AVX2 assembler macros
+ *
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#define load_16way(src, x0, x1, x2, x3, x4, x5, x6, x7) \
+       vmovdqu (0*32)(src), x0; \
+       vmovdqu (1*32)(src), x1; \
+       vmovdqu (2*32)(src), x2; \
+       vmovdqu (3*32)(src), x3; \
+       vmovdqu (4*32)(src), x4; \
+       vmovdqu (5*32)(src), x5; \
+       vmovdqu (6*32)(src), x6; \
+       vmovdqu (7*32)(src), x7;
+
+#define store_16way(dst, x0, x1, x2, x3, x4, x5, x6, x7) \
+       vmovdqu x0, (0*32)(dst); \
+       vmovdqu x1, (1*32)(dst); \
+       vmovdqu x2, (2*32)(dst); \
+       vmovdqu x3, (3*32)(dst); \
+       vmovdqu x4, (4*32)(dst); \
+       vmovdqu x5, (5*32)(dst); \
+       vmovdqu x6, (6*32)(dst); \
+       vmovdqu x7, (7*32)(dst);
+
+#define store_cbc_16way(src, dst, x0, x1, x2, x3, x4, x5, x6, x7, t0) \
+       vpxor t0, t0, t0; \
+       vinserti128 $1, (src), t0, t0; \
+       vpxor t0, x0, x0; \
+       vpxor (0*32+16)(src), x1, x1; \
+       vpxor (1*32+16)(src), x2, x2; \
+       vpxor (2*32+16)(src), x3, x3; \
+       vpxor (3*32+16)(src), x4, x4; \
+       vpxor (4*32+16)(src), x5, x5; \
+       vpxor (5*32+16)(src), x6, x6; \
+       vpxor (6*32+16)(src), x7, x7; \
+       store_16way(dst, x0, x1, x2, x3, x4, x5, x6, x7);
+
+#define inc_le128(x, minus_one, tmp) \
+       vpcmpeqq minus_one, x, tmp; \
+       vpsubq minus_one, x, x; \
+       vpslldq $8, tmp, tmp; \
+       vpsubq tmp, x, x;
+
+#define add2_le128(x, minus_one, minus_two, tmp1, tmp2) \
+       vpcmpeqq minus_one, x, tmp1; \
+       vpcmpeqq minus_two, x, tmp2; \
+       vpsubq minus_two, x, x; \
+       vpor tmp2, tmp1, tmp1; \
+       vpslldq $8, tmp1, tmp1; \
+       vpsubq tmp1, x, x;
+
+#define load_ctr_16way(iv, bswap, x0, x1, x2, x3, x4, x5, x6, x7, t0, t0x, t1, \
+                      t1x, t2, t2x, t3, t3x, t4, t5) \
+       vpcmpeqd t0, t0, t0; \
+       vpsrldq $8, t0, t0; /* ab: -1:0 ; cd: -1:0 */ \
+       vpaddq t0, t0, t4; /* ab: -2:0 ; cd: -2:0 */\
+       \
+       /* load IV and byteswap */ \
+       vmovdqu (iv), t2x; \
+       vmovdqa t2x, t3x; \
+       inc_le128(t2x, t0x, t1x); \
+       vbroadcasti128 bswap, t1; \
+       vinserti128 $1, t2x, t3, t2; /* ab: le0 ; cd: le1 */ \
+       vpshufb t1, t2, x0; \
+       \
+       /* construct IVs */ \
+       add2_le128(t2, t0, t4, t3, t5); /* ab: le2 ; cd: le3 */ \
+       vpshufb t1, t2, x1; \
+       add2_le128(t2, t0, t4, t3, t5); \
+       vpshufb t1, t2, x2; \
+       add2_le128(t2, t0, t4, t3, t5); \
+       vpshufb t1, t2, x3; \
+       add2_le128(t2, t0, t4, t3, t5); \
+       vpshufb t1, t2, x4; \
+       add2_le128(t2, t0, t4, t3, t5); \
+       vpshufb t1, t2, x5; \
+       add2_le128(t2, t0, t4, t3, t5); \
+       vpshufb t1, t2, x6; \
+       add2_le128(t2, t0, t4, t3, t5); \
+       vpshufb t1, t2, x7; \
+       vextracti128 $1, t2, t2x; \
+       inc_le128(t2x, t0x, t3x); \
+       vmovdqu t2x, (iv);
+
+#define store_ctr_16way(src, dst, x0, x1, x2, x3, x4, x5, x6, x7) \
+       vpxor (0*32)(src), x0, x0; \
+       vpxor (1*32)(src), x1, x1; \
+       vpxor (2*32)(src), x2, x2; \
+       vpxor (3*32)(src), x3, x3; \
+       vpxor (4*32)(src), x4, x4; \
+       vpxor (5*32)(src), x5, x5; \
+       vpxor (6*32)(src), x6, x6; \
+       vpxor (7*32)(src), x7, x7; \
+       store_16way(dst, x0, x1, x2, x3, x4, x5, x6, x7);
+
+#define gf128mul_x_ble(iv, mask, tmp) \
+       vpsrad $31, iv, tmp; \
+       vpaddq iv, iv, iv; \
+       vpshufd $0x13, tmp, tmp; \
+       vpand mask, tmp, tmp; \
+       vpxor tmp, iv, iv;
+
+#define gf128mul_x2_ble(iv, mask1, mask2, tmp0, tmp1) \
+       vpsrad $31, iv, tmp0; \
+       vpaddq iv, iv, tmp1; \
+       vpsllq $2, iv, iv; \
+       vpshufd $0x13, tmp0, tmp0; \
+       vpsrad $31, tmp1, tmp1; \
+       vpand mask2, tmp0, tmp0; \
+       vpshufd $0x13, tmp1, tmp1; \
+       vpxor tmp0, iv, iv; \
+       vpand mask1, tmp1, tmp1; \
+       vpxor tmp1, iv, iv;
+
+#define load_xts_16way(iv, src, dst, x0, x1, x2, x3, x4, x5, x6, x7, tiv, \
+                      tivx, t0, t0x, t1, t1x, t2, t2x, t3, \
+                      xts_gf128mul_and_shl1_mask_0, \
+                      xts_gf128mul_and_shl1_mask_1) \
+       vbroadcasti128 xts_gf128mul_and_shl1_mask_0, t1; \
+       \
+       /* load IV and construct second IV */ \
+       vmovdqu (iv), tivx; \
+       vmovdqa tivx, t0x; \
+       gf128mul_x_ble(tivx, t1x, t2x); \
+       vbroadcasti128 xts_gf128mul_and_shl1_mask_1, t2; \
+       vinserti128 $1, tivx, t0, tiv; \
+       vpxor (0*32)(src), tiv, x0; \
+       vmovdqu tiv, (0*32)(dst); \
+       \
+       /* construct and store IVs, also xor with source */ \
+       gf128mul_x2_ble(tiv, t1, t2, t0, t3); \
+       vpxor (1*32)(src), tiv, x1; \
+       vmovdqu tiv, (1*32)(dst); \
+       \
+       gf128mul_x2_ble(tiv, t1, t2, t0, t3); \
+       vpxor (2*32)(src), tiv, x2; \
+       vmovdqu tiv, (2*32)(dst); \
+       \
+       gf128mul_x2_ble(tiv, t1, t2, t0, t3); \
+       vpxor (3*32)(src), tiv, x3; \
+       vmovdqu tiv, (3*32)(dst); \
+       \
+       gf128mul_x2_ble(tiv, t1, t2, t0, t3); \
+       vpxor (4*32)(src), tiv, x4; \
+       vmovdqu tiv, (4*32)(dst); \
+       \
+       gf128mul_x2_ble(tiv, t1, t2, t0, t3); \
+       vpxor (5*32)(src), tiv, x5; \
+       vmovdqu tiv, (5*32)(dst); \
+       \
+       gf128mul_x2_ble(tiv, t1, t2, t0, t3); \
+       vpxor (6*32)(src), tiv, x6; \
+       vmovdqu tiv, (6*32)(dst); \
+       \
+       gf128mul_x2_ble(tiv, t1, t2, t0, t3); \
+       vpxor (7*32)(src), tiv, x7; \
+       vmovdqu tiv, (7*32)(dst); \
+       \
+       vextracti128 $1, tiv, tivx; \
+       gf128mul_x_ble(tivx, t1x, t2x); \
+       vmovdqu tivx, (iv);
+
+#define store_xts_16way(dst, x0, x1, x2, x3, x4, x5, x6, x7) \
+       vpxor (0*32)(dst), x0, x0; \
+       vpxor (1*32)(dst), x1, x1; \
+       vpxor (2*32)(dst), x2, x2; \
+       vpxor (3*32)(dst), x3, x3; \
+       vpxor (4*32)(dst), x4, x4; \
+       vpxor (5*32)(dst), x5, x5; \
+       vpxor (6*32)(dst), x6, x6; \
+       vpxor (7*32)(dst), x7, x7; \
+       store_16way(dst, x0, x1, x2, x3, x4, x5, x6, x7);
index 22ce4f6..432f1d7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Shared glue code for 128bit block ciphers
  *
- * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
  *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
@@ -304,4 +304,99 @@ int glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx,
 }
 EXPORT_SYMBOL_GPL(glue_ctr_crypt_128bit);
 
+static unsigned int __glue_xts_crypt_128bit(const struct common_glue_ctx *gctx,
+                                           void *ctx,
+                                           struct blkcipher_desc *desc,
+                                           struct blkcipher_walk *walk)
+{
+       const unsigned int bsize = 128 / 8;
+       unsigned int nbytes = walk->nbytes;
+       u128 *src = (u128 *)walk->src.virt.addr;
+       u128 *dst = (u128 *)walk->dst.virt.addr;
+       unsigned int num_blocks, func_bytes;
+       unsigned int i;
+
+       /* Process multi-block batch */
+       for (i = 0; i < gctx->num_funcs; i++) {
+               num_blocks = gctx->funcs[i].num_blocks;
+               func_bytes = bsize * num_blocks;
+
+               if (nbytes >= func_bytes) {
+                       do {
+                               gctx->funcs[i].fn_u.xts(ctx, dst, src,
+                                                       (le128 *)walk->iv);
+
+                               src += num_blocks;
+                               dst += num_blocks;
+                               nbytes -= func_bytes;
+                       } while (nbytes >= func_bytes);
+
+                       if (nbytes < bsize)
+                               goto done;
+               }
+       }
+
+done:
+       return nbytes;
+}
+
+/* for implementations implementing faster XTS IV generator */
+int glue_xts_crypt_128bit(const struct common_glue_ctx *gctx,
+                         struct blkcipher_desc *desc, struct scatterlist *dst,
+                         struct scatterlist *src, unsigned int nbytes,
+                         void (*tweak_fn)(void *ctx, u8 *dst, const u8 *src),
+                         void *tweak_ctx, void *crypt_ctx)
+{
+       const unsigned int bsize = 128 / 8;
+       bool fpu_enabled = false;
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+
+       err = blkcipher_walk_virt(desc, &walk);
+       nbytes = walk.nbytes;
+       if (!nbytes)
+               return err;
+
+       /* set minimum length to bsize, for tweak_fn */
+       fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit,
+                                    desc, fpu_enabled,
+                                    nbytes < bsize ? bsize : nbytes);
+
+       /* calculate first value of T */
+       tweak_fn(tweak_ctx, walk.iv, walk.iv);
+
+       while (nbytes) {
+               nbytes = __glue_xts_crypt_128bit(gctx, crypt_ctx, desc, &walk);
+
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+               nbytes = walk.nbytes;
+       }
+
+       glue_fpu_end(fpu_enabled);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(glue_xts_crypt_128bit);
+
+void glue_xts_crypt_128bit_one(void *ctx, u128 *dst, const u128 *src, le128 *iv,
+                              common_glue_func_t fn)
+{
+       le128 ivblk = *iv;
+
+       /* generate next IV */
+       le128_gf128mul_x_ble(iv, &ivblk);
+
+       /* CC <- T xor C */
+       u128_xor(dst, src, (u128 *)&ivblk);
+
+       /* PP <- D(Key2,CC) */
+       fn(ctx, (u8 *)dst, (u8 *)dst);
+
+       /* P <- T xor PP */
+       u128_xor(dst, dst, (u128 *)&ivblk);
+}
+EXPORT_SYMBOL_GPL(glue_xts_crypt_128bit_one);
+
 MODULE_LICENSE("GPL");
index 43c9386..2f202f4 100644 (file)
@@ -4,8 +4,7 @@
  * Copyright (C) 2012 Johannes Goetzfried
  *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
  *
- * Based on arch/x86/crypto/serpent-sse2-x86_64-asm_64.S by
- *  Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2011-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,6 +33,8 @@
 
 .Lbswap128_mask:
        .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+.Lxts_gf128mul_and_shl1_mask:
+       .byte 0x87, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
 
 .text
 
@@ -739,3 +740,43 @@ ENTRY(serpent_ctr_8way_avx)
 
        ret;
 ENDPROC(serpent_ctr_8way_avx)
+
+ENTRY(serpent_xts_enc_8way_avx)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       /* regs <= src, dst <= IVs, regs <= regs xor IVs */
+       load_xts_8way(%rcx, %rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2,
+                     RK0, RK1, RK2, .Lxts_gf128mul_and_shl1_mask);
+
+       call __serpent_enc_blk8_avx;
+
+       /* dst <= regs xor IVs(in dst) */
+       store_xts_8way(%rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       ret;
+ENDPROC(serpent_xts_enc_8way_avx)
+
+ENTRY(serpent_xts_dec_8way_avx)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       /* regs <= src, dst <= IVs, regs <= regs xor IVs */
+       load_xts_8way(%rcx, %rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2,
+                     RK0, RK1, RK2, .Lxts_gf128mul_and_shl1_mask);
+
+       call __serpent_dec_blk8_avx;
+
+       /* dst <= regs xor IVs(in dst) */
+       store_xts_8way(%rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2);
+
+       ret;
+ENDPROC(serpent_xts_dec_8way_avx)
diff --git a/arch/x86/crypto/serpent-avx2-asm_64.S b/arch/x86/crypto/serpent-avx2-asm_64.S
new file mode 100644 (file)
index 0000000..b222085
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * x86_64/AVX2 assembler optimized version of Serpent
+ *
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * Based on AVX assembler implementation of Serpent by:
+ *  Copyright © 2012 Johannes Goetzfried
+ *      <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/linkage.h>
+#include "glue_helper-asm-avx2.S"
+
+.file "serpent-avx2-asm_64.S"
+
+.data
+.align 16
+
+.Lbswap128_mask:
+       .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+.Lxts_gf128mul_and_shl1_mask_0:
+       .byte 0x87, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
+.Lxts_gf128mul_and_shl1_mask_1:
+       .byte 0x0e, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0
+
+.text
+
+#define CTX %rdi
+
+#define RNOT %ymm0
+#define tp  %ymm1
+
+#define RA1 %ymm2
+#define RA2 %ymm3
+#define RB1 %ymm4
+#define RB2 %ymm5
+#define RC1 %ymm6
+#define RC2 %ymm7
+#define RD1 %ymm8
+#define RD2 %ymm9
+#define RE1 %ymm10
+#define RE2 %ymm11
+
+#define RK0 %ymm12
+#define RK1 %ymm13
+#define RK2 %ymm14
+#define RK3 %ymm15
+
+#define RK0x %xmm12
+#define RK1x %xmm13
+#define RK2x %xmm14
+#define RK3x %xmm15
+
+#define S0_1(x0, x1, x2, x3, x4)      \
+       vpor            x0,   x3, tp; \
+       vpxor           x3,   x0, x0; \
+       vpxor           x2,   x3, x4; \
+       vpxor           RNOT, x4, x4; \
+       vpxor           x1,   tp, x3; \
+       vpand           x0,   x1, x1; \
+       vpxor           x4,   x1, x1; \
+       vpxor           x0,   x2, x2;
+#define S0_2(x0, x1, x2, x3, x4)      \
+       vpxor           x3,   x0, x0; \
+       vpor            x0,   x4, x4; \
+       vpxor           x2,   x0, x0; \
+       vpand           x1,   x2, x2; \
+       vpxor           x2,   x3, x3; \
+       vpxor           RNOT, x1, x1; \
+       vpxor           x4,   x2, x2; \
+       vpxor           x2,   x1, x1;
+
+#define S1_1(x0, x1, x2, x3, x4)      \
+       vpxor           x0,   x1, tp; \
+       vpxor           x3,   x0, x0; \
+       vpxor           RNOT, x3, x3; \
+       vpand           tp,   x1, x4; \
+       vpor            tp,   x0, x0; \
+       vpxor           x2,   x3, x3; \
+       vpxor           x3,   x0, x0; \
+       vpxor           x3,   tp, x1;
+#define S1_2(x0, x1, x2, x3, x4)      \
+       vpxor           x4,   x3, x3; \
+       vpor            x4,   x1, x1; \
+       vpxor           x2,   x4, x4; \
+       vpand           x0,   x2, x2; \
+       vpxor           x1,   x2, x2; \
+       vpor            x0,   x1, x1; \
+       vpxor           RNOT, x0, x0; \
+       vpxor           x2,   x0, x0; \
+       vpxor           x1,   x4, x4;
+
+#define S2_1(x0, x1, x2, x3, x4)      \
+       vpxor           RNOT, x3, x3; \
+       vpxor           x0,   x1, x1; \
+       vpand           x2,   x0, tp; \
+       vpxor           x3,   tp, tp; \
+       vpor            x0,   x3, x3; \
+       vpxor           x1,   x2, x2; \
+       vpxor           x1,   x3, x3; \
+       vpand           tp,   x1, x1;
+#define S2_2(x0, x1, x2, x3, x4)      \
+       vpxor           x2,   tp, tp; \
+       vpand           x3,   x2, x2; \
+       vpor            x1,   x3, x3; \
+       vpxor           RNOT, tp, tp; \
+       vpxor           tp,   x3, x3; \
+       vpxor           tp,   x0, x4; \
+       vpxor           x2,   tp, x0; \
+       vpor            x2,   x1, x1;
+
+#define S3_1(x0, x1, x2, x3, x4)      \
+       vpxor           x3,   x1, tp; \
+       vpor            x0,   x3, x3; \
+       vpand           x0,   x1, x4; \
+       vpxor           x2,   x0, x0; \
+       vpxor           tp,   x2, x2; \
+       vpand           x3,   tp, x1; \
+       vpxor           x3,   x2, x2; \
+       vpor            x4,   x0, x0; \
+       vpxor           x3,   x4, x4;
+#define S3_2(x0, x1, x2, x3, x4)      \
+       vpxor           x0,   x1, x1; \
+       vpand           x3,   x0, x0; \
+       vpand           x4,   x3, x3; \
+       vpxor           x2,   x3, x3; \
+       vpor            x1,   x4, x4; \
+       vpand           x1,   x2, x2; \
+       vpxor           x3,   x4, x4; \
+       vpxor           x3,   x0, x0; \
+       vpxor           x2,   x3, x3;
+
+#define S4_1(x0, x1, x2, x3, x4)      \
+       vpand           x0,   x3, tp; \
+       vpxor           x3,   x0, x0; \
+       vpxor           x2,   tp, tp; \
+       vpor            x3,   x2, x2; \
+       vpxor           x1,   x0, x0; \
+       vpxor           tp,   x3, x4; \
+       vpor            x0,   x2, x2; \
+       vpxor           x1,   x2, x2;
+#define S4_2(x0, x1, x2, x3, x4)      \
+       vpand           x0,   x1, x1; \
+       vpxor           x4,   x1, x1; \
+       vpand           x2,   x4, x4; \
+       vpxor           tp,   x2, x2; \
+       vpxor           x0,   x4, x4; \
+       vpor            x1,   tp, x3; \
+       vpxor           RNOT, x1, x1; \
+       vpxor           x0,   x3, x3;
+
+#define S5_1(x0, x1, x2, x3, x4)      \
+       vpor            x0,   x1, tp; \
+       vpxor           tp,   x2, x2; \
+       vpxor           RNOT, x3, x3; \
+       vpxor           x0,   x1, x4; \
+       vpxor           x2,   x0, x0; \
+       vpand           x4,   tp, x1; \
+       vpor            x3,   x4, x4; \
+       vpxor           x0,   x4, x4;
+#define S5_2(x0, x1, x2, x3, x4)      \
+       vpand           x3,   x0, x0; \
+       vpxor           x3,   x1, x1; \
+       vpxor           x2,   x3, x3; \
+       vpxor           x1,   x0, x0; \
+       vpand           x4,   x2, x2; \
+       vpxor           x2,   x1, x1; \
+       vpand           x0,   x2, x2; \
+       vpxor           x2,   x3, x3;
+
+#define S6_1(x0, x1, x2, x3, x4)      \
+       vpxor           x0,   x3, x3; \
+       vpxor           x2,   x1, tp; \
+       vpxor           x0,   x2, x2; \
+       vpand           x3,   x0, x0; \
+       vpor            x3,   tp, tp; \
+       vpxor           RNOT, x1, x4; \
+       vpxor           tp,   x0, x0; \
+       vpxor           x2,   tp, x1;
+#define S6_2(x0, x1, x2, x3, x4)      \
+       vpxor           x4,   x3, x3; \
+       vpxor           x0,   x4, x4; \
+       vpand           x0,   x2, x2; \
+       vpxor           x1,   x4, x4; \
+       vpxor           x3,   x2, x2; \
+       vpand           x1,   x3, x3; \
+       vpxor           x0,   x3, x3; \
+       vpxor           x2,   x1, x1;
+
+#define S7_1(x0, x1, x2, x3, x4)      \
+       vpxor           RNOT, x1, tp; \
+       vpxor           RNOT, x0, x0; \
+       vpand           x2,   tp, x1; \
+       vpxor           x3,   x1, x1; \
+       vpor            tp,   x3, x3; \
+       vpxor           x2,   tp, x4; \
+       vpxor           x3,   x2, x2; \
+       vpxor           x0,   x3, x3; \
+       vpor            x1,   x0, x0;
+#define S7_2(x0, x1, x2, x3, x4)      \
+       vpand           x0,   x2, x2; \
+       vpxor           x4,   x0, x0; \
+       vpxor           x3,   x4, x4; \
+       vpand           x0,   x3, x3; \
+       vpxor           x1,   x4, x4; \
+       vpxor           x4,   x2, x2; \
+       vpxor           x1,   x3, x3; \
+       vpor            x0,   x4, x4; \
+       vpxor           x1,   x4, x4;
+
+#define SI0_1(x0, x1, x2, x3, x4)     \
+       vpxor           x0,   x1, x1; \
+       vpor            x1,   x3, tp; \
+       vpxor           x1,   x3, x4; \
+       vpxor           RNOT, x0, x0; \
+       vpxor           tp,   x2, x2; \
+       vpxor           x0,   tp, x3; \
+       vpand           x1,   x0, x0; \
+       vpxor           x2,   x0, x0;
+#define SI0_2(x0, x1, x2, x3, x4)     \
+       vpand           x3,   x2, x2; \
+       vpxor           x4,   x3, x3; \
+       vpxor           x3,   x2, x2; \
+       vpxor           x3,   x1, x1; \
+       vpand           x0,   x3, x3; \
+       vpxor           x0,   x1, x1; \
+       vpxor           x2,   x0, x0; \
+       vpxor           x3,   x4, x4;
+
+#define SI1_1(x0, x1, x2, x3, x4)     \
+       vpxor           x3,   x1, x1; \
+       vpxor           x2,   x0, tp; \
+       vpxor           RNOT, x2, x2; \
+       vpor            x1,   x0, x4; \
+       vpxor           x3,   x4, x4; \
+       vpand           x1,   x3, x3; \
+       vpxor           x2,   x1, x1; \
+       vpand           x4,   x2, x2;
+#define SI1_2(x0, x1, x2, x3, x4)     \
+       vpxor           x1,   x4, x4; \
+       vpor            x3,   x1, x1; \
+       vpxor           tp,   x3, x3; \
+       vpxor           tp,   x2, x2; \
+       vpor            x4,   tp, x0; \
+       vpxor           x4,   x2, x2; \
+       vpxor           x0,   x1, x1; \
+       vpxor           x1,   x4, x4;
+
+#define SI2_1(x0, x1, x2, x3, x4)     \
+       vpxor           x1,   x2, x2; \
+       vpxor           RNOT, x3, tp; \
+       vpor            x2,   tp, tp; \
+       vpxor           x3,   x2, x2; \
+       vpxor           x0,   x3, x4; \
+       vpxor           x1,   tp, x3; \
+       vpor            x2,   x1, x1; \
+       vpxor           x0,   x2, x2;
+#define SI2_2(x0, x1, x2, x3, x4)     \
+       vpxor           x4,   x1, x1; \
+       vpor            x3,   x4, x4; \
+       vpxor           x3,   x2, x2; \
+       vpxor           x2,   x4, x4; \
+       vpand           x1,   x2, x2; \
+       vpxor           x3,   x2, x2; \
+       vpxor           x4,   x3, x3; \
+       vpxor           x0,   x4, x4;
+
+#define SI3_1(x0, x1, x2, x3, x4)     \
+       vpxor           x1,   x2, x2; \
+       vpand           x2,   x1, tp; \
+       vpxor           x0,   tp, tp; \
+       vpor            x1,   x0, x0; \
+       vpxor           x3,   x1, x4; \
+       vpxor           x3,   x0, x0; \
+       vpor            tp,   x3, x3; \
+       vpxor           x2,   tp, x1;
+#define SI3_2(x0, x1, x2, x3, x4)     \
+       vpxor           x3,   x1, x1; \
+       vpxor           x2,   x0, x0; \
+       vpxor           x3,   x2, x2; \
+       vpand           x1,   x3, x3; \
+       vpxor           x0,   x1, x1; \
+       vpand           x2,   x0, x0; \
+       vpxor           x3,   x4, x4; \
+       vpxor           x0,   x3, x3; \
+       vpxor           x1,   x0, x0;
+
+#define SI4_1(x0, x1, x2, x3, x4)     \
+       vpxor           x3,   x2, x2; \
+       vpand           x1,   x0, tp; \
+       vpxor           x2,   tp, tp; \
+       vpor            x3,   x2, x2; \
+       vpxor           RNOT, x0, x4; \
+       vpxor           tp,   x1, x1; \
+       vpxor           x2,   tp, x0; \
+       vpand           x4,   x2, x2;
+#define SI4_2(x0, x1, x2, x3, x4)     \
+       vpxor           x0,   x2, x2; \
+       vpor            x4,   x0, x0; \
+       vpxor           x3,   x0, x0; \
+       vpand           x2,   x3, x3; \
+       vpxor           x3,   x4, x4; \
+       vpxor           x1,   x3, x3; \
+       vpand           x0,   x1, x1; \
+       vpxor           x1,   x4, x4; \
+       vpxor           x3,   x0, x0;
+
+#define SI5_1(x0, x1, x2, x3, x4)     \
+       vpor            x2,   x1, tp; \
+       vpxor           x1,   x2, x2; \
+       vpxor           x3,   tp, tp; \
+       vpand           x1,   x3, x3; \
+       vpxor           x3,   x2, x2; \
+       vpor            x0,   x3, x3; \
+       vpxor           RNOT, x0, x0; \
+       vpxor           x2,   x3, x3; \
+       vpor            x0,   x2, x2;
+#define SI5_2(x0, x1, x2, x3, x4)     \
+       vpxor           tp,   x1, x4; \
+       vpxor           x4,   x2, x2; \
+       vpand           x0,   x4, x4; \
+       vpxor           tp,   x0, x0; \
+       vpxor           x3,   tp, x1; \
+       vpand           x2,   x0, x0; \
+       vpxor           x3,   x2, x2; \
+       vpxor           x2,   x0, x0; \
+       vpxor           x4,   x2, x2; \
+       vpxor           x3,   x4, x4;
+
+#define SI6_1(x0, x1, x2, x3, x4)     \
+       vpxor           x2,   x0, x0; \
+       vpand           x3,   x0, tp; \
+       vpxor           x3,   x2, x2; \
+       vpxor           x2,   tp, tp; \
+       vpxor           x1,   x3, x3; \
+       vpor            x0,   x2, x2; \
+       vpxor           x3,   x2, x2; \
+       vpand           tp,   x3, x3;
+#define SI6_2(x0, x1, x2, x3, x4)     \
+       vpxor           RNOT, tp, tp; \
+       vpxor           x1,   x3, x3; \
+       vpand           x2,   x1, x1; \
+       vpxor           tp,   x0, x4; \
+       vpxor           x4,   x3, x3; \
+       vpxor           x2,   x4, x4; \
+       vpxor           x1,   tp, x0; \
+       vpxor           x0,   x2, x2;
+
+#define SI7_1(x0, x1, x2, x3, x4)     \
+       vpand           x0,   x3, tp; \
+       vpxor           x2,   x0, x0; \
+       vpor            x3,   x2, x2; \
+       vpxor           x1,   x3, x4; \
+       vpxor           RNOT, x0, x0; \
+       vpor            tp,   x1, x1; \
+       vpxor           x0,   x4, x4; \
+       vpand           x2,   x0, x0; \
+       vpxor           x1,   x0, x0;
+#define SI7_2(x0, x1, x2, x3, x4)     \
+       vpand           x2,   x1, x1; \
+       vpxor           x2,   tp, x3; \
+       vpxor           x3,   x4, x4; \
+       vpand           x3,   x2, x2; \
+       vpor            x0,   x3, x3; \
+       vpxor           x4,   x1, x1; \
+       vpxor           x4,   x3, x3; \
+       vpand           x0,   x4, x4; \
+       vpxor           x2,   x4, x4;
+
+#define get_key(i,j,t) \
+       vpbroadcastd (4*(i)+(j))*4(CTX), t;
+
+#define K2(x0, x1, x2, x3, x4, i) \
+       get_key(i, 0, RK0); \
+       get_key(i, 1, RK1); \
+       get_key(i, 2, RK2); \
+       get_key(i, 3, RK3); \
+       vpxor RK0,      x0 ## 1, x0 ## 1; \
+       vpxor RK1,      x1 ## 1, x1 ## 1; \
+       vpxor RK2,      x2 ## 1, x2 ## 1; \
+       vpxor RK3,      x3 ## 1, x3 ## 1; \
+               vpxor RK0,      x0 ## 2, x0 ## 2; \
+               vpxor RK1,      x1 ## 2, x1 ## 2; \
+               vpxor RK2,      x2 ## 2, x2 ## 2; \
+               vpxor RK3,      x3 ## 2, x3 ## 2;
+
+#define LK2(x0, x1, x2, x3, x4, i) \
+       vpslld $13,             x0 ## 1, x4 ## 1;          \
+       vpsrld $(32 - 13),      x0 ## 1, x0 ## 1;          \
+       vpor                    x4 ## 1, x0 ## 1, x0 ## 1; \
+       vpxor                   x0 ## 1, x1 ## 1, x1 ## 1; \
+       vpslld $3,              x2 ## 1, x4 ## 1;          \
+       vpsrld $(32 - 3),       x2 ## 1, x2 ## 1;          \
+       vpor                    x4 ## 1, x2 ## 1, x2 ## 1; \
+       vpxor                   x2 ## 1, x1 ## 1, x1 ## 1; \
+               vpslld $13,             x0 ## 2, x4 ## 2;          \
+               vpsrld $(32 - 13),      x0 ## 2, x0 ## 2;          \
+               vpor                    x4 ## 2, x0 ## 2, x0 ## 2; \
+               vpxor                   x0 ## 2, x1 ## 2, x1 ## 2; \
+               vpslld $3,              x2 ## 2, x4 ## 2;          \
+               vpsrld $(32 - 3),       x2 ## 2, x2 ## 2;          \
+               vpor                    x4 ## 2, x2 ## 2, x2 ## 2; \
+               vpxor                   x2 ## 2, x1 ## 2, x1 ## 2; \
+       vpslld $1,              x1 ## 1, x4 ## 1;          \
+       vpsrld $(32 - 1),       x1 ## 1, x1 ## 1;          \
+       vpor                    x4 ## 1, x1 ## 1, x1 ## 1; \
+       vpslld $3,              x0 ## 1, x4 ## 1;          \
+       vpxor                   x2 ## 1, x3 ## 1, x3 ## 1; \
+       vpxor                   x4 ## 1, x3 ## 1, x3 ## 1; \
+       get_key(i, 1, RK1); \
+               vpslld $1,              x1 ## 2, x4 ## 2;          \
+               vpsrld $(32 - 1),       x1 ## 2, x1 ## 2;          \
+               vpor                    x4 ## 2, x1 ## 2, x1 ## 2; \
+               vpslld $3,              x0 ## 2, x4 ## 2;          \
+               vpxor                   x2 ## 2, x3 ## 2, x3 ## 2; \
+               vpxor                   x4 ## 2, x3 ## 2, x3 ## 2; \
+               get_key(i, 3, RK3); \
+       vpslld $7,              x3 ## 1, x4 ## 1;          \
+       vpsrld $(32 - 7),       x3 ## 1, x3 ## 1;          \
+       vpor                    x4 ## 1, x3 ## 1, x3 ## 1; \
+       vpslld $7,              x1 ## 1, x4 ## 1;          \
+       vpxor                   x1 ## 1, x0 ## 1, x0 ## 1; \
+       vpxor                   x3 ## 1, x0 ## 1, x0 ## 1; \
+       vpxor                   x3 ## 1, x2 ## 1, x2 ## 1; \
+       vpxor                   x4 ## 1, x2 ## 1, x2 ## 1; \
+       get_key(i, 0, RK0); \
+               vpslld $7,              x3 ## 2, x4 ## 2;          \
+               vpsrld $(32 - 7),       x3 ## 2, x3 ## 2;          \
+               vpor                    x4 ## 2, x3 ## 2, x3 ## 2; \
+               vpslld $7,              x1 ## 2, x4 ## 2;          \
+               vpxor                   x1 ## 2, x0 ## 2, x0 ## 2; \
+               vpxor                   x3 ## 2, x0 ## 2, x0 ## 2; \
+               vpxor                   x3 ## 2, x2 ## 2, x2 ## 2; \
+               vpxor                   x4 ## 2, x2 ## 2, x2 ## 2; \
+               get_key(i, 2, RK2); \
+       vpxor                   RK1, x1 ## 1, x1 ## 1;     \
+       vpxor                   RK3, x3 ## 1, x3 ## 1;     \
+       vpslld $5,              x0 ## 1, x4 ## 1;          \
+       vpsrld $(32 - 5),       x0 ## 1, x0 ## 1;          \
+       vpor                    x4 ## 1, x0 ## 1, x0 ## 1; \
+       vpslld $22,             x2 ## 1, x4 ## 1;          \
+       vpsrld $(32 - 22),      x2 ## 1, x2 ## 1;          \
+       vpor                    x4 ## 1, x2 ## 1, x2 ## 1; \
+       vpxor                   RK0, x0 ## 1, x0 ## 1;     \
+       vpxor                   RK2, x2 ## 1, x2 ## 1;     \
+               vpxor                   RK1, x1 ## 2, x1 ## 2;     \
+               vpxor                   RK3, x3 ## 2, x3 ## 2;     \
+               vpslld $5,              x0 ## 2, x4 ## 2;          \
+               vpsrld $(32 - 5),       x0 ## 2, x0 ## 2;          \
+               vpor                    x4 ## 2, x0 ## 2, x0 ## 2; \
+               vpslld $22,             x2 ## 2, x4 ## 2;          \
+               vpsrld $(32 - 22),      x2 ## 2, x2 ## 2;          \
+               vpor                    x4 ## 2, x2 ## 2, x2 ## 2; \
+               vpxor                   RK0, x0 ## 2, x0 ## 2;     \
+               vpxor                   RK2, x2 ## 2, x2 ## 2;
+
+#define KL2(x0, x1, x2, x3, x4, i) \
+       vpxor                   RK0, x0 ## 1, x0 ## 1;     \
+       vpxor                   RK2, x2 ## 1, x2 ## 1;     \
+       vpsrld $5,              x0 ## 1, x4 ## 1;          \
+       vpslld $(32 - 5),       x0 ## 1, x0 ## 1;          \
+       vpor                    x4 ## 1, x0 ## 1, x0 ## 1; \
+       vpxor                   RK3, x3 ## 1, x3 ## 1;     \
+       vpxor                   RK1, x1 ## 1, x1 ## 1;     \
+       vpsrld $22,             x2 ## 1, x4 ## 1;          \
+       vpslld $(32 - 22),      x2 ## 1, x2 ## 1;          \
+       vpor                    x4 ## 1, x2 ## 1, x2 ## 1; \
+       vpxor                   x3 ## 1, x2 ## 1, x2 ## 1; \
+               vpxor                   RK0, x0 ## 2, x0 ## 2;     \
+               vpxor                   RK2, x2 ## 2, x2 ## 2;     \
+               vpsrld $5,              x0 ## 2, x4 ## 2;          \
+               vpslld $(32 - 5),       x0 ## 2, x0 ## 2;          \
+               vpor                    x4 ## 2, x0 ## 2, x0 ## 2; \
+               vpxor                   RK3, x3 ## 2, x3 ## 2;     \
+               vpxor                   RK1, x1 ## 2, x1 ## 2;     \
+               vpsrld $22,             x2 ## 2, x4 ## 2;          \
+               vpslld $(32 - 22),      x2 ## 2, x2 ## 2;          \
+               vpor                    x4 ## 2, x2 ## 2, x2 ## 2; \
+               vpxor                   x3 ## 2, x2 ## 2, x2 ## 2; \
+       vpxor                   x3 ## 1, x0 ## 1, x0 ## 1; \
+       vpslld $7,              x1 ## 1, x4 ## 1;          \
+       vpxor                   x1 ## 1, x0 ## 1, x0 ## 1; \
+       vpxor                   x4 ## 1, x2 ## 1, x2 ## 1; \
+       vpsrld $1,              x1 ## 1, x4 ## 1;          \
+       vpslld $(32 - 1),       x1 ## 1, x1 ## 1;          \
+       vpor                    x4 ## 1, x1 ## 1, x1 ## 1; \
+               vpxor                   x3 ## 2, x0 ## 2, x0 ## 2; \
+               vpslld $7,              x1 ## 2, x4 ## 2;          \
+               vpxor                   x1 ## 2, x0 ## 2, x0 ## 2; \
+               vpxor                   x4 ## 2, x2 ## 2, x2 ## 2; \
+               vpsrld $1,              x1 ## 2, x4 ## 2;          \
+               vpslld $(32 - 1),       x1 ## 2, x1 ## 2;          \
+               vpor                    x4 ## 2, x1 ## 2, x1 ## 2; \
+       vpsrld $7,              x3 ## 1, x4 ## 1;          \
+       vpslld $(32 - 7),       x3 ## 1, x3 ## 1;          \
+       vpor                    x4 ## 1, x3 ## 1, x3 ## 1; \
+       vpxor                   x0 ## 1, x1 ## 1, x1 ## 1; \
+       vpslld $3,              x0 ## 1, x4 ## 1;          \
+       vpxor                   x4 ## 1, x3 ## 1, x3 ## 1; \
+               vpsrld $7,              x3 ## 2, x4 ## 2;          \
+               vpslld $(32 - 7),       x3 ## 2, x3 ## 2;          \
+               vpor                    x4 ## 2, x3 ## 2, x3 ## 2; \
+               vpxor                   x0 ## 2, x1 ## 2, x1 ## 2; \
+               vpslld $3,              x0 ## 2, x4 ## 2;          \
+               vpxor                   x4 ## 2, x3 ## 2, x3 ## 2; \
+       vpsrld $13,             x0 ## 1, x4 ## 1;          \
+       vpslld $(32 - 13),      x0 ## 1, x0 ## 1;          \
+       vpor                    x4 ## 1, x0 ## 1, x0 ## 1; \
+       vpxor                   x2 ## 1, x1 ## 1, x1 ## 1; \
+       vpxor                   x2 ## 1, x3 ## 1, x3 ## 1; \
+       vpsrld $3,              x2 ## 1, x4 ## 1;          \
+       vpslld $(32 - 3),       x2 ## 1, x2 ## 1;          \
+       vpor                    x4 ## 1, x2 ## 1, x2 ## 1; \
+               vpsrld $13,             x0 ## 2, x4 ## 2;          \
+               vpslld $(32 - 13),      x0 ## 2, x0 ## 2;          \
+               vpor                    x4 ## 2, x0 ## 2, x0 ## 2; \
+               vpxor                   x2 ## 2, x1 ## 2, x1 ## 2; \
+               vpxor                   x2 ## 2, x3 ## 2, x3 ## 2; \
+               vpsrld $3,              x2 ## 2, x4 ## 2;          \
+               vpslld $(32 - 3),       x2 ## 2, x2 ## 2;          \
+               vpor                    x4 ## 2, x2 ## 2, x2 ## 2;
+
+#define S(SBOX, x0, x1, x2, x3, x4) \
+       SBOX ## _1(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       SBOX ## _2(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       SBOX ## _1(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+       SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2);
+
+#define SP(SBOX, x0, x1, x2, x3, x4, i) \
+       get_key(i, 0, RK0); \
+       SBOX ## _1(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       get_key(i, 2, RK2); \
+       SBOX ## _2(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       get_key(i, 3, RK3); \
+       SBOX ## _1(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+       get_key(i, 1, RK1); \
+       SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+
+#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       vpunpckldq              x1, x0, t0; \
+       vpunpckhdq              x1, x0, t2; \
+       vpunpckldq              x3, x2, t1; \
+       vpunpckhdq              x3, x2, x3; \
+       \
+       vpunpcklqdq             t1, t0, x0; \
+       vpunpckhqdq             t1, t0, x1; \
+       vpunpcklqdq             x3, t2, x2; \
+       vpunpckhqdq             x3, t2, x3;
+
+#define read_blocks(x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+#define write_blocks(x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+.align 8
+__serpent_enc_blk16:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2: plaintext
+        * output:
+        *      RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2: ciphertext
+        */
+
+       vpcmpeqd RNOT, RNOT, RNOT;
+
+       read_blocks(RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+       read_blocks(RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+                                                K2(RA, RB, RC, RD, RE, 0);
+       S(S0, RA, RB, RC, RD, RE);              LK2(RC, RB, RD, RA, RE, 1);
+       S(S1, RC, RB, RD, RA, RE);              LK2(RE, RD, RA, RC, RB, 2);
+       S(S2, RE, RD, RA, RC, RB);              LK2(RB, RD, RE, RC, RA, 3);
+       S(S3, RB, RD, RE, RC, RA);              LK2(RC, RA, RD, RB, RE, 4);
+       S(S4, RC, RA, RD, RB, RE);              LK2(RA, RD, RB, RE, RC, 5);
+       S(S5, RA, RD, RB, RE, RC);              LK2(RC, RA, RD, RE, RB, 6);
+       S(S6, RC, RA, RD, RE, RB);              LK2(RD, RB, RA, RE, RC, 7);
+       S(S7, RD, RB, RA, RE, RC);              LK2(RC, RA, RE, RD, RB, 8);
+       S(S0, RC, RA, RE, RD, RB);              LK2(RE, RA, RD, RC, RB, 9);
+       S(S1, RE, RA, RD, RC, RB);              LK2(RB, RD, RC, RE, RA, 10);
+       S(S2, RB, RD, RC, RE, RA);              LK2(RA, RD, RB, RE, RC, 11);
+       S(S3, RA, RD, RB, RE, RC);              LK2(RE, RC, RD, RA, RB, 12);
+       S(S4, RE, RC, RD, RA, RB);              LK2(RC, RD, RA, RB, RE, 13);
+       S(S5, RC, RD, RA, RB, RE);              LK2(RE, RC, RD, RB, RA, 14);
+       S(S6, RE, RC, RD, RB, RA);              LK2(RD, RA, RC, RB, RE, 15);
+       S(S7, RD, RA, RC, RB, RE);              LK2(RE, RC, RB, RD, RA, 16);
+       S(S0, RE, RC, RB, RD, RA);              LK2(RB, RC, RD, RE, RA, 17);
+       S(S1, RB, RC, RD, RE, RA);              LK2(RA, RD, RE, RB, RC, 18);
+       S(S2, RA, RD, RE, RB, RC);              LK2(RC, RD, RA, RB, RE, 19);
+       S(S3, RC, RD, RA, RB, RE);              LK2(RB, RE, RD, RC, RA, 20);
+       S(S4, RB, RE, RD, RC, RA);              LK2(RE, RD, RC, RA, RB, 21);
+       S(S5, RE, RD, RC, RA, RB);              LK2(RB, RE, RD, RA, RC, 22);
+       S(S6, RB, RE, RD, RA, RC);              LK2(RD, RC, RE, RA, RB, 23);
+       S(S7, RD, RC, RE, RA, RB);              LK2(RB, RE, RA, RD, RC, 24);
+       S(S0, RB, RE, RA, RD, RC);              LK2(RA, RE, RD, RB, RC, 25);
+       S(S1, RA, RE, RD, RB, RC);              LK2(RC, RD, RB, RA, RE, 26);
+       S(S2, RC, RD, RB, RA, RE);              LK2(RE, RD, RC, RA, RB, 27);
+       S(S3, RE, RD, RC, RA, RB);              LK2(RA, RB, RD, RE, RC, 28);
+       S(S4, RA, RB, RD, RE, RC);              LK2(RB, RD, RE, RC, RA, 29);
+       S(S5, RB, RD, RE, RC, RA);              LK2(RA, RB, RD, RC, RE, 30);
+       S(S6, RA, RB, RD, RC, RE);              LK2(RD, RE, RB, RC, RA, 31);
+       S(S7, RD, RE, RB, RC, RA);               K2(RA, RB, RC, RD, RE, 32);
+
+       write_blocks(RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+       write_blocks(RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+       ret;
+ENDPROC(__serpent_enc_blk16)
+
+.align 8
+__serpent_dec_blk16:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2: ciphertext
+        * output:
+        *      RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2: plaintext
+        */
+
+       vpcmpeqd RNOT, RNOT, RNOT;
+
+       read_blocks(RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+       read_blocks(RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+                                                K2(RA, RB, RC, RD, RE, 32);
+       SP(SI7, RA, RB, RC, RD, RE, 31);        KL2(RB, RD, RA, RE, RC, 31);
+       SP(SI6, RB, RD, RA, RE, RC, 30);        KL2(RA, RC, RE, RB, RD, 30);
+       SP(SI5, RA, RC, RE, RB, RD, 29);        KL2(RC, RD, RA, RE, RB, 29);
+       SP(SI4, RC, RD, RA, RE, RB, 28);        KL2(RC, RA, RB, RE, RD, 28);
+       SP(SI3, RC, RA, RB, RE, RD, 27);        KL2(RB, RC, RD, RE, RA, 27);
+       SP(SI2, RB, RC, RD, RE, RA, 26);        KL2(RC, RA, RE, RD, RB, 26);
+       SP(SI1, RC, RA, RE, RD, RB, 25);        KL2(RB, RA, RE, RD, RC, 25);
+       SP(SI0, RB, RA, RE, RD, RC, 24);        KL2(RE, RC, RA, RB, RD, 24);
+       SP(SI7, RE, RC, RA, RB, RD, 23);        KL2(RC, RB, RE, RD, RA, 23);
+       SP(SI6, RC, RB, RE, RD, RA, 22);        KL2(RE, RA, RD, RC, RB, 22);
+       SP(SI5, RE, RA, RD, RC, RB, 21);        KL2(RA, RB, RE, RD, RC, 21);
+       SP(SI4, RA, RB, RE, RD, RC, 20);        KL2(RA, RE, RC, RD, RB, 20);
+       SP(SI3, RA, RE, RC, RD, RB, 19);        KL2(RC, RA, RB, RD, RE, 19);
+       SP(SI2, RC, RA, RB, RD, RE, 18);        KL2(RA, RE, RD, RB, RC, 18);
+       SP(SI1, RA, RE, RD, RB, RC, 17);        KL2(RC, RE, RD, RB, RA, 17);
+       SP(SI0, RC, RE, RD, RB, RA, 16);        KL2(RD, RA, RE, RC, RB, 16);
+       SP(SI7, RD, RA, RE, RC, RB, 15);        KL2(RA, RC, RD, RB, RE, 15);
+       SP(SI6, RA, RC, RD, RB, RE, 14);        KL2(RD, RE, RB, RA, RC, 14);
+       SP(SI5, RD, RE, RB, RA, RC, 13);        KL2(RE, RC, RD, RB, RA, 13);
+       SP(SI4, RE, RC, RD, RB, RA, 12);        KL2(RE, RD, RA, RB, RC, 12);
+       SP(SI3, RE, RD, RA, RB, RC, 11);        KL2(RA, RE, RC, RB, RD, 11);
+       SP(SI2, RA, RE, RC, RB, RD, 10);        KL2(RE, RD, RB, RC, RA, 10);
+       SP(SI1, RE, RD, RB, RC, RA, 9);         KL2(RA, RD, RB, RC, RE, 9);
+       SP(SI0, RA, RD, RB, RC, RE, 8);         KL2(RB, RE, RD, RA, RC, 8);
+       SP(SI7, RB, RE, RD, RA, RC, 7);         KL2(RE, RA, RB, RC, RD, 7);
+       SP(SI6, RE, RA, RB, RC, RD, 6);         KL2(RB, RD, RC, RE, RA, 6);
+       SP(SI5, RB, RD, RC, RE, RA, 5);         KL2(RD, RA, RB, RC, RE, 5);
+       SP(SI4, RD, RA, RB, RC, RE, 4);         KL2(RD, RB, RE, RC, RA, 4);
+       SP(SI3, RD, RB, RE, RC, RA, 3);         KL2(RE, RD, RA, RC, RB, 3);
+       SP(SI2, RE, RD, RA, RC, RB, 2);         KL2(RD, RB, RC, RA, RE, 2);
+       SP(SI1, RD, RB, RC, RA, RE, 1);         KL2(RE, RB, RC, RA, RD, 1);
+       S(SI0, RE, RB, RC, RA, RD);              K2(RC, RD, RB, RE, RA, 0);
+
+       write_blocks(RC1, RD1, RB1, RE1, RK0, RK1, RK2);
+       write_blocks(RC2, RD2, RB2, RE2, RK0, RK1, RK2);
+
+       ret;
+ENDPROC(__serpent_dec_blk16)
+
+ENTRY(serpent_ecb_enc_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       vzeroupper;
+
+       load_16way(%rdx, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       call __serpent_enc_blk16;
+
+       store_16way(%rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(serpent_ecb_enc_16way)
+
+ENTRY(serpent_ecb_dec_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       vzeroupper;
+
+       load_16way(%rdx, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       call __serpent_dec_blk16;
+
+       store_16way(%rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(serpent_ecb_dec_16way)
+
+ENTRY(serpent_cbc_dec_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       vzeroupper;
+
+       load_16way(%rdx, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       call __serpent_dec_blk16;
+
+       store_cbc_16way(%rdx, %rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2,
+                       RK0);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(serpent_cbc_dec_16way)
+
+ENTRY(serpent_ctr_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (16 blocks)
+        *      %rdx: src (16 blocks)
+        *      %rcx: iv (little endian, 128bit)
+        */
+
+       vzeroupper;
+
+       load_ctr_16way(%rcx, .Lbswap128_mask, RA1, RB1, RC1, RD1, RA2, RB2, RC2,
+                      RD2, RK0, RK0x, RK1, RK1x, RK2, RK2x, RK3, RK3x, RNOT,
+                      tp);
+
+       call __serpent_enc_blk16;
+
+       store_ctr_16way(%rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(serpent_ctr_16way)
+
+ENTRY(serpent_xts_enc_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (16 blocks)
+        *      %rdx: src (16 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       vzeroupper;
+
+       load_xts_16way(%rcx, %rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2,
+                      RD2, RK0, RK0x, RK1, RK1x, RK2, RK2x, RK3, RK3x, RNOT,
+                      .Lxts_gf128mul_and_shl1_mask_0,
+                      .Lxts_gf128mul_and_shl1_mask_1);
+
+       call __serpent_enc_blk16;
+
+       store_xts_16way(%rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2, RD2);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(serpent_xts_enc_16way)
+
+ENTRY(serpent_xts_dec_16way)
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst (16 blocks)
+        *      %rdx: src (16 blocks)
+        *      %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
+        */
+
+       vzeroupper;
+
+       load_xts_16way(%rcx, %rdx, %rsi, RA1, RB1, RC1, RD1, RA2, RB2, RC2,
+                      RD2, RK0, RK0x, RK1, RK1x, RK2, RK2x, RK3, RK3x, RNOT,
+                      .Lxts_gf128mul_and_shl1_mask_0,
+                      .Lxts_gf128mul_and_shl1_mask_1);
+
+       call __serpent_dec_blk16;
+
+       store_xts_16way(%rsi, RC1, RD1, RB1, RE1, RC2, RD2, RB2, RE2);
+
+       vzeroupper;
+
+       ret;
+ENDPROC(serpent_xts_dec_16way)
diff --git a/arch/x86/crypto/serpent_avx2_glue.c b/arch/x86/crypto/serpent_avx2_glue.c
new file mode 100644 (file)
index 0000000..23aabc6
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ * Glue Code for x86_64/AVX2 assembler optimized version of Serpent
+ *
+ * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+#include <crypto/serpent.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/crypto/serpent-avx.h>
+#include <asm/crypto/ablk_helper.h>
+#include <asm/crypto/glue_helper.h>
+
+#define SERPENT_AVX2_PARALLEL_BLOCKS 16
+
+/* 16-way AVX2 parallel cipher functions */
+asmlinkage void serpent_ecb_enc_16way(struct serpent_ctx *ctx, u8 *dst,
+                                     const u8 *src);
+asmlinkage void serpent_ecb_dec_16way(struct serpent_ctx *ctx, u8 *dst,
+                                     const u8 *src);
+asmlinkage void serpent_cbc_dec_16way(void *ctx, u128 *dst, const u128 *src);
+
+asmlinkage void serpent_ctr_16way(void *ctx, u128 *dst, const u128 *src,
+                                 le128 *iv);
+asmlinkage void serpent_xts_enc_16way(struct serpent_ctx *ctx, u8 *dst,
+                                     const u8 *src, le128 *iv);
+asmlinkage void serpent_xts_dec_16way(struct serpent_ctx *ctx, u8 *dst,
+                                     const u8 *src, le128 *iv);
+
+static const struct common_glue_ctx serpent_enc = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = 8,
+
+       .funcs = { {
+               .num_blocks = 16,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_enc_16way) }
+       }, {
+               .num_blocks = 8,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_enc_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) }
+       } }
+};
+
+static const struct common_glue_ctx serpent_ctr = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = 8,
+
+       .funcs = { {
+               .num_blocks = 16,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_ctr_16way) }
+       },  {
+               .num_blocks = 8,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_ctr_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(__serpent_crypt_ctr) }
+       } }
+};
+
+static const struct common_glue_ctx serpent_enc_xts = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = 8,
+
+       .funcs = { {
+               .num_blocks = 16,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc_16way) }
+       }, {
+               .num_blocks = 8,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc) }
+       } }
+};
+
+static const struct common_glue_ctx serpent_dec = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = 8,
+
+       .funcs = { {
+               .num_blocks = 16,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_dec_16way) }
+       }, {
+               .num_blocks = 8,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_ecb_dec_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) }
+       } }
+};
+
+static const struct common_glue_ctx serpent_dec_cbc = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = 8,
+
+       .funcs = { {
+               .num_blocks = 16,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_cbc_dec_16way) }
+       }, {
+               .num_blocks = 8,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_cbc_dec_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) }
+       } }
+};
+
+static const struct common_glue_ctx serpent_dec_xts = {
+       .num_funcs = 3,
+       .fpu_blocks_limit = 8,
+
+       .funcs = { {
+               .num_blocks = 16,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec_16way) }
+       }, {
+               .num_blocks = 8,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec) }
+       } }
+};
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ecb_crypt_128bit(&serpent_enc, desc, dst, src, nbytes);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ecb_crypt_128bit(&serpent_dec, desc, dst, src, nbytes);
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt), desc,
+                                      dst, src, nbytes);
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_cbc_decrypt_128bit(&serpent_dec_cbc, desc, dst, src,
+                                      nbytes);
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ctr_crypt_128bit(&serpent_ctr, desc, dst, src, nbytes);
+}
+
+static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+       /* since reusing AVX functions, starts using FPU at 8 parallel blocks */
+       return glue_fpu_begin(SERPENT_BLOCK_SIZE, 8, NULL, fpu_enabled, nbytes);
+}
+
+static inline void serpent_fpu_end(bool fpu_enabled)
+{
+       glue_fpu_end(fpu_enabled);
+}
+
+struct crypt_priv {
+       struct serpent_ctx *ctx;
+       bool fpu_enabled;
+};
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes >= SERPENT_AVX2_PARALLEL_BLOCKS * bsize) {
+               serpent_ecb_enc_16way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
+               nbytes -= bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
+       }
+
+       while (nbytes >= SERPENT_PARALLEL_BLOCKS * bsize) {
+               serpent_ecb_enc_8way_avx(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * SERPENT_PARALLEL_BLOCKS;
+               nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               __serpent_encrypt(ctx->ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes >= SERPENT_AVX2_PARALLEL_BLOCKS * bsize) {
+               serpent_ecb_dec_16way(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
+               nbytes -= bsize * SERPENT_AVX2_PARALLEL_BLOCKS;
+       }
+
+       while (nbytes >= SERPENT_PARALLEL_BLOCKS * bsize) {
+               serpent_ecb_dec_8way_avx(ctx->ctx, srcdst, srcdst);
+               srcdst += bsize * SERPENT_PARALLEL_BLOCKS;
+               nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               __serpent_decrypt(ctx->ctx, srcdst, srcdst);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[SERPENT_AVX2_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->serpent_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[SERPENT_AVX2_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->serpent_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+
+       return glue_xts_crypt_128bit(&serpent_enc_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(__serpent_encrypt),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+
+       return glue_xts_crypt_128bit(&serpent_dec_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(__serpent_encrypt),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
+}
+
+static struct crypto_alg srp_algs[10] = { {
+       .cra_name               = "__ecb-serpent-avx2",
+       .cra_driver_name        = "__driver-ecb-serpent-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[0].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__cbc-serpent-avx2",
+       .cra_driver_name        = "__driver-cbc-serpent-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[1].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__ctr-serpent-avx2",
+       .cra_driver_name        = "__driver-ctr-serpent-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[2].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "__lrw-serpent-avx2",
+       .cra_driver_name        = "__driver-lrw-serpent-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[3].cra_list),
+       .cra_exit               = lrw_serpent_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = lrw_serpent_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__xts-serpent-avx2",
+       .cra_driver_name        = "__driver-xts-serpent-avx2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_xts_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[4].cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE * 2,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = xts_serpent_setkey,
+                       .encrypt        = xts_encrypt,
+                       .decrypt        = xts_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ecb(serpent)",
+       .cra_driver_name        = "ecb-serpent-avx2",
+       .cra_priority           = 600,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[5].cra_list),
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(serpent)",
+       .cra_driver_name        = "cbc-serpent-avx2",
+       .cra_priority           = 600,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[6].cra_list),
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = __ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ctr(serpent)",
+       .cra_driver_name        = "ctr-serpent-avx2",
+       .cra_priority           = 600,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[7].cra_list),
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_encrypt,
+                       .geniv          = "chainiv",
+               },
+       },
+}, {
+       .cra_name               = "lrw(serpent)",
+       .cra_driver_name        = "lrw-serpent-avx2",
+       .cra_priority           = 600,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[8].cra_list),
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "xts(serpent)",
+       .cra_driver_name        = "xts-serpent-avx2",
+       .cra_priority           = 600,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(srp_algs[9].cra_list),
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE * 2,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+} };
+
+static int __init init(void)
+{
+       u64 xcr0;
+
+       if (!cpu_has_avx2 || !cpu_has_osxsave) {
+               pr_info("AVX2 instructions are not detected.\n");
+               return -ENODEV;
+       }
+
+       xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+       if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+               pr_info("AVX detected but unusable.\n");
+               return -ENODEV;
+       }
+
+       return crypto_register_algs(srp_algs, ARRAY_SIZE(srp_algs));
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_algs(srp_algs, ARRAY_SIZE(srp_algs));
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Serpent Cipher Algorithm, AVX2 optimized");
+MODULE_ALIAS("serpent");
+MODULE_ALIAS("serpent-asm");
index 52abaaf..9ae83cf 100644 (file)
@@ -4,8 +4,7 @@
  * Copyright (C) 2012 Johannes Goetzfried
  *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
  *
- * Glue code based on serpent_sse2_glue.c by:
- *  Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright © 2011-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <asm/crypto/ablk_helper.h>
 #include <asm/crypto/glue_helper.h>
 
-static void serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+/* 8-way parallel cipher functions */
+asmlinkage void serpent_ecb_enc_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+                                        const u8 *src);
+EXPORT_SYMBOL_GPL(serpent_ecb_enc_8way_avx);
+
+asmlinkage void serpent_ecb_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+                                        const u8 *src);
+EXPORT_SYMBOL_GPL(serpent_ecb_dec_8way_avx);
+
+asmlinkage void serpent_cbc_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+                                        const u8 *src);
+EXPORT_SYMBOL_GPL(serpent_cbc_dec_8way_avx);
+
+asmlinkage void serpent_ctr_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+                                    const u8 *src, le128 *iv);
+EXPORT_SYMBOL_GPL(serpent_ctr_8way_avx);
+
+asmlinkage void serpent_xts_enc_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+                                        const u8 *src, le128 *iv);
+EXPORT_SYMBOL_GPL(serpent_xts_enc_8way_avx);
+
+asmlinkage void serpent_xts_dec_8way_avx(struct serpent_ctx *ctx, u8 *dst,
+                                        const u8 *src, le128 *iv);
+EXPORT_SYMBOL_GPL(serpent_xts_dec_8way_avx);
+
+void __serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
 {
        be128 ctrblk;
 
@@ -52,6 +76,22 @@ static void serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv)
        __serpent_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk);
        u128_xor(dst, src, (u128 *)&ctrblk);
 }
+EXPORT_SYMBOL_GPL(__serpent_crypt_ctr);
+
+void serpent_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv,
+                                 GLUE_FUNC_CAST(__serpent_encrypt));
+}
+EXPORT_SYMBOL_GPL(serpent_xts_enc);
+
+void serpent_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+{
+       glue_xts_crypt_128bit_one(ctx, dst, src, iv,
+                                 GLUE_FUNC_CAST(__serpent_decrypt));
+}
+EXPORT_SYMBOL_GPL(serpent_xts_dec);
+
 
 static const struct common_glue_ctx serpent_enc = {
        .num_funcs = 2,
@@ -75,7 +115,20 @@ static const struct common_glue_ctx serpent_ctr = {
                .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_ctr_8way_avx) }
        }, {
                .num_blocks = 1,
-               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr) }
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(__serpent_crypt_ctr) }
+       } }
+};
+
+static const struct common_glue_ctx serpent_enc_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = SERPENT_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_enc) }
        } }
 };
 
@@ -105,6 +158,19 @@ static const struct common_glue_ctx serpent_dec_cbc = {
        } }
 };
 
+static const struct common_glue_ctx serpent_dec_xts = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = SERPENT_PARALLEL_BLOCKS,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec_8way_avx) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .xts = GLUE_XTS_FUNC_CAST(serpent_xts_dec) }
+       } }
+};
+
 static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
@@ -187,13 +253,8 @@ static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
                __serpent_decrypt(ctx->ctx, srcdst, srcdst);
 }
 
-struct serpent_lrw_ctx {
-       struct lrw_table_ctx lrw_table;
-       struct serpent_ctx serpent_ctx;
-};
-
-static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
-                             unsigned int keylen)
+int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+                      unsigned int keylen)
 {
        struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
        int err;
@@ -206,6 +267,7 @@ static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
        return lrw_init_table(&ctx->lrw_table, key + keylen -
                                                SERPENT_BLOCK_SIZE);
 }
+EXPORT_SYMBOL_GPL(lrw_serpent_setkey);
 
 static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
@@ -259,20 +321,16 @@ static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
        return ret;
 }
 
-static void lrw_exit_tfm(struct crypto_tfm *tfm)
+void lrw_serpent_exit_tfm(struct crypto_tfm *tfm)
 {
        struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
 
        lrw_free_table(&ctx->lrw_table);
 }
+EXPORT_SYMBOL_GPL(lrw_serpent_exit_tfm);
 
-struct serpent_xts_ctx {
-       struct serpent_ctx tweak_ctx;
-       struct serpent_ctx crypt_ctx;
-};
-
-static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
-                             unsigned int keylen)
+int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+                      unsigned int keylen)
 {
        struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
        u32 *flags = &tfm->crt_flags;
@@ -294,59 +352,26 @@ static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
        /* second half of xts-key is for tweak */
        return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
 }
+EXPORT_SYMBOL_GPL(xts_serpent_setkey);
 
 static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
        struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-       be128 buf[SERPENT_PARALLEL_BLOCKS];
-       struct crypt_priv crypt_ctx = {
-               .ctx = &ctx->crypt_ctx,
-               .fpu_enabled = false,
-       };
-       struct xts_crypt_req req = {
-               .tbuf = buf,
-               .tbuflen = sizeof(buf),
-
-               .tweak_ctx = &ctx->tweak_ctx,
-               .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
-               .crypt_ctx = &crypt_ctx,
-               .crypt_fn = encrypt_callback,
-       };
-       int ret;
-
-       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-       ret = xts_crypt(desc, dst, src, nbytes, &req);
-       serpent_fpu_end(crypt_ctx.fpu_enabled);
 
-       return ret;
+       return glue_xts_crypt_128bit(&serpent_enc_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(__serpent_encrypt),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
 }
 
 static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                       struct scatterlist *src, unsigned int nbytes)
 {
        struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-       be128 buf[SERPENT_PARALLEL_BLOCKS];
-       struct crypt_priv crypt_ctx = {
-               .ctx = &ctx->crypt_ctx,
-               .fpu_enabled = false,
-       };
-       struct xts_crypt_req req = {
-               .tbuf = buf,
-               .tbuflen = sizeof(buf),
-
-               .tweak_ctx = &ctx->tweak_ctx,
-               .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
-               .crypt_ctx = &crypt_ctx,
-               .crypt_fn = decrypt_callback,
-       };
-       int ret;
 
-       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-       ret = xts_crypt(desc, dst, src, nbytes, &req);
-       serpent_fpu_end(crypt_ctx.fpu_enabled);
-
-       return ret;
+       return glue_xts_crypt_128bit(&serpent_dec_xts, desc, dst, src, nbytes,
+                                    XTS_TWEAK_CAST(__serpent_encrypt),
+                                    &ctx->tweak_ctx, &ctx->crypt_ctx);
 }
 
 static struct crypto_alg serpent_algs[10] = { {
@@ -417,7 +442,7 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_exit               = lrw_exit_tfm,
+       .cra_exit               = lrw_serpent_exit_tfm,
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE +
diff --git a/arch/x86/crypto/sha256-avx-asm.S b/arch/x86/crypto/sha256-avx-asm.S
new file mode 100644 (file)
index 0000000..56610c4
--- /dev/null
@@ -0,0 +1,496 @@
+########################################################################
+# Implement fast SHA-256 with AVX1 instructions. (x86_64)
+#
+# Copyright (C) 2013 Intel Corporation.
+#
+# Authors:
+#     James Guilford <james.guilford@intel.com>
+#     Kirk Yap <kirk.s.yap@intel.com>
+#     Tim Chen <tim.c.chen@linux.intel.com>
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+#     Redistribution and use in source and binary forms, with or
+#     without modification, are permitted provided that the following
+#     conditions are met:
+#
+#      - Redistributions of source code must retain the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer.
+#
+#      - Redistributions in binary form must reproduce the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer in the documentation and/or other materials
+#        provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+########################################################################
+#
+# This code is described in an Intel White-Paper:
+# "Fast SHA-256 Implementations on Intel Architecture Processors"
+#
+# To find it, surf to http://www.intel.com/p/en_US/embedded
+# and search for that title.
+#
+########################################################################
+# This code schedules 1 block at a time, with 4 lanes per block
+########################################################################
+
+#ifdef CONFIG_AS_AVX
+#include <linux/linkage.h>
+
+## assume buffers not aligned
+#define    VMOVDQ vmovdqu
+
+################################ Define Macros
+
+# addm [mem], reg
+# Add reg to mem using reg-mem add and store
+.macro addm p1 p2
+       add     \p1, \p2
+       mov     \p2, \p1
+.endm
+
+
+.macro MY_ROR p1 p2
+       shld    $(32-(\p1)), \p2, \p2
+.endm
+
+################################
+
+# COPY_XMM_AND_BSWAP xmm, [mem], byte_flip_mask
+# Load xmm with mem and byte swap each dword
+.macro COPY_XMM_AND_BSWAP p1 p2 p3
+       VMOVDQ \p2, \p1
+       vpshufb \p3, \p1, \p1
+.endm
+
+################################
+
+X0 = %xmm4
+X1 = %xmm5
+X2 = %xmm6
+X3 = %xmm7
+
+XTMP0 = %xmm0
+XTMP1 = %xmm1
+XTMP2 = %xmm2
+XTMP3 = %xmm3
+XTMP4 = %xmm8
+XFER = %xmm9
+XTMP5 = %xmm11
+
+SHUF_00BA = %xmm10      # shuffle xBxA -> 00BA
+SHUF_DC00 = %xmm12      # shuffle xDxC -> DC00
+BYTE_FLIP_MASK = %xmm13
+
+NUM_BLKS = %rdx   # 3rd arg
+CTX = %rsi        # 2nd arg
+INP = %rdi        # 1st arg
+
+SRND = %rdi       # clobbers INP
+c = %ecx
+d = %r8d
+e = %edx
+TBL = %rbp
+a = %eax
+b = %ebx
+
+f = %r9d
+g = %r10d
+h = %r11d
+
+y0 = %r13d
+y1 = %r14d
+y2 = %r15d
+
+
+_INP_END_SIZE = 8
+_INP_SIZE = 8
+_XFER_SIZE = 8
+_XMM_SAVE_SIZE = 0
+
+_INP_END = 0
+_INP            = _INP_END  + _INP_END_SIZE
+_XFER           = _INP      + _INP_SIZE
+_XMM_SAVE       = _XFER     + _XFER_SIZE
+STACK_SIZE      = _XMM_SAVE + _XMM_SAVE_SIZE
+
+# rotate_Xs
+# Rotate values of symbols X0...X3
+.macro rotate_Xs
+X_ = X0
+X0 = X1
+X1 = X2
+X2 = X3
+X3 = X_
+.endm
+
+# ROTATE_ARGS
+# Rotate values of symbols a...h
+.macro ROTATE_ARGS
+TMP_ = h
+h = g
+g = f
+f = e
+e = d
+d = c
+c = b
+b = a
+a = TMP_
+.endm
+
+.macro FOUR_ROUNDS_AND_SCHED
+       ## compute s0 four at a time and s1 two at a time
+       ## compute W[-16] + W[-7] 4 at a time
+
+       mov     e, y0                   # y0 = e
+       MY_ROR  (25-11), y0             # y0 = e >> (25-11)
+       mov     a, y1                   # y1 = a
+       vpalignr $4, X2, X3, XTMP0      # XTMP0 = W[-7]
+       MY_ROR  (22-13), y1             # y1 = a >> (22-13)
+       xor     e, y0                   # y0 = e ^ (e >> (25-11))
+       mov     f, y2                   # y2 = f
+       MY_ROR  (11-6), y0              # y0 = (e >> (11-6)) ^ (e >> (25-6))
+       xor     a, y1                   # y1 = a ^ (a >> (22-13)
+       xor     g, y2                   # y2 = f^g
+       vpaddd  X0, XTMP0, XTMP0        # XTMP0 = W[-7] + W[-16]
+       xor     e, y0                   # y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+       and     e, y2                   # y2 = (f^g)&e
+       MY_ROR  (13-2), y1              # y1 = (a >> (13-2)) ^ (a >> (22-2))
+       ## compute s0
+       vpalignr $4, X0, X1, XTMP1      # XTMP1 = W[-15]
+       xor     a, y1                   # y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+       MY_ROR  6, y0                   # y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+       xor     g, y2                   # y2 = CH = ((f^g)&e)^g
+       MY_ROR  2, y1                   # y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+       add     y0, y2                  # y2 = S1 + CH
+       add     _XFER(%rsp), y2         # y2 = k + w + S1 + CH
+       mov     a, y0                   # y0 = a
+       add     y2, h                   # h = h + S1 + CH + k + w
+       mov     a, y2                   # y2 = a
+       vpsrld  $7, XTMP1, XTMP2
+       or      c, y0                   # y0 = a|c
+       add     h, d                    # d = d + h + S1 + CH + k + w
+       and     c, y2                   # y2 = a&c
+       vpslld  $(32-7), XTMP1, XTMP3
+       and     b, y0                   # y0 = (a|c)&b
+       add     y1, h                   # h = h + S1 + CH + k + w + S0
+       vpor    XTMP2, XTMP3, XTMP3     # XTMP1 = W[-15] MY_ROR 7
+       or      y2, y0                  # y0 = MAJ = (a|c)&b)|(a&c)
+       add     y0, h                   # h = h + S1 + CH + k + w + S0 + MAJ
+       ROTATE_ARGS
+       mov     e, y0                   # y0 = e
+       mov     a, y1                   # y1 = a
+       MY_ROR  (25-11), y0             # y0 = e >> (25-11)
+       xor     e, y0                   # y0 = e ^ (e >> (25-11))
+       mov     f, y2                   # y2 = f
+       MY_ROR  (22-13), y1             # y1 = a >> (22-13)
+       vpsrld  $18, XTMP1, XTMP2       #
+       xor     a, y1                   # y1 = a ^ (a >> (22-13)
+       MY_ROR  (11-6), y0              # y0 = (e >> (11-6)) ^ (e >> (25-6))
+       xor     g, y2                   # y2 = f^g
+       vpsrld  $3, XTMP1, XTMP4        # XTMP4 = W[-15] >> 3
+       MY_ROR  (13-2), y1              # y1 = (a >> (13-2)) ^ (a >> (22-2))
+       xor     e, y0                   # y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+       and     e, y2                   # y2 = (f^g)&e
+       MY_ROR  6, y0                   # y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+       vpslld  $(32-18), XTMP1, XTMP1
+       xor     a, y1                   # y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+       xor     g, y2                   # y2 = CH = ((f^g)&e)^g
+       vpxor   XTMP1, XTMP3, XTMP3     #
+       add     y0, y2                  # y2 = S1 + CH
+       add     (1*4 + _XFER)(%rsp), y2 # y2 = k + w + S1 + CH
+       MY_ROR  2, y1                   # y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+       vpxor   XTMP2, XTMP3, XTMP3     # XTMP1 = W[-15] MY_ROR 7 ^ W[-15] MY_ROR
+       mov     a, y0                   # y0 = a
+       add     y2, h                   # h = h + S1 + CH + k + w
+       mov     a, y2                   # y2 = a
+       vpxor   XTMP4, XTMP3, XTMP1     # XTMP1 = s0
+       or      c, y0                   # y0 = a|c
+       add     h, d                    # d = d + h + S1 + CH + k + w
+       and     c, y2                   # y2 = a&c
+       ## compute low s1
+       vpshufd $0b11111010, X3, XTMP2  # XTMP2 = W[-2] {BBAA}
+       and     b, y0                   # y0 = (a|c)&b
+       add     y1, h                   # h = h + S1 + CH + k + w + S0
+       vpaddd  XTMP1, XTMP0, XTMP0     # XTMP0 = W[-16] + W[-7] + s0
+       or      y2, y0                  # y0 = MAJ = (a|c)&b)|(a&c)
+       add     y0, h                   # h = h + S1 + CH + k + w + S0 + MAJ
+       ROTATE_ARGS
+       mov     e, y0                   # y0 = e
+       mov     a, y1                   # y1 = a
+       MY_ROR  (25-11), y0             # y0 = e >> (25-11)
+       xor     e, y0                   # y0 = e ^ (e >> (25-11))
+       MY_ROR  (22-13), y1             # y1 = a >> (22-13)
+       mov     f, y2                   # y2 = f
+       xor     a, y1                   # y1 = a ^ (a >> (22-13)
+       MY_ROR  (11-6), y0              # y0 = (e >> (11-6)) ^ (e >> (25-6))
+       vpsrld  $10, XTMP2, XTMP4       # XTMP4 = W[-2] >> 10 {BBAA}
+       xor     g, y2                   # y2 = f^g
+       vpsrlq  $19, XTMP2, XTMP3       # XTMP3 = W[-2] MY_ROR 19 {xBxA}
+       xor     e, y0                   # y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+       and     e, y2                   # y2 = (f^g)&e
+       vpsrlq  $17, XTMP2, XTMP2       # XTMP2 = W[-2] MY_ROR 17 {xBxA}
+       MY_ROR  (13-2), y1              # y1 = (a >> (13-2)) ^ (a >> (22-2))
+       xor     a, y1                   # y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+       xor     g, y2                   # y2 = CH = ((f^g)&e)^g
+       MY_ROR  6, y0                   # y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+       vpxor   XTMP3, XTMP2, XTMP2     #
+       add     y0, y2                  # y2 = S1 + CH
+       MY_ROR  2, y1                   # y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+       add     (2*4 + _XFER)(%rsp), y2 # y2 = k + w + S1 + CH
+       vpxor   XTMP2, XTMP4, XTMP4     # XTMP4 = s1 {xBxA}
+       mov     a, y0                   # y0 = a
+       add     y2, h                   # h = h + S1 + CH + k + w
+       mov     a, y2                   # y2 = a
+       vpshufb SHUF_00BA, XTMP4, XTMP4 # XTMP4 = s1 {00BA}
+       or      c, y0                   # y0 = a|c
+       add     h, d                    # d = d + h + S1 + CH + k + w
+       and     c, y2                   # y2 = a&c
+       vpaddd  XTMP4, XTMP0, XTMP0     # XTMP0 = {..., ..., W[1], W[0]}
+       and     b, y0                   # y0 = (a|c)&b
+       add     y1, h                   # h = h + S1 + CH + k + w + S0
+       ## compute high s1
+       vpshufd $0b01010000, XTMP0, XTMP2 # XTMP2 = W[-2] {DDCC}
+       or      y2, y0                  # y0 = MAJ = (a|c)&b)|(a&c)
+       add     y0, h                   # h = h + S1 + CH + k + w + S0 + MAJ
+       ROTATE_ARGS
+       mov     e, y0                   # y0 = e
+       MY_ROR  (25-11), y0             # y0 = e >> (25-11)
+       mov     a, y1                   # y1 = a
+       MY_ROR  (22-13), y1             # y1 = a >> (22-13)
+       xor     e, y0                   # y0 = e ^ (e >> (25-11))
+       mov     f, y2                   # y2 = f
+       MY_ROR  (11-6), y0              # y0 = (e >> (11-6)) ^ (e >> (25-6))
+       vpsrld  $10, XTMP2, XTMP5       # XTMP5 = W[-2] >> 10 {DDCC}
+       xor     a, y1                   # y1 = a ^ (a >> (22-13)
+       xor     g, y2                   # y2 = f^g
+       vpsrlq  $19, XTMP2, XTMP3       # XTMP3 = W[-2] MY_ROR 19 {xDxC}
+       xor     e, y0                   # y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+       and     e, y2                   # y2 = (f^g)&e
+       MY_ROR  (13-2), y1              # y1 = (a >> (13-2)) ^ (a >> (22-2))
+       vpsrlq  $17, XTMP2, XTMP2       # XTMP2 = W[-2] MY_ROR 17 {xDxC}
+       xor     a, y1                   # y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+       MY_ROR  6, y0                   # y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+       xor     g, y2                   # y2 = CH = ((f^g)&e)^g
+       vpxor   XTMP3, XTMP2, XTMP2
+       MY_ROR  2, y1                   # y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+       add     y0, y2                  # y2 = S1 + CH
+       add     (3*4 + _XFER)(%rsp), y2 # y2 = k + w + S1 + CH
+       vpxor   XTMP2, XTMP5, XTMP5     # XTMP5 = s1 {xDxC}
+       mov     a, y0                   # y0 = a
+       add     y2, h                   # h = h + S1 + CH + k + w
+       mov     a, y2                   # y2 = a
+       vpshufb SHUF_DC00, XTMP5, XTMP5 # XTMP5 = s1 {DC00}
+       or      c, y0                   # y0 = a|c
+       add     h, d                    # d = d + h + S1 + CH + k + w
+       and     c, y2                   # y2 = a&c
+       vpaddd  XTMP0, XTMP5, X0        # X0 = {W[3], W[2], W[1], W[0]}
+       and     b, y0                   # y0 = (a|c)&b
+       add     y1, h                   # h = h + S1 + CH + k + w + S0
+       or      y2, y0                  # y0 = MAJ = (a|c)&b)|(a&c)
+       add     y0, h                   # h = h + S1 + CH + k + w + S0 + MAJ
+       ROTATE_ARGS
+       rotate_Xs
+.endm
+
+## input is [rsp + _XFER + %1 * 4]
+.macro DO_ROUND round
+       mov     e, y0                   # y0 = e
+        MY_ROR  (25-11), y0             # y0 = e >> (25-11)
+        mov     a, y1                   # y1 = a
+        xor     e, y0                   # y0 = e ^ (e >> (25-11))
+        MY_ROR  (22-13), y1             # y1 = a >> (22-13)
+        mov     f, y2                   # y2 = f
+        xor     a, y1                   # y1 = a ^ (a >> (22-13)
+        MY_ROR  (11-6), y0              # y0 = (e >> (11-6)) ^ (e >> (25-6))
+        xor     g, y2                   # y2 = f^g
+        xor     e, y0                   # y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
+        MY_ROR  (13-2), y1              # y1 = (a >> (13-2)) ^ (a >> (22-2))
+        and     e, y2                   # y2 = (f^g)&e
+        xor     a, y1                   # y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
+        MY_ROR  6, y0                   # y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
+        xor     g, y2                   # y2 = CH = ((f^g)&e)^g
+        add     y0, y2                  # y2 = S1 + CH
+        MY_ROR  2, y1                   # y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
+        offset = \round * 4 + _XFER     #
+        add     offset(%rsp), y2       # y2 = k + w + S1 + CH
+        mov     a, y0                  # y0 = a
+        add     y2, h                   # h = h + S1 + CH + k + w
+        mov     a, y2                   # y2 = a
+        or      c, y0                   # y0 = a|c
+        add     h, d                    # d = d + h + S1 + CH + k + w
+        and     c, y2                   # y2 = a&c
+        and     b, y0                   # y0 = (a|c)&b
+        add     y1, h                   # h = h + S1 + CH + k + w + S0
+        or      y2, y0                  # y0 = MAJ = (a|c)&b)|(a&c)
+        add     y0, h                   # h = h + S1 + CH + k + w + S0 + MAJ
+        ROTATE_ARGS
+.endm
+
+########################################################################
+## void sha256_transform_avx(void *input_data, UINT32 digest[8], UINT64 num_blks)
+## arg 1 : pointer to input data
+## arg 2 : pointer to digest
+## arg 3 : Num blocks
+########################################################################
+.text
+ENTRY(sha256_transform_avx)
+.align 32
+       pushq   %rbx
+       pushq   %rbp
+       pushq   %r13
+       pushq   %r14
+       pushq   %r15
+       pushq   %r12
+
+       mov     %rsp, %r12
+       subq    $STACK_SIZE, %rsp       # allocate stack space
+       and     $~15, %rsp              # align stack pointer
+
+       shl     $6, NUM_BLKS            # convert to bytes
+       jz      done_hash
+       add     INP, NUM_BLKS           # pointer to end of data
+       mov     NUM_BLKS, _INP_END(%rsp)
+
+       ## load initial digest
+       mov     4*0(CTX), a
+       mov     4*1(CTX), b
+       mov     4*2(CTX), c
+       mov     4*3(CTX), d
+       mov     4*4(CTX), e
+       mov     4*5(CTX), f
+       mov     4*6(CTX), g
+       mov     4*7(CTX), h
+
+       vmovdqa  PSHUFFLE_BYTE_FLIP_MASK(%rip), BYTE_FLIP_MASK
+       vmovdqa  _SHUF_00BA(%rip), SHUF_00BA
+       vmovdqa  _SHUF_DC00(%rip), SHUF_DC00
+loop0:
+       lea     K256(%rip), TBL
+
+       ## byte swap first 16 dwords
+       COPY_XMM_AND_BSWAP      X0, 0*16(INP), BYTE_FLIP_MASK
+       COPY_XMM_AND_BSWAP      X1, 1*16(INP), BYTE_FLIP_MASK
+       COPY_XMM_AND_BSWAP      X2, 2*16(INP), BYTE_FLIP_MASK
+       COPY_XMM_AND_BSWAP      X3, 3*16(INP), BYTE_FLIP_MASK
+
+       mov     INP, _INP(%rsp)
+
+       ## schedule 48 input dwords, by doing 3 rounds of 16 each
+       mov     $3, SRND
+.align 16
+loop1:
+       vpaddd  (TBL), X0, XFER
+       vmovdqa XFER, _XFER(%rsp)
+       FOUR_ROUNDS_AND_SCHED
+
+       vpaddd  1*16(TBL), X0, XFER
+       vmovdqa XFER, _XFER(%rsp)
+       FOUR_ROUNDS_AND_SCHED
+
+       vpaddd  2*16(TBL), X0, XFER
+       vmovdqa XFER, _XFER(%rsp)
+       FOUR_ROUNDS_AND_SCHED
+
+       vpaddd  3*16(TBL), X0, XFER
+       vmovdqa XFER, _XFER(%rsp)
+       add     $4*16, TBL
+       FOUR_ROUNDS_AND_SCHED
+
+       sub     $1, SRND
+       jne     loop1
+
+       mov     $2, SRND
+loop2:
+       vpaddd  (TBL), X0, XFER
+       vmovdqa XFER, _XFER(%rsp)
+       DO_ROUND        0
+       DO_ROUND        1
+       DO_ROUND        2
+       DO_ROUND        3
+
+       vpaddd  1*16(TBL), X1, XFER
+       vmovdqa XFER, _XFER(%rsp)
+       add     $2*16, TBL
+       DO_ROUND        0
+       DO_ROUND        1
+       DO_ROUND        2
+       DO_ROUND        3
+
+       vmovdqa X2, X0
+       vmovdqa X3, X1
+
+       sub     $1, SRND
+       jne     loop2
+
+       addm    (4*0)(CTX),a
+       addm    (4*1)(CTX),b
+       addm    (4*2)(CTX),c
+       addm    (4*3)(CTX),d
+       addm    (4*4)(CTX),e
+       addm    (4*5)(CTX),f
+       addm    (4*6)(CTX),g
+       addm    (4*7)(CTX),h
+
+       mov     _INP(%rsp), INP
+       add     $64, INP
+       cmp     _INP_END(%rsp), INP
+       jne     loop0
+
+done_hash:
+
+       mov     %r12, %rsp
+
+       popq    %r12
+       popq    %r15
+       popq    %r14
+       popq    %r13
+       popq    %rbp
+       popq    %rbx
+       ret
+ENDPROC(sha256_transform_avx)
+
+.data
+.align 64
+K256:
+       .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+       .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+       .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+       .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+       .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+       .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+       .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+       .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+       .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+       .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+       .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+       .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+       .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+       .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+       .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+       .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+
+PSHUFFLE_BYTE_FLIP_MASK:
+       .octa 0x0c0d0e0f08090a0b0405060700010203
+
+# shuffle xBxA -> 00BA
+_SHUF_00BA:
+       .octa 0xFFFFFFFFFFFFFFFF0b0a090803020100
+
+# shuffle xDxC -> DC00
+_SHUF_DC00:
+       .octa 0x0b0a090803020100FFFFFFFFFFFFFFFF
+#endif
diff --git a/arch/x86/crypto/sha256-avx2-asm.S b/arch/x86/crypto/sha256-avx2-asm.S
new file mode 100644 (file)
index 0000000..9e86944
--- /dev/null
@@ -0,0 +1,772 @@
+########################################################################
+# Implement fast SHA-256 with AVX2 instructions. (x86_64)
+#
+# Copyright (C) 2013 Intel Corporation.
+#
+# Authors:
+#     James Guilford <james.guilford@intel.com>
+#     Kirk Yap <kirk.s.yap@intel.com>
+#     Tim Chen <tim.c.chen@linux.intel.com>
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+#     Redistribution and use in source and binary forms, with or
+#     without modification, are permitted provided that the following
+#     conditions are met:
+#
+#      - Redistributions of source code must retain the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer.
+#
+#      - Redistributions in binary form must reproduce the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer in the documentation and/or other materials
+#        provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+########################################################################
+#
+# This code is described in an Intel White-Paper:
+# "Fast SHA-256 Implementations on Intel Architecture Processors"
+#
+# To find it, surf to http://www.intel.com/p/en_US/embedded
+# and search for that title.
+#
+########################################################################
+# This code schedules 2 blocks at a time, with 4 lanes per block
+########################################################################
+
+#ifdef CONFIG_AS_AVX2
+#include <linux/linkage.h>
+
+## assume buffers not aligned
+#define        VMOVDQ vmovdqu
+
+################################ Define Macros
+
+# addm [mem], reg
+# Add reg to mem using reg-mem add and store
+.macro addm p1 p2
+       add     \p1, \p2
+       mov     \p2, \p1
+.endm
+
+################################
+
+X0 = %ymm4
+X1 = %ymm5
+X2 = %ymm6
+X3 = %ymm7
+
+# XMM versions of above
+XWORD0 = %xmm4
+XWORD1 = %xmm5
+XWORD2 = %xmm6
+XWORD3 = %xmm7
+
+XTMP0 = %ymm0
+XTMP1 = %ymm1
+XTMP2 = %ymm2
+XTMP3 = %ymm3
+XTMP4 = %ymm8
+XFER  = %ymm9
+XTMP5 = %ymm11
+
+SHUF_00BA =    %ymm10 # shuffle xBxA -> 00BA
+SHUF_DC00 =    %ymm12 # shuffle xDxC -> DC00
+BYTE_FLIP_MASK = %ymm13
+
+X_BYTE_FLIP_MASK = %xmm13 # XMM version of BYTE_FLIP_MASK
+
+NUM_BLKS = %rdx        # 3rd arg
+CTX    = %rsi  # 2nd arg
+INP    = %rdi  # 1st arg
+c      = %ecx
+d      = %r8d
+e       = %edx # clobbers NUM_BLKS
+y3     = %edi  # clobbers INP
+
+
+TBL    = %rbp
+SRND   = CTX   # SRND is same register as CTX
+
+a = %eax
+b = %ebx
+f = %r9d
+g = %r10d
+h = %r11d
+old_h = %r11d
+
+T1 = %r12d
+y0 = %r13d
+y1 = %r14d
+y2 = %r15d
+
+
+_XFER_SIZE     = 2*64*4        # 2 blocks, 64 rounds, 4 bytes/round
+_XMM_SAVE_SIZE = 0
+_INP_END_SIZE  = 8
+_INP_SIZE      = 8
+_CTX_SIZE      = 8
+_RSP_SIZE      = 8
+
+_XFER          = 0
+_XMM_SAVE      = _XFER     + _XFER_SIZE
+_INP_END       = _XMM_SAVE + _XMM_SAVE_SIZE
+_INP           = _INP_END  + _INP_END_SIZE
+_CTX           = _INP      + _INP_SIZE
+_RSP           = _CTX      + _CTX_SIZE
+STACK_SIZE     = _RSP      + _RSP_SIZE
+
+# rotate_Xs
+# Rotate values of symbols X0...X3
+.macro rotate_Xs
+       X_ = X0
+       X0 = X1
+       X1 = X2
+       X2 = X3
+       X3 = X_
+.endm
+
+# ROTATE_ARGS
+# Rotate values of symbols a...h
+.macro ROTATE_ARGS
+       old_h = h
+       TMP_ = h
+       h = g
+       g = f
+       f = e
+       e = d
+       d = c
+       c = b
+       b = a
+       a = TMP_
+.endm
+
+.macro FOUR_ROUNDS_AND_SCHED disp
+################################### RND N + 0 ############################
+
+       mov     a, y3           # y3 = a                                # MAJA
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+
+       addl    \disp(%rsp, SRND), h            # h = k + w + h         # --
+       or      c, y3           # y3 = a|c                              # MAJA
+       vpalignr $4, X2, X3, XTMP0 # XTMP0 = W[-7]
+       mov     f, y2           # y2 = f                                # CH
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       xor     g, y2           # y2 = f^g                              # CH
+       vpaddd  X0, XTMP0, XTMP0 # XTMP0 = W[-7] + W[-16]# y1 = (e >> 6)# S1
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+
+       and     e, y2           # y2 = (f^g)&e                          # CH
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       add     h, d            # d = k + w + h + d                     # --
+
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+       vpalignr $4, X0, X1, XTMP1      # XTMP1 = W[-15]
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+       rorx    $2, a, T1       # T1 = (a >> 2)                         # S0
+
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+       vpsrld  $7, XTMP1, XTMP2
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     c, T1           # T1 = a&c                              # MAJB
+
+       add     y0, y2          # y2 = S1 + CH                          # --
+       vpslld  $(32-7), XTMP1, XTMP3
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+       add     y1, h           # h = k + w + h + S0                    # --
+
+       add     y2, d           # d = k + w + h + d + S1 + CH = d + t1  # --
+       vpor    XTMP2, XTMP3, XTMP3     # XTMP3 = W[-15] ror 7
+
+       vpsrld  $18, XTMP1, XTMP2
+       add     y2, h           # h = k + w + h + S0 + S1 + CH = t1 + S0# --
+       add     y3, h           # h = t1 + S0 + MAJ                     # --
+
+
+       ROTATE_ARGS
+
+################################### RND N + 1 ############################
+
+       mov     a, y3           # y3 = a                                # MAJA
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+       offset = \disp + 1*4
+       addl    offset(%rsp, SRND), h   # h = k + w + h         # --
+       or      c, y3           # y3 = a|c                              # MAJA
+
+
+       vpsrld  $3, XTMP1, XTMP4 # XTMP4 = W[-15] >> 3
+       mov     f, y2           # y2 = f                                # CH
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       xor     g, y2           # y2 = f^g                              # CH
+
+
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       and     e, y2           # y2 = (f^g)&e                          # CH
+       add     h, d            # d = k + w + h + d                     # --
+
+       vpslld  $(32-18), XTMP1, XTMP1
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+
+       vpxor   XTMP1, XTMP3, XTMP3
+       rorx    $2, a, T1       # T1 = (a >> 2)                         # S0
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+
+       vpxor   XTMP2, XTMP3, XTMP3     # XTMP3 = W[-15] ror 7 ^ W[-15] ror 18
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     c, T1           # T1 = a&c                              # MAJB
+       add     y0, y2          # y2 = S1 + CH                          # --
+
+       vpxor   XTMP4, XTMP3, XTMP1     # XTMP1 = s0
+       vpshufd $0b11111010, X3, XTMP2  # XTMP2 = W[-2] {BBAA}
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+       add     y1, h           # h = k + w + h + S0                    # --
+
+       vpaddd  XTMP1, XTMP0, XTMP0     # XTMP0 = W[-16] + W[-7] + s0
+       add     y2, d           # d = k + w + h + d + S1 + CH = d + t1  # --
+       add     y2, h           # h = k + w + h + S0 + S1 + CH = t1 + S0# --
+       add     y3, h           # h = t1 + S0 + MAJ                     # --
+
+       vpsrld  $10, XTMP2, XTMP4 # XTMP4 = W[-2] >> 10 {BBAA}
+
+
+       ROTATE_ARGS
+
+################################### RND N + 2 ############################
+
+       mov     a, y3           # y3 = a                                # MAJA
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       offset = \disp + 2*4
+       addl    offset(%rsp, SRND), h   # h = k + w + h         # --
+
+       vpsrlq  $19, XTMP2, XTMP3 # XTMP3 = W[-2] ror 19 {xBxA}
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+       or      c, y3           # y3 = a|c                              # MAJA
+       mov     f, y2           # y2 = f                                # CH
+       xor     g, y2           # y2 = f^g                              # CH
+
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       vpsrlq  $17, XTMP2, XTMP2       # XTMP2 = W[-2] ror 17 {xBxA}
+       and     e, y2           # y2 = (f^g)&e                          # CH
+
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+       vpxor   XTMP3, XTMP2, XTMP2
+       add     h, d            # d = k + w + h + d                     # --
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       vpxor   XTMP2, XTMP4, XTMP4     # XTMP4 = s1 {xBxA}
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+
+       vpshufb SHUF_00BA, XTMP4, XTMP4 # XTMP4 = s1 {00BA}
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+       rorx    $2, a ,T1       # T1 = (a >> 2)                         # S0
+       vpaddd  XTMP4, XTMP0, XTMP0     # XTMP0 = {..., ..., W[1], W[0]}
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     c, T1           # T1 = a&c                              # MAJB
+       add     y0, y2          # y2 = S1 + CH                          # --
+       vpshufd $0b01010000, XTMP0, XTMP2       # XTMP2 = W[-2] {DDCC}
+
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+       add     y1,h            # h = k + w + h + S0                    # --
+       add     y2,d            # d = k + w + h + d + S1 + CH = d + t1  # --
+       add     y2,h            # h = k + w + h + S0 + S1 + CH = t1 + S0# --
+
+       add     y3,h            # h = t1 + S0 + MAJ                     # --
+
+
+       ROTATE_ARGS
+
+################################### RND N + 3 ############################
+
+       mov     a, y3           # y3 = a                                # MAJA
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+       offset = \disp + 3*4
+       addl    offset(%rsp, SRND), h   # h = k + w + h         # --
+       or      c, y3           # y3 = a|c                              # MAJA
+
+
+       vpsrld  $10, XTMP2, XTMP5       # XTMP5 = W[-2] >> 10 {DDCC}
+       mov     f, y2           # y2 = f                                # CH
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       xor     g, y2           # y2 = f^g                              # CH
+
+
+       vpsrlq  $19, XTMP2, XTMP3       # XTMP3 = W[-2] ror 19 {xDxC}
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+       and     e, y2           # y2 = (f^g)&e                          # CH
+       add     h, d            # d = k + w + h + d                     # --
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+
+       vpsrlq  $17, XTMP2, XTMP2       # XTMP2 = W[-2] ror 17 {xDxC}
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+
+       vpxor   XTMP3, XTMP2, XTMP2
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       add     y0, y2          # y2 = S1 + CH                          # --
+
+       vpxor   XTMP2, XTMP5, XTMP5     # XTMP5 = s1 {xDxC}
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+       add     y2, d           # d = k + w + h + d + S1 + CH = d + t1  # --
+
+       rorx    $2, a, T1       # T1 = (a >> 2)                         # S0
+       vpshufb SHUF_DC00, XTMP5, XTMP5 # XTMP5 = s1 {DC00}
+
+       vpaddd  XTMP0, XTMP5, X0        # X0 = {W[3], W[2], W[1], W[0]}
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     c, T1           # T1 = a&c                              # MAJB
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+
+       add     y1, h           # h = k + w + h + S0                    # --
+       add     y2, h           # h = k + w + h + S0 + S1 + CH = t1 + S0# --
+       add     y3, h           # h = t1 + S0 + MAJ                     # --
+
+       ROTATE_ARGS
+       rotate_Xs
+.endm
+
+.macro DO_4ROUNDS disp
+################################### RND N + 0 ###########################
+
+       mov     f, y2           # y2 = f                                # CH
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+       xor     g, y2           # y2 = f^g                              # CH
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+       and     e, y2           # y2 = (f^g)&e                          # CH
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       mov     a, y3           # y3 = a                                # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+       rorx    $2, a, T1       # T1 = (a >> 2)                         # S0
+       addl    \disp(%rsp, SRND), h            # h = k + w + h # --
+       or      c, y3           # y3 = a|c                              # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+       and     c, T1           # T1 = a&c                              # MAJB
+       add     y0, y2          # y2 = S1 + CH                          # --
+
+
+       add     h, d            # d = k + w + h + d                     # --
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+       add     y1, h           # h = k + w + h + S0                    # --
+       add     y2, d           # d = k + w + h + d + S1 + CH = d + t1  # --
+
+       ROTATE_ARGS
+
+################################### RND N + 1 ###########################
+
+       add     y2, old_h       # h = k + w + h + S0 + S1 + CH = t1 + S0# --
+       mov     f, y2           # y2 = f                                # CH
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+       xor     g, y2           # y2 = f^g                              # CH
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+       and     e, y2           # y2 = (f^g)&e                          # CH
+       add     y3, old_h       # h = t1 + S0 + MAJ                     # --
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       mov     a, y3           # y3 = a                                # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+       rorx    $2, a, T1       # T1 = (a >> 2)                         # S0
+       offset = 4*1 + \disp
+       addl    offset(%rsp, SRND), h           # h = k + w + h # --
+       or      c, y3           # y3 = a|c                              # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+       and     c, T1           # T1 = a&c                              # MAJB
+       add     y0, y2          # y2 = S1 + CH                          # --
+
+
+       add     h, d            # d = k + w + h + d                     # --
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+       add     y1, h           # h = k + w + h + S0                    # --
+
+       add     y2, d           # d = k + w + h + d + S1 + CH = d + t1  # --
+
+       ROTATE_ARGS
+
+################################### RND N + 2 ##############################
+
+       add     y2, old_h       # h = k + w + h + S0 + S1 + CH = t1 + S0# --
+       mov     f, y2           # y2 = f                                # CH
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+       xor     g, y2           # y2 = f^g                              # CH
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+       and     e, y2           # y2 = (f^g)&e                          # CH
+       add     y3, old_h       # h = t1 + S0 + MAJ                     # --
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       mov     a, y3           # y3 = a                                # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+       rorx    $2, a, T1       # T1 = (a >> 2)                         # S0
+       offset = 4*2 + \disp
+       addl    offset(%rsp, SRND), h           # h = k + w + h # --
+       or      c, y3           # y3 = a|c                              # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+       and     c, T1           # T1 = a&c                              # MAJB
+       add     y0, y2          # y2 = S1 + CH                          # --
+
+
+       add     h, d            # d = k + w + h + d                     # --
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+       add     y1, h           # h = k + w + h + S0                    # --
+
+       add     y2, d           # d = k + w + h + d + S1 + CH = d + t1  # --
+
+       ROTATE_ARGS
+
+################################### RND N + 3 ###########################
+
+       add     y2, old_h       # h = k + w + h + S0 + S1 + CH = t1 + S0# --
+       mov     f, y2           # y2 = f                                # CH
+       rorx    $25, e, y0      # y0 = e >> 25                          # S1A
+       rorx    $11, e, y1      # y1 = e >> 11                          # S1B
+       xor     g, y2           # y2 = f^g                              # CH
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11)                # S1
+       rorx    $6, e, y1       # y1 = (e >> 6)                         # S1
+       and     e, y2           # y2 = (f^g)&e                          # CH
+       add     y3, old_h       # h = t1 + S0 + MAJ                     # --
+
+       xor     y1, y0          # y0 = (e>>25) ^ (e>>11) ^ (e>>6)       # S1
+       rorx    $13, a, T1      # T1 = a >> 13                          # S0B
+       xor     g, y2           # y2 = CH = ((f^g)&e)^g                 # CH
+       rorx    $22, a, y1      # y1 = a >> 22                          # S0A
+       mov     a, y3           # y3 = a                                # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13)                # S0
+       rorx    $2, a, T1       # T1 = (a >> 2)                         # S0
+       offset = 4*3 + \disp
+       addl    offset(%rsp, SRND), h           # h = k + w + h # --
+       or      c, y3           # y3 = a|c                              # MAJA
+
+       xor     T1, y1          # y1 = (a>>22) ^ (a>>13) ^ (a>>2)       # S0
+       mov     a, T1           # T1 = a                                # MAJB
+       and     b, y3           # y3 = (a|c)&b                          # MAJA
+       and     c, T1           # T1 = a&c                              # MAJB
+       add     y0, y2          # y2 = S1 + CH                          # --
+
+
+       add     h, d            # d = k + w + h + d                     # --
+       or      T1, y3          # y3 = MAJ = (a|c)&b)|(a&c)             # MAJ
+      &n