/*
 * Copyright 2005-2019 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
 */

/**
 * The Whirlpool hashing function.
 *
 * See
 *      P.S.L.M. Barreto, V. Rijmen,
 *      ``The Whirlpool hashing function,''
 *      NESSIE submission, 2000 (tweaked version, 2001),
 *      <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip>
 *
 * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and
 * Vincent Rijmen. Lookup "reference implementations" on
 * <http://planeta.terra.com.br/informatica/paulobarreto/>
 *
 * =============================================================================
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 THE AUTHORS 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.
 *
 */

#include "wp_locl.h"
#include <string.h>

typedef unsigned char u8;
#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32)
typedef unsigned __int64 u64;
#elif defined(__arch64__)
typedef unsigned long u64;
#else
typedef unsigned long long u64;
#endif

#define ROUNDS  10

#define STRICT_ALIGNMENT
#if !defined(PEDANTIC) && (defined(__i386) || defined(__i386__) || \
                           defined(__x86_64) || defined(__x86_64__) || \
                           defined(_M_IX86) || defined(_M_AMD64) || \
                           defined(_M_X64))
/*
 * Well, formally there're couple of other architectures, which permit
 * unaligned loads, specifically those not crossing cache lines, IA-64 and
 * PowerPC...
 */
# undef STRICT_ALIGNMENT
#endif

#undef SMALL_REGISTER_BANK
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
# define SMALL_REGISTER_BANK
# if defined(WHIRLPOOL_ASM)
#  ifndef OPENSSL_SMALL_FOOTPRINT
/*
 * it appears that for elder non-MMX
 * CPUs this is actually faster!
 */
#   define OPENSSL_SMALL_FOOTPRINT
#  endif
#  define GO_FOR_MMX(ctx,inp,num)     do {                    \
        extern unsigned long OPENSSL_ia32cap_P[];               \
        void whirlpool_block_mmx(void *,const void *,size_t);   \
        if (!(OPENSSL_ia32cap_P[0] & (1<<23)))  break;          \
        whirlpool_block_mmx(ctx->H.c,inp,num);  return;         \
                                        } while (0)
# endif
#endif

#undef ROTATE
#ifndef PEDANTIC
# if defined(_MSC_VER)
#  if defined(_WIN64)            /* applies to both IA-64 and AMD64 */
#   include <stdlib.h>
#   pragma intrinsic(_rotl64)
#   define ROTATE(a,n) _rotl64((a),n)
#  endif
# elif defined(__GNUC__) && __GNUC__>=2
#  if defined(__x86_64) || defined(__x86_64__)
#   if defined(L_ENDIAN)
#    define ROTATE(a,n)       ({ u64 ret; asm ("rolq %1,%0"   \
                                   : "=r"(ret) : "J"(n),"0"(a) : "cc"); ret; })
#   elif defined(B_ENDIAN)
       /*
        * Most will argue that x86_64 is always little-endian. Well, yes, but
        * then we have stratus.com who has modified gcc to "emulate"
        * big-endian on x86. Is there evidence that they [or somebody else]
        * won't do same for x86_64? Naturally no. And this line is waiting
        * ready for that brave soul:-)
        */
#    define ROTATE(a,n)       ({ u64 ret; asm ("rorq %1,%0"   \
                                   : "=r"(ret) : "J"(n),"0"(a) : "cc"); ret; })
#   endif
#  elif defined(__ia64) || defined(__ia64__)
#   if defined(L_ENDIAN)
#    define ROTATE(a,n)       ({ u64 ret; asm ("shrp %0=%1,%1,%2"     \
                                   : "=r"(ret) : "r"(a),"M"(64-(n))); ret; })
#   elif defined(B_ENDIAN)
#    define ROTATE(a,n)       ({ u64 ret; asm ("shrp %0=%1,%1,%2"     \
                                   : "=r"(ret) : "r"(a),"M"(n)); ret; })
#   endif
#  endif
# endif
#endif

#if defined(OPENSSL_SMALL_FOOTPRINT)
# if !defined(ROTATE)
#  if defined(L_ENDIAN)         /* little-endians have to rotate left */
#   define ROTATE(i,n)       ((i)<<(n) ^ (i)>>(64-n))
#  elif defined(B_ENDIAN)       /* big-endians have to rotate right */
#   define ROTATE(i,n)       ((i)>>(n) ^ (i)<<(64-n))
#  endif
# endif
# if defined(ROTATE) && !defined(STRICT_ALIGNMENT)
#  define STRICT_ALIGNMENT      /* ensure smallest table size */
# endif
#endif

/*
 * Table size depends on STRICT_ALIGNMENT and whether or not endian-
 * specific ROTATE macro is defined. If STRICT_ALIGNMENT is not
 * defined, which is normally the case on x86[_64] CPUs, the table is
 * 4KB large unconditionally. Otherwise if ROTATE is defined, the
 * table is 2KB large, and otherwise - 16KB. 2KB table requires a
 * whole bunch of additional rotations, but I'm willing to "trade,"
 * because 16KB table certainly trashes L1 cache. I wish all CPUs
 * could handle unaligned load as 4KB table doesn't trash the cache,
 * nor does it require additional rotations.
 */
/*
 * Note that every Cn macro expands as two loads: one byte load and
 * one quadword load. One can argue that that many single-byte loads
 * is too excessive, as one could load a quadword and "milk" it for
 * eight 8-bit values instead. Well, yes, but in order to do so *and*
 * avoid excessive loads you have to accommodate a handful of 64-bit
 * values in the register bank and issue a bunch of shifts and mask.
 * It's a tradeoff: loads vs. shift and mask in big register bank[!].
 * On most CPUs eight single-byte loads are faster and I let other
 * ones to depend on smart compiler to fold byte loads if beneficial.
 * Hand-coded assembler would be another alternative:-)
 */
#ifdef STRICT_ALIGNMENT
# if defined(ROTATE)
#  define N   1
#  define LL(c0,c1,c2,c3,c4,c5,c6,c7) c0,c1,c2,c3,c4,c5,c6,c7
#  define C0(K,i)     (Cx.q[K.c[(i)*8+0]])
#  define C1(K,i)     ROTATE(Cx.q[K.c[(i)*8+1]],8)
#  define C2(K,i)     ROTATE(Cx.q[K.c[(i)*8+2]],16)
#  define C3(K,i)     ROTATE(Cx.q[K.c[(i)*8+3]],24)
#  define C4(K,i)     ROTATE(Cx.q[K.c[(i)*8+4]],32)
#  define C5(K,i)     ROTATE(Cx.q[K.c[(i)*8+5]],40)
#  define C6(K,i)     ROTATE(Cx.q[K.c[(i)*8+6]],48)
#  define C7(K,i)     ROTATE(Cx.q[K.c[(i)*8+7]],56)
# else
#  define N   8
#  define LL(c0,c1,c2,c3,c4,c5,c6,c7) c0,c1,c2,c3,c4,c5,c6,c7, \
                                        c7,c0,c1,c2,c3,c4,c5,c6, \
                                        c6,c7,c0,c1,c2,c3,c4,c5, \
                                        c5,c6,c7,c0,c1,c2,c3,c4, \
                                        c4,c5,c6,c7,c0,c1,c2,c3, \
                                       