195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/*****************************************************************************
295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  Copyright (c) 2012, Intel Corporation                                     *
495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  All rights reserved.                                                      *
695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  Redistribution and use in source and binary forms, with or without        *
895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  modification, are permitted provided that the following conditions are    *
995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  met:                                                                      *
1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  *  Redistributions of source code must retain the above copyright         *
1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*     notice, this list of conditions and the following disclaimer.          *
1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  *  Redistributions in binary form must reproduce the above copyright      *
1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*     notice, this list of conditions and the following disclaimer in the    *
1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*     documentation and/or other materials provided with the                 *
1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*     distribution.                                                          *
1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  *  Neither the name of the Intel Corporation nor the names of its         *
2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*     contributors may be used to endorse or promote products derived from   *
2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*     this software without specific prior written permission.               *
2295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
2395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY          *
2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE         *
2695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        *
2795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR            *
2895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
2995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
3195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
3295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
3395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
3495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
3595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*                                                                            *
3695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley******************************************************************************
3795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley* Developers and authors:                                                    *
3895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley* Shay Gueron (1, 2), and Vlad Krasnov (1)                                   *
3995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley* (1) Intel Corporation, Israel Development Center, Haifa, Israel            *
4095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley* (2) University of Haifa, Israel                                            *
4195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley*****************************************************************************/
4295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
4323b460df0275d7b1543d3b5e0a33b1660a501ce9Adam Langley#include <openssl/base.h>
4423b460df0275d7b1543d3b5e0a33b1660a501ce9Adam Langley
450113a4fb60c3b6e9e93a217d5b4d373eb343a8c6Adam Langley#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64)
4623b460df0275d7b1543d3b5e0a33b1660a501ce9Adam Langley
4795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "rsaz_exp.h"
4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/mem.h>
5095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/*
5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * See crypto/bn/asm/rsaz-avx2.pl for further details.
5395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley */
5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_1024_norm2red_avx2(void *red,const void *norm);
5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_1024_mul_avx2(void *ret,const void *a,const void *b,const void *n,BN_ULONG k);
5695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_1024_sqr_avx2(void *ret,const void *a,const void *n,BN_ULONG k,int cnt);
5795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_1024_scatter5_avx2(void *tbl,const void *val,int i);
5895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_1024_gather5_avx2(void *val,const void *tbl,int i);
5995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_1024_red2norm_avx2(void *norm,const void *red);
6095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#if defined(__GNUC__)
6295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# define ALIGN64	__attribute__((aligned(64)))
6395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#elif defined(_MSC_VER)
6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# define ALIGN64	__declspec(align(64))
6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#elif defined(__SUNPRO_C)
6695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# define ALIGN64
6795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# pragma align 64(one,two80)
6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#else
6995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley# define ALIGN64	/* not fatal, might hurt performance a little */
7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#endif
7195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7295c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyALIGN64 static const BN_ULONG one[40] =
7395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	{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};
7495c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyALIGN64 static const BN_ULONG two80[40] =
7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	{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};
7695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],
7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	const BN_ULONG base_norm[16], const BN_ULONG exponent[16],
7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0)
8095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{
8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	unsigned char	 storage[320*3+32*9*16+64];	/* 5.5KB */
8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	unsigned char	*p_str = storage + (64-((size_t)storage%64));
8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	unsigned char	*a_inv, *m, *result,
8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			*table_s = p_str+320*3,
8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			*R2      = table_s;	/* borrow */
8695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	int index;
8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	int wvalue;
8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	if ((((size_t)p_str&4095)+320)>>12) {
9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		result = p_str;
9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		a_inv = p_str + 320;
9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		m = p_str + 320*2;	/* should not cross page */
9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	} else {
9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		m = p_str;		/* should not cross page */
9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		result = p_str + 320;
9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		a_inv = p_str + 320*2;
9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_norm2red_avx2(m, m_norm);
10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_norm2red_avx2(a_inv, base_norm);
10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_norm2red_avx2(R2, RR);
10295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(R2, R2, R2, m, k0);
10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(R2, R2, two80, m, k0);
10595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[0] = 1 */
10795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, R2, one, m, k0);
10895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[1] = a_inv^1 */
10995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);
11095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,0);
11295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,a_inv,1);
11395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[2] = a_inv^2 */
11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1);
11695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,2);
11795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#if 0
11895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* this is almost 2x smaller and less than 1% slower */
11995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	for (index=3; index<32; index++) {
12095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
12195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_1024_scatter5_avx2(table_s,result,index);
12295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
12395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#else
12495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[4] = a_inv^4 */
12595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
12695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,4);
12795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[8] = a_inv^8 */
12895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
12995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,8);
13095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[16] = a_inv^16 */
13195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
13295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,16);
13395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[17] = a_inv^17 */
13495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
13595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,17);
13695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
13795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[3] */
13895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,2);
13995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
14095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,3);
14195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[6] */
14295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
14395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,6);
14495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[12] */
14595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
14695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,12);
14795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley 	/* table[24] */
14895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
14995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,24);
15095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[25] */
15195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
15295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,25);
15395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[5] */
15595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,4);
15695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
15795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,5);
15895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[10] */
15995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
16095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,10);
16195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[20] */
16295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
16395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,20);
16495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[21] */
16595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
16695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,21);
16795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
16895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[7] */
16995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,6);
17095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
17195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,7);
17295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[14] */
17395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
17495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,14);
17595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[28] */
17695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
17795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,28);
17895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[29] */
17995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
18095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,29);
18195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[9] */
18395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,8);
18495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
18595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,9);
18695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[18] */
18795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
18895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,18);
18995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[19] */
19095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
19195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,19);
19295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[11] */
19495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,10);
19595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
19695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,11);
19795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[22] */
19895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
19995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,22);
20095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[23] */
20195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
20295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,23);
20395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[13] */
20595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,12);
20695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
20795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,13);
20895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[26] */
20995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
21095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,26);
21195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[27] */
21295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
21395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,27);
21495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[15] */
21695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,14);
21795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
21895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,15);
21995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[30] */
22095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 1);
22195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,30);
22295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[31] */
22395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
22495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_scatter5_avx2(table_s,result,31);
22595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#endif
22695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* load first window */
22895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	p_str = (unsigned char*)exponent;
22995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	wvalue = p_str[127] >> 3;
23095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(result,table_s,wvalue);
23195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	index = 1014;
23395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	while(index > -1) {	/* loop for the remaining 127 windows */
23595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_1024_sqr_avx2(result, result, m, k0, 5);
23795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		wvalue = *((unsigned short*)&p_str[index/8]);
23995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		wvalue = (wvalue>> (index%8)) & 31;
24095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		index-=5;
24195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_1024_gather5_avx2(a_inv,table_s,wvalue);	/* borrow a_inv */
24395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
24495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
24595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* square four times */
24795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_sqr_avx2(result, result, m, k0, 4);
24895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	wvalue = p_str[0] & 15;
25095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_gather5_avx2(a_inv,table_s,wvalue);	/* borrow a_inv */
25295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
25395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* from Montgomery */
25595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_mul_avx2(result, result, one, m, k0);
25695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_1024_red2norm_avx2(result_norm, result);
25895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	OPENSSL_cleanse(storage,sizeof(storage));
26095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
26195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/*
26395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * See crypto/bn/rsaz-x86_64.pl for further details.
26495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley */
26595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_512_mul(void *ret,const void *a,const void *b,const void *n,BN_ULONG k);
26695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_512_mul_scatter4(void *ret,const void *a,const void *n,BN_ULONG k,const void *tbl,unsigned int power);
26795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_512_mul_gather4(void *ret,const void *a,const void *tbl,const void *n,BN_ULONG k,unsigned int power);
26895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_512_mul_by_one(void *ret,const void *a,const void *n,BN_ULONG k);
26995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_512_sqr(void *ret,const void *a,const void *n,BN_ULONG k,int cnt);
27095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_512_scatter4(void *tbl, const BN_ULONG *val, int power);
27195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid rsaz_512_gather4(BN_ULONG *val, const void *tbl, int power);
27295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
27395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid RSAZ_512_mod_exp(BN_ULONG result[8],
27495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	const BN_ULONG base[8], const BN_ULONG exponent[8],
27595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8])
27695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley{
27795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	unsigned char	 storage[16*8*8+64*2+64];	/* 1.2KB */
27895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	unsigned char	*table = storage + (64-((size_t)storage%64));
27995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	BN_ULONG	*a_inv = (BN_ULONG *)(table+16*8*8),
28095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley			*temp  = (BN_ULONG *)(table+16*8*8+8*8);
28195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	unsigned char	*p_str = (unsigned char*)exponent;
28295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	int index;
28395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	unsigned int wvalue;
28495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
28595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table[0] = 1_inv */
28695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	temp[0] = 0-m[0];	temp[1] = ~m[1];
28795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	temp[2] = ~m[2];	temp[3] = ~m[3];
28895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	temp[4] = ~m[4];	temp[5] = ~m[5];
28995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	temp[6] = ~m[6];	temp[7] = ~m[7];
29095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_scatter4(table, temp, 0);
29195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
29295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table [1] = a_inv^1 */
29395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_mul(a_inv, base, RR, m, k0);
29495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_scatter4(table, a_inv, 1);
29595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
29695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* table [2] = a_inv^2 */
29795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_sqr(temp, a_inv, m, k0, 1);
29895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_scatter4(table, temp, 2);
29995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
30095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	for (index=3; index<16; index++)
30195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index);
30295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
30395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* load first window */
30495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	wvalue = p_str[63];
30595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
30695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_gather4(temp, table, wvalue>>4);
30795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_sqr(temp, temp, m, k0, 4);
30895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0xf);
30995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
31095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	for (index=62; index>=0; index--) {
31195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		wvalue = p_str[index];
31295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
31395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_512_sqr(temp, temp, m, k0, 4);
31495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue>>4);
31595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
31695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_512_sqr(temp, temp, m, k0, 4);
31795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley		rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0x0f);
31895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	}
31995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
32095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	/* from Montgomery */
32195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	rsaz_512_mul_by_one(result, temp, m, k0);
32295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
32395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley	OPENSSL_cleanse(storage,sizeof(storage));
32495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
32523b460df0275d7b1543d3b5e0a33b1660a501ce9Adam Langley
32623b460df0275d7b1543d3b5e0a33b1660a501ce9Adam Langley#endif  /* OPENSSL_X86_64 */
327