/* fe_x25519_128.i
 *
 * Copyright (C) 2006-2020 wolfSSL Inc.
 *
 * This file is part of wolfSSL.
 *
 * wolfSSL is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * wolfSSL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
 */

void fe_init(void)
{
}

/* Convert a number represented as an array of bytes to an array of words with
 * 51-bits of data in each word.
 *
 * in   An array of bytes.
 * out  An array of words.
 */
void fe_frombytes(fe out, const unsigned char *in)
{
    out[0] = (((int64_t)((in[ 0]      )       ))      )
           | (((int64_t)((in[ 1]      )       )) <<  8)
           | (((int64_t)((in[ 2]      )       )) << 16)
           | (((int64_t)((in[ 3]      )       )) << 24)
           | (((int64_t)((in[ 4]      )       )) << 32)
           | (((int64_t)((in[ 5]      )       )) << 40)
           | (((int64_t)((in[ 6]      ) & 0x07)) << 48);
    out[1] = (((int64_t)((in[ 6] >>  3) & 0x1f))      )
           | (((int64_t)((in[ 7]      )       )) <<  5)
           | (((int64_t)((in[ 8]      )       )) << 13)
           | (((int64_t)((in[ 9]      )       )) << 21)
           | (((int64_t)((in[10]      )       )) << 29)
           | (((int64_t)((in[11]      )       )) << 37)
           | (((int64_t)((in[12]      ) & 0x3f)) << 45);
    out[2] = (((int64_t)((in[12] >>  6) & 0x03))      )
           | (((int64_t)((in[13]      )       )) <<  2)
           | (((int64_t)((in[14]      )       )) << 10)
           | (((int64_t)((in[15]      )       )) << 18)
           | (((int64_t)((in[16]      )       )) << 26)
           | (((int64_t)((in[17]      )       )) << 34)
           | (((int64_t)((in[18]      )       )) << 42)
           | (((int64_t)((in[19]      ) & 0x01)) << 50);
    out[3] = (((int64_t)((in[19] >>  1) & 0x7f))      )
           | (((int64_t)((in[20]      )       )) <<  7)
           | (((int64_t)((in[21]      )       )) << 15)
           | (((int64_t)((in[22]      )       )) << 23)
           | (((int64_t)((in[23]      )       )) << 31)
           | (((int64_t)((in[24]      )       )) << 39)
           | (((int64_t)((in[25]      ) & 0x0f)) << 47);
    out[4] = (((int64_t)((in[25] >>  4) & 0x0f))      )
           | (((int64_t)((in[26]      )       )) <<  4)
           | (((int64_t)((in[27]      )       )) << 12)
           | (((int64_t)((in[28]      )       )) << 20)
           | (((int64_t)((in[29]      )       )) << 28)
           | (((int64_t)((in[30]      )       )) << 36)
           | (((int64_t)((in[31]      ) & 0x7f)) << 44);
}

/* Convert a number represented as an array of words to an array of bytes.
 * The array of words is normalized to an array of 51-bit data words and if
 * greater than the mod, modulo reduced by the prime 2^255 - 1.
 *
 * n    An array of words.
 * out  An array of bytes.
 */
void fe_tobytes(unsigned char *out, const fe n)
{
    fe      in;
    int64_t c;

    in[0] = n[0];
    in[1] = n[1];
    in[2] = n[2];
    in[3] = n[3];
    in[4] = n[4];

    /* Normalize to 51-bits of data per word. */
    in[0] += (in[4] >> 51) * 19; in[4] &= 0x7ffffffffffff;

    in[1] += in[0] >> 51; in[0] &= 0x7ffffffffffff;
    in[2] += in[1] >> 51; in[1] &= 0x7ffffffffffff;
    in[3] += in[2] >> 51; in[2] &= 0x7ffffffffffff;
    in[4] += in[3] >> 51; in[3] &= 0x7ffffffffffff;
    in[0] += (in[4] >> 51) * 19;
    in[4] &= 0x7ffffffffffff;

    c = (in[0] + 19) >> 51;
    c = (in[1] + c) >> 51;
    c = (in[2] + c) >> 51;
    c = (in[3] + c) >> 51;
    c = (in[4] + c) >> 51;
    in[0] += c * 19;
    in[1] += in[0] >> 51; in[0] &= 0x7ffffffffffff;
    in[2] += in[1] >> 51; in[1] &= 0x7ffffffffffff;
    in[3] += in[2] >> 51; in[2] &= 0x7ffffffffffff;
    in[4] += in[3] >> 51; in[3] &= 0x7ffffffffffff;
    in[4] &= 0x7ffffffffffff;

    out[ 0] = (((byte)((in[0]      )       ))      );
    out[ 1] = (((byte)((in[0] >>  8)       ))      );
    out[ 2] = (((byte)((in[0] >> 16)       ))      );
    out[ 3] = (((byte)((in[0] >> 24)       ))      );
    out[ 4] = (((byte)((in[0] >> 32)       ))      );
    out[ 5] = (((byte)((in[0] >> 40)       ))      );
    out[ 6] = (((byte)((in[0] >> 48) & 0x07))      )
            | (((byte)((in[1]      ) & 0x1f)) <<  3);
    out[ 7] = (((byte)((in[1] >>  5)       ))      );
    out[ 8] = (((byte)((in[1] >> 13)       ))      );
    out[ 9] = (((byte)((in[1] >> 21)       ))      );
    out[10] = (((byte)((in[1] >> 29)       ))      );
    out[11] = (((byte)((in[1] >> 37)       ))      );
    out[12] = (((byte)((in[1] >> 45) & 0x3f))      )
            | (((byte)((in[2]      ) & 0x03)) <<  6);
    out[13] = (((byte)((in[2] >>  2)       ))      );
    out[14] = (((byte)((in[2] >> 10)       ))      );
    out[15] = (((byte)((in[2] >> 18)       ))      );
    out[16] = (((byte)((in[2] >> 26)       ))      );
    out[17] = (((byte)((in[2] >> 34)       ))      );
    out[18] = (((byte)((in[2] >> 42)       ))      );
    out[19] = (((byte)((in[2] >> 50) & 0x01))      )
            | (((byte)((in[3]      ) & 0x7f)) <<  1);
    out[20] = (((byte)((in[3] >>  7)       ))      );
    out[21] = (((byte)((in[3] >> 15)       ))      );
    out[22] = (((byte)((in[3] >> 23)       ))      );
    out[23] = (((byte)((in[3] >> 31)       ))      );
    out[24] = (((byte)((in[3] >> 39)       ))      );
    out[25] = (((byte)((in[3] >> 47) & 0x0f))      )
            | (((byte)((in[4]      ) & 0x0f)) <<  4);
    out[26] = (((byte)((in[4] >>  4)       ))      );
    out[27] = (((byte)((in[4] >> 12)       ))      );
    out[28] = (((byte)((in[4] >> 20)       ))      );
    out[29] = (((byte)((in[4] >> 28)       ))      );
    out[30] = (((byte)((in[4] >> 36)       ))      );
    out[31] = (((byte)((in[4] >> 44) & 0x7f))      );
}

/* Set the field element to 1.
 *
 * n  The field element number.
 */
void fe_1(fe n)
{
    n[0] = 0x0000000000001;
    n[1] = 0x0000000000000;
    n[2] = 0x0000000000000;
    n[3] = 0x0000000000000;
    n[4] = 0x0000000000000;
}

/* Set the field element to 0.
 *
 * n  The field element number.
 */
void fe_0(fe n)
{
    n[0] = 0x0000000000000;
    n[1] = 0x0000000000000;
    n[2] = 0x0000000000000;
    n[3] = 0x0000000000000;
    n[4] = 0x0000000000000;
}

/* Copy field element a into field element r.
 *
 * r  Field element to copy into.
 * a  Field element to copy.
 */
void fe_copy(fe r, const fe a)
{
    r[0] = a[0];
    r[1] = a[1];
    r[2] = a[2];
    r[3] = a[3];
    r[4] = a[4];
}

/* Constant time, conditional swap of field elements a and b.
 *
 * a  A field element.
 * b  A field element.
 * c  If 1 then swap and if 0 then don't swap.
 */
void fe_cswap(fe a, fe b, int c)
{
    int64_t m = c;
    int64_t t0, t1, t2, t3, t4;

    /* Convert conditional into mask. */
    m = -m;
    t0 = m & (a[0] ^ b[0]);
    t1 = m & (a[1] ^ b[1]);
    t2 = m & (a[2] ^ b[2]);
    t3 = m & (a[3] ^ b[3]);
    t4 = m & (a[4] ^ b[4]);

    a[0] ^= t0;
    a[1] ^= t1;
    a[2] ^= t2;
    a[3] ^= t3;
    a[4] ^= t4;

    b[0] ^= t0;
    b[1] ^= t1;
    b[2] ^= t2;
    b[3] ^= t3;
    b[4] ^= t4;
}

/* Subtract b from a into r. (r = a - b)
 *
 * r  A field element.
 * a  A field element.
 * b  A field element.
 */
void fe_sub(fe r, const fe a, const fe b)
{
    r[0] = a[0] - b[0];
    r[1] = a[1] - b[1];
    r[2] = a[2] - b[2];
    r[3] = a[3] - b[3];
    r[4] = a[4] - b[4];
}

/* Add b to a into r. (r = a + b)
 *
 * r  A field element.
 * a  A field element.
 * b  A field element.
 */
void fe_add(fe r, const fe a, const fe b)
{
    r[0] = a[0] + b[0];
    r[1] = a[1] + b[1];
    r[2] = a[2] + b[2];
    r[3] = a[3] + b[3];
    r[4] = a[4] + b[4];
}

/* Multiply a and b into r. (r = a * b)
 *
 * r  A field element.
 * a  A field element.
 * b  A field element.
 */
void fe_mul(fe r, const fe a, const fe b)
{
    const __int128_t k19 = 19;
    __int128_t t0 = ((__int128_t)a[0]) * b[0];
    __int128_t t1 = ((__int128_t)a[0]) * b[1]
                  + ((__int128_t)a[1]) * b[0];
    __int128_t t2 = ((__int128_t)a[0]) * b[2]
                  + ((__int128_t)a[1]) * b[1]
                  + ((__int128_t)a[2]) * b[0];
    __int128_t t3 = ((__int128_t)a[0]) * b[3]
                  + ((__int128_t)a[1]) * b[2]
                  + ((__int128_t)a[2]) * b[1]
                  + ((__int128_t)a[3]) * b[0];
    __int128_t t4 = ((__int128_t)a[0]) * b[4]
                  + ((__int128_t)a[1]) * b[3]
                  + ((__int128_t)a[2]) * b[2]
                  + ((__int128_t)a[3]) * b[1]
                  + ((__int128_t)a[4]) * b[0];
    __int128_t t5 = ((__int128_t)a[1]) * b[4]
                  + ((__int128_t)a[2]) * b[3]
                  + ((__int128_t)a[3]) * b[2]
                  + ((__int128_t)a[4]) * b[1];
    __int128_t t6 = ((__int128_t)a[2]) * b[4]
                  + ((__int128_t)a[3]) * b[3]
                  + ((__int128_t)a[4]) * b[2];
    __int128_t t7 = ((__int128_t)a[3]) * b[4]
                  + ((__int128_t)a[4]) * b[3];
    __int128_t t8 = ((__int128_t)a[4]) * b[4];

    /* Modulo reduce double long word. */
    t0 += t5 * k19;
    t1 += t6 * k19;
    t2 += t7 * k19;
    t3 += t8 * k19;

    /* Normalize to 51-bits of data per word. */
    t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;

    t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
    t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
    t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
    t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
    r[0] += (t4 >> 51) * k19;
    r[4] = t4 & 0x7ffffffffffff;
}

/* Square a and put result in r. (r = a * a)
 *
 * r  A field element.
 * a  A field element.
 * b  A field element.
 */
void fe_sq(fe r, const fe a)
{
    const __int128_t k19 = 19;
    const __int128_t k2 = 2;
    __int128_t t0 = ((__int128_t)a[0]) * a[0];
    __int128_t t1 = ((__int128_t)a[0]) * a[1] * k2;
    __int128_t t2 = ((__int128_t)a[0]) * a[2] * k2
                  + ((__int128_t)a[1]) * a[1];
    __int128_t t3 = ((__int128_t)a[0]) * a[3] * k2
                  + ((__int128_t)a[1]) * a[2] * k2;
    __int128_t t4 = ((__int128_t)a[0]) * a[4] * k2
                  + ((__int128_t)a[1]) * a[3] * k2
                  + ((__int128_t)a[2]) * a[2];
    __int128_t t5 = ((__int128_t)a[1]) * a[4] * k2
                  + ((__int128_t)a[2]) * a[3] * k2;
    __int128_t t6 = ((__int128_t)a[2]) * a[4] * k2
                  + ((__int128_t)a[3]) * a[3];
    __int128_t t7 = ((__int128_t)a[3]) * a[4] * k2;
    __int128_t t8 = ((__int128_t)a[4]) * a[4];

    /* Modulo reduce double long word. */
    t0 += t5 * k19;
    t1 += t6 * k19;
    t2 += t7 * k19;
    t3 += t8 * k19;

    /* Normalize to 51-bits of data per word. */
    t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;

    t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
    t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
    t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
    t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
    r[0] += (t4 >> 51) * k19;
    r[4] = t4 & 0x7ffffffffffff;
}

/* Multiply a by 121666 and put result in r. (r = 121666 * a)
 *
 * r  A field element.
 * a  A field element.
 * b  A field element.
 */
void fe_mul121666(fe r, fe a)
{
    const __int128_t k19 = 19;
    const __int128_t k121666 = 121666;
    __int128_t t0 = ((__int128_t)a[0]) * k121666;
    __int128_t t1 = ((__int128_t)a[1]) * k121666;
    __int128_t t2 = ((__int128_t)a[2]) * k121666;
    __int128_t t3 = ((__int128_t)a[3]) * k121666;
    __int128_t t4 = ((__int128_t)a[4]) * k121666;

    /* Normalize to 51-bits of data per word. */
    t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;

    t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
    t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
    t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
    t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
    r[0] += (t4 >> 51) * k19;
    r[4] = t4 & 0x7ffffffffffff;
}

/* Find the inverse of a modulo 2^255 - 1 and put result in r.
 * (r * a) mod (2^255 - 1) = 1
 * Implementation is constant time.
 *
 * r  A field element.
 * a  A field element.
 */
void fe_invert(fe r, const fe a)
{
    fe  t0, t1, t2, t3;
    int i;

    /* a ^ (2^255 - 21) */
    fe_sq(t0,  a); for (i = 1; i <   1; ++i) fe_sq(t0, t0);
    fe_sq(t1, t0); for (i = 1; i <   2; ++i) fe_sq(t1, t1); fe_mul(t1,  a, t1);
    fe_mul(t0, t0, t1);
    fe_sq(t2, t0); for (i = 1; i <   1; ++i) fe_sq(t2, t2); fe_mul(t1, t1, t2);
    fe_sq(t2, t1); for (i = 1; i <   5; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
    fe_sq(t2, t1); for (i = 1; i <  10; ++i) fe_sq(t2, t2); fe_mul(t2, t2, t1);
    fe_sq(t3, t2); for (i = 1; i <  20; ++i) fe_sq(t3, t3); fe_mul(t2, t3, t2);
    fe_sq(t2, t2); for (i = 1; i <  10; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
    fe_sq(t2, t1); for (i = 1; i <  50; ++i) fe_sq(t2, t2); fe_mul(t2, t2, t1);
    fe_sq(t3, t2); for (i = 1; i < 100; ++i) fe_sq(t3, t3); fe_mul(t2, t3, t2);
    fe_sq(t2, t2); for (i = 1; i <  50; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
    fe_sq(t1, t1); for (i = 1; i <   5; ++i) fe_sq(t1, t1); fe_mul( r, t1, t0);
}

#ifndef CURVE25519_SMALL
/* Scalar multiply the field element a by n using Montgomery Ladder and places
 * result in r.
 *
 * r  A field element as an array of bytes.
 * n  The scalar as an array of bytes.
 * a  A field element as an array of bytes.
 */
int curve25519(byte* r, const byte* n, const byte* a)
{
    fe           x1, x2, z2, x3, z3;
    fe           t0, t1;
    int          pos;
    unsigned int swap;
    unsigned int b;

    fe_frombytes(x1, a);
    fe_1(x2);
    fe_0(z2);
    fe_copy(x3, x1);
    fe_1(z3);

    swap = 0;
    for (pos = 254;pos >= 0;--pos) {
        b = n[pos / 8] >> (pos & 7);
        b &= 1;
        swap ^= b;
        fe_cswap(x2, x3, swap);
        fe_cswap(z2, z3, swap);
        swap = b;

        fe_sub(t0, x3, z3);
        fe_sub(t1, x2, z2);
        fe_add(x2, x2, z2);
        fe_add(z2, x3, z3);
        fe_mul(z3, t0, x2);
        fe_mul(z2, z2, t1);
        fe_sq(t0, t1);
        fe_sq(t1, x2);
        fe_add(x3, z3, z2);
        fe_sub(z2, z3, z2);
        fe_mul(x2, t1, t0);
        fe_sub(t1, t1, t0);
        fe_sq(z2, z2);
        fe_mul121666(z3, t1);
        fe_sq(x3, x3);
        fe_add(t0, t0, z3);
        fe_mul(z3, x1, z2);
        fe_mul(z2, t1, t0);
    }
    fe_cswap(x2, x3, swap);
    fe_cswap(z2, z3, swap);

    fe_invert(z2, z2);
    fe_mul(x2, x2, z2);
    fe_tobytes(r, x2);

    return 0;
}
#endif /* !CURVE25519_SMALL */

/* The field element value 0 as an array of bytes. */
static const unsigned char zero[32] = {0};

/* Constant time check as to whether a is not 0.
 *
 * a  A field element.
 */
int fe_isnonzero(const fe a)
{
    unsigned char s[32];
    fe_tobytes(s, a);
    return ConstantCompare(s, zero, 32);
}

/* Checks whether a is negative.
 *
 * a  A field element.
 */
int fe_isnegative(const fe a)
{
    unsigned char s[32];
    fe_tobytes(s, a);
    return s[0] & 1;
}

/* Negates field element a and stores the result in r.
 *
 * r  A field element.
 * a  A field element.
 */
void fe_neg(fe r, const fe a)
{
    r[0] = -a[0];
    r[1] = -a[1];
    r[2] = -a[2];
    r[3] = -a[3];
    r[4] = -a[4];
}

/* Constant time, conditional move of b into a.
 * a is not changed if the condition is 0.
 *
 * a  A field element.
 * b  A field element.
 * c  If 1 then copy and if 0 then don't copy.
 */
void fe_cmov(fe a, const fe b, int c)
{
    int64_t m = c;
    int64_t t0, t1, t2, t3, t4;

    /* Convert conditional into mask. */
    m = -m;
    t0 = m & (a[0] ^ b[0]);
    t1 = m & (a[1] ^ b[1]);
    t2 = m & (a[2] ^ b[2]);
    t3 = m & (a[3] ^ b[3]);
    t4 = m & (a[4] ^ b[4]);

    a[0] ^= t0;
    a[1] ^= t1;
    a[2] ^= t2;
    a[3] ^= t3;
    a[4] ^= t4;
}

void fe_pow22523(fe r, const fe a)
{
    fe t0, t1, t2;
    int i;

    /* a ^ (2^255 - 23) */
    fe_sq(t0,  a); for (i = 1; i <   1; ++i) fe_sq(t0, t0);
    fe_sq(t1, t0); for (i = 1; i <   2; ++i) fe_sq(t1, t1); fe_mul(t1,  a, t1);
    fe_mul(t0, t0, t1);
    fe_sq(t0, t0); for (i = 1; i <   1; ++i) fe_sq(t0, t0); fe_mul(t0, t1, t0);
    fe_sq(t1, t0); for (i = 1; i <   5; ++i) fe_sq(t1, t1); fe_mul(t0, t1, t0);
    fe_sq(t1, t0); for (i = 1; i <  10; ++i) fe_sq(t1, t1); fe_mul(t1, t1, t0);
    fe_sq(t2, t1); for (i = 1; i <  20; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
    fe_sq(t1, t1); for (i = 1; i <  10; ++i) fe_sq(t1, t1); fe_mul(t0, t1, t0);
    fe_sq(t1, t0); for (i = 1; i <  50; ++i) fe_sq(t1, t1); fe_mul(t1, t1, t0);
    fe_sq(t2, t1); for (i = 1; i < 100; ++i) fe_sq(t2, t2); fe_mul(t1, t2, t1);
    fe_sq(t1, t1); for (i = 1; i <  50; ++i) fe_sq(t1, t1); fe_mul(t0, t1, t0);
    fe_sq(t0, t0); for (i = 1; i <   2; ++i) fe_sq(t0, t0); fe_mul( r, t0, a);

    return;
}

/* Double the square of a and put result in r. (r = 2 * a * a)
 *
 * r  A field element.
 * a  A field element.
 * b  A field element.
 */
void fe_sq2(fe r, const fe a)
{
    const __int128_t k2 = 2;
    const __int128_t k19 = 19;
    __int128_t t0 = k2 * (((__int128_t)a[0]) * a[0]);
    __int128_t t1 = k2 * (((__int128_t)a[0]) * a[1] * k2);
    __int128_t t2 = k2 * (((__int128_t)a[0]) * a[2] * k2
                  + ((__int128_t)a[1]) * a[1]);
    __int128_t t3 = k2 * (((__int128_t)a[0]) * a[3] * k2
                  + ((__int128_t)a[1]) * a[2] * k2);
    __int128_t t4 = k2 * (((__int128_t)a[0]) * a[4] * k2
                  + ((__int128_t)a[1]) * a[3] * k2
                  + ((__int128_t)a[2]) * a[2]);
    __int128_t t5 = k2 * (((__int128_t)a[1]) * a[4] * k2
                  + ((__int128_t)a[2]) * a[3] * k2);
    __int128_t t6 = k2 * (((__int128_t)a[2]) * a[4] * k2
                  + ((__int128_t)a[3]) * a[3]);
    __int128_t t7 = k2 * (((__int128_t)a[3]) * a[4] * k2);
    __int128_t t8 = k2 * (((__int128_t)a[4]) * a[4]);

    /* Modulo reduce double long word. */
    t0 += t5 * k19;
    t1 += t6 * k19;
    t2 += t7 * k19;
    t3 += t8 * k19;

    /* Normalize to 51-bits of data per word. */
    t0 += (t4 >> 51) * k19; t4 &= 0x7ffffffffffff;

    t1 += t0 >> 51; r[0] = t0 & 0x7ffffffffffff;
    t2 += t1 >> 51; r[1] = t1 & 0x7ffffffffffff;
    t3 += t2 >> 51; r[2] = t2 & 0x7ffffffffffff;
    t4 += t3 >> 51; r[3] = t3 & 0x7ffffffffffff;
    r[0] += (t4 >> 51) * k19;
    r[4] = t4 & 0x7ffffffffffff;
}

/* Load 3 little endian bytes into a 64-bit word.
 *
 * in  An array of bytes.
 * returns a 64-bit word.
 */
uint64_t load_3(const unsigned char *in)
{
    uint64_t result;

    result = ((((uint64_t)in[0])      ) |
              (((uint64_t)in[1]) <<  8) |
              (((uint64_t)in[2]) << 16));

    return result;
}

/* Load 4 little endian bytes into a 64-bit word.
 *
 * in  An array of bytes.
 * returns a 64-bit word.
 */
uint64_t load_4(const unsigned char *in)
{
    uint64_t result;

    result = ((((uint64_t)in[0])      ) |
              (((uint64_t)in[1]) <<  8) |
              (((uint64_t)in[2]) << 16) |
              (((uint64_t)in[3]) << 24));

    return result;
}

