/*
 ---------------------------------------------------------------------------
 Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.

 LICENSE TERMS

 The redistribution and use of this software (with or without changes)
 is allowed without the payment of fees or royalties provided that:

  1. source code distributions include the above copyright notice, this
     list of conditions and the following disclaimer;

  2. binary distributions include the above copyright notice, this list
     of conditions and the following disclaimer in their documentation;

  3. the name of the copyright holder is not used to endorse products
     built using this software without specific written permission.

 DISCLAIMER

 This software is provided 'as is' with no explicit or implied warranties
 in respect of its properties, including, but not limited to, correctness
 and/or fitness for purpose.
 ---------------------------------------------------------------------------
 Issue Date: 20/12/2007

 This file provides fast multiplication in GF(128) as required by several
 cryptographic authentication modes (see gfmul128.h).
*/

/*  Speed critical loops can be unrolled to gain speed but consume more memory */
#if 1
#  define UNROLL_LOOPS
#endif

#if defined( INC_ALL )		/* pcg */
  #include "gf128mul.h"
  #include "mode_hdr.h"
  #include "gf_mul_lo.h"
#else
  #include "crypt/gf128mul.h"
  #include "crypt/mode_hdr.h"
  #include "crypt/gf_mul_lo.h"
#endif /* Compiler-specific includes */

#if defined( GF_MODE_LL )
#  define mode   _ll
#elif defined( GF_MODE_BL )
#  define mode   _bl
#elif defined( GF_MODE_LB )
#  define mode   _lb
#elif defined( GF_MODE_BB )
#  define mode   _bb
#else
#  error mode is not defined
#endif

#if defined( GF_MODE_LL) || defined( GF_MODE_LB )
#  define GF_INDEX(i)  (i)
#else
#  define GF_INDEX(i)  (15 - (i))
#endif

/* A slow field multiplier */

void gf_mul(gf_t a, const gf_t b)
{   gf_t p[8];
    uint_8t *q, ch;
    int i;

    copy_block_aligned(p[0], a);
    for(i = 0; i < 7; ++i)
        gf_mulx1(mode)(p[i + 1], p[i]);

    q = (uint_8t*)(a == b ? p[0] : b);
    memset(a, 0, GF_BYTE_LEN);
    for(i = 15 ;  ; )
    {
        ch = q[GF_INDEX(i)];
        if(ch & X_0)
            xor_block_aligned(a, a, p[0]);
        if(ch & X_1)
            xor_block_aligned(a, a, p[1]);
        if(ch & X_2)
            xor_block_aligned(a, a, p[2]);
        if(ch & X_3)
            xor_block_aligned(a, a, p[3]);
        if(ch & X_4)
            xor_block_aligned(a, a, p[4]);
        if(ch & X_5)
            xor_block_aligned(a, a, p[5]);
        if(ch & X_6)
            xor_block_aligned(a, a, p[6]);
        if(ch & X_7)
            xor_block_aligned(a, a, p[7]);
        if(!i--)
            break;
        gf_mulx8(mode)(a);
    }
}

#if defined( TABLES_64K )

/*  This version uses 64k bytes of table space on the stack.
    An input variable field value in a[] has to be multiplied
    by a key value in g[] that changes far less frequently.

    To do this a[] is split up into 16 smaller field values,
    each one byte in length. For the 256 values of each of
    these smaller values, we can precompute the result of
    mulltiplying g by this field value. We can then combine
    these values to provide the full multiply. So for each
    of 16 bytes we have a table of 256 field values each of
    16 bytes - 64k bytes in total.
*/

void init_64k_table(const gf_t g, gf_t64k_t t)
{   int i = 0, j, k;

    /*
    depending on the representation we have to process bits
    within bytes high to low (0xe1 style ) or low to high
    (0x87 style).  We start by producing the powers x ,x^2
    .. x^7 and put them in t[0][1], t[0][2] .. t[128] or in
    t[128], t[64] .. t[1] depending on the bit order in use.
    */

    /* clear the element for the zero field element */
    memset(t[0][0], 0, GF_BYTE_LEN);

#if defined( GF_MODE_LL ) || defined( GF_MODE_BL )

    /* g -> t[0][1], generate t[0][2] ...           */
    memcpy(t[0][1], g, GF_BYTE_LEN);
    for(j = 1; j <= 64; j <<= 1)
        gf_mulx1(mode)(t[0][j + j], t[0][j]);
#else

    /* g -> t[0][128], generate t[0][64] ...        */
    memcpy(t[0][128], g, GF_BYTE_LEN);
    for(j = 64; j >= 1; j >>= 1)
        gf_mulx1(mode)(t[0][j], t[0][j + j]);
#endif

    for( ; ; )
    {
        /*  if { n } stands for the field value represented by
            the integer n, we can express higher multiplies in
            the table as follows:

                1. g * { 3} = g * {2} ^ g * {1}

                2. g * { 5} = g * {4} ^ g * {1}
                   g * { 6} = g * {4} ^ g * {2}
                   g * { 7} = g * {4} ^ g * {3}

                3. g * { 9} = g * {8} ^ g * {1}
                   g * {10} = g * {8} ^ g * {2}
                   ....

           and so on.  This is what the following loops do.
        */
        for(j = 2; j < 256; j += j)
            for(k = 1; k < j; ++k)
                xor_block_aligned(t[i][j + k], t[i][j], t[i][k]);

        if(++i == GF_BYTE_LEN)  /* all 16 byte positions done */
            return;

        /*  We now move to the next byte up and set up its eight
            starting values by multiplying the values in the
            lower table by x^8
        */
        memset(t[i][0], 0, GF_BYTE_LEN);
        for(j = 128; j > 0; j >>= 1)
        {
            memcpy(t[i][j], t[i - 1][j], GF_BYTE_LEN);
            gf_mulx8(mode)(t[i][j]);
        }
    }
}

#define xor_64k(i,ap,t,r) xor_block_aligned(r, r, t[i][ap[GF_INDEX(i)]])

#if defined( UNROLL_LOOPS )

void gf_mul_64k(gf_t a, const  gf_t64k_t t, gf_t r)
{   uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    xor_64k(15, ap, t, r); xor_64k(14, ap, t, r);
    xor_64k(13, ap, t, r); xor_64k(12, ap, t, r);
    xor_64k(11, ap, t, r); xor_64k(10, ap, t, r);
    xor_64k( 9, ap, t, r); xor_64k( 8, ap, t, r);
    xor_64k( 7, ap, t, r); xor_64k( 6, ap, t, r);
    xor_64k( 5, ap, t, r); xor_64k( 4, ap, t, r);
    xor_64k( 3, ap, t, r); xor_64k( 2, ap, t, r);
    xor_64k( 1, ap, t, r); xor_64k( 0, ap, t, r);
    copy_block_aligned(a, r);
}

#else

void gf_mul_64k(gf_t a, const  gf_t64k_t t, gf_t r)
{   int i;
    uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    for(i = 15; i >= 0; --i)
    {
        xor_64k(i,ap,t,r);
    }
    copy_block_aligned(a, r);
}

#endif

#endif

#if defined( TABLES_8K )

/*  This version uses 8k bytes of table space on the stack.
    An input field value in a[] has to be multiplied by a
    key value in g[]. To do this a[] is split up into 32
    smaller field values each 4-bits in length. For the
    16 values of each of these smaller field values we can
    precompute the result of mulltiplying g[] by the field
    value in question. So for each of 32 nibbles we have a
    table of 16 field values, each of 16 bytes - 8k bytes
    in total.
*/
void init_8k_table(const gf_t g, gf_t8k_t t)
{   int i = 0, j, k;

    /*  do the low 4-bit nibble first - t[0][16] - and note
        that the unit multiplier sits at 0x01 - t[0][1] in
        the table. Then multiplies by x go at 2, 4, 8
    */
    /* set the table elements for a zero multiplier */
    memset(t[0][0], 0, GF_BYTE_LEN);
    memset(t[1][0], 0, GF_BYTE_LEN);

#if defined( GF_MODE_LL ) || defined( GF_MODE_BL )

    /* t[0][1] = g, compute t[0][2], t[0][4], t[0][8]   */
    memcpy(t[0][1], g, GF_BYTE_LEN);
    for(j = 1; j <= 4; j <<= 1)
        gf_mulx1(mode)(t[0][j + j], t[0][j]);
    /* t[1][1] = t[0][1] * x^4 = t[0][8] * x            */
    gf_mulx1(mode)(t[1][1], t[0][8]);
    for(j = 1; j <= 4; j <<= 1)
        gf_mulx1(mode)(t[1][j + j], t[1][j]);
#else

    /* g -> t[0][8], compute t[0][4], t[0][2], t[0][1]  */
    memcpy(t[1][8], g, GF_BYTE_LEN);
    for(j = 4; j >= 1; j >>= 1)
        gf_mulx1(mode)(t[1][j], t[1][j + j]);
    /* t[1][1] = t[0][1] * x^4 = t[0][8] * x            */
    gf_mulx1(mode)(t[0][8], t[1][1]);
    for(j = 4; j >= 1; j >>= 1)
        gf_mulx1(mode)(t[0][j], t[0][j + j]);
#endif

    for( ; ; )
    {
        for(j = 2; j < 16; j += j)
            for(k = 1; k < j; ++k)
                xor_block_aligned(t[i][j + k], t[i][j], t[i][k]);

        if(++i == 2 * GF_BYTE_LEN)
            return;

        if(i > 1)
        {
            memset(t[i][0], 0, GF_BYTE_LEN);
            for(j = 8; j > 0; j >>= 1)
            {
                memcpy(t[i][j], t[i - 2][j], GF_BYTE_LEN);
                gf_mulx8(mode)(t[i][j]);
            }
        }

    }
}

#define xor_8k(i,ap,t,r)   \
    xor_block_aligned(r, r, t[i + i][ap[GF_INDEX(i)] & 15]); \
    xor_block_aligned(r, r, t[i + i + 1][ap[GF_INDEX(i)] >> 4])

#if defined( UNROLL_LOOPS )

void gf_mul_8k(gf_t a, const gf_t8k_t t, gf_t r)
{   uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    xor_8k(15, ap, t, r); xor_8k(14, ap, t, r);
    xor_8k(13, ap, t, r); xor_8k(12, ap, t, r);
    xor_8k(11, ap, t, r); xor_8k(10, ap, t, r);
    xor_8k( 9, ap, t, r); xor_8k( 8, ap, t, r);
    xor_8k( 7, ap, t, r); xor_8k( 6, ap, t, r);
    xor_8k( 5, ap, t, r); xor_8k( 4, ap, t, r);
    xor_8k( 3, ap, t, r); xor_8k( 2, ap, t, r);
    xor_8k( 1, ap, t, r); xor_8k( 0, ap, t, r);
    copy_block_aligned(a, r);
}

#else

void gf_mul_8k(gf_t a, const gf_t8k_t t, gf_t r)
{   int i;
    uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    for(i = 15; i >= 0; --i)
    {
        xor_8k(i,ap,t,r);
    }
    memcpy(a, r, GF_BYTE_LEN);
}

#endif

#endif

#if defined( TABLES_4K )

/*  This version uses 4k bytes of table space on the stack.
    A 16 byte buffer has to be multiplied by a 16 byte key
    value in GF(128).  If we consider a GF(128) value in a
    single byte, we can construct a table of the 256 16
    byte values that result from multiplying g by the 256
    values of this byte.  This requires 4096 bytes.

    If we take the highest byte in the buffer and use this
    table to multiply it by g, we then have to multiply it
    by x^120 to get the final value. For the next highest
    byte the result has to be multiplied by x^112 and so on.

    But we can do this by accumulating the result in an
    accumulator starting with the result for the top byte.
    We repeatedly multiply the accumulator value by x^8 and
    then add in (i.e. xor) the 16 bytes of the next lower
    byte in the buffer, stopping when we reach the lowest
    byte. This requires a 4096 byte table.
*/

void init_4k_table(const gf_t g, gf_t4k_t t)
{   int j, k;

    memset(t[0], 0, GF_BYTE_LEN);

#if defined( GF_MODE_LL ) || defined( GF_MODE_BL )

    memcpy(t[1], g, GF_BYTE_LEN);
    for(j = 1; j <= 64; j <<= 1)
        gf_mulx1(mode)(t[j + j], t[j]);
#else

    memcpy(t[128], g, GF_BYTE_LEN);
    for(j = 64; j >= 1; j >>= 1)
        gf_mulx1(mode)(t[j], t[j + j]);
#endif

    for(j = 2; j < 256; j += j)
        for(k = 1; k < j; ++k)
            xor_block_aligned(t[j + k], t[j], t[k]);
}

#define xor_4k(i,ap,t,r) gf_mulx8(mode)(r); xor_block_aligned(r, r, t[ap[GF_INDEX(i)]])

#if defined( UNROLL_LOOPS )

void gf_mul_4k(gf_t a, const gf_t4k_t t, gf_t r)
{   uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    xor_4k(15, ap, t, r); xor_4k(14, ap, t, r);
    xor_4k(13, ap, t, r); xor_4k(12, ap, t, r);
    xor_4k(11, ap, t, r); xor_4k(10, ap, t, r);
    xor_4k( 9, ap, t, r); xor_4k( 8, ap, t, r);
    xor_4k( 7, ap, t, r); xor_4k( 6, ap, t, r);
    xor_4k( 5, ap, t, r); xor_4k( 4, ap, t, r);
    xor_4k( 3, ap, t, r); xor_4k( 2, ap, t, r);
    xor_4k( 1, ap, t, r); xor_4k( 0, ap, t, r);
    copy_block_aligned(a, r);
}

#else

void gf_mul_4k(gf_t a, const gf_t4k_t t, gf_t r)
{   int i = 15;
    uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    for(i = 15; i >=0; --i)
    {
        xor_4k(i, ap, t, r);
    }
    copy_block_aligned(a, r);
}

#endif

#endif

#if defined( TABLES_256 )

/*  This version uses 256 bytes of table space on the stack.
    A 16 byte buffer has to be multiplied by a 16 byte key
    value in GF(128).  If we consider a GF(128) value in a
    single 4-bit nibble, we can construct a table of the 16
    16 byte  values that result from the 16 values of this
    byte.  This requires 256 bytes. If we take the highest
    4-bit nibble in the buffer and use this table to get the
    result, we then have to multiply by x^124 to get the
    final value. For the next highest byte the result has to
    be multiplied by x^120 and so on. But we can do this by
    accumulating the result in an accumulator starting with
    the result for the top nibble.  We repeatedly multiply
    the accumulator value by x^4 and then add in (i.e. xor)
    the 16 bytes of the next lower nibble in the buffer,
    stopping when we reach the lowest nibble. This uses a
    256 byte table.
*/

void init_256_table(const gf_t g, gf_t256_t t)
{   int j, k;

    memset(t[0], 0, GF_BYTE_LEN);

#if defined( GF_MODE_LL ) || defined( GF_MODE_BL )

    memcpy(t[1], g, GF_BYTE_LEN);
    for(j = 1; j <= 4; j <<= 1)
        gf_mulx1(mode)(t[j + j], t[j]);
#else

    memcpy(t[8], g, GF_BYTE_LEN);
    for(j = 4; j >= 1; j >>= 1)
        gf_mulx1(mode)(t[j], t[j + j]);
#endif

    for(j = 2; j < 16; j += j)
        for(k = 1; k < j; ++k)
            xor_block_aligned(t[j + k], t[j], t[k]);
}

#define x_lo(i,ap,t,r) gf_mulx4(mode)(r); xor_block_aligned(r, r, t[ap[GF_INDEX(i)] & 0x0f])
#define x_hi(i,ap,t,r) gf_mulx4(mode)(r); xor_block_aligned(r, r, t[ap[GF_INDEX(i)] >> 4])

#if defined( GF_MODE_LL ) || defined( GF_MODE_BL )
#define xor_256(a,b,c,d)    x_hi(a,b,c,d);  x_lo(a,b,c,d)
#else
#define xor_256(a,b,c,d)    x_lo(a,b,c,d);  x_hi(a,b,c,d)
#endif

#if defined( UNROLL_LOOPS )

void gf_mul_256(gf_t a, const gf_t256_t t, gf_t r)
{   uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    xor_256(15, ap, t, r); xor_256(14, ap, t, r);
    xor_256(13, ap, t, r); xor_256(12, ap, t, r);
    xor_256(11, ap, t, r); xor_256(10, ap, t, r);
    xor_256( 9, ap, t, r); xor_256( 8, ap, t, r);
    xor_256( 7, ap, t, r); xor_256( 6, ap, t, r);
    xor_256( 5, ap, t, r); xor_256( 4, ap, t, r);
    xor_256( 3, ap, t, r); xor_256( 2, ap, t, r);
    xor_256( 1, ap, t, r); xor_256( 0, ap, t, r);
    copy_block_aligned(a, r);
}

#else

void gf_mul_256(gf_t a, const gf_t256_t t, gf_t r)
{   int i;
    uint_8t *ap = (uint_8t*)a;
    memset(r, 0, GF_BYTE_LEN);
    for(i = 15; i >= 0; --i)
    {
        xor_256(i, ap, t, r);
    }
    copy_block_aligned(a, r);
}

#endif

#endif
