/******************************************************************************
 * NTRU Cryptography Reference Source Code
 *
 * Copyright (C) 2009-2016  Security Innovation (SI)
 *
 * SI has dedicated the work to the public domain by waiving all of its rights
 * to the work worldwide under copyright law, including all related and
 * neighboring rights, to the extent allowed by law.
 *
 *
 * This program 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.
 * You can copy, modify, distribute and perform the work, even for commercial
 * purposes, all without asking permission. You should have received a copy of
 * the creative commons license (CC0 1.0 universal) along with this program.
 * See the license file for more information. 
 *
 *
 *********************************************************************************/
 
 
/******************************************************************************
 *
 * File: ntru_crypto_sha1.c
 *
 * Contents: Routines implementing the SHA-1 hash calculation.
 *
 *****************************************************************************/

#include "ntru_crypto.h"
#include "ntru_crypto_sha1.h"
#include "ntru_crypto_msbyte_uint32.h"


/* chaining state elements */

#define H0      state[0]
#define H1      state[1]
#define H2      state[2]
#define H3      state[3]
#define H4      state[4]


/* standard SHA-1 initialization values */

#define H0_INIT 0x67452301UL
#define H1_INIT 0xefcdab89UL
#define H2_INIT 0x98badcfeUL
#define H3_INIT 0x10325476UL
#define H4_INIT 0xc3d2e1f0UL


/* sha1_blk()
 *
 * This routine updates the current hash output (chaining state)
 * by performing SHA-1 on a 512-bit block of data represented as sixteen
 * 32-bit words.
 */

#define K00_19  0x5a827999UL
#define K20_39  0x6ed9eba1UL
#define K40_59  0x8f1bbcdcUL
#define K60_79  0xca62c1d6UL

#define RL(a, n)    ( ((a) << (n)) | ((a) >> (32 - (n))) )


static void
sha1_blk(
    uint32_t const *data,       /*     in - ptr to 16 32-bit word input block */
    uint32_t       *state)      /* in/out - ptr to 5 32-bit word chaining state */
{
    uint32_t A, B, C, D, E;
    uint32_t w[16];

    /* init A - E */

    A = H0; B = H1; C = H2; D = H3; E = H4;

    /* rounds 0 - 15 */

    E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[ 0]; B = RL(B, 30);
    D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + data[ 1]; A = RL(A, 30);
    C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + data[ 2]; E = RL(E, 30);
    B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + data[ 3]; D = RL(D, 30);
    A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + data[ 4]; C = RL(C, 30);
    E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[ 5]; B = RL(B, 30);
    D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + data[ 6]; A = RL(A, 30);
    C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + data[ 7]; E = RL(E, 30);
    B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + data[ 8]; D = RL(D, 30);
    A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + data[ 9]; C = RL(C, 30);
    E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[10]; B = RL(B, 30);
    D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + data[11]; A = RL(A, 30);
    C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + data[12]; E = RL(E, 30);
    B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + data[13]; D = RL(D, 30);
    A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + data[14]; C = RL(C, 30);
    E += RL(A, 5) + K00_19 + (B & (C ^ D) ^ D) + data[15]; B = RL(B, 30);

    /* rounds 16 - 19 */

    w[ 0] = data[ 0] ^ data[ 2] ^ data[ 8] ^ data[13]; w[ 0] = RL(w[0], 1);
    D += RL(E, 5) + K00_19 + (A & (B ^ C) ^ C) + w[ 0]; A = RL(A, 30);
    w[ 1] = data[ 1] ^ data[ 3] ^ data[ 9] ^ data[14]; w[ 1] = RL(w[1], 1);
    C += RL(D, 5) + K00_19 + (E & (A ^ B) ^ B) + w[ 1]; E = RL(E, 30);
    w[ 2] = data[ 2] ^ data[ 4] ^ data[10] ^ data[15]; w[ 2] = RL(w[ 2], 1);
    B += RL(C, 5) + K00_19 + (D & (E ^ A) ^ A) + w[ 2]; D = RL(D, 30);
    w[ 3] = data[ 3] ^ data[ 5] ^ data[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1);
    A += RL(B, 5) + K00_19 + (C & (D ^ E) ^ E) + w[ 3]; C = RL(C, 30);

    /* rounds 20 - 39 */

    w[ 4] = data[ 4] ^ data[ 6] ^ data[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1);
    E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[ 4]; B = RL(B, 30);
    w[ 5] = data[ 5] ^ data[ 7] ^ data[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1);
    D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[ 5]; A = RL(A, 30);
    w[ 6] = data[ 6] ^ data[ 8] ^ data[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1);
    C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[ 6]; E = RL(E, 30);
    w[ 7] = data[ 7] ^ data[ 9] ^ data[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1);
    B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[ 7]; D = RL(D, 30);
    w[ 8] = data[ 8] ^ data[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1);
    A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[ 8]; C = RL(C, 30);
    w[ 9] = data[ 9] ^ data[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1);
    E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[ 9]; B = RL(B, 30);
    w[10] = data[10] ^ data[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1);
    D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[10]; A = RL(A, 30);
    w[11] = data[11] ^ data[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1);
    C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[11]; E = RL(E, 30);
    w[12] = data[12] ^ data[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1);
    B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[12]; D = RL(D, 30);
    w[13] = data[13] ^ data[15] ^ w[ 5] ^ w[10]; w[13] = RL(w[13], 1);
    A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[13]; C = RL(C, 30);
    w[14] = data[14] ^ w[ 0] ^ w[ 6] ^ w[11]; w[14] = RL(w[14], 1);
    E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[14]; B = RL(B, 30);
    w[15] = data[15] ^ w[ 1] ^ w[ 7] ^ w[12]; w[15] = RL(w[15], 1);
    D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[15]; A = RL(A, 30);
    w[ 0] = w[ 0] ^ w[ 2] ^ w[ 8] ^ w[13]; w[ 0] = RL(w[ 0], 1);
    C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[ 0]; E = RL(E, 30);
    w[ 1] = w[ 1] ^ w[ 3] ^ w[ 9] ^ w[14]; w[ 1] = RL(w[ 1], 1);
    B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[ 1]; D = RL(D, 30);
    w[ 2] = w[ 2] ^ w[ 4] ^ w[10] ^ w[15]; w[ 2] = RL(w[ 2], 1);
    A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[ 2]; C = RL(C, 30);
    w[ 3] = w[ 3] ^ w[ 5] ^ w[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1);
    E += RL(A, 5) + K20_39 + (B ^ C ^ D) + w[ 3]; B = RL(B, 30);
    w[ 4] = w[ 4] ^ w[ 6] ^ w[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1);
    D += RL(E, 5) + K20_39 + (A ^ B ^ C) + w[ 4]; A = RL(A, 30);
    w[ 5] = w[ 5] ^ w[ 7] ^ w[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1);
    C += RL(D, 5) + K20_39 + (E ^ A ^ B) + w[ 5]; E = RL(E, 30);
    w[ 6] = w[ 6] ^ w[ 8] ^ w[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1);
    B += RL(C, 5) + K20_39 + (D ^ E ^ A) + w[ 6]; D = RL(D, 30);
    w[ 7] = w[ 7] ^ w[ 9] ^ w[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1);
    A += RL(B, 5) + K20_39 + (C ^ D ^ E) + w[ 7]; C = RL(C, 30);

    /* rounds 40 - 59 */

    w[ 8] = w[ 8] ^ w[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1);
    E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[ 8]; B = RL(B, 30);
    w[ 9] = w[ 9] ^ w[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1);
    D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[ 9]; A = RL(A, 30);
    w[10] = w[10] ^ w[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1);
    C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[10]; E = RL(E, 30);
    w[11] = w[11] ^ w[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1);
    B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[11]; D = RL(D, 30);
    w[12] = w[12] ^ w[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1);
    A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[12]; C = RL(C, 30);
    w[13] = w[13] ^ w[15] ^ w[ 5] ^ w[10]; w[13] = RL(w[13], 1);
    E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[13]; B = RL(B, 30);
    w[14] = w[14] ^ w[ 0] ^ w[ 6] ^ w[11]; w[14] = RL(w[14], 1);
    D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[14]; A = RL(A, 30);
    w[15] = w[15] ^ w[ 1] ^ w[ 7] ^ w[12]; w[15] = RL(w[15], 1);
    C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[15]; E = RL(E, 30);
    w[ 0] = w[ 0] ^ w[ 2] ^ w[ 8] ^ w[13]; w[ 0] = RL(w[ 0], 1);
    B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[ 0]; D = RL(D, 30);
    w[ 1] = w[ 1] ^ w[ 3] ^ w[ 9] ^ w[14]; w[ 1] = RL(w[ 1], 1);
    A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[ 1]; C = RL(C, 30);
    w[ 2] = w[ 2] ^ w[ 4] ^ w[10] ^ w[15]; w[ 2] = RL(w[ 2], 1);
    E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[ 2]; B = RL(B, 30);
    w[ 3] = w[ 3] ^ w[ 5] ^ w[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1);
    D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[ 3]; A = RL(A, 30);
    w[ 4] = w[ 4] ^ w[ 6] ^ w[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1);
    C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[ 4]; E = RL(E, 30);
    w[ 5] = w[ 5] ^ w[ 7] ^ w[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1);
    B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[ 5]; D = RL(D, 30);
    w[ 6] = w[ 6] ^ w[ 8] ^ w[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1);
    A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[ 6]; C = RL(C, 30);
    w[ 7] = w[ 7] ^ w[ 9] ^ w[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1);
    E += RL(A, 5) + K40_59 + ((B & C) | (D & (B | C))) + w[ 7]; B = RL(B, 30);
    w[ 8] = w[ 8] ^ w[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1);
    D += RL(E, 5) + K40_59 + ((A & B) | (C & (A | B))) + w[ 8]; A = RL(A, 30);
    w[ 9] = w[ 9] ^ w[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1);
    C += RL(D, 5) + K40_59 + ((E & A) | (B & (E | A))) + w[ 9]; E = RL(E, 30);
    w[10] = w[10] ^ w[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1);
    B += RL(C, 5) + K40_59 + ((D & E) | (A & (D | E))) + w[10]; D = RL(D, 30);
    w[11] = w[11] ^ w[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1);
    A += RL(B, 5) + K40_59 + ((C & D) | (E & (C | D))) + w[11]; C = RL(C, 30);

    /* rounds 60 - 79 */

    w[12] = w[12] ^ w[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1);
    E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[12]; B = RL(B, 30);
    w[13] = w[13] ^ w[15] ^ w[ 5] ^ w[10]; w[13] = RL(w[13], 1);
    D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[13]; A = RL(A, 30);
    w[14] = w[14] ^ w[ 0] ^ w[ 6] ^ w[11]; w[14] = RL(w[14], 1);
    C += RL(D, 5) + K60_79 + (E ^ A ^ B) + w[14]; E = RL(E, 30);
    w[15] = w[15] ^ w[ 1] ^ w[ 7] ^ w[12]; w[15] = RL(w[15], 1);
    B += RL(C, 5) + K60_79 + (D ^ E ^ A) + w[15]; D = RL(D, 30);
    w[ 0] = w[ 0] ^ w[ 2] ^ w[ 8] ^ w[13]; w[ 0] = RL(w[ 0], 1);
    A += RL(B, 5) + K60_79 + (C ^ D ^ E) + w[ 0]; C = RL(C, 30);
    w[ 1] = w[ 1] ^ w[ 3] ^ w[ 9] ^ w[14]; w[ 1] = RL(w[ 1], 1);
    E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[ 1]; B = RL(B, 30);
    w[ 2] = w[ 2] ^ w[ 4] ^ w[10] ^ w[15]; w[ 2] = RL(w[ 2], 1);
    D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[ 2]; A = RL(A, 30);
    w[ 3] = w[ 3] ^ w[ 5] ^ w[11] ^ w[ 0]; w[ 3] = RL(w[ 3], 1);
    C += RL(D, 5) + K60_79 + (E ^ A ^ B) + w[ 3]; E = RL(E, 30);
    w[ 4] = w[ 4] ^ w[ 6] ^ w[12] ^ w[ 1]; w[ 4] = RL(w[ 4], 1);
    B += RL(C, 5) + K60_79 + (D ^ E ^ A) + w[ 4]; D = RL(D, 30);
    w[ 5] = w[ 5] ^ w[ 7] ^ w[13] ^ w[ 2]; w[ 5] = RL(w[ 5], 1);
    A += RL(B, 5) + K60_79 + (C ^ D ^ E) + w[ 5]; C = RL(C, 30);
    w[ 6] = w[ 6] ^ w[ 8] ^ w[14] ^ w[ 3]; w[ 6] = RL(w[ 6], 1);
    E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[ 6]; B = RL(B, 30);
    w[ 7] = w[ 7] ^ w[ 9] ^ w[15] ^ w[ 4]; w[ 7] = RL(w[ 7], 1);
    D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[ 7]; A = RL(A, 30);
    w[ 8] = w[ 8] ^ w[10] ^ w[ 0] ^ w[ 5]; w[ 8] = RL(w[ 8], 1);
    C += RL(D, 5) + K60_79 + (E ^ A ^ B) + w[ 8]; E = RL(E, 30);
    w[ 9] = w[ 9] ^ w[11] ^ w[ 1] ^ w[ 6]; w[ 9] = RL(w[ 9], 1);
    B += RL(C, 5) + K60_79 + (D ^ E ^ A) + w[ 9]; D = RL(D, 30);
    w[10] = w[10] ^ w[12] ^ w[ 2] ^ w[ 7]; w[10] = RL(w[10], 1);
    A += RL(B, 5) + K60_79 + (C ^ D ^ E) + w[10]; C = RL(C, 30);
    w[11] = w[11] ^ w[13] ^ w[ 3] ^ w[ 8]; w[11] = RL(w[11], 1);
    E += RL(A, 5) + K60_79 + (B ^ C ^ D) + w[11]; B = RL(B, 30);
    w[12] = w[12] ^ w[14] ^ w[ 4] ^ w[ 9]; w[12] = RL(w[12], 1);
    D += RL(E, 5) + K60_79 + (A ^ B ^ C) + w[12]; A = RL(A, 30);
    w[13] = w[13] ^ w[15] ^ w[ 5] ^ w[10];
    C += RL(D, 5) + K60_79 + (E ^ A ^ B) + RL(w[13], 1); E = RL(E, 30);
    w[14] = w[14] ^ w[ 0] ^ w[ 6] ^ w[11];
    B += RL(C, 5) + K60_79 + (D ^ E ^ A) + RL(w[14], 1); D = RL(D, 30);

    /* update H0 - H4 */

    w[15] = w[15] ^ w[ 1] ^ w[ 7] ^ w[12];
    H0 += A + RL(B, 5) + K60_79 + (C ^ D ^ E) + RL(w[15], 1);
    H1 += B;
    H2 += RL(C, 30);
    H3 += D;
    H4 += E;

    /* clear temp variables */

    A = B = C = D = E = 0;
    SecureZeroMemory(w, sizeof(w));
}


/* ntru_crypto_sha1()
 *
 * This routine provides all operations for a SHA-1 hash, and the use
 * of SHA-1 for DSA signing and key generation.
 * It may be used to initialize, update, or complete a message digest,
 * or any combination of those actions, as determined by the SHA_INIT flag,
 * the in_len parameter, and the SHA_FINISH flag, respectively.
 *
 * When in_len == 0 (no data to hash), the parameter, in, may be NULL.
 * When the SHA_FINISH flag is not set, the parameter, md, may be NULL.
 *
 * Initialization may be standard or use a specified initialization vector,
 * and is indicated by setting the SHA_INIT flag.
 * Setting init = NULL specifies standard initialization.  Otherwise, init
 * points to the array of five alternate initialization 32-bit words.
 *
 * The hash operation can be updated with any number of input bytes, including
 * zero.
 *
 * Returns SHA_OK on success.
 * Returns SHA_FAIL with corrupted context.
 * Returns SHA_BAD_PARAMETER if  inappropriate NULL pointers are passed.
 * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed.
 */

uint32_t
ntru_crypto_sha1(
    NTRU_CRYPTO_SHA1_CTX *c,        /* in/out - pointer to SHA-1 context */
    uint32_t const       *init,     /*     in - pointer to alternate */
                                    /*          initialization - may be NULL */
    uint8_t const        *in,       /*     in - pointer to input data -
                                                may be NULL if in_len == 0 */
    uint32_t              in_len,   /*     in - number of input data bytes */
    uint32_t              flags,    /*     in - INIT, FINISH flags */
    uint8_t              *md)       /*    out - address for message digest -
                                                may be NULL if not FINISH */
{
    uint32_t    in_blk[16];         /* input block */
    uint32_t    space;
    uint8_t    *d = NULL;

    /* check error conditions */

    if (!c || (in_len && !in) || ((flags & SHA_FINISH) && !md))
    {
        SHA_RET(SHA_BAD_PARAMETER)
    }

    /* initialize context if requested */

    if (flags & SHA_INIT)
    {

        /* init chaining state */

        if (!init)
        {
            c->state[0] = H0_INIT;              /* standard initialization */
            c->state[1] = H1_INIT;
            c->state[2] = H2_INIT;
            c->state[3] = H3_INIT;
            c->state[4] = H4_INIT;
        }
        else
        {
            /* Non standard initialization values are not supported */
            SHA_RET(SHA_BAD_PARAMETER);
        }

        /* init bit count and number of unhashed data bytes */

        c->num_bits_hashed[0] = 0;
        c->num_bits_hashed[1] = 0;
        c->unhashed_len = 0;
    }

    /* determine space left in unhashed data buffer */

    if (c->unhashed_len > 63)
    {
        SHA_RET(SHA_FAIL)
    }
    
    space = 64 - c->unhashed_len;

    /* process input if it exists */

    if (in_len)
    {

        /* update count of bits hashed */

        {
            uint32_t    bits0, bits1;

            bits0 = in_len << 3;
            bits1 = in_len >> 29;
            
            if ((c->num_bits_hashed[0] += bits0) < bits0)
            {
                bits1++;
            }
            
            if ((c->num_bits_hashed[1] += bits1) < bits1)
            {
                memset((uint8_t *) c, 0, sizeof(NTRU_CRYPTO_SHA1_CTX));
                memset((char *) in_blk, 0, sizeof(in_blk));
                SHA_RET(SHA_OVERFLOW)
            }
        }

        /* process input bytes */

        if (in_len < space)
        {

            /* input does not fill block buffer:
             * add input to buffer
             */

            memcpy(c->unhashed + c->unhashed_len, in, in_len);
            c->unhashed_len += in_len;

        }
        else
        {
            uint32_t    blks;

            /* input will fill block buffer:
             *  fill unhashed data buffer,
             *  convert to block buffer,
             *  and process block
             */

            in_len -= space;
            
            for (d = c->unhashed + c->unhashed_len; space; space--)
            {
                *d++ = *in++;
            }
            
            ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed,
                                        16);
            sha1_blk((uint32_t const *) in_blk, c->state);

            /* process any remaining full blocks */

            for (blks = in_len >> 6; blks--; in += 64)
            {
                ntru_crypto_msbyte_2_uint32(in_blk, in, 16);
                sha1_blk((uint32_t const *) in_blk, c->state);
            }

            /* put any remaining input in the unhashed data buffer */

            in_len &= 0x3f;
            memcpy(c->unhashed, in, in_len);
            c->unhashed_len = in_len;
        }
    }

    /* complete message digest if requested */

    if (flags & SHA_FINISH)
    {
        space = 64 - c->unhashed_len;

        /* add 0x80 padding byte to the unhashed data buffer
         * (there is always space since the buffer can't be full)
         */

        d = c->unhashed + c->unhashed_len;
        *d++ = 0x80;
        space--;

        /* check for space for bit count */

        if (space < 8)
        {

            /* no space for count:
             *  fill remainder of unhashed data buffer with zeros,
             *  convert to input block,
             *  process block,
             *  fill all but 8 bytes of unhashed data buffer with zeros
             */

            memset(d, 0, space);
            ntru_crypto_msbyte_2_uint32(in_blk,
                                        (uint8_t const *) c->unhashed, 16);
            sha1_blk((uint32_t const *) in_blk, c->state);
            SecureZeroMemory(c->unhashed, 56);

        }
        else
        {

            /* fill unhashed data buffer with zeros,
             *  leaving space for bit count
             */

            for (space -= 8; space; space--)
            {
                *d++ = 0;
            }
        }

        /* convert partially filled unhashed data buffer to input block and
         *  add bit count to input block
         */

        ntru_crypto_msbyte_2_uint32(in_blk, (uint8_t const *) c->unhashed,
                                    14);
        in_blk[14] = c->num_bits_hashed[1];
        in_blk[15] = c->num_bits_hashed[0];

        /* process last block */

        sha1_blk((uint32_t const *) in_blk, c->state);

        /* copy result to message digest buffer */

        ntru_crypto_uint32_2_msbyte(md, c->state, 5);
        
        /* clear context and stack variables */

        memset((uint8_t *) c, 0, sizeof(NTRU_CRYPTO_SHA1_CTX));
        memset((char *) in_blk, 0, sizeof(in_blk));
    }

    SHA_RET(SHA_OK)
}


/* ntru_crypto_sha1_init
 *
 * This routine performs standard initialization of the SHA-1 state.
 *
 * Returns SHA_OK on success.
 * Returns SHA_FAIL with corrupted context.
 * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed.
 */

uint32_t
ntru_crypto_sha1_init(
    NTRU_CRYPTO_SHA1_CTX *c)        /* in/out - pointer to SHA-1 context */
{
    return ntru_crypto_sha1(c, NULL, NULL, 0, SHA_INIT, NULL);
}


/* ntru_crypto_sha1_update
 *
 * This routine processes input data and updates the SHA-1 hash calculation.
 *
 * Returns SHA_OK on success.
 * Returns SHA_FAIL with corrupted context.
 * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed.
 * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed.
 */

uint32_t
ntru_crypto_sha1_update(
    NTRU_CRYPTO_SHA1_CTX *c,        /* in/out - pointer to SHA-1 context */
    uint8_t const        *data,     /*    in - pointer to input data */
    uint32_t              data_len) /*    in - number of bytes of input data */
{
    return ntru_crypto_sha1(c, NULL, data, data_len, SHA_DATA_ONLY, NULL);
}


/* ntru_crypto_sha1_final
 *
 * This routine completes the SHA-1 hash calculation and returns the
 * message digest.
 *
 * Returns SHA_OK on success.
 * Returns SHA_FAIL with corrupted context.
 * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed.
 * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed.
 */

uint32_t
ntru_crypto_sha1_final(
    NTRU_CRYPTO_SHA1_CTX *c,        /* in/out - pointer to SHA-1 context */
    uint8_t              *md)       /*   out - address for message digest */
{
    return ntru_crypto_sha1(c, NULL, NULL, 0, SHA_FINISH, md);
}

/* ntru_crypto_sha1_digest
 *
 * This routine computes a SHA-1 message digest.
 *
 * Returns SHA_OK on success.
 * Returns SHA_FAIL with corrupted context.
 * Returns SHA_BAD_PARAMETER if inappropriate NULL pointers are passed.
 * Returns SHA_OVERFLOW if more than 2^64 - 1 bytes are hashed.
 */

uint32_t
ntru_crypto_sha1_digest(
    uint8_t const  *data,           /*  in - pointer to input data */
    uint32_t        data_len,       /*  in - number of bytes of input data */
    uint8_t        *md)             /* out - address for message digest */
{
    NTRU_CRYPTO_SHA1_CTX c;

    return ntru_crypto_sha1(&c, NULL, data, data_len, SHA_INIT | SHA_FINISH, md);
}

