/*************************************************************************
* Copyright (C) 2014 Intel Corporation
*
* Licensed under the Apache License,  Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 	http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law  or agreed  to  in  writing,  software
* distributed under  the License  is  distributed  on  an  "AS IS"  BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the  specific  language  governing  permissions  and
* limitations under the License.
*************************************************************************/

/*
//
//  Purpose:
//     Cryptography Primitive.
//     SMS4 ECB encryption/decryption
//
//  Contents:
//     cpSMS4_ECB_aesni_x4()
//     cpSMS4_ECB_aesni_x8()
//     cpSMS4_ECB_aesni_x12()
//
//
*/

#include "owndefs.h"
#include "owncp.h"
#include "sms4/pcpsms4.h"
#include "pcptool.h"

#if (_IPP >= _IPP_P8) || (_IPP32E >= _IPP32E_Y8)

#include "sms4/pcpsms4_y8cn.h"

/*
// (1-3)*MBS_SMS4 processing
*/

static int cpSMS4_ECB_aesni_tail(Ipp8u* pOut, const Ipp8u* pInp, int len, const Ipp32u* pRKey)
{
    __ALIGN16 __m128i TMP[6];
    /*
      TMP[0] = T
      TMP[1] = K0
      TMP[2] = K1
      TMP[3] = K2
      TMP[4] = K3
      TMP[5] = key4
   */

    TMP[2] = _mm_setzero_si128();
    TMP[3] = _mm_setzero_si128();
    TMP[4] = _mm_setzero_si128();

    switch (len) {
    case (3 * MBS_SMS4):
        TMP[3] =
            _mm_shuffle_epi8(_mm_loadu_si128((__m128i*)(pInp + 2 * MBS_SMS4)), M128(swapBytes));
        IPPCP_FALLTHROUGH;
    case (2 * MBS_SMS4):
        TMP[2] =
            _mm_shuffle_epi8(_mm_loadu_si128((__m128i*)(pInp + 1 * MBS_SMS4)), M128(swapBytes));
        IPPCP_FALLTHROUGH;
    case (1 * MBS_SMS4):
        TMP[1] =
            _mm_shuffle_epi8(_mm_loadu_si128((__m128i*)(pInp + 0 * MBS_SMS4)), M128(swapBytes));
        break;
    default:
        return 0;
    }
    TRANSPOSE_INP(TMP[1], TMP[2], TMP[3], TMP[4], TMP[0]);

    {
        int itr;
        for (itr = 0; itr < 8; itr++, pRKey += 4) {
            TMP[5] = _mm_loadu_si128((__m128i*)pRKey);

            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(TMP[5], 0x00); /* broadcast(key4 TMP[0]) */
            TMP[0] = _mm_xor_si128(TMP[0], TMP[2]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[1] = _mm_xor_si128(_mm_xor_si128(TMP[1], TMP[0]), L(TMP[0]));

            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(TMP[5], 0x55); /* broadcast(key4 TMP[1]) */
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[1]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[2] = _mm_xor_si128(_mm_xor_si128(TMP[2], TMP[0]), L(TMP[0]));

            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(TMP[5], 0xAA); /* broadcast(key4 TMP[2]) */
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[1]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[2]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[3] = _mm_xor_si128(_mm_xor_si128(TMP[3], TMP[0]), L(TMP[0]));

            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(TMP[5], 0xFF); /* broadcast(key4 TMP[3]) */
            TMP[0] = _mm_xor_si128(TMP[0], TMP[1]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[2]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[4] = _mm_xor_si128(_mm_xor_si128(TMP[4], TMP[0]), L(TMP[0]));
        }
    }

    TRANSPOSE_OUT(TMP[1], TMP[2], TMP[3], TMP[4], TMP[0]);
    TMP[4] = _mm_shuffle_epi8(TMP[4], M128(swapBytes));
    TMP[3] = _mm_shuffle_epi8(TMP[3], M128(swapBytes));
    TMP[2] = _mm_shuffle_epi8(TMP[2], M128(swapBytes));
    TMP[1] = _mm_shuffle_epi8(TMP[1], M128(swapBytes));

    switch (len) {
    case (3 * MBS_SMS4):
        _mm_storeu_si128((__m128i*)(pOut + 2 * MBS_SMS4), TMP[2]);
        IPPCP_FALLTHROUGH;
    case (2 * MBS_SMS4):
        _mm_storeu_si128((__m128i*)(pOut + 1 * MBS_SMS4), TMP[3]);
        IPPCP_FALLTHROUGH;
    case (1 * MBS_SMS4):
        _mm_storeu_si128((__m128i*)(pOut + 0 * MBS_SMS4), TMP[4]);
        break;
    }

    /* clear secret data */
    PurgeBlock(TMP, sizeof(TMP));

    return len;
}

/*
// 4*MBS_SMS4 processing
*/
static int cpSMS4_ECB_aesni_x4(Ipp8u* pOut, const Ipp8u* pInp, int len, const Ipp32u* pRKey)
{
    __ALIGN16 __m128i TMP[5];
    /*
      TMP[0] = T
      TMP[1] = K0
      TMP[2] = K1
      TMP[3] = K2
      TMP[4] = K3
   */
    int processedLen = len & -(4 * MBS_SMS4);
    int n;
    for (n = 0; n < processedLen;
         n += (4 * MBS_SMS4), pInp += (4 * MBS_SMS4), pOut += (4 * MBS_SMS4)) {
        int itr;
        TMP[1] = _mm_loadu_si128((__m128i*)(pInp));
        TMP[2] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4));
        TMP[3] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 2));
        TMP[4] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 3));
        TMP[1] = _mm_shuffle_epi8(TMP[1], M128(swapBytes));
        TMP[2] = _mm_shuffle_epi8(TMP[2], M128(swapBytes));
        TMP[3] = _mm_shuffle_epi8(TMP[3], M128(swapBytes));
        TMP[4] = _mm_shuffle_epi8(TMP[4], M128(swapBytes));
        TRANSPOSE_INP(TMP[1], TMP[2], TMP[3], TMP[4], TMP[0]);

        for (itr = 0; itr < 8; itr++, pRKey += 4) {
            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[0]), 0);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[2]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[1] = _mm_xor_si128(_mm_xor_si128(TMP[1], TMP[0]), L(TMP[0]));

            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[1]), 0);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[1]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[2] = _mm_xor_si128(_mm_xor_si128(TMP[2], TMP[0]), L(TMP[0]));

            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[2]), 0);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[1]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[2]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[3] = _mm_xor_si128(_mm_xor_si128(TMP[3], TMP[0]), L(TMP[0]));

            /* initial xors */
            TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[3]), 0);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[1]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[2]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            /* Sbox done, now L */
            TMP[4] = _mm_xor_si128(_mm_xor_si128(TMP[4], TMP[0]), L(TMP[0]));
        }

        pRKey -= 32;

        TRANSPOSE_OUT(TMP[1], TMP[2], TMP[3], TMP[4], TMP[0]);
        TMP[4] = _mm_shuffle_epi8(TMP[4], M128(swapBytes));
        TMP[3] = _mm_shuffle_epi8(TMP[3], M128(swapBytes));
        TMP[2] = _mm_shuffle_epi8(TMP[2], M128(swapBytes));
        TMP[1] = _mm_shuffle_epi8(TMP[1], M128(swapBytes));
        _mm_storeu_si128((__m128i*)(pOut), TMP[4]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4), TMP[3]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 2), TMP[2]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 3), TMP[1]);
    }

    len -= processedLen;
    if (len)
        processedLen += cpSMS4_ECB_aesni_tail(pOut, pInp, len, pRKey);

    /* clear secret data */
    PurgeBlock(TMP, sizeof(TMP));

    return processedLen;
}

/*
// 8*MBS_SMS4 processing
*/
static int cpSMS4_ECB_aesni_x8(Ipp8u* pOut, const Ipp8u* pInp, int len, const Ipp32u* pRKey)
{
    __ALIGN16 __m128i TMP[10];
    /*
      TMP[0] = T
      TMP[1] = U
      TMP[2] = K0
      TMP[3] = K1
      TMP[4] = K2
      TMP[5] = K3
      TMP[6] = P0
      TMP[7] = P1
      TMP[8] = P2
      TMP[9] = P3
   */

    int processedLen = len & -(8 * MBS_SMS4);
    int n;
    for (n = 0; n < processedLen;
         n += (8 * MBS_SMS4), pInp += (8 * MBS_SMS4), pOut += (8 * MBS_SMS4)) {
        int itr;
        TMP[2] = _mm_loadu_si128((__m128i*)(pInp));
        TMP[3] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4));
        TMP[4] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 2));
        TMP[5] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 3));

        TMP[6] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 4));
        TMP[7] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 5));
        TMP[8] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 6));
        TMP[9] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 7));

        TMP[2] = _mm_shuffle_epi8(TMP[2], M128(swapBytes));
        TMP[3] = _mm_shuffle_epi8(TMP[3], M128(swapBytes));
        TMP[4] = _mm_shuffle_epi8(TMP[4], M128(swapBytes));
        TMP[5] = _mm_shuffle_epi8(TMP[5], M128(swapBytes));
        TRANSPOSE_INP(TMP[2], TMP[3], TMP[4], TMP[5], TMP[0]);

        TMP[6] = _mm_shuffle_epi8(TMP[6], M128(swapBytes));
        TMP[7] = _mm_shuffle_epi8(TMP[7], M128(swapBytes));
        TMP[8] = _mm_shuffle_epi8(TMP[8], M128(swapBytes));
        TMP[9] = _mm_shuffle_epi8(TMP[9], M128(swapBytes));
        TRANSPOSE_INP(TMP[6], TMP[7], TMP[8], TMP[9], TMP[0]);

        for (itr = 0; itr < 8; itr++, pRKey += 4) {
            /* initial xors */
            TMP[1] = TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[0]), 0);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[5]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[7]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[8]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[9]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            /* Sbox done, now L */
            TMP[2] = _mm_xor_si128(_mm_xor_si128(TMP[2], TMP[0]), L(TMP[0]));
            TMP[6] = _mm_xor_si128(_mm_xor_si128(TMP[6], TMP[1]), L(TMP[1]));

            /* initial xors */
            TMP[1] = TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[1]), 0);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[5]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[2]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[8]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[9]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[6]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            /* Sbox done, now L */
            TMP[3] = _mm_xor_si128(_mm_xor_si128(TMP[3], TMP[0]), L(TMP[0]));
            TMP[7] = _mm_xor_si128(_mm_xor_si128(TMP[7], TMP[1]), L(TMP[1]));

            /* initial xors */
            TMP[1] = TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[2]), 0);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[5]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[2]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[9]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[6]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[7]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            /* Sbox done, now L */
            TMP[4] = _mm_xor_si128(_mm_xor_si128(TMP[4], TMP[0]), L(TMP[0]));
            TMP[8] = _mm_xor_si128(_mm_xor_si128(TMP[8], TMP[1]), L(TMP[1]));

            /* initial xors */
            TMP[1] = TMP[0] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[3]), 0);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[2]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0]          = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[6]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[7]);
            TMP[1]          = _mm_xor_si128(TMP[1], TMP[8]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            /* Sbox done, now L */
            TMP[5] = _mm_xor_si128(_mm_xor_si128(TMP[5], TMP[0]), L(TMP[0]));
            TMP[9] = _mm_xor_si128(_mm_xor_si128(TMP[9], TMP[1]), L(TMP[1]));
        }

        pRKey -= 32;

        TRANSPOSE_OUT(TMP[2], TMP[3], TMP[4], TMP[5], TMP[0]);
        TMP[5] = _mm_shuffle_epi8(TMP[5], M128(swapBytes));
        TMP[4] = _mm_shuffle_epi8(TMP[4], M128(swapBytes));
        TMP[3] = _mm_shuffle_epi8(TMP[3], M128(swapBytes));
        TMP[2] = _mm_shuffle_epi8(TMP[2], M128(swapBytes));
        _mm_storeu_si128((__m128i*)(pOut), TMP[5]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4), TMP[4]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 2), TMP[3]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 3), TMP[2]);

        TRANSPOSE_OUT(TMP[6], TMP[7], TMP[8], TMP[9], TMP[0]);
        TMP[9] = _mm_shuffle_epi8(TMP[9], M128(swapBytes));
        TMP[8] = _mm_shuffle_epi8(TMP[8], M128(swapBytes));
        TMP[7] = _mm_shuffle_epi8(TMP[7], M128(swapBytes));
        TMP[6] = _mm_shuffle_epi8(TMP[6], M128(swapBytes));
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 4), TMP[9]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 5), TMP[8]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 6), TMP[7]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 7), TMP[6]);
    }


    len -= processedLen;
    if (len)
        processedLen += cpSMS4_ECB_aesni_x4(pOut, pInp, len, pRKey);

    /* clear secret data */
    PurgeBlock(TMP, sizeof(TMP));

    return processedLen;
}

/*
// 12*MBS_SMS4 processing
*/
#if (_IPP >= _IPP_H9) || (_IPP32E >= _IPP32E_L9)
#define cpSMS4_ECB_aesni_x12 OWNAPI(cpSMS4_ECB_aesni_x12)
/* clang-format off */
IPP_OWN_DECL(int, cpSMS4_ECB_aesni_x12, (Ipp8u* pOut,
                                         const Ipp8u* pInp,
                                         int len,
                                         const Ipp32u* pRKey))
IPP_OWN_DEFN(int, cpSMS4_ECB_aesni_x12, (Ipp8u* pOut,
                                         const Ipp8u* pInp,
                                         int len,
                                         const Ipp32u* pRKey))
/* clang-format on */
#else
#define cpSMS4_ECB_aesni OWNAPI(cpSMS4_ECB_aesni)
IPP_OWN_DECL(int, cpSMS4_ECB_aesni, (Ipp8u * pOut, const Ipp8u* pInp, int len, const Ipp32u* pRKey))
IPP_OWN_DEFN(int, cpSMS4_ECB_aesni, (Ipp8u * pOut, const Ipp8u* pInp, int len, const Ipp32u* pRKey))
#endif
{
    __ALIGN16 __m128i TMP[15];
    /*
      TMP[ 0] = T
      TMP[ 1] = U
      TMP[ 2] = V
      TMP[ 3] = K0
      TMP[ 4] = K1
      TMP[ 5] = K2
      TMP[ 6] = K3
      TMP[ 7] = P0
      TMP[ 8] = P1
      TMP[ 9] = P2
      TMP[10] = P3
      TMP[11] = Q0
      TMP[12] = Q1
      TMP[13] = Q2
      TMP[14] = Q3
   */

    int processedLen = len - (len % (12 * MBS_SMS4));
    int n;
    for (n = 0; n < processedLen;
         n += (12 * MBS_SMS4), pInp += (12 * MBS_SMS4), pOut += (12 * MBS_SMS4)) {
        int itr;

        TMP[3] = _mm_loadu_si128((__m128i*)(pInp));
        TMP[4] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4));
        TMP[5] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 2));
        TMP[6] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 3));

        TMP[7]  = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 4));
        TMP[8]  = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 5));
        TMP[9]  = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 6));
        TMP[10] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 7));

        TMP[11] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 8));
        TMP[12] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 9));
        TMP[13] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 10));
        TMP[14] = _mm_loadu_si128((__m128i*)(pInp + MBS_SMS4 * 11));

        TMP[3] = _mm_shuffle_epi8(TMP[3], M128(swapBytes));
        TMP[4] = _mm_shuffle_epi8(TMP[4], M128(swapBytes));
        TMP[5] = _mm_shuffle_epi8(TMP[5], M128(swapBytes));
        TMP[6] = _mm_shuffle_epi8(TMP[6], M128(swapBytes));
        TRANSPOSE_INP(TMP[3], TMP[4], TMP[5], TMP[6], TMP[0]);

        TMP[7]  = _mm_shuffle_epi8(TMP[7], M128(swapBytes));
        TMP[8]  = _mm_shuffle_epi8(TMP[8], M128(swapBytes));
        TMP[9]  = _mm_shuffle_epi8(TMP[9], M128(swapBytes));
        TMP[10] = _mm_shuffle_epi8(TMP[10], M128(swapBytes));
        TRANSPOSE_INP(TMP[7], TMP[8], TMP[9], TMP[10], TMP[0]);

        TMP[11] = _mm_shuffle_epi8(TMP[11], M128(swapBytes));
        TMP[12] = _mm_shuffle_epi8(TMP[12], M128(swapBytes));
        TMP[13] = _mm_shuffle_epi8(TMP[13], M128(swapBytes));
        TMP[14] = _mm_shuffle_epi8(TMP[14], M128(swapBytes));
        TRANSPOSE_INP(TMP[11], TMP[12], TMP[13], TMP[14], TMP[0]);

        for (itr = 0; itr < 8; itr++, pRKey += 4) {
            /* initial xors */
            TMP[1] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[0]), 0);
            TMP[2] = TMP[1];
            TMP[0] = TMP[1];
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[5]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[6]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[8]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[9]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[10]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[12]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[13]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[14]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            TMP[2] = sBox(TMP[2]);
            /* Sbox done, now L */
            TMP[3]  = _mm_xor_si128(_mm_xor_si128(TMP[3], TMP[0]), L(TMP[0]));
            TMP[7]  = _mm_xor_si128(_mm_xor_si128(TMP[7], TMP[1]), L(TMP[1]));
            TMP[11] = _mm_xor_si128(_mm_xor_si128(TMP[11], TMP[2]), L(TMP[2]));

            /* initial xors */
            TMP[1] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[1]), 0);
            TMP[2] = TMP[1];
            TMP[0] = TMP[1];
            TMP[0] = _mm_xor_si128(TMP[0], TMP[5]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[6]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[9]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[10]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[7]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[13]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[14]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[11]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            TMP[2] = sBox(TMP[2]);
            /* Sbox done, now L */
            TMP[4]  = _mm_xor_si128(_mm_xor_si128(TMP[4], TMP[0]), L(TMP[0]));
            TMP[8]  = _mm_xor_si128(_mm_xor_si128(TMP[8], TMP[1]), L(TMP[1]));
            TMP[12] = _mm_xor_si128(_mm_xor_si128(TMP[12], TMP[2]), L(TMP[2]));

            /* initial xors */
            TMP[1] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[2]), 0);
            TMP[2] = TMP[1];
            TMP[0] = TMP[1];
            TMP[0] = _mm_xor_si128(TMP[0], TMP[6]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[10]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[7]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[8]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[14]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[11]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[12]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            TMP[2] = sBox(TMP[2]);
            /* Sbox done, now L */
            TMP[5]  = _mm_xor_si128(_mm_xor_si128(TMP[5], TMP[0]), L(TMP[0]));
            TMP[9]  = _mm_xor_si128(_mm_xor_si128(TMP[9], TMP[1]), L(TMP[1]));
            TMP[13] = _mm_xor_si128(_mm_xor_si128(TMP[13], TMP[2]), L(TMP[2]));

            /* initial xors */
            TMP[1] = _mm_shuffle_epi32(_mm_cvtsi32_si128((Ipp32s)pRKey[3]), 0);
            TMP[2] = TMP[1];
            TMP[0] = TMP[1];
            TMP[0] = _mm_xor_si128(TMP[0], TMP[3]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[4]);
            TMP[0] = _mm_xor_si128(TMP[0], TMP[5]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[7]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[8]);
            TMP[1] = _mm_xor_si128(TMP[1], TMP[9]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[11]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[12]);
            TMP[2] = _mm_xor_si128(TMP[2], TMP[13]);
            /* Sbox */
            TMP[0] = sBox(TMP[0]);
            TMP[1] = sBox(TMP[1]);
            TMP[2] = sBox(TMP[2]);
            /* Sbox done, now L */
            TMP[6]  = _mm_xor_si128(_mm_xor_si128(TMP[6], TMP[0]), L(TMP[0]));
            TMP[10] = _mm_xor_si128(_mm_xor_si128(TMP[10], TMP[1]), L(TMP[1]));
            TMP[14] = _mm_xor_si128(_mm_xor_si128(TMP[14], TMP[2]), L(TMP[2]));
        }

        pRKey -= 32;

        TRANSPOSE_OUT(TMP[3], TMP[4], TMP[5], TMP[6], TMP[0]);
        TMP[6] = _mm_shuffle_epi8(TMP[6], M128(swapBytes));
        TMP[5] = _mm_shuffle_epi8(TMP[5], M128(swapBytes));
        TMP[4] = _mm_shuffle_epi8(TMP[4], M128(swapBytes));
        TMP[3] = _mm_shuffle_epi8(TMP[3], M128(swapBytes));
        _mm_storeu_si128((__m128i*)(pOut), TMP[6]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4), TMP[5]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 2), TMP[4]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 3), TMP[3]);

        TRANSPOSE_OUT(TMP[7], TMP[8], TMP[9], TMP[10], TMP[0]);
        TMP[10] = _mm_shuffle_epi8(TMP[10], M128(swapBytes));
        TMP[9]  = _mm_shuffle_epi8(TMP[9], M128(swapBytes));
        TMP[8]  = _mm_shuffle_epi8(TMP[8], M128(swapBytes));
        TMP[7]  = _mm_shuffle_epi8(TMP[7], M128(swapBytes));
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 4), TMP[10]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 5), TMP[9]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 6), TMP[8]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 7), TMP[7]);

        TRANSPOSE_OUT(TMP[11], TMP[12], TMP[13], TMP[14], TMP[0]);
        TMP[14] = _mm_shuffle_epi8(TMP[14], M128(swapBytes));
        TMP[13] = _mm_shuffle_epi8(TMP[13], M128(swapBytes));
        TMP[12] = _mm_shuffle_epi8(TMP[12], M128(swapBytes));
        TMP[11] = _mm_shuffle_epi8(TMP[11], M128(swapBytes));
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 8), TMP[14]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 9), TMP[13]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 10), TMP[12]);
        _mm_storeu_si128((__m128i*)(pOut + MBS_SMS4 * 11), TMP[11]);
    }

    len -= processedLen;
    if (len)
        processedLen += cpSMS4_ECB_aesni_x8(pOut, pInp, len, pRKey);

    /* clear secret data */
    PurgeBlock(TMP, sizeof(TMP));

    return processedLen;
}

#endif /* _IPP_P8, _IPP32E_Y8 */
