Copyright consolidation 06/10
[openssl.git] / crypto / bn / rsaz_exp.c
index 57591b8db34f2076b53dda1be015e922e918ade5..3398cce9ab450f2a7663161367c3acce1d60af3f 100644 (file)
-/******************************************************************************\r
-* Copyright(c) 2012, Intel Corp.                                             \r
-* Developers and authors:                                                    \r
-* Shay Gueron (1, 2), and Vlad Krasnov (1)                                   \r
-* (1) Intel Corporation, Israel Development Center, Haifa, Israel                               \r
-* (2) University of Haifa, Israel                                              \r
-******************************************************************************\r
-* LICENSE:                                                                \r
-* This submission to OpenSSL is to be made available under the OpenSSL  \r
-* license, and only to the OpenSSL project, in order to allow integration    \r
-* into the publicly distributed code. \r
-* The use of this code, or portions of this code, or concepts embedded in\r
-* this code, or modification of this code and/or algorithm(s) in it, or the\r
-* use of this code for any other purpose than stated above, requires special\r
-* licensing.                                                                  \r
-******************************************************************************\r
-* DISCLAIMER:                                                                \r
-* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS AND THE COPYRIGHT OWNERS     \r
-* ``AS IS''. ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED \r
-* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR \r
-* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS OR THE COPYRIGHT\r
-* OWNERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, \r
-* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF    \r
-* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS   \r
-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN    \r
-* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)    \r
-* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE \r
-* POSSIBILITY OF SUCH DAMAGE.                                                \r
-******************************************************************************/\r
-\r
-#include "rsaz_exp.h"\r
-\r
-/*\r
- * See crypto/bn/asm/rsaz-avx2.pl for further details.\r
- */\r
-void rsaz_1024_norm2red_avx2(void *red,const void *norm);\r
-void rsaz_1024_mul_avx2(void *ret,const void *a,const void *b,const void *n,unsigned long k);\r
-void rsaz_1024_sqr_avx2(void *ret,const void *a,const void *n,unsigned long k,int cnt);\r
-void rsaz_1024_scatter5_avx2(void *tbl,const void *val,int i);\r
-void rsaz_1024_gather5_avx2(void *val,const void *tbl,int i);\r
-void rsaz_1024_red2norm_avx2(void *norm,const void *red);\r
-\r
-#if defined(__GNUC__)\r
-# define ALIGN64       __attribute__((aligned(64)))\r
-#elif defined(_MSC_VER)\r
-# define ALIGN64       __declspec(align(64))\r
-#elif defined(__SUNPRO_C)\r
-# define ALIGN64\r
-# pragma align 64(one,two80)\r
-#else\r
-# define ALIGN64       /* not fatal, might hurt performance a little */\r
-#endif\r
-\r
-ALIGN64 static const unsigned long one[40] =\r
-       {1,0,0,    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};\r
-ALIGN64 static const unsigned long two80[40] =\r
-       {0,0,1<<22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};\r
-\r
-void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],\r
-       const BN_ULONG base_norm[16], const BN_ULONG exponent[16],\r
-       const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0)\r
-{\r
-       unsigned char    storage[320*3+32*9*16+64];     /* 5.5KB */\r
-       unsigned char   *p_str = storage + (64-((size_t)storage%64));\r
-       unsigned char   *a_inv, *m, *result,\r
-                       *table_s = p_str+320*3,\r
-                       *R2      = table_s;     /* borrow */\r
-       int index;\r
-       int wvalue;\r
-\r
-       if ((((size_t)p_str&4095)+320)>>12) {\r
-               result = p_str;\r
-               a_inv = p_str + 320;\r
-               m = p_str + 320*2;      /* should not cross page */\r
-       } else {\r
-               m = p_str;              /* should not cross page */\r
-               result = p_str + 320;\r
-               a_inv = p_str + 320*2;\r
-       }\r
-\r
-       rsaz_1024_norm2red_avx2(m, m_norm);\r
-       rsaz_1024_norm2red_avx2(a_inv, base_norm);\r
-       rsaz_1024_norm2red_avx2(R2, RR);\r
-\r
-       rsaz_1024_mul_avx2(R2, R2, R2, m, k0);\r
-       rsaz_1024_mul_avx2(R2, R2, two80, m, k0);\r
-\r
-       /* table[0] = 1 */\r
-       rsaz_1024_mul_avx2(result, R2, one, m, k0);\r
-       /* table[1] = a_inv^1 */\r
-       rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);\r
-\r
-       rsaz_1024_scatter5_avx2(table_s,result,0);\r
-       rsaz_1024_scatter5_avx2(table_s,a_inv,1);\r
-\r
-       /* table[2] = a_inv^2 */\r
-       rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,2);\r
-#if 0\r
-       /* this is almost 2x smaller and less than 1% slower */\r
-       for (index=3; index<32; index++) {\r
-               rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-               rsaz_1024_scatter5_avx2(table_s,result,index);\r
-       }\r
-#else\r
-       /* table[4] = a_inv^4 */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,4);\r
-       /* table[8] = a_inv^8 */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,8);\r
-       /* table[16] = a_inv^16 */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,16);\r
-       /* table[17] = a_inv^17 */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,17);\r
-\r
-       /* table[3] */\r
-       rsaz_1024_gather5_avx2(result,table_s,2);\r
-       rsaz_1024_mul_avx2(result,result,a_inv,m,k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,3);\r
-       /* table[6] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,6);\r
-       /* table[12] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,12);\r
-       /* table[24] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,24);\r
-       /* table[25] */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,25);\r
-\r
-       /* table[5] */\r
-       rsaz_1024_gather5_avx2(result,table_s,4);\r
-       rsaz_1024_mul_avx2(result,result,a_inv,m,k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,5);\r
-       /* table[10] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,10);\r
-       /* table[20] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,20);\r
-       /* table[21] */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,21);\r
-\r
-       /* table[7] */\r
-       rsaz_1024_gather5_avx2(result,table_s,6);\r
-       rsaz_1024_mul_avx2(result,result,a_inv,m,k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,7);\r
-       /* table[14] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,14);\r
-       /* table[28] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,28);\r
-       /* table[29] */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,29);\r
-\r
-       /* table[9] */\r
-       rsaz_1024_gather5_avx2(result,table_s,8);\r
-       rsaz_1024_mul_avx2(result,result,a_inv,m,k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,9);\r
-       /* table[18] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,18);\r
-       /* table[19] */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,19);\r
-\r
-       /* table[11] */\r
-       rsaz_1024_gather5_avx2(result,table_s,10);\r
-       rsaz_1024_mul_avx2(result,result,a_inv,m,k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,11);\r
-       /* table[22] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,22);\r
-       /* table[23] */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,23);\r
-\r
-       /* table[13] */\r
-       rsaz_1024_gather5_avx2(result,table_s,12);\r
-       rsaz_1024_mul_avx2(result,result,a_inv,m,k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,13);\r
-       /* table[26] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,26);\r
-       /* table[27] */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,27);\r
-\r
-       /* table[15] */\r
-       rsaz_1024_gather5_avx2(result,table_s,14);\r
-       rsaz_1024_mul_avx2(result,result,a_inv,m,k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,15);\r
-       /* table[30] */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 1);\r
-       rsaz_1024_scatter5_avx2(table_s,result,30);\r
-       /* table[31] */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       rsaz_1024_scatter5_avx2(table_s,result,31);\r
-#endif\r
-\r
-       /* load first window */\r
-       p_str = (unsigned char*)exponent;\r
-       wvalue = p_str[127] >> 3;\r
-       rsaz_1024_gather5_avx2(result,table_s,wvalue);\r
-\r
-       index = 1014;\r
-\r
-       while(index > -1) {     /* loop for the remaining 127 windows */\r
-\r
-               rsaz_1024_sqr_avx2(result, result, m, k0, 5);\r
-\r
-               wvalue = *((unsigned short*)&p_str[index/8]);\r
-               wvalue = (wvalue>> (index%8)) & 31;\r
-               index-=5;\r
-\r
-               rsaz_1024_gather5_avx2(a_inv,table_s,wvalue);   /* borrow a_inv */\r
-               rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-       }\r
-\r
-       /* square four times */\r
-       rsaz_1024_sqr_avx2(result, result, m, k0, 4);\r
-\r
-       wvalue = p_str[0] & 15;\r
-\r
-       rsaz_1024_gather5_avx2(a_inv,table_s,wvalue);   /* borrow a_inv */\r
-       rsaz_1024_mul_avx2(result, result, a_inv, m, k0);\r
-\r
-       /* from Montgomery */\r
-       rsaz_1024_mul_avx2(result, result, one, m, k0);\r
-\r
-       rsaz_1024_red2norm_avx2(result_norm, result);\r
-\r
-       OPENSSL_cleanse(storage,sizeof(storage));\r
-}\r
-\r
-/*\r
- * See crypto/bn/rsaz-x86_64.pl for further details.\r
- */\r
-void rsaz_512_mul(void *ret,const void *a,const void *b,const void *n,unsigned long k);\r
-void rsaz_512_mul_scatter4(void *ret,const void *a,const void *n,unsigned long k,const void *tbl,unsigned int power);\r
-void rsaz_512_mul_gather4(void *ret,const void *a,const void *tbl,const void *n,unsigned long k,unsigned int power);\r
-void rsaz_512_mul_by_one(void *ret,const void *a,const void *n,unsigned long k);\r
-void rsaz_512_sqr(void *ret,const void *a,const void *n,unsigned long k,int cnt);\r
-void rsaz_512_scatter4(void *tbl, const unsigned long *val, int power);\r
-void rsaz_512_gather4(unsigned long *val, const void *tbl, int power);\r
-\r
-void RSAZ_512_mod_exp(BN_ULONG result[8],\r
-       const BN_ULONG base[8], const BN_ULONG exponent[8],\r
-       const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8])\r
-{\r
-       unsigned char    storage[16*8*8+64*2+64];       /* 1.2KB */\r
-       unsigned char   *table = storage + (64-((size_t)storage%64));\r
-       unsigned long   *a_inv = (unsigned long *)(table+16*8*8),\r
-                       *temp  = (unsigned long *)(table+16*8*8+8*8);\r
-       unsigned char   *p_str = (unsigned char*)exponent;\r
-       int index;\r
-       unsigned int wvalue;\r
-\r
-       /* table[0] = 1_inv */\r
-       temp[0] = 0-m[0];       temp[1] = ~m[1];\r
-       temp[2] = ~m[2];        temp[3] = ~m[3];\r
-       temp[4] = ~m[4];        temp[5] = ~m[5];\r
-       temp[6] = ~m[6];        temp[7] = ~m[7];\r
-       rsaz_512_scatter4(table, temp, 0);\r
-\r
-       /* table [1] = a_inv^1 */\r
-       rsaz_512_mul(a_inv, base, RR, m, k0);\r
-       rsaz_512_scatter4(table, a_inv, 1);\r
-\r
-       /* table [2] = a_inv^2 */\r
-       rsaz_512_sqr(temp, a_inv, m, k0, 1);\r
-       rsaz_512_scatter4(table, temp, 2);\r
-\r
-       for (index=3; index<16; index++)\r
-               rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index);\r
-\r
-       /* load first window */\r
-       wvalue = p_str[63];\r
-\r
-       rsaz_512_gather4(temp, table, wvalue>>4);\r
-       rsaz_512_sqr(temp, temp, m, k0, 4);\r
-       rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0xf);\r
-\r
-       for (index=62; index>=0; index--) {\r
-               wvalue = p_str[index];\r
-\r
-               rsaz_512_sqr(temp, temp, m, k0, 4);\r
-               rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue>>4);\r
-\r
-               rsaz_512_sqr(temp, temp, m, k0, 4);\r
-               rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0x0f);\r
-       }\r
-\r
-       /* from Montgomery */\r
-       rsaz_512_mul_by_one(result, temp, m, k0);\r
-\r
-       OPENSSL_cleanse(storage,sizeof(storage));\r
-}\r
+/*
+ * Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*****************************************************************************
+*                                                                            *
+*  Copyright (c) 2012, Intel Corporation                                     *
+*                                                                            *
+*  All rights reserved.                                                      *
+*                                                                            *
+*  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.                                                          *
+*                                                                            *
+*  *  Neither the name of the Intel Corporation nor the names of its         *
+*     contributors may be used to endorse or promote products derived from   *
+*     this software without specific prior written permission.               *
+*                                                                            *
+*                                                                            *
+*  THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY          *
+*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE         *
+*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        *
+*  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR            *
+*  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
+*  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
+*  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
+*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
+*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
+*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
+*                                                                            *
+******************************************************************************
+* Developers and authors:                                                    *
+* Shay Gueron (1, 2), and Vlad Krasnov (1)                                   *
+* (1) Intel Corporation, Israel Development Center, Haifa, Israel            *
+* (2) University of Haifa, Israel                                            *
+*****************************************************************************/
+
+#include <openssl/opensslconf.h>
+#include "rsaz_exp.h"
+
+#ifndef RSAZ_ENABLED
+NON_EMPTY_TRANSLATION_UNIT
+#else
+
+/*
+ * See crypto/bn/asm/rsaz-avx2.pl for further details.
+ */
+void rsaz_1024_norm2red_avx2(void *red, const void *norm);
+void rsaz_1024_mul_avx2(void *ret, const void *a, const void *b,
+                        const void *n, BN_ULONG k);
+void rsaz_1024_sqr_avx2(void *ret, const void *a, const void *n, BN_ULONG k,
+                        int cnt);
+void rsaz_1024_scatter5_avx2(void *tbl, const void *val, int i);
+void rsaz_1024_gather5_avx2(void *val, const void *tbl, int i);
+void rsaz_1024_red2norm_avx2(void *norm, const void *red);
+
+#if defined(__GNUC__)
+# define ALIGN64        __attribute__((aligned(64)))
+#elif defined(_MSC_VER)
+# define ALIGN64        __declspec(align(64))
+#elif defined(__SUNPRO_C)
+# define ALIGN64
+# pragma align 64(one,two80)
+#else
+/* not fatal, might hurt performance a little */
+# define ALIGN64
+#endif
+
+ALIGN64 static const BN_ULONG one[40] = {
+    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+ALIGN64 static const BN_ULONG two80[40] = {
+    0, 0, 1 << 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],
+                            const BN_ULONG base_norm[16],
+                            const BN_ULONG exponent[16],
+                            const BN_ULONG m_norm[16], const BN_ULONG RR[16],
+                            BN_ULONG k0)
+{
+    unsigned char storage[320 * 3 + 32 * 9 * 16 + 64]; /* 5.5KB */
+    unsigned char *p_str = storage + (64 - ((size_t)storage % 64));
+    unsigned char *a_inv, *m, *result;
+    unsigned char *table_s = p_str + 320 * 3;
+    unsigned char *R2 = table_s; /* borrow */
+    int index;
+    int wvalue;
+
+    if ((((size_t)p_str & 4095) + 320) >> 12) {
+        result = p_str;
+        a_inv = p_str + 320;
+        m = p_str + 320 * 2;    /* should not cross page */
+    } else {
+        m = p_str;              /* should not cross page */
+        result = p_str + 320;
+        a_inv = p_str + 320 * 2;
+    }
+
+    rsaz_1024_norm2red_avx2(m, m_norm);
+    rsaz_1024_norm2red_avx2(a_inv, base_norm);
+    rsaz_1024_norm2red_avx2(R2, RR);
+
+    rsaz_1024_mul_avx2(R2, R2, R2, m, k0);
+    rsaz_1024_mul_avx2(R2, R2, two80, m, k0);
+
+    /* table[0] = 1 */
+    rsaz_1024_mul_avx2(result, R2, one, m, k0);
+    /* table[1] = a_inv^1 */
+    rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);
+
+    rsaz_1024_scatter5_avx2(table_s, result, 0);
+    rsaz_1024_scatter5_avx2(table_s, a_inv, 1);
+
+    /* table[2] = a_inv^2 */
+    rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 2);
+#if 0
+    /* this is almost 2x smaller and less than 1% slower */
+    for (index = 3; index < 32; index++) {
+        rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+        rsaz_1024_scatter5_avx2(table_s, result, index);
+    }
+#else
+    /* table[4] = a_inv^4 */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 4);
+    /* table[8] = a_inv^8 */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 8);
+    /* table[16] = a_inv^16 */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 16);
+    /* table[17] = a_inv^17 */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 17);
+
+    /* table[3] */
+    rsaz_1024_gather5_avx2(result, table_s, 2);
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 3);
+    /* table[6] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 6);
+    /* table[12] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 12);
+    /* table[24] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 24);
+    /* table[25] */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 25);
+
+    /* table[5] */
+    rsaz_1024_gather5_avx2(result, table_s, 4);
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 5);
+    /* table[10] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 10);
+    /* table[20] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 20);
+    /* table[21] */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 21);
+
+    /* table[7] */
+    rsaz_1024_gather5_avx2(result, table_s, 6);
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 7);
+    /* table[14] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 14);
+    /* table[28] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 28);
+    /* table[29] */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 29);
+
+    /* table[9] */
+    rsaz_1024_gather5_avx2(result, table_s, 8);
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 9);
+    /* table[18] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 18);
+    /* table[19] */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 19);
+
+    /* table[11] */
+    rsaz_1024_gather5_avx2(result, table_s, 10);
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 11);
+    /* table[22] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 22);
+    /* table[23] */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 23);
+
+    /* table[13] */
+    rsaz_1024_gather5_avx2(result, table_s, 12);
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 13);
+    /* table[26] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 26);
+    /* table[27] */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 27);
+
+    /* table[15] */
+    rsaz_1024_gather5_avx2(result, table_s, 14);
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 15);
+    /* table[30] */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+    rsaz_1024_scatter5_avx2(table_s, result, 30);
+    /* table[31] */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    rsaz_1024_scatter5_avx2(table_s, result, 31);
+#endif
+
+    /* load first window */
+    p_str = (unsigned char *)exponent;
+    wvalue = p_str[127] >> 3;
+    rsaz_1024_gather5_avx2(result, table_s, wvalue);
+
+    index = 1014;
+
+    while (index > -1) {        /* loop for the remaining 127 windows */
+
+        rsaz_1024_sqr_avx2(result, result, m, k0, 5);
+
+        wvalue = *((unsigned short *)&p_str[index / 8]);
+        wvalue = (wvalue >> (index % 8)) & 31;
+        index -= 5;
+
+        rsaz_1024_gather5_avx2(a_inv, table_s, wvalue); /* borrow a_inv */
+        rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+    }
+
+    /* square four times */
+    rsaz_1024_sqr_avx2(result, result, m, k0, 4);
+
+    wvalue = p_str[0] & 15;
+
+    rsaz_1024_gather5_avx2(a_inv, table_s, wvalue); /* borrow a_inv */
+    rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+
+    /* from Montgomery */
+    rsaz_1024_mul_avx2(result, result, one, m, k0);
+
+    rsaz_1024_red2norm_avx2(result_norm, result);
+
+    OPENSSL_cleanse(storage, sizeof(storage));
+}
+
+/*
+ * See crypto/bn/rsaz-x86_64.pl for further details.
+ */
+void rsaz_512_mul(void *ret, const void *a, const void *b, const void *n,
+                  BN_ULONG k);
+void rsaz_512_mul_scatter4(void *ret, const void *a, const void *n,
+                           BN_ULONG k, const void *tbl, unsigned int power);
+void rsaz_512_mul_gather4(void *ret, const void *a, const void *tbl,
+                          const void *n, BN_ULONG k, unsigned int power);
+void rsaz_512_mul_by_one(void *ret, const void *a, const void *n, BN_ULONG k);
+void rsaz_512_sqr(void *ret, const void *a, const void *n, BN_ULONG k,
+                  int cnt);
+void rsaz_512_scatter4(void *tbl, const BN_ULONG *val, int power);
+void rsaz_512_gather4(BN_ULONG *val, const void *tbl, int power);
+
+void RSAZ_512_mod_exp(BN_ULONG result[8],
+                      const BN_ULONG base[8], const BN_ULONG exponent[8],
+                      const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8])
+{
+    unsigned char storage[16 * 8 * 8 + 64 * 2 + 64]; /* 1.2KB */
+    unsigned char *table = storage + (64 - ((size_t)storage % 64));
+    BN_ULONG *a_inv = (BN_ULONG *)(table + 16 * 8 * 8);
+    BN_ULONG *temp = (BN_ULONG *)(table + 16 * 8 * 8 + 8 * 8);
+    unsigned char *p_str = (unsigned char *)exponent;
+    int index;
+    unsigned int wvalue;
+
+    /* table[0] = 1_inv */
+    temp[0] = 0 - m[0];
+    temp[1] = ~m[1];
+    temp[2] = ~m[2];
+    temp[3] = ~m[3];
+    temp[4] = ~m[4];
+    temp[5] = ~m[5];
+    temp[6] = ~m[6];
+    temp[7] = ~m[7];
+    rsaz_512_scatter4(table, temp, 0);
+
+    /* table [1] = a_inv^1 */
+    rsaz_512_mul(a_inv, base, RR, m, k0);
+    rsaz_512_scatter4(table, a_inv, 1);
+
+    /* table [2] = a_inv^2 */
+    rsaz_512_sqr(temp, a_inv, m, k0, 1);
+    rsaz_512_scatter4(table, temp, 2);
+
+    for (index = 3; index < 16; index++)
+        rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index);
+
+    /* load first window */
+    wvalue = p_str[63];
+
+    rsaz_512_gather4(temp, table, wvalue >> 4);
+    rsaz_512_sqr(temp, temp, m, k0, 4);
+    rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue & 0xf);
+
+    for (index = 62; index >= 0; index--) {
+        wvalue = p_str[index];
+
+        rsaz_512_sqr(temp, temp, m, k0, 4);
+        rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue >> 4);
+
+        rsaz_512_sqr(temp, temp, m, k0, 4);
+        rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue & 0x0f);
+    }
+
+    /* from Montgomery */
+    rsaz_512_mul_by_one(result, temp, m, k0);
+
+    OPENSSL_cleanse(storage, sizeof(storage));
+}
+
+#endif