/*
 * This implementation of SHA2 is somewhat similar to that in RFC6234, thanks
 * for publishing that!
 */

#ifndef SHA2_H
#define SHA2_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#define HASH(b0, b1, b2, b3, b4, b5, b6, b7) {b0, b1, b2, b3, b4, b5, b6, b7}
#define SHA2_256_HashBits 256
#define SHA2_256_HashBytes SHA2_256_HashBits / 8
#define SHA2_256_HashParts SHA2_256_HashBytes / 4
#define SHA2_256_BlockSize 2 * SHA2_256_HashBytes
typedef enum {
  shaSuccess = 0,
  shaNull,         /* Null pointer parameter */
  shaInputTooLong, /* input data too long */
  shaStateError,   /* called Input after Result */
  shaBadArg        /* Bad argument was given to a function */
} SHA2Result;
typedef uint32_t SHA2Digest[SHA2_256_HashParts];

/*
 *  This structure will hold context information for the SHA-1
 *  hashing operation
 */
typedef struct SHA2Context {
  SHA2Digest intermediate_hash; /* Message Digest  */

  uint32_t length_low;  /* Message length in bits      */
  uint32_t length_high; /* Message length in bits      */

  /* Index into message block array   */
  int_least16_t message_block_index;
  uint8_t message_block[SHA2_256_BlockSize]; /* 512-bit message blocks      */

  bool computed;  /* Is the digest computed?         */
  bool corrupted; /* Is the message digest corrupted? */
} SHA2Context;

/** data should always be null terminated */
extern SHA2Result sha2_256_oneshot(const uint8_t data[], const size_t len,
                                   SHA2Digest digest);
extern SHA2Result sha2_256_reset(SHA2Context *context);
extern SHA2Result sha2_256_input(SHA2Context *context, const uint8_t data[],
                                 size_t len);
extern SHA2Result sha2_256_result(SHA2Context *context, SHA2Digest digest);
extern void sha2_256_oneshot_n_times(uint32_t n, const uint8_t data[],
                                     const size_t len);

#endif // !SHA2_H
