/*
 * Copyright (C) 2021 Southern Storm Software, Pty Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#ifndef LW_INTERNAL_PHOTON256_MIX_H
#define LW_INTERNAL_PHOTON256_MIX_H

/**
 * \file internal-photon256-mix.h
 * \brief Macros to help mixing the columns in the PHOTON-256 permutation.
 */

#ifdef __cplusplus
extern "C" {
#endif

/** @cond photon256_mix_columns */

/* These macros were generated by a script to produce the minimum number
 * of XOR's and rotations necessary to mix each vector together */

#define MIXL0(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x02, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) = s; \
        /* MIX(0x04, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x02, s2) */ \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0b, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXR0(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x02, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x08, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x05, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x06, s3) */ \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXL1(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x0c, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) = s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x09, s1) */ \
        (out) ^= (s1); \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x08, s2) */ \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0d, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXR1(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x07, s0) */ \
        (out) ^= (s0); \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x07, s1) */ \
        (out) ^= (s1); \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x05, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x02, s3) */ \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXL2(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x04, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) = s; \
        /* MIX(0x04, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0d, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0d, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXR2(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x09, s0) */ \
        (out) ^= (s0); \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x04, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0d, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x09, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXL3(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x01, s0) */ \
        (out) = (s0); \
        /* MIX(0x06, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x05, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x01, s3) */ \
        (out) ^= (s3); \
    } while (0)

#define MIXR3(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x0c, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0d, s1) */ \
        (out) ^= (s1); \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0f, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0e, s3) */ \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXL4(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x0f, s0) */ \
        (out) = (s0); \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0c, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x09, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0d, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXR4(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x0e, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x05, s1) */ \
        (out) ^= (s1); \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0e, s2) */ \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0d, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXL5(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x09, s0) */ \
        (out) = (s0); \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0e, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x05, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0f, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXR5(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x04, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0c, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x09, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x06, s3) */ \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXL6(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x0c, s0) */ \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) = s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x02, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x02, s2) */ \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0a, s3) */ \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXR6(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x03, s0) */ \
        (out) ^= (s0); \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x01, s1) */ \
        (out) ^= (s1); \
        /* MIX(0x01, s2) */ \
        (out) ^= (s2); \
        /* MIX(0x0e, s3) */ \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXL7(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x0f, s0) */ \
        (out) = (s0); \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x01, s1) */ \
        (out) ^= (s1); \
        /* MIX(0x0d, s2) */ \
        (out) ^= (s2); \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0a, s3) */ \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

#define MIXR7(out, s0, s1, s2, s3) \
    do { \
        uint32_t s, t; \
        /* MIX(0x05, s0) */ \
        (out) ^= (s0); \
        s = (s0); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x0a, s1) */ \
        s = (s1); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x02, s2) */ \
        s = (s2); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
        /* MIX(0x03, s3) */ \
        (out) ^= (s3); \
        s = (s3); \
        t = s >> 24; \
        s = (s << 8) ^ t ^ (t << 8); \
        (out) ^= s; \
    } while (0)

/** @endcond */

#ifdef __cplusplus
}
#endif

#endif
