/*************************************************************************
* Copyright (C) 2015 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.
//     Encrypt 128-bit data block according to Rijndael
//     (compact S-box based implementation)
//
//  Contents:
//     Safe2Encrypt_RIJ128()
//
//
*/

#include "owncp.h"

#if ((_IPP < _IPP_V8) && (_IPP32E < _IPP32E_U8)) /* no pshufb instruction */

#if (_ALG_AES_SAFE_ == _ALG_AES_SAFE_COMPACT_SBOX_)

#include "pcprij128safe.h"
#include "pcprij128safe2.h"
#include "pcprijtables.h"

IPPCP_INLINE void SubBytes(Ipp8u state[])
{
    int i;
    for (i = 0; i < 16; i++) {
        state[i] = getSboxValue(state[i]);
    }
}


IPPCP_INLINE void ShiftRows(Ipp32u* state)
{
    state[1] = ROR32(state[1], 8);
    state[2] = ROR32(state[2], 16);
    state[3] = ROR32(state[3], 24);
}

// MixColumns4 function mixes the columns of the state matrix
IPPCP_INLINE void MixColumns(Ipp32u* state)
{
    Ipp32u y0 = state[1] ^ state[2] ^ state[3];
    Ipp32u y1 = state[0] ^ state[2] ^ state[3];
    Ipp32u y2 = state[0] ^ state[1] ^ state[3];
    Ipp32u y3 = state[0] ^ state[1] ^ state[2];

    state[0] = xtime4(state[0]);
    state[1] = xtime4(state[1]);
    state[2] = xtime4(state[2]);
    state[3] = xtime4(state[3]);

    y0 ^= state[0] ^ state[1];
    y1 ^= state[1] ^ state[2];
    y2 ^= state[2] ^ state[3];
    y3 ^= state[3] ^ state[0];

    state[0] = y0;
    state[1] = y1;
    state[2] = y2;
    state[3] = y3;
}

/* clang-format off */
IPP_OWN_DEFN(void, Safe2Encrypt_RIJ128, (const Ipp8u* in,
                                         Ipp8u* out,
                                         int Nr,
                                         const Ipp8u* RoundKey,
                                         const void* sbox))
/* clang-format on */
{
    Ipp32u state[4];

    int round = 0;

    IPP_UNREFERENCED_PARAMETER(sbox);

    // copy input to the state array
    TRANSPOSE((Ipp8u*)state, in);

    // add round key to the state before starting the rounds.
    XorRoundKey(state, (Ipp32u*)(RoundKey + 0 * 16));

    // there will be Nr rounds
    for (round = 1; round < Nr; round++) {
        SubBytes((Ipp8u*)state);
        ShiftRows(state);
        MixColumns(state);
        XorRoundKey(state, (Ipp32u*)(RoundKey + round * 16));
    }

    // last round
    SubBytes((Ipp8u*)state);
    ShiftRows(state);
    XorRoundKey(state, (Ipp32u*)(RoundKey + Nr * 16));

    // copy from the state to output
    TRANSPOSE(out, (Ipp8u*)state);
}
#endif /* _ALG_AES_SAFE_COMPACT_SBOX_ */

#endif /* (_IPP <_IPP_V8) && (_IPP32E <_IPP32E_U8) */
